blob: 24f9848f0a653b17689de9d3a2db02c0860ca77d [file] [log] [blame]
sewardjc9a65702004-07-07 16:32:57 +00001
2/*--------------------------------------------------------------------*/
sewardj752f9062010-05-03 21:38:49 +00003/*--- begin guest_x86_toIR.c ---*/
sewardjc9a65702004-07-07 16:32:57 +00004/*--------------------------------------------------------------------*/
5
sewardjf8ed9d82004-11-12 17:40:23 +00006/*
sewardj752f9062010-05-03 21:38:49 +00007 This file is part of Valgrind, a dynamic binary instrumentation
8 framework.
sewardjf8ed9d82004-11-12 17:40:23 +00009
sewardj785952d2015-08-21 11:29:16 +000010 Copyright (C) 2004-2015 OpenWorks LLP
sewardj752f9062010-05-03 21:38:49 +000011 info@open-works.net
sewardjf8ed9d82004-11-12 17:40:23 +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.
sewardjf8ed9d82004-11-12 17:40:23 +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.
sewardjf8ed9d82004-11-12 17:40:23 +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.
sewardjf8ed9d82004-11-12 17:40:23 +000034*/
35
sewardje9d8a262009-07-01 08:06:34 +000036/* Translates x86 code to IR. */
37
sewardj77b86be2004-07-11 13:28:24 +000038/* TODO:
sewardj45f1ff82005-05-05 12:04:14 +000039
sewardj3b3eacd2005-08-24 10:01:36 +000040 All Puts to CC_OP/CC_DEP1/CC_DEP2/CC_NDEP should really be checked
41 to ensure a 32-bit value is being written.
42
sewardj883b00b2004-09-11 09:30:24 +000043 FUCOMI(P): what happens to A and S flags? Currently are forced
44 to zero.
sewardj3f61ddb2004-10-16 20:51:05 +000045
sewardjce70a5c2004-10-18 14:09:54 +000046 x87 FP Limitations:
sewardja0e83b02005-01-06 12:36:38 +000047
48 * all arithmetic done at 64 bits
49
sewardj3f61ddb2004-10-16 20:51:05 +000050 * no FP exceptions, except for handling stack over/underflow
sewardja0e83b02005-01-06 12:36:38 +000051
sewardj3f61ddb2004-10-16 20:51:05 +000052 * FP rounding mode observed only for float->int conversions
sewardja0e83b02005-01-06 12:36:38 +000053 and int->float conversions which could lose accuracy, and
54 for float-to-float rounding. For all other operations,
55 round-to-nearest is used, regardless.
56
sewardje166ed02004-10-25 02:27:01 +000057 * some of the FCOM cases could do with testing -- not convinced
58 that the args are the right way round.
sewardj52444cb2004-12-13 14:09:01 +000059
sewardja0e83b02005-01-06 12:36:38 +000060 * FSAVE does not re-initialise the FPU; it should do
61
62 * FINIT not only initialises the FPU environment, it also
63 zeroes all the FP registers. It should leave the registers
64 unchanged.
65
sewardjcb2c99d2004-12-17 19:14:24 +000066 SAHF should cause eflags[1] == 1, and in fact it produces 0. As
67 per Intel docs this bit has no meaning anyway. Since PUSHF is the
68 only way to observe eflags[1], a proper fix would be to make that
69 bit be set by PUSHF.
70
sewardj6d269842005-08-06 11:45:02 +000071 The state of %eflags.AC (alignment check, bit 18) is recorded by
72 the simulation (viz, if you set it with popf then a pushf produces
73 the value you set it to), but it is otherwise ignored. In
74 particular, setting it to 1 does NOT cause alignment checking to
75 happen. Programs that set it to 1 and then rely on the resulting
76 SIGBUSs to inform them of misaligned accesses will not work.
77
sewardje9d8a262009-07-01 08:06:34 +000078 Implementation of sysenter is necessarily partial. sysenter is a
79 kind of system call entry. When doing a sysenter, the return
80 address is not known -- that is something that is beyond Vex's
81 knowledge. So the generated IR forces a return to the scheduler,
82 which can do what it likes to simulate the systenter, but it MUST
83 set this thread's guest_EIP field with the continuation address
84 before resuming execution. If that doesn't happen, the thread will
85 jump to address zero, which is probably fatal.
sewardjf07ed032005-08-07 14:48:03 +000086
sewardj52444cb2004-12-13 14:09:01 +000087 This module uses global variables and so is not MT-safe (if that
sewardje395ae82005-02-26 02:00:50 +000088 should ever become relevant).
89
90 The delta values are 32-bit ints, not 64-bit ints. That means
91 this module may not work right if run on a 64-bit host. That should
92 be fixed properly, really -- if anyone ever wants to use Vex to
sewardje9d8a262009-07-01 08:06:34 +000093 translate x86 code for execution on a 64-bit host.
94
95 casLE (implementation of lock-prefixed insns) and rep-prefixed
96 insns: the side-exit back to the start of the insn is done with
97 Ijk_Boring. This is quite wrong, it should be done with
98 Ijk_NoRedir, since otherwise the side exit, which is intended to
99 restart the instruction for whatever reason, could go somewhere
100 entirely else. Doing it right (with Ijk_NoRedir jumps) would make
101 no-redir jumps performance critical, at least for rep-prefixed
102 instructions, since all iterations thereof would involve such a
103 jump. It's not such a big deal with casLE since the side exit is
104 only taken if the CAS fails, that is, the location is contended,
105 which is relatively unlikely.
sewardj1fb8c922009-07-12 12:56:53 +0000106
sewardj6c299f32009-12-31 18:00:12 +0000107 XXXX: Nov 2009: handling of SWP on ARM suffers from the same
108 problem.
109
sewardj1fb8c922009-07-12 12:56:53 +0000110 Note also, the test for CAS success vs failure is done using
111 Iop_CasCmp{EQ,NE}{8,16,32,64} rather than the ordinary
112 Iop_Cmp{EQ,NE} equivalents. This is so as to tell Memcheck that it
113 shouldn't definedness-check these comparisons. See
114 COMMENT_ON_CasCmpEQ in memcheck/mc_translate.c for
115 background/rationale.
sewardje9d8a262009-07-01 08:06:34 +0000116*/
sewardje05c42c2004-07-08 20:25:10 +0000117
sewardj9f8a3952005-04-06 10:27:11 +0000118/* Performance holes:
119
120 - fcom ; fstsw %ax ; sahf
121 sahf does not update the O flag (sigh) and so O needs to
122 be computed. This is done expensively; it would be better
123 to have a calculate_eflags_o helper.
124
125 - emwarns; some FP codes can generate huge numbers of these
126 if the fpucw is changed in an inner loop. It would be
127 better for the guest state to have an emwarn-enable reg
128 which can be set zero or nonzero. If it is zero, emwarns
129 are not flagged, and instead control just flows all the
130 way through bbs as usual.
131*/
132
sewardjce02aa72006-01-12 12:27:58 +0000133/* "Special" instructions.
134
135 This instruction decoder can decode three special instructions
136 which mean nothing natively (are no-ops as far as regs/mem are
137 concerned) but have meaning for supporting Valgrind. A special
138 instruction is flagged by the 12-byte preamble C1C703 C1C70D C1C71D
139 C1C713 (in the standard interpretation, that means: roll $3, %edi;
140 roll $13, %edi; roll $29, %edi; roll $19, %edi). Following that,
141 one of the following 3 are allowed (standard interpretation in
142 parentheses):
143
144 87DB (xchgl %ebx,%ebx) %EDX = client_request ( %EAX )
145 87C9 (xchgl %ecx,%ecx) %EAX = guest_NRADDR
146 87D2 (xchgl %edx,%edx) call-noredir *%EAX
florian2245ce92012-08-28 16:49:30 +0000147 87FF (xchgl %edi,%edi) IR injection
sewardjce02aa72006-01-12 12:27:58 +0000148
149 Any other bytes following the 12-byte preamble are illegal and
150 constitute a failure in instruction decoding. This all assumes
151 that the preamble will never occur except in specific code
152 fragments designed for Valgrind to catch.
153
154 No prefixes may precede a "Special" instruction.
155*/
156
sewardje9d8a262009-07-01 08:06:34 +0000157/* LOCK prefixed instructions. These are translated using IR-level
158 CAS statements (IRCAS) and are believed to preserve atomicity, even
159 from the point of view of some other process racing against a
160 simulated one (presumably they communicate via a shared memory
161 segment).
sewardjce02aa72006-01-12 12:27:58 +0000162
sewardje9d8a262009-07-01 08:06:34 +0000163 Handlers which are aware of LOCK prefixes are:
164 dis_op2_G_E (add, or, adc, sbb, and, sub, xor)
165 dis_cmpxchg_G_E (cmpxchg)
166 dis_Grp1 (add, or, adc, sbb, and, sub, xor)
167 dis_Grp3 (not, neg)
168 dis_Grp4 (inc, dec)
169 dis_Grp5 (inc, dec)
170 dis_Grp8_Imm (bts, btc, btr)
171 dis_bt_G_E (bts, btc, btr)
172 dis_xadd_G_E (xadd)
173*/
174
sewardjc9a65702004-07-07 16:32:57 +0000175
176#include "libvex_basictypes.h"
177#include "libvex_ir.h"
sewardje87b4842004-07-10 12:23:30 +0000178#include "libvex.h"
sewardjf6dc3ce2004-10-19 01:03:46 +0000179#include "libvex_guest_x86.h"
sewardjc0ee2ed2004-07-27 10:29:41 +0000180
sewardjcef7d3e2009-07-02 12:21:59 +0000181#include "main_util.h"
182#include "main_globals.h"
183#include "guest_generic_bb_to_IR.h"
184#include "guest_generic_x87.h"
185#include "guest_x86_defs.h"
sewardjc9a65702004-07-07 16:32:57 +0000186
187
188/*------------------------------------------------------------*/
189/*--- Globals ---*/
190/*------------------------------------------------------------*/
191
sewardj9e6491a2005-07-02 19:24:10 +0000192/* These are set at the start of the translation of an insn, right
193 down in disInstr_X86, so that we don't have to pass them around
194 endlessly. They are all constant during the translation of any
195 given insn. */
sewardjc9a65702004-07-07 16:32:57 +0000196
197/* We need to know this to do sub-register accesses correctly. */
sewardj9b769162014-07-24 12:42:03 +0000198static VexEndness host_endness;
sewardjc9a65702004-07-07 16:32:57 +0000199
sewardj9e6491a2005-07-02 19:24:10 +0000200/* Pointer to the guest code area (points to start of BB, not to the
201 insn being processed). */
florian8462d112014-09-24 15:18:09 +0000202static const UChar* guest_code;
sewardjc9a65702004-07-07 16:32:57 +0000203
204/* The guest address corresponding to guest_code[0]. */
sewardj9e6491a2005-07-02 19:24:10 +0000205static Addr32 guest_EIP_bbstart;
sewardjc9a65702004-07-07 16:32:57 +0000206
sewardj52444cb2004-12-13 14:09:01 +0000207/* The guest address for the instruction currently being
208 translated. */
sewardj9e6491a2005-07-02 19:24:10 +0000209static Addr32 guest_EIP_curr_instr;
sewardj52444cb2004-12-13 14:09:01 +0000210
sewardjdd40fdf2006-12-24 02:20:24 +0000211/* The IRSB* into which we're generating code. */
212static IRSB* irsb;
sewardjc9a65702004-07-07 16:32:57 +0000213
sewardjc9a65702004-07-07 16:32:57 +0000214
sewardjce70a5c2004-10-18 14:09:54 +0000215/*------------------------------------------------------------*/
216/*--- Debugging output ---*/
217/*------------------------------------------------------------*/
218
sewardjf48ac192004-10-29 00:41:29 +0000219#define DIP(format, args...) \
sewardj9e6491a2005-07-02 19:24:10 +0000220 if (vex_traceflags & VEX_TRACE_FE) \
sewardjce70a5c2004-10-18 14:09:54 +0000221 vex_printf(format, ## args)
222
sewardjf48ac192004-10-29 00:41:29 +0000223#define DIS(buf, format, args...) \
sewardj9e6491a2005-07-02 19:24:10 +0000224 if (vex_traceflags & VEX_TRACE_FE) \
sewardjce70a5c2004-10-18 14:09:54 +0000225 vex_sprintf(buf, format, ## args)
226
227
228/*------------------------------------------------------------*/
sewardjdcc85fc2004-10-26 13:26:20 +0000229/*--- Offsets of various parts of the x86 guest state. ---*/
230/*------------------------------------------------------------*/
231
sewardjc9a43662004-11-30 18:51:59 +0000232#define OFFB_EAX offsetof(VexGuestX86State,guest_EAX)
233#define OFFB_EBX offsetof(VexGuestX86State,guest_EBX)
234#define OFFB_ECX offsetof(VexGuestX86State,guest_ECX)
235#define OFFB_EDX offsetof(VexGuestX86State,guest_EDX)
236#define OFFB_ESP offsetof(VexGuestX86State,guest_ESP)
237#define OFFB_EBP offsetof(VexGuestX86State,guest_EBP)
238#define OFFB_ESI offsetof(VexGuestX86State,guest_ESI)
239#define OFFB_EDI offsetof(VexGuestX86State,guest_EDI)
sewardj2a2ba8b2004-11-08 13:14:06 +0000240
sewardjc9a43662004-11-30 18:51:59 +0000241#define OFFB_EIP offsetof(VexGuestX86State,guest_EIP)
sewardj2a2ba8b2004-11-08 13:14:06 +0000242
sewardjc9a43662004-11-30 18:51:59 +0000243#define OFFB_CC_OP offsetof(VexGuestX86State,guest_CC_OP)
244#define OFFB_CC_DEP1 offsetof(VexGuestX86State,guest_CC_DEP1)
245#define OFFB_CC_DEP2 offsetof(VexGuestX86State,guest_CC_DEP2)
246#define OFFB_CC_NDEP offsetof(VexGuestX86State,guest_CC_NDEP)
sewardj893aada2004-11-29 19:57:54 +0000247
sewardjc9a43662004-11-30 18:51:59 +0000248#define OFFB_FPREGS offsetof(VexGuestX86State,guest_FPREG[0])
249#define OFFB_FPTAGS offsetof(VexGuestX86State,guest_FPTAG[0])
250#define OFFB_DFLAG offsetof(VexGuestX86State,guest_DFLAG)
251#define OFFB_IDFLAG offsetof(VexGuestX86State,guest_IDFLAG)
sewardj6d269842005-08-06 11:45:02 +0000252#define OFFB_ACFLAG offsetof(VexGuestX86State,guest_ACFLAG)
sewardjc9a43662004-11-30 18:51:59 +0000253#define OFFB_FTOP offsetof(VexGuestX86State,guest_FTOP)
254#define OFFB_FC3210 offsetof(VexGuestX86State,guest_FC3210)
255#define OFFB_FPROUND offsetof(VexGuestX86State,guest_FPROUND)
256
257#define OFFB_CS offsetof(VexGuestX86State,guest_CS)
258#define OFFB_DS offsetof(VexGuestX86State,guest_DS)
259#define OFFB_ES offsetof(VexGuestX86State,guest_ES)
260#define OFFB_FS offsetof(VexGuestX86State,guest_FS)
261#define OFFB_GS offsetof(VexGuestX86State,guest_GS)
262#define OFFB_SS offsetof(VexGuestX86State,guest_SS)
sewardj3bd6f3e2004-12-13 10:48:19 +0000263#define OFFB_LDT offsetof(VexGuestX86State,guest_LDT)
264#define OFFB_GDT offsetof(VexGuestX86State,guest_GDT)
sewardjc9a43662004-11-30 18:51:59 +0000265
266#define OFFB_SSEROUND offsetof(VexGuestX86State,guest_SSEROUND)
267#define OFFB_XMM0 offsetof(VexGuestX86State,guest_XMM0)
268#define OFFB_XMM1 offsetof(VexGuestX86State,guest_XMM1)
269#define OFFB_XMM2 offsetof(VexGuestX86State,guest_XMM2)
270#define OFFB_XMM3 offsetof(VexGuestX86State,guest_XMM3)
271#define OFFB_XMM4 offsetof(VexGuestX86State,guest_XMM4)
272#define OFFB_XMM5 offsetof(VexGuestX86State,guest_XMM5)
273#define OFFB_XMM6 offsetof(VexGuestX86State,guest_XMM6)
274#define OFFB_XMM7 offsetof(VexGuestX86State,guest_XMM7)
275
florian6ef84be2012-08-26 03:20:07 +0000276#define OFFB_EMNOTE offsetof(VexGuestX86State,guest_EMNOTE)
sewardjdcc85fc2004-10-26 13:26:20 +0000277
sewardj05f5e012014-05-04 10:52:11 +0000278#define OFFB_CMSTART offsetof(VexGuestX86State,guest_CMSTART)
279#define OFFB_CMLEN offsetof(VexGuestX86State,guest_CMLEN)
sewardjce02aa72006-01-12 12:27:58 +0000280#define OFFB_NRADDR offsetof(VexGuestX86State,guest_NRADDR)
281
sewardje86310f2009-03-19 22:21:40 +0000282#define OFFB_IP_AT_SYSCALL offsetof(VexGuestX86State,guest_IP_AT_SYSCALL)
283
sewardjdcc85fc2004-10-26 13:26:20 +0000284
285/*------------------------------------------------------------*/
sewardjce70a5c2004-10-18 14:09:54 +0000286/*--- Helper bits and pieces for deconstructing the ---*/
287/*--- x86 insn stream. ---*/
288/*------------------------------------------------------------*/
289
290/* This is the Intel register encoding -- integer regs. */
291#define R_EAX 0
292#define R_ECX 1
293#define R_EDX 2
294#define R_EBX 3
295#define R_ESP 4
296#define R_EBP 5
297#define R_ESI 6
298#define R_EDI 7
299
300#define R_AL (0+R_EAX)
301#define R_AH (4+R_EAX)
302
sewardj063f02f2004-10-20 12:36:12 +0000303/* This is the Intel register encoding -- segment regs. */
304#define R_ES 0
305#define R_CS 1
306#define R_SS 2
307#define R_DS 3
308#define R_FS 4
309#define R_GS 5
310
sewardjce70a5c2004-10-18 14:09:54 +0000311
sewardjc9a65702004-07-07 16:32:57 +0000312/* Add a statement to the list held by "irbb". */
sewardjd7cb8532004-08-17 23:59:23 +0000313static void stmt ( IRStmt* st )
sewardjc9a65702004-07-07 16:32:57 +0000314{
sewardjdd40fdf2006-12-24 02:20:24 +0000315 addStmtToIRSB( irsb, st );
sewardjc9a65702004-07-07 16:32:57 +0000316}
317
318/* Generate a new temporary of the given type. */
319static IRTemp newTemp ( IRType ty )
320{
sewardj496a58d2005-03-20 18:44:44 +0000321 vassert(isPlausibleIRType(ty));
sewardjdd40fdf2006-12-24 02:20:24 +0000322 return newIRTemp( irsb->tyenv, ty );
sewardjc9a65702004-07-07 16:32:57 +0000323}
324
sewardjce70a5c2004-10-18 14:09:54 +0000325/* Various simple conversions */
sewardjd1061ab2004-07-08 01:45:30 +0000326
sewardje05c42c2004-07-08 20:25:10 +0000327static UInt extend_s_8to32( UInt x )
sewardjd1061ab2004-07-08 01:45:30 +0000328{
florian108e03f2015-03-10 16:11:58 +0000329 return (UInt)((Int)(x << 24) >> 24);
sewardjd1061ab2004-07-08 01:45:30 +0000330}
331
sewardj0611d802004-07-11 02:37:54 +0000332static UInt extend_s_16to32 ( UInt x )
333{
florian108e03f2015-03-10 16:11:58 +0000334 return (UInt)((Int)(x << 16) >> 16);
sewardj0611d802004-07-11 02:37:54 +0000335}
336
sewardjd1061ab2004-07-08 01:45:30 +0000337/* Fetch a byte from the guest insn stream. */
sewardj52d04912005-07-03 00:52:48 +0000338static UChar getIByte ( Int delta )
sewardjd1061ab2004-07-08 01:45:30 +0000339{
340 return guest_code[delta];
341}
342
sewardjc9a65702004-07-07 16:32:57 +0000343/* Extract the reg field from a modRM byte. */
sewardje05c42c2004-07-08 20:25:10 +0000344static Int gregOfRM ( UChar mod_reg_rm )
sewardjc9a65702004-07-07 16:32:57 +0000345{
346 return (Int)( (mod_reg_rm >> 3) & 7 );
347}
348
349/* Figure out whether the mod and rm parts of a modRM byte refer to a
350 register or memory. If so, the byte will have the form 11XXXYYY,
351 where YYY is the register number. */
sewardje05c42c2004-07-08 20:25:10 +0000352static Bool epartIsReg ( UChar mod_reg_rm )
sewardjc9a65702004-07-07 16:32:57 +0000353{
sewardj2d49b432005-02-01 00:37:06 +0000354 return toBool(0xC0 == (mod_reg_rm & 0xC0));
sewardjc9a65702004-07-07 16:32:57 +0000355}
356
357/* ... and extract the register number ... */
sewardje05c42c2004-07-08 20:25:10 +0000358static Int eregOfRM ( UChar mod_reg_rm )
sewardjc9a65702004-07-07 16:32:57 +0000359{
360 return (Int)(mod_reg_rm & 0x7);
361}
362
sewardje05c42c2004-07-08 20:25:10 +0000363/* Get a 8/16/32-bit unsigned value out of the insn stream. */
364
sewardj52d04912005-07-03 00:52:48 +0000365static UChar getUChar ( Int delta )
sewardje05c42c2004-07-08 20:25:10 +0000366{
sewardj2d49b432005-02-01 00:37:06 +0000367 UChar v = guest_code[delta+0];
sewardj9b45b482005-02-07 01:42:18 +0000368 return toUChar(v);
sewardje05c42c2004-07-08 20:25:10 +0000369}
370
sewardj52d04912005-07-03 00:52:48 +0000371static UInt getUDisp16 ( Int delta )
sewardje05c42c2004-07-08 20:25:10 +0000372{
373 UInt v = guest_code[delta+1]; v <<= 8;
374 v |= guest_code[delta+0];
375 return v & 0xFFFF;
376}
377
sewardj52d04912005-07-03 00:52:48 +0000378static UInt getUDisp32 ( Int delta )
sewardjd1061ab2004-07-08 01:45:30 +0000379{
380 UInt v = guest_code[delta+3]; v <<= 8;
381 v |= guest_code[delta+2]; v <<= 8;
382 v |= guest_code[delta+1]; v <<= 8;
383 v |= guest_code[delta+0];
384 return v;
385}
386
sewardj52d04912005-07-03 00:52:48 +0000387static UInt getUDisp ( Int size, Int delta )
sewardje05c42c2004-07-08 20:25:10 +0000388{
389 switch (size) {
390 case 4: return getUDisp32(delta);
391 case 2: return getUDisp16(delta);
sewardj2d49b432005-02-01 00:37:06 +0000392 case 1: return (UInt)getUChar(delta);
sewardje05c42c2004-07-08 20:25:10 +0000393 default: vpanic("getUDisp(x86)");
394 }
395 return 0; /*notreached*/
396}
397
398
sewardjd1061ab2004-07-08 01:45:30 +0000399/* Get a byte value out of the insn stream and sign-extend to 32
400 bits. */
sewardj52d04912005-07-03 00:52:48 +0000401static UInt getSDisp8 ( Int delta )
sewardjd1061ab2004-07-08 01:45:30 +0000402{
403 return extend_s_8to32( (UInt) (guest_code[delta]) );
404}
405
sewardj52d04912005-07-03 00:52:48 +0000406static UInt getSDisp16 ( Int delta0 )
sewardj0611d802004-07-11 02:37:54 +0000407{
florian8462d112014-09-24 15:18:09 +0000408 const UChar* eip = &guest_code[delta0];
sewardj0611d802004-07-11 02:37:54 +0000409 UInt d = *eip++;
410 d |= ((*eip++) << 8);
411 return extend_s_16to32(d);
412}
413
sewardj52d04912005-07-03 00:52:48 +0000414static UInt getSDisp ( Int size, Int delta )
sewardj0611d802004-07-11 02:37:54 +0000415{
416 switch (size) {
417 case 4: return getUDisp32(delta);
418 case 2: return getSDisp16(delta);
419 case 1: return getSDisp8(delta);
420 default: vpanic("getSDisp(x86)");
421 }
422 return 0; /*notreached*/
423}
sewardjd1061ab2004-07-08 01:45:30 +0000424
sewardjc9a65702004-07-07 16:32:57 +0000425
426/*------------------------------------------------------------*/
427/*--- Helpers for constructing IR. ---*/
428/*------------------------------------------------------------*/
429
430/* Create a 1/2/4 byte read of an x86 integer registers. For 16/8 bit
431 register references, we need to take the host endianness into
432 account. Supplied value is 0 .. 7 and in the Intel instruction
433 encoding. */
sewardje05c42c2004-07-08 20:25:10 +0000434
sewardj9334b0f2004-07-10 22:43:54 +0000435static IRType szToITy ( Int n )
436{
437 switch (n) {
438 case 1: return Ity_I8;
439 case 2: return Ity_I16;
440 case 4: return Ity_I32;
441 default: vpanic("szToITy(x86)");
442 }
443}
444
sewardj67e002d2004-12-02 18:16:33 +0000445/* On a little-endian host, less significant bits of the guest
446 registers are at lower addresses. Therefore, if a reference to a
447 register low half has the safe guest state offset as a reference to
448 the full register.
449*/
sewardj9334b0f2004-07-10 22:43:54 +0000450static Int integerGuestRegOffset ( Int sz, UInt archreg )
451{
452 vassert(archreg < 8);
453
sewardj9334b0f2004-07-10 22:43:54 +0000454 /* Correct for little-endian host only. */
sewardj9b769162014-07-24 12:42:03 +0000455 vassert(host_endness == VexEndnessLE);
sewardj063f02f2004-10-20 12:36:12 +0000456
457 if (sz == 4 || sz == 2 || (sz == 1 && archreg < 4)) {
458 switch (archreg) {
sewardjc9a43662004-11-30 18:51:59 +0000459 case R_EAX: return OFFB_EAX;
460 case R_EBX: return OFFB_EBX;
461 case R_ECX: return OFFB_ECX;
462 case R_EDX: return OFFB_EDX;
463 case R_ESI: return OFFB_ESI;
464 case R_EDI: return OFFB_EDI;
465 case R_ESP: return OFFB_ESP;
466 case R_EBP: return OFFB_EBP;
sewardj063f02f2004-10-20 12:36:12 +0000467 default: vpanic("integerGuestRegOffset(x86,le)(4,2)");
468 }
469 }
470
471 vassert(archreg >= 4 && archreg < 8 && sz == 1);
472 switch (archreg-4) {
sewardjc9a43662004-11-30 18:51:59 +0000473 case R_EAX: return 1+ OFFB_EAX;
474 case R_EBX: return 1+ OFFB_EBX;
475 case R_ECX: return 1+ OFFB_ECX;
476 case R_EDX: return 1+ OFFB_EDX;
sewardj063f02f2004-10-20 12:36:12 +0000477 default: vpanic("integerGuestRegOffset(x86,le)(1h)");
478 }
479
480 /* NOTREACHED */
481 vpanic("integerGuestRegOffset(x86,le)");
482}
483
484static Int segmentGuestRegOffset ( UInt sreg )
485{
486 switch (sreg) {
sewardjc9a43662004-11-30 18:51:59 +0000487 case R_ES: return OFFB_ES;
488 case R_CS: return OFFB_CS;
489 case R_SS: return OFFB_SS;
490 case R_DS: return OFFB_DS;
491 case R_FS: return OFFB_FS;
492 case R_GS: return OFFB_GS;
sewardj063f02f2004-10-20 12:36:12 +0000493 default: vpanic("segmentGuestRegOffset(x86)");
sewardj9334b0f2004-07-10 22:43:54 +0000494 }
495}
496
sewardjc9a43662004-11-30 18:51:59 +0000497static Int xmmGuestRegOffset ( UInt xmmreg )
498{
499 switch (xmmreg) {
500 case 0: return OFFB_XMM0;
501 case 1: return OFFB_XMM1;
502 case 2: return OFFB_XMM2;
503 case 3: return OFFB_XMM3;
504 case 4: return OFFB_XMM4;
505 case 5: return OFFB_XMM5;
506 case 6: return OFFB_XMM6;
507 case 7: return OFFB_XMM7;
508 default: vpanic("xmmGuestRegOffset");
509 }
510}
511
sewardj67e002d2004-12-02 18:16:33 +0000512/* Lanes of vector registers are always numbered from zero being the
513 least significant lane (rightmost in the register). */
514
sewardje5854d62004-12-09 03:44:34 +0000515static Int xmmGuestRegLane16offset ( UInt xmmreg, Int laneno )
516{
517 /* Correct for little-endian host only. */
sewardj9b769162014-07-24 12:42:03 +0000518 vassert(host_endness == VexEndnessLE);
sewardje5854d62004-12-09 03:44:34 +0000519 vassert(laneno >= 0 && laneno < 8);
520 return xmmGuestRegOffset( xmmreg ) + 2 * laneno;
521}
522
sewardj67e002d2004-12-02 18:16:33 +0000523static Int xmmGuestRegLane32offset ( UInt xmmreg, Int laneno )
524{
525 /* Correct for little-endian host only. */
sewardj9b769162014-07-24 12:42:03 +0000526 vassert(host_endness == VexEndnessLE);
sewardj67e002d2004-12-02 18:16:33 +0000527 vassert(laneno >= 0 && laneno < 4);
528 return xmmGuestRegOffset( xmmreg ) + 4 * laneno;
529}
530
531static Int xmmGuestRegLane64offset ( UInt xmmreg, Int laneno )
532{
533 /* Correct for little-endian host only. */
sewardj9b769162014-07-24 12:42:03 +0000534 vassert(host_endness == VexEndnessLE);
sewardj67e002d2004-12-02 18:16:33 +0000535 vassert(laneno >= 0 && laneno < 2);
536 return xmmGuestRegOffset( xmmreg ) + 8 * laneno;
537}
538
sewardjd1061ab2004-07-08 01:45:30 +0000539static IRExpr* getIReg ( Int sz, UInt archreg )
sewardjc9a65702004-07-07 16:32:57 +0000540{
541 vassert(sz == 1 || sz == 2 || sz == 4);
542 vassert(archreg < 8);
sewardj9334b0f2004-07-10 22:43:54 +0000543 return IRExpr_Get( integerGuestRegOffset(sz,archreg),
sewardj5bd4d162004-11-10 13:02:48 +0000544 szToITy(sz) );
sewardjc9a65702004-07-07 16:32:57 +0000545}
546
547/* Ditto, but write to a reg instead. */
sewardj41f43bc2004-07-08 14:23:22 +0000548static void putIReg ( Int sz, UInt archreg, IRExpr* e )
sewardjc9a65702004-07-07 16:32:57 +0000549{
sewardjdd40fdf2006-12-24 02:20:24 +0000550 IRType ty = typeOfIRExpr(irsb->tyenv, e);
sewardjd24931d2005-03-20 12:51:39 +0000551 switch (sz) {
552 case 1: vassert(ty == Ity_I8); break;
553 case 2: vassert(ty == Ity_I16); break;
554 case 4: vassert(ty == Ity_I32); break;
555 default: vpanic("putIReg(x86)");
556 }
sewardjc9a65702004-07-07 16:32:57 +0000557 vassert(archreg < 8);
sewardjeeb9ef82004-07-15 12:39:03 +0000558 stmt( IRStmt_Put(integerGuestRegOffset(sz,archreg), e) );
sewardjd1061ab2004-07-08 01:45:30 +0000559}
560
sewardj063f02f2004-10-20 12:36:12 +0000561static IRExpr* getSReg ( UInt sreg )
562{
563 return IRExpr_Get( segmentGuestRegOffset(sreg), Ity_I16 );
564}
565
566static void putSReg ( UInt sreg, IRExpr* e )
567{
sewardjdd40fdf2006-12-24 02:20:24 +0000568 vassert(typeOfIRExpr(irsb->tyenv,e) == Ity_I16);
sewardj063f02f2004-10-20 12:36:12 +0000569 stmt( IRStmt_Put( segmentGuestRegOffset(sreg), e ) );
570}
571
sewardjc9a43662004-11-30 18:51:59 +0000572static IRExpr* getXMMReg ( UInt xmmreg )
573{
574 return IRExpr_Get( xmmGuestRegOffset(xmmreg), Ity_V128 );
575}
576
sewardj67e002d2004-12-02 18:16:33 +0000577static IRExpr* getXMMRegLane64 ( UInt xmmreg, Int laneno )
578{
579 return IRExpr_Get( xmmGuestRegLane64offset(xmmreg,laneno), Ity_I64 );
580}
581
sewardjfd226452004-12-07 19:02:18 +0000582static IRExpr* getXMMRegLane64F ( UInt xmmreg, Int laneno )
sewardj67e002d2004-12-02 18:16:33 +0000583{
sewardjfd226452004-12-07 19:02:18 +0000584 return IRExpr_Get( xmmGuestRegLane64offset(xmmreg,laneno), Ity_F64 );
sewardj67e002d2004-12-02 18:16:33 +0000585}
586
sewardj9636b442004-12-04 01:38:37 +0000587static IRExpr* getXMMRegLane32 ( UInt xmmreg, Int laneno )
588{
589 return IRExpr_Get( xmmGuestRegLane32offset(xmmreg,laneno), Ity_I32 );
590}
591
sewardjfd226452004-12-07 19:02:18 +0000592static IRExpr* getXMMRegLane32F ( UInt xmmreg, Int laneno )
593{
594 return IRExpr_Get( xmmGuestRegLane32offset(xmmreg,laneno), Ity_F32 );
595}
596
sewardjc9a43662004-11-30 18:51:59 +0000597static void putXMMReg ( UInt xmmreg, IRExpr* e )
598{
sewardjdd40fdf2006-12-24 02:20:24 +0000599 vassert(typeOfIRExpr(irsb->tyenv,e) == Ity_V128);
sewardjc9a43662004-11-30 18:51:59 +0000600 stmt( IRStmt_Put( xmmGuestRegOffset(xmmreg), e ) );
601}
602
sewardj67e002d2004-12-02 18:16:33 +0000603static void putXMMRegLane64 ( UInt xmmreg, Int laneno, IRExpr* e )
604{
sewardjdd40fdf2006-12-24 02:20:24 +0000605 vassert(typeOfIRExpr(irsb->tyenv,e) == Ity_I64);
sewardj67e002d2004-12-02 18:16:33 +0000606 stmt( IRStmt_Put( xmmGuestRegLane64offset(xmmreg,laneno), e ) );
607}
608
sewardjfd226452004-12-07 19:02:18 +0000609static void putXMMRegLane64F ( UInt xmmreg, Int laneno, IRExpr* e )
610{
sewardjdd40fdf2006-12-24 02:20:24 +0000611 vassert(typeOfIRExpr(irsb->tyenv,e) == Ity_F64);
sewardjfd226452004-12-07 19:02:18 +0000612 stmt( IRStmt_Put( xmmGuestRegLane64offset(xmmreg,laneno), e ) );
613}
614
sewardj4cb918d2004-12-03 19:43:31 +0000615static void putXMMRegLane32F ( UInt xmmreg, Int laneno, IRExpr* e )
sewardj67e002d2004-12-02 18:16:33 +0000616{
sewardjdd40fdf2006-12-24 02:20:24 +0000617 vassert(typeOfIRExpr(irsb->tyenv,e) == Ity_F32);
sewardj67e002d2004-12-02 18:16:33 +0000618 stmt( IRStmt_Put( xmmGuestRegLane32offset(xmmreg,laneno), e ) );
619}
620
sewardj9636b442004-12-04 01:38:37 +0000621static void putXMMRegLane32 ( UInt xmmreg, Int laneno, IRExpr* e )
622{
sewardjdd40fdf2006-12-24 02:20:24 +0000623 vassert(typeOfIRExpr(irsb->tyenv,e) == Ity_I32);
sewardj9636b442004-12-04 01:38:37 +0000624 stmt( IRStmt_Put( xmmGuestRegLane32offset(xmmreg,laneno), e ) );
625}
626
sewardje5854d62004-12-09 03:44:34 +0000627static void putXMMRegLane16 ( UInt xmmreg, Int laneno, IRExpr* e )
628{
sewardjdd40fdf2006-12-24 02:20:24 +0000629 vassert(typeOfIRExpr(irsb->tyenv,e) == Ity_I16);
sewardje5854d62004-12-09 03:44:34 +0000630 stmt( IRStmt_Put( xmmGuestRegLane16offset(xmmreg,laneno), e ) );
631}
632
sewardj41f43bc2004-07-08 14:23:22 +0000633static void assign ( IRTemp dst, IRExpr* e )
sewardjd1061ab2004-07-08 01:45:30 +0000634{
sewardjdd40fdf2006-12-24 02:20:24 +0000635 stmt( IRStmt_WrTmp(dst, e) );
sewardjd1061ab2004-07-08 01:45:30 +0000636}
637
sewardj41f43bc2004-07-08 14:23:22 +0000638static void storeLE ( IRExpr* addr, IRExpr* data )
sewardjd1061ab2004-07-08 01:45:30 +0000639{
sewardje768e922009-11-26 17:17:37 +0000640 stmt( IRStmt_Store(Iend_LE, addr, data) );
sewardjd1061ab2004-07-08 01:45:30 +0000641}
642
sewardje87b4842004-07-10 12:23:30 +0000643static IRExpr* unop ( IROp op, IRExpr* a )
644{
645 return IRExpr_Unop(op, a);
646}
647
sewardjd1061ab2004-07-08 01:45:30 +0000648static IRExpr* binop ( IROp op, IRExpr* a1, IRExpr* a2 )
649{
650 return IRExpr_Binop(op, a1, a2);
651}
652
sewardjf1b5b1a2006-02-03 22:54:17 +0000653static IRExpr* triop ( IROp op, IRExpr* a1, IRExpr* a2, IRExpr* a3 )
654{
655 return IRExpr_Triop(op, a1, a2, a3);
656}
657
sewardjd1061ab2004-07-08 01:45:30 +0000658static IRExpr* mkexpr ( IRTemp tmp )
659{
sewardjdd40fdf2006-12-24 02:20:24 +0000660 return IRExpr_RdTmp(tmp);
sewardjd1061ab2004-07-08 01:45:30 +0000661}
662
sewardjc2ac51e2004-07-12 01:03:26 +0000663static IRExpr* mkU8 ( UInt i )
664{
665 vassert(i < 256);
sewardj2d49b432005-02-01 00:37:06 +0000666 return IRExpr_Const(IRConst_U8( (UChar)i ));
sewardjc2ac51e2004-07-12 01:03:26 +0000667}
668
669static IRExpr* mkU16 ( UInt i )
670{
671 vassert(i < 65536);
sewardj2d49b432005-02-01 00:37:06 +0000672 return IRExpr_Const(IRConst_U16( (UShort)i ));
sewardjc2ac51e2004-07-12 01:03:26 +0000673}
674
sewardjd1061ab2004-07-08 01:45:30 +0000675static IRExpr* mkU32 ( UInt i )
676{
677 return IRExpr_Const(IRConst_U32(i));
sewardjc9a65702004-07-07 16:32:57 +0000678}
679
sewardj95535fe2004-12-15 17:42:58 +0000680static IRExpr* mkU64 ( ULong i )
681{
682 return IRExpr_Const(IRConst_U64(i));
683}
684
sewardj41f43bc2004-07-08 14:23:22 +0000685static IRExpr* mkU ( IRType ty, UInt i )
686{
sewardjc2ac51e2004-07-12 01:03:26 +0000687 if (ty == Ity_I8) return mkU8(i);
688 if (ty == Ity_I16) return mkU16(i);
689 if (ty == Ity_I32) return mkU32(i);
sewardje90ad6a2004-07-10 19:02:10 +0000690 /* If this panics, it usually means you passed a size (1,2,4)
691 value as the IRType, rather than a real IRType. */
sewardj41f43bc2004-07-08 14:23:22 +0000692 vpanic("mkU(x86)");
693}
694
sewardj1e6ad742004-12-02 16:16:11 +0000695static IRExpr* mkV128 ( UShort mask )
696{
697 return IRExpr_Const(IRConst_V128(mask));
698}
699
sewardje768e922009-11-26 17:17:37 +0000700static IRExpr* loadLE ( IRType ty, IRExpr* addr )
sewardj41f43bc2004-07-08 14:23:22 +0000701{
sewardje768e922009-11-26 17:17:37 +0000702 return IRExpr_Load(Iend_LE, ty, addr);
sewardj41f43bc2004-07-08 14:23:22 +0000703}
704
705static IROp mkSizedOp ( IRType ty, IROp op8 )
706{
sewardje05c42c2004-07-08 20:25:10 +0000707 Int adj;
sewardj41f43bc2004-07-08 14:23:22 +0000708 vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32);
709 vassert(op8 == Iop_Add8 || op8 == Iop_Sub8
sewardj41f43bc2004-07-08 14:23:22 +0000710 || op8 == Iop_Mul8
711 || op8 == Iop_Or8 || op8 == Iop_And8 || op8 == Iop_Xor8
sewardj5bd4d162004-11-10 13:02:48 +0000712 || op8 == Iop_Shl8 || op8 == Iop_Shr8 || op8 == Iop_Sar8
sewardje90ad6a2004-07-10 19:02:10 +0000713 || op8 == Iop_CmpEQ8 || op8 == Iop_CmpNE8
sewardj1fb8c922009-07-12 12:56:53 +0000714 || op8 == Iop_CasCmpNE8
sewardje13074c2012-11-08 10:57:08 +0000715 || op8 == Iop_ExpCmpNE8
sewardjeb17e492007-08-25 23:07:44 +0000716 || op8 == Iop_Not8);
sewardje05c42c2004-07-08 20:25:10 +0000717 adj = ty==Ity_I8 ? 0 : (ty==Ity_I16 ? 1 : 2);
718 return adj + op8;
sewardj41f43bc2004-07-08 14:23:22 +0000719}
720
sewardj9334b0f2004-07-10 22:43:54 +0000721static IROp mkWidenOp ( Int szSmall, Int szBig, Bool signd )
sewardj41f43bc2004-07-08 14:23:22 +0000722{
sewardj9334b0f2004-07-10 22:43:54 +0000723 if (szSmall == 1 && szBig == 4) {
724 return signd ? Iop_8Sto32 : Iop_8Uto32;
sewardj41f43bc2004-07-08 14:23:22 +0000725 }
sewardj9334b0f2004-07-10 22:43:54 +0000726 if (szSmall == 1 && szBig == 2) {
727 return signd ? Iop_8Sto16 : Iop_8Uto16;
728 }
729 if (szSmall == 2 && szBig == 4) {
730 return signd ? Iop_16Sto32 : Iop_16Uto32;
731 }
sewardj948d48b2004-11-05 19:49:09 +0000732 vpanic("mkWidenOp(x86,guest)");
sewardj41f43bc2004-07-08 14:23:22 +0000733}
734
sewardjbaa66082005-08-23 17:29:27 +0000735static IRExpr* mkAnd1 ( IRExpr* x, IRExpr* y )
736{
sewardjdd40fdf2006-12-24 02:20:24 +0000737 vassert(typeOfIRExpr(irsb->tyenv,x) == Ity_I1);
738 vassert(typeOfIRExpr(irsb->tyenv,y) == Ity_I1);
sewardjbaa66082005-08-23 17:29:27 +0000739 return unop(Iop_32to1,
740 binop(Iop_And32,
741 unop(Iop_1Uto32,x),
742 unop(Iop_1Uto32,y)));
743}
744
sewardje9d8a262009-07-01 08:06:34 +0000745/* Generate a compare-and-swap operation, operating on memory at
746 'addr'. The expected value is 'expVal' and the new value is
747 'newVal'. If the operation fails, then transfer control (with a
748 no-redir jump (XXX no -- see comment at top of this file)) to
749 'restart_point', which is presumably the address of the guest
750 instruction again -- retrying, essentially. */
751static void casLE ( IRExpr* addr, IRExpr* expVal, IRExpr* newVal,
752 Addr32 restart_point )
753{
754 IRCAS* cas;
755 IRType tyE = typeOfIRExpr(irsb->tyenv, expVal);
756 IRType tyN = typeOfIRExpr(irsb->tyenv, newVal);
757 IRTemp oldTmp = newTemp(tyE);
758 IRTemp expTmp = newTemp(tyE);
759 vassert(tyE == tyN);
760 vassert(tyE == Ity_I32 || tyE == Ity_I16 || tyE == Ity_I8);
761 assign(expTmp, expVal);
762 cas = mkIRCAS( IRTemp_INVALID, oldTmp, Iend_LE, addr,
763 NULL, mkexpr(expTmp), NULL, newVal );
764 stmt( IRStmt_CAS(cas) );
765 stmt( IRStmt_Exit(
sewardj1fb8c922009-07-12 12:56:53 +0000766 binop( mkSizedOp(tyE,Iop_CasCmpNE8),
767 mkexpr(oldTmp), mkexpr(expTmp) ),
sewardje9d8a262009-07-01 08:06:34 +0000768 Ijk_Boring, /*Ijk_NoRedir*/
sewardjc6f970f2012-04-02 21:54:49 +0000769 IRConst_U32( restart_point ),
770 OFFB_EIP
sewardje9d8a262009-07-01 08:06:34 +0000771 ));
772}
773
sewardj41f43bc2004-07-08 14:23:22 +0000774
775/*------------------------------------------------------------*/
776/*--- Helpers for %eflags. ---*/
777/*------------------------------------------------------------*/
778
sewardj0611d802004-07-11 02:37:54 +0000779/* -------------- Evaluating the flags-thunk. -------------- */
sewardjc9a65702004-07-07 16:32:57 +0000780
sewardje87b4842004-07-10 12:23:30 +0000781/* Build IR to calculate all the eflags from stored
sewardj2a2ba8b2004-11-08 13:14:06 +0000782 CC_OP/CC_DEP1/CC_DEP2/CC_NDEP. Returns an expression ::
783 Ity_I32. */
sewardj2a9ad022004-11-25 02:46:58 +0000784static IRExpr* mk_x86g_calculate_eflags_all ( void )
sewardje87b4842004-07-10 12:23:30 +0000785{
sewardjf9655262004-10-31 20:02:16 +0000786 IRExpr** args
sewardj2a2ba8b2004-11-08 13:14:06 +0000787 = mkIRExprVec_4( IRExpr_Get(OFFB_CC_OP, Ity_I32),
788 IRExpr_Get(OFFB_CC_DEP1, Ity_I32),
789 IRExpr_Get(OFFB_CC_DEP2, Ity_I32),
790 IRExpr_Get(OFFB_CC_NDEP, Ity_I32) );
sewardj43c56462004-11-06 12:17:57 +0000791 IRExpr* call
792 = mkIRExprCCall(
793 Ity_I32,
794 0/*regparm*/,
sewardj2a9ad022004-11-25 02:46:58 +0000795 "x86g_calculate_eflags_all", &x86g_calculate_eflags_all,
sewardj43c56462004-11-06 12:17:57 +0000796 args
797 );
sewardj2a2ba8b2004-11-08 13:14:06 +0000798 /* Exclude OP and NDEP from definedness checking. We're only
799 interested in DEP1 and DEP2. */
800 call->Iex.CCall.cee->mcx_mask = (1<<0) | (1<<3);
sewardj43c56462004-11-06 12:17:57 +0000801 return call;
sewardje87b4842004-07-10 12:23:30 +0000802}
803
sewardj84ff0652004-08-23 16:16:08 +0000804/* Build IR to calculate some particular condition from stored
sewardj2a2ba8b2004-11-08 13:14:06 +0000805 CC_OP/CC_DEP1/CC_DEP2/CC_NDEP. Returns an expression ::
806 Ity_Bit. */
sewardj2a9ad022004-11-25 02:46:58 +0000807static IRExpr* mk_x86g_calculate_condition ( X86Condcode cond )
sewardj84ff0652004-08-23 16:16:08 +0000808{
sewardjf9655262004-10-31 20:02:16 +0000809 IRExpr** args
sewardj2a2ba8b2004-11-08 13:14:06 +0000810 = mkIRExprVec_5( mkU32(cond),
sewardjf9655262004-10-31 20:02:16 +0000811 IRExpr_Get(OFFB_CC_OP, Ity_I32),
sewardj2a2ba8b2004-11-08 13:14:06 +0000812 IRExpr_Get(OFFB_CC_DEP1, Ity_I32),
813 IRExpr_Get(OFFB_CC_DEP2, Ity_I32),
814 IRExpr_Get(OFFB_CC_NDEP, Ity_I32) );
sewardj43c56462004-11-06 12:17:57 +0000815 IRExpr* call
816 = mkIRExprCCall(
817 Ity_I32,
818 0/*regparm*/,
sewardj2a9ad022004-11-25 02:46:58 +0000819 "x86g_calculate_condition", &x86g_calculate_condition,
sewardj43c56462004-11-06 12:17:57 +0000820 args
821 );
sewardj2a2ba8b2004-11-08 13:14:06 +0000822 /* Exclude the requested condition, OP and NDEP from definedness
823 checking. We're only interested in DEP1 and DEP2. */
824 call->Iex.CCall.cee->mcx_mask = (1<<0) | (1<<1) | (1<<4);
sewardj43c56462004-11-06 12:17:57 +0000825 return unop(Iop_32to1, call);
826}
827
828/* Build IR to calculate just the carry flag from stored
sewardj2a2ba8b2004-11-08 13:14:06 +0000829 CC_OP/CC_DEP1/CC_DEP2/CC_NDEP. Returns an expression :: Ity_I32. */
sewardj2a9ad022004-11-25 02:46:58 +0000830static IRExpr* mk_x86g_calculate_eflags_c ( void )
sewardj43c56462004-11-06 12:17:57 +0000831{
832 IRExpr** args
sewardj2a2ba8b2004-11-08 13:14:06 +0000833 = mkIRExprVec_4( IRExpr_Get(OFFB_CC_OP, Ity_I32),
834 IRExpr_Get(OFFB_CC_DEP1, Ity_I32),
835 IRExpr_Get(OFFB_CC_DEP2, Ity_I32),
836 IRExpr_Get(OFFB_CC_NDEP, Ity_I32) );
sewardj43c56462004-11-06 12:17:57 +0000837 IRExpr* call
838 = mkIRExprCCall(
839 Ity_I32,
sewardj893a3302005-01-24 10:49:02 +0000840 3/*regparm*/,
sewardj2a9ad022004-11-25 02:46:58 +0000841 "x86g_calculate_eflags_c", &x86g_calculate_eflags_c,
sewardj43c56462004-11-06 12:17:57 +0000842 args
843 );
sewardj2a2ba8b2004-11-08 13:14:06 +0000844 /* Exclude OP and NDEP from definedness checking. We're only
845 interested in DEP1 and DEP2. */
846 call->Iex.CCall.cee->mcx_mask = (1<<0) | (1<<3);
sewardj43c56462004-11-06 12:17:57 +0000847 return call;
sewardj84ff0652004-08-23 16:16:08 +0000848}
849
sewardje87b4842004-07-10 12:23:30 +0000850
sewardj0611d802004-07-11 02:37:54 +0000851/* -------------- Building the flags-thunk. -------------- */
852
sewardjb9c5cf62004-08-24 15:10:38 +0000853/* The machinery in this section builds the flag-thunk following a
854 flag-setting operation. Hence the various setFlags_* functions.
sewardjb9c5cf62004-08-24 15:10:38 +0000855*/
856
857static Bool isAddSub ( IROp op8 )
858{
sewardj2d49b432005-02-01 00:37:06 +0000859 return toBool(op8 == Iop_Add8 || op8 == Iop_Sub8);
sewardjb9c5cf62004-08-24 15:10:38 +0000860}
sewardj0611d802004-07-11 02:37:54 +0000861
sewardj2a2ba8b2004-11-08 13:14:06 +0000862static Bool isLogic ( IROp op8 )
863{
sewardj2d49b432005-02-01 00:37:06 +0000864 return toBool(op8 == Iop_And8 || op8 == Iop_Or8 || op8 == Iop_Xor8);
sewardj2a2ba8b2004-11-08 13:14:06 +0000865}
866
sewardja2384712004-07-29 14:36:40 +0000867/* U-widen 8/16/32 bit int expr to 32. */
sewardjc22a6fd2004-07-29 23:41:47 +0000868static IRExpr* widenUto32 ( IRExpr* e )
sewardj443cd9d2004-07-18 23:06:45 +0000869{
sewardjdd40fdf2006-12-24 02:20:24 +0000870 switch (typeOfIRExpr(irsb->tyenv,e)) {
sewardj443cd9d2004-07-18 23:06:45 +0000871 case Ity_I32: return e;
872 case Ity_I16: return unop(Iop_16Uto32,e);
873 case Ity_I8: return unop(Iop_8Uto32,e);
874 default: vpanic("widenUto32");
875 }
876}
877
sewardjc22a6fd2004-07-29 23:41:47 +0000878/* S-widen 8/16/32 bit int expr to 32. */
879static IRExpr* widenSto32 ( IRExpr* e )
880{
sewardjdd40fdf2006-12-24 02:20:24 +0000881 switch (typeOfIRExpr(irsb->tyenv,e)) {
sewardjc22a6fd2004-07-29 23:41:47 +0000882 case Ity_I32: return e;
883 case Ity_I16: return unop(Iop_16Sto32,e);
884 case Ity_I8: return unop(Iop_8Sto32,e);
885 default: vpanic("widenSto32");
886 }
887}
888
sewardja2384712004-07-29 14:36:40 +0000889/* Narrow 8/16/32 bit int expr to 8/16/32. Clearly only some
890 of these combinations make sense. */
891static IRExpr* narrowTo ( IRType dst_ty, IRExpr* e )
892{
sewardjdd40fdf2006-12-24 02:20:24 +0000893 IRType src_ty = typeOfIRExpr(irsb->tyenv,e);
sewardja2384712004-07-29 14:36:40 +0000894 if (src_ty == dst_ty)
895 return e;
896 if (src_ty == Ity_I32 && dst_ty == Ity_I16)
897 return unop(Iop_32to16, e);
898 if (src_ty == Ity_I32 && dst_ty == Ity_I8)
899 return unop(Iop_32to8, e);
900
901 vex_printf("\nsrc, dst tys are: ");
902 ppIRType(src_ty);
903 vex_printf(", ");
904 ppIRType(dst_ty);
905 vex_printf("\n");
906 vpanic("narrowTo(x86)");
907}
908
sewardj443cd9d2004-07-18 23:06:45 +0000909
sewardj2a2ba8b2004-11-08 13:14:06 +0000910/* Set the flags thunk OP, DEP1 and DEP2 fields. The supplied op is
sewardj948d48b2004-11-05 19:49:09 +0000911 auto-sized up to the real op. */
sewardj0611d802004-07-11 02:37:54 +0000912
sewardj2a2ba8b2004-11-08 13:14:06 +0000913static
914void setFlags_DEP1_DEP2 ( IROp op8, IRTemp dep1, IRTemp dep2, IRType ty )
sewardj0611d802004-07-11 02:37:54 +0000915{
sewardjb9c5cf62004-08-24 15:10:38 +0000916 Int ccOp = ty==Ity_I8 ? 0 : (ty==Ity_I16 ? 1 : 2);
917
918 vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32);
919
920 switch (op8) {
sewardj2a9ad022004-11-25 02:46:58 +0000921 case Iop_Add8: ccOp += X86G_CC_OP_ADDB; break;
922 case Iop_Sub8: ccOp += X86G_CC_OP_SUBB; break;
sewardjb9c5cf62004-08-24 15:10:38 +0000923 default: ppIROp(op8);
sewardj2a2ba8b2004-11-08 13:14:06 +0000924 vpanic("setFlags_DEP1_DEP2(x86)");
sewardjb9c5cf62004-08-24 15:10:38 +0000925 }
sewardj2a2ba8b2004-11-08 13:14:06 +0000926 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(ccOp)) );
927 stmt( IRStmt_Put( OFFB_CC_DEP1, widenUto32(mkexpr(dep1))) );
928 stmt( IRStmt_Put( OFFB_CC_DEP2, widenUto32(mkexpr(dep2))) );
sewardja3b7e3a2005-04-05 01:54:19 +0000929 /* Set NDEP even though it isn't used. This makes redundant-PUT
930 elimination of previous stores to this field work better. */
931 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
sewardjb9c5cf62004-08-24 15:10:38 +0000932}
933
934
sewardj2a2ba8b2004-11-08 13:14:06 +0000935/* Set the OP and DEP1 fields only, and write zero to DEP2. */
sewardjb9c5cf62004-08-24 15:10:38 +0000936
sewardj2a2ba8b2004-11-08 13:14:06 +0000937static
938void setFlags_DEP1 ( IROp op8, IRTemp dep1, IRType ty )
sewardjb9c5cf62004-08-24 15:10:38 +0000939{
940 Int ccOp = ty==Ity_I8 ? 0 : (ty==Ity_I16 ? 1 : 2);
sewardj0611d802004-07-11 02:37:54 +0000941
942 vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32);
943
944 switch (op8) {
945 case Iop_Or8:
946 case Iop_And8:
sewardj2a9ad022004-11-25 02:46:58 +0000947 case Iop_Xor8: ccOp += X86G_CC_OP_LOGICB; break;
sewardj0611d802004-07-11 02:37:54 +0000948 default: ppIROp(op8);
sewardj2a2ba8b2004-11-08 13:14:06 +0000949 vpanic("setFlags_DEP1(x86)");
sewardj0611d802004-07-11 02:37:54 +0000950 }
sewardj2a2ba8b2004-11-08 13:14:06 +0000951 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(ccOp)) );
952 stmt( IRStmt_Put( OFFB_CC_DEP1, widenUto32(mkexpr(dep1))) );
953 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0)) );
sewardja3b7e3a2005-04-05 01:54:19 +0000954 /* Set NDEP even though it isn't used. This makes redundant-PUT
955 elimination of previous stores to this field work better. */
956 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
sewardj0611d802004-07-11 02:37:54 +0000957}
958
959
sewardj948d48b2004-11-05 19:49:09 +0000960/* For shift operations, we put in the result and the undershifted
961 result. Except if the shift amount is zero, the thunk is left
962 unchanged. */
sewardj0611d802004-07-11 02:37:54 +0000963
sewardj2a2ba8b2004-11-08 13:14:06 +0000964static void setFlags_DEP1_DEP2_shift ( IROp op32,
965 IRTemp res,
966 IRTemp resUS,
967 IRType ty,
968 IRTemp guard )
sewardj0611d802004-07-11 02:37:54 +0000969{
sewardjc22a6fd2004-07-29 23:41:47 +0000970 Int ccOp = ty==Ity_I8 ? 2 : (ty==Ity_I16 ? 1 : 0);
sewardj0611d802004-07-11 02:37:54 +0000971
972 vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32);
973 vassert(guard);
974
sewardj2a2ba8b2004-11-08 13:14:06 +0000975 /* Both kinds of right shifts are handled by the same thunk
976 operation. */
sewardjc22a6fd2004-07-29 23:41:47 +0000977 switch (op32) {
978 case Iop_Shr32:
sewardj2a9ad022004-11-25 02:46:58 +0000979 case Iop_Sar32: ccOp = X86G_CC_OP_SHRL - ccOp; break;
980 case Iop_Shl32: ccOp = X86G_CC_OP_SHLL - ccOp; break;
sewardjc22a6fd2004-07-29 23:41:47 +0000981 default: ppIROp(op32);
sewardj2a2ba8b2004-11-08 13:14:06 +0000982 vpanic("setFlags_DEP1_DEP2_shift(x86)");
sewardj0611d802004-07-11 02:37:54 +0000983 }
984
sewardj009230b2013-01-26 11:47:55 +0000985 /* guard :: Ity_I8. We need to convert it to I1. */
986 IRTemp guardB = newTemp(Ity_I1);
987 assign( guardB, binop(Iop_CmpNE8, mkexpr(guard), mkU8(0)) );
988
sewardj2a2ba8b2004-11-08 13:14:06 +0000989 /* DEP1 contains the result, DEP2 contains the undershifted value. */
sewardjeeb9ef82004-07-15 12:39:03 +0000990 stmt( IRStmt_Put( OFFB_CC_OP,
florian99dd03e2013-01-29 03:56:06 +0000991 IRExpr_ITE( mkexpr(guardB),
992 mkU32(ccOp),
993 IRExpr_Get(OFFB_CC_OP,Ity_I32) ) ));
sewardj2a2ba8b2004-11-08 13:14:06 +0000994 stmt( IRStmt_Put( OFFB_CC_DEP1,
florian99dd03e2013-01-29 03:56:06 +0000995 IRExpr_ITE( mkexpr(guardB),
996 widenUto32(mkexpr(res)),
997 IRExpr_Get(OFFB_CC_DEP1,Ity_I32) ) ));
sewardj2a2ba8b2004-11-08 13:14:06 +0000998 stmt( IRStmt_Put( OFFB_CC_DEP2,
florian99dd03e2013-01-29 03:56:06 +0000999 IRExpr_ITE( mkexpr(guardB),
1000 widenUto32(mkexpr(resUS)),
1001 IRExpr_Get(OFFB_CC_DEP2,Ity_I32) ) ));
sewardja3b7e3a2005-04-05 01:54:19 +00001002 /* Set NDEP even though it isn't used. This makes redundant-PUT
1003 elimination of previous stores to this field work better. */
sewardj17b0e212011-03-26 07:28:51 +00001004 stmt( IRStmt_Put( OFFB_CC_NDEP,
florian99dd03e2013-01-29 03:56:06 +00001005 IRExpr_ITE( mkexpr(guardB),
1006 mkU32(0),
1007 IRExpr_Get(OFFB_CC_NDEP,Ity_I32) ) ));
sewardj0611d802004-07-11 02:37:54 +00001008}
1009
1010
sewardj2a2ba8b2004-11-08 13:14:06 +00001011/* For the inc/dec case, we store in DEP1 the result value and in NDEP
sewardj948d48b2004-11-05 19:49:09 +00001012 the former value of the carry flag, which unfortunately we have to
1013 compute. */
sewardj0611d802004-07-11 02:37:54 +00001014
sewardj948d48b2004-11-05 19:49:09 +00001015static void setFlags_INC_DEC ( Bool inc, IRTemp res, IRType ty )
sewardj0611d802004-07-11 02:37:54 +00001016{
sewardj2a9ad022004-11-25 02:46:58 +00001017 Int ccOp = inc ? X86G_CC_OP_INCB : X86G_CC_OP_DECB;
sewardj0611d802004-07-11 02:37:54 +00001018
1019 ccOp += ty==Ity_I8 ? 0 : (ty==Ity_I16 ? 1 : 2);
1020 vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32);
1021
1022 /* This has to come first, because calculating the C flag
sewardj2a2ba8b2004-11-08 13:14:06 +00001023 may require reading all four thunk fields. */
sewardj2a9ad022004-11-25 02:46:58 +00001024 stmt( IRStmt_Put( OFFB_CC_NDEP, mk_x86g_calculate_eflags_c()) );
sewardj2a2ba8b2004-11-08 13:14:06 +00001025 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(ccOp)) );
sewardj478646f2008-05-01 20:13:04 +00001026 stmt( IRStmt_Put( OFFB_CC_DEP1, widenUto32(mkexpr(res))) );
sewardj2a2ba8b2004-11-08 13:14:06 +00001027 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0)) );
sewardj0611d802004-07-11 02:37:54 +00001028}
1029
1030
sewardj2a2ba8b2004-11-08 13:14:06 +00001031/* Multiplies are pretty much like add and sub: DEP1 and DEP2 hold the
1032 two arguments. */
sewardjcf780b42004-07-13 18:42:17 +00001033
1034static
sewardj2a2ba8b2004-11-08 13:14:06 +00001035void setFlags_MUL ( IRType ty, IRTemp arg1, IRTemp arg2, UInt base_op )
sewardjcf780b42004-07-13 18:42:17 +00001036{
1037 switch (ty) {
sewardj2a2ba8b2004-11-08 13:14:06 +00001038 case Ity_I8:
1039 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(base_op+0) ) );
1040 break;
1041 case Ity_I16:
1042 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(base_op+1) ) );
1043 break;
1044 case Ity_I32:
1045 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(base_op+2) ) );
1046 break;
1047 default:
1048 vpanic("setFlags_MUL(x86)");
sewardjcf780b42004-07-13 18:42:17 +00001049 }
sewardj2a2ba8b2004-11-08 13:14:06 +00001050 stmt( IRStmt_Put( OFFB_CC_DEP1, widenUto32(mkexpr(arg1)) ));
1051 stmt( IRStmt_Put( OFFB_CC_DEP2, widenUto32(mkexpr(arg2)) ));
sewardja3b7e3a2005-04-05 01:54:19 +00001052 /* Set NDEP even though it isn't used. This makes redundant-PUT
1053 elimination of previous stores to this field work better. */
1054 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
sewardjcf780b42004-07-13 18:42:17 +00001055}
1056
1057
sewardj3af115f2004-07-14 02:46:52 +00001058/* -------------- Condition codes. -------------- */
1059
sewardje87b4842004-07-10 12:23:30 +00001060/* Condition codes, using the Intel encoding. */
sewardj0611d802004-07-11 02:37:54 +00001061
florian55085f82012-11-21 00:36:55 +00001062static const HChar* name_X86Condcode ( X86Condcode cond )
sewardje87b4842004-07-10 12:23:30 +00001063{
1064 switch (cond) {
sewardj2a9ad022004-11-25 02:46:58 +00001065 case X86CondO: return "o";
1066 case X86CondNO: return "no";
1067 case X86CondB: return "b";
1068 case X86CondNB: return "nb";
1069 case X86CondZ: return "z";
1070 case X86CondNZ: return "nz";
1071 case X86CondBE: return "be";
1072 case X86CondNBE: return "nbe";
1073 case X86CondS: return "s";
1074 case X86CondNS: return "ns";
1075 case X86CondP: return "p";
1076 case X86CondNP: return "np";
1077 case X86CondL: return "l";
1078 case X86CondNL: return "nl";
1079 case X86CondLE: return "le";
1080 case X86CondNLE: return "nle";
1081 case X86CondAlways: return "ALWAYS";
1082 default: vpanic("name_X86Condcode");
sewardje87b4842004-07-10 12:23:30 +00001083 }
1084}
1085
sewardj2a9ad022004-11-25 02:46:58 +00001086static
1087X86Condcode positiveIse_X86Condcode ( X86Condcode cond,
sewardjdbf550c2005-01-24 11:54:11 +00001088 Bool* needInvert )
sewardje87b4842004-07-10 12:23:30 +00001089{
sewardj2a9ad022004-11-25 02:46:58 +00001090 vassert(cond >= X86CondO && cond <= X86CondNLE);
sewardje87b4842004-07-10 12:23:30 +00001091 if (cond & 1) {
1092 *needInvert = True;
1093 return cond-1;
1094 } else {
1095 *needInvert = False;
1096 return cond;
1097 }
1098}
1099
1100
sewardj3af115f2004-07-14 02:46:52 +00001101/* -------------- Helpers for ADD/SUB with carry. -------------- */
1102
sewardj948d48b2004-11-05 19:49:09 +00001103/* Given ta1, ta2 and tres, compute tres = ADC(ta1,ta2) and set flags
sewardj2a2ba8b2004-11-08 13:14:06 +00001104 appropriately.
sewardje9d8a262009-07-01 08:06:34 +00001105
1106 Optionally, generate a store for the 'tres' value. This can either
1107 be a normal store, or it can be a cas-with-possible-failure style
1108 store:
1109
1110 if taddr is IRTemp_INVALID, then no store is generated.
1111
1112 if taddr is not IRTemp_INVALID, then a store (using taddr as
1113 the address) is generated:
1114
1115 if texpVal is IRTemp_INVALID then a normal store is
1116 generated, and restart_point must be zero (it is irrelevant).
1117
1118 if texpVal is not IRTemp_INVALID then a cas-style store is
1119 generated. texpVal is the expected value, restart_point
1120 is the restart point if the store fails, and texpVal must
1121 have the same type as tres.
sewardj3af115f2004-07-14 02:46:52 +00001122*/
1123static void helper_ADC ( Int sz,
sewardje9d8a262009-07-01 08:06:34 +00001124 IRTemp tres, IRTemp ta1, IRTemp ta2,
1125 /* info about optional store: */
1126 IRTemp taddr, IRTemp texpVal, Addr32 restart_point )
sewardj3af115f2004-07-14 02:46:52 +00001127{
1128 UInt thunkOp;
sewardj2a2ba8b2004-11-08 13:14:06 +00001129 IRType ty = szToITy(sz);
1130 IRTemp oldc = newTemp(Ity_I32);
1131 IRTemp oldcn = newTemp(ty);
1132 IROp plus = mkSizedOp(ty, Iop_Add8);
1133 IROp xor = mkSizedOp(ty, Iop_Xor8);
sewardja2384712004-07-29 14:36:40 +00001134
sewardje9d8a262009-07-01 08:06:34 +00001135 vassert(typeOfIRTemp(irsb->tyenv, tres) == ty);
sewardja2384712004-07-29 14:36:40 +00001136 vassert(sz == 1 || sz == 2 || sz == 4);
sewardj2a9ad022004-11-25 02:46:58 +00001137 thunkOp = sz==4 ? X86G_CC_OP_ADCL
1138 : (sz==2 ? X86G_CC_OP_ADCW : X86G_CC_OP_ADCB);
sewardj3af115f2004-07-14 02:46:52 +00001139
sewardj2a2ba8b2004-11-08 13:14:06 +00001140 /* oldc = old carry flag, 0 or 1 */
1141 assign( oldc, binop(Iop_And32,
sewardj2a9ad022004-11-25 02:46:58 +00001142 mk_x86g_calculate_eflags_c(),
sewardj5bd4d162004-11-10 13:02:48 +00001143 mkU32(1)) );
sewardj3af115f2004-07-14 02:46:52 +00001144
sewardj2a2ba8b2004-11-08 13:14:06 +00001145 assign( oldcn, narrowTo(ty, mkexpr(oldc)) );
1146
1147 assign( tres, binop(plus,
1148 binop(plus,mkexpr(ta1),mkexpr(ta2)),
1149 mkexpr(oldcn)) );
1150
sewardje9d8a262009-07-01 08:06:34 +00001151 /* Possibly generate a store of 'tres' to 'taddr'. See comment at
1152 start of this function. */
1153 if (taddr != IRTemp_INVALID) {
1154 if (texpVal == IRTemp_INVALID) {
1155 vassert(restart_point == 0);
1156 storeLE( mkexpr(taddr), mkexpr(tres) );
1157 } else {
1158 vassert(typeOfIRTemp(irsb->tyenv, texpVal) == ty);
1159 /* .. and hence 'texpVal' has the same type as 'tres'. */
1160 casLE( mkexpr(taddr),
1161 mkexpr(texpVal), mkexpr(tres), restart_point );
1162 }
1163 }
1164
sewardj2a2ba8b2004-11-08 13:14:06 +00001165 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(thunkOp) ) );
sewardj3b3eacd2005-08-24 10:01:36 +00001166 stmt( IRStmt_Put( OFFB_CC_DEP1, widenUto32(mkexpr(ta1)) ));
1167 stmt( IRStmt_Put( OFFB_CC_DEP2, widenUto32(binop(xor, mkexpr(ta2),
1168 mkexpr(oldcn)) )) );
sewardj2a2ba8b2004-11-08 13:14:06 +00001169 stmt( IRStmt_Put( OFFB_CC_NDEP, mkexpr(oldc) ) );
sewardj3af115f2004-07-14 02:46:52 +00001170}
1171
1172
sewardj948d48b2004-11-05 19:49:09 +00001173/* Given ta1, ta2 and tres, compute tres = SBB(ta1,ta2) and set flags
sewardje9d8a262009-07-01 08:06:34 +00001174 appropriately. As with helper_ADC, possibly generate a store of
1175 the result -- see comments on helper_ADC for details.
sewardjcaca9d02004-07-28 07:11:32 +00001176*/
1177static void helper_SBB ( Int sz,
sewardje9d8a262009-07-01 08:06:34 +00001178 IRTemp tres, IRTemp ta1, IRTemp ta2,
1179 /* info about optional store: */
1180 IRTemp taddr, IRTemp texpVal, Addr32 restart_point )
sewardjcaca9d02004-07-28 07:11:32 +00001181{
1182 UInt thunkOp;
sewardj2a2ba8b2004-11-08 13:14:06 +00001183 IRType ty = szToITy(sz);
1184 IRTemp oldc = newTemp(Ity_I32);
1185 IRTemp oldcn = newTemp(ty);
1186 IROp minus = mkSizedOp(ty, Iop_Sub8);
1187 IROp xor = mkSizedOp(ty, Iop_Xor8);
1188
sewardje9d8a262009-07-01 08:06:34 +00001189 vassert(typeOfIRTemp(irsb->tyenv, tres) == ty);
sewardj2a2ba8b2004-11-08 13:14:06 +00001190 vassert(sz == 1 || sz == 2 || sz == 4);
sewardj2a9ad022004-11-25 02:46:58 +00001191 thunkOp = sz==4 ? X86G_CC_OP_SBBL
1192 : (sz==2 ? X86G_CC_OP_SBBW : X86G_CC_OP_SBBB);
sewardjcaca9d02004-07-28 07:11:32 +00001193
1194 /* oldc = old carry flag, 0 or 1 */
sewardja2384712004-07-29 14:36:40 +00001195 assign( oldc, binop(Iop_And32,
sewardj2a9ad022004-11-25 02:46:58 +00001196 mk_x86g_calculate_eflags_c(),
sewardj5bd4d162004-11-10 13:02:48 +00001197 mkU32(1)) );
sewardjcaca9d02004-07-28 07:11:32 +00001198
sewardj2a2ba8b2004-11-08 13:14:06 +00001199 assign( oldcn, narrowTo(ty, mkexpr(oldc)) );
sewardja2384712004-07-29 14:36:40 +00001200
sewardj2a2ba8b2004-11-08 13:14:06 +00001201 assign( tres, binop(minus,
1202 binop(minus,mkexpr(ta1),mkexpr(ta2)),
1203 mkexpr(oldcn)) );
sewardjcaca9d02004-07-28 07:11:32 +00001204
sewardje9d8a262009-07-01 08:06:34 +00001205 /* Possibly generate a store of 'tres' to 'taddr'. See comment at
1206 start of this function. */
1207 if (taddr != IRTemp_INVALID) {
1208 if (texpVal == IRTemp_INVALID) {
1209 vassert(restart_point == 0);
1210 storeLE( mkexpr(taddr), mkexpr(tres) );
1211 } else {
1212 vassert(typeOfIRTemp(irsb->tyenv, texpVal) == ty);
1213 /* .. and hence 'texpVal' has the same type as 'tres'. */
1214 casLE( mkexpr(taddr),
1215 mkexpr(texpVal), mkexpr(tres), restart_point );
1216 }
1217 }
1218
sewardj2a2ba8b2004-11-08 13:14:06 +00001219 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(thunkOp) ) );
sewardj3b3eacd2005-08-24 10:01:36 +00001220 stmt( IRStmt_Put( OFFB_CC_DEP1, widenUto32(mkexpr(ta1) )) );
1221 stmt( IRStmt_Put( OFFB_CC_DEP2, widenUto32(binop(xor, mkexpr(ta2),
1222 mkexpr(oldcn)) )) );
sewardj2a2ba8b2004-11-08 13:14:06 +00001223 stmt( IRStmt_Put( OFFB_CC_NDEP, mkexpr(oldc) ) );
sewardjcaca9d02004-07-28 07:11:32 +00001224}
1225
1226
sewardj7dd2eb22005-01-05 10:38:54 +00001227/* -------------- Helpers for disassembly printing. -------------- */
sewardj41f43bc2004-07-08 14:23:22 +00001228
florian55085f82012-11-21 00:36:55 +00001229static const HChar* nameGrp1 ( Int opc_aux )
sewardj41f43bc2004-07-08 14:23:22 +00001230{
florian55085f82012-11-21 00:36:55 +00001231 static const HChar* grp1_names[8]
sewardj41f43bc2004-07-08 14:23:22 +00001232 = { "add", "or", "adc", "sbb", "and", "sub", "xor", "cmp" };
1233 if (opc_aux < 0 || opc_aux > 7) vpanic("nameGrp1(x86)");
1234 return grp1_names[opc_aux];
1235}
1236
florian55085f82012-11-21 00:36:55 +00001237static const HChar* nameGrp2 ( Int opc_aux )
sewardje90ad6a2004-07-10 19:02:10 +00001238{
florian55085f82012-11-21 00:36:55 +00001239 static const HChar* grp2_names[8]
sewardje90ad6a2004-07-10 19:02:10 +00001240 = { "rol", "ror", "rcl", "rcr", "shl", "shr", "shl", "sar" };
sewardjc2ac51e2004-07-12 01:03:26 +00001241 if (opc_aux < 0 || opc_aux > 7) vpanic("nameGrp2(x86)");
sewardje90ad6a2004-07-10 19:02:10 +00001242 return grp2_names[opc_aux];
1243}
1244
florian55085f82012-11-21 00:36:55 +00001245static const HChar* nameGrp4 ( Int opc_aux )
sewardjc2ac51e2004-07-12 01:03:26 +00001246{
florian55085f82012-11-21 00:36:55 +00001247 static const HChar* grp4_names[8]
sewardjc2ac51e2004-07-12 01:03:26 +00001248 = { "inc", "dec", "???", "???", "???", "???", "???", "???" };
1249 if (opc_aux < 0 || opc_aux > 1) vpanic("nameGrp4(x86)");
1250 return grp4_names[opc_aux];
1251}
sewardj0611d802004-07-11 02:37:54 +00001252
florian55085f82012-11-21 00:36:55 +00001253static const HChar* nameGrp5 ( Int opc_aux )
sewardj0611d802004-07-11 02:37:54 +00001254{
florian55085f82012-11-21 00:36:55 +00001255 static const HChar* grp5_names[8]
sewardj0611d802004-07-11 02:37:54 +00001256 = { "inc", "dec", "call*", "call*", "jmp*", "jmp*", "push", "???" };
1257 if (opc_aux < 0 || opc_aux > 6) vpanic("nameGrp5(x86)");
1258 return grp5_names[opc_aux];
1259}
1260
florian55085f82012-11-21 00:36:55 +00001261static const HChar* nameGrp8 ( Int opc_aux )
sewardj490ad382005-03-13 17:25:53 +00001262{
florian55085f82012-11-21 00:36:55 +00001263 static const HChar* grp8_names[8]
sewardj490ad382005-03-13 17:25:53 +00001264 = { "???", "???", "???", "???", "bt", "bts", "btr", "btc" };
1265 if (opc_aux < 4 || opc_aux > 7) vpanic("nameGrp8(x86)");
1266 return grp8_names[opc_aux];
1267}
sewardjc9a65702004-07-07 16:32:57 +00001268
florian55085f82012-11-21 00:36:55 +00001269static const HChar* nameIReg ( Int size, Int reg )
sewardjc9a65702004-07-07 16:32:57 +00001270{
florian55085f82012-11-21 00:36:55 +00001271 static const HChar* ireg32_names[8]
sewardjc9a65702004-07-07 16:32:57 +00001272 = { "%eax", "%ecx", "%edx", "%ebx",
1273 "%esp", "%ebp", "%esi", "%edi" };
florian55085f82012-11-21 00:36:55 +00001274 static const HChar* ireg16_names[8]
sewardjc9a65702004-07-07 16:32:57 +00001275 = { "%ax", "%cx", "%dx", "%bx", "%sp", "%bp", "%si", "%di" };
florian55085f82012-11-21 00:36:55 +00001276 static const HChar* ireg8_names[8]
sewardjc9a65702004-07-07 16:32:57 +00001277 = { "%al", "%cl", "%dl", "%bl",
1278 "%ah{sp}", "%ch{bp}", "%dh{si}", "%bh{di}" };
1279 if (reg < 0 || reg > 7) goto bad;
1280 switch (size) {
1281 case 4: return ireg32_names[reg];
1282 case 2: return ireg16_names[reg];
1283 case 1: return ireg8_names[reg];
1284 }
1285 bad:
1286 vpanic("nameIReg(X86)");
1287 return NULL; /*notreached*/
1288}
1289
florian55085f82012-11-21 00:36:55 +00001290static const HChar* nameSReg ( UInt sreg )
sewardj063f02f2004-10-20 12:36:12 +00001291{
1292 switch (sreg) {
1293 case R_ES: return "%es";
1294 case R_CS: return "%cs";
1295 case R_SS: return "%ss";
1296 case R_DS: return "%ds";
1297 case R_FS: return "%fs";
1298 case R_GS: return "%gs";
1299 default: vpanic("nameSReg(x86)");
1300 }
1301}
1302
florian55085f82012-11-21 00:36:55 +00001303static const HChar* nameMMXReg ( Int mmxreg )
sewardj464efa42004-11-19 22:17:29 +00001304{
florian55085f82012-11-21 00:36:55 +00001305 static const HChar* mmx_names[8]
sewardj464efa42004-11-19 22:17:29 +00001306 = { "%mm0", "%mm1", "%mm2", "%mm3", "%mm4", "%mm5", "%mm6", "%mm7" };
1307 if (mmxreg < 0 || mmxreg > 7) vpanic("nameMMXReg(x86,guest)");
1308 return mmx_names[mmxreg];
1309}
1310
florian55085f82012-11-21 00:36:55 +00001311static const HChar* nameXMMReg ( Int xmmreg )
sewardjc9a43662004-11-30 18:51:59 +00001312{
florian55085f82012-11-21 00:36:55 +00001313 static const HChar* xmm_names[8]
sewardjc9a43662004-11-30 18:51:59 +00001314 = { "%xmm0", "%xmm1", "%xmm2", "%xmm3",
1315 "%xmm4", "%xmm5", "%xmm6", "%xmm7" };
1316 if (xmmreg < 0 || xmmreg > 7) vpanic("name_of_xmm_reg");
1317 return xmm_names[xmmreg];
1318}
sewardj464efa42004-11-19 22:17:29 +00001319
florian55085f82012-11-21 00:36:55 +00001320static const HChar* nameMMXGran ( Int gran )
sewardj464efa42004-11-19 22:17:29 +00001321{
1322 switch (gran) {
1323 case 0: return "b";
1324 case 1: return "w";
1325 case 2: return "d";
1326 case 3: return "q";
1327 default: vpanic("nameMMXGran(x86,guest)");
1328 }
1329}
sewardjc9a65702004-07-07 16:32:57 +00001330
sewardj2d49b432005-02-01 00:37:06 +00001331static HChar nameISize ( Int size )
sewardjc9a65702004-07-07 16:32:57 +00001332{
1333 switch (size) {
1334 case 4: return 'l';
1335 case 2: return 'w';
1336 case 1: return 'b';
1337 default: vpanic("nameISize(x86)");
1338 }
1339}
1340
sewardjd1061ab2004-07-08 01:45:30 +00001341
1342/*------------------------------------------------------------*/
1343/*--- JMP helpers ---*/
1344/*------------------------------------------------------------*/
1345
sewardjc6f970f2012-04-02 21:54:49 +00001346static void jmp_lit( /*MOD*/DisResult* dres,
1347 IRJumpKind kind, Addr32 d32 )
sewardjd1061ab2004-07-08 01:45:30 +00001348{
sewardjc6f970f2012-04-02 21:54:49 +00001349 vassert(dres->whatNext == Dis_Continue);
1350 vassert(dres->len == 0);
1351 vassert(dres->continueAt == 0);
1352 vassert(dres->jk_StopHere == Ijk_INVALID);
1353 dres->whatNext = Dis_StopHere;
1354 dres->jk_StopHere = kind;
1355 stmt( IRStmt_Put( OFFB_EIP, mkU32(d32) ) );
sewardjd1061ab2004-07-08 01:45:30 +00001356}
1357
sewardjc6f970f2012-04-02 21:54:49 +00001358static void jmp_treg( /*MOD*/DisResult* dres,
1359 IRJumpKind kind, IRTemp t )
sewardje05c42c2004-07-08 20:25:10 +00001360{
sewardjc6f970f2012-04-02 21:54:49 +00001361 vassert(dres->whatNext == Dis_Continue);
1362 vassert(dres->len == 0);
1363 vassert(dres->continueAt == 0);
1364 vassert(dres->jk_StopHere == Ijk_INVALID);
1365 dres->whatNext = Dis_StopHere;
1366 dres->jk_StopHere = kind;
1367 stmt( IRStmt_Put( OFFB_EIP, mkexpr(t) ) );
sewardje05c42c2004-07-08 20:25:10 +00001368}
sewardje87b4842004-07-10 12:23:30 +00001369
sewardj2a9ad022004-11-25 02:46:58 +00001370static
sewardjc6f970f2012-04-02 21:54:49 +00001371void jcc_01( /*MOD*/DisResult* dres,
1372 X86Condcode cond, Addr32 d32_false, Addr32 d32_true )
sewardje87b4842004-07-10 12:23:30 +00001373{
sewardj2a9ad022004-11-25 02:46:58 +00001374 Bool invert;
1375 X86Condcode condPos;
sewardjc6f970f2012-04-02 21:54:49 +00001376 vassert(dres->whatNext == Dis_Continue);
1377 vassert(dres->len == 0);
1378 vassert(dres->continueAt == 0);
1379 vassert(dres->jk_StopHere == Ijk_INVALID);
1380 dres->whatNext = Dis_StopHere;
1381 dres->jk_StopHere = Ijk_Boring;
sewardj2a9ad022004-11-25 02:46:58 +00001382 condPos = positiveIse_X86Condcode ( cond, &invert );
sewardje87b4842004-07-10 12:23:30 +00001383 if (invert) {
sewardj2a9ad022004-11-25 02:46:58 +00001384 stmt( IRStmt_Exit( mk_x86g_calculate_condition(condPos),
sewardj893aada2004-11-29 19:57:54 +00001385 Ijk_Boring,
sewardjc6f970f2012-04-02 21:54:49 +00001386 IRConst_U32(d32_false),
1387 OFFB_EIP ) );
1388 stmt( IRStmt_Put( OFFB_EIP, mkU32(d32_true) ) );
sewardje87b4842004-07-10 12:23:30 +00001389 } else {
sewardj2a9ad022004-11-25 02:46:58 +00001390 stmt( IRStmt_Exit( mk_x86g_calculate_condition(condPos),
sewardj893aada2004-11-29 19:57:54 +00001391 Ijk_Boring,
sewardjc6f970f2012-04-02 21:54:49 +00001392 IRConst_U32(d32_true),
1393 OFFB_EIP ) );
1394 stmt( IRStmt_Put( OFFB_EIP, mkU32(d32_false) ) );
sewardje87b4842004-07-10 12:23:30 +00001395 }
1396}
sewardjc9a65702004-07-07 16:32:57 +00001397
1398
sewardjd1061ab2004-07-08 01:45:30 +00001399/*------------------------------------------------------------*/
1400/*--- Disassembling addressing modes ---*/
1401/*------------------------------------------------------------*/
sewardjc9a65702004-07-07 16:32:57 +00001402
sewardjd1061ab2004-07-08 01:45:30 +00001403static
florian55085f82012-11-21 00:36:55 +00001404const HChar* sorbTxt ( UChar sorb )
sewardjd1061ab2004-07-08 01:45:30 +00001405{
1406 switch (sorb) {
1407 case 0: return ""; /* no override */
1408 case 0x3E: return "%ds";
1409 case 0x26: return "%es:";
1410 case 0x64: return "%fs:";
1411 case 0x65: return "%gs:";
sewardj7df596b2004-12-06 14:29:12 +00001412 default: vpanic("sorbTxt(x86,guest)");
sewardjd1061ab2004-07-08 01:45:30 +00001413 }
1414}
1415
1416
sewardj7df596b2004-12-06 14:29:12 +00001417/* 'virtual' is an IRExpr* holding a virtual address. Convert it to a
1418 linear address by adding any required segment override as indicated
1419 by sorb. */
sewardjd1061ab2004-07-08 01:45:30 +00001420static
1421IRExpr* handleSegOverride ( UChar sorb, IRExpr* virtual )
1422{
sewardj3bd6f3e2004-12-13 10:48:19 +00001423 Int sreg;
1424 IRType hWordTy;
1425 IRTemp ldt_ptr, gdt_ptr, seg_selector, r64;
sewardjd1061ab2004-07-08 01:45:30 +00001426
1427 if (sorb == 0)
1428 /* the common case - no override */
1429 return virtual;
1430
sewardjd1061ab2004-07-08 01:45:30 +00001431 switch (sorb) {
1432 case 0x3E: sreg = R_DS; break;
1433 case 0x26: sreg = R_ES; break;
1434 case 0x64: sreg = R_FS; break;
1435 case 0x65: sreg = R_GS; break;
sewardj7df596b2004-12-06 14:29:12 +00001436 default: vpanic("handleSegOverride(x86,guest)");
sewardjd1061ab2004-07-08 01:45:30 +00001437 }
1438
sewardj3bd6f3e2004-12-13 10:48:19 +00001439 hWordTy = sizeof(HWord)==4 ? Ity_I32 : Ity_I64;
sewardjd1061ab2004-07-08 01:45:30 +00001440
sewardj3bd6f3e2004-12-13 10:48:19 +00001441 seg_selector = newTemp(Ity_I32);
1442 ldt_ptr = newTemp(hWordTy);
1443 gdt_ptr = newTemp(hWordTy);
1444 r64 = newTemp(Ity_I64);
sewardjd1061ab2004-07-08 01:45:30 +00001445
sewardj3bd6f3e2004-12-13 10:48:19 +00001446 assign( seg_selector, unop(Iop_16Uto32, getSReg(sreg)) );
1447 assign( ldt_ptr, IRExpr_Get( OFFB_LDT, hWordTy ));
1448 assign( gdt_ptr, IRExpr_Get( OFFB_GDT, hWordTy ));
sewardj7df596b2004-12-06 14:29:12 +00001449
sewardj3bd6f3e2004-12-13 10:48:19 +00001450 /*
1451 Call this to do the translation and limit checks:
1452 ULong x86g_use_seg_selector ( HWord ldt, HWord gdt,
1453 UInt seg_selector, UInt virtual_addr )
1454 */
1455 assign(
1456 r64,
1457 mkIRExprCCall(
1458 Ity_I64,
1459 0/*regparms*/,
1460 "x86g_use_seg_selector",
1461 &x86g_use_seg_selector,
1462 mkIRExprVec_4( mkexpr(ldt_ptr), mkexpr(gdt_ptr),
1463 mkexpr(seg_selector), virtual)
1464 )
1465 );
sewardj7df596b2004-12-06 14:29:12 +00001466
sewardj52444cb2004-12-13 14:09:01 +00001467 /* If the high 32 of the result are non-zero, there was a
1468 failure in address translation. In which case, make a
1469 quick exit.
1470 */
1471 stmt(
1472 IRStmt_Exit(
1473 binop(Iop_CmpNE32, unop(Iop_64HIto32, mkexpr(r64)), mkU32(0)),
1474 Ijk_MapFail,
sewardjc6f970f2012-04-02 21:54:49 +00001475 IRConst_U32( guest_EIP_curr_instr ),
1476 OFFB_EIP
sewardj52444cb2004-12-13 14:09:01 +00001477 )
1478 );
1479
1480 /* otherwise, here's the translated result. */
sewardj3bd6f3e2004-12-13 10:48:19 +00001481 return unop(Iop_64to32, mkexpr(r64));
sewardjd1061ab2004-07-08 01:45:30 +00001482}
1483
1484
1485/* Generate IR to calculate an address indicated by a ModRM and
1486 following SIB bytes. The expression, and the number of bytes in
1487 the address mode, are returned. Note that this fn should not be
1488 called if the R/M part of the address denotes a register instead of
1489 memory. If print_codegen is true, text of the addressing mode is
sewardj940e8c92004-07-11 16:53:24 +00001490 placed in buf.
1491
1492 The computed address is stored in a new tempreg, and the
1493 identity of the tempreg is returned. */
1494
1495static IRTemp disAMode_copy2tmp ( IRExpr* addr32 )
1496{
1497 IRTemp tmp = newTemp(Ity_I32);
1498 assign( tmp, addr32 );
1499 return tmp;
1500}
sewardjd1061ab2004-07-08 01:45:30 +00001501
1502static
sewardj52d04912005-07-03 00:52:48 +00001503IRTemp disAMode ( Int* len, UChar sorb, Int delta, HChar* buf )
sewardjd1061ab2004-07-08 01:45:30 +00001504{
1505 UChar mod_reg_rm = getIByte(delta);
1506 delta++;
1507
sewardj9ee82862004-12-14 01:16:59 +00001508 buf[0] = (UChar)0;
1509
sewardjd1061ab2004-07-08 01:45:30 +00001510 /* squeeze out the reg field from mod_reg_rm, since a 256-entry
1511 jump table seems a bit excessive.
1512 */
sewardj9b45b482005-02-07 01:42:18 +00001513 mod_reg_rm &= 0xC7; /* is now XX000YYY */
1514 mod_reg_rm = toUChar(mod_reg_rm | (mod_reg_rm >> 3));
1515 /* is now XX0XXYYY */
1516 mod_reg_rm &= 0x1F; /* is now 000XXYYY */
sewardjd1061ab2004-07-08 01:45:30 +00001517 switch (mod_reg_rm) {
1518
1519 /* (%eax) .. (%edi), not including (%esp) or (%ebp).
1520 --> GET %reg, t
1521 */
1522 case 0x00: case 0x01: case 0x02: case 0x03:
1523 /* ! 04 */ /* ! 05 */ case 0x06: case 0x07:
1524 { UChar rm = mod_reg_rm;
1525 DIS(buf, "%s(%s)", sorbTxt(sorb), nameIReg(4,rm));
1526 *len = 1;
sewardj5bd4d162004-11-10 13:02:48 +00001527 return disAMode_copy2tmp(
sewardj940e8c92004-07-11 16:53:24 +00001528 handleSegOverride(sorb, getIReg(4,rm)));
sewardjd1061ab2004-07-08 01:45:30 +00001529 }
1530
1531 /* d8(%eax) ... d8(%edi), not including d8(%esp)
1532 --> GET %reg, t ; ADDL d8, t
1533 */
1534 case 0x08: case 0x09: case 0x0A: case 0x0B:
1535 /* ! 0C */ case 0x0D: case 0x0E: case 0x0F:
sewardj9b45b482005-02-07 01:42:18 +00001536 { UChar rm = toUChar(mod_reg_rm & 7);
sewardjd1061ab2004-07-08 01:45:30 +00001537 UInt d = getSDisp8(delta);
sewardj2d49b432005-02-01 00:37:06 +00001538 DIS(buf, "%s%d(%s)", sorbTxt(sorb), (Int)d, nameIReg(4,rm));
sewardj5bd4d162004-11-10 13:02:48 +00001539 *len = 2;
1540 return disAMode_copy2tmp(
sewardj940e8c92004-07-11 16:53:24 +00001541 handleSegOverride(sorb,
1542 binop(Iop_Add32,getIReg(4,rm),mkU32(d))));
sewardjd1061ab2004-07-08 01:45:30 +00001543 }
1544
1545 /* d32(%eax) ... d32(%edi), not including d32(%esp)
1546 --> GET %reg, t ; ADDL d8, t
1547 */
1548 case 0x10: case 0x11: case 0x12: case 0x13:
1549 /* ! 14 */ case 0x15: case 0x16: case 0x17:
sewardj9b45b482005-02-07 01:42:18 +00001550 { UChar rm = toUChar(mod_reg_rm & 7);
sewardjd1061ab2004-07-08 01:45:30 +00001551 UInt d = getUDisp32(delta);
florianb1737742015-08-03 16:03:13 +00001552 DIS(buf, "%s0x%x(%s)", sorbTxt(sorb), d, nameIReg(4,rm));
sewardj5bd4d162004-11-10 13:02:48 +00001553 *len = 5;
1554 return disAMode_copy2tmp(
sewardj940e8c92004-07-11 16:53:24 +00001555 handleSegOverride(sorb,
1556 binop(Iop_Add32,getIReg(4,rm),mkU32(d))));
sewardjd1061ab2004-07-08 01:45:30 +00001557 }
1558
1559 /* a register, %eax .. %edi. This shouldn't happen. */
1560 case 0x18: case 0x19: case 0x1A: case 0x1B:
1561 case 0x1C: case 0x1D: case 0x1E: case 0x1F:
1562 vpanic("disAMode(x86): not an addr!");
1563
1564 /* a 32-bit literal address
1565 --> MOV d32, tmp
1566 */
1567 case 0x05:
1568 { UInt d = getUDisp32(delta);
1569 *len = 5;
1570 DIS(buf, "%s(0x%x)", sorbTxt(sorb), d);
sewardj940e8c92004-07-11 16:53:24 +00001571 return disAMode_copy2tmp(
1572 handleSegOverride(sorb, mkU32(d)));
sewardjd1061ab2004-07-08 01:45:30 +00001573 }
1574
1575 case 0x04: {
1576 /* SIB, with no displacement. Special cases:
1577 -- %esp cannot act as an index value.
1578 If index_r indicates %esp, zero is used for the index.
1579 -- when mod is zero and base indicates EBP, base is instead
1580 a 32-bit literal.
1581 It's all madness, I tell you. Extract %index, %base and
1582 scale from the SIB byte. The value denoted is then:
1583 | %index == %ESP && %base == %EBP
1584 = d32 following SIB byte
1585 | %index == %ESP && %base != %EBP
1586 = %base
1587 | %index != %ESP && %base == %EBP
1588 = d32 following SIB byte + (%index << scale)
1589 | %index != %ESP && %base != %ESP
1590 = %base + (%index << scale)
1591
1592 What happens to the souls of CPU architects who dream up such
1593 horrendous schemes, do you suppose?
1594 */
1595 UChar sib = getIByte(delta);
sewardj9b45b482005-02-07 01:42:18 +00001596 UChar scale = toUChar((sib >> 6) & 3);
1597 UChar index_r = toUChar((sib >> 3) & 7);
1598 UChar base_r = toUChar(sib & 7);
sewardj5bd4d162004-11-10 13:02:48 +00001599 delta++;
sewardjd1061ab2004-07-08 01:45:30 +00001600
1601 if (index_r != R_ESP && base_r != R_EBP) {
1602 DIS(buf, "%s(%s,%s,%d)", sorbTxt(sorb),
1603 nameIReg(4,base_r), nameIReg(4,index_r), 1<<scale);
sewardj5bd4d162004-11-10 13:02:48 +00001604 *len = 2;
sewardj940e8c92004-07-11 16:53:24 +00001605 return
1606 disAMode_copy2tmp(
sewardj5bd4d162004-11-10 13:02:48 +00001607 handleSegOverride(sorb,
1608 binop(Iop_Add32,
sewardjd1061ab2004-07-08 01:45:30 +00001609 getIReg(4,base_r),
1610 binop(Iop_Shl32, getIReg(4,index_r),
sewardj6d2638e2004-07-15 09:38:27 +00001611 mkU8(scale)))));
sewardjd1061ab2004-07-08 01:45:30 +00001612 }
1613
1614 if (index_r != R_ESP && base_r == R_EBP) {
1615 UInt d = getUDisp32(delta);
1616 DIS(buf, "%s0x%x(,%s,%d)", sorbTxt(sorb), d,
1617 nameIReg(4,index_r), 1<<scale);
1618 *len = 6;
1619 return
sewardj940e8c92004-07-11 16:53:24 +00001620 disAMode_copy2tmp(
sewardjd1061ab2004-07-08 01:45:30 +00001621 handleSegOverride(sorb,
sewardj5bd4d162004-11-10 13:02:48 +00001622 binop(Iop_Add32,
1623 binop(Iop_Shl32, getIReg(4,index_r), mkU8(scale)),
sewardj940e8c92004-07-11 16:53:24 +00001624 mkU32(d))));
sewardjd1061ab2004-07-08 01:45:30 +00001625 }
1626
1627 if (index_r == R_ESP && base_r != R_EBP) {
1628 DIS(buf, "%s(%s,,)", sorbTxt(sorb), nameIReg(4,base_r));
sewardj5bd4d162004-11-10 13:02:48 +00001629 *len = 2;
1630 return disAMode_copy2tmp(
sewardj940e8c92004-07-11 16:53:24 +00001631 handleSegOverride(sorb, getIReg(4,base_r)));
sewardjd1061ab2004-07-08 01:45:30 +00001632 }
1633
1634 if (index_r == R_ESP && base_r == R_EBP) {
1635 UInt d = getUDisp32(delta);
sewardj9c3b25a2007-04-05 15:06:56 +00001636 DIS(buf, "%s0x%x(,,)", sorbTxt(sorb), d);
sewardj5bd4d162004-11-10 13:02:48 +00001637 *len = 6;
sewardj5bd4d162004-11-10 13:02:48 +00001638 return disAMode_copy2tmp(
sewardj940e8c92004-07-11 16:53:24 +00001639 handleSegOverride(sorb, mkU32(d)));
sewardjd1061ab2004-07-08 01:45:30 +00001640 }
sewardjba89f4c2005-04-07 17:31:27 +00001641 /*NOTREACHED*/
sewardjd1061ab2004-07-08 01:45:30 +00001642 vassert(0);
1643 }
1644
1645 /* SIB, with 8-bit displacement. Special cases:
1646 -- %esp cannot act as an index value.
1647 If index_r indicates %esp, zero is used for the index.
1648 Denoted value is:
1649 | %index == %ESP
1650 = d8 + %base
1651 | %index != %ESP
1652 = d8 + %base + (%index << scale)
1653 */
1654 case 0x0C: {
1655 UChar sib = getIByte(delta);
sewardj9b45b482005-02-07 01:42:18 +00001656 UChar scale = toUChar((sib >> 6) & 3);
1657 UChar index_r = toUChar((sib >> 3) & 7);
1658 UChar base_r = toUChar(sib & 7);
sewardjd1061ab2004-07-08 01:45:30 +00001659 UInt d = getSDisp8(delta+1);
1660
1661 if (index_r == R_ESP) {
sewardj2d49b432005-02-01 00:37:06 +00001662 DIS(buf, "%s%d(%s,,)", sorbTxt(sorb),
1663 (Int)d, nameIReg(4,base_r));
sewardj5bd4d162004-11-10 13:02:48 +00001664 *len = 3;
1665 return disAMode_copy2tmp(
sewardj940e8c92004-07-11 16:53:24 +00001666 handleSegOverride(sorb,
1667 binop(Iop_Add32, getIReg(4,base_r), mkU32(d)) ));
sewardjd1061ab2004-07-08 01:45:30 +00001668 } else {
sewardj2d49b432005-02-01 00:37:06 +00001669 DIS(buf, "%s%d(%s,%s,%d)", sorbTxt(sorb), (Int)d,
sewardjd1061ab2004-07-08 01:45:30 +00001670 nameIReg(4,base_r), nameIReg(4,index_r), 1<<scale);
sewardj5bd4d162004-11-10 13:02:48 +00001671 *len = 3;
1672 return
sewardj940e8c92004-07-11 16:53:24 +00001673 disAMode_copy2tmp(
1674 handleSegOverride(sorb,
sewardj77b86be2004-07-11 13:28:24 +00001675 binop(Iop_Add32,
1676 binop(Iop_Add32,
1677 getIReg(4,base_r),
1678 binop(Iop_Shl32,
sewardj6d2638e2004-07-15 09:38:27 +00001679 getIReg(4,index_r), mkU8(scale))),
sewardj940e8c92004-07-11 16:53:24 +00001680 mkU32(d))));
sewardjd1061ab2004-07-08 01:45:30 +00001681 }
sewardjba89f4c2005-04-07 17:31:27 +00001682 /*NOTREACHED*/
sewardjd1061ab2004-07-08 01:45:30 +00001683 vassert(0);
1684 }
1685
1686 /* SIB, with 32-bit displacement. Special cases:
1687 -- %esp cannot act as an index value.
1688 If index_r indicates %esp, zero is used for the index.
1689 Denoted value is:
1690 | %index == %ESP
1691 = d32 + %base
1692 | %index != %ESP
1693 = d32 + %base + (%index << scale)
1694 */
1695 case 0x14: {
1696 UChar sib = getIByte(delta);
sewardj9b45b482005-02-07 01:42:18 +00001697 UChar scale = toUChar((sib >> 6) & 3);
1698 UChar index_r = toUChar((sib >> 3) & 7);
1699 UChar base_r = toUChar(sib & 7);
sewardjd1061ab2004-07-08 01:45:30 +00001700 UInt d = getUDisp32(delta+1);
1701
1702 if (index_r == R_ESP) {
sewardj2d49b432005-02-01 00:37:06 +00001703 DIS(buf, "%s%d(%s,,)", sorbTxt(sorb),
1704 (Int)d, nameIReg(4,base_r));
sewardj5bd4d162004-11-10 13:02:48 +00001705 *len = 6;
1706 return disAMode_copy2tmp(
sewardj940e8c92004-07-11 16:53:24 +00001707 handleSegOverride(sorb,
1708 binop(Iop_Add32, getIReg(4,base_r), mkU32(d)) ));
sewardjd1061ab2004-07-08 01:45:30 +00001709 } else {
sewardj2d49b432005-02-01 00:37:06 +00001710 DIS(buf, "%s%d(%s,%s,%d)", sorbTxt(sorb), (Int)d,
1711 nameIReg(4,base_r), nameIReg(4,index_r), 1<<scale);
sewardj5bd4d162004-11-10 13:02:48 +00001712 *len = 6;
1713 return
sewardj940e8c92004-07-11 16:53:24 +00001714 disAMode_copy2tmp(
1715 handleSegOverride(sorb,
sewardj9334b0f2004-07-10 22:43:54 +00001716 binop(Iop_Add32,
1717 binop(Iop_Add32,
1718 getIReg(4,base_r),
1719 binop(Iop_Shl32,
sewardj6d2638e2004-07-15 09:38:27 +00001720 getIReg(4,index_r), mkU8(scale))),
sewardj940e8c92004-07-11 16:53:24 +00001721 mkU32(d))));
sewardjd1061ab2004-07-08 01:45:30 +00001722 }
sewardjba89f4c2005-04-07 17:31:27 +00001723 /*NOTREACHED*/
sewardjd1061ab2004-07-08 01:45:30 +00001724 vassert(0);
1725 }
1726
1727 default:
1728 vpanic("disAMode(x86)");
1729 return 0; /*notreached*/
1730 }
1731}
1732
1733
1734/* Figure out the number of (insn-stream) bytes constituting the amode
1735 beginning at delta. Is useful for getting hold of literals beyond
1736 the end of the amode before it has been disassembled. */
1737
sewardj52d04912005-07-03 00:52:48 +00001738static UInt lengthAMode ( Int delta )
sewardjd1061ab2004-07-08 01:45:30 +00001739{
1740 UChar mod_reg_rm = getIByte(delta); delta++;
1741
1742 /* squeeze out the reg field from mod_reg_rm, since a 256-entry
1743 jump table seems a bit excessive.
1744 */
1745 mod_reg_rm &= 0xC7; /* is now XX000YYY */
sewardj9b45b482005-02-07 01:42:18 +00001746 mod_reg_rm = toUChar(mod_reg_rm | (mod_reg_rm >> 3));
1747 /* is now XX0XXYYY */
sewardjd1061ab2004-07-08 01:45:30 +00001748 mod_reg_rm &= 0x1F; /* is now 000XXYYY */
1749 switch (mod_reg_rm) {
1750
1751 /* (%eax) .. (%edi), not including (%esp) or (%ebp). */
1752 case 0x00: case 0x01: case 0x02: case 0x03:
1753 /* ! 04 */ /* ! 05 */ case 0x06: case 0x07:
1754 return 1;
1755
1756 /* d8(%eax) ... d8(%edi), not including d8(%esp). */
1757 case 0x08: case 0x09: case 0x0A: case 0x0B:
1758 /* ! 0C */ case 0x0D: case 0x0E: case 0x0F:
1759 return 2;
1760
1761 /* d32(%eax) ... d32(%edi), not including d32(%esp). */
1762 case 0x10: case 0x11: case 0x12: case 0x13:
1763 /* ! 14 */ case 0x15: case 0x16: case 0x17:
1764 return 5;
1765
1766 /* a register, %eax .. %edi. (Not an addr, but still handled.) */
1767 case 0x18: case 0x19: case 0x1A: case 0x1B:
1768 case 0x1C: case 0x1D: case 0x1E: case 0x1F:
1769 return 1;
1770
1771 /* a 32-bit literal address. */
1772 case 0x05: return 5;
1773
1774 /* SIB, no displacement. */
1775 case 0x04: {
1776 UChar sib = getIByte(delta);
sewardj9b45b482005-02-07 01:42:18 +00001777 UChar base_r = toUChar(sib & 7);
sewardjd1061ab2004-07-08 01:45:30 +00001778 if (base_r == R_EBP) return 6; else return 2;
1779 }
1780 /* SIB, with 8-bit displacement. */
1781 case 0x0C: return 3;
1782
1783 /* SIB, with 32-bit displacement. */
1784 case 0x14: return 6;
1785
1786 default:
1787 vpanic("lengthAMode");
1788 return 0; /*notreached*/
1789 }
1790}
1791
1792/*------------------------------------------------------------*/
1793/*--- Disassembling common idioms ---*/
1794/*------------------------------------------------------------*/
1795
sewardje87b4842004-07-10 12:23:30 +00001796/* Handle binary integer instructions of the form
1797 op E, G meaning
1798 op reg-or-mem, reg
1799 Is passed the a ptr to the modRM byte, the actual operation, and the
1800 data size. Returns the address advanced completely over this
1801 instruction.
1802
1803 E(src) is reg-or-mem
1804 G(dst) is reg.
1805
1806 If E is reg, --> GET %G, tmp
1807 OP %E, tmp
1808 PUT tmp, %G
1809
1810 If E is mem and OP is not reversible,
1811 --> (getAddr E) -> tmpa
1812 LD (tmpa), tmpa
1813 GET %G, tmp2
1814 OP tmpa, tmp2
1815 PUT tmp2, %G
1816
1817 If E is mem and OP is reversible
1818 --> (getAddr E) -> tmpa
1819 LD (tmpa), tmpa
1820 OP %G, tmpa
1821 PUT tmpa, %G
1822*/
1823static
1824UInt dis_op2_E_G ( UChar sorb,
sewardj180e8b32004-07-29 01:40:11 +00001825 Bool addSubCarry,
sewardje87b4842004-07-10 12:23:30 +00001826 IROp op8,
1827 Bool keep,
1828 Int size,
sewardj52d04912005-07-03 00:52:48 +00001829 Int delta0,
florian55085f82012-11-21 00:36:55 +00001830 const HChar* t_x86opc )
sewardje87b4842004-07-10 12:23:30 +00001831{
sewardjc9a43662004-11-30 18:51:59 +00001832 HChar dis_buf[50];
sewardj9334b0f2004-07-10 22:43:54 +00001833 Int len;
sewardje87b4842004-07-10 12:23:30 +00001834 IRType ty = szToITy(size);
1835 IRTemp dst1 = newTemp(ty);
1836 IRTemp src = newTemp(ty);
1837 IRTemp dst0 = newTemp(ty);
1838 UChar rm = getUChar(delta0);
sewardj92d168d2004-11-15 14:22:12 +00001839 IRTemp addr = IRTemp_INVALID;
sewardje87b4842004-07-10 12:23:30 +00001840
sewardj180e8b32004-07-29 01:40:11 +00001841 /* addSubCarry == True indicates the intended operation is
1842 add-with-carry or subtract-with-borrow. */
1843 if (addSubCarry) {
1844 vassert(op8 == Iop_Add8 || op8 == Iop_Sub8);
1845 vassert(keep);
1846 }
1847
sewardje87b4842004-07-10 12:23:30 +00001848 if (epartIsReg(rm)) {
sewardje87b4842004-07-10 12:23:30 +00001849 /* Specially handle XOR reg,reg, because that doesn't really
1850 depend on reg, and doing the obvious thing potentially
1851 generates a spurious value check failure due to the bogus
sewardj55efbdf2005-05-02 17:07:02 +00001852 dependency. Ditto SBB reg,reg. */
1853 if ((op8 == Iop_Xor8 || (op8 == Iop_Sub8 && addSubCarry))
1854 && gregOfRM(rm) == eregOfRM(rm)) {
1855 putIReg(size, gregOfRM(rm), mkU(ty,0));
sewardje87b4842004-07-10 12:23:30 +00001856 }
sewardje87b4842004-07-10 12:23:30 +00001857 assign( dst0, getIReg(size,gregOfRM(rm)) );
1858 assign( src, getIReg(size,eregOfRM(rm)) );
sewardje87b4842004-07-10 12:23:30 +00001859
sewardj180e8b32004-07-29 01:40:11 +00001860 if (addSubCarry && op8 == Iop_Add8) {
sewardje9d8a262009-07-01 08:06:34 +00001861 helper_ADC( size, dst1, dst0, src,
1862 /*no store*/IRTemp_INVALID, IRTemp_INVALID, 0 );
sewardje87b4842004-07-10 12:23:30 +00001863 putIReg(size, gregOfRM(rm), mkexpr(dst1));
sewardj180e8b32004-07-29 01:40:11 +00001864 } else
1865 if (addSubCarry && op8 == Iop_Sub8) {
sewardje9d8a262009-07-01 08:06:34 +00001866 helper_SBB( size, dst1, dst0, src,
1867 /*no store*/IRTemp_INVALID, IRTemp_INVALID, 0 );
sewardj180e8b32004-07-29 01:40:11 +00001868 putIReg(size, gregOfRM(rm), mkexpr(dst1));
1869 } else {
1870 assign( dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)) );
sewardj5bd4d162004-11-10 13:02:48 +00001871 if (isAddSub(op8))
sewardj2a2ba8b2004-11-08 13:14:06 +00001872 setFlags_DEP1_DEP2(op8, dst0, src, ty);
sewardjb9c5cf62004-08-24 15:10:38 +00001873 else
sewardj2a2ba8b2004-11-08 13:14:06 +00001874 setFlags_DEP1(op8, dst1, ty);
sewardj180e8b32004-07-29 01:40:11 +00001875 if (keep)
1876 putIReg(size, gregOfRM(rm), mkexpr(dst1));
1877 }
sewardje87b4842004-07-10 12:23:30 +00001878
1879 DIP("%s%c %s,%s\n", t_x86opc, nameISize(size),
1880 nameIReg(size,eregOfRM(rm)),
1881 nameIReg(size,gregOfRM(rm)));
1882 return 1+delta0;
sewardje87b4842004-07-10 12:23:30 +00001883 } else {
sewardj9334b0f2004-07-10 22:43:54 +00001884 /* E refers to memory */
1885 addr = disAMode ( &len, sorb, delta0, dis_buf);
1886 assign( dst0, getIReg(size,gregOfRM(rm)) );
sewardj940e8c92004-07-11 16:53:24 +00001887 assign( src, loadLE(szToITy(size), mkexpr(addr)) );
sewardj9334b0f2004-07-10 22:43:54 +00001888
sewardj180e8b32004-07-29 01:40:11 +00001889 if (addSubCarry && op8 == Iop_Add8) {
sewardje9d8a262009-07-01 08:06:34 +00001890 helper_ADC( size, dst1, dst0, src,
1891 /*no store*/IRTemp_INVALID, IRTemp_INVALID, 0 );
sewardj9334b0f2004-07-10 22:43:54 +00001892 putIReg(size, gregOfRM(rm), mkexpr(dst1));
sewardj180e8b32004-07-29 01:40:11 +00001893 } else
1894 if (addSubCarry && op8 == Iop_Sub8) {
sewardje9d8a262009-07-01 08:06:34 +00001895 helper_SBB( size, dst1, dst0, src,
1896 /*no store*/IRTemp_INVALID, IRTemp_INVALID, 0 );
sewardj180e8b32004-07-29 01:40:11 +00001897 putIReg(size, gregOfRM(rm), mkexpr(dst1));
1898 } else {
1899 assign( dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)) );
sewardj5bd4d162004-11-10 13:02:48 +00001900 if (isAddSub(op8))
sewardj2a2ba8b2004-11-08 13:14:06 +00001901 setFlags_DEP1_DEP2(op8, dst0, src, ty);
sewardjb9c5cf62004-08-24 15:10:38 +00001902 else
sewardj2a2ba8b2004-11-08 13:14:06 +00001903 setFlags_DEP1(op8, dst1, ty);
sewardj180e8b32004-07-29 01:40:11 +00001904 if (keep)
1905 putIReg(size, gregOfRM(rm), mkexpr(dst1));
1906 }
sewardj9334b0f2004-07-10 22:43:54 +00001907
sewardje87b4842004-07-10 12:23:30 +00001908 DIP("%s%c %s,%s\n", t_x86opc, nameISize(size),
1909 dis_buf,nameIReg(size,gregOfRM(rm)));
sewardj9334b0f2004-07-10 22:43:54 +00001910 return len+delta0;
sewardje87b4842004-07-10 12:23:30 +00001911 }
sewardje87b4842004-07-10 12:23:30 +00001912}
sewardje05c42c2004-07-08 20:25:10 +00001913
1914
1915
1916/* Handle binary integer instructions of the form
1917 op G, E meaning
1918 op reg, reg-or-mem
1919 Is passed the a ptr to the modRM byte, the actual operation, and the
1920 data size. Returns the address advanced completely over this
1921 instruction.
1922
1923 G(src) is reg.
1924 E(dst) is reg-or-mem
1925
1926 If E is reg, --> GET %E, tmp
1927 OP %G, tmp
1928 PUT tmp, %E
1929
1930 If E is mem, --> (getAddr E) -> tmpa
1931 LD (tmpa), tmpv
1932 OP %G, tmpv
1933 ST tmpv, (tmpa)
1934*/
1935static
1936UInt dis_op2_G_E ( UChar sorb,
sewardje9d8a262009-07-01 08:06:34 +00001937 Bool locked,
sewardjcaca9d02004-07-28 07:11:32 +00001938 Bool addSubCarry,
sewardje05c42c2004-07-08 20:25:10 +00001939 IROp op8,
1940 Bool keep,
1941 Int size,
sewardj52d04912005-07-03 00:52:48 +00001942 Int delta0,
florian55085f82012-11-21 00:36:55 +00001943 const HChar* t_x86opc )
sewardje05c42c2004-07-08 20:25:10 +00001944{
sewardjc9a43662004-11-30 18:51:59 +00001945 HChar dis_buf[50];
sewardje87b4842004-07-10 12:23:30 +00001946 Int len;
sewardje05c42c2004-07-08 20:25:10 +00001947 IRType ty = szToITy(size);
1948 IRTemp dst1 = newTemp(ty);
1949 IRTemp src = newTemp(ty);
1950 IRTemp dst0 = newTemp(ty);
1951 UChar rm = getIByte(delta0);
sewardj92d168d2004-11-15 14:22:12 +00001952 IRTemp addr = IRTemp_INVALID;
sewardje05c42c2004-07-08 20:25:10 +00001953
sewardjcaca9d02004-07-28 07:11:32 +00001954 /* addSubCarry == True indicates the intended operation is
1955 add-with-carry or subtract-with-borrow. */
1956 if (addSubCarry) {
1957 vassert(op8 == Iop_Add8 || op8 == Iop_Sub8);
1958 vassert(keep);
1959 }
1960
sewardje05c42c2004-07-08 20:25:10 +00001961 if (epartIsReg(rm)) {
sewardje05c42c2004-07-08 20:25:10 +00001962 /* Specially handle XOR reg,reg, because that doesn't really
1963 depend on reg, and doing the obvious thing potentially
1964 generates a spurious value check failure due to the bogus
sewardj55efbdf2005-05-02 17:07:02 +00001965 dependency. Ditto SBB reg,reg.*/
1966 if ((op8 == Iop_Xor8 || (op8 == Iop_Sub8 && addSubCarry))
1967 && gregOfRM(rm) == eregOfRM(rm)) {
1968 putIReg(size, eregOfRM(rm), mkU(ty,0));
sewardje05c42c2004-07-08 20:25:10 +00001969 }
sewardje05c42c2004-07-08 20:25:10 +00001970 assign(dst0, getIReg(size,eregOfRM(rm)));
1971 assign(src, getIReg(size,gregOfRM(rm)));
sewardje05c42c2004-07-08 20:25:10 +00001972
sewardjcaca9d02004-07-28 07:11:32 +00001973 if (addSubCarry && op8 == Iop_Add8) {
sewardje9d8a262009-07-01 08:06:34 +00001974 helper_ADC( size, dst1, dst0, src,
1975 /*no store*/IRTemp_INVALID, IRTemp_INVALID, 0 );
sewardj1813dbe2004-07-28 17:09:04 +00001976 putIReg(size, eregOfRM(rm), mkexpr(dst1));
sewardjcaca9d02004-07-28 07:11:32 +00001977 } else
1978 if (addSubCarry && op8 == Iop_Sub8) {
sewardje9d8a262009-07-01 08:06:34 +00001979 helper_SBB( size, dst1, dst0, src,
1980 /*no store*/IRTemp_INVALID, IRTemp_INVALID, 0 );
sewardje05c42c2004-07-08 20:25:10 +00001981 putIReg(size, eregOfRM(rm), mkexpr(dst1));
sewardjcaca9d02004-07-28 07:11:32 +00001982 } else {
1983 assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)));
sewardj5bd4d162004-11-10 13:02:48 +00001984 if (isAddSub(op8))
sewardj2a2ba8b2004-11-08 13:14:06 +00001985 setFlags_DEP1_DEP2(op8, dst0, src, ty);
sewardjb9c5cf62004-08-24 15:10:38 +00001986 else
sewardj2a2ba8b2004-11-08 13:14:06 +00001987 setFlags_DEP1(op8, dst1, ty);
sewardjcaca9d02004-07-28 07:11:32 +00001988 if (keep)
1989 putIReg(size, eregOfRM(rm), mkexpr(dst1));
1990 }
sewardje05c42c2004-07-08 20:25:10 +00001991
1992 DIP("%s%c %s,%s\n", t_x86opc, nameISize(size),
1993 nameIReg(size,gregOfRM(rm)),
1994 nameIReg(size,eregOfRM(rm)));
1995 return 1+delta0;
1996 }
1997
1998 /* E refers to memory */
1999 {
sewardje87b4842004-07-10 12:23:30 +00002000 addr = disAMode ( &len, sorb, delta0, dis_buf);
sewardj940e8c92004-07-11 16:53:24 +00002001 assign(dst0, loadLE(ty,mkexpr(addr)));
sewardje87b4842004-07-10 12:23:30 +00002002 assign(src, getIReg(size,gregOfRM(rm)));
sewardje05c42c2004-07-08 20:25:10 +00002003
sewardjcaca9d02004-07-28 07:11:32 +00002004 if (addSubCarry && op8 == Iop_Add8) {
sewardje9d8a262009-07-01 08:06:34 +00002005 if (locked) {
2006 /* cas-style store */
2007 helper_ADC( size, dst1, dst0, src,
2008 /*store*/addr, dst0/*expVal*/, guest_EIP_curr_instr );
2009 } else {
2010 /* normal store */
2011 helper_ADC( size, dst1, dst0, src,
2012 /*store*/addr, IRTemp_INVALID, 0 );
2013 }
sewardjcaca9d02004-07-28 07:11:32 +00002014 } else
2015 if (addSubCarry && op8 == Iop_Sub8) {
sewardje9d8a262009-07-01 08:06:34 +00002016 if (locked) {
2017 /* cas-style store */
2018 helper_SBB( size, dst1, dst0, src,
2019 /*store*/addr, dst0/*expVal*/, guest_EIP_curr_instr );
2020 } else {
2021 /* normal store */
2022 helper_SBB( size, dst1, dst0, src,
2023 /*store*/addr, IRTemp_INVALID, 0 );
2024 }
sewardjcaca9d02004-07-28 07:11:32 +00002025 } else {
2026 assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)));
sewardje9d8a262009-07-01 08:06:34 +00002027 if (keep) {
2028 if (locked) {
2029 if (0) vex_printf("locked case\n" );
2030 casLE( mkexpr(addr),
2031 mkexpr(dst0)/*expval*/,
2032 mkexpr(dst1)/*newval*/, guest_EIP_curr_instr );
2033 } else {
2034 if (0) vex_printf("nonlocked case\n");
2035 storeLE(mkexpr(addr), mkexpr(dst1));
2036 }
2037 }
sewardj5bd4d162004-11-10 13:02:48 +00002038 if (isAddSub(op8))
sewardj2a2ba8b2004-11-08 13:14:06 +00002039 setFlags_DEP1_DEP2(op8, dst0, src, ty);
sewardjb9c5cf62004-08-24 15:10:38 +00002040 else
sewardj2a2ba8b2004-11-08 13:14:06 +00002041 setFlags_DEP1(op8, dst1, ty);
sewardjcaca9d02004-07-28 07:11:32 +00002042 }
sewardje87b4842004-07-10 12:23:30 +00002043
sewardje05c42c2004-07-08 20:25:10 +00002044 DIP("%s%c %s,%s\n", t_x86opc, nameISize(size),
2045 nameIReg(size,gregOfRM(rm)), dis_buf);
sewardje87b4842004-07-10 12:23:30 +00002046 return len+delta0;
sewardje05c42c2004-07-08 20:25:10 +00002047 }
2048}
2049
2050
2051/* Handle move instructions of the form
2052 mov E, G meaning
2053 mov reg-or-mem, reg
2054 Is passed the a ptr to the modRM byte, and the data size. Returns
2055 the address advanced completely over this instruction.
2056
2057 E(src) is reg-or-mem
2058 G(dst) is reg.
2059
2060 If E is reg, --> GET %E, tmpv
2061 PUT tmpv, %G
2062
2063 If E is mem --> (getAddr E) -> tmpa
2064 LD (tmpa), tmpb
2065 PUT tmpb, %G
2066*/
2067static
2068UInt dis_mov_E_G ( UChar sorb,
2069 Int size,
sewardj52d04912005-07-03 00:52:48 +00002070 Int delta0 )
sewardje05c42c2004-07-08 20:25:10 +00002071{
2072 Int len;
2073 UChar rm = getIByte(delta0);
sewardjc9a43662004-11-30 18:51:59 +00002074 HChar dis_buf[50];
sewardje05c42c2004-07-08 20:25:10 +00002075
2076 if (epartIsReg(rm)) {
sewardj7ca37d92004-10-25 02:58:30 +00002077 putIReg(size, gregOfRM(rm), getIReg(size, eregOfRM(rm)));
sewardje05c42c2004-07-08 20:25:10 +00002078 DIP("mov%c %s,%s\n", nameISize(size),
2079 nameIReg(size,eregOfRM(rm)),
2080 nameIReg(size,gregOfRM(rm)));
sewardj7ca37d92004-10-25 02:58:30 +00002081 return 1+delta0;
sewardje05c42c2004-07-08 20:25:10 +00002082 }
2083
2084 /* E refers to memory */
2085 {
sewardj940e8c92004-07-11 16:53:24 +00002086 IRTemp addr = disAMode ( &len, sorb, delta0, dis_buf );
2087 putIReg(size, gregOfRM(rm), loadLE(szToITy(size), mkexpr(addr)));
sewardje05c42c2004-07-08 20:25:10 +00002088 DIP("mov%c %s,%s\n", nameISize(size),
2089 dis_buf,nameIReg(size,gregOfRM(rm)));
2090 return delta0+len;
2091 }
2092}
2093
2094
2095/* Handle move instructions of the form
2096 mov G, E meaning
2097 mov reg, reg-or-mem
2098 Is passed the a ptr to the modRM byte, and the data size. Returns
2099 the address advanced completely over this instruction.
2100
2101 G(src) is reg.
2102 E(dst) is reg-or-mem
2103
2104 If E is reg, --> GET %G, tmp
2105 PUT tmp, %E
2106
2107 If E is mem, --> (getAddr E) -> tmpa
2108 GET %G, tmpv
2109 ST tmpv, (tmpa)
2110*/
sewardjc9a65702004-07-07 16:32:57 +00002111static
2112UInt dis_mov_G_E ( UChar sorb,
2113 Int size,
sewardj52d04912005-07-03 00:52:48 +00002114 Int delta0 )
sewardjc9a65702004-07-07 16:32:57 +00002115{
sewardje05c42c2004-07-08 20:25:10 +00002116 Int len;
sewardjc9a65702004-07-07 16:32:57 +00002117 UChar rm = getIByte(delta0);
sewardjc9a43662004-11-30 18:51:59 +00002118 HChar dis_buf[50];
sewardjc9a65702004-07-07 16:32:57 +00002119
2120 if (epartIsReg(rm)) {
sewardj41f43bc2004-07-08 14:23:22 +00002121 putIReg(size, eregOfRM(rm), getIReg(size, gregOfRM(rm)));
sewardjc9a65702004-07-07 16:32:57 +00002122 DIP("mov%c %s,%s\n", nameISize(size),
2123 nameIReg(size,gregOfRM(rm)),
2124 nameIReg(size,eregOfRM(rm)));
2125 return 1+delta0;
2126 }
2127
sewardjc9a65702004-07-07 16:32:57 +00002128 /* E refers to memory */
2129 {
sewardj940e8c92004-07-11 16:53:24 +00002130 IRTemp addr = disAMode ( &len, sorb, delta0, dis_buf);
2131 storeLE( mkexpr(addr), getIReg(size, gregOfRM(rm)) );
sewardjc9a65702004-07-07 16:32:57 +00002132 DIP("mov%c %s,%s\n", nameISize(size),
2133 nameIReg(size,gregOfRM(rm)), dis_buf);
sewardje05c42c2004-07-08 20:25:10 +00002134 return len+delta0;
sewardjc9a65702004-07-07 16:32:57 +00002135 }
sewardjc9a65702004-07-07 16:32:57 +00002136}
2137
2138
sewardj0611d802004-07-11 02:37:54 +00002139/* op $immediate, AL/AX/EAX. */
2140static
2141UInt dis_op_imm_A ( Int size,
sewardja718d5d2005-04-03 14:59:54 +00002142 Bool carrying,
sewardj0611d802004-07-11 02:37:54 +00002143 IROp op8,
2144 Bool keep,
sewardj52d04912005-07-03 00:52:48 +00002145 Int delta,
florian55085f82012-11-21 00:36:55 +00002146 const HChar* t_x86opc )
sewardj0611d802004-07-11 02:37:54 +00002147{
2148 IRType ty = szToITy(size);
2149 IRTemp dst0 = newTemp(ty);
2150 IRTemp src = newTemp(ty);
2151 IRTemp dst1 = newTemp(ty);
2152 UInt lit = getUDisp(size,delta);
2153 assign(dst0, getIReg(size,R_EAX));
2154 assign(src, mkU(ty,lit));
sewardja718d5d2005-04-03 14:59:54 +00002155
2156 if (isAddSub(op8) && !carrying) {
2157 assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)) );
sewardj2a2ba8b2004-11-08 13:14:06 +00002158 setFlags_DEP1_DEP2(op8, dst0, src, ty);
sewardja718d5d2005-04-03 14:59:54 +00002159 }
sewardjb9c5cf62004-08-24 15:10:38 +00002160 else
sewardja718d5d2005-04-03 14:59:54 +00002161 if (isLogic(op8)) {
2162 vassert(!carrying);
2163 assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)) );
sewardj2a2ba8b2004-11-08 13:14:06 +00002164 setFlags_DEP1(op8, dst1, ty);
sewardja718d5d2005-04-03 14:59:54 +00002165 }
2166 else
2167 if (op8 == Iop_Add8 && carrying) {
sewardje9d8a262009-07-01 08:06:34 +00002168 helper_ADC( size, dst1, dst0, src,
2169 /*no store*/IRTemp_INVALID, IRTemp_INVALID, 0 );
sewardja718d5d2005-04-03 14:59:54 +00002170 }
sewardj2a2ba8b2004-11-08 13:14:06 +00002171 else
sewardj2fbae082005-10-03 02:07:08 +00002172 if (op8 == Iop_Sub8 && carrying) {
sewardje9d8a262009-07-01 08:06:34 +00002173 helper_SBB( size, dst1, dst0, src,
2174 /*no store*/IRTemp_INVALID, IRTemp_INVALID, 0 );
sewardj2fbae082005-10-03 02:07:08 +00002175 }
2176 else
sewardj2a2ba8b2004-11-08 13:14:06 +00002177 vpanic("dis_op_imm_A(x86,guest)");
sewardj0611d802004-07-11 02:37:54 +00002178
2179 if (keep)
2180 putIReg(size, R_EAX, mkexpr(dst1));
2181
2182 DIP("%s%c $0x%x, %s\n", t_x86opc, nameISize(size),
2183 lit, nameIReg(size,R_EAX));
2184 return delta+size;
2185}
sewardj9334b0f2004-07-10 22:43:54 +00002186
2187
2188/* Sign- and Zero-extending moves. */
2189static
sewardj52d04912005-07-03 00:52:48 +00002190UInt dis_movx_E_G ( UChar sorb,
2191 Int delta, Int szs, Int szd, Bool sign_extend )
sewardj9334b0f2004-07-10 22:43:54 +00002192{
sewardj9334b0f2004-07-10 22:43:54 +00002193 UChar rm = getIByte(delta);
2194 if (epartIsReg(rm)) {
sewardj33ca4ac2010-09-30 13:37:31 +00002195 if (szd == szs) {
2196 // mutant case. See #250799
2197 putIReg(szd, gregOfRM(rm),
2198 getIReg(szs,eregOfRM(rm)));
2199 } else {
2200 // normal case
2201 putIReg(szd, gregOfRM(rm),
2202 unop(mkWidenOp(szs,szd,sign_extend),
2203 getIReg(szs,eregOfRM(rm))));
2204 }
sewardj9334b0f2004-07-10 22:43:54 +00002205 DIP("mov%c%c%c %s,%s\n", sign_extend ? 's' : 'z',
2206 nameISize(szs), nameISize(szd),
2207 nameIReg(szs,eregOfRM(rm)),
2208 nameIReg(szd,gregOfRM(rm)));
2209 return 1+delta;
2210 }
2211
2212 /* E refers to memory */
2213 {
sewardj940e8c92004-07-11 16:53:24 +00002214 Int len;
sewardjc9a43662004-11-30 18:51:59 +00002215 HChar dis_buf[50];
sewardj940e8c92004-07-11 16:53:24 +00002216 IRTemp addr = disAMode ( &len, sorb, delta, dis_buf );
sewardj33ca4ac2010-09-30 13:37:31 +00002217 if (szd == szs) {
2218 // mutant case. See #250799
2219 putIReg(szd, gregOfRM(rm),
2220 loadLE(szToITy(szs),mkexpr(addr)));
2221 } else {
2222 // normal case
2223 putIReg(szd, gregOfRM(rm),
2224 unop(mkWidenOp(szs,szd,sign_extend),
2225 loadLE(szToITy(szs),mkexpr(addr))));
2226 }
sewardj9334b0f2004-07-10 22:43:54 +00002227 DIP("mov%c%c%c %s,%s\n", sign_extend ? 's' : 'z',
2228 nameISize(szs), nameISize(szd),
2229 dis_buf, nameIReg(szd,gregOfRM(rm)));
sewardj0611d802004-07-11 02:37:54 +00002230 return len+delta;
sewardj9334b0f2004-07-10 22:43:54 +00002231 }
2232}
2233
sewardj9690d922004-07-14 01:39:17 +00002234
2235/* Generate code to divide ArchRegs EDX:EAX / DX:AX / AX by the 32 /
2236 16 / 8 bit quantity in the given IRTemp. */
2237static
2238void codegen_div ( Int sz, IRTemp t, Bool signed_divide )
2239{
sewardje5427e82004-09-11 19:43:51 +00002240 IROp op = signed_divide ? Iop_DivModS64to32 : Iop_DivModU64to32;
2241 IRTemp src64 = newTemp(Ity_I64);
2242 IRTemp dst64 = newTemp(Ity_I64);
sewardj9690d922004-07-14 01:39:17 +00002243 switch (sz) {
sewardje5427e82004-09-11 19:43:51 +00002244 case 4:
sewardj9690d922004-07-14 01:39:17 +00002245 assign( src64, binop(Iop_32HLto64,
sewardje5427e82004-09-11 19:43:51 +00002246 getIReg(4,R_EDX), getIReg(4,R_EAX)) );
sewardj9690d922004-07-14 01:39:17 +00002247 assign( dst64, binop(op, mkexpr(src64), mkexpr(t)) );
sewardj8c7f1ab2004-07-29 20:31:09 +00002248 putIReg( 4, R_EAX, unop(Iop_64to32,mkexpr(dst64)) );
sewardj9690d922004-07-14 01:39:17 +00002249 putIReg( 4, R_EDX, unop(Iop_64HIto32,mkexpr(dst64)) );
2250 break;
sewardje5427e82004-09-11 19:43:51 +00002251 case 2: {
2252 IROp widen3264 = signed_divide ? Iop_32Sto64 : Iop_32Uto64;
2253 IROp widen1632 = signed_divide ? Iop_16Sto32 : Iop_16Uto32;
2254 assign( src64, unop(widen3264,
2255 binop(Iop_16HLto32,
2256 getIReg(2,R_EDX), getIReg(2,R_EAX))) );
2257 assign( dst64, binop(op, mkexpr(src64), unop(widen1632,mkexpr(t))) );
2258 putIReg( 2, R_EAX, unop(Iop_32to16,unop(Iop_64to32,mkexpr(dst64))) );
2259 putIReg( 2, R_EDX, unop(Iop_32to16,unop(Iop_64HIto32,mkexpr(dst64))) );
2260 break;
sewardj9690d922004-07-14 01:39:17 +00002261 }
sewardj4e82db72004-10-16 11:32:15 +00002262 case 1: {
2263 IROp widen3264 = signed_divide ? Iop_32Sto64 : Iop_32Uto64;
2264 IROp widen1632 = signed_divide ? Iop_16Sto32 : Iop_16Uto32;
2265 IROp widen816 = signed_divide ? Iop_8Sto16 : Iop_8Uto16;
2266 assign( src64, unop(widen3264, unop(widen1632, getIReg(2,R_EAX))) );
2267 assign( dst64,
2268 binop(op, mkexpr(src64),
2269 unop(widen1632, unop(widen816, mkexpr(t)))) );
2270 putIReg( 1, R_AL, unop(Iop_16to8, unop(Iop_32to16,
2271 unop(Iop_64to32,mkexpr(dst64)))) );
2272 putIReg( 1, R_AH, unop(Iop_16to8, unop(Iop_32to16,
2273 unop(Iop_64HIto32,mkexpr(dst64)))) );
2274 break;
2275 }
sewardj9690d922004-07-14 01:39:17 +00002276 default: vpanic("codegen_div(x86)");
2277 }
2278}
sewardj41f43bc2004-07-08 14:23:22 +00002279
2280
2281static
sewardje9d8a262009-07-01 08:06:34 +00002282UInt dis_Grp1 ( UChar sorb, Bool locked,
sewardj52d04912005-07-03 00:52:48 +00002283 Int delta, UChar modrm,
sewardj41f43bc2004-07-08 14:23:22 +00002284 Int am_sz, Int d_sz, Int sz, UInt d32 )
2285{
sewardj41f43bc2004-07-08 14:23:22 +00002286 Int len;
sewardjc9a43662004-11-30 18:51:59 +00002287 HChar dis_buf[50];
sewardje05c42c2004-07-08 20:25:10 +00002288 IRType ty = szToITy(sz);
2289 IRTemp dst1 = newTemp(ty);
2290 IRTemp src = newTemp(ty);
2291 IRTemp dst0 = newTemp(ty);
sewardj92d168d2004-11-15 14:22:12 +00002292 IRTemp addr = IRTemp_INVALID;
sewardj66de2272004-07-16 21:19:05 +00002293 IROp op8 = Iop_INVALID;
sewardj180e8b32004-07-29 01:40:11 +00002294 UInt mask = sz==1 ? 0xFF : (sz==2 ? 0xFFFF : 0xFFFFFFFF);
sewardj41f43bc2004-07-08 14:23:22 +00002295
2296 switch (gregOfRM(modrm)) {
sewardje05c42c2004-07-08 20:25:10 +00002297 case 0: op8 = Iop_Add8; break; case 1: op8 = Iop_Or8; break;
sewardj66de2272004-07-16 21:19:05 +00002298 case 2: break; // ADC
2299 case 3: break; // SBB
sewardje05c42c2004-07-08 20:25:10 +00002300 case 4: op8 = Iop_And8; break; case 5: op8 = Iop_Sub8; break;
2301 case 6: op8 = Iop_Xor8; break; case 7: op8 = Iop_Sub8; break;
sewardjd51dc812007-03-20 14:18:45 +00002302 /*NOTREACHED*/
sewardj41f43bc2004-07-08 14:23:22 +00002303 default: vpanic("dis_Grp1: unhandled case");
2304 }
sewardj41f43bc2004-07-08 14:23:22 +00002305
2306 if (epartIsReg(modrm)) {
2307 vassert(am_sz == 1);
2308
2309 assign(dst0, getIReg(sz,eregOfRM(modrm)));
sewardj180e8b32004-07-29 01:40:11 +00002310 assign(src, mkU(ty,d32 & mask));
sewardj41f43bc2004-07-08 14:23:22 +00002311
sewardj180e8b32004-07-29 01:40:11 +00002312 if (gregOfRM(modrm) == 2 /* ADC */) {
sewardje9d8a262009-07-01 08:06:34 +00002313 helper_ADC( sz, dst1, dst0, src,
2314 /*no store*/IRTemp_INVALID, IRTemp_INVALID, 0 );
sewardj180e8b32004-07-29 01:40:11 +00002315 } else
2316 if (gregOfRM(modrm) == 3 /* SBB */) {
sewardje9d8a262009-07-01 08:06:34 +00002317 helper_SBB( sz, dst1, dst0, src,
2318 /*no store*/IRTemp_INVALID, IRTemp_INVALID, 0 );
sewardj180e8b32004-07-29 01:40:11 +00002319 } else {
2320 assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)));
sewardj5bd4d162004-11-10 13:02:48 +00002321 if (isAddSub(op8))
sewardj2a2ba8b2004-11-08 13:14:06 +00002322 setFlags_DEP1_DEP2(op8, dst0, src, ty);
sewardjb9c5cf62004-08-24 15:10:38 +00002323 else
sewardj2a2ba8b2004-11-08 13:14:06 +00002324 setFlags_DEP1(op8, dst1, ty);
sewardj180e8b32004-07-29 01:40:11 +00002325 }
sewardj41f43bc2004-07-08 14:23:22 +00002326
2327 if (gregOfRM(modrm) < 7)
sewardje05c42c2004-07-08 20:25:10 +00002328 putIReg(sz, eregOfRM(modrm), mkexpr(dst1));
sewardj41f43bc2004-07-08 14:23:22 +00002329
2330 delta += (am_sz + d_sz);
2331 DIP("%s%c $0x%x, %s\n", nameGrp1(gregOfRM(modrm)), nameISize(sz), d32,
2332 nameIReg(sz,eregOfRM(modrm)));
2333 } else {
sewardje87b4842004-07-10 12:23:30 +00002334 addr = disAMode ( &len, sorb, delta, dis_buf);
sewardj41f43bc2004-07-08 14:23:22 +00002335
sewardj940e8c92004-07-11 16:53:24 +00002336 assign(dst0, loadLE(ty,mkexpr(addr)));
sewardj180e8b32004-07-29 01:40:11 +00002337 assign(src, mkU(ty,d32 & mask));
sewardj41f43bc2004-07-08 14:23:22 +00002338
sewardj66de2272004-07-16 21:19:05 +00002339 if (gregOfRM(modrm) == 2 /* ADC */) {
sewardje9d8a262009-07-01 08:06:34 +00002340 if (locked) {
2341 /* cas-style store */
2342 helper_ADC( sz, dst1, dst0, src,
2343 /*store*/addr, dst0/*expVal*/, guest_EIP_curr_instr );
2344 } else {
2345 /* normal store */
2346 helper_ADC( sz, dst1, dst0, src,
2347 /*store*/addr, IRTemp_INVALID, 0 );
2348 }
sewardj3af115f2004-07-14 02:46:52 +00002349 } else
sewardj66de2272004-07-16 21:19:05 +00002350 if (gregOfRM(modrm) == 3 /* SBB */) {
sewardje9d8a262009-07-01 08:06:34 +00002351 if (locked) {
2352 /* cas-style store */
2353 helper_SBB( sz, dst1, dst0, src,
2354 /*store*/addr, dst0/*expVal*/, guest_EIP_curr_instr );
2355 } else {
2356 /* normal store */
2357 helper_SBB( sz, dst1, dst0, src,
2358 /*store*/addr, IRTemp_INVALID, 0 );
2359 }
sewardj3af115f2004-07-14 02:46:52 +00002360 } else {
2361 assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)));
sewardje9d8a262009-07-01 08:06:34 +00002362 if (gregOfRM(modrm) < 7) {
2363 if (locked) {
2364 casLE( mkexpr(addr), mkexpr(dst0)/*expVal*/,
2365 mkexpr(dst1)/*newVal*/,
2366 guest_EIP_curr_instr );
2367 } else {
2368 storeLE(mkexpr(addr), mkexpr(dst1));
2369 }
2370 }
sewardj5bd4d162004-11-10 13:02:48 +00002371 if (isAddSub(op8))
sewardj2a2ba8b2004-11-08 13:14:06 +00002372 setFlags_DEP1_DEP2(op8, dst0, src, ty);
sewardjb9c5cf62004-08-24 15:10:38 +00002373 else
sewardj2a2ba8b2004-11-08 13:14:06 +00002374 setFlags_DEP1(op8, dst1, ty);
sewardj3af115f2004-07-14 02:46:52 +00002375 }
sewardj41f43bc2004-07-08 14:23:22 +00002376
sewardj41f43bc2004-07-08 14:23:22 +00002377 delta += (len+d_sz);
2378 DIP("%s%c $0x%x, %s\n", nameGrp1(gregOfRM(modrm)), nameISize(sz),
2379 d32, dis_buf);
2380 }
2381 return delta;
2382}
2383
2384
sewardj6d2638e2004-07-15 09:38:27 +00002385/* Group 2 extended opcodes. shift_expr must be an 8-bit typed
2386 expression. */
2387
sewardje90ad6a2004-07-10 19:02:10 +00002388static
sewardj52d04912005-07-03 00:52:48 +00002389UInt dis_Grp2 ( UChar sorb,
2390 Int delta, UChar modrm,
sewardj6d2638e2004-07-15 09:38:27 +00002391 Int am_sz, Int d_sz, Int sz, IRExpr* shift_expr,
florian55085f82012-11-21 00:36:55 +00002392 const HChar* shift_expr_txt, Bool* decode_OK )
sewardje90ad6a2004-07-10 19:02:10 +00002393{
2394 /* delta on entry points at the modrm byte. */
sewardjc9a43662004-11-30 18:51:59 +00002395 HChar dis_buf[50];
sewardj6d2638e2004-07-15 09:38:27 +00002396 Int len;
sewardj2eef7732005-08-23 15:41:14 +00002397 Bool isShift, isRotate, isRotateC;
sewardj6d2638e2004-07-15 09:38:27 +00002398 IRType ty = szToITy(sz);
2399 IRTemp dst0 = newTemp(ty);
2400 IRTemp dst1 = newTemp(ty);
sewardj92d168d2004-11-15 14:22:12 +00002401 IRTemp addr = IRTemp_INVALID;
sewardje90ad6a2004-07-10 19:02:10 +00002402
sewardjd51dc812007-03-20 14:18:45 +00002403 *decode_OK = True;
2404
sewardje90ad6a2004-07-10 19:02:10 +00002405 vassert(sz == 1 || sz == 2 || sz == 4);
2406
sewardje90ad6a2004-07-10 19:02:10 +00002407 /* Put value to shift/rotate in dst0. */
2408 if (epartIsReg(modrm)) {
2409 assign(dst0, getIReg(sz, eregOfRM(modrm)));
sewardj940e8c92004-07-11 16:53:24 +00002410 delta += (am_sz + d_sz);
sewardje90ad6a2004-07-10 19:02:10 +00002411 } else {
sewardj940e8c92004-07-11 16:53:24 +00002412 addr = disAMode ( &len, sorb, delta, dis_buf);
2413 assign(dst0, loadLE(ty,mkexpr(addr)));
2414 delta += len + d_sz;
sewardje90ad6a2004-07-10 19:02:10 +00002415 }
2416
2417 isShift = False;
tomd6b43fd2011-08-19 16:06:52 +00002418 switch (gregOfRM(modrm)) { case 4: case 5: case 6: case 7: isShift = True; }
sewardje90ad6a2004-07-10 19:02:10 +00002419
sewardj750f4072004-07-26 22:39:11 +00002420 isRotate = False;
2421 switch (gregOfRM(modrm)) { case 0: case 1: isRotate = True; }
2422
sewardj2eef7732005-08-23 15:41:14 +00002423 isRotateC = False;
2424 switch (gregOfRM(modrm)) { case 2: case 3: isRotateC = True; }
sewardj9aebb0c2004-10-24 19:20:43 +00002425
sewardj2eef7732005-08-23 15:41:14 +00002426 if (!isShift && !isRotate && !isRotateC) {
sewardjd51dc812007-03-20 14:18:45 +00002427 /*NOTREACHED*/
sewardj8c7f1ab2004-07-29 20:31:09 +00002428 vpanic("dis_Grp2(Reg): unhandled case(x86)");
2429 }
2430
sewardj2eef7732005-08-23 15:41:14 +00002431 if (isRotateC) {
2432 /* call a helper; these insns are so ridiculous they do not
2433 deserve better */
2434 Bool left = toBool(gregOfRM(modrm) == 2);
sewardj9aebb0c2004-10-24 19:20:43 +00002435 IRTemp r64 = newTemp(Ity_I64);
sewardjf9655262004-10-31 20:02:16 +00002436 IRExpr** args
2437 = mkIRExprVec_4( widenUto32(mkexpr(dst0)), /* thing to rotate */
2438 widenUto32(shift_expr), /* rotate amount */
sewardj2a9ad022004-11-25 02:46:58 +00002439 widenUto32(mk_x86g_calculate_eflags_all()),
sewardjf9655262004-10-31 20:02:16 +00002440 mkU32(sz) );
2441 assign( r64, mkIRExprCCall(
sewardj8ea867b2004-10-30 19:03:02 +00002442 Ity_I64,
sewardjf9655262004-10-31 20:02:16 +00002443 0/*regparm*/,
sewardj2eef7732005-08-23 15:41:14 +00002444 left ? "x86g_calculate_RCL" : "x86g_calculate_RCR",
2445 left ? &x86g_calculate_RCL : &x86g_calculate_RCR,
sewardj8ea867b2004-10-30 19:03:02 +00002446 args
sewardjf9655262004-10-31 20:02:16 +00002447 )
2448 );
sewardj9aebb0c2004-10-24 19:20:43 +00002449 /* new eflags in hi half r64; new value in lo half r64 */
2450 assign( dst1, narrowTo(ty, unop(Iop_64to32, mkexpr(r64))) );
sewardj2a9ad022004-11-25 02:46:58 +00002451 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(X86G_CC_OP_COPY) ));
sewardj2a2ba8b2004-11-08 13:14:06 +00002452 stmt( IRStmt_Put( OFFB_CC_DEP1, unop(Iop_64HIto32, mkexpr(r64)) ));
2453 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
sewardja3b7e3a2005-04-05 01:54:19 +00002454 /* Set NDEP even though it isn't used. This makes redundant-PUT
2455 elimination of previous stores to this field work better. */
2456 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
sewardj9aebb0c2004-10-24 19:20:43 +00002457 }
2458
sewardje90ad6a2004-07-10 19:02:10 +00002459 if (isShift) {
2460
sewardjc22a6fd2004-07-29 23:41:47 +00002461 IRTemp pre32 = newTemp(Ity_I32);
2462 IRTemp res32 = newTemp(Ity_I32);
2463 IRTemp res32ss = newTemp(Ity_I32);
sewardj6d2638e2004-07-15 09:38:27 +00002464 IRTemp shift_amt = newTemp(Ity_I8);
sewardjc22a6fd2004-07-29 23:41:47 +00002465 IROp op32;
sewardje90ad6a2004-07-10 19:02:10 +00002466
2467 switch (gregOfRM(modrm)) {
sewardjc22a6fd2004-07-29 23:41:47 +00002468 case 4: op32 = Iop_Shl32; break;
2469 case 5: op32 = Iop_Shr32; break;
tomd6b43fd2011-08-19 16:06:52 +00002470 case 6: op32 = Iop_Shl32; break;
sewardjc22a6fd2004-07-29 23:41:47 +00002471 case 7: op32 = Iop_Sar32; break;
sewardjd51dc812007-03-20 14:18:45 +00002472 /*NOTREACHED*/
sewardje90ad6a2004-07-10 19:02:10 +00002473 default: vpanic("dis_Grp2:shift"); break;
2474 }
2475
sewardjc22a6fd2004-07-29 23:41:47 +00002476 /* Widen the value to be shifted to 32 bits, do the shift, and
2477 narrow back down. This seems surprisingly long-winded, but
2478 unfortunately the Intel semantics requires that 8/16-bit
2479 shifts give defined results for shift values all the way up
2480 to 31, and this seems the simplest way to do it. It has the
2481 advantage that the only IR level shifts generated are of 32
2482 bit values, and the shift amount is guaranteed to be in the
2483 range 0 .. 31, thereby observing the IR semantics requiring
2484 all shift values to be in the range 0 .. 2^word_size-1. */
2485
2486 /* shift_amt = shift_expr & 31, regardless of operation size */
2487 assign( shift_amt, binop(Iop_And8, shift_expr, mkU8(31)) );
2488
2489 /* suitably widen the value to be shifted to 32 bits. */
2490 assign( pre32, op32==Iop_Sar32 ? widenSto32(mkexpr(dst0))
2491 : widenUto32(mkexpr(dst0)) );
2492
2493 /* res32 = pre32 `shift` shift_amt */
2494 assign( res32, binop(op32, mkexpr(pre32), mkexpr(shift_amt)) );
2495
2496 /* res32ss = pre32 `shift` ((shift_amt - 1) & 31) */
2497 assign( res32ss,
2498 binop(op32,
2499 mkexpr(pre32),
2500 binop(Iop_And8,
2501 binop(Iop_Sub8,
2502 mkexpr(shift_amt), mkU8(1)),
2503 mkU8(31))) );
sewardje90ad6a2004-07-10 19:02:10 +00002504
2505 /* Build the flags thunk. */
sewardj2a2ba8b2004-11-08 13:14:06 +00002506 setFlags_DEP1_DEP2_shift(op32, res32, res32ss, ty, shift_amt);
sewardjc22a6fd2004-07-29 23:41:47 +00002507
2508 /* Narrow the result back down. */
2509 assign( dst1, narrowTo(ty, mkexpr(res32)) );
sewardj750f4072004-07-26 22:39:11 +00002510
sewardj1813dbe2004-07-28 17:09:04 +00002511 } /* if (isShift) */
2512
2513 else
sewardj750f4072004-07-26 22:39:11 +00002514 if (isRotate) {
sewardj7ebbdae2004-08-26 12:30:48 +00002515 Int ccOp = ty==Ity_I8 ? 0 : (ty==Ity_I16 ? 1 : 2);
sewardj2d49b432005-02-01 00:37:06 +00002516 Bool left = toBool(gregOfRM(modrm) == 0);
sewardj7ebbdae2004-08-26 12:30:48 +00002517 IRTemp rot_amt = newTemp(Ity_I8);
2518 IRTemp rot_amt32 = newTemp(Ity_I8);
2519 IRTemp oldFlags = newTemp(Ity_I32);
sewardj750f4072004-07-26 22:39:11 +00002520
2521 /* rot_amt = shift_expr & mask */
sewardjc22a6fd2004-07-29 23:41:47 +00002522 /* By masking the rotate amount thusly, the IR-level Shl/Shr
2523 expressions never shift beyond the word size and thus remain
2524 well defined. */
sewardj7ebbdae2004-08-26 12:30:48 +00002525 assign(rot_amt32, binop(Iop_And8, shift_expr, mkU8(31)));
2526
2527 if (ty == Ity_I32)
2528 assign(rot_amt, mkexpr(rot_amt32));
2529 else
2530 assign(rot_amt, binop(Iop_And8, mkexpr(rot_amt32), mkU8(8*sz-1)));
sewardj750f4072004-07-26 22:39:11 +00002531
2532 if (left) {
sewardj1813dbe2004-07-28 17:09:04 +00002533
sewardj750f4072004-07-26 22:39:11 +00002534 /* dst1 = (dst0 << rot_amt) | (dst0 >>u (wordsize-rot_amt)) */
2535 assign(dst1,
2536 binop( mkSizedOp(ty,Iop_Or8),
2537 binop( mkSizedOp(ty,Iop_Shl8),
2538 mkexpr(dst0),
2539 mkexpr(rot_amt)
2540 ),
2541 binop( mkSizedOp(ty,Iop_Shr8),
2542 mkexpr(dst0),
2543 binop(Iop_Sub8,mkU8(8*sz), mkexpr(rot_amt))
2544 )
2545 )
2546 );
sewardj2a9ad022004-11-25 02:46:58 +00002547 ccOp += X86G_CC_OP_ROLB;
sewardj750f4072004-07-26 22:39:11 +00002548
sewardj1813dbe2004-07-28 17:09:04 +00002549 } else { /* right */
sewardj750f4072004-07-26 22:39:11 +00002550
sewardj1813dbe2004-07-28 17:09:04 +00002551 /* dst1 = (dst0 >>u rot_amt) | (dst0 << (wordsize-rot_amt)) */
2552 assign(dst1,
2553 binop( mkSizedOp(ty,Iop_Or8),
2554 binop( mkSizedOp(ty,Iop_Shr8),
2555 mkexpr(dst0),
2556 mkexpr(rot_amt)
2557 ),
2558 binop( mkSizedOp(ty,Iop_Shl8),
2559 mkexpr(dst0),
2560 binop(Iop_Sub8,mkU8(8*sz), mkexpr(rot_amt))
sewardj750f4072004-07-26 22:39:11 +00002561 )
2562 )
2563 );
sewardj2a9ad022004-11-25 02:46:58 +00002564 ccOp += X86G_CC_OP_RORB;
sewardjc22a6fd2004-07-29 23:41:47 +00002565
sewardj750f4072004-07-26 22:39:11 +00002566 }
sewardjc22a6fd2004-07-29 23:41:47 +00002567
sewardj1813dbe2004-07-28 17:09:04 +00002568 /* dst1 now holds the rotated value. Build flag thunk. We
2569 need the resulting value for this, and the previous flags.
2570 Except don't set it if the rotate count is zero. */
2571
sewardj2a9ad022004-11-25 02:46:58 +00002572 assign(oldFlags, mk_x86g_calculate_eflags_all());
sewardj1813dbe2004-07-28 17:09:04 +00002573
sewardj009230b2013-01-26 11:47:55 +00002574 /* rot_amt32 :: Ity_I8. We need to convert it to I1. */
2575 IRTemp rot_amt32b = newTemp(Ity_I1);
2576 assign(rot_amt32b, binop(Iop_CmpNE8, mkexpr(rot_amt32), mkU8(0)) );
2577
sewardj2a2ba8b2004-11-08 13:14:06 +00002578 /* CC_DEP1 is the rotated value. CC_NDEP is flags before. */
sewardj1813dbe2004-07-28 17:09:04 +00002579 stmt( IRStmt_Put( OFFB_CC_OP,
florian99dd03e2013-01-29 03:56:06 +00002580 IRExpr_ITE( mkexpr(rot_amt32b),
2581 mkU32(ccOp),
2582 IRExpr_Get(OFFB_CC_OP,Ity_I32) ) ));
sewardj2a2ba8b2004-11-08 13:14:06 +00002583 stmt( IRStmt_Put( OFFB_CC_DEP1,
florian99dd03e2013-01-29 03:56:06 +00002584 IRExpr_ITE( mkexpr(rot_amt32b),
2585 widenUto32(mkexpr(dst1)),
2586 IRExpr_Get(OFFB_CC_DEP1,Ity_I32) ) ));
sewardj2a2ba8b2004-11-08 13:14:06 +00002587 stmt( IRStmt_Put( OFFB_CC_DEP2,
florian99dd03e2013-01-29 03:56:06 +00002588 IRExpr_ITE( mkexpr(rot_amt32b),
2589 mkU32(0),
2590 IRExpr_Get(OFFB_CC_DEP2,Ity_I32) ) ));
sewardj2a2ba8b2004-11-08 13:14:06 +00002591 stmt( IRStmt_Put( OFFB_CC_NDEP,
florian99dd03e2013-01-29 03:56:06 +00002592 IRExpr_ITE( mkexpr(rot_amt32b),
2593 mkexpr(oldFlags),
2594 IRExpr_Get(OFFB_CC_NDEP,Ity_I32) ) ));
sewardj1813dbe2004-07-28 17:09:04 +00002595 } /* if (isRotate) */
sewardje90ad6a2004-07-10 19:02:10 +00002596
2597 /* Save result, and finish up. */
2598 if (epartIsReg(modrm)) {
2599 putIReg(sz, eregOfRM(modrm), mkexpr(dst1));
sewardjf48ac192004-10-29 00:41:29 +00002600 if (vex_traceflags & VEX_TRACE_FE) {
sewardje90ad6a2004-07-10 19:02:10 +00002601 vex_printf("%s%c ",
2602 nameGrp2(gregOfRM(modrm)), nameISize(sz) );
sewardj6d2638e2004-07-15 09:38:27 +00002603 if (shift_expr_txt)
2604 vex_printf("%s", shift_expr_txt);
2605 else
2606 ppIRExpr(shift_expr);
sewardje90ad6a2004-07-10 19:02:10 +00002607 vex_printf(", %s\n", nameIReg(sz,eregOfRM(modrm)));
2608 }
sewardje90ad6a2004-07-10 19:02:10 +00002609 } else {
sewardj940e8c92004-07-11 16:53:24 +00002610 storeLE(mkexpr(addr), mkexpr(dst1));
sewardjf48ac192004-10-29 00:41:29 +00002611 if (vex_traceflags & VEX_TRACE_FE) {
sewardj940e8c92004-07-11 16:53:24 +00002612 vex_printf("%s%c ",
2613 nameGrp2(gregOfRM(modrm)), nameISize(sz) );
sewardj6d2638e2004-07-15 09:38:27 +00002614 if (shift_expr_txt)
2615 vex_printf("%s", shift_expr_txt);
2616 else
2617 ppIRExpr(shift_expr);
sewardj940e8c92004-07-11 16:53:24 +00002618 vex_printf(", %s\n", dis_buf);
2619 }
sewardje90ad6a2004-07-10 19:02:10 +00002620 }
sewardje90ad6a2004-07-10 19:02:10 +00002621 return delta;
2622}
2623
2624
sewardj490ad382005-03-13 17:25:53 +00002625/* Group 8 extended opcodes (but BT/BTS/BTC/BTR only). */
2626static
sewardj52d04912005-07-03 00:52:48 +00002627UInt dis_Grp8_Imm ( UChar sorb,
sewardje9d8a262009-07-01 08:06:34 +00002628 Bool locked,
sewardj52d04912005-07-03 00:52:48 +00002629 Int delta, UChar modrm,
sewardj490ad382005-03-13 17:25:53 +00002630 Int am_sz, Int sz, UInt src_val,
2631 Bool* decode_OK )
2632{
2633 /* src_val denotes a d8.
2634 And delta on entry points at the modrm byte. */
sewardje90ad6a2004-07-10 19:02:10 +00002635
sewardj490ad382005-03-13 17:25:53 +00002636 IRType ty = szToITy(sz);
2637 IRTemp t2 = newTemp(Ity_I32);
2638 IRTemp t2m = newTemp(Ity_I32);
2639 IRTemp t_addr = IRTemp_INVALID;
2640 HChar dis_buf[50];
2641 UInt mask;
sewardjd1061ab2004-07-08 01:45:30 +00002642
sewardj490ad382005-03-13 17:25:53 +00002643 /* we're optimists :-) */
2644 *decode_OK = True;
sewardjd1061ab2004-07-08 01:45:30 +00002645
sewardj490ad382005-03-13 17:25:53 +00002646 /* Limit src_val -- the bit offset -- to something within a word.
2647 The Intel docs say that literal offsets larger than a word are
2648 masked in this way. */
2649 switch (sz) {
2650 case 2: src_val &= 15; break;
2651 case 4: src_val &= 31; break;
2652 default: *decode_OK = False; return delta;
2653 }
sewardjcf780b42004-07-13 18:42:17 +00002654
sewardj490ad382005-03-13 17:25:53 +00002655 /* Invent a mask suitable for the operation. */
2656 switch (gregOfRM(modrm)) {
2657 case 4: /* BT */ mask = 0; break;
2658 case 5: /* BTS */ mask = 1 << src_val; break;
2659 case 6: /* BTR */ mask = ~(1 << src_val); break;
2660 case 7: /* BTC */ mask = 1 << src_val; break;
2661 /* If this needs to be extended, probably simplest to make a
2662 new function to handle the other cases (0 .. 3). The
2663 Intel docs do however not indicate any use for 0 .. 3, so
2664 we don't expect this to happen. */
2665 default: *decode_OK = False; return delta;
2666 }
2667
2668 /* Fetch the value to be tested and modified into t2, which is
2669 32-bits wide regardless of sz. */
2670 if (epartIsReg(modrm)) {
2671 vassert(am_sz == 1);
sewardj5a8334e2005-03-13 19:52:45 +00002672 assign( t2, widenUto32(getIReg(sz, eregOfRM(modrm))) );
sewardj490ad382005-03-13 17:25:53 +00002673 delta += (am_sz + 1);
2674 DIP("%s%c $0x%x, %s\n", nameGrp8(gregOfRM(modrm)), nameISize(sz),
2675 src_val, nameIReg(sz,eregOfRM(modrm)));
2676 } else {
2677 Int len;
2678 t_addr = disAMode ( &len, sorb, delta, dis_buf);
2679 delta += (len+1);
2680 assign( t2, widenUto32(loadLE(ty, mkexpr(t_addr))) );
2681 DIP("%s%c $0x%x, %s\n", nameGrp8(gregOfRM(modrm)), nameISize(sz),
2682 src_val, dis_buf);
2683 }
2684
sewardj490ad382005-03-13 17:25:53 +00002685 /* Compute the new value into t2m, if non-BT. */
2686 switch (gregOfRM(modrm)) {
2687 case 4: /* BT */
2688 break;
2689 case 5: /* BTS */
2690 assign( t2m, binop(Iop_Or32, mkU32(mask), mkexpr(t2)) );
2691 break;
2692 case 6: /* BTR */
2693 assign( t2m, binop(Iop_And32, mkU32(mask), mkexpr(t2)) );
2694 break;
2695 case 7: /* BTC */
2696 assign( t2m, binop(Iop_Xor32, mkU32(mask), mkexpr(t2)) );
2697 break;
sewardjba89f4c2005-04-07 17:31:27 +00002698 default:
2699 /*NOTREACHED*/ /*the previous switch guards this*/
sewardj490ad382005-03-13 17:25:53 +00002700 vassert(0);
2701 }
2702
sewardje9d8a262009-07-01 08:06:34 +00002703 /* Write the result back, if non-BT. If the CAS fails then we
2704 side-exit from the trace at this point, and so the flag state is
2705 not affected. This is of course as required. */
sewardj490ad382005-03-13 17:25:53 +00002706 if (gregOfRM(modrm) != 4 /* BT */) {
2707 if (epartIsReg(modrm)) {
sewardje9d8a262009-07-01 08:06:34 +00002708 putIReg(sz, eregOfRM(modrm), narrowTo(ty, mkexpr(t2m)));
sewardj490ad382005-03-13 17:25:53 +00002709 } else {
sewardje9d8a262009-07-01 08:06:34 +00002710 if (locked) {
2711 casLE( mkexpr(t_addr),
2712 narrowTo(ty, mkexpr(t2))/*expd*/,
2713 narrowTo(ty, mkexpr(t2m))/*new*/,
2714 guest_EIP_curr_instr );
2715 } else {
2716 storeLE(mkexpr(t_addr), narrowTo(ty, mkexpr(t2m)));
2717 }
sewardj490ad382005-03-13 17:25:53 +00002718 }
2719 }
2720
sewardje9d8a262009-07-01 08:06:34 +00002721 /* Copy relevant bit from t2 into the carry flag. */
2722 /* Flags: C=selected bit, O,S,Z,A,P undefined, so are set to zero. */
2723 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(X86G_CC_OP_COPY) ));
2724 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
2725 stmt( IRStmt_Put(
2726 OFFB_CC_DEP1,
2727 binop(Iop_And32,
2728 binop(Iop_Shr32, mkexpr(t2), mkU8(src_val)),
2729 mkU32(1))
2730 ));
2731 /* Set NDEP even though it isn't used. This makes redundant-PUT
2732 elimination of previous stores to this field work better. */
2733 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
2734
sewardj490ad382005-03-13 17:25:53 +00002735 return delta;
2736}
sewardjcf780b42004-07-13 18:42:17 +00002737
2738
sewardj1813dbe2004-07-28 17:09:04 +00002739/* Signed/unsigned widening multiply. Generate IR to multiply the
2740 value in EAX/AX/AL by the given IRTemp, and park the result in
2741 EDX:EAX/DX:AX/AX.
sewardjcf780b42004-07-13 18:42:17 +00002742*/
sewardj1813dbe2004-07-28 17:09:04 +00002743static void codegen_mulL_A_D ( Int sz, Bool syned,
florian55085f82012-11-21 00:36:55 +00002744 IRTemp tmp, const HChar* tmp_txt )
sewardjcf780b42004-07-13 18:42:17 +00002745{
sewardjcf780b42004-07-13 18:42:17 +00002746 IRType ty = szToITy(sz);
2747 IRTemp t1 = newTemp(ty);
sewardjcf780b42004-07-13 18:42:17 +00002748
sewardj1813dbe2004-07-28 17:09:04 +00002749 assign( t1, getIReg(sz, R_EAX) );
sewardjcf780b42004-07-13 18:42:17 +00002750
2751 switch (ty) {
sewardjb81f8b32004-07-30 10:17:50 +00002752 case Ity_I32: {
2753 IRTemp res64 = newTemp(Ity_I64);
sewardj948d48b2004-11-05 19:49:09 +00002754 IRTemp resHi = newTemp(Ity_I32);
2755 IRTemp resLo = newTemp(Ity_I32);
sewardjb81f8b32004-07-30 10:17:50 +00002756 IROp mulOp = syned ? Iop_MullS32 : Iop_MullU32;
sewardj2a9ad022004-11-25 02:46:58 +00002757 UInt tBaseOp = syned ? X86G_CC_OP_SMULB : X86G_CC_OP_UMULB;
sewardj2a2ba8b2004-11-08 13:14:06 +00002758 setFlags_MUL ( Ity_I32, t1, tmp, tBaseOp );
sewardjb81f8b32004-07-30 10:17:50 +00002759 assign( res64, binop(mulOp, mkexpr(t1), mkexpr(tmp)) );
sewardj948d48b2004-11-05 19:49:09 +00002760 assign( resHi, unop(Iop_64HIto32,mkexpr(res64)));
2761 assign( resLo, unop(Iop_64to32,mkexpr(res64)));
sewardj948d48b2004-11-05 19:49:09 +00002762 putIReg(4, R_EDX, mkexpr(resHi));
2763 putIReg(4, R_EAX, mkexpr(resLo));
sewardjb81f8b32004-07-30 10:17:50 +00002764 break;
2765 }
2766 case Ity_I16: {
2767 IRTemp res32 = newTemp(Ity_I32);
sewardj948d48b2004-11-05 19:49:09 +00002768 IRTemp resHi = newTemp(Ity_I16);
2769 IRTemp resLo = newTemp(Ity_I16);
sewardjb81f8b32004-07-30 10:17:50 +00002770 IROp mulOp = syned ? Iop_MullS16 : Iop_MullU16;
sewardj2a9ad022004-11-25 02:46:58 +00002771 UInt tBaseOp = syned ? X86G_CC_OP_SMULB : X86G_CC_OP_UMULB;
sewardj2a2ba8b2004-11-08 13:14:06 +00002772 setFlags_MUL ( Ity_I16, t1, tmp, tBaseOp );
sewardjb81f8b32004-07-30 10:17:50 +00002773 assign( res32, binop(mulOp, mkexpr(t1), mkexpr(tmp)) );
sewardj948d48b2004-11-05 19:49:09 +00002774 assign( resHi, unop(Iop_32HIto16,mkexpr(res32)));
2775 assign( resLo, unop(Iop_32to16,mkexpr(res32)));
sewardj948d48b2004-11-05 19:49:09 +00002776 putIReg(2, R_EDX, mkexpr(resHi));
2777 putIReg(2, R_EAX, mkexpr(resLo));
sewardjb81f8b32004-07-30 10:17:50 +00002778 break;
2779 }
2780 case Ity_I8: {
2781 IRTemp res16 = newTemp(Ity_I16);
sewardj948d48b2004-11-05 19:49:09 +00002782 IRTemp resHi = newTemp(Ity_I8);
2783 IRTemp resLo = newTemp(Ity_I8);
sewardjb81f8b32004-07-30 10:17:50 +00002784 IROp mulOp = syned ? Iop_MullS8 : Iop_MullU8;
sewardj2a9ad022004-11-25 02:46:58 +00002785 UInt tBaseOp = syned ? X86G_CC_OP_SMULB : X86G_CC_OP_UMULB;
sewardj2a2ba8b2004-11-08 13:14:06 +00002786 setFlags_MUL ( Ity_I8, t1, tmp, tBaseOp );
sewardjb81f8b32004-07-30 10:17:50 +00002787 assign( res16, binop(mulOp, mkexpr(t1), mkexpr(tmp)) );
sewardj948d48b2004-11-05 19:49:09 +00002788 assign( resHi, unop(Iop_16HIto8,mkexpr(res16)));
2789 assign( resLo, unop(Iop_16to8,mkexpr(res16)));
sewardjb81f8b32004-07-30 10:17:50 +00002790 putIReg(2, R_EAX, mkexpr(res16));
2791 break;
2792 }
2793 default:
2794 vpanic("codegen_mulL_A_D(x86)");
sewardjcf780b42004-07-13 18:42:17 +00002795 }
sewardj1813dbe2004-07-28 17:09:04 +00002796 DIP("%s%c %s\n", syned ? "imul" : "mul", nameISize(sz), tmp_txt);
sewardjcf780b42004-07-13 18:42:17 +00002797}
2798
sewardj940e8c92004-07-11 16:53:24 +00002799
2800/* Group 3 extended opcodes. */
2801static
sewardje9d8a262009-07-01 08:06:34 +00002802UInt dis_Grp3 ( UChar sorb, Bool locked, Int sz, Int delta, Bool* decode_OK )
sewardj940e8c92004-07-11 16:53:24 +00002803{
sewardjc9a43662004-11-30 18:51:59 +00002804 UInt d32;
2805 UChar modrm;
2806 HChar dis_buf[50];
2807 Int len;
sewardjc2ac51e2004-07-12 01:03:26 +00002808 IRTemp addr;
sewardj940e8c92004-07-11 16:53:24 +00002809 IRType ty = szToITy(sz);
2810 IRTemp t1 = newTemp(ty);
sewardj940e8c92004-07-11 16:53:24 +00002811 IRTemp dst1, src, dst0;
sewardjd51dc812007-03-20 14:18:45 +00002812
2813 *decode_OK = True; /* may change this later */
2814
sewardj940e8c92004-07-11 16:53:24 +00002815 modrm = getIByte(delta);
sewardje9d8a262009-07-01 08:06:34 +00002816
2817 if (locked && (gregOfRM(modrm) != 2 && gregOfRM(modrm) != 3)) {
2818 /* LOCK prefix only allowed with not and neg subopcodes */
2819 *decode_OK = False;
2820 return delta;
2821 }
2822
sewardj940e8c92004-07-11 16:53:24 +00002823 if (epartIsReg(modrm)) {
2824 switch (gregOfRM(modrm)) {
sewardjc2ac51e2004-07-12 01:03:26 +00002825 case 0: { /* TEST */
2826 delta++; d32 = getUDisp(sz, delta); delta += sz;
sewardj5bd4d162004-11-10 13:02:48 +00002827 dst1 = newTemp(ty);
2828 assign(dst1, binop(mkSizedOp(ty,Iop_And8),
2829 getIReg(sz,eregOfRM(modrm)),
sewardjc2ac51e2004-07-12 01:03:26 +00002830 mkU(ty,d32)));
sewardj5bd4d162004-11-10 13:02:48 +00002831 setFlags_DEP1( Iop_And8, dst1, ty );
sewardjc2ac51e2004-07-12 01:03:26 +00002832 DIP("test%c $0x%x, %s\n", nameISize(sz), d32,
2833 nameIReg(sz, eregOfRM(modrm)));
2834 break;
2835 }
sewardjd51dc812007-03-20 14:18:45 +00002836 case 1: /* UNDEFINED */
2837 /* The Intel docs imply this insn is undefined and binutils
2838 agrees. Unfortunately Core 2 will run it (with who
2839 knows what result?) sandpile.org reckons it's an alias
2840 for case 0. We play safe. */
2841 *decode_OK = False;
2842 break;
sewardj940e8c92004-07-11 16:53:24 +00002843 case 2: /* NOT */
2844 delta++;
2845 putIReg(sz, eregOfRM(modrm),
2846 unop(mkSizedOp(ty,Iop_Not8),
2847 getIReg(sz, eregOfRM(modrm))));
2848 DIP("not%c %s\n", nameISize(sz), nameIReg(sz, eregOfRM(modrm)));
2849 break;
2850 case 3: /* NEG */
2851 delta++;
2852 dst0 = newTemp(ty);
2853 src = newTemp(ty);
2854 dst1 = newTemp(ty);
sewardj5bd4d162004-11-10 13:02:48 +00002855 assign(dst0, mkU(ty,0));
sewardja511afc2004-07-29 22:26:03 +00002856 assign(src, getIReg(sz,eregOfRM(modrm)));
sewardjeb17e492007-08-25 23:07:44 +00002857 assign(dst1, binop(mkSizedOp(ty,Iop_Sub8), mkexpr(dst0), mkexpr(src)));
sewardj2a2ba8b2004-11-08 13:14:06 +00002858 setFlags_DEP1_DEP2(Iop_Sub8, dst0, src, ty);
sewardj5bd4d162004-11-10 13:02:48 +00002859 putIReg(sz, eregOfRM(modrm), mkexpr(dst1));
sewardj940e8c92004-07-11 16:53:24 +00002860 DIP("neg%c %s\n", nameISize(sz), nameIReg(sz, eregOfRM(modrm)));
2861 break;
sewardjcf780b42004-07-13 18:42:17 +00002862 case 4: /* MUL (unsigned widening) */
2863 delta++;
sewardj1813dbe2004-07-28 17:09:04 +00002864 src = newTemp(ty);
sewardj5bd4d162004-11-10 13:02:48 +00002865 assign(src, getIReg(sz,eregOfRM(modrm)));
sewardj1813dbe2004-07-28 17:09:04 +00002866 codegen_mulL_A_D ( sz, False, src, nameIReg(sz,eregOfRM(modrm)) );
sewardjcf780b42004-07-13 18:42:17 +00002867 break;
sewardjcaca9d02004-07-28 07:11:32 +00002868 case 5: /* IMUL (signed widening) */
2869 delta++;
sewardj1813dbe2004-07-28 17:09:04 +00002870 src = newTemp(ty);
sewardj5bd4d162004-11-10 13:02:48 +00002871 assign(src, getIReg(sz,eregOfRM(modrm)));
sewardj1813dbe2004-07-28 17:09:04 +00002872 codegen_mulL_A_D ( sz, True, src, nameIReg(sz,eregOfRM(modrm)) );
sewardjcaca9d02004-07-28 07:11:32 +00002873 break;
sewardj68511542004-07-28 00:15:44 +00002874 case 6: /* DIV */
2875 delta++;
2876 assign( t1, getIReg(sz, eregOfRM(modrm)) );
2877 codegen_div ( sz, t1, False );
2878 DIP("div%c %s\n", nameISize(sz), nameIReg(sz, eregOfRM(modrm)));
2879 break;
sewardjcaca9d02004-07-28 07:11:32 +00002880 case 7: /* IDIV */
2881 delta++;
2882 assign( t1, getIReg(sz, eregOfRM(modrm)) );
2883 codegen_div ( sz, t1, True );
2884 DIP("idiv%c %s\n", nameISize(sz), nameIReg(sz, eregOfRM(modrm)));
2885 break;
sewardj940e8c92004-07-11 16:53:24 +00002886 default:
sewardjd51dc812007-03-20 14:18:45 +00002887 /* This can't happen - gregOfRM should return 0 .. 7 only */
sewardj940e8c92004-07-11 16:53:24 +00002888 vpanic("Grp3(x86)");
2889 }
2890 } else {
sewardjc2ac51e2004-07-12 01:03:26 +00002891 addr = disAMode ( &len, sorb, delta, dis_buf );
2892 t1 = newTemp(ty);
2893 delta += len;
2894 assign(t1, loadLE(ty,mkexpr(addr)));
2895 switch (gregOfRM(modrm)) {
2896 case 0: { /* TEST */
2897 d32 = getUDisp(sz, delta); delta += sz;
sewardj5bd4d162004-11-10 13:02:48 +00002898 dst1 = newTemp(ty);
2899 assign(dst1, binop(mkSizedOp(ty,Iop_And8),
2900 mkexpr(t1), mkU(ty,d32)));
2901 setFlags_DEP1( Iop_And8, dst1, ty );
sewardjc2ac51e2004-07-12 01:03:26 +00002902 DIP("test%c $0x%x, %s\n", nameISize(sz), d32, dis_buf);
2903 break;
2904 }
sewardjd51dc812007-03-20 14:18:45 +00002905 case 1: /* UNDEFINED */
2906 /* See comment above on R case */
2907 *decode_OK = False;
2908 break;
sewardj78fe7912004-08-20 23:38:07 +00002909 case 2: /* NOT */
sewardje9d8a262009-07-01 08:06:34 +00002910 dst1 = newTemp(ty);
2911 assign(dst1, unop(mkSizedOp(ty,Iop_Not8), mkexpr(t1)));
2912 if (locked) {
2913 casLE( mkexpr(addr), mkexpr(t1)/*expd*/, mkexpr(dst1)/*new*/,
2914 guest_EIP_curr_instr );
2915 } else {
2916 storeLE( mkexpr(addr), mkexpr(dst1) );
2917 }
sewardj78fe7912004-08-20 23:38:07 +00002918 DIP("not%c %s\n", nameISize(sz), dis_buf);
2919 break;
sewardj0c12ea82004-07-12 08:18:16 +00002920 case 3: /* NEG */
2921 dst0 = newTemp(ty);
2922 src = newTemp(ty);
2923 dst1 = newTemp(ty);
sewardj5bd4d162004-11-10 13:02:48 +00002924 assign(dst0, mkU(ty,0));
sewardja511afc2004-07-29 22:26:03 +00002925 assign(src, mkexpr(t1));
sewardje9d8a262009-07-01 08:06:34 +00002926 assign(dst1, binop(mkSizedOp(ty,Iop_Sub8),
2927 mkexpr(dst0), mkexpr(src)));
2928 if (locked) {
2929 casLE( mkexpr(addr), mkexpr(t1)/*expd*/, mkexpr(dst1)/*new*/,
2930 guest_EIP_curr_instr );
2931 } else {
2932 storeLE( mkexpr(addr), mkexpr(dst1) );
2933 }
sewardj2a2ba8b2004-11-08 13:14:06 +00002934 setFlags_DEP1_DEP2(Iop_Sub8, dst0, src, ty);
sewardj0c12ea82004-07-12 08:18:16 +00002935 DIP("neg%c %s\n", nameISize(sz), dis_buf);
2936 break;
sewardj1813dbe2004-07-28 17:09:04 +00002937 case 4: /* MUL */
2938 codegen_mulL_A_D ( sz, False, t1, dis_buf );
2939 break;
2940 case 5: /* IMUL */
2941 codegen_mulL_A_D ( sz, True, t1, dis_buf );
2942 break;
sewardj9690d922004-07-14 01:39:17 +00002943 case 6: /* DIV */
2944 codegen_div ( sz, t1, False );
2945 DIP("div%c %s\n", nameISize(sz), dis_buf);
2946 break;
sewardj1813dbe2004-07-28 17:09:04 +00002947 case 7: /* IDIV */
2948 codegen_div ( sz, t1, True );
2949 DIP("idiv%c %s\n", nameISize(sz), dis_buf);
2950 break;
sewardjc2ac51e2004-07-12 01:03:26 +00002951 default:
sewardjd51dc812007-03-20 14:18:45 +00002952 /* This can't happen - gregOfRM should return 0 .. 7 only */
sewardjc2ac51e2004-07-12 01:03:26 +00002953 vpanic("Grp3(x86)");
2954 }
sewardj940e8c92004-07-11 16:53:24 +00002955 }
2956 return delta;
2957}
2958
2959
sewardjc2ac51e2004-07-12 01:03:26 +00002960/* Group 4 extended opcodes. */
2961static
sewardje9d8a262009-07-01 08:06:34 +00002962UInt dis_Grp4 ( UChar sorb, Bool locked, Int delta, Bool* decode_OK )
sewardjc2ac51e2004-07-12 01:03:26 +00002963{
sewardjc9a43662004-11-30 18:51:59 +00002964 Int alen;
sewardjc2ac51e2004-07-12 01:03:26 +00002965 UChar modrm;
sewardjc9a43662004-11-30 18:51:59 +00002966 HChar dis_buf[50];
sewardjc2ac51e2004-07-12 01:03:26 +00002967 IRType ty = Ity_I8;
sewardj7ed22952004-07-29 00:09:58 +00002968 IRTemp t1 = newTemp(ty);
2969 IRTemp t2 = newTemp(ty);
sewardjc2ac51e2004-07-12 01:03:26 +00002970
sewardjd51dc812007-03-20 14:18:45 +00002971 *decode_OK = True;
2972
sewardjc2ac51e2004-07-12 01:03:26 +00002973 modrm = getIByte(delta);
sewardje9d8a262009-07-01 08:06:34 +00002974
2975 if (locked && (gregOfRM(modrm) != 0 && gregOfRM(modrm) != 1)) {
2976 /* LOCK prefix only allowed with inc and dec subopcodes */
2977 *decode_OK = False;
2978 return delta;
2979 }
2980
sewardjc2ac51e2004-07-12 01:03:26 +00002981 if (epartIsReg(modrm)) {
sewardjc2ac51e2004-07-12 01:03:26 +00002982 assign(t1, getIReg(1, eregOfRM(modrm)));
2983 switch (gregOfRM(modrm)) {
sewardj7ed22952004-07-29 00:09:58 +00002984 case 0: /* INC */
2985 assign(t2, binop(Iop_Add8, mkexpr(t1), mkU8(1)));
2986 putIReg(1, eregOfRM(modrm), mkexpr(t2));
2987 setFlags_INC_DEC( True, t2, ty );
2988 break;
sewardjc2ac51e2004-07-12 01:03:26 +00002989 case 1: /* DEC */
sewardjc2ac51e2004-07-12 01:03:26 +00002990 assign(t2, binop(Iop_Sub8, mkexpr(t1), mkU8(1)));
2991 putIReg(1, eregOfRM(modrm), mkexpr(t2));
2992 setFlags_INC_DEC( False, t2, ty );
2993 break;
2994 default:
sewardjd51dc812007-03-20 14:18:45 +00002995 *decode_OK = False;
2996 return delta;
sewardjc2ac51e2004-07-12 01:03:26 +00002997 }
2998 delta++;
2999 DIP("%sb %s\n", nameGrp4(gregOfRM(modrm)),
3000 nameIReg(1, eregOfRM(modrm)));
3001 } else {
sewardj7ed22952004-07-29 00:09:58 +00003002 IRTemp addr = disAMode ( &alen, sorb, delta, dis_buf );
3003 assign( t1, loadLE(ty, mkexpr(addr)) );
3004 switch (gregOfRM(modrm)) {
sewardj588ea762004-09-10 18:56:32 +00003005 case 0: /* INC */
3006 assign(t2, binop(Iop_Add8, mkexpr(t1), mkU8(1)));
sewardje9d8a262009-07-01 08:06:34 +00003007 if (locked) {
3008 casLE( mkexpr(addr), mkexpr(t1)/*expd*/, mkexpr(t2)/*new*/,
3009 guest_EIP_curr_instr );
3010 } else {
3011 storeLE( mkexpr(addr), mkexpr(t2) );
3012 }
sewardj588ea762004-09-10 18:56:32 +00003013 setFlags_INC_DEC( True, t2, ty );
3014 break;
sewardj7ed22952004-07-29 00:09:58 +00003015 case 1: /* DEC */
3016 assign(t2, binop(Iop_Sub8, mkexpr(t1), mkU8(1)));
sewardje9d8a262009-07-01 08:06:34 +00003017 if (locked) {
3018 casLE( mkexpr(addr), mkexpr(t1)/*expd*/, mkexpr(t2)/*new*/,
3019 guest_EIP_curr_instr );
3020 } else {
3021 storeLE( mkexpr(addr), mkexpr(t2) );
3022 }
sewardj7ed22952004-07-29 00:09:58 +00003023 setFlags_INC_DEC( False, t2, ty );
3024 break;
3025 default:
sewardjd51dc812007-03-20 14:18:45 +00003026 *decode_OK = False;
3027 return delta;
sewardj7ed22952004-07-29 00:09:58 +00003028 }
3029 delta += alen;
3030 DIP("%sb %s\n", nameGrp4(gregOfRM(modrm)), dis_buf);
sewardjc2ac51e2004-07-12 01:03:26 +00003031 }
3032 return delta;
3033}
sewardj0611d802004-07-11 02:37:54 +00003034
3035
3036/* Group 5 extended opcodes. */
3037static
sewardje9d8a262009-07-01 08:06:34 +00003038UInt dis_Grp5 ( UChar sorb, Bool locked, Int sz, Int delta,
sewardjc6f970f2012-04-02 21:54:49 +00003039 /*MOD*/DisResult* dres, /*OUT*/Bool* decode_OK )
sewardj0611d802004-07-11 02:37:54 +00003040{
3041 Int len;
3042 UChar modrm;
sewardjc9a43662004-11-30 18:51:59 +00003043 HChar dis_buf[50];
sewardj92d168d2004-11-15 14:22:12 +00003044 IRTemp addr = IRTemp_INVALID;
sewardj0611d802004-07-11 02:37:54 +00003045 IRType ty = szToITy(sz);
3046 IRTemp t1 = newTemp(ty);
sewardj92d168d2004-11-15 14:22:12 +00003047 IRTemp t2 = IRTemp_INVALID;
sewardj0611d802004-07-11 02:37:54 +00003048
sewardjd51dc812007-03-20 14:18:45 +00003049 *decode_OK = True;
3050
sewardj0611d802004-07-11 02:37:54 +00003051 modrm = getIByte(delta);
sewardje9d8a262009-07-01 08:06:34 +00003052
3053 if (locked && (gregOfRM(modrm) != 0 && gregOfRM(modrm) != 1)) {
3054 /* LOCK prefix only allowed with inc and dec subopcodes */
3055 *decode_OK = False;
3056 return delta;
3057 }
3058
sewardj0611d802004-07-11 02:37:54 +00003059 if (epartIsReg(modrm)) {
sewardj940e8c92004-07-11 16:53:24 +00003060 assign(t1, getIReg(sz,eregOfRM(modrm)));
sewardj0611d802004-07-11 02:37:54 +00003061 switch (gregOfRM(modrm)) {
sewardj59ff5d42005-10-05 10:39:58 +00003062 case 0: /* INC */
3063 vassert(sz == 2 || sz == 4);
3064 t2 = newTemp(ty);
3065 assign(t2, binop(mkSizedOp(ty,Iop_Add8),
3066 mkexpr(t1), mkU(ty,1)));
3067 setFlags_INC_DEC( True, t2, ty );
3068 putIReg(sz,eregOfRM(modrm),mkexpr(t2));
3069 break;
3070 case 1: /* DEC */
3071 vassert(sz == 2 || sz == 4);
3072 t2 = newTemp(ty);
3073 assign(t2, binop(mkSizedOp(ty,Iop_Sub8),
3074 mkexpr(t1), mkU(ty,1)));
3075 setFlags_INC_DEC( False, t2, ty );
3076 putIReg(sz,eregOfRM(modrm),mkexpr(t2));
3077 break;
sewardjc2ac51e2004-07-12 01:03:26 +00003078 case 2: /* call Ev */
3079 vassert(sz == 4);
3080 t2 = newTemp(Ity_I32);
3081 assign(t2, binop(Iop_Sub32, getIReg(4,R_ESP), mkU32(4)));
3082 putIReg(4, R_ESP, mkexpr(t2));
sewardj9e6491a2005-07-02 19:24:10 +00003083 storeLE( mkexpr(t2), mkU32(guest_EIP_bbstart+delta+1));
sewardjc6f970f2012-04-02 21:54:49 +00003084 jmp_treg(dres, Ijk_Call, t1);
3085 vassert(dres->whatNext == Dis_StopHere);
sewardjc2ac51e2004-07-12 01:03:26 +00003086 break;
sewardj0611d802004-07-11 02:37:54 +00003087 case 4: /* jmp Ev */
3088 vassert(sz == 4);
sewardjc6f970f2012-04-02 21:54:49 +00003089 jmp_treg(dres, Ijk_Boring, t1);
3090 vassert(dres->whatNext == Dis_StopHere);
sewardj0611d802004-07-11 02:37:54 +00003091 break;
sewardj28905822006-11-18 22:56:46 +00003092 case 6: /* PUSH Ev */
3093 vassert(sz == 4 || sz == 2);
3094 t2 = newTemp(Ity_I32);
3095 assign( t2, binop(Iop_Sub32,getIReg(4,R_ESP),mkU32(sz)) );
3096 putIReg(4, R_ESP, mkexpr(t2) );
3097 storeLE( mkexpr(t2), mkexpr(t1) );
3098 break;
sewardj0611d802004-07-11 02:37:54 +00003099 default:
sewardjd51dc812007-03-20 14:18:45 +00003100 *decode_OK = False;
3101 return delta;
sewardj0611d802004-07-11 02:37:54 +00003102 }
3103 delta++;
3104 DIP("%s%c %s\n", nameGrp5(gregOfRM(modrm)),
3105 nameISize(sz), nameIReg(sz, eregOfRM(modrm)));
3106 } else {
3107 addr = disAMode ( &len, sorb, delta, dis_buf );
sewardj940e8c92004-07-11 16:53:24 +00003108 assign(t1, loadLE(ty,mkexpr(addr)));
sewardj0611d802004-07-11 02:37:54 +00003109 switch (gregOfRM(modrm)) {
3110 case 0: /* INC */
3111 t2 = newTemp(ty);
3112 assign(t2, binop(mkSizedOp(ty,Iop_Add8),
3113 mkexpr(t1), mkU(ty,1)));
sewardje9d8a262009-07-01 08:06:34 +00003114 if (locked) {
3115 casLE( mkexpr(addr),
3116 mkexpr(t1), mkexpr(t2), guest_EIP_curr_instr );
3117 } else {
3118 storeLE(mkexpr(addr),mkexpr(t2));
3119 }
sewardj0611d802004-07-11 02:37:54 +00003120 setFlags_INC_DEC( True, t2, ty );
sewardj0611d802004-07-11 02:37:54 +00003121 break;
sewardjc2ac51e2004-07-12 01:03:26 +00003122 case 1: /* DEC */
3123 t2 = newTemp(ty);
3124 assign(t2, binop(mkSizedOp(ty,Iop_Sub8),
3125 mkexpr(t1), mkU(ty,1)));
sewardje9d8a262009-07-01 08:06:34 +00003126 if (locked) {
3127 casLE( mkexpr(addr),
3128 mkexpr(t1), mkexpr(t2), guest_EIP_curr_instr );
3129 } else {
3130 storeLE(mkexpr(addr),mkexpr(t2));
3131 }
sewardjc2ac51e2004-07-12 01:03:26 +00003132 setFlags_INC_DEC( False, t2, ty );
sewardjc2ac51e2004-07-12 01:03:26 +00003133 break;
sewardj77b86be2004-07-11 13:28:24 +00003134 case 2: /* call Ev */
3135 vassert(sz == 4);
3136 t2 = newTemp(Ity_I32);
3137 assign(t2, binop(Iop_Sub32, getIReg(4,R_ESP), mkU32(4)));
3138 putIReg(4, R_ESP, mkexpr(t2));
sewardj9e6491a2005-07-02 19:24:10 +00003139 storeLE( mkexpr(t2), mkU32(guest_EIP_bbstart+delta+len));
sewardjc6f970f2012-04-02 21:54:49 +00003140 jmp_treg(dres, Ijk_Call, t1);
3141 vassert(dres->whatNext == Dis_StopHere);
sewardj77b86be2004-07-11 13:28:24 +00003142 break;
3143 case 4: /* JMP Ev */
3144 vassert(sz == 4);
sewardjc6f970f2012-04-02 21:54:49 +00003145 jmp_treg(dres, Ijk_Boring, t1);
3146 vassert(dres->whatNext == Dis_StopHere);
sewardj77b86be2004-07-11 13:28:24 +00003147 break;
sewardj0c12ea82004-07-12 08:18:16 +00003148 case 6: /* PUSH Ev */
3149 vassert(sz == 4 || sz == 2);
3150 t2 = newTemp(Ity_I32);
3151 assign( t2, binop(Iop_Sub32,getIReg(4,R_ESP),mkU32(sz)) );
3152 putIReg(4, R_ESP, mkexpr(t2) );
sewardj5bd4d162004-11-10 13:02:48 +00003153 storeLE( mkexpr(t2), mkexpr(t1) );
sewardj0c12ea82004-07-12 08:18:16 +00003154 break;
sewardj0611d802004-07-11 02:37:54 +00003155 default:
sewardjd51dc812007-03-20 14:18:45 +00003156 *decode_OK = False;
3157 return delta;
sewardj0611d802004-07-11 02:37:54 +00003158 }
3159 delta += len;
3160 DIP("%s%c %s\n", nameGrp5(gregOfRM(modrm)),
3161 nameISize(sz), dis_buf);
3162 }
3163 return delta;
3164}
3165
sewardj464efa42004-11-19 22:17:29 +00003166
sewardj64e1d652004-07-12 14:00:46 +00003167/*------------------------------------------------------------*/
3168/*--- Disassembling string ops (including REP prefixes) ---*/
3169/*------------------------------------------------------------*/
3170
3171/* Code shared by all the string ops */
3172static
3173void dis_string_op_increment(Int sz, Int t_inc)
3174{
3175 if (sz == 4 || sz == 2) {
3176 assign( t_inc,
3177 binop(Iop_Shl32, IRExpr_Get( OFFB_DFLAG, Ity_I32 ),
sewardj6d2638e2004-07-15 09:38:27 +00003178 mkU8(sz/2) ) );
sewardj64e1d652004-07-12 14:00:46 +00003179 } else {
3180 assign( t_inc,
3181 IRExpr_Get( OFFB_DFLAG, Ity_I32 ) );
3182 }
3183}
3184
sewardj64e1d652004-07-12 14:00:46 +00003185static
3186void dis_string_op( void (*dis_OP)( Int, IRTemp ),
florian55085f82012-11-21 00:36:55 +00003187 Int sz, const HChar* name, UChar sorb )
sewardj64e1d652004-07-12 14:00:46 +00003188{
3189 IRTemp t_inc = newTemp(Ity_I32);
sewardj9c3b25a2007-04-05 15:06:56 +00003190 vassert(sorb == 0); /* hmm. so what was the point of passing it in? */
sewardj64e1d652004-07-12 14:00:46 +00003191 dis_string_op_increment(sz, t_inc);
3192 dis_OP( sz, t_inc );
3193 DIP("%s%c\n", name, nameISize(sz));
3194}
sewardj64e1d652004-07-12 14:00:46 +00003195
3196static
3197void dis_MOVS ( Int sz, IRTemp t_inc )
3198{
3199 IRType ty = szToITy(sz);
sewardj64e1d652004-07-12 14:00:46 +00003200 IRTemp td = newTemp(Ity_I32); /* EDI */
3201 IRTemp ts = newTemp(Ity_I32); /* ESI */
3202
sewardj64e1d652004-07-12 14:00:46 +00003203 assign( td, getIReg(4, R_EDI) );
3204 assign( ts, getIReg(4, R_ESI) );
3205
sewardj64e1d652004-07-12 14:00:46 +00003206 storeLE( mkexpr(td), loadLE(ty,mkexpr(ts)) );
3207
sewardj64e1d652004-07-12 14:00:46 +00003208 putIReg( 4, R_EDI, binop(Iop_Add32, mkexpr(td), mkexpr(t_inc)) );
3209 putIReg( 4, R_ESI, binop(Iop_Add32, mkexpr(ts), mkexpr(t_inc)) );
3210}
3211
sewardj10ca4eb2005-05-30 11:19:54 +00003212static
3213void dis_LODS ( Int sz, IRTemp t_inc )
3214{
3215 IRType ty = szToITy(sz);
3216 IRTemp ts = newTemp(Ity_I32); /* ESI */
3217
3218 assign( ts, getIReg(4, R_ESI) );
3219
3220 putIReg( sz, R_EAX, loadLE(ty, mkexpr(ts)) );
3221
3222 putIReg( 4, R_ESI, binop(Iop_Add32, mkexpr(ts), mkexpr(t_inc)) );
3223}
sewardj64e1d652004-07-12 14:00:46 +00003224
3225static
3226void dis_STOS ( Int sz, IRTemp t_inc )
3227{
3228 IRType ty = szToITy(sz);
3229 IRTemp ta = newTemp(ty); /* EAX */
3230 IRTemp td = newTemp(Ity_I32); /* EDI */
3231
sewardj64e1d652004-07-12 14:00:46 +00003232 assign( ta, getIReg(sz, R_EAX) );
sewardj64e1d652004-07-12 14:00:46 +00003233 assign( td, getIReg(4, R_EDI) );
3234
sewardj6d2638e2004-07-15 09:38:27 +00003235 storeLE( mkexpr(td), mkexpr(ta) );
sewardj64e1d652004-07-12 14:00:46 +00003236
sewardj64e1d652004-07-12 14:00:46 +00003237 putIReg( 4, R_EDI, binop(Iop_Add32, mkexpr(td), mkexpr(t_inc)) );
3238}
3239
3240static
3241void dis_CMPS ( Int sz, IRTemp t_inc )
3242{
3243 IRType ty = szToITy(sz);
sewardj6d2638e2004-07-15 09:38:27 +00003244 IRTemp tdv = newTemp(ty); /* (EDI) */
3245 IRTemp tsv = newTemp(ty); /* (ESI) */
sewardj64e1d652004-07-12 14:00:46 +00003246 IRTemp td = newTemp(Ity_I32); /* EDI */
3247 IRTemp ts = newTemp(Ity_I32); /* ESI */
3248
sewardj64e1d652004-07-12 14:00:46 +00003249 assign( td, getIReg(4, R_EDI) );
sewardj64e1d652004-07-12 14:00:46 +00003250 assign( ts, getIReg(4, R_ESI) );
3251
sewardj64e1d652004-07-12 14:00:46 +00003252 assign( tdv, loadLE(ty,mkexpr(td)) );
sewardjb9c5cf62004-08-24 15:10:38 +00003253 assign( tsv, loadLE(ty,mkexpr(ts)) );
sewardj64e1d652004-07-12 14:00:46 +00003254
sewardj2a2ba8b2004-11-08 13:14:06 +00003255 setFlags_DEP1_DEP2 ( Iop_Sub8, tsv, tdv, ty );
sewardj64e1d652004-07-12 14:00:46 +00003256
sewardj64e1d652004-07-12 14:00:46 +00003257 putIReg(4, R_EDI, binop(Iop_Add32, mkexpr(td), mkexpr(t_inc)) );
sewardj64e1d652004-07-12 14:00:46 +00003258 putIReg(4, R_ESI, binop(Iop_Add32, mkexpr(ts), mkexpr(t_inc)) );
3259}
3260
sewardj64e1d652004-07-12 14:00:46 +00003261static
3262void dis_SCAS ( Int sz, IRTemp t_inc )
3263{
3264 IRType ty = szToITy(sz);
sewardj82292882004-07-27 00:15:59 +00003265 IRTemp ta = newTemp(ty); /* EAX */
sewardj64e1d652004-07-12 14:00:46 +00003266 IRTemp td = newTemp(Ity_I32); /* EDI */
3267 IRTemp tdv = newTemp(ty); /* (EDI) */
3268
sewardjb9c5cf62004-08-24 15:10:38 +00003269 assign( ta, getIReg(sz, R_EAX) );
sewardj64e1d652004-07-12 14:00:46 +00003270 assign( td, getIReg(4, R_EDI) );
3271
sewardj64e1d652004-07-12 14:00:46 +00003272 assign( tdv, loadLE(ty,mkexpr(td)) );
sewardj2a2ba8b2004-11-08 13:14:06 +00003273 setFlags_DEP1_DEP2 ( Iop_Sub8, ta, tdv, ty );
sewardj64e1d652004-07-12 14:00:46 +00003274
sewardj64e1d652004-07-12 14:00:46 +00003275 putIReg(4, R_EDI, binop(Iop_Add32, mkexpr(td), mkexpr(t_inc)) );
3276}
sewardj82292882004-07-27 00:15:59 +00003277
sewardj64e1d652004-07-12 14:00:46 +00003278
3279/* Wrap the appropriate string op inside a REP/REPE/REPNE.
3280 We assume the insn is the last one in the basic block, and so emit a jump
3281 to the next insn, rather than just falling through. */
3282static
sewardjc6f970f2012-04-02 21:54:49 +00003283void dis_REP_op ( /*MOD*/DisResult* dres,
3284 X86Condcode cond,
sewardj64e1d652004-07-12 14:00:46 +00003285 void (*dis_OP)(Int, IRTemp),
florian55085f82012-11-21 00:36:55 +00003286 Int sz, Addr32 eip, Addr32 eip_next, const HChar* name )
sewardj64e1d652004-07-12 14:00:46 +00003287{
3288 IRTemp t_inc = newTemp(Ity_I32);
3289 IRTemp tc = newTemp(Ity_I32); /* ECX */
3290
sewardj64e1d652004-07-12 14:00:46 +00003291 assign( tc, getIReg(4,R_ECX) );
3292
sewardj64e1d652004-07-12 14:00:46 +00003293 stmt( IRStmt_Exit( binop(Iop_CmpEQ32,mkexpr(tc),mkU32(0)),
sewardj893aada2004-11-29 19:57:54 +00003294 Ijk_Boring,
sewardjc6f970f2012-04-02 21:54:49 +00003295 IRConst_U32(eip_next), OFFB_EIP ) );
sewardj64e1d652004-07-12 14:00:46 +00003296
sewardj64e1d652004-07-12 14:00:46 +00003297 putIReg(4, R_ECX, binop(Iop_Sub32, mkexpr(tc), mkU32(1)) );
3298
3299 dis_string_op_increment(sz, t_inc);
3300 dis_OP (sz, t_inc);
3301
sewardj2a9ad022004-11-25 02:46:58 +00003302 if (cond == X86CondAlways) {
sewardjc6f970f2012-04-02 21:54:49 +00003303 jmp_lit(dres, Ijk_Boring, eip);
3304 vassert(dres->whatNext == Dis_StopHere);
sewardj64e1d652004-07-12 14:00:46 +00003305 } else {
sewardj2a9ad022004-11-25 02:46:58 +00003306 stmt( IRStmt_Exit( mk_x86g_calculate_condition(cond),
sewardj893aada2004-11-29 19:57:54 +00003307 Ijk_Boring,
sewardjc6f970f2012-04-02 21:54:49 +00003308 IRConst_U32(eip), OFFB_EIP ) );
3309 jmp_lit(dres, Ijk_Boring, eip_next);
3310 vassert(dres->whatNext == Dis_StopHere);
sewardj64e1d652004-07-12 14:00:46 +00003311 }
3312 DIP("%s%c\n", name, nameISize(sz));
3313}
3314
sewardj464efa42004-11-19 22:17:29 +00003315
sewardj64e1d652004-07-12 14:00:46 +00003316/*------------------------------------------------------------*/
3317/*--- Arithmetic, etc. ---*/
3318/*------------------------------------------------------------*/
3319
sewardj2a2ba8b2004-11-08 13:14:06 +00003320/* IMUL E, G. Supplied eip points to the modR/M byte. */
sewardjcf780b42004-07-13 18:42:17 +00003321static
3322UInt dis_mul_E_G ( UChar sorb,
3323 Int size,
sewardj52d04912005-07-03 00:52:48 +00003324 Int delta0 )
sewardjcf780b42004-07-13 18:42:17 +00003325{
sewardj71a65362004-07-28 01:48:34 +00003326 Int alen;
sewardjc9a43662004-11-30 18:51:59 +00003327 HChar dis_buf[50];
sewardjcf780b42004-07-13 18:42:17 +00003328 UChar rm = getIByte(delta0);
3329 IRType ty = szToITy(size);
sewardj6d2638e2004-07-15 09:38:27 +00003330 IRTemp te = newTemp(ty);
3331 IRTemp tg = newTemp(ty);
sewardj948d48b2004-11-05 19:49:09 +00003332 IRTemp resLo = newTemp(ty);
sewardj71a65362004-07-28 01:48:34 +00003333
sewardj948d48b2004-11-05 19:49:09 +00003334 assign( tg, getIReg(size, gregOfRM(rm)) );
sewardjcf780b42004-07-13 18:42:17 +00003335 if (epartIsReg(rm)) {
sewardjcf780b42004-07-13 18:42:17 +00003336 assign( te, getIReg(size, eregOfRM(rm)) );
sewardj948d48b2004-11-05 19:49:09 +00003337 } else {
3338 IRTemp addr = disAMode( &alen, sorb, delta0, dis_buf );
3339 assign( te, loadLE(ty,mkexpr(addr)) );
3340 }
sewardjcf780b42004-07-13 18:42:17 +00003341
sewardj2a9ad022004-11-25 02:46:58 +00003342 setFlags_MUL ( ty, te, tg, X86G_CC_OP_SMULB );
sewardj948d48b2004-11-05 19:49:09 +00003343
sewardj2a2ba8b2004-11-08 13:14:06 +00003344 assign( resLo, binop( mkSizedOp(ty, Iop_Mul8), mkexpr(te), mkexpr(tg) ) );
sewardj948d48b2004-11-05 19:49:09 +00003345
3346 putIReg(size, gregOfRM(rm), mkexpr(resLo) );
3347
3348 if (epartIsReg(rm)) {
sewardj2a2ba8b2004-11-08 13:14:06 +00003349 DIP("imul%c %s, %s\n", nameISize(size),
3350 nameIReg(size,eregOfRM(rm)),
3351 nameIReg(size,gregOfRM(rm)));
sewardjcf780b42004-07-13 18:42:17 +00003352 return 1+delta0;
3353 } else {
sewardj2a2ba8b2004-11-08 13:14:06 +00003354 DIP("imul%c %s, %s\n", nameISize(size),
3355 dis_buf, nameIReg(size,gregOfRM(rm)));
sewardj71a65362004-07-28 01:48:34 +00003356 return alen+delta0;
sewardjcf780b42004-07-13 18:42:17 +00003357 }
3358}
3359
3360
sewardj1813dbe2004-07-28 17:09:04 +00003361/* IMUL I * E -> G. Supplied eip points to the modR/M byte. */
3362static
3363UInt dis_imul_I_E_G ( UChar sorb,
3364 Int size,
sewardj52d04912005-07-03 00:52:48 +00003365 Int delta,
sewardj1813dbe2004-07-28 17:09:04 +00003366 Int litsize )
3367{
sewardj883b00b2004-09-11 09:30:24 +00003368 Int d32, alen;
sewardjc9a43662004-11-30 18:51:59 +00003369 HChar dis_buf[50];
sewardjb81f8b32004-07-30 10:17:50 +00003370 UChar rm = getIByte(delta);
sewardj1813dbe2004-07-28 17:09:04 +00003371 IRType ty = szToITy(size);
3372 IRTemp te = newTemp(ty);
3373 IRTemp tl = newTemp(ty);
sewardj948d48b2004-11-05 19:49:09 +00003374 IRTemp resLo = newTemp(ty);
sewardj1813dbe2004-07-28 17:09:04 +00003375
sewardjb81f8b32004-07-30 10:17:50 +00003376 vassert(size == 1 || size == 2 || size == 4);
3377
sewardj1813dbe2004-07-28 17:09:04 +00003378 if (epartIsReg(rm)) {
3379 assign(te, getIReg(size, eregOfRM(rm)));
3380 delta++;
3381 } else {
sewardj883b00b2004-09-11 09:30:24 +00003382 IRTemp addr = disAMode( &alen, sorb, delta, dis_buf );
3383 assign(te, loadLE(ty, mkexpr(addr)));
3384 delta += alen;
sewardj1813dbe2004-07-28 17:09:04 +00003385 }
3386 d32 = getSDisp(litsize,delta);
3387 delta += litsize;
3388
sewardjb81f8b32004-07-30 10:17:50 +00003389 if (size == 1) d32 &= 0xFF;
3390 if (size == 2) d32 &= 0xFFFF;
3391
sewardj1813dbe2004-07-28 17:09:04 +00003392 assign(tl, mkU(ty,d32));
sewardj948d48b2004-11-05 19:49:09 +00003393
sewardj2a2ba8b2004-11-08 13:14:06 +00003394 assign( resLo, binop( mkSizedOp(ty, Iop_Mul8), mkexpr(te), mkexpr(tl) ));
sewardj948d48b2004-11-05 19:49:09 +00003395
sewardj2a9ad022004-11-25 02:46:58 +00003396 setFlags_MUL ( ty, te, tl, X86G_CC_OP_SMULB );
sewardj948d48b2004-11-05 19:49:09 +00003397
3398 putIReg(size, gregOfRM(rm), mkexpr(resLo));
sewardj1813dbe2004-07-28 17:09:04 +00003399
3400 DIP("imul %d, %s, %s\n", d32,
3401 ( epartIsReg(rm) ? nameIReg(size,eregOfRM(rm)) : dis_buf ),
3402 nameIReg(size,gregOfRM(rm)) );
3403 return delta;
sewardj948d48b2004-11-05 19:49:09 +00003404}
sewardj1813dbe2004-07-28 17:09:04 +00003405
3406
sewardj9a660ea2010-07-29 11:34:38 +00003407/* Generate an IR sequence to do a count-leading-zeroes operation on
3408 the supplied IRTemp, and return a new IRTemp holding the result.
3409 'ty' may be Ity_I16 or Ity_I32 only. In the case where the
3410 argument is zero, return the number of bits in the word (the
3411 natural semantics). */
3412static IRTemp gen_LZCNT ( IRType ty, IRTemp src )
3413{
3414 vassert(ty == Ity_I32 || ty == Ity_I16);
3415
3416 IRTemp src32 = newTemp(Ity_I32);
3417 assign(src32, widenUto32( mkexpr(src) ));
3418
3419 IRTemp src32x = newTemp(Ity_I32);
3420 assign(src32x,
3421 binop(Iop_Shl32, mkexpr(src32),
3422 mkU8(32 - 8 * sizeofIRType(ty))));
3423
3424 // Clz32 has undefined semantics when its input is zero, so
3425 // special-case around that.
3426 IRTemp res32 = newTemp(Ity_I32);
3427 assign(res32,
florian99dd03e2013-01-29 03:56:06 +00003428 IRExpr_ITE(
sewardj009230b2013-01-26 11:47:55 +00003429 binop(Iop_CmpEQ32, mkexpr(src32x), mkU32(0)),
florian99dd03e2013-01-29 03:56:06 +00003430 mkU32(8 * sizeofIRType(ty)),
3431 unop(Iop_Clz32, mkexpr(src32x))
sewardj9a660ea2010-07-29 11:34:38 +00003432 ));
3433
3434 IRTemp res = newTemp(ty);
3435 assign(res, narrowTo(ty, mkexpr(res32)));
3436 return res;
3437}
3438
3439
sewardjd1725d12004-08-12 20:46:53 +00003440/*------------------------------------------------------------*/
sewardj464efa42004-11-19 22:17:29 +00003441/*--- ---*/
3442/*--- x87 FLOATING POINT INSTRUCTIONS ---*/
3443/*--- ---*/
sewardjd1725d12004-08-12 20:46:53 +00003444/*------------------------------------------------------------*/
3445
sewardj207557a2004-08-27 12:00:18 +00003446/* --- Helper functions for dealing with the register stack. --- */
3447
sewardj893aada2004-11-29 19:57:54 +00003448/* --- Set the emulation-warning pseudo-register. --- */
3449
3450static void put_emwarn ( IRExpr* e /* :: Ity_I32 */ )
3451{
sewardjdd40fdf2006-12-24 02:20:24 +00003452 vassert(typeOfIRExpr(irsb->tyenv, e) == Ity_I32);
florian6ef84be2012-08-26 03:20:07 +00003453 stmt( IRStmt_Put( OFFB_EMNOTE, e ) );
sewardj893aada2004-11-29 19:57:54 +00003454}
3455
sewardj17442fe2004-09-20 14:54:28 +00003456/* --- Produce an IRExpr* denoting a 64-bit QNaN. --- */
sewardj207557a2004-08-27 12:00:18 +00003457
sewardj17442fe2004-09-20 14:54:28 +00003458static IRExpr* mkQNaN64 ( void )
sewardj207557a2004-08-27 12:00:18 +00003459{
sewardj17442fe2004-09-20 14:54:28 +00003460 /* QNaN is 0 2047 1 0(51times)
3461 == 0b 11111111111b 1 0(51times)
3462 == 0x7FF8 0000 0000 0000
3463 */
3464 return IRExpr_Const(IRConst_F64i(0x7FF8000000000000ULL));
sewardj207557a2004-08-27 12:00:18 +00003465}
3466
sewardj893aada2004-11-29 19:57:54 +00003467/* --------- Get/put the top-of-stack pointer. --------- */
sewardjd1725d12004-08-12 20:46:53 +00003468
3469static IRExpr* get_ftop ( void )
3470{
3471 return IRExpr_Get( OFFB_FTOP, Ity_I32 );
3472}
3473
sewardj207557a2004-08-27 12:00:18 +00003474static void put_ftop ( IRExpr* e )
sewardjd1725d12004-08-12 20:46:53 +00003475{
sewardjdd40fdf2006-12-24 02:20:24 +00003476 vassert(typeOfIRExpr(irsb->tyenv, e) == Ity_I32);
sewardj207557a2004-08-27 12:00:18 +00003477 stmt( IRStmt_Put( OFFB_FTOP, e ) );
sewardjd1725d12004-08-12 20:46:53 +00003478}
3479
sewardj893aada2004-11-29 19:57:54 +00003480/* --------- Get/put the C3210 bits. --------- */
sewardjbdc7d212004-09-09 02:46:40 +00003481
sewardjc4be80c2004-09-10 16:17:45 +00003482static IRExpr* get_C3210 ( void )
sewardjbdc7d212004-09-09 02:46:40 +00003483{
sewardjc4be80c2004-09-10 16:17:45 +00003484 return IRExpr_Get( OFFB_FC3210, Ity_I32 );
sewardjbdc7d212004-09-09 02:46:40 +00003485}
3486
sewardjc4be80c2004-09-10 16:17:45 +00003487static void put_C3210 ( IRExpr* e )
sewardjbdc7d212004-09-09 02:46:40 +00003488{
sewardjc4be80c2004-09-10 16:17:45 +00003489 stmt( IRStmt_Put( OFFB_FC3210, e ) );
sewardjbdc7d212004-09-09 02:46:40 +00003490}
sewardjd1725d12004-08-12 20:46:53 +00003491
sewardj893aada2004-11-29 19:57:54 +00003492/* --------- Get/put the FPU rounding mode. --------- */
sewardjd01a9632004-11-30 13:18:37 +00003493static IRExpr* /* :: Ity_I32 */ get_fpround ( void )
sewardj8f3debf2004-09-08 23:42:23 +00003494{
sewardjd01a9632004-11-30 13:18:37 +00003495 return IRExpr_Get( OFFB_FPROUND, Ity_I32 );
sewardj8f3debf2004-09-08 23:42:23 +00003496}
3497
sewardjd01a9632004-11-30 13:18:37 +00003498static void put_fpround ( IRExpr* /* :: Ity_I32 */ e )
sewardj8f3debf2004-09-08 23:42:23 +00003499{
sewardjd01a9632004-11-30 13:18:37 +00003500 stmt( IRStmt_Put( OFFB_FPROUND, e ) );
sewardj8f3debf2004-09-08 23:42:23 +00003501}
3502
3503
sewardj893aada2004-11-29 19:57:54 +00003504/* --------- Synthesise a 2-bit FPU rounding mode. --------- */
sewardj8f3debf2004-09-08 23:42:23 +00003505/* Produces a value in 0 .. 3, which is encoded as per the type
sewardjd01a9632004-11-30 13:18:37 +00003506 IRRoundingMode. Since the guest_FPROUND value is also encoded as
3507 per IRRoundingMode, we merely need to get it and mask it for
3508 safety.
sewardj8f3debf2004-09-08 23:42:23 +00003509*/
3510static IRExpr* /* :: Ity_I32 */ get_roundingmode ( void )
3511{
sewardjd01a9632004-11-30 13:18:37 +00003512 return binop( Iop_And32, get_fpround(), mkU32(3) );
sewardj8f3debf2004-09-08 23:42:23 +00003513}
3514
sewardjf1b5b1a2006-02-03 22:54:17 +00003515static IRExpr* /* :: Ity_I32 */ get_FAKE_roundingmode ( void )
3516{
3517 return mkU32(Irrm_NEAREST);
3518}
3519
sewardj8f3debf2004-09-08 23:42:23 +00003520
sewardj207557a2004-08-27 12:00:18 +00003521/* --------- Get/set FP register tag bytes. --------- */
3522
sewardj207557a2004-08-27 12:00:18 +00003523/* Given i, and some expression e, generate 'ST_TAG(i) = e'. */
3524
3525static void put_ST_TAG ( Int i, IRExpr* value )
3526{
sewardjdd40fdf2006-12-24 02:20:24 +00003527 IRRegArray* descr;
3528 vassert(typeOfIRExpr(irsb->tyenv, value) == Ity_I8);
3529 descr = mkIRRegArray( OFFB_FPTAGS, Ity_I8, 8 );
floriand6f38b32012-05-31 15:46:18 +00003530 stmt( IRStmt_PutI( mkIRPutI(descr, get_ftop(), i, value) ) );
sewardj207557a2004-08-27 12:00:18 +00003531}
3532
3533/* Given i, generate an expression yielding 'ST_TAG(i)'. This will be
sewardjdb199622004-09-06 23:19:03 +00003534 zero to indicate "Empty" and nonzero to indicate "NonEmpty". */
sewardj207557a2004-08-27 12:00:18 +00003535
3536static IRExpr* get_ST_TAG ( Int i )
3537{
sewardjdd40fdf2006-12-24 02:20:24 +00003538 IRRegArray* descr = mkIRRegArray( OFFB_FPTAGS, Ity_I8, 8 );
sewardj2d3f77c2004-09-22 23:49:09 +00003539 return IRExpr_GetI( descr, get_ftop(), i );
sewardj207557a2004-08-27 12:00:18 +00003540}
3541
3542
3543/* --------- Get/set FP registers. --------- */
3544
sewardj2d3f77c2004-09-22 23:49:09 +00003545/* Given i, and some expression e, emit 'ST(i) = e' and set the
3546 register's tag to indicate the register is full. The previous
3547 state of the register is not checked. */
sewardj207557a2004-08-27 12:00:18 +00003548
3549static void put_ST_UNCHECKED ( Int i, IRExpr* value )
sewardjd1725d12004-08-12 20:46:53 +00003550{
sewardjdd40fdf2006-12-24 02:20:24 +00003551 IRRegArray* descr;
3552 vassert(typeOfIRExpr(irsb->tyenv, value) == Ity_F64);
3553 descr = mkIRRegArray( OFFB_FPREGS, Ity_F64, 8 );
floriand6f38b32012-05-31 15:46:18 +00003554 stmt( IRStmt_PutI( mkIRPutI(descr, get_ftop(), i, value) ) );
sewardj207557a2004-08-27 12:00:18 +00003555 /* Mark the register as in-use. */
3556 put_ST_TAG(i, mkU8(1));
sewardjd1725d12004-08-12 20:46:53 +00003557}
3558
sewardj207557a2004-08-27 12:00:18 +00003559/* Given i, and some expression e, emit
3560 ST(i) = is_full(i) ? NaN : e
3561 and set the tag accordingly.
3562*/
3563
3564static void put_ST ( Int i, IRExpr* value )
3565{
sewardj009230b2013-01-26 11:47:55 +00003566 put_ST_UNCHECKED(
3567 i,
florian99dd03e2013-01-29 03:56:06 +00003568 IRExpr_ITE( binop(Iop_CmpNE8, get_ST_TAG(i), mkU8(0)),
3569 /* non-0 means full */
3570 mkQNaN64(),
3571 /* 0 means empty */
3572 value
sewardj009230b2013-01-26 11:47:55 +00003573 )
sewardj207557a2004-08-27 12:00:18 +00003574 );
3575}
3576
3577
sewardjd1725d12004-08-12 20:46:53 +00003578/* Given i, generate an expression yielding 'ST(i)'. */
3579
sewardj207557a2004-08-27 12:00:18 +00003580static IRExpr* get_ST_UNCHECKED ( Int i )
sewardjd1725d12004-08-12 20:46:53 +00003581{
sewardjdd40fdf2006-12-24 02:20:24 +00003582 IRRegArray* descr = mkIRRegArray( OFFB_FPREGS, Ity_F64, 8 );
sewardj2d3f77c2004-09-22 23:49:09 +00003583 return IRExpr_GetI( descr, get_ftop(), i );
sewardjd1725d12004-08-12 20:46:53 +00003584}
3585
sewardjc4be80c2004-09-10 16:17:45 +00003586
sewardj207557a2004-08-27 12:00:18 +00003587/* Given i, generate an expression yielding
3588 is_full(i) ? ST(i) : NaN
3589*/
3590
3591static IRExpr* get_ST ( Int i )
3592{
3593 return
florian99dd03e2013-01-29 03:56:06 +00003594 IRExpr_ITE( binop(Iop_CmpNE8, get_ST_TAG(i), mkU8(0)),
3595 /* non-0 means full */
3596 get_ST_UNCHECKED(i),
3597 /* 0 means empty */
3598 mkQNaN64());
sewardj207557a2004-08-27 12:00:18 +00003599}
3600
3601
sewardje9c51c92014-04-30 22:50:34 +00003602/* Given i, and some expression e, and a condition cond, generate IR
3603 which has the same effect as put_ST(i,e) when cond is true and has
3604 no effect when cond is false. Given the lack of proper
3605 if-then-else in the IR, this is pretty tricky.
3606*/
3607
3608static void maybe_put_ST ( IRTemp cond, Int i, IRExpr* value )
3609{
3610 // new_tag = if cond then FULL else old_tag
3611 // new_val = if cond then (if old_tag==FULL then NaN else val)
3612 // else old_val
3613
3614 IRTemp old_tag = newTemp(Ity_I8);
3615 assign(old_tag, get_ST_TAG(i));
3616 IRTemp new_tag = newTemp(Ity_I8);
3617 assign(new_tag,
3618 IRExpr_ITE(mkexpr(cond), mkU8(1)/*FULL*/, mkexpr(old_tag)));
3619
3620 IRTemp old_val = newTemp(Ity_F64);
3621 assign(old_val, get_ST_UNCHECKED(i));
3622 IRTemp new_val = newTemp(Ity_F64);
3623 assign(new_val,
3624 IRExpr_ITE(mkexpr(cond),
3625 IRExpr_ITE(binop(Iop_CmpNE8, mkexpr(old_tag), mkU8(0)),
3626 /* non-0 means full */
3627 mkQNaN64(),
3628 /* 0 means empty */
3629 value),
3630 mkexpr(old_val)));
3631
3632 put_ST_UNCHECKED(i, mkexpr(new_val));
3633 // put_ST_UNCHECKED incorrectly sets tag(i) to always be FULL. So
3634 // now set it to new_tag instead.
3635 put_ST_TAG(i, mkexpr(new_tag));
3636}
3637
sewardjd1725d12004-08-12 20:46:53 +00003638/* Adjust FTOP downwards by one register. */
3639
sewardj207557a2004-08-27 12:00:18 +00003640static void fp_push ( void )
sewardjd1725d12004-08-12 20:46:53 +00003641{
sewardj2d3f77c2004-09-22 23:49:09 +00003642 put_ftop( binop(Iop_Sub32, get_ftop(), mkU32(1)) );
sewardjd1725d12004-08-12 20:46:53 +00003643}
3644
sewardje9c51c92014-04-30 22:50:34 +00003645/* Adjust FTOP downwards by one register when COND is 1:I1. Else
3646 don't change it. */
3647
3648static void maybe_fp_push ( IRTemp cond )
3649{
3650 put_ftop( binop(Iop_Sub32, get_ftop(), unop(Iop_1Uto32,mkexpr(cond))) );
3651}
3652
sewardj207557a2004-08-27 12:00:18 +00003653/* Adjust FTOP upwards by one register, and mark the vacated register
3654 as empty. */
sewardja58ea662004-08-15 03:12:41 +00003655
sewardj207557a2004-08-27 12:00:18 +00003656static void fp_pop ( void )
sewardja58ea662004-08-15 03:12:41 +00003657{
sewardjdb199622004-09-06 23:19:03 +00003658 put_ST_TAG(0, mkU8(0));
sewardj2d3f77c2004-09-22 23:49:09 +00003659 put_ftop( binop(Iop_Add32, get_ftop(), mkU32(1)) );
sewardja58ea662004-08-15 03:12:41 +00003660}
3661
sewardje9c51c92014-04-30 22:50:34 +00003662/* Set the C2 bit of the FPU status register to e[0]. Assumes that
3663 e[31:1] == 0.
3664*/
3665static void set_C2 ( IRExpr* e )
sewardj3f61ddb2004-10-16 20:51:05 +00003666{
sewardje9c51c92014-04-30 22:50:34 +00003667 IRExpr* cleared = binop(Iop_And32, get_C3210(), mkU32(~X86G_FC_MASK_C2));
3668 put_C3210( binop(Iop_Or32,
3669 cleared,
3670 binop(Iop_Shl32, e, mkU8(X86G_FC_SHIFT_C2))) );
3671}
3672
3673/* Generate code to check that abs(d64) < 2^63 and is finite. This is
3674 used to do the range checks for FSIN, FCOS, FSINCOS and FPTAN. The
3675 test is simple, but the derivation of it is not so simple.
3676
3677 The exponent field for an IEEE754 double is 11 bits. That means it
3678 can take values 0 through 0x7FF. If the exponent has value 0x7FF,
3679 the number is either a NaN or an Infinity and so is not finite.
3680 Furthermore, a finite value of exactly 2^63 is the smallest value
3681 that has exponent value 0x43E. Hence, what we need to do is
3682 extract the exponent, ignoring the sign bit and mantissa, and check
3683 it is < 0x43E, or <= 0x43D.
3684
3685 To make this easily applicable to 32- and 64-bit targets, a
3686 roundabout approach is used. First the number is converted to I64,
3687 then the top 32 bits are taken. Shifting them right by 20 bits
3688 places the sign bit and exponent in the bottom 12 bits. Anding
3689 with 0x7FF gets rid of the sign bit, leaving just the exponent
3690 available for comparison.
3691*/
3692static IRTemp math_IS_TRIG_ARG_FINITE_AND_IN_RANGE ( IRTemp d64 )
3693{
3694 IRTemp i64 = newTemp(Ity_I64);
3695 assign(i64, unop(Iop_ReinterpF64asI64, mkexpr(d64)) );
3696 IRTemp exponent = newTemp(Ity_I32);
3697 assign(exponent,
3698 binop(Iop_And32,
3699 binop(Iop_Shr32, unop(Iop_64HIto32, mkexpr(i64)), mkU8(20)),
3700 mkU32(0x7FF)));
3701 IRTemp in_range_and_finite = newTemp(Ity_I1);
3702 assign(in_range_and_finite,
3703 binop(Iop_CmpLE32U, mkexpr(exponent), mkU32(0x43D)));
3704 return in_range_and_finite;
sewardj3f61ddb2004-10-16 20:51:05 +00003705}
3706
sewardjd24931d2005-03-20 12:51:39 +00003707/* Invent a plausible-looking FPU status word value:
3708 ((ftop & 7) << 11) | (c3210 & 0x4700)
3709 */
3710static IRExpr* get_FPU_sw ( void )
3711{
3712 return
3713 unop(Iop_32to16,
3714 binop(Iop_Or32,
3715 binop(Iop_Shl32,
3716 binop(Iop_And32, get_ftop(), mkU32(7)),
3717 mkU8(11)),
3718 binop(Iop_And32, get_C3210(), mkU32(0x4700))
3719 ));
3720}
3721
sewardj3f61ddb2004-10-16 20:51:05 +00003722
sewardj207557a2004-08-27 12:00:18 +00003723/* ------------------------------------------------------- */
3724/* Given all that stack-mangling junk, we can now go ahead
3725 and describe FP instructions.
3726*/
3727
sewardj3fd5e572004-09-09 22:43:51 +00003728/* ST(0) = ST(0) `op` mem64/32(addr)
sewardj207557a2004-08-27 12:00:18 +00003729 Need to check ST(0)'s tag on read, but not on write.
3730*/
sewardja58ea662004-08-15 03:12:41 +00003731static
florian55085f82012-11-21 00:36:55 +00003732void fp_do_op_mem_ST_0 ( IRTemp addr, const HChar* op_txt, HChar* dis_buf,
sewardja58ea662004-08-15 03:12:41 +00003733 IROp op, Bool dbl )
3734{
sewardj33dd31b2005-01-08 18:17:32 +00003735 DIP("f%s%c %s\n", op_txt, dbl?'l':'s', dis_buf);
sewardja58ea662004-08-15 03:12:41 +00003736 if (dbl) {
sewardj3fd5e572004-09-09 22:43:51 +00003737 put_ST_UNCHECKED(0,
sewardjf1b5b1a2006-02-03 22:54:17 +00003738 triop( op,
3739 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
sewardj3fd5e572004-09-09 22:43:51 +00003740 get_ST(0),
3741 loadLE(Ity_F64,mkexpr(addr))
3742 ));
sewardja58ea662004-08-15 03:12:41 +00003743 } else {
sewardj3fd5e572004-09-09 22:43:51 +00003744 put_ST_UNCHECKED(0,
sewardjf1b5b1a2006-02-03 22:54:17 +00003745 triop( op,
3746 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
sewardj3fd5e572004-09-09 22:43:51 +00003747 get_ST(0),
3748 unop(Iop_F32toF64, loadLE(Ity_F32,mkexpr(addr)))
3749 ));
3750 }
3751}
3752
3753
3754/* ST(0) = mem64/32(addr) `op` ST(0)
3755 Need to check ST(0)'s tag on read, but not on write.
3756*/
3757static
florian55085f82012-11-21 00:36:55 +00003758void fp_do_oprev_mem_ST_0 ( IRTemp addr, const HChar* op_txt, HChar* dis_buf,
sewardj883b00b2004-09-11 09:30:24 +00003759 IROp op, Bool dbl )
sewardj3fd5e572004-09-09 22:43:51 +00003760{
sewardj33dd31b2005-01-08 18:17:32 +00003761 DIP("f%s%c %s\n", op_txt, dbl?'l':'s', dis_buf);
sewardj3fd5e572004-09-09 22:43:51 +00003762 if (dbl) {
3763 put_ST_UNCHECKED(0,
sewardjf1b5b1a2006-02-03 22:54:17 +00003764 triop( op,
3765 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
sewardj3fd5e572004-09-09 22:43:51 +00003766 loadLE(Ity_F64,mkexpr(addr)),
3767 get_ST(0)
3768 ));
3769 } else {
3770 put_ST_UNCHECKED(0,
sewardjf1b5b1a2006-02-03 22:54:17 +00003771 triop( op,
3772 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
sewardj3fd5e572004-09-09 22:43:51 +00003773 unop(Iop_F32toF64, loadLE(Ity_F32,mkexpr(addr))),
3774 get_ST(0)
3775 ));
sewardja58ea662004-08-15 03:12:41 +00003776 }
3777}
3778
sewardjd1725d12004-08-12 20:46:53 +00003779
sewardjdb199622004-09-06 23:19:03 +00003780/* ST(dst) = ST(dst) `op` ST(src).
3781 Check dst and src tags when reading but not on write.
3782*/
3783static
florian55085f82012-11-21 00:36:55 +00003784void fp_do_op_ST_ST ( const HChar* op_txt, IROp op, UInt st_src, UInt st_dst,
sewardjbdc7d212004-09-09 02:46:40 +00003785 Bool pop_after )
sewardjdb199622004-09-06 23:19:03 +00003786{
florianb1737742015-08-03 16:03:13 +00003787 DIP("f%s%s st(%u), st(%u)\n", op_txt, pop_after?"p":"",
3788 st_src, st_dst);
sewardjdb199622004-09-06 23:19:03 +00003789 put_ST_UNCHECKED(
3790 st_dst,
sewardjf1b5b1a2006-02-03 22:54:17 +00003791 triop( op,
3792 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
3793 get_ST(st_dst),
3794 get_ST(st_src) )
sewardjdb199622004-09-06 23:19:03 +00003795 );
sewardjbdc7d212004-09-09 02:46:40 +00003796 if (pop_after)
3797 fp_pop();
3798}
3799
3800/* ST(dst) = ST(src) `op` ST(dst).
3801 Check dst and src tags when reading but not on write.
3802*/
3803static
florian55085f82012-11-21 00:36:55 +00003804void fp_do_oprev_ST_ST ( const HChar* op_txt, IROp op, UInt st_src,
3805 UInt st_dst, Bool pop_after )
sewardjbdc7d212004-09-09 02:46:40 +00003806{
florianb1737742015-08-03 16:03:13 +00003807 DIP("f%s%s st(%u), st(%u)\n", op_txt, pop_after?"p":"",
3808 st_src, st_dst);
sewardjbdc7d212004-09-09 02:46:40 +00003809 put_ST_UNCHECKED(
3810 st_dst,
sewardjf1b5b1a2006-02-03 22:54:17 +00003811 triop( op,
3812 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
3813 get_ST(st_src),
3814 get_ST(st_dst) )
sewardjbdc7d212004-09-09 02:46:40 +00003815 );
3816 if (pop_after)
3817 fp_pop();
sewardjdb199622004-09-06 23:19:03 +00003818}
3819
sewardj8308aad2004-09-12 11:09:54 +00003820/* %eflags(Z,P,C) = UCOMI( st(0), st(i) ) */
3821static void fp_do_ucomi_ST0_STi ( UInt i, Bool pop_after )
3822{
florianb1737742015-08-03 16:03:13 +00003823 DIP("fucomi%s %%st(0),%%st(%u)\n", pop_after ? "p" : "", i);
sewardj8308aad2004-09-12 11:09:54 +00003824 /* This is a bit of a hack (and isn't really right). It sets
3825 Z,P,C,O correctly, but forces A and S to zero, whereas the Intel
3826 documentation implies A and S are unchanged.
3827 */
sewardjfeeb8a82004-11-30 12:30:11 +00003828 /* It's also fishy in that it is used both for COMIP and
3829 UCOMIP, and they aren't the same (although similar). */
sewardj2a9ad022004-11-25 02:46:58 +00003830 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(X86G_CC_OP_COPY) ));
sewardj2a2ba8b2004-11-08 13:14:06 +00003831 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
3832 stmt( IRStmt_Put( OFFB_CC_DEP1,
sewardj8308aad2004-09-12 11:09:54 +00003833 binop( Iop_And32,
3834 binop(Iop_CmpF64, get_ST(0), get_ST(i)),
3835 mkU32(0x45)
3836 )));
sewardja3b7e3a2005-04-05 01:54:19 +00003837 /* Set NDEP even though it isn't used. This makes redundant-PUT
3838 elimination of previous stores to this field work better. */
3839 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
sewardj8308aad2004-09-12 11:09:54 +00003840 if (pop_after)
3841 fp_pop();
3842}
3843
sewardjdb199622004-09-06 23:19:03 +00003844
sewardjd1725d12004-08-12 20:46:53 +00003845static
sewardj52d04912005-07-03 00:52:48 +00003846UInt dis_FPU ( Bool* decode_ok, UChar sorb, Int delta )
sewardjd1725d12004-08-12 20:46:53 +00003847{
sewardja58ea662004-08-15 03:12:41 +00003848 Int len;
3849 UInt r_src, r_dst;
sewardjc9a43662004-11-30 18:51:59 +00003850 HChar dis_buf[50];
sewardj89cd0932004-09-08 18:23:25 +00003851 IRTemp t1, t2;
sewardjd1725d12004-08-12 20:46:53 +00003852
3853 /* On entry, delta points at the second byte of the insn (the modrm
3854 byte).*/
3855 UChar first_opcode = getIByte(delta-1);
3856 UChar modrm = getIByte(delta+0);
3857
3858 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xD8 opcodes +-+-+-+-+-+-+-+ */
3859
3860 if (first_opcode == 0xD8) {
sewardjdb199622004-09-06 23:19:03 +00003861 if (modrm < 0xC0) {
sewardj89cd0932004-09-08 18:23:25 +00003862
3863 /* bits 5,4,3 are an opcode extension, and the modRM also
3864 specifies an address. */
3865 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
3866 delta += len;
3867
3868 switch (gregOfRM(modrm)) {
3869
sewardj3fd5e572004-09-09 22:43:51 +00003870 case 0: /* FADD single-real */
3871 fp_do_op_mem_ST_0 ( addr, "add", dis_buf, Iop_AddF64, False );
3872 break;
3873
sewardj89cd0932004-09-08 18:23:25 +00003874 case 1: /* FMUL single-real */
3875 fp_do_op_mem_ST_0 ( addr, "mul", dis_buf, Iop_MulF64, False );
3876 break;
3877
sewardj7ca37d92004-10-25 02:58:30 +00003878 case 2: /* FCOM single-real */
3879 DIP("fcoms %s\n", dis_buf);
3880 /* This forces C1 to zero, which isn't right. */
3881 put_C3210(
3882 binop( Iop_And32,
3883 binop(Iop_Shl32,
3884 binop(Iop_CmpF64,
3885 get_ST(0),
3886 unop(Iop_F32toF64,
3887 loadLE(Ity_F32,mkexpr(addr)))),
3888 mkU8(8)),
3889 mkU32(0x4500)
3890 ));
3891 break;
3892
3893 case 3: /* FCOMP single-real */
sewardje166ed02004-10-25 02:27:01 +00003894 DIP("fcomps %s\n", dis_buf);
3895 /* This forces C1 to zero, which isn't right. */
3896 put_C3210(
3897 binop( Iop_And32,
3898 binop(Iop_Shl32,
3899 binop(Iop_CmpF64,
3900 get_ST(0),
3901 unop(Iop_F32toF64,
3902 loadLE(Ity_F32,mkexpr(addr)))),
3903 mkU8(8)),
3904 mkU32(0x4500)
3905 ));
3906 fp_pop();
3907 break;
3908
sewardj588ea762004-09-10 18:56:32 +00003909 case 4: /* FSUB single-real */
3910 fp_do_op_mem_ST_0 ( addr, "sub", dis_buf, Iop_SubF64, False );
3911 break;
3912
3913 case 5: /* FSUBR single-real */
3914 fp_do_oprev_mem_ST_0 ( addr, "subr", dis_buf, Iop_SubF64, False );
3915 break;
3916
sewardjbdc7d212004-09-09 02:46:40 +00003917 case 6: /* FDIV single-real */
3918 fp_do_op_mem_ST_0 ( addr, "div", dis_buf, Iop_DivF64, False );
3919 break;
3920
sewardj8308aad2004-09-12 11:09:54 +00003921 case 7: /* FDIVR single-real */
3922 fp_do_oprev_mem_ST_0 ( addr, "divr", dis_buf, Iop_DivF64, False );
3923 break;
3924
sewardj89cd0932004-09-08 18:23:25 +00003925 default:
florianb1737742015-08-03 16:03:13 +00003926 vex_printf("unhandled opc_aux = 0x%2x\n", (UInt)gregOfRM(modrm));
sewardj89cd0932004-09-08 18:23:25 +00003927 vex_printf("first_opcode == 0xD8\n");
3928 goto decode_fail;
3929 }
sewardjdb199622004-09-06 23:19:03 +00003930 } else {
3931 delta++;
3932 switch (modrm) {
sewardj89cd0932004-09-08 18:23:25 +00003933
sewardjdb199622004-09-06 23:19:03 +00003934 case 0xC0 ... 0xC7: /* FADD %st(?),%st(0) */
sewardjbdc7d212004-09-09 02:46:40 +00003935 fp_do_op_ST_ST ( "add", Iop_AddF64, modrm - 0xC0, 0, False );
sewardjdb199622004-09-06 23:19:03 +00003936 break;
sewardj89cd0932004-09-08 18:23:25 +00003937
sewardj3fd5e572004-09-09 22:43:51 +00003938 case 0xC8 ... 0xCF: /* FMUL %st(?),%st(0) */
3939 fp_do_op_ST_ST ( "mul", Iop_MulF64, modrm - 0xC8, 0, False );
3940 break;
3941
sewardje166ed02004-10-25 02:27:01 +00003942 /* Dunno if this is right */
3943 case 0xD0 ... 0xD7: /* FCOM %st(?),%st(0) */
3944 r_dst = (UInt)modrm - 0xD0;
florianb1737742015-08-03 16:03:13 +00003945 DIP("fcom %%st(0),%%st(%u)\n", r_dst);
sewardje166ed02004-10-25 02:27:01 +00003946 /* This forces C1 to zero, which isn't right. */
3947 put_C3210(
3948 binop( Iop_And32,
3949 binop(Iop_Shl32,
3950 binop(Iop_CmpF64, get_ST(0), get_ST(r_dst)),
3951 mkU8(8)),
3952 mkU32(0x4500)
3953 ));
3954 break;
sewardj2d49b432005-02-01 00:37:06 +00003955
sewardj98169c52004-10-24 13:11:39 +00003956 /* Dunno if this is right */
3957 case 0xD8 ... 0xDF: /* FCOMP %st(?),%st(0) */
3958 r_dst = (UInt)modrm - 0xD8;
florianb1737742015-08-03 16:03:13 +00003959 DIP("fcomp %%st(0),%%st(%u)\n", r_dst);
sewardj98169c52004-10-24 13:11:39 +00003960 /* This forces C1 to zero, which isn't right. */
3961 put_C3210(
3962 binop( Iop_And32,
3963 binop(Iop_Shl32,
3964 binop(Iop_CmpF64, get_ST(0), get_ST(r_dst)),
3965 mkU8(8)),
3966 mkU32(0x4500)
3967 ));
3968 fp_pop();
3969 break;
sewardj2d49b432005-02-01 00:37:06 +00003970
sewardj89cd0932004-09-08 18:23:25 +00003971 case 0xE0 ... 0xE7: /* FSUB %st(?),%st(0) */
sewardjbdc7d212004-09-09 02:46:40 +00003972 fp_do_op_ST_ST ( "sub", Iop_SubF64, modrm - 0xE0, 0, False );
sewardj89cd0932004-09-08 18:23:25 +00003973 break;
3974
sewardj8308aad2004-09-12 11:09:54 +00003975 case 0xE8 ... 0xEF: /* FSUBR %st(?),%st(0) */
3976 fp_do_oprev_ST_ST ( "subr", Iop_SubF64, modrm - 0xE8, 0, False );
3977 break;
3978
sewardj3fd5e572004-09-09 22:43:51 +00003979 case 0xF0 ... 0xF7: /* FDIV %st(?),%st(0) */
3980 fp_do_op_ST_ST ( "div", Iop_DivF64, modrm - 0xF0, 0, False );
3981 break;
3982
3983 case 0xF8 ... 0xFF: /* FDIVR %st(?),%st(0) */
3984 fp_do_oprev_ST_ST ( "divr", Iop_DivF64, modrm - 0xF8, 0, False );
3985 break;
3986
sewardjdb199622004-09-06 23:19:03 +00003987 default:
3988 goto decode_fail;
3989 }
3990 }
sewardjd1725d12004-08-12 20:46:53 +00003991 }
3992
3993 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xD9 opcodes +-+-+-+-+-+-+-+ */
3994 else
3995 if (first_opcode == 0xD9) {
sewardjbb53f8c2004-08-14 11:50:01 +00003996 if (modrm < 0xC0) {
sewardj89cd0932004-09-08 18:23:25 +00003997
3998 /* bits 5,4,3 are an opcode extension, and the modRM also
sewardjfeeb8a82004-11-30 12:30:11 +00003999 specifies an address. */
sewardj89cd0932004-09-08 18:23:25 +00004000 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
4001 delta += len;
4002
4003 switch (gregOfRM(modrm)) {
4004
4005 case 0: /* FLD single-real */
sewardj33dd31b2005-01-08 18:17:32 +00004006 DIP("flds %s\n", dis_buf);
sewardj89cd0932004-09-08 18:23:25 +00004007 fp_push();
4008 put_ST(0, unop(Iop_F32toF64,
sewardj8f3debf2004-09-08 23:42:23 +00004009 loadLE(Ity_F32, mkexpr(addr))));
sewardj89cd0932004-09-08 18:23:25 +00004010 break;
4011
sewardj588ea762004-09-10 18:56:32 +00004012 case 2: /* FST single-real */
sewardj33dd31b2005-01-08 18:17:32 +00004013 DIP("fsts %s\n", dis_buf);
sewardj3bca9062004-12-04 14:36:09 +00004014 storeLE(mkexpr(addr),
4015 binop(Iop_F64toF32, get_roundingmode(), get_ST(0)));
sewardj588ea762004-09-10 18:56:32 +00004016 break;
4017
sewardj89cd0932004-09-08 18:23:25 +00004018 case 3: /* FSTP single-real */
sewardj33dd31b2005-01-08 18:17:32 +00004019 DIP("fstps %s\n", dis_buf);
sewardj3bca9062004-12-04 14:36:09 +00004020 storeLE(mkexpr(addr),
4021 binop(Iop_F64toF32, get_roundingmode(), get_ST(0)));
sewardj5bd4d162004-11-10 13:02:48 +00004022 fp_pop();
sewardj89cd0932004-09-08 18:23:25 +00004023 break;
4024
sewardjd24931d2005-03-20 12:51:39 +00004025 case 4: { /* FLDENV m28 */
sewardj7df596b2004-12-06 14:29:12 +00004026 /* Uses dirty helper:
florian6ef84be2012-08-26 03:20:07 +00004027 VexEmNote x86g_do_FLDENV ( VexGuestX86State*, HWord ) */
sewardj7df596b2004-12-06 14:29:12 +00004028 IRTemp ew = newTemp(Ity_I32);
4029 IRDirty* d = unsafeIRDirty_0_N (
4030 0/*regparms*/,
4031 "x86g_dirtyhelper_FLDENV",
4032 &x86g_dirtyhelper_FLDENV,
florian90419562013-08-15 20:54:52 +00004033 mkIRExprVec_2( IRExpr_BBPTR(), mkexpr(addr) )
sewardj7df596b2004-12-06 14:29:12 +00004034 );
sewardj74142b82013-08-08 10:28:59 +00004035 d->tmp = ew;
sewardj7df596b2004-12-06 14:29:12 +00004036 /* declare we're reading memory */
4037 d->mFx = Ifx_Read;
4038 d->mAddr = mkexpr(addr);
4039 d->mSize = 28;
4040
4041 /* declare we're writing guest state */
sewardj46813fc2005-06-13 12:33:36 +00004042 d->nFxState = 4;
sewardjc9069f22012-06-01 16:09:50 +00004043 vex_bzero(&d->fxState, sizeof(d->fxState));
sewardj7df596b2004-12-06 14:29:12 +00004044
4045 d->fxState[0].fx = Ifx_Write;
4046 d->fxState[0].offset = OFFB_FTOP;
4047 d->fxState[0].size = sizeof(UInt);
4048
4049 d->fxState[1].fx = Ifx_Write;
sewardj46813fc2005-06-13 12:33:36 +00004050 d->fxState[1].offset = OFFB_FPTAGS;
4051 d->fxState[1].size = 8 * sizeof(UChar);
sewardj7df596b2004-12-06 14:29:12 +00004052
4053 d->fxState[2].fx = Ifx_Write;
sewardj46813fc2005-06-13 12:33:36 +00004054 d->fxState[2].offset = OFFB_FPROUND;
4055 d->fxState[2].size = sizeof(UInt);
sewardj7df596b2004-12-06 14:29:12 +00004056
4057 d->fxState[3].fx = Ifx_Write;
sewardj46813fc2005-06-13 12:33:36 +00004058 d->fxState[3].offset = OFFB_FC3210;
sewardj7df596b2004-12-06 14:29:12 +00004059 d->fxState[3].size = sizeof(UInt);
4060
sewardj7df596b2004-12-06 14:29:12 +00004061 stmt( IRStmt_Dirty(d) );
4062
4063 /* ew contains any emulation warning we may need to
4064 issue. If needed, side-exit to the next insn,
4065 reporting the warning, so that Valgrind's dispatcher
4066 sees the warning. */
4067 put_emwarn( mkexpr(ew) );
4068 stmt(
4069 IRStmt_Exit(
4070 binop(Iop_CmpNE32, mkexpr(ew), mkU32(0)),
4071 Ijk_EmWarn,
sewardjc6f970f2012-04-02 21:54:49 +00004072 IRConst_U32( ((Addr32)guest_EIP_bbstart)+delta),
4073 OFFB_EIP
sewardj7df596b2004-12-06 14:29:12 +00004074 )
4075 );
4076
sewardj33dd31b2005-01-08 18:17:32 +00004077 DIP("fldenv %s\n", dis_buf);
sewardj7df596b2004-12-06 14:29:12 +00004078 break;
4079 }
4080
sewardj893aada2004-11-29 19:57:54 +00004081 case 5: {/* FLDCW */
4082 /* The only thing we observe in the control word is the
sewardjd01a9632004-11-30 13:18:37 +00004083 rounding mode. Therefore, pass the 16-bit value
4084 (x87 native-format control word) to a clean helper,
4085 getting back a 64-bit value, the lower half of which
4086 is the FPROUND value to store, and the upper half of
4087 which is the emulation-warning token which may be
4088 generated.
sewardj893aada2004-11-29 19:57:54 +00004089 */
4090 /* ULong x86h_check_fldcw ( UInt ); */
4091 IRTemp t64 = newTemp(Ity_I64);
4092 IRTemp ew = newTemp(Ity_I32);
sewardj33dd31b2005-01-08 18:17:32 +00004093 DIP("fldcw %s\n", dis_buf);
sewardj893aada2004-11-29 19:57:54 +00004094 assign( t64, mkIRExprCCall(
4095 Ity_I64, 0/*regparms*/,
sewardj3bd6f3e2004-12-13 10:48:19 +00004096 "x86g_check_fldcw",
4097 &x86g_check_fldcw,
sewardj893aada2004-11-29 19:57:54 +00004098 mkIRExprVec_1(
4099 unop( Iop_16Uto32,
4100 loadLE(Ity_I16, mkexpr(addr)))
4101 )
4102 )
4103 );
4104
sewardjd01a9632004-11-30 13:18:37 +00004105 put_fpround( unop(Iop_64to32, mkexpr(t64)) );
sewardj893aada2004-11-29 19:57:54 +00004106 assign( ew, unop(Iop_64HIto32, mkexpr(t64) ) );
4107 put_emwarn( mkexpr(ew) );
4108 /* Finally, if an emulation warning was reported,
4109 side-exit to the next insn, reporting the warning,
4110 so that Valgrind's dispatcher sees the warning. */
4111 stmt(
4112 IRStmt_Exit(
4113 binop(Iop_CmpNE32, mkexpr(ew), mkU32(0)),
4114 Ijk_EmWarn,
sewardjc6f970f2012-04-02 21:54:49 +00004115 IRConst_U32( ((Addr32)guest_EIP_bbstart)+delta),
4116 OFFB_EIP
sewardj893aada2004-11-29 19:57:54 +00004117 )
4118 );
sewardj89cd0932004-09-08 18:23:25 +00004119 break;
sewardj893aada2004-11-29 19:57:54 +00004120 }
sewardj89cd0932004-09-08 18:23:25 +00004121
sewardj7df596b2004-12-06 14:29:12 +00004122 case 6: { /* FNSTENV m28 */
4123 /* Uses dirty helper:
sewardj4017a3b2005-06-13 12:17:27 +00004124 void x86g_do_FSTENV ( VexGuestX86State*, HWord ) */
sewardj7df596b2004-12-06 14:29:12 +00004125 IRDirty* d = unsafeIRDirty_0_N (
4126 0/*regparms*/,
4127 "x86g_dirtyhelper_FSTENV",
4128 &x86g_dirtyhelper_FSTENV,
florian90419562013-08-15 20:54:52 +00004129 mkIRExprVec_2( IRExpr_BBPTR(), mkexpr(addr) )
sewardj7df596b2004-12-06 14:29:12 +00004130 );
sewardj7df596b2004-12-06 14:29:12 +00004131 /* declare we're writing memory */
4132 d->mFx = Ifx_Write;
4133 d->mAddr = mkexpr(addr);
4134 d->mSize = 28;
4135
4136 /* declare we're reading guest state */
4137 d->nFxState = 4;
sewardjc9069f22012-06-01 16:09:50 +00004138 vex_bzero(&d->fxState, sizeof(d->fxState));
sewardj7df596b2004-12-06 14:29:12 +00004139
4140 d->fxState[0].fx = Ifx_Read;
4141 d->fxState[0].offset = OFFB_FTOP;
4142 d->fxState[0].size = sizeof(UInt);
4143
4144 d->fxState[1].fx = Ifx_Read;
4145 d->fxState[1].offset = OFFB_FPTAGS;
4146 d->fxState[1].size = 8 * sizeof(UChar);
4147
4148 d->fxState[2].fx = Ifx_Read;
4149 d->fxState[2].offset = OFFB_FPROUND;
4150 d->fxState[2].size = sizeof(UInt);
4151
4152 d->fxState[3].fx = Ifx_Read;
4153 d->fxState[3].offset = OFFB_FC3210;
4154 d->fxState[3].size = sizeof(UInt);
4155
4156 stmt( IRStmt_Dirty(d) );
4157
sewardj33dd31b2005-01-08 18:17:32 +00004158 DIP("fnstenv %s\n", dis_buf);
sewardj7df596b2004-12-06 14:29:12 +00004159 break;
4160 }
4161
sewardj588ea762004-09-10 18:56:32 +00004162 case 7: /* FNSTCW */
sewardj893aada2004-11-29 19:57:54 +00004163 /* Fake up a native x87 FPU control word. The only
sewardjd01a9632004-11-30 13:18:37 +00004164 thing it depends on is FPROUND[1:0], so call a clean
sewardj893aada2004-11-29 19:57:54 +00004165 helper to cook it up. */
sewardjd01a9632004-11-30 13:18:37 +00004166 /* UInt x86h_create_fpucw ( UInt fpround ) */
sewardj33dd31b2005-01-08 18:17:32 +00004167 DIP("fnstcw %s\n", dis_buf);
sewardj893aada2004-11-29 19:57:54 +00004168 storeLE(
4169 mkexpr(addr),
4170 unop( Iop_32to16,
4171 mkIRExprCCall(
4172 Ity_I32, 0/*regp*/,
sewardj3bd6f3e2004-12-13 10:48:19 +00004173 "x86g_create_fpucw", &x86g_create_fpucw,
sewardjd01a9632004-11-30 13:18:37 +00004174 mkIRExprVec_1( get_fpround() )
sewardj893aada2004-11-29 19:57:54 +00004175 )
4176 )
4177 );
sewardj89cd0932004-09-08 18:23:25 +00004178 break;
4179
4180 default:
florianb1737742015-08-03 16:03:13 +00004181 vex_printf("unhandled opc_aux = 0x%2x\n", (UInt)gregOfRM(modrm));
sewardj89cd0932004-09-08 18:23:25 +00004182 vex_printf("first_opcode == 0xD9\n");
4183 goto decode_fail;
4184 }
4185
sewardjbb53f8c2004-08-14 11:50:01 +00004186 } else {
4187 delta++;
4188 switch (modrm) {
sewardj89cd0932004-09-08 18:23:25 +00004189
sewardjbb53f8c2004-08-14 11:50:01 +00004190 case 0xC0 ... 0xC7: /* FLD %st(?) */
sewardja58ea662004-08-15 03:12:41 +00004191 r_src = (UInt)modrm - 0xC0;
florianb1737742015-08-03 16:03:13 +00004192 DIP("fld %%st(%u)\n", r_src);
sewardj5bd4d162004-11-10 13:02:48 +00004193 t1 = newTemp(Ity_F64);
4194 assign(t1, get_ST(r_src));
4195 fp_push();
4196 put_ST(0, mkexpr(t1));
sewardjbb53f8c2004-08-14 11:50:01 +00004197 break;
4198
sewardj89cd0932004-09-08 18:23:25 +00004199 case 0xC8 ... 0xCF: /* FXCH %st(?) */
4200 r_src = (UInt)modrm - 0xC8;
florianb1737742015-08-03 16:03:13 +00004201 DIP("fxch %%st(%u)\n", r_src);
sewardj89cd0932004-09-08 18:23:25 +00004202 t1 = newTemp(Ity_F64);
4203 t2 = newTemp(Ity_F64);
4204 assign(t1, get_ST(0));
4205 assign(t2, get_ST(r_src));
4206 put_ST_UNCHECKED(0, mkexpr(t2));
4207 put_ST_UNCHECKED(r_src, mkexpr(t1));
4208 break;
4209
sewardjcfded9a2004-09-09 11:44:16 +00004210 case 0xE0: /* FCHS */
4211 DIP("fchs\n");
4212 put_ST_UNCHECKED(0, unop(Iop_NegF64, get_ST(0)));
4213 break;
4214
sewardj883b00b2004-09-11 09:30:24 +00004215 case 0xE1: /* FABS */
4216 DIP("fabs\n");
4217 put_ST_UNCHECKED(0, unop(Iop_AbsF64, get_ST(0)));
4218 break;
sewardjc4be80c2004-09-10 16:17:45 +00004219
sewardj1c318772005-03-19 14:27:04 +00004220 case 0xE4: /* FTST */
4221 DIP("ftst\n");
4222 /* This forces C1 to zero, which isn't right. */
4223 /* Well, in fact the Intel docs say (bizarrely): "C1 is
4224 set to 0 if stack underflow occurred; otherwise, set
4225 to 0" which is pretty nonsensical. I guess it's a
4226 typo. */
4227 put_C3210(
4228 binop( Iop_And32,
4229 binop(Iop_Shl32,
4230 binop(Iop_CmpF64,
4231 get_ST(0),
4232 IRExpr_Const(IRConst_F64i(0x0ULL))),
4233 mkU8(8)),
4234 mkU32(0x4500)
4235 ));
4236 break;
4237
sewardj883b00b2004-09-11 09:30:24 +00004238 case 0xE5: { /* FXAM */
4239 /* This is an interesting one. It examines %st(0),
4240 regardless of whether the tag says it's empty or not.
4241 Here, just pass both the tag (in our format) and the
4242 value (as a double, actually a ULong) to a helper
4243 function. */
sewardjf9655262004-10-31 20:02:16 +00004244 IRExpr** args
4245 = mkIRExprVec_2( unop(Iop_8Uto32, get_ST_TAG(0)),
4246 unop(Iop_ReinterpF64asI64,
4247 get_ST_UNCHECKED(0)) );
4248 put_C3210(mkIRExprCCall(
sewardj8ea867b2004-10-30 19:03:02 +00004249 Ity_I32,
sewardjf9655262004-10-31 20:02:16 +00004250 0/*regparm*/,
sewardj2a9ad022004-11-25 02:46:58 +00004251 "x86g_calculate_FXAM", &x86g_calculate_FXAM,
sewardj8ea867b2004-10-30 19:03:02 +00004252 args
4253 ));
sewardj33dd31b2005-01-08 18:17:32 +00004254 DIP("fxam\n");
sewardj883b00b2004-09-11 09:30:24 +00004255 break;
4256 }
4257
4258 case 0xE8: /* FLD1 */
sewardj33dd31b2005-01-08 18:17:32 +00004259 DIP("fld1\n");
sewardjce646f22004-08-31 23:55:54 +00004260 fp_push();
sewardj9c323762005-01-10 16:49:19 +00004261 /* put_ST(0, IRExpr_Const(IRConst_F64(1.0))); */
4262 put_ST(0, IRExpr_Const(IRConst_F64i(0x3ff0000000000000ULL)));
sewardjce646f22004-08-31 23:55:54 +00004263 break;
4264
sewardj37158712004-10-15 21:23:12 +00004265 case 0xE9: /* FLDL2T */
sewardj33dd31b2005-01-08 18:17:32 +00004266 DIP("fldl2t\n");
sewardj37158712004-10-15 21:23:12 +00004267 fp_push();
sewardj9c323762005-01-10 16:49:19 +00004268 /* put_ST(0, IRExpr_Const(IRConst_F64(3.32192809488736234781))); */
4269 put_ST(0, IRExpr_Const(IRConst_F64i(0x400a934f0979a371ULL)));
sewardj37158712004-10-15 21:23:12 +00004270 break;
4271
sewardj8308aad2004-09-12 11:09:54 +00004272 case 0xEA: /* FLDL2E */
sewardj33dd31b2005-01-08 18:17:32 +00004273 DIP("fldl2e\n");
sewardj8308aad2004-09-12 11:09:54 +00004274 fp_push();
sewardj9c323762005-01-10 16:49:19 +00004275 /* put_ST(0, IRExpr_Const(IRConst_F64(1.44269504088896340739))); */
4276 put_ST(0, IRExpr_Const(IRConst_F64i(0x3ff71547652b82feULL)));
sewardj8308aad2004-09-12 11:09:54 +00004277 break;
4278
sewardja0d48d62004-09-20 21:19:03 +00004279 case 0xEB: /* FLDPI */
sewardj33dd31b2005-01-08 18:17:32 +00004280 DIP("fldpi\n");
sewardja0d48d62004-09-20 21:19:03 +00004281 fp_push();
sewardj9c323762005-01-10 16:49:19 +00004282 /* put_ST(0, IRExpr_Const(IRConst_F64(3.14159265358979323851))); */
4283 put_ST(0, IRExpr_Const(IRConst_F64i(0x400921fb54442d18ULL)));
sewardja0d48d62004-09-20 21:19:03 +00004284 break;
4285
sewardjdb199622004-09-06 23:19:03 +00004286 case 0xEC: /* FLDLG2 */
sewardj33dd31b2005-01-08 18:17:32 +00004287 DIP("fldlg2\n");
sewardjdb199622004-09-06 23:19:03 +00004288 fp_push();
sewardj9c323762005-01-10 16:49:19 +00004289 /* put_ST(0, IRExpr_Const(IRConst_F64(0.301029995663981143))); */
4290 put_ST(0, IRExpr_Const(IRConst_F64i(0x3fd34413509f79ffULL)));
sewardjdb199622004-09-06 23:19:03 +00004291 break;
4292
4293 case 0xED: /* FLDLN2 */
sewardj33dd31b2005-01-08 18:17:32 +00004294 DIP("fldln2\n");
sewardjdb199622004-09-06 23:19:03 +00004295 fp_push();
sewardj9c323762005-01-10 16:49:19 +00004296 /* put_ST(0, IRExpr_Const(IRConst_F64(0.69314718055994530942))); */
4297 put_ST(0, IRExpr_Const(IRConst_F64i(0x3fe62e42fefa39efULL)));
sewardjdb199622004-09-06 23:19:03 +00004298 break;
4299
sewardja58ea662004-08-15 03:12:41 +00004300 case 0xEE: /* FLDZ */
sewardj33dd31b2005-01-08 18:17:32 +00004301 DIP("fldz\n");
sewardj207557a2004-08-27 12:00:18 +00004302 fp_push();
sewardj9c323762005-01-10 16:49:19 +00004303 /* put_ST(0, IRExpr_Const(IRConst_F64(0.0))); */
4304 put_ST(0, IRExpr_Const(IRConst_F64i(0x0000000000000000ULL)));
sewardja58ea662004-08-15 03:12:41 +00004305 break;
4306
sewardj06c32a02004-09-12 12:07:34 +00004307 case 0xF0: /* F2XM1 */
4308 DIP("f2xm1\n");
sewardjf1b5b1a2006-02-03 22:54:17 +00004309 put_ST_UNCHECKED(0,
4310 binop(Iop_2xm1F64,
4311 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4312 get_ST(0)));
sewardj06c32a02004-09-12 12:07:34 +00004313 break;
4314
sewardj52ace3e2004-09-11 17:10:08 +00004315 case 0xF1: /* FYL2X */
4316 DIP("fyl2x\n");
sewardjf1b5b1a2006-02-03 22:54:17 +00004317 put_ST_UNCHECKED(1,
4318 triop(Iop_Yl2xF64,
4319 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4320 get_ST(1),
4321 get_ST(0)));
sewardj52ace3e2004-09-11 17:10:08 +00004322 fp_pop();
4323 break;
4324
sewardje9c51c92014-04-30 22:50:34 +00004325 case 0xF2: { /* FPTAN */
4326 DIP("fptan\n");
4327 IRTemp argD = newTemp(Ity_F64);
4328 assign(argD, get_ST(0));
4329 IRTemp argOK = math_IS_TRIG_ARG_FINITE_AND_IN_RANGE(argD);
4330 IRTemp resD = newTemp(Ity_F64);
4331 assign(resD,
4332 IRExpr_ITE(
4333 mkexpr(argOK),
4334 binop(Iop_TanF64,
4335 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4336 mkexpr(argD)),
4337 mkexpr(argD))
4338 );
4339 put_ST_UNCHECKED(0, mkexpr(resD));
4340 /* Conditionally push 1.0 on the stack, if the arg is
4341 in range */
4342 maybe_fp_push(argOK);
4343 maybe_put_ST(argOK, 0,
4344 IRExpr_Const(IRConst_F64(1.0)));
4345 set_C2( binop(Iop_Xor32,
4346 unop(Iop_1Uto32, mkexpr(argOK)),
4347 mkU32(1)) );
sewardj99016a72004-10-15 22:09:17 +00004348 break;
sewardje9c51c92014-04-30 22:50:34 +00004349 }
sewardj99016a72004-10-15 22:09:17 +00004350
sewardjcfded9a2004-09-09 11:44:16 +00004351 case 0xF3: /* FPATAN */
4352 DIP("fpatan\n");
sewardjf1b5b1a2006-02-03 22:54:17 +00004353 put_ST_UNCHECKED(1,
4354 triop(Iop_AtanF64,
4355 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4356 get_ST(1),
4357 get_ST(0)));
sewardjcfded9a2004-09-09 11:44:16 +00004358 fp_pop();
4359 break;
4360
sewardjf1b5b1a2006-02-03 22:54:17 +00004361 case 0xF4: { /* FXTRACT */
sewardjfda10af2005-10-03 01:02:40 +00004362 IRTemp argF = newTemp(Ity_F64);
4363 IRTemp sigF = newTemp(Ity_F64);
4364 IRTemp expF = newTemp(Ity_F64);
4365 IRTemp argI = newTemp(Ity_I64);
4366 IRTemp sigI = newTemp(Ity_I64);
4367 IRTemp expI = newTemp(Ity_I64);
4368 DIP("fxtract\n");
4369 assign( argF, get_ST(0) );
4370 assign( argI, unop(Iop_ReinterpF64asI64, mkexpr(argF)));
4371 assign( sigI,
sewardj879cee02006-03-07 01:15:50 +00004372 mkIRExprCCall(
4373 Ity_I64, 0/*regparms*/,
4374 "x86amd64g_calculate_FXTRACT",
4375 &x86amd64g_calculate_FXTRACT,
4376 mkIRExprVec_2( mkexpr(argI),
4377 mkIRExpr_HWord(0)/*sig*/ ))
4378 );
sewardjfda10af2005-10-03 01:02:40 +00004379 assign( expI,
sewardj879cee02006-03-07 01:15:50 +00004380 mkIRExprCCall(
4381 Ity_I64, 0/*regparms*/,
4382 "x86amd64g_calculate_FXTRACT",
4383 &x86amd64g_calculate_FXTRACT,
4384 mkIRExprVec_2( mkexpr(argI),
4385 mkIRExpr_HWord(1)/*exp*/ ))
4386 );
sewardjfda10af2005-10-03 01:02:40 +00004387 assign( sigF, unop(Iop_ReinterpI64asF64, mkexpr(sigI)) );
4388 assign( expF, unop(Iop_ReinterpI64asF64, mkexpr(expI)) );
4389 /* exponent */
4390 put_ST_UNCHECKED(0, mkexpr(expF) );
4391 fp_push();
4392 /* significand */
4393 put_ST(0, mkexpr(sigF) );
4394 break;
4395 }
4396
sewardj442d0be2004-10-15 22:57:13 +00004397 case 0xF5: { /* FPREM1 -- IEEE compliant */
4398 IRTemp a1 = newTemp(Ity_F64);
4399 IRTemp a2 = newTemp(Ity_F64);
4400 DIP("fprem1\n");
4401 /* Do FPREM1 twice, once to get the remainder, and once
4402 to get the C3210 flag values. */
4403 assign( a1, get_ST(0) );
4404 assign( a2, get_ST(1) );
sewardjf47286e2006-02-04 15:20:13 +00004405 put_ST_UNCHECKED(0,
4406 triop(Iop_PRem1F64,
4407 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4408 mkexpr(a1),
4409 mkexpr(a2)));
4410 put_C3210(
4411 triop(Iop_PRem1C3210F64,
4412 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4413 mkexpr(a1),
4414 mkexpr(a2)) );
sewardj442d0be2004-10-15 22:57:13 +00004415 break;
4416 }
4417
sewardjfeeb8a82004-11-30 12:30:11 +00004418 case 0xF7: /* FINCSTP */
4419 DIP("fprem\n");
4420 put_ftop( binop(Iop_Add32, get_ftop(), mkU32(1)) );
4421 break;
4422
sewardj46de4072004-09-11 19:23:24 +00004423 case 0xF8: { /* FPREM -- not IEEE compliant */
4424 IRTemp a1 = newTemp(Ity_F64);
4425 IRTemp a2 = newTemp(Ity_F64);
4426 DIP("fprem\n");
4427 /* Do FPREM twice, once to get the remainder, and once
4428 to get the C3210 flag values. */
4429 assign( a1, get_ST(0) );
4430 assign( a2, get_ST(1) );
sewardjf47286e2006-02-04 15:20:13 +00004431 put_ST_UNCHECKED(0,
4432 triop(Iop_PRemF64,
4433 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4434 mkexpr(a1),
4435 mkexpr(a2)));
4436 put_C3210(
4437 triop(Iop_PRemC3210F64,
4438 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4439 mkexpr(a1),
4440 mkexpr(a2)) );
sewardj46de4072004-09-11 19:23:24 +00004441 break;
4442 }
4443
sewardj8308aad2004-09-12 11:09:54 +00004444 case 0xF9: /* FYL2XP1 */
4445 DIP("fyl2xp1\n");
sewardjf1b5b1a2006-02-03 22:54:17 +00004446 put_ST_UNCHECKED(1,
4447 triop(Iop_Yl2xp1F64,
4448 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4449 get_ST(1),
4450 get_ST(0)));
sewardj8308aad2004-09-12 11:09:54 +00004451 fp_pop();
4452 break;
4453
sewardjc4be80c2004-09-10 16:17:45 +00004454 case 0xFA: /* FSQRT */
4455 DIP("fsqrt\n");
sewardjf1b5b1a2006-02-03 22:54:17 +00004456 put_ST_UNCHECKED(0,
4457 binop(Iop_SqrtF64,
4458 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4459 get_ST(0)));
sewardjc4be80c2004-09-10 16:17:45 +00004460 break;
4461
sewardj519d66f2004-12-15 11:57:58 +00004462 case 0xFB: { /* FSINCOS */
sewardj519d66f2004-12-15 11:57:58 +00004463 DIP("fsincos\n");
sewardje9c51c92014-04-30 22:50:34 +00004464 IRTemp argD = newTemp(Ity_F64);
4465 assign(argD, get_ST(0));
4466 IRTemp argOK = math_IS_TRIG_ARG_FINITE_AND_IN_RANGE(argD);
4467 IRTemp resD = newTemp(Ity_F64);
4468 assign(resD,
4469 IRExpr_ITE(
4470 mkexpr(argOK),
4471 binop(Iop_SinF64,
4472 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4473 mkexpr(argD)),
4474 mkexpr(argD))
4475 );
4476 put_ST_UNCHECKED(0, mkexpr(resD));
4477 /* Conditionally push the cos value on the stack, if
4478 the arg is in range */
4479 maybe_fp_push(argOK);
4480 maybe_put_ST(argOK, 0,
sewardjf1b5b1a2006-02-03 22:54:17 +00004481 binop(Iop_CosF64,
4482 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
sewardje9c51c92014-04-30 22:50:34 +00004483 mkexpr(argD)));
4484 set_C2( binop(Iop_Xor32,
4485 unop(Iop_1Uto32, mkexpr(argOK)),
4486 mkU32(1)) );
sewardj519d66f2004-12-15 11:57:58 +00004487 break;
4488 }
4489
sewardje6709112004-09-10 18:37:18 +00004490 case 0xFC: /* FRNDINT */
4491 DIP("frndint\n");
4492 put_ST_UNCHECKED(0,
sewardjb183b852006-02-03 16:08:03 +00004493 binop(Iop_RoundF64toInt, get_roundingmode(), get_ST(0)) );
sewardje6709112004-09-10 18:37:18 +00004494 break;
4495
sewardj06c32a02004-09-12 12:07:34 +00004496 case 0xFD: /* FSCALE */
4497 DIP("fscale\n");
sewardjf1b5b1a2006-02-03 22:54:17 +00004498 put_ST_UNCHECKED(0,
4499 triop(Iop_ScaleF64,
4500 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4501 get_ST(0),
4502 get_ST(1)));
sewardj06c32a02004-09-12 12:07:34 +00004503 break;
4504
sewardje9c51c92014-04-30 22:50:34 +00004505 case 0xFE: /* FSIN */
4506 case 0xFF: { /* FCOS */
4507 Bool isSIN = modrm == 0xFE;
4508 DIP("%s\n", isSIN ? "fsin" : "fcos");
4509 IRTemp argD = newTemp(Ity_F64);
4510 assign(argD, get_ST(0));
4511 IRTemp argOK = math_IS_TRIG_ARG_FINITE_AND_IN_RANGE(argD);
4512 IRTemp resD = newTemp(Ity_F64);
4513 assign(resD,
4514 IRExpr_ITE(
4515 mkexpr(argOK),
4516 binop(isSIN ? Iop_SinF64 : Iop_CosF64,
4517 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4518 mkexpr(argD)),
4519 mkexpr(argD))
4520 );
4521 put_ST_UNCHECKED(0, mkexpr(resD));
4522 set_C2( binop(Iop_Xor32,
4523 unop(Iop_1Uto32, mkexpr(argOK)),
4524 mkU32(1)) );
sewardjcfded9a2004-09-09 11:44:16 +00004525 break;
sewardje9c51c92014-04-30 22:50:34 +00004526 }
sewardjcfded9a2004-09-09 11:44:16 +00004527
sewardjbb53f8c2004-08-14 11:50:01 +00004528 default:
4529 goto decode_fail;
4530 }
4531 }
sewardjd1725d12004-08-12 20:46:53 +00004532 }
4533
4534 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDA opcodes +-+-+-+-+-+-+-+ */
4535 else
4536 if (first_opcode == 0xDA) {
sewardjbb53f8c2004-08-14 11:50:01 +00004537
4538 if (modrm < 0xC0) {
4539
sewardjfeeb8a82004-11-30 12:30:11 +00004540 /* bits 5,4,3 are an opcode extension, and the modRM also
sewardjbb53f8c2004-08-14 11:50:01 +00004541 specifies an address. */
sewardjce646f22004-08-31 23:55:54 +00004542 IROp fop;
sewardjbb53f8c2004-08-14 11:50:01 +00004543 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
4544 delta += len;
sewardjbb53f8c2004-08-14 11:50:01 +00004545 switch (gregOfRM(modrm)) {
sewardjce646f22004-08-31 23:55:54 +00004546
sewardjdb199622004-09-06 23:19:03 +00004547 case 0: /* FIADD m32int */ /* ST(0) += m32int */
sewardj33dd31b2005-01-08 18:17:32 +00004548 DIP("fiaddl %s\n", dis_buf);
sewardj5bd4d162004-11-10 13:02:48 +00004549 fop = Iop_AddF64;
4550 goto do_fop_m32;
sewardjdb199622004-09-06 23:19:03 +00004551
sewardj207557a2004-08-27 12:00:18 +00004552 case 1: /* FIMUL m32int */ /* ST(0) *= m32int */
sewardj33dd31b2005-01-08 18:17:32 +00004553 DIP("fimull %s\n", dis_buf);
sewardj5bd4d162004-11-10 13:02:48 +00004554 fop = Iop_MulF64;
4555 goto do_fop_m32;
sewardjce646f22004-08-31 23:55:54 +00004556
sewardj071895f2005-07-29 11:28:38 +00004557 case 2: /* FICOM m32int */
4558 DIP("ficoml %s\n", dis_buf);
4559 /* This forces C1 to zero, which isn't right. */
4560 put_C3210(
4561 binop( Iop_And32,
4562 binop(Iop_Shl32,
4563 binop(Iop_CmpF64,
4564 get_ST(0),
sewardj6c299f32009-12-31 18:00:12 +00004565 unop(Iop_I32StoF64,
sewardj071895f2005-07-29 11:28:38 +00004566 loadLE(Ity_I32,mkexpr(addr)))),
4567 mkU8(8)),
4568 mkU32(0x4500)
4569 ));
4570 break;
4571
4572 case 3: /* FICOMP m32int */
4573 DIP("ficompl %s\n", dis_buf);
4574 /* This forces C1 to zero, which isn't right. */
4575 put_C3210(
4576 binop( Iop_And32,
4577 binop(Iop_Shl32,
4578 binop(Iop_CmpF64,
4579 get_ST(0),
sewardj6c299f32009-12-31 18:00:12 +00004580 unop(Iop_I32StoF64,
sewardj071895f2005-07-29 11:28:38 +00004581 loadLE(Ity_I32,mkexpr(addr)))),
4582 mkU8(8)),
4583 mkU32(0x4500)
4584 ));
4585 fp_pop();
4586 break;
4587
sewardjce646f22004-08-31 23:55:54 +00004588 case 4: /* FISUB m32int */ /* ST(0) -= m32int */
sewardj33dd31b2005-01-08 18:17:32 +00004589 DIP("fisubl %s\n", dis_buf);
sewardj5bd4d162004-11-10 13:02:48 +00004590 fop = Iop_SubF64;
4591 goto do_fop_m32;
sewardjce646f22004-08-31 23:55:54 +00004592
sewardj8308aad2004-09-12 11:09:54 +00004593 case 5: /* FISUBR m32int */ /* ST(0) = m32int - ST(0) */
sewardj33dd31b2005-01-08 18:17:32 +00004594 DIP("fisubrl %s\n", dis_buf);
sewardj5bd4d162004-11-10 13:02:48 +00004595 fop = Iop_SubF64;
4596 goto do_foprev_m32;
sewardj8308aad2004-09-12 11:09:54 +00004597
sewardjce646f22004-08-31 23:55:54 +00004598 case 6: /* FIDIV m32int */ /* ST(0) /= m32int */
sewardj36917e92005-03-21 00:12:15 +00004599 DIP("fidivl %s\n", dis_buf);
sewardj5bd4d162004-11-10 13:02:48 +00004600 fop = Iop_DivF64;
4601 goto do_fop_m32;
sewardjce646f22004-08-31 23:55:54 +00004602
sewardjc4eaff32004-09-10 20:25:11 +00004603 case 7: /* FIDIVR m32int */ /* ST(0) = m32int / ST(0) */
sewardj33dd31b2005-01-08 18:17:32 +00004604 DIP("fidivrl %s\n", dis_buf);
sewardj5bd4d162004-11-10 13:02:48 +00004605 fop = Iop_DivF64;
4606 goto do_foprev_m32;
sewardjc4eaff32004-09-10 20:25:11 +00004607
sewardjce646f22004-08-31 23:55:54 +00004608 do_fop_m32:
sewardj207557a2004-08-27 12:00:18 +00004609 put_ST_UNCHECKED(0,
sewardjf1b5b1a2006-02-03 22:54:17 +00004610 triop(fop,
4611 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
sewardj207557a2004-08-27 12:00:18 +00004612 get_ST(0),
sewardj6c299f32009-12-31 18:00:12 +00004613 unop(Iop_I32StoF64,
sewardj89cd0932004-09-08 18:23:25 +00004614 loadLE(Ity_I32, mkexpr(addr)))));
sewardjbb53f8c2004-08-14 11:50:01 +00004615 break;
4616
sewardjc4eaff32004-09-10 20:25:11 +00004617 do_foprev_m32:
4618 put_ST_UNCHECKED(0,
sewardjf1b5b1a2006-02-03 22:54:17 +00004619 triop(fop,
4620 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
sewardj6c299f32009-12-31 18:00:12 +00004621 unop(Iop_I32StoF64,
sewardjc4eaff32004-09-10 20:25:11 +00004622 loadLE(Ity_I32, mkexpr(addr))),
4623 get_ST(0)));
4624 break;
4625
sewardjbb53f8c2004-08-14 11:50:01 +00004626 default:
florianb1737742015-08-03 16:03:13 +00004627 vex_printf("unhandled opc_aux = 0x%2x\n", (UInt)gregOfRM(modrm));
sewardjbb53f8c2004-08-14 11:50:01 +00004628 vex_printf("first_opcode == 0xDA\n");
4629 goto decode_fail;
4630 }
sewardj4cb918d2004-12-03 19:43:31 +00004631
sewardjbb53f8c2004-08-14 11:50:01 +00004632 } else {
sewardjbdc7d212004-09-09 02:46:40 +00004633
4634 delta++;
4635 switch (modrm) {
4636
sewardj519d66f2004-12-15 11:57:58 +00004637 case 0xC0 ... 0xC7: /* FCMOVB ST(i), ST(0) */
4638 r_src = (UInt)modrm - 0xC0;
florianb1737742015-08-03 16:03:13 +00004639 DIP("fcmovb %%st(%u), %%st(0)\n", r_src);
sewardj519d66f2004-12-15 11:57:58 +00004640 put_ST_UNCHECKED(0,
florian99dd03e2013-01-29 03:56:06 +00004641 IRExpr_ITE(
sewardj009230b2013-01-26 11:47:55 +00004642 mk_x86g_calculate_condition(X86CondB),
florian99dd03e2013-01-29 03:56:06 +00004643 get_ST(r_src), get_ST(0)) );
sewardj519d66f2004-12-15 11:57:58 +00004644 break;
4645
sewardj3fd5e572004-09-09 22:43:51 +00004646 case 0xC8 ... 0xCF: /* FCMOVE(Z) ST(i), ST(0) */
4647 r_src = (UInt)modrm - 0xC8;
florianb1737742015-08-03 16:03:13 +00004648 DIP("fcmovz %%st(%u), %%st(0)\n", r_src);
sewardj5bd4d162004-11-10 13:02:48 +00004649 put_ST_UNCHECKED(0,
florian99dd03e2013-01-29 03:56:06 +00004650 IRExpr_ITE(
sewardj009230b2013-01-26 11:47:55 +00004651 mk_x86g_calculate_condition(X86CondZ),
florian99dd03e2013-01-29 03:56:06 +00004652 get_ST(r_src), get_ST(0)) );
sewardj3fd5e572004-09-09 22:43:51 +00004653 break;
4654
sewardj519d66f2004-12-15 11:57:58 +00004655 case 0xD0 ... 0xD7: /* FCMOVBE ST(i), ST(0) */
4656 r_src = (UInt)modrm - 0xD0;
florianb1737742015-08-03 16:03:13 +00004657 DIP("fcmovbe %%st(%u), %%st(0)\n", r_src);
sewardj519d66f2004-12-15 11:57:58 +00004658 put_ST_UNCHECKED(0,
florian99dd03e2013-01-29 03:56:06 +00004659 IRExpr_ITE(
sewardj009230b2013-01-26 11:47:55 +00004660 mk_x86g_calculate_condition(X86CondBE),
florian99dd03e2013-01-29 03:56:06 +00004661 get_ST(r_src), get_ST(0)) );
sewardj519d66f2004-12-15 11:57:58 +00004662 break;
4663
sewardj8253ad32005-07-04 10:26:32 +00004664 case 0xD8 ... 0xDF: /* FCMOVU ST(i), ST(0) */
4665 r_src = (UInt)modrm - 0xD8;
florianb1737742015-08-03 16:03:13 +00004666 DIP("fcmovu %%st(%u), %%st(0)\n", r_src);
sewardj8253ad32005-07-04 10:26:32 +00004667 put_ST_UNCHECKED(0,
florian99dd03e2013-01-29 03:56:06 +00004668 IRExpr_ITE(
sewardj009230b2013-01-26 11:47:55 +00004669 mk_x86g_calculate_condition(X86CondP),
florian99dd03e2013-01-29 03:56:06 +00004670 get_ST(r_src), get_ST(0)) );
sewardj8253ad32005-07-04 10:26:32 +00004671 break;
4672
sewardjbdc7d212004-09-09 02:46:40 +00004673 case 0xE9: /* FUCOMPP %st(0),%st(1) */
4674 DIP("fucompp %%st(0),%%st(1)\n");
sewardjc4be80c2004-09-10 16:17:45 +00004675 /* This forces C1 to zero, which isn't right. */
4676 put_C3210(
4677 binop( Iop_And32,
4678 binop(Iop_Shl32,
4679 binop(Iop_CmpF64, get_ST(0), get_ST(1)),
4680 mkU8(8)),
4681 mkU32(0x4500)
4682 ));
sewardjbdc7d212004-09-09 02:46:40 +00004683 fp_pop();
4684 fp_pop();
4685 break;
4686
sewardj5bd4d162004-11-10 13:02:48 +00004687 default:
sewardjbdc7d212004-09-09 02:46:40 +00004688 goto decode_fail;
sewardj5bd4d162004-11-10 13:02:48 +00004689 }
sewardjbdc7d212004-09-09 02:46:40 +00004690
sewardjbb53f8c2004-08-14 11:50:01 +00004691 }
sewardjd1725d12004-08-12 20:46:53 +00004692 }
4693
4694 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDB opcodes +-+-+-+-+-+-+-+ */
4695 else
4696 if (first_opcode == 0xDB) {
sewardj89cd0932004-09-08 18:23:25 +00004697 if (modrm < 0xC0) {
4698
sewardjfeeb8a82004-11-30 12:30:11 +00004699 /* bits 5,4,3 are an opcode extension, and the modRM also
sewardj89cd0932004-09-08 18:23:25 +00004700 specifies an address. */
4701 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
4702 delta += len;
4703
4704 switch (gregOfRM(modrm)) {
4705
4706 case 0: /* FILD m32int */
4707 DIP("fildl %s\n", dis_buf);
4708 fp_push();
sewardj6c299f32009-12-31 18:00:12 +00004709 put_ST(0, unop(Iop_I32StoF64,
sewardj89cd0932004-09-08 18:23:25 +00004710 loadLE(Ity_I32, mkexpr(addr))));
4711 break;
4712
sewardjdd5d2042006-08-03 15:03:19 +00004713 case 1: /* FISTTPL m32 (SSE3) */
4714 DIP("fisttpl %s\n", dis_buf);
4715 storeLE( mkexpr(addr),
sewardj6c299f32009-12-31 18:00:12 +00004716 binop(Iop_F64toI32S, mkU32(Irrm_ZERO), get_ST(0)) );
sewardjdd5d2042006-08-03 15:03:19 +00004717 fp_pop();
4718 break;
4719
sewardj8f3debf2004-09-08 23:42:23 +00004720 case 2: /* FIST m32 */
sewardj33dd31b2005-01-08 18:17:32 +00004721 DIP("fistl %s\n", dis_buf);
sewardj8f3debf2004-09-08 23:42:23 +00004722 storeLE( mkexpr(addr),
sewardj6c299f32009-12-31 18:00:12 +00004723 binop(Iop_F64toI32S, get_roundingmode(), get_ST(0)) );
sewardj8f3debf2004-09-08 23:42:23 +00004724 break;
4725
sewardj89cd0932004-09-08 18:23:25 +00004726 case 3: /* FISTP m32 */
sewardj33dd31b2005-01-08 18:17:32 +00004727 DIP("fistpl %s\n", dis_buf);
sewardj8f3debf2004-09-08 23:42:23 +00004728 storeLE( mkexpr(addr),
sewardj6c299f32009-12-31 18:00:12 +00004729 binop(Iop_F64toI32S, get_roundingmode(), get_ST(0)) );
sewardj5bd4d162004-11-10 13:02:48 +00004730 fp_pop();
sewardj89cd0932004-09-08 18:23:25 +00004731 break;
sewardj17442fe2004-09-20 14:54:28 +00004732
sewardjb3bce0e2004-09-14 23:20:10 +00004733 case 5: { /* FLD extended-real */
sewardj7cb49d72004-10-24 22:31:25 +00004734 /* Uses dirty helper:
sewardj56579232005-03-26 21:49:42 +00004735 ULong x86g_loadF80le ( UInt )
sewardj7cb49d72004-10-24 22:31:25 +00004736 addr holds the address. First, do a dirty call to
sewardjb3bce0e2004-09-14 23:20:10 +00004737 get hold of the data. */
sewardjc5fc7aa2004-10-27 23:00:55 +00004738 IRTemp val = newTemp(Ity_I64);
4739 IRExpr** args = mkIRExprVec_1 ( mkexpr(addr) );
4740
sewardj8ea867b2004-10-30 19:03:02 +00004741 IRDirty* d = unsafeIRDirty_1_N (
4742 val,
sewardj2a9ad022004-11-25 02:46:58 +00004743 0/*regparms*/,
sewardj8f40b072005-08-23 19:30:58 +00004744 "x86g_dirtyhelper_loadF80le",
4745 &x86g_dirtyhelper_loadF80le,
sewardj8ea867b2004-10-30 19:03:02 +00004746 args
4747 );
sewardjb3bce0e2004-09-14 23:20:10 +00004748 /* declare that we're reading memory */
4749 d->mFx = Ifx_Read;
sewardj17442fe2004-09-20 14:54:28 +00004750 d->mAddr = mkexpr(addr);
sewardjb3bce0e2004-09-14 23:20:10 +00004751 d->mSize = 10;
sewardjc5fc7aa2004-10-27 23:00:55 +00004752
4753 /* execute the dirty call, dumping the result in val. */
sewardjb3bce0e2004-09-14 23:20:10 +00004754 stmt( IRStmt_Dirty(d) );
4755 fp_push();
sewardjc5fc7aa2004-10-27 23:00:55 +00004756 put_ST(0, unop(Iop_ReinterpI64asF64, mkexpr(val)));
4757
sewardj33dd31b2005-01-08 18:17:32 +00004758 DIP("fldt %s\n", dis_buf);
sewardjb3bce0e2004-09-14 23:20:10 +00004759 break;
4760 }
sewardj17442fe2004-09-20 14:54:28 +00004761
4762 case 7: { /* FSTP extended-real */
sewardj9fc9e782004-11-26 17:57:40 +00004763 /* Uses dirty helper: void x86g_storeF80le ( UInt, ULong ) */
sewardjc5fc7aa2004-10-27 23:00:55 +00004764 IRExpr** args
4765 = mkIRExprVec_2( mkexpr(addr),
4766 unop(Iop_ReinterpF64asI64, get_ST(0)) );
4767
sewardj8ea867b2004-10-30 19:03:02 +00004768 IRDirty* d = unsafeIRDirty_0_N (
sewardjf9655262004-10-31 20:02:16 +00004769 0/*regparms*/,
sewardj8f40b072005-08-23 19:30:58 +00004770 "x86g_dirtyhelper_storeF80le",
4771 &x86g_dirtyhelper_storeF80le,
sewardj8ea867b2004-10-30 19:03:02 +00004772 args
4773 );
sewardj17442fe2004-09-20 14:54:28 +00004774 /* declare we're writing memory */
4775 d->mFx = Ifx_Write;
4776 d->mAddr = mkexpr(addr);
4777 d->mSize = 10;
sewardjc5fc7aa2004-10-27 23:00:55 +00004778
sewardj17442fe2004-09-20 14:54:28 +00004779 /* execute the dirty call. */
4780 stmt( IRStmt_Dirty(d) );
4781 fp_pop();
sewardjc5fc7aa2004-10-27 23:00:55 +00004782
sewardj33dd31b2005-01-08 18:17:32 +00004783 DIP("fstpt\n %s", dis_buf);
sewardj17442fe2004-09-20 14:54:28 +00004784 break;
4785 }
4786
sewardjb3bce0e2004-09-14 23:20:10 +00004787 default:
florianb1737742015-08-03 16:03:13 +00004788 vex_printf("unhandled opc_aux = 0x%2x\n", (UInt)gregOfRM(modrm));
sewardj89cd0932004-09-08 18:23:25 +00004789 vex_printf("first_opcode == 0xDB\n");
4790 goto decode_fail;
4791 }
4792
4793 } else {
sewardj8308aad2004-09-12 11:09:54 +00004794
4795 delta++;
4796 switch (modrm) {
4797
sewardj519d66f2004-12-15 11:57:58 +00004798 case 0xC0 ... 0xC7: /* FCMOVNB ST(i), ST(0) */
4799 r_src = (UInt)modrm - 0xC0;
florianb1737742015-08-03 16:03:13 +00004800 DIP("fcmovnb %%st(%u), %%st(0)\n", r_src);
sewardj519d66f2004-12-15 11:57:58 +00004801 put_ST_UNCHECKED(0,
florian99dd03e2013-01-29 03:56:06 +00004802 IRExpr_ITE(
sewardj009230b2013-01-26 11:47:55 +00004803 mk_x86g_calculate_condition(X86CondNB),
florian99dd03e2013-01-29 03:56:06 +00004804 get_ST(r_src), get_ST(0)) );
sewardj519d66f2004-12-15 11:57:58 +00004805 break;
4806
sewardj4e82db72004-10-16 11:32:15 +00004807 case 0xC8 ... 0xCF: /* FCMOVNE(NZ) ST(i), ST(0) */
4808 r_src = (UInt)modrm - 0xC8;
florianb1737742015-08-03 16:03:13 +00004809 DIP("fcmovnz %%st(%u), %%st(0)\n", r_src);
sewardj5bd4d162004-11-10 13:02:48 +00004810 put_ST_UNCHECKED(0,
florian99dd03e2013-01-29 03:56:06 +00004811 IRExpr_ITE(
sewardj009230b2013-01-26 11:47:55 +00004812 mk_x86g_calculate_condition(X86CondNZ),
florian99dd03e2013-01-29 03:56:06 +00004813 get_ST(r_src), get_ST(0)) );
sewardj4e82db72004-10-16 11:32:15 +00004814 break;
4815
sewardj519d66f2004-12-15 11:57:58 +00004816 case 0xD0 ... 0xD7: /* FCMOVNBE ST(i), ST(0) */
4817 r_src = (UInt)modrm - 0xD0;
florianb1737742015-08-03 16:03:13 +00004818 DIP("fcmovnbe %%st(%u), %%st(0)\n", r_src);
sewardj519d66f2004-12-15 11:57:58 +00004819 put_ST_UNCHECKED(0,
florian99dd03e2013-01-29 03:56:06 +00004820 IRExpr_ITE(
sewardj009230b2013-01-26 11:47:55 +00004821 mk_x86g_calculate_condition(X86CondNBE),
florian99dd03e2013-01-29 03:56:06 +00004822 get_ST(r_src), get_ST(0)) );
sewardj519d66f2004-12-15 11:57:58 +00004823 break;
4824
sewardj8253ad32005-07-04 10:26:32 +00004825 case 0xD8 ... 0xDF: /* FCMOVNU ST(i), ST(0) */
4826 r_src = (UInt)modrm - 0xD8;
florianb1737742015-08-03 16:03:13 +00004827 DIP("fcmovnu %%st(%u), %%st(0)\n", r_src);
sewardj8253ad32005-07-04 10:26:32 +00004828 put_ST_UNCHECKED(0,
florian99dd03e2013-01-29 03:56:06 +00004829 IRExpr_ITE(
sewardj009230b2013-01-26 11:47:55 +00004830 mk_x86g_calculate_condition(X86CondNP),
florian99dd03e2013-01-29 03:56:06 +00004831 get_ST(r_src), get_ST(0)) );
sewardj8253ad32005-07-04 10:26:32 +00004832 break;
4833
sewardj7df596b2004-12-06 14:29:12 +00004834 case 0xE2:
4835 DIP("fnclex\n");
4836 break;
4837
sewardja0e83b02005-01-06 12:36:38 +00004838 case 0xE3: {
4839 /* Uses dirty helper:
4840 void x86g_do_FINIT ( VexGuestX86State* ) */
4841 IRDirty* d = unsafeIRDirty_0_N (
4842 0/*regparms*/,
4843 "x86g_dirtyhelper_FINIT",
4844 &x86g_dirtyhelper_FINIT,
florian90419562013-08-15 20:54:52 +00004845 mkIRExprVec_1(IRExpr_BBPTR())
sewardja0e83b02005-01-06 12:36:38 +00004846 );
sewardja0e83b02005-01-06 12:36:38 +00004847
4848 /* declare we're writing guest state */
4849 d->nFxState = 5;
sewardjc9069f22012-06-01 16:09:50 +00004850 vex_bzero(&d->fxState, sizeof(d->fxState));
sewardja0e83b02005-01-06 12:36:38 +00004851
4852 d->fxState[0].fx = Ifx_Write;
4853 d->fxState[0].offset = OFFB_FTOP;
4854 d->fxState[0].size = sizeof(UInt);
4855
4856 d->fxState[1].fx = Ifx_Write;
4857 d->fxState[1].offset = OFFB_FPREGS;
4858 d->fxState[1].size = 8 * sizeof(ULong);
4859
4860 d->fxState[2].fx = Ifx_Write;
4861 d->fxState[2].offset = OFFB_FPTAGS;
4862 d->fxState[2].size = 8 * sizeof(UChar);
4863
4864 d->fxState[3].fx = Ifx_Write;
4865 d->fxState[3].offset = OFFB_FPROUND;
4866 d->fxState[3].size = sizeof(UInt);
4867
4868 d->fxState[4].fx = Ifx_Write;
4869 d->fxState[4].offset = OFFB_FC3210;
4870 d->fxState[4].size = sizeof(UInt);
4871
4872 stmt( IRStmt_Dirty(d) );
4873
sewardj33dd31b2005-01-08 18:17:32 +00004874 DIP("fninit\n");
sewardja0e83b02005-01-06 12:36:38 +00004875 break;
4876 }
4877
sewardj8308aad2004-09-12 11:09:54 +00004878 case 0xE8 ... 0xEF: /* FUCOMI %st(0),%st(?) */
4879 fp_do_ucomi_ST0_STi( (UInt)modrm - 0xE8, False );
4880 break;
4881
sewardj37158712004-10-15 21:23:12 +00004882 case 0xF0 ... 0xF7: /* FCOMI %st(0),%st(?) */
4883 fp_do_ucomi_ST0_STi( (UInt)modrm - 0xF0, False );
4884 break;
4885
sewardj8308aad2004-09-12 11:09:54 +00004886 default:
4887 goto decode_fail;
sewardj17442fe2004-09-20 14:54:28 +00004888 }
sewardj89cd0932004-09-08 18:23:25 +00004889 }
sewardjd1725d12004-08-12 20:46:53 +00004890 }
4891
4892 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDC opcodes +-+-+-+-+-+-+-+ */
4893 else
4894 if (first_opcode == 0xDC) {
sewardja58ea662004-08-15 03:12:41 +00004895 if (modrm < 0xC0) {
4896
sewardj89cd0932004-09-08 18:23:25 +00004897 /* bits 5,4,3 are an opcode extension, and the modRM also
sewardjfeeb8a82004-11-30 12:30:11 +00004898 specifies an address. */
sewardja58ea662004-08-15 03:12:41 +00004899 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
4900 delta += len;
4901
4902 switch (gregOfRM(modrm)) {
4903
4904 case 0: /* FADD double-real */
4905 fp_do_op_mem_ST_0 ( addr, "add", dis_buf, Iop_AddF64, True );
4906 break;
4907
sewardjcfded9a2004-09-09 11:44:16 +00004908 case 1: /* FMUL double-real */
4909 fp_do_op_mem_ST_0 ( addr, "mul", dis_buf, Iop_MulF64, True );
4910 break;
4911
sewardje166ed02004-10-25 02:27:01 +00004912 case 2: /* FCOM double-real */
4913 DIP("fcoml %s\n", dis_buf);
4914 /* This forces C1 to zero, which isn't right. */
4915 put_C3210(
4916 binop( Iop_And32,
4917 binop(Iop_Shl32,
4918 binop(Iop_CmpF64,
4919 get_ST(0),
4920 loadLE(Ity_F64,mkexpr(addr))),
4921 mkU8(8)),
4922 mkU32(0x4500)
4923 ));
4924 break;
4925
sewardj883b00b2004-09-11 09:30:24 +00004926 case 3: /* FCOMP double-real */
sewardje166ed02004-10-25 02:27:01 +00004927 DIP("fcompl %s\n", dis_buf);
sewardj883b00b2004-09-11 09:30:24 +00004928 /* This forces C1 to zero, which isn't right. */
4929 put_C3210(
4930 binop( Iop_And32,
4931 binop(Iop_Shl32,
4932 binop(Iop_CmpF64,
4933 get_ST(0),
4934 loadLE(Ity_F64,mkexpr(addr))),
4935 mkU8(8)),
4936 mkU32(0x4500)
4937 ));
4938 fp_pop();
4939 break;
4940
sewardjcfded9a2004-09-09 11:44:16 +00004941 case 4: /* FSUB double-real */
4942 fp_do_op_mem_ST_0 ( addr, "sub", dis_buf, Iop_SubF64, True );
4943 break;
4944
sewardj3fd5e572004-09-09 22:43:51 +00004945 case 5: /* FSUBR double-real */
4946 fp_do_oprev_mem_ST_0 ( addr, "subr", dis_buf, Iop_SubF64, True );
4947 break;
4948
sewardjcfded9a2004-09-09 11:44:16 +00004949 case 6: /* FDIV double-real */
4950 fp_do_op_mem_ST_0 ( addr, "div", dis_buf, Iop_DivF64, True );
4951 break;
4952
sewardj883b00b2004-09-11 09:30:24 +00004953 case 7: /* FDIVR double-real */
4954 fp_do_oprev_mem_ST_0 ( addr, "divr", dis_buf, Iop_DivF64, True );
4955 break;
4956
sewardja58ea662004-08-15 03:12:41 +00004957 default:
florianb1737742015-08-03 16:03:13 +00004958 vex_printf("unhandled opc_aux = 0x%2x\n", (UInt)gregOfRM(modrm));
sewardja58ea662004-08-15 03:12:41 +00004959 vex_printf("first_opcode == 0xDC\n");
4960 goto decode_fail;
4961 }
4962
4963 } else {
sewardjbdc7d212004-09-09 02:46:40 +00004964
4965 delta++;
4966 switch (modrm) {
4967
sewardj3fd5e572004-09-09 22:43:51 +00004968 case 0xC0 ... 0xC7: /* FADD %st(0),%st(?) */
4969 fp_do_op_ST_ST ( "add", Iop_AddF64, 0, modrm - 0xC0, False );
4970 break;
4971
sewardjcfded9a2004-09-09 11:44:16 +00004972 case 0xC8 ... 0xCF: /* FMUL %st(0),%st(?) */
4973 fp_do_op_ST_ST ( "mul", Iop_MulF64, 0, modrm - 0xC8, False );
4974 break;
4975
sewardj47341042004-09-19 11:55:46 +00004976 case 0xE0 ... 0xE7: /* FSUBR %st(0),%st(?) */
4977 fp_do_oprev_ST_ST ( "subr", Iop_SubF64, 0, modrm - 0xE0, False );
4978 break;
4979
sewardjcfded9a2004-09-09 11:44:16 +00004980 case 0xE8 ... 0xEF: /* FSUB %st(0),%st(?) */
4981 fp_do_op_ST_ST ( "sub", Iop_SubF64, 0, modrm - 0xE8, False );
4982 break;
4983
sewardja0d48d62004-09-20 21:19:03 +00004984 case 0xF0 ... 0xF7: /* FDIVR %st(0),%st(?) */
4985 fp_do_oprev_ST_ST ( "divr", Iop_DivF64, 0, modrm - 0xF0, False );
4986 break;
4987
sewardjbdc7d212004-09-09 02:46:40 +00004988 case 0xF8 ... 0xFF: /* FDIV %st(0),%st(?) */
4989 fp_do_op_ST_ST ( "div", Iop_DivF64, 0, modrm - 0xF8, False );
4990 break;
4991
4992 default:
4993 goto decode_fail;
sewardj5bd4d162004-11-10 13:02:48 +00004994 }
sewardjbdc7d212004-09-09 02:46:40 +00004995
sewardja58ea662004-08-15 03:12:41 +00004996 }
sewardjd1725d12004-08-12 20:46:53 +00004997 }
4998
4999 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDD opcodes +-+-+-+-+-+-+-+ */
5000 else
5001 if (first_opcode == 0xDD) {
5002
5003 if (modrm < 0xC0) {
5004
sewardjfeeb8a82004-11-30 12:30:11 +00005005 /* bits 5,4,3 are an opcode extension, and the modRM also
sewardjd1725d12004-08-12 20:46:53 +00005006 specifies an address. */
sewardjbb53f8c2004-08-14 11:50:01 +00005007 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
5008 delta += len;
sewardjd1725d12004-08-12 20:46:53 +00005009
5010 switch (gregOfRM(modrm)) {
5011
5012 case 0: /* FLD double-real */
sewardj33dd31b2005-01-08 18:17:32 +00005013 DIP("fldl %s\n", dis_buf);
sewardj207557a2004-08-27 12:00:18 +00005014 fp_push();
sewardjaf1ceca2005-06-30 23:31:27 +00005015 put_ST(0, loadLE(Ity_F64, mkexpr(addr)));
sewardjbb53f8c2004-08-14 11:50:01 +00005016 break;
sewardjd1725d12004-08-12 20:46:53 +00005017
sewardjdd5d2042006-08-03 15:03:19 +00005018 case 1: /* FISTTPQ m64 (SSE3) */
5019 DIP("fistppll %s\n", dis_buf);
5020 storeLE( mkexpr(addr),
sewardj6c299f32009-12-31 18:00:12 +00005021 binop(Iop_F64toI64S, mkU32(Irrm_ZERO), get_ST(0)) );
sewardjdd5d2042006-08-03 15:03:19 +00005022 fp_pop();
5023 break;
5024
sewardjd1725d12004-08-12 20:46:53 +00005025 case 2: /* FST double-real */
sewardj33dd31b2005-01-08 18:17:32 +00005026 DIP("fstl %s\n", dis_buf);
sewardj5bd4d162004-11-10 13:02:48 +00005027 storeLE(mkexpr(addr), get_ST(0));
sewardjd1725d12004-08-12 20:46:53 +00005028 break;
sewardj89cd0932004-09-08 18:23:25 +00005029
sewardja58ea662004-08-15 03:12:41 +00005030 case 3: /* FSTP double-real */
sewardj33dd31b2005-01-08 18:17:32 +00005031 DIP("fstpl %s\n", dis_buf);
sewardj5bd4d162004-11-10 13:02:48 +00005032 storeLE(mkexpr(addr), get_ST(0));
5033 fp_pop();
sewardja58ea662004-08-15 03:12:41 +00005034 break;
sewardjd1725d12004-08-12 20:46:53 +00005035
sewardj9fc9e782004-11-26 17:57:40 +00005036 case 4: { /* FRSTOR m108 */
sewardj893aada2004-11-29 19:57:54 +00005037 /* Uses dirty helper:
florian6ef84be2012-08-26 03:20:07 +00005038 VexEmNote x86g_do_FRSTOR ( VexGuestX86State*, Addr32 ) */
sewardj893aada2004-11-29 19:57:54 +00005039 IRTemp ew = newTemp(Ity_I32);
5040 IRDirty* d = unsafeIRDirty_0_N (
5041 0/*regparms*/,
5042 "x86g_dirtyhelper_FRSTOR",
5043 &x86g_dirtyhelper_FRSTOR,
florian90419562013-08-15 20:54:52 +00005044 mkIRExprVec_2( IRExpr_BBPTR(), mkexpr(addr) )
sewardj893aada2004-11-29 19:57:54 +00005045 );
sewardj74142b82013-08-08 10:28:59 +00005046 d->tmp = ew;
sewardj9fc9e782004-11-26 17:57:40 +00005047 /* declare we're reading memory */
5048 d->mFx = Ifx_Read;
5049 d->mAddr = mkexpr(addr);
5050 d->mSize = 108;
5051
5052 /* declare we're writing guest state */
sewardj893aada2004-11-29 19:57:54 +00005053 d->nFxState = 5;
sewardjc9069f22012-06-01 16:09:50 +00005054 vex_bzero(&d->fxState, sizeof(d->fxState));
sewardj9fc9e782004-11-26 17:57:40 +00005055
5056 d->fxState[0].fx = Ifx_Write;
sewardjc9a43662004-11-30 18:51:59 +00005057 d->fxState[0].offset = OFFB_FTOP;
sewardj9fc9e782004-11-26 17:57:40 +00005058 d->fxState[0].size = sizeof(UInt);
5059
5060 d->fxState[1].fx = Ifx_Write;
sewardjc9a43662004-11-30 18:51:59 +00005061 d->fxState[1].offset = OFFB_FPREGS;
sewardj9fc9e782004-11-26 17:57:40 +00005062 d->fxState[1].size = 8 * sizeof(ULong);
5063
5064 d->fxState[2].fx = Ifx_Write;
sewardjc9a43662004-11-30 18:51:59 +00005065 d->fxState[2].offset = OFFB_FPTAGS;
sewardj9fc9e782004-11-26 17:57:40 +00005066 d->fxState[2].size = 8 * sizeof(UChar);
5067
5068 d->fxState[3].fx = Ifx_Write;
sewardjc9a43662004-11-30 18:51:59 +00005069 d->fxState[3].offset = OFFB_FPROUND;
sewardj9fc9e782004-11-26 17:57:40 +00005070 d->fxState[3].size = sizeof(UInt);
5071
5072 d->fxState[4].fx = Ifx_Write;
sewardjc9a43662004-11-30 18:51:59 +00005073 d->fxState[4].offset = OFFB_FC3210;
sewardj9fc9e782004-11-26 17:57:40 +00005074 d->fxState[4].size = sizeof(UInt);
5075
5076 stmt( IRStmt_Dirty(d) );
5077
sewardj893aada2004-11-29 19:57:54 +00005078 /* ew contains any emulation warning we may need to
5079 issue. If needed, side-exit to the next insn,
5080 reporting the warning, so that Valgrind's dispatcher
5081 sees the warning. */
5082 put_emwarn( mkexpr(ew) );
5083 stmt(
5084 IRStmt_Exit(
5085 binop(Iop_CmpNE32, mkexpr(ew), mkU32(0)),
5086 Ijk_EmWarn,
sewardjc6f970f2012-04-02 21:54:49 +00005087 IRConst_U32( ((Addr32)guest_EIP_bbstart)+delta),
5088 OFFB_EIP
sewardj893aada2004-11-29 19:57:54 +00005089 )
5090 );
5091
sewardj33dd31b2005-01-08 18:17:32 +00005092 DIP("frstor %s\n", dis_buf);
sewardj9fc9e782004-11-26 17:57:40 +00005093 break;
5094 }
5095
5096 case 6: { /* FNSAVE m108 */
sewardj893aada2004-11-29 19:57:54 +00005097 /* Uses dirty helper:
5098 void x86g_do_FSAVE ( VexGuestX86State*, UInt ) */
sewardj9fc9e782004-11-26 17:57:40 +00005099 IRDirty* d = unsafeIRDirty_0_N (
5100 0/*regparms*/,
5101 "x86g_dirtyhelper_FSAVE",
5102 &x86g_dirtyhelper_FSAVE,
florian90419562013-08-15 20:54:52 +00005103 mkIRExprVec_2( IRExpr_BBPTR(), mkexpr(addr) )
sewardj9fc9e782004-11-26 17:57:40 +00005104 );
sewardj9fc9e782004-11-26 17:57:40 +00005105 /* declare we're writing memory */
5106 d->mFx = Ifx_Write;
5107 d->mAddr = mkexpr(addr);
5108 d->mSize = 108;
5109
5110 /* declare we're reading guest state */
sewardj893aada2004-11-29 19:57:54 +00005111 d->nFxState = 5;
sewardjc9069f22012-06-01 16:09:50 +00005112 vex_bzero(&d->fxState, sizeof(d->fxState));
sewardj9fc9e782004-11-26 17:57:40 +00005113
5114 d->fxState[0].fx = Ifx_Read;
sewardjc9a43662004-11-30 18:51:59 +00005115 d->fxState[0].offset = OFFB_FTOP;
sewardj9fc9e782004-11-26 17:57:40 +00005116 d->fxState[0].size = sizeof(UInt);
5117
5118 d->fxState[1].fx = Ifx_Read;
sewardjc9a43662004-11-30 18:51:59 +00005119 d->fxState[1].offset = OFFB_FPREGS;
sewardj9fc9e782004-11-26 17:57:40 +00005120 d->fxState[1].size = 8 * sizeof(ULong);
5121
5122 d->fxState[2].fx = Ifx_Read;
sewardjc9a43662004-11-30 18:51:59 +00005123 d->fxState[2].offset = OFFB_FPTAGS;
sewardj9fc9e782004-11-26 17:57:40 +00005124 d->fxState[2].size = 8 * sizeof(UChar);
5125
5126 d->fxState[3].fx = Ifx_Read;
sewardjc9a43662004-11-30 18:51:59 +00005127 d->fxState[3].offset = OFFB_FPROUND;
sewardj9fc9e782004-11-26 17:57:40 +00005128 d->fxState[3].size = sizeof(UInt);
5129
5130 d->fxState[4].fx = Ifx_Read;
sewardjc9a43662004-11-30 18:51:59 +00005131 d->fxState[4].offset = OFFB_FC3210;
sewardj9fc9e782004-11-26 17:57:40 +00005132 d->fxState[4].size = sizeof(UInt);
5133
5134 stmt( IRStmt_Dirty(d) );
5135
sewardj33dd31b2005-01-08 18:17:32 +00005136 DIP("fnsave %s\n", dis_buf);
sewardj9fc9e782004-11-26 17:57:40 +00005137 break;
5138 }
5139
sewardjd24931d2005-03-20 12:51:39 +00005140 case 7: { /* FNSTSW m16 */
5141 IRExpr* sw = get_FPU_sw();
sewardjdd40fdf2006-12-24 02:20:24 +00005142 vassert(typeOfIRExpr(irsb->tyenv, sw) == Ity_I16);
sewardjd24931d2005-03-20 12:51:39 +00005143 storeLE( mkexpr(addr), sw );
5144 DIP("fnstsw %s\n", dis_buf);
5145 break;
5146 }
5147
sewardjd1725d12004-08-12 20:46:53 +00005148 default:
florianb1737742015-08-03 16:03:13 +00005149 vex_printf("unhandled opc_aux = 0x%2x\n", (UInt)gregOfRM(modrm));
sewardjbb53f8c2004-08-14 11:50:01 +00005150 vex_printf("first_opcode == 0xDD\n");
sewardjd1725d12004-08-12 20:46:53 +00005151 goto decode_fail;
sewardjbb53f8c2004-08-14 11:50:01 +00005152 }
sewardjd1725d12004-08-12 20:46:53 +00005153 } else {
sewardja58ea662004-08-15 03:12:41 +00005154 delta++;
5155 switch (modrm) {
sewardjbdc7d212004-09-09 02:46:40 +00005156
sewardj3ddedc42005-03-25 20:30:00 +00005157 case 0xC0 ... 0xC7: /* FFREE %st(?) */
5158 r_dst = (UInt)modrm - 0xC0;
florianb1737742015-08-03 16:03:13 +00005159 DIP("ffree %%st(%u)\n", r_dst);
sewardj3ddedc42005-03-25 20:30:00 +00005160 put_ST_TAG ( r_dst, mkU8(0) );
5161 break;
5162
sewardj06c32a02004-09-12 12:07:34 +00005163 case 0xD0 ... 0xD7: /* FST %st(0),%st(?) */
5164 r_dst = (UInt)modrm - 0xD0;
florianb1737742015-08-03 16:03:13 +00005165 DIP("fst %%st(0),%%st(%u)\n", r_dst);
sewardj5bd4d162004-11-10 13:02:48 +00005166 /* P4 manual says: "If the destination operand is a
sewardj06c32a02004-09-12 12:07:34 +00005167 non-empty register, the invalid-operation exception
5168 is not generated. Hence put_ST_UNCHECKED. */
5169 put_ST_UNCHECKED(r_dst, get_ST(0));
5170 break;
5171
sewardja58ea662004-08-15 03:12:41 +00005172 case 0xD8 ... 0xDF: /* FSTP %st(0),%st(?) */
5173 r_dst = (UInt)modrm - 0xD8;
florianb1737742015-08-03 16:03:13 +00005174 DIP("fstp %%st(0),%%st(%u)\n", r_dst);
sewardj5bd4d162004-11-10 13:02:48 +00005175 /* P4 manual says: "If the destination operand is a
sewardj207557a2004-08-27 12:00:18 +00005176 non-empty register, the invalid-operation exception
5177 is not generated. Hence put_ST_UNCHECKED. */
5178 put_ST_UNCHECKED(r_dst, get_ST(0));
5179 fp_pop();
sewardja58ea662004-08-15 03:12:41 +00005180 break;
sewardjbdc7d212004-09-09 02:46:40 +00005181
5182 case 0xE0 ... 0xE7: /* FUCOM %st(0),%st(?) */
5183 r_dst = (UInt)modrm - 0xE0;
florianb1737742015-08-03 16:03:13 +00005184 DIP("fucom %%st(0),%%st(%u)\n", r_dst);
sewardjc4be80c2004-09-10 16:17:45 +00005185 /* This forces C1 to zero, which isn't right. */
5186 put_C3210(
5187 binop( Iop_And32,
5188 binop(Iop_Shl32,
5189 binop(Iop_CmpF64, get_ST(0), get_ST(r_dst)),
5190 mkU8(8)),
5191 mkU32(0x4500)
5192 ));
sewardjbdc7d212004-09-09 02:46:40 +00005193 break;
5194
5195 case 0xE8 ... 0xEF: /* FUCOMP %st(0),%st(?) */
5196 r_dst = (UInt)modrm - 0xE8;
florianb1737742015-08-03 16:03:13 +00005197 DIP("fucomp %%st(0),%%st(%u)\n", r_dst);
sewardjc4be80c2004-09-10 16:17:45 +00005198 /* This forces C1 to zero, which isn't right. */
5199 put_C3210(
5200 binop( Iop_And32,
5201 binop(Iop_Shl32,
5202 binop(Iop_CmpF64, get_ST(0), get_ST(r_dst)),
5203 mkU8(8)),
5204 mkU32(0x4500)
5205 ));
sewardjbdc7d212004-09-09 02:46:40 +00005206 fp_pop();
5207 break;
5208
sewardj5bd4d162004-11-10 13:02:48 +00005209 default:
sewardja58ea662004-08-15 03:12:41 +00005210 goto decode_fail;
sewardj5bd4d162004-11-10 13:02:48 +00005211 }
sewardjd1725d12004-08-12 20:46:53 +00005212 }
5213 }
5214
5215 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDE opcodes +-+-+-+-+-+-+-+ */
5216 else
5217 if (first_opcode == 0xDE) {
sewardjbdc7d212004-09-09 02:46:40 +00005218
5219 if (modrm < 0xC0) {
sewardjfeeb8a82004-11-30 12:30:11 +00005220
5221 /* bits 5,4,3 are an opcode extension, and the modRM also
5222 specifies an address. */
5223 IROp fop;
5224 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
5225 delta += len;
5226
5227 switch (gregOfRM(modrm)) {
5228
5229 case 0: /* FIADD m16int */ /* ST(0) += m16int */
sewardj33dd31b2005-01-08 18:17:32 +00005230 DIP("fiaddw %s\n", dis_buf);
sewardjfeeb8a82004-11-30 12:30:11 +00005231 fop = Iop_AddF64;
5232 goto do_fop_m16;
5233
5234 case 1: /* FIMUL m16int */ /* ST(0) *= m16int */
sewardj33dd31b2005-01-08 18:17:32 +00005235 DIP("fimulw %s\n", dis_buf);
sewardjfeeb8a82004-11-30 12:30:11 +00005236 fop = Iop_MulF64;
5237 goto do_fop_m16;
5238
sewardj071895f2005-07-29 11:28:38 +00005239 case 2: /* FICOM m16int */
5240 DIP("ficomw %s\n", dis_buf);
5241 /* This forces C1 to zero, which isn't right. */
5242 put_C3210(
5243 binop( Iop_And32,
5244 binop(Iop_Shl32,
5245 binop(Iop_CmpF64,
5246 get_ST(0),
sewardj6c299f32009-12-31 18:00:12 +00005247 unop(Iop_I32StoF64,
sewardj071895f2005-07-29 11:28:38 +00005248 unop(Iop_16Sto32,
5249 loadLE(Ity_I16,mkexpr(addr))))),
5250 mkU8(8)),
5251 mkU32(0x4500)
5252 ));
5253 break;
5254
5255 case 3: /* FICOMP m16int */
5256 DIP("ficompw %s\n", dis_buf);
5257 /* This forces C1 to zero, which isn't right. */
5258 put_C3210(
5259 binop( Iop_And32,
5260 binop(Iop_Shl32,
5261 binop(Iop_CmpF64,
5262 get_ST(0),
sewardj6c299f32009-12-31 18:00:12 +00005263 unop(Iop_I32StoF64,
sewardj071895f2005-07-29 11:28:38 +00005264 unop(Iop_16Sto32,
sewardjf1b5b1a2006-02-03 22:54:17 +00005265 loadLE(Ity_I16,mkexpr(addr))))),
sewardj071895f2005-07-29 11:28:38 +00005266 mkU8(8)),
5267 mkU32(0x4500)
5268 ));
5269 fp_pop();
5270 break;
5271
sewardjfeeb8a82004-11-30 12:30:11 +00005272 case 4: /* FISUB m16int */ /* ST(0) -= m16int */
sewardj33dd31b2005-01-08 18:17:32 +00005273 DIP("fisubw %s\n", dis_buf);
sewardjfeeb8a82004-11-30 12:30:11 +00005274 fop = Iop_SubF64;
5275 goto do_fop_m16;
5276
5277 case 5: /* FISUBR m16int */ /* ST(0) = m16int - ST(0) */
sewardj33dd31b2005-01-08 18:17:32 +00005278 DIP("fisubrw %s\n", dis_buf);
sewardjfeeb8a82004-11-30 12:30:11 +00005279 fop = Iop_SubF64;
5280 goto do_foprev_m16;
5281
5282 case 6: /* FIDIV m16int */ /* ST(0) /= m16int */
sewardj33dd31b2005-01-08 18:17:32 +00005283 DIP("fisubw %s\n", dis_buf);
sewardjfeeb8a82004-11-30 12:30:11 +00005284 fop = Iop_DivF64;
5285 goto do_fop_m16;
5286
5287 case 7: /* FIDIVR m16int */ /* ST(0) = m16int / ST(0) */
sewardj33dd31b2005-01-08 18:17:32 +00005288 DIP("fidivrw %s\n", dis_buf);
sewardjfeeb8a82004-11-30 12:30:11 +00005289 fop = Iop_DivF64;
5290 goto do_foprev_m16;
5291
5292 do_fop_m16:
5293 put_ST_UNCHECKED(0,
sewardjf1b5b1a2006-02-03 22:54:17 +00005294 triop(fop,
5295 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
sewardjfeeb8a82004-11-30 12:30:11 +00005296 get_ST(0),
sewardj6c299f32009-12-31 18:00:12 +00005297 unop(Iop_I32StoF64,
sewardjfeeb8a82004-11-30 12:30:11 +00005298 unop(Iop_16Sto32,
5299 loadLE(Ity_I16, mkexpr(addr))))));
5300 break;
5301
5302 do_foprev_m16:
5303 put_ST_UNCHECKED(0,
sewardjf1b5b1a2006-02-03 22:54:17 +00005304 triop(fop,
5305 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
sewardj6c299f32009-12-31 18:00:12 +00005306 unop(Iop_I32StoF64,
sewardjfeeb8a82004-11-30 12:30:11 +00005307 unop(Iop_16Sto32,
5308 loadLE(Ity_I16, mkexpr(addr)))),
5309 get_ST(0)));
5310 break;
5311
5312 default:
florianb1737742015-08-03 16:03:13 +00005313 vex_printf("unhandled opc_aux = 0x%2x\n", (UInt)gregOfRM(modrm));
sewardjfeeb8a82004-11-30 12:30:11 +00005314 vex_printf("first_opcode == 0xDE\n");
5315 goto decode_fail;
5316 }
sewardjbdc7d212004-09-09 02:46:40 +00005317
5318 } else {
5319
5320 delta++;
sewardj5bd4d162004-11-10 13:02:48 +00005321 switch (modrm) {
sewardjbdc7d212004-09-09 02:46:40 +00005322
sewardjcfded9a2004-09-09 11:44:16 +00005323 case 0xC0 ... 0xC7: /* FADDP %st(0),%st(?) */
5324 fp_do_op_ST_ST ( "add", Iop_AddF64, 0, modrm - 0xC0, True );
5325 break;
5326
sewardjbdc7d212004-09-09 02:46:40 +00005327 case 0xC8 ... 0xCF: /* FMULP %st(0),%st(?) */
5328 fp_do_op_ST_ST ( "mul", Iop_MulF64, 0, modrm - 0xC8, True );
5329 break;
5330
sewardje166ed02004-10-25 02:27:01 +00005331 case 0xD9: /* FCOMPP %st(0),%st(1) */
5332 DIP("fuompp %%st(0),%%st(1)\n");
5333 /* This forces C1 to zero, which isn't right. */
5334 put_C3210(
5335 binop( Iop_And32,
5336 binop(Iop_Shl32,
5337 binop(Iop_CmpF64, get_ST(0), get_ST(1)),
5338 mkU8(8)),
5339 mkU32(0x4500)
5340 ));
5341 fp_pop();
5342 fp_pop();
5343 break;
5344
sewardjcfded9a2004-09-09 11:44:16 +00005345 case 0xE0 ... 0xE7: /* FSUBRP %st(0),%st(?) */
5346 fp_do_oprev_ST_ST ( "subr", Iop_SubF64, 0, modrm - 0xE0, True );
5347 break;
5348
sewardj3fd5e572004-09-09 22:43:51 +00005349 case 0xE8 ... 0xEF: /* FSUBP %st(0),%st(?) */
5350 fp_do_op_ST_ST ( "sub", Iop_SubF64, 0, modrm - 0xE8, True );
5351 break;
5352
sewardjbdc7d212004-09-09 02:46:40 +00005353 case 0xF0 ... 0xF7: /* FDIVRP %st(0),%st(?) */
5354 fp_do_oprev_ST_ST ( "divr", Iop_DivF64, 0, modrm - 0xF0, True );
5355 break;
5356
5357 case 0xF8 ... 0xFF: /* FDIVP %st(0),%st(?) */
5358 fp_do_op_ST_ST ( "div", Iop_DivF64, 0, modrm - 0xF8, True );
5359 break;
5360
5361 default:
5362 goto decode_fail;
sewardj5bd4d162004-11-10 13:02:48 +00005363 }
sewardjbdc7d212004-09-09 02:46:40 +00005364
5365 }
sewardjd1725d12004-08-12 20:46:53 +00005366 }
5367
5368 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDF opcodes +-+-+-+-+-+-+-+ */
5369 else
5370 if (first_opcode == 0xDF) {
sewardj89cd0932004-09-08 18:23:25 +00005371
5372 if (modrm < 0xC0) {
5373
sewardjfeeb8a82004-11-30 12:30:11 +00005374 /* bits 5,4,3 are an opcode extension, and the modRM also
sewardj89cd0932004-09-08 18:23:25 +00005375 specifies an address. */
5376 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
5377 delta += len;
5378
5379 switch (gregOfRM(modrm)) {
5380
sewardj883b00b2004-09-11 09:30:24 +00005381 case 0: /* FILD m16int */
5382 DIP("fildw %s\n", dis_buf);
5383 fp_push();
sewardj6c299f32009-12-31 18:00:12 +00005384 put_ST(0, unop(Iop_I32StoF64,
sewardj883b00b2004-09-11 09:30:24 +00005385 unop(Iop_16Sto32,
5386 loadLE(Ity_I16, mkexpr(addr)))));
5387 break;
5388
sewardjdd5d2042006-08-03 15:03:19 +00005389 case 1: /* FISTTPS m16 (SSE3) */
5390 DIP("fisttps %s\n", dis_buf);
5391 storeLE( mkexpr(addr),
sewardj6c299f32009-12-31 18:00:12 +00005392 binop(Iop_F64toI16S, mkU32(Irrm_ZERO), get_ST(0)) );
sewardjdd5d2042006-08-03 15:03:19 +00005393 fp_pop();
5394 break;
5395
sewardj37158712004-10-15 21:23:12 +00005396 case 2: /* FIST m16 */
sewardj33dd31b2005-01-08 18:17:32 +00005397 DIP("fistp %s\n", dis_buf);
sewardj37158712004-10-15 21:23:12 +00005398 storeLE( mkexpr(addr),
sewardj6c299f32009-12-31 18:00:12 +00005399 binop(Iop_F64toI16S, get_roundingmode(), get_ST(0)) );
sewardj37158712004-10-15 21:23:12 +00005400 break;
5401
sewardj89cd0932004-09-08 18:23:25 +00005402 case 3: /* FISTP m16 */
sewardj33dd31b2005-01-08 18:17:32 +00005403 DIP("fistps %s\n", dis_buf);
sewardj8f3debf2004-09-08 23:42:23 +00005404 storeLE( mkexpr(addr),
sewardj6c299f32009-12-31 18:00:12 +00005405 binop(Iop_F64toI16S, get_roundingmode(), get_ST(0)) );
sewardj8f3debf2004-09-08 23:42:23 +00005406 fp_pop();
sewardj89cd0932004-09-08 18:23:25 +00005407 break;
5408
sewardj89cd0932004-09-08 18:23:25 +00005409 case 5: /* FILD m64 */
5410 DIP("fildll %s\n", dis_buf);
5411 fp_push();
sewardj6c299f32009-12-31 18:00:12 +00005412 put_ST(0, binop(Iop_I64StoF64,
sewardj4cb918d2004-12-03 19:43:31 +00005413 get_roundingmode(),
5414 loadLE(Ity_I64, mkexpr(addr))));
sewardj89cd0932004-09-08 18:23:25 +00005415 break;
sewardj89cd0932004-09-08 18:23:25 +00005416
sewardjcfded9a2004-09-09 11:44:16 +00005417 case 7: /* FISTP m64 */
sewardj33dd31b2005-01-08 18:17:32 +00005418 DIP("fistpll %s\n", dis_buf);
sewardjcfded9a2004-09-09 11:44:16 +00005419 storeLE( mkexpr(addr),
sewardj6c299f32009-12-31 18:00:12 +00005420 binop(Iop_F64toI64S, get_roundingmode(), get_ST(0)) );
sewardjcfded9a2004-09-09 11:44:16 +00005421 fp_pop();
5422 break;
5423
sewardj89cd0932004-09-08 18:23:25 +00005424 default:
florianb1737742015-08-03 16:03:13 +00005425 vex_printf("unhandled opc_aux = 0x%2x\n", (UInt)gregOfRM(modrm));
sewardj89cd0932004-09-08 18:23:25 +00005426 vex_printf("first_opcode == 0xDF\n");
5427 goto decode_fail;
5428 }
5429
5430 } else {
sewardjbdc7d212004-09-09 02:46:40 +00005431
5432 delta++;
sewardj5bd4d162004-11-10 13:02:48 +00005433 switch (modrm) {
sewardjbdc7d212004-09-09 02:46:40 +00005434
sewardj8fb88692005-07-29 11:57:00 +00005435 case 0xC0: /* FFREEP %st(0) */
5436 DIP("ffreep %%st(%d)\n", 0);
5437 put_ST_TAG ( 0, mkU8(0) );
5438 fp_pop();
5439 break;
5440
sewardjbdc7d212004-09-09 02:46:40 +00005441 case 0xE0: /* FNSTSW %ax */
5442 DIP("fnstsw %%ax\n");
sewardjd24931d2005-03-20 12:51:39 +00005443 /* Get the FPU status word value and dump it in %AX. */
sewardj1d2e77f2008-06-04 09:10:38 +00005444 if (0) {
5445 /* The obvious thing to do is simply dump the 16-bit
5446 status word value in %AX. However, due to a
5447 limitation in Memcheck's origin tracking
5448 machinery, this causes Memcheck not to track the
5449 origin of any undefinedness into %AH (only into
5450 %AL/%AX/%EAX), which means origins are lost in
5451 the sequence "fnstsw %ax; test $M,%ah; jcond .." */
5452 putIReg(2, R_EAX, get_FPU_sw());
5453 } else {
5454 /* So a somewhat lame kludge is to make it very
5455 clear to Memcheck that the value is written to
5456 both %AH and %AL. This generates marginally
5457 worse code, but I don't think it matters much. */
5458 IRTemp t16 = newTemp(Ity_I16);
5459 assign(t16, get_FPU_sw());
5460 putIReg( 1, R_AL, unop(Iop_16to8, mkexpr(t16)) );
5461 putIReg( 1, R_AH, unop(Iop_16HIto8, mkexpr(t16)) );
5462 }
sewardjbdc7d212004-09-09 02:46:40 +00005463 break;
5464
sewardj883b00b2004-09-11 09:30:24 +00005465 case 0xE8 ... 0xEF: /* FUCOMIP %st(0),%st(?) */
sewardj8308aad2004-09-12 11:09:54 +00005466 fp_do_ucomi_ST0_STi( (UInt)modrm - 0xE8, True );
sewardj883b00b2004-09-11 09:30:24 +00005467 break;
5468
sewardjfeeb8a82004-11-30 12:30:11 +00005469 case 0xF0 ... 0xF7: /* FCOMIP %st(0),%st(?) */
5470 /* not really right since COMIP != UCOMIP */
5471 fp_do_ucomi_ST0_STi( (UInt)modrm - 0xF0, True );
5472 break;
5473
sewardjbdc7d212004-09-09 02:46:40 +00005474 default:
5475 goto decode_fail;
sewardj5bd4d162004-11-10 13:02:48 +00005476 }
sewardj89cd0932004-09-08 18:23:25 +00005477 }
5478
sewardjd1725d12004-08-12 20:46:53 +00005479 }
5480
5481 else
5482 vpanic("dis_FPU(x86): invalid primary opcode");
5483
sewardj69d9d662004-10-14 21:58:52 +00005484 *decode_ok = True;
5485 return delta;
5486
sewardjd1725d12004-08-12 20:46:53 +00005487 decode_fail:
5488 *decode_ok = False;
5489 return delta;
5490}
5491
5492
sewardj464efa42004-11-19 22:17:29 +00005493/*------------------------------------------------------------*/
5494/*--- ---*/
5495/*--- MMX INSTRUCTIONS ---*/
5496/*--- ---*/
5497/*------------------------------------------------------------*/
sewardja06e5562004-07-14 13:18:05 +00005498
sewardj464efa42004-11-19 22:17:29 +00005499/* Effect of MMX insns on x87 FPU state (table 11-2 of
5500 IA32 arch manual, volume 3):
5501
5502 Read from, or write to MMX register (viz, any insn except EMMS):
5503 * All tags set to Valid (non-empty) -- FPTAGS[i] := nonzero
5504 * FP stack pointer set to zero
5505
5506 EMMS:
5507 * All tags set to Invalid (empty) -- FPTAGS[i] := zero
5508 * FP stack pointer set to zero
5509*/
5510
sewardj4cb918d2004-12-03 19:43:31 +00005511static void do_MMX_preamble ( void )
sewardj464efa42004-11-19 22:17:29 +00005512{
sewardjdd40fdf2006-12-24 02:20:24 +00005513 Int i;
5514 IRRegArray* descr = mkIRRegArray( OFFB_FPTAGS, Ity_I8, 8 );
5515 IRExpr* zero = mkU32(0);
5516 IRExpr* tag1 = mkU8(1);
sewardj464efa42004-11-19 22:17:29 +00005517 put_ftop(zero);
5518 for (i = 0; i < 8; i++)
floriand6f38b32012-05-31 15:46:18 +00005519 stmt( IRStmt_PutI( mkIRPutI(descr, zero, i, tag1) ) );
sewardj464efa42004-11-19 22:17:29 +00005520}
5521
sewardj4cb918d2004-12-03 19:43:31 +00005522static void do_EMMS_preamble ( void )
sewardj464efa42004-11-19 22:17:29 +00005523{
sewardjdd40fdf2006-12-24 02:20:24 +00005524 Int i;
5525 IRRegArray* descr = mkIRRegArray( OFFB_FPTAGS, Ity_I8, 8 );
5526 IRExpr* zero = mkU32(0);
5527 IRExpr* tag0 = mkU8(0);
sewardj464efa42004-11-19 22:17:29 +00005528 put_ftop(zero);
5529 for (i = 0; i < 8; i++)
floriand6f38b32012-05-31 15:46:18 +00005530 stmt( IRStmt_PutI( mkIRPutI(descr, zero, i, tag0) ) );
sewardj464efa42004-11-19 22:17:29 +00005531}
5532
5533
5534static IRExpr* getMMXReg ( UInt archreg )
5535{
5536 vassert(archreg < 8);
5537 return IRExpr_Get( OFFB_FPREGS + 8 * archreg, Ity_I64 );
5538}
5539
5540
5541static void putMMXReg ( UInt archreg, IRExpr* e )
5542{
5543 vassert(archreg < 8);
sewardjdd40fdf2006-12-24 02:20:24 +00005544 vassert(typeOfIRExpr(irsb->tyenv,e) == Ity_I64);
sewardj464efa42004-11-19 22:17:29 +00005545 stmt( IRStmt_Put( OFFB_FPREGS + 8 * archreg, e ) );
5546}
5547
5548
sewardj38a3f862005-01-13 15:06:51 +00005549/* Helper for non-shift MMX insns. Note this is incomplete in the
5550 sense that it does not first call do_MMX_preamble() -- that is the
5551 responsibility of its caller. */
5552
sewardj464efa42004-11-19 22:17:29 +00005553static
sewardj2d49b432005-02-01 00:37:06 +00005554UInt dis_MMXop_regmem_to_reg ( UChar sorb,
sewardj52d04912005-07-03 00:52:48 +00005555 Int delta,
sewardj2d49b432005-02-01 00:37:06 +00005556 UChar opc,
florian55085f82012-11-21 00:36:55 +00005557 const HChar* name,
sewardj2d49b432005-02-01 00:37:06 +00005558 Bool show_granularity )
sewardj464efa42004-11-19 22:17:29 +00005559{
sewardjc9a43662004-11-30 18:51:59 +00005560 HChar dis_buf[50];
sewardj63ba4092004-11-21 12:30:18 +00005561 UChar modrm = getIByte(delta);
5562 Bool isReg = epartIsReg(modrm);
5563 IRExpr* argL = NULL;
5564 IRExpr* argR = NULL;
sewardj38a3f862005-01-13 15:06:51 +00005565 IRExpr* argG = NULL;
5566 IRExpr* argE = NULL;
sewardj63ba4092004-11-21 12:30:18 +00005567 IRTemp res = newTemp(Ity_I64);
sewardj464efa42004-11-19 22:17:29 +00005568
sewardj38a3f862005-01-13 15:06:51 +00005569 Bool invG = False;
5570 IROp op = Iop_INVALID;
5571 void* hAddr = NULL;
sewardj38a3f862005-01-13 15:06:51 +00005572 Bool eLeft = False;
florian55085f82012-11-21 00:36:55 +00005573 const HChar* hName = NULL;
sewardj38a3f862005-01-13 15:06:51 +00005574
sewardj2b7a9202004-11-26 19:15:38 +00005575# define XXX(_name) do { hAddr = &_name; hName = #_name; } while (0)
sewardj464efa42004-11-19 22:17:29 +00005576
sewardj464efa42004-11-19 22:17:29 +00005577 switch (opc) {
sewardjb5452082004-12-04 20:33:02 +00005578 /* Original MMX ones */
sewardj38a3f862005-01-13 15:06:51 +00005579 case 0xFC: op = Iop_Add8x8; break;
5580 case 0xFD: op = Iop_Add16x4; break;
5581 case 0xFE: op = Iop_Add32x2; break;
sewardj464efa42004-11-19 22:17:29 +00005582
sewardj38a3f862005-01-13 15:06:51 +00005583 case 0xEC: op = Iop_QAdd8Sx8; break;
5584 case 0xED: op = Iop_QAdd16Sx4; break;
sewardj464efa42004-11-19 22:17:29 +00005585
sewardj38a3f862005-01-13 15:06:51 +00005586 case 0xDC: op = Iop_QAdd8Ux8; break;
5587 case 0xDD: op = Iop_QAdd16Ux4; break;
sewardj464efa42004-11-19 22:17:29 +00005588
sewardj38a3f862005-01-13 15:06:51 +00005589 case 0xF8: op = Iop_Sub8x8; break;
5590 case 0xF9: op = Iop_Sub16x4; break;
5591 case 0xFA: op = Iop_Sub32x2; break;
sewardj464efa42004-11-19 22:17:29 +00005592
sewardj38a3f862005-01-13 15:06:51 +00005593 case 0xE8: op = Iop_QSub8Sx8; break;
5594 case 0xE9: op = Iop_QSub16Sx4; break;
sewardj464efa42004-11-19 22:17:29 +00005595
sewardj38a3f862005-01-13 15:06:51 +00005596 case 0xD8: op = Iop_QSub8Ux8; break;
5597 case 0xD9: op = Iop_QSub16Ux4; break;
sewardj464efa42004-11-19 22:17:29 +00005598
sewardj38a3f862005-01-13 15:06:51 +00005599 case 0xE5: op = Iop_MulHi16Sx4; break;
5600 case 0xD5: op = Iop_Mul16x4; break;
5601 case 0xF5: XXX(x86g_calculate_mmx_pmaddwd); break;
sewardj4340dac2004-11-20 13:17:04 +00005602
sewardj38a3f862005-01-13 15:06:51 +00005603 case 0x74: op = Iop_CmpEQ8x8; break;
5604 case 0x75: op = Iop_CmpEQ16x4; break;
5605 case 0x76: op = Iop_CmpEQ32x2; break;
sewardj4340dac2004-11-20 13:17:04 +00005606
sewardj38a3f862005-01-13 15:06:51 +00005607 case 0x64: op = Iop_CmpGT8Sx8; break;
5608 case 0x65: op = Iop_CmpGT16Sx4; break;
5609 case 0x66: op = Iop_CmpGT32Sx2; break;
sewardj63ba4092004-11-21 12:30:18 +00005610
sewardj5f438dd2011-06-16 11:36:23 +00005611 case 0x6B: op = Iop_QNarrowBin32Sto16Sx4; eLeft = True; break;
5612 case 0x63: op = Iop_QNarrowBin16Sto8Sx8; eLeft = True; break;
5613 case 0x67: op = Iop_QNarrowBin16Sto8Ux8; eLeft = True; break;
sewardj63ba4092004-11-21 12:30:18 +00005614
sewardj38a3f862005-01-13 15:06:51 +00005615 case 0x68: op = Iop_InterleaveHI8x8; eLeft = True; break;
5616 case 0x69: op = Iop_InterleaveHI16x4; eLeft = True; break;
5617 case 0x6A: op = Iop_InterleaveHI32x2; eLeft = True; break;
sewardj63ba4092004-11-21 12:30:18 +00005618
sewardj38a3f862005-01-13 15:06:51 +00005619 case 0x60: op = Iop_InterleaveLO8x8; eLeft = True; break;
5620 case 0x61: op = Iop_InterleaveLO16x4; eLeft = True; break;
5621 case 0x62: op = Iop_InterleaveLO32x2; eLeft = True; break;
sewardj63ba4092004-11-21 12:30:18 +00005622
sewardj38a3f862005-01-13 15:06:51 +00005623 case 0xDB: op = Iop_And64; break;
5624 case 0xDF: op = Iop_And64; invG = True; break;
5625 case 0xEB: op = Iop_Or64; break;
5626 case 0xEF: /* Possibly do better here if argL and argR are the
5627 same reg */
5628 op = Iop_Xor64; break;
sewardj464efa42004-11-19 22:17:29 +00005629
sewardjb5452082004-12-04 20:33:02 +00005630 /* Introduced in SSE1 */
sewardj38a3f862005-01-13 15:06:51 +00005631 case 0xE0: op = Iop_Avg8Ux8; break;
5632 case 0xE3: op = Iop_Avg16Ux4; break;
5633 case 0xEE: op = Iop_Max16Sx4; break;
5634 case 0xDE: op = Iop_Max8Ux8; break;
5635 case 0xEA: op = Iop_Min16Sx4; break;
5636 case 0xDA: op = Iop_Min8Ux8; break;
5637 case 0xE4: op = Iop_MulHi16Ux4; break;
5638 case 0xF6: XXX(x86g_calculate_mmx_psadbw); break;
sewardjb5452082004-12-04 20:33:02 +00005639
sewardj164f9272004-12-09 00:39:32 +00005640 /* Introduced in SSE2 */
sewardj38a3f862005-01-13 15:06:51 +00005641 case 0xD4: op = Iop_Add64; break;
5642 case 0xFB: op = Iop_Sub64; break;
sewardj164f9272004-12-09 00:39:32 +00005643
sewardj464efa42004-11-19 22:17:29 +00005644 default:
florianb1737742015-08-03 16:03:13 +00005645 vex_printf("\n0x%x\n", opc);
sewardj464efa42004-11-19 22:17:29 +00005646 vpanic("dis_MMXop_regmem_to_reg");
5647 }
5648
5649# undef XXX
5650
sewardj38a3f862005-01-13 15:06:51 +00005651 argG = getMMXReg(gregOfRM(modrm));
5652 if (invG)
5653 argG = unop(Iop_Not64, argG);
sewardj63ba4092004-11-21 12:30:18 +00005654
sewardj464efa42004-11-19 22:17:29 +00005655 if (isReg) {
sewardj464efa42004-11-19 22:17:29 +00005656 delta++;
sewardj38a3f862005-01-13 15:06:51 +00005657 argE = getMMXReg(eregOfRM(modrm));
sewardj464efa42004-11-19 22:17:29 +00005658 } else {
5659 Int len;
5660 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
5661 delta += len;
sewardj38a3f862005-01-13 15:06:51 +00005662 argE = loadLE(Ity_I64, mkexpr(addr));
sewardj464efa42004-11-19 22:17:29 +00005663 }
5664
sewardj38a3f862005-01-13 15:06:51 +00005665 if (eLeft) {
5666 argL = argE;
5667 argR = argG;
5668 } else {
5669 argL = argG;
5670 argR = argE;
5671 }
5672
5673 if (op != Iop_INVALID) {
5674 vassert(hName == NULL);
5675 vassert(hAddr == NULL);
5676 assign(res, binop(op, argL, argR));
5677 } else {
5678 vassert(hName != NULL);
5679 vassert(hAddr != NULL);
5680 assign( res,
5681 mkIRExprCCall(
5682 Ity_I64,
5683 0/*regparms*/, hName, hAddr,
5684 mkIRExprVec_2( argL, argR )
5685 )
5686 );
sewardj63ba4092004-11-21 12:30:18 +00005687 }
5688
5689 putMMXReg( gregOfRM(modrm), mkexpr(res) );
5690
sewardj464efa42004-11-19 22:17:29 +00005691 DIP("%s%s %s, %s\n",
sewardj2d49b432005-02-01 00:37:06 +00005692 name, show_granularity ? nameMMXGran(opc & 3) : "",
sewardj464efa42004-11-19 22:17:29 +00005693 ( isReg ? nameMMXReg(eregOfRM(modrm)) : dis_buf ),
5694 nameMMXReg(gregOfRM(modrm)) );
5695
5696 return delta;
5697}
5698
5699
sewardj38a3f862005-01-13 15:06:51 +00005700/* Vector by scalar shift of G by the amount specified at the bottom
5701 of E. This is a straight copy of dis_SSE_shiftG_byE. */
5702
sewardj52d04912005-07-03 00:52:48 +00005703static UInt dis_MMX_shiftG_byE ( UChar sorb, Int delta,
florian55085f82012-11-21 00:36:55 +00005704 const HChar* opname, IROp op )
sewardj38a3f862005-01-13 15:06:51 +00005705{
5706 HChar dis_buf[50];
5707 Int alen, size;
5708 IRTemp addr;
5709 Bool shl, shr, sar;
5710 UChar rm = getIByte(delta);
5711 IRTemp g0 = newTemp(Ity_I64);
5712 IRTemp g1 = newTemp(Ity_I64);
5713 IRTemp amt = newTemp(Ity_I32);
5714 IRTemp amt8 = newTemp(Ity_I8);
5715
5716 if (epartIsReg(rm)) {
5717 assign( amt, unop(Iop_64to32, getMMXReg(eregOfRM(rm))) );
5718 DIP("%s %s,%s\n", opname,
5719 nameMMXReg(eregOfRM(rm)),
5720 nameMMXReg(gregOfRM(rm)) );
5721 delta++;
5722 } else {
5723 addr = disAMode ( &alen, sorb, delta, dis_buf );
5724 assign( amt, loadLE(Ity_I32, mkexpr(addr)) );
5725 DIP("%s %s,%s\n", opname,
5726 dis_buf,
5727 nameMMXReg(gregOfRM(rm)) );
5728 delta += alen;
5729 }
5730 assign( g0, getMMXReg(gregOfRM(rm)) );
5731 assign( amt8, unop(Iop_32to8, mkexpr(amt)) );
5732
5733 shl = shr = sar = False;
5734 size = 0;
5735 switch (op) {
5736 case Iop_ShlN16x4: shl = True; size = 32; break;
5737 case Iop_ShlN32x2: shl = True; size = 32; break;
5738 case Iop_Shl64: shl = True; size = 64; break;
5739 case Iop_ShrN16x4: shr = True; size = 16; break;
5740 case Iop_ShrN32x2: shr = True; size = 32; break;
5741 case Iop_Shr64: shr = True; size = 64; break;
5742 case Iop_SarN16x4: sar = True; size = 16; break;
5743 case Iop_SarN32x2: sar = True; size = 32; break;
5744 default: vassert(0);
5745 }
5746
5747 if (shl || shr) {
5748 assign(
5749 g1,
florian99dd03e2013-01-29 03:56:06 +00005750 IRExpr_ITE(
sewardj009230b2013-01-26 11:47:55 +00005751 binop(Iop_CmpLT32U,mkexpr(amt),mkU32(size)),
florian99dd03e2013-01-29 03:56:06 +00005752 binop(op, mkexpr(g0), mkexpr(amt8)),
5753 mkU64(0)
sewardj38a3f862005-01-13 15:06:51 +00005754 )
5755 );
5756 } else
5757 if (sar) {
5758 assign(
5759 g1,
florian99dd03e2013-01-29 03:56:06 +00005760 IRExpr_ITE(
sewardj009230b2013-01-26 11:47:55 +00005761 binop(Iop_CmpLT32U,mkexpr(amt),mkU32(size)),
florian99dd03e2013-01-29 03:56:06 +00005762 binop(op, mkexpr(g0), mkexpr(amt8)),
5763 binop(op, mkexpr(g0), mkU8(size-1))
sewardj38a3f862005-01-13 15:06:51 +00005764 )
5765 );
5766 } else {
sewardjba89f4c2005-04-07 17:31:27 +00005767 /*NOTREACHED*/
sewardj38a3f862005-01-13 15:06:51 +00005768 vassert(0);
5769 }
5770
5771 putMMXReg( gregOfRM(rm), mkexpr(g1) );
5772 return delta;
5773}
5774
5775
5776/* Vector by scalar shift of E by an immediate byte. This is a
5777 straight copy of dis_SSE_shiftE_imm. */
5778
5779static
florian55085f82012-11-21 00:36:55 +00005780UInt dis_MMX_shiftE_imm ( Int delta, const HChar* opname, IROp op )
sewardj38a3f862005-01-13 15:06:51 +00005781{
5782 Bool shl, shr, sar;
5783 UChar rm = getIByte(delta);
5784 IRTemp e0 = newTemp(Ity_I64);
5785 IRTemp e1 = newTemp(Ity_I64);
5786 UChar amt, size;
5787 vassert(epartIsReg(rm));
5788 vassert(gregOfRM(rm) == 2
5789 || gregOfRM(rm) == 4 || gregOfRM(rm) == 6);
sewardj2d49b432005-02-01 00:37:06 +00005790 amt = getIByte(delta+1);
sewardj38a3f862005-01-13 15:06:51 +00005791 delta += 2;
5792 DIP("%s $%d,%s\n", opname,
5793 (Int)amt,
5794 nameMMXReg(eregOfRM(rm)) );
5795
5796 assign( e0, getMMXReg(eregOfRM(rm)) );
5797
5798 shl = shr = sar = False;
5799 size = 0;
5800 switch (op) {
5801 case Iop_ShlN16x4: shl = True; size = 16; break;
5802 case Iop_ShlN32x2: shl = True; size = 32; break;
5803 case Iop_Shl64: shl = True; size = 64; break;
5804 case Iop_SarN16x4: sar = True; size = 16; break;
5805 case Iop_SarN32x2: sar = True; size = 32; break;
5806 case Iop_ShrN16x4: shr = True; size = 16; break;
5807 case Iop_ShrN32x2: shr = True; size = 32; break;
5808 case Iop_Shr64: shr = True; size = 64; break;
5809 default: vassert(0);
5810 }
5811
5812 if (shl || shr) {
sewardjba89f4c2005-04-07 17:31:27 +00005813 assign( e1, amt >= size
5814 ? mkU64(0)
5815 : binop(op, mkexpr(e0), mkU8(amt))
5816 );
sewardj38a3f862005-01-13 15:06:51 +00005817 } else
5818 if (sar) {
sewardjba89f4c2005-04-07 17:31:27 +00005819 assign( e1, amt >= size
5820 ? binop(op, mkexpr(e0), mkU8(size-1))
5821 : binop(op, mkexpr(e0), mkU8(amt))
5822 );
sewardj38a3f862005-01-13 15:06:51 +00005823 } else {
sewardjba89f4c2005-04-07 17:31:27 +00005824 /*NOTREACHED*/
sewardj38a3f862005-01-13 15:06:51 +00005825 vassert(0);
5826 }
5827
5828 putMMXReg( eregOfRM(rm), mkexpr(e1) );
5829 return delta;
5830}
5831
5832
5833/* Completely handle all MMX instructions except emms. */
sewardj464efa42004-11-19 22:17:29 +00005834
5835static
sewardj52d04912005-07-03 00:52:48 +00005836UInt dis_MMX ( Bool* decode_ok, UChar sorb, Int sz, Int delta )
sewardj464efa42004-11-19 22:17:29 +00005837{
5838 Int len;
5839 UChar modrm;
sewardjc9a43662004-11-30 18:51:59 +00005840 HChar dis_buf[50];
sewardj464efa42004-11-19 22:17:29 +00005841 UChar opc = getIByte(delta);
5842 delta++;
5843
sewardj4cb918d2004-12-03 19:43:31 +00005844 /* dis_MMX handles all insns except emms. */
5845 do_MMX_preamble();
sewardj464efa42004-11-19 22:17:29 +00005846
5847 switch (opc) {
5848
sewardj2b7a9202004-11-26 19:15:38 +00005849 case 0x6E:
5850 /* MOVD (src)ireg-or-mem (E), (dst)mmxreg (G)*/
sewardj9df271d2004-12-31 22:37:42 +00005851 if (sz != 4)
5852 goto mmx_decode_failure;
sewardj2b7a9202004-11-26 19:15:38 +00005853 modrm = getIByte(delta);
5854 if (epartIsReg(modrm)) {
5855 delta++;
5856 putMMXReg(
5857 gregOfRM(modrm),
5858 binop( Iop_32HLto64,
5859 mkU32(0),
5860 getIReg(4, eregOfRM(modrm)) ) );
5861 DIP("movd %s, %s\n",
5862 nameIReg(4,eregOfRM(modrm)), nameMMXReg(gregOfRM(modrm)));
5863 } else {
5864 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
5865 delta += len;
5866 putMMXReg(
5867 gregOfRM(modrm),
5868 binop( Iop_32HLto64,
5869 mkU32(0),
5870 loadLE(Ity_I32, mkexpr(addr)) ) );
5871 DIP("movd %s, %s\n", dis_buf, nameMMXReg(gregOfRM(modrm)));
5872 }
5873 break;
5874
5875 case 0x7E: /* MOVD (src)mmxreg (G), (dst)ireg-or-mem (E) */
sewardj9df271d2004-12-31 22:37:42 +00005876 if (sz != 4)
5877 goto mmx_decode_failure;
sewardj2b7a9202004-11-26 19:15:38 +00005878 modrm = getIByte(delta);
5879 if (epartIsReg(modrm)) {
5880 delta++;
5881 putIReg( 4, eregOfRM(modrm),
5882 unop(Iop_64to32, getMMXReg(gregOfRM(modrm)) ) );
5883 DIP("movd %s, %s\n",
5884 nameMMXReg(gregOfRM(modrm)), nameIReg(4,eregOfRM(modrm)));
5885 } else {
5886 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
5887 delta += len;
5888 storeLE( mkexpr(addr),
5889 unop(Iop_64to32, getMMXReg(gregOfRM(modrm)) ) );
5890 DIP("movd %s, %s\n", nameMMXReg(gregOfRM(modrm)), dis_buf);
5891 }
5892 break;
5893
sewardj464efa42004-11-19 22:17:29 +00005894 case 0x6F:
5895 /* MOVQ (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00005896 if (sz != 4)
5897 goto mmx_decode_failure;
sewardj464efa42004-11-19 22:17:29 +00005898 modrm = getIByte(delta);
5899 if (epartIsReg(modrm)) {
5900 delta++;
5901 putMMXReg( gregOfRM(modrm), getMMXReg(eregOfRM(modrm)) );
5902 DIP("movq %s, %s\n",
5903 nameMMXReg(eregOfRM(modrm)), nameMMXReg(gregOfRM(modrm)));
5904 } else {
5905 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
5906 delta += len;
5907 putMMXReg( gregOfRM(modrm), loadLE(Ity_I64, mkexpr(addr)) );
5908 DIP("movq %s, %s\n",
5909 dis_buf, nameMMXReg(gregOfRM(modrm)));
5910 }
5911 break;
5912
5913 case 0x7F:
5914 /* MOVQ (src)mmxreg, (dst)mmxreg-or-mem */
sewardj9df271d2004-12-31 22:37:42 +00005915 if (sz != 4)
5916 goto mmx_decode_failure;
sewardj464efa42004-11-19 22:17:29 +00005917 modrm = getIByte(delta);
5918 if (epartIsReg(modrm)) {
sewardj9ca26402005-10-03 02:44:01 +00005919 delta++;
5920 putMMXReg( eregOfRM(modrm), getMMXReg(gregOfRM(modrm)) );
5921 DIP("movq %s, %s\n",
5922 nameMMXReg(gregOfRM(modrm)), nameMMXReg(eregOfRM(modrm)));
sewardj464efa42004-11-19 22:17:29 +00005923 } else {
5924 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
5925 delta += len;
sewardj893aada2004-11-29 19:57:54 +00005926 storeLE( mkexpr(addr), getMMXReg(gregOfRM(modrm)) );
sewardj464efa42004-11-19 22:17:29 +00005927 DIP("mov(nt)q %s, %s\n",
5928 nameMMXReg(gregOfRM(modrm)), dis_buf);
5929 }
5930 break;
5931
sewardj4340dac2004-11-20 13:17:04 +00005932 case 0xFC:
5933 case 0xFD:
5934 case 0xFE: /* PADDgg (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00005935 if (sz != 4)
5936 goto mmx_decode_failure;
sewardj464efa42004-11-19 22:17:29 +00005937 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "padd", True );
5938 break;
5939
sewardj4340dac2004-11-20 13:17:04 +00005940 case 0xEC:
5941 case 0xED: /* PADDSgg (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00005942 if (sz != 4)
5943 goto mmx_decode_failure;
sewardj464efa42004-11-19 22:17:29 +00005944 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "padds", True );
5945 break;
5946
sewardj4340dac2004-11-20 13:17:04 +00005947 case 0xDC:
5948 case 0xDD: /* PADDUSgg (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00005949 if (sz != 4)
5950 goto mmx_decode_failure;
sewardj464efa42004-11-19 22:17:29 +00005951 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "paddus", True );
5952 break;
5953
sewardj4340dac2004-11-20 13:17:04 +00005954 case 0xF8:
5955 case 0xF9:
5956 case 0xFA: /* PSUBgg (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00005957 if (sz != 4)
5958 goto mmx_decode_failure;
sewardj464efa42004-11-19 22:17:29 +00005959 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "psub", True );
5960 break;
5961
sewardj4340dac2004-11-20 13:17:04 +00005962 case 0xE8:
5963 case 0xE9: /* PSUBSgg (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00005964 if (sz != 4)
5965 goto mmx_decode_failure;
sewardj464efa42004-11-19 22:17:29 +00005966 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "psubs", True );
5967 break;
5968
sewardj4340dac2004-11-20 13:17:04 +00005969 case 0xD8:
5970 case 0xD9: /* PSUBUSgg (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00005971 if (sz != 4)
5972 goto mmx_decode_failure;
sewardj464efa42004-11-19 22:17:29 +00005973 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "psubus", True );
5974 break;
5975
5976 case 0xE5: /* PMULHW (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00005977 if (sz != 4)
5978 goto mmx_decode_failure;
sewardj464efa42004-11-19 22:17:29 +00005979 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "pmulhw", False );
5980 break;
5981
5982 case 0xD5: /* PMULLW (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00005983 if (sz != 4)
5984 goto mmx_decode_failure;
sewardj464efa42004-11-19 22:17:29 +00005985 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "pmullw", False );
5986 break;
5987
sewardj4340dac2004-11-20 13:17:04 +00005988 case 0xF5: /* PMADDWD (src)mmxreg-or-mem, (dst)mmxreg */
5989 vassert(sz == 4);
5990 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "pmaddwd", False );
5991 break;
5992
5993 case 0x74:
5994 case 0x75:
5995 case 0x76: /* PCMPEQgg (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00005996 if (sz != 4)
5997 goto mmx_decode_failure;
sewardj4340dac2004-11-20 13:17:04 +00005998 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "pcmpeq", True );
5999 break;
6000
6001 case 0x64:
6002 case 0x65:
6003 case 0x66: /* PCMPGTgg (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00006004 if (sz != 4)
6005 goto mmx_decode_failure;
sewardj4340dac2004-11-20 13:17:04 +00006006 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "pcmpgt", True );
6007 break;
6008
sewardj63ba4092004-11-21 12:30:18 +00006009 case 0x6B: /* PACKSSDW (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00006010 if (sz != 4)
6011 goto mmx_decode_failure;
sewardj63ba4092004-11-21 12:30:18 +00006012 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "packssdw", False );
6013 break;
6014
6015 case 0x63: /* PACKSSWB (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00006016 if (sz != 4)
6017 goto mmx_decode_failure;
sewardj63ba4092004-11-21 12:30:18 +00006018 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "packsswb", False );
6019 break;
6020
6021 case 0x67: /* PACKUSWB (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00006022 if (sz != 4)
6023 goto mmx_decode_failure;
sewardj63ba4092004-11-21 12:30:18 +00006024 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "packuswb", False );
6025 break;
6026
6027 case 0x68:
6028 case 0x69:
6029 case 0x6A: /* PUNPCKHgg (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00006030 if (sz != 4)
6031 goto mmx_decode_failure;
sewardj63ba4092004-11-21 12:30:18 +00006032 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "punpckh", True );
6033 break;
6034
6035 case 0x60:
6036 case 0x61:
6037 case 0x62: /* PUNPCKLgg (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00006038 if (sz != 4)
6039 goto mmx_decode_failure;
sewardj63ba4092004-11-21 12:30:18 +00006040 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "punpckl", True );
6041 break;
6042
6043 case 0xDB: /* PAND (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00006044 if (sz != 4)
6045 goto mmx_decode_failure;
sewardj63ba4092004-11-21 12:30:18 +00006046 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "pand", False );
6047 break;
6048
6049 case 0xDF: /* PANDN (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00006050 if (sz != 4)
6051 goto mmx_decode_failure;
sewardj63ba4092004-11-21 12:30:18 +00006052 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "pandn", False );
6053 break;
6054
6055 case 0xEB: /* POR (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00006056 if (sz != 4)
6057 goto mmx_decode_failure;
sewardj63ba4092004-11-21 12:30:18 +00006058 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "por", False );
6059 break;
6060
6061 case 0xEF: /* PXOR (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00006062 if (sz != 4)
6063 goto mmx_decode_failure;
sewardj63ba4092004-11-21 12:30:18 +00006064 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "pxor", False );
sewardj38a3f862005-01-13 15:06:51 +00006065 break;
sewardj63ba4092004-11-21 12:30:18 +00006066
sewardj38a3f862005-01-13 15:06:51 +00006067# define SHIFT_BY_REG(_name,_op) \
6068 delta = dis_MMX_shiftG_byE(sorb, delta, _name, _op); \
6069 break;
sewardj8d14a592004-11-21 17:04:50 +00006070
sewardj38a3f862005-01-13 15:06:51 +00006071 /* PSLLgg (src)mmxreg-or-mem, (dst)mmxreg */
6072 case 0xF1: SHIFT_BY_REG("psllw", Iop_ShlN16x4);
6073 case 0xF2: SHIFT_BY_REG("pslld", Iop_ShlN32x2);
6074 case 0xF3: SHIFT_BY_REG("psllq", Iop_Shl64);
sewardj8d14a592004-11-21 17:04:50 +00006075
sewardj38a3f862005-01-13 15:06:51 +00006076 /* PSRLgg (src)mmxreg-or-mem, (dst)mmxreg */
6077 case 0xD1: SHIFT_BY_REG("psrlw", Iop_ShrN16x4);
6078 case 0xD2: SHIFT_BY_REG("psrld", Iop_ShrN32x2);
6079 case 0xD3: SHIFT_BY_REG("psrlq", Iop_Shr64);
6080
6081 /* PSRAgg (src)mmxreg-or-mem, (dst)mmxreg */
6082 case 0xE1: SHIFT_BY_REG("psraw", Iop_SarN16x4);
6083 case 0xE2: SHIFT_BY_REG("psrad", Iop_SarN32x2);
6084
6085# undef SHIFT_BY_REG
sewardj8d14a592004-11-21 17:04:50 +00006086
sewardj2b7a9202004-11-26 19:15:38 +00006087 case 0x71:
6088 case 0x72:
6089 case 0x73: {
6090 /* (sz==4): PSLLgg/PSRAgg/PSRLgg mmxreg by imm8 */
sewardja8415ff2005-01-21 20:55:36 +00006091 UChar byte2, subopc;
sewardj38a3f862005-01-13 15:06:51 +00006092 if (sz != 4)
6093 goto mmx_decode_failure;
sewardj38a3f862005-01-13 15:06:51 +00006094 byte2 = getIByte(delta); /* amode / sub-opcode */
sewardj9b45b482005-02-07 01:42:18 +00006095 subopc = toUChar( (byte2 >> 3) & 7 );
sewardj2b7a9202004-11-26 19:15:38 +00006096
sewardj38a3f862005-01-13 15:06:51 +00006097# define SHIFT_BY_IMM(_name,_op) \
6098 do { delta = dis_MMX_shiftE_imm(delta,_name,_op); \
6099 } while (0)
sewardj2b7a9202004-11-26 19:15:38 +00006100
sewardj2b7a9202004-11-26 19:15:38 +00006101 if (subopc == 2 /*SRL*/ && opc == 0x71)
sewardj38a3f862005-01-13 15:06:51 +00006102 SHIFT_BY_IMM("psrlw", Iop_ShrN16x4);
sewardj2b7a9202004-11-26 19:15:38 +00006103 else if (subopc == 2 /*SRL*/ && opc == 0x72)
sewardj38a3f862005-01-13 15:06:51 +00006104 SHIFT_BY_IMM("psrld", Iop_ShrN32x2);
sewardj2b7a9202004-11-26 19:15:38 +00006105 else if (subopc == 2 /*SRL*/ && opc == 0x73)
sewardj38a3f862005-01-13 15:06:51 +00006106 SHIFT_BY_IMM("psrlq", Iop_Shr64);
sewardj2b7a9202004-11-26 19:15:38 +00006107
6108 else if (subopc == 4 /*SAR*/ && opc == 0x71)
sewardj38a3f862005-01-13 15:06:51 +00006109 SHIFT_BY_IMM("psraw", Iop_SarN16x4);
sewardj2b7a9202004-11-26 19:15:38 +00006110 else if (subopc == 4 /*SAR*/ && opc == 0x72)
sewardj38a3f862005-01-13 15:06:51 +00006111 SHIFT_BY_IMM("psrad", Iop_SarN32x2);
sewardj2b7a9202004-11-26 19:15:38 +00006112
6113 else if (subopc == 6 /*SHL*/ && opc == 0x71)
sewardj38a3f862005-01-13 15:06:51 +00006114 SHIFT_BY_IMM("psllw", Iop_ShlN16x4);
sewardj2b7a9202004-11-26 19:15:38 +00006115 else if (subopc == 6 /*SHL*/ && opc == 0x72)
sewardj38a3f862005-01-13 15:06:51 +00006116 SHIFT_BY_IMM("pslld", Iop_ShlN32x2);
sewardj2b7a9202004-11-26 19:15:38 +00006117 else if (subopc == 6 /*SHL*/ && opc == 0x73)
sewardj38a3f862005-01-13 15:06:51 +00006118 SHIFT_BY_IMM("psllq", Iop_Shl64);
sewardj2b7a9202004-11-26 19:15:38 +00006119
6120 else goto mmx_decode_failure;
6121
sewardj38a3f862005-01-13 15:06:51 +00006122# undef SHIFT_BY_IMM
sewardj2b7a9202004-11-26 19:15:38 +00006123 break;
6124 }
6125
sewardjd71ba832006-12-27 01:15:29 +00006126 case 0xF7: {
6127 IRTemp addr = newTemp(Ity_I32);
6128 IRTemp regD = newTemp(Ity_I64);
6129 IRTemp regM = newTemp(Ity_I64);
6130 IRTemp mask = newTemp(Ity_I64);
6131 IRTemp olddata = newTemp(Ity_I64);
6132 IRTemp newdata = newTemp(Ity_I64);
6133
6134 modrm = getIByte(delta);
6135 if (sz != 4 || (!epartIsReg(modrm)))
6136 goto mmx_decode_failure;
6137 delta++;
6138
6139 assign( addr, handleSegOverride( sorb, getIReg(4, R_EDI) ));
6140 assign( regM, getMMXReg( eregOfRM(modrm) ));
6141 assign( regD, getMMXReg( gregOfRM(modrm) ));
6142 assign( mask, binop(Iop_SarN8x8, mkexpr(regM), mkU8(7)) );
6143 assign( olddata, loadLE( Ity_I64, mkexpr(addr) ));
6144 assign( newdata,
6145 binop(Iop_Or64,
6146 binop(Iop_And64,
6147 mkexpr(regD),
6148 mkexpr(mask) ),
6149 binop(Iop_And64,
6150 mkexpr(olddata),
6151 unop(Iop_Not64, mkexpr(mask)))) );
6152 storeLE( mkexpr(addr), mkexpr(newdata) );
6153 DIP("maskmovq %s,%s\n", nameMMXReg( eregOfRM(modrm) ),
6154 nameMMXReg( gregOfRM(modrm) ) );
6155 break;
6156 }
6157
sewardj2b7a9202004-11-26 19:15:38 +00006158 /* --- MMX decode failure --- */
sewardj464efa42004-11-19 22:17:29 +00006159 default:
sewardj2b7a9202004-11-26 19:15:38 +00006160 mmx_decode_failure:
sewardj464efa42004-11-19 22:17:29 +00006161 *decode_ok = False;
6162 return delta; /* ignored */
6163
6164 }
6165
6166 *decode_ok = True;
6167 return delta;
6168}
6169
6170
6171/*------------------------------------------------------------*/
6172/*--- More misc arithmetic and other obscure insns. ---*/
6173/*------------------------------------------------------------*/
sewardja06e5562004-07-14 13:18:05 +00006174
6175/* Double length left and right shifts. Apparently only required in
6176 v-size (no b- variant). */
6177static
6178UInt dis_SHLRD_Gv_Ev ( UChar sorb,
sewardj52d04912005-07-03 00:52:48 +00006179 Int delta, UChar modrm,
sewardja06e5562004-07-14 13:18:05 +00006180 Int sz,
6181 IRExpr* shift_amt,
6182 Bool amt_is_literal,
florian55085f82012-11-21 00:36:55 +00006183 const HChar* shift_amt_txt,
sewardja06e5562004-07-14 13:18:05 +00006184 Bool left_shift )
6185{
6186 /* shift_amt :: Ity_I8 is the amount to shift. shift_amt_txt is used
6187 for printing it. And eip on entry points at the modrm byte. */
6188 Int len;
sewardjc9a43662004-11-30 18:51:59 +00006189 HChar dis_buf[50];
sewardja06e5562004-07-14 13:18:05 +00006190
sewardj6d2638e2004-07-15 09:38:27 +00006191 IRType ty = szToITy(sz);
6192 IRTemp gsrc = newTemp(ty);
6193 IRTemp esrc = newTemp(ty);
sewardj92d168d2004-11-15 14:22:12 +00006194 IRTemp addr = IRTemp_INVALID;
sewardj6d2638e2004-07-15 09:38:27 +00006195 IRTemp tmpSH = newTemp(Ity_I8);
sewardj92d168d2004-11-15 14:22:12 +00006196 IRTemp tmpL = IRTemp_INVALID;
6197 IRTemp tmpRes = IRTemp_INVALID;
6198 IRTemp tmpSubSh = IRTemp_INVALID;
sewardja06e5562004-07-14 13:18:05 +00006199 IROp mkpair;
6200 IROp getres;
6201 IROp shift;
sewardja06e5562004-07-14 13:18:05 +00006202 IRExpr* mask = NULL;
6203
6204 vassert(sz == 2 || sz == 4);
6205
6206 /* The E-part is the destination; this is shifted. The G-part
6207 supplies bits to be shifted into the E-part, but is not
6208 changed.
6209
6210 If shifting left, form a double-length word with E at the top
6211 and G at the bottom, and shift this left. The result is then in
6212 the high part.
6213
6214 If shifting right, form a double-length word with G at the top
6215 and E at the bottom, and shift this right. The result is then
6216 at the bottom. */
6217
6218 /* Fetch the operands. */
6219
6220 assign( gsrc, getIReg(sz, gregOfRM(modrm)) );
6221
6222 if (epartIsReg(modrm)) {
6223 delta++;
6224 assign( esrc, getIReg(sz, eregOfRM(modrm)) );
sewardj68511542004-07-28 00:15:44 +00006225 DIP("sh%cd%c %s, %s, %s\n",
sewardja06e5562004-07-14 13:18:05 +00006226 ( left_shift ? 'l' : 'r' ), nameISize(sz),
sewardj68511542004-07-28 00:15:44 +00006227 shift_amt_txt,
sewardja06e5562004-07-14 13:18:05 +00006228 nameIReg(sz, gregOfRM(modrm)), nameIReg(sz, eregOfRM(modrm)));
6229 } else {
6230 addr = disAMode ( &len, sorb, delta, dis_buf );
6231 delta += len;
6232 assign( esrc, loadLE(ty, mkexpr(addr)) );
sewardj68511542004-07-28 00:15:44 +00006233 DIP("sh%cd%c %s, %s, %s\n",
6234 ( left_shift ? 'l' : 'r' ), nameISize(sz),
6235 shift_amt_txt,
6236 nameIReg(sz, gregOfRM(modrm)), dis_buf);
sewardja06e5562004-07-14 13:18:05 +00006237 }
6238
6239 /* Round up the relevant primops. */
6240
6241 if (sz == 4) {
6242 tmpL = newTemp(Ity_I64);
6243 tmpRes = newTemp(Ity_I32);
6244 tmpSubSh = newTemp(Ity_I32);
sewardje539a402004-07-14 18:24:17 +00006245 mkpair = Iop_32HLto64;
sewardj8c7f1ab2004-07-29 20:31:09 +00006246 getres = left_shift ? Iop_64HIto32 : Iop_64to32;
sewardje539a402004-07-14 18:24:17 +00006247 shift = left_shift ? Iop_Shl64 : Iop_Shr64;
6248 mask = mkU8(31);
sewardja06e5562004-07-14 13:18:05 +00006249 } else {
6250 /* sz == 2 */
sewardj8c7f1ab2004-07-29 20:31:09 +00006251 tmpL = newTemp(Ity_I32);
6252 tmpRes = newTemp(Ity_I16);
6253 tmpSubSh = newTemp(Ity_I16);
6254 mkpair = Iop_16HLto32;
6255 getres = left_shift ? Iop_32HIto16 : Iop_32to16;
6256 shift = left_shift ? Iop_Shl32 : Iop_Shr32;
6257 mask = mkU8(15);
sewardja06e5562004-07-14 13:18:05 +00006258 }
6259
6260 /* Do the shift, calculate the subshift value, and set
6261 the flag thunk. */
6262
sewardj8c7f1ab2004-07-29 20:31:09 +00006263 assign( tmpSH, binop(Iop_And8, shift_amt, mask) );
6264
sewardja06e5562004-07-14 13:18:05 +00006265 if (left_shift)
6266 assign( tmpL, binop(mkpair, mkexpr(esrc), mkexpr(gsrc)) );
6267 else
6268 assign( tmpL, binop(mkpair, mkexpr(gsrc), mkexpr(esrc)) );
6269
6270 assign( tmpRes, unop(getres, binop(shift, mkexpr(tmpL), mkexpr(tmpSH)) ) );
6271 assign( tmpSubSh,
6272 unop(getres,
6273 binop(shift,
6274 mkexpr(tmpL),
6275 binop(Iop_And8,
6276 binop(Iop_Sub8, mkexpr(tmpSH), mkU8(1) ),
6277 mask))) );
sewardja06e5562004-07-14 13:18:05 +00006278
sewardj2a2ba8b2004-11-08 13:14:06 +00006279 setFlags_DEP1_DEP2_shift ( left_shift ? Iop_Shl32 : Iop_Sar32,
6280 tmpRes, tmpSubSh, ty, tmpSH );
sewardja06e5562004-07-14 13:18:05 +00006281
6282 /* Put result back. */
6283
6284 if (epartIsReg(modrm)) {
6285 putIReg(sz, eregOfRM(modrm), mkexpr(tmpRes));
6286 } else {
6287 storeLE( mkexpr(addr), mkexpr(tmpRes) );
6288 }
6289
6290 if (amt_is_literal) delta++;
6291 return delta;
6292}
6293
6294
sewardj1c6f9912004-09-07 10:15:24 +00006295/* Handle BT/BTS/BTR/BTC Gv, Ev. Apparently b-size is not
6296 required. */
6297
6298typedef enum { BtOpNone, BtOpSet, BtOpReset, BtOpComp } BtOp;
6299
florian55085f82012-11-21 00:36:55 +00006300static const HChar* nameBtOp ( BtOp op )
sewardj1c6f9912004-09-07 10:15:24 +00006301{
6302 switch (op) {
6303 case BtOpNone: return "";
6304 case BtOpSet: return "s";
6305 case BtOpReset: return "r";
6306 case BtOpComp: return "c";
6307 default: vpanic("nameBtOp(x86)");
6308 }
6309}
6310
6311
6312static
floriancacba8e2014-12-15 18:58:07 +00006313UInt dis_bt_G_E ( const VexAbiInfo* vbi,
sewardj02834302010-07-29 18:10:51 +00006314 UChar sorb, Bool locked, Int sz, Int delta, BtOp op )
sewardj1c6f9912004-09-07 10:15:24 +00006315{
sewardjc9a43662004-11-30 18:51:59 +00006316 HChar dis_buf[50];
sewardj1c6f9912004-09-07 10:15:24 +00006317 UChar modrm;
6318 Int len;
6319 IRTemp t_fetched, t_bitno0, t_bitno1, t_bitno2, t_addr0,
sewardje9d8a262009-07-01 08:06:34 +00006320 t_addr1, t_esp, t_mask, t_new;
sewardj1c6f9912004-09-07 10:15:24 +00006321
6322 vassert(sz == 2 || sz == 4);
6323
6324 t_fetched = t_bitno0 = t_bitno1 = t_bitno2
sewardje9d8a262009-07-01 08:06:34 +00006325 = t_addr0 = t_addr1 = t_esp
6326 = t_mask = t_new = IRTemp_INVALID;
sewardj1c6f9912004-09-07 10:15:24 +00006327
6328 t_fetched = newTemp(Ity_I8);
sewardje9d8a262009-07-01 08:06:34 +00006329 t_new = newTemp(Ity_I8);
sewardj1c6f9912004-09-07 10:15:24 +00006330 t_bitno0 = newTemp(Ity_I32);
6331 t_bitno1 = newTemp(Ity_I32);
6332 t_bitno2 = newTemp(Ity_I8);
6333 t_addr1 = newTemp(Ity_I32);
6334 modrm = getIByte(delta);
6335
sewardj9ed16802005-08-24 10:46:19 +00006336 assign( t_bitno0, widenSto32(getIReg(sz, gregOfRM(modrm))) );
sewardj1c6f9912004-09-07 10:15:24 +00006337
6338 if (epartIsReg(modrm)) {
sewardj1c6f9912004-09-07 10:15:24 +00006339 delta++;
6340 /* Get it onto the client's stack. */
6341 t_esp = newTemp(Ity_I32);
6342 t_addr0 = newTemp(Ity_I32);
6343
sewardj02834302010-07-29 18:10:51 +00006344 /* For the choice of the value 128, see comment in dis_bt_G_E in
6345 guest_amd64_toIR.c. We point out here only that 128 is
6346 fast-cased in Memcheck and is > 0, so seems like a good
6347 choice. */
6348 vassert(vbi->guest_stack_redzone_size == 0);
6349 assign( t_esp, binop(Iop_Sub32, getIReg(4, R_ESP), mkU32(128)) );
sewardj1c6f9912004-09-07 10:15:24 +00006350 putIReg(4, R_ESP, mkexpr(t_esp));
6351
6352 storeLE( mkexpr(t_esp), getIReg(sz, eregOfRM(modrm)) );
6353
6354 /* Make t_addr0 point at it. */
6355 assign( t_addr0, mkexpr(t_esp) );
6356
6357 /* Mask out upper bits of the shift amount, since we're doing a
6358 reg. */
6359 assign( t_bitno1, binop(Iop_And32,
6360 mkexpr(t_bitno0),
6361 mkU32(sz == 4 ? 31 : 15)) );
6362
6363 } else {
6364 t_addr0 = disAMode ( &len, sorb, delta, dis_buf );
6365 delta += len;
6366 assign( t_bitno1, mkexpr(t_bitno0) );
6367 }
6368
6369 /* At this point: t_addr0 is the address being operated on. If it
6370 was a reg, we will have pushed it onto the client's stack.
6371 t_bitno1 is the bit number, suitably masked in the case of a
6372 reg. */
6373
6374 /* Now the main sequence. */
6375 assign( t_addr1,
6376 binop(Iop_Add32,
6377 mkexpr(t_addr0),
6378 binop(Iop_Sar32, mkexpr(t_bitno1), mkU8(3))) );
6379
6380 /* t_addr1 now holds effective address */
6381
6382 assign( t_bitno2,
6383 unop(Iop_32to8,
6384 binop(Iop_And32, mkexpr(t_bitno1), mkU32(7))) );
6385
6386 /* t_bitno2 contains offset of bit within byte */
6387
6388 if (op != BtOpNone) {
6389 t_mask = newTemp(Ity_I8);
6390 assign( t_mask, binop(Iop_Shl8, mkU8(1), mkexpr(t_bitno2)) );
6391 }
sewardj4963a422004-10-14 23:34:03 +00006392
sewardj1c6f9912004-09-07 10:15:24 +00006393 /* t_mask is now a suitable byte mask */
6394
6395 assign( t_fetched, loadLE(Ity_I8, mkexpr(t_addr1)) );
6396
6397 if (op != BtOpNone) {
6398 switch (op) {
sewardje9d8a262009-07-01 08:06:34 +00006399 case BtOpSet:
6400 assign( t_new,
6401 binop(Iop_Or8, mkexpr(t_fetched), mkexpr(t_mask)) );
sewardj1c6f9912004-09-07 10:15:24 +00006402 break;
sewardje9d8a262009-07-01 08:06:34 +00006403 case BtOpComp:
6404 assign( t_new,
6405 binop(Iop_Xor8, mkexpr(t_fetched), mkexpr(t_mask)) );
sewardj1c6f9912004-09-07 10:15:24 +00006406 break;
sewardje9d8a262009-07-01 08:06:34 +00006407 case BtOpReset:
6408 assign( t_new,
6409 binop(Iop_And8, mkexpr(t_fetched),
6410 unop(Iop_Not8, mkexpr(t_mask))) );
sewardj1c6f9912004-09-07 10:15:24 +00006411 break;
6412 default:
6413 vpanic("dis_bt_G_E(x86)");
6414 }
sewardje9d8a262009-07-01 08:06:34 +00006415 if (locked && !epartIsReg(modrm)) {
6416 casLE( mkexpr(t_addr1), mkexpr(t_fetched)/*expd*/,
6417 mkexpr(t_new)/*new*/,
6418 guest_EIP_curr_instr );
6419 } else {
6420 storeLE( mkexpr(t_addr1), mkexpr(t_new) );
6421 }
sewardj1c6f9912004-09-07 10:15:24 +00006422 }
6423
6424 /* Side effect done; now get selected bit into Carry flag */
sewardj2a2ba8b2004-11-08 13:14:06 +00006425 /* Flags: C=selected bit, O,S,Z,A,P undefined, so are set to zero. */
sewardj2a9ad022004-11-25 02:46:58 +00006426 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(X86G_CC_OP_COPY) ));
sewardj2a2ba8b2004-11-08 13:14:06 +00006427 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
sewardj1c6f9912004-09-07 10:15:24 +00006428 stmt( IRStmt_Put(
sewardj2a2ba8b2004-11-08 13:14:06 +00006429 OFFB_CC_DEP1,
sewardj1c6f9912004-09-07 10:15:24 +00006430 binop(Iop_And32,
6431 binop(Iop_Shr32,
6432 unop(Iop_8Uto32, mkexpr(t_fetched)),
sewardj5bd4d162004-11-10 13:02:48 +00006433 mkexpr(t_bitno2)),
6434 mkU32(1)))
sewardj1c6f9912004-09-07 10:15:24 +00006435 );
sewardja3b7e3a2005-04-05 01:54:19 +00006436 /* Set NDEP even though it isn't used. This makes redundant-PUT
6437 elimination of previous stores to this field work better. */
6438 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
sewardj1c6f9912004-09-07 10:15:24 +00006439
6440 /* Move reg operand from stack back to reg */
6441 if (epartIsReg(modrm)) {
6442 /* t_esp still points at it. */
sewardj4963a422004-10-14 23:34:03 +00006443 putIReg(sz, eregOfRM(modrm), loadLE(szToITy(sz), mkexpr(t_esp)) );
sewardj02834302010-07-29 18:10:51 +00006444 putIReg(4, R_ESP, binop(Iop_Add32, mkexpr(t_esp), mkU32(128)) );
sewardj1c6f9912004-09-07 10:15:24 +00006445 }
6446
6447 DIP("bt%s%c %s, %s\n",
6448 nameBtOp(op), nameISize(sz), nameIReg(sz, gregOfRM(modrm)),
6449 ( epartIsReg(modrm) ? nameIReg(sz, eregOfRM(modrm)) : dis_buf ) );
6450
6451 return delta;
6452}
sewardjce646f22004-08-31 23:55:54 +00006453
6454
6455
6456/* Handle BSF/BSR. Only v-size seems necessary. */
6457static
sewardj52d04912005-07-03 00:52:48 +00006458UInt dis_bs_E_G ( UChar sorb, Int sz, Int delta, Bool fwds )
sewardjce646f22004-08-31 23:55:54 +00006459{
6460 Bool isReg;
6461 UChar modrm;
sewardjc9a43662004-11-30 18:51:59 +00006462 HChar dis_buf[50];
sewardjce646f22004-08-31 23:55:54 +00006463
6464 IRType ty = szToITy(sz);
6465 IRTemp src = newTemp(ty);
6466 IRTemp dst = newTemp(ty);
6467
6468 IRTemp src32 = newTemp(Ity_I32);
6469 IRTemp dst32 = newTemp(Ity_I32);
sewardj009230b2013-01-26 11:47:55 +00006470 IRTemp srcB = newTemp(Ity_I1);
sewardjce646f22004-08-31 23:55:54 +00006471
6472 vassert(sz == 4 || sz == 2);
sewardjce646f22004-08-31 23:55:54 +00006473
6474 modrm = getIByte(delta);
6475
6476 isReg = epartIsReg(modrm);
6477 if (isReg) {
6478 delta++;
6479 assign( src, getIReg(sz, eregOfRM(modrm)) );
6480 } else {
6481 Int len;
6482 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
6483 delta += len;
6484 assign( src, loadLE(ty, mkexpr(addr)) );
6485 }
6486
6487 DIP("bs%c%c %s, %s\n",
6488 fwds ? 'f' : 'r', nameISize(sz),
6489 ( isReg ? nameIReg(sz, eregOfRM(modrm)) : dis_buf ),
6490 nameIReg(sz, gregOfRM(modrm)));
6491
sewardj009230b2013-01-26 11:47:55 +00006492 /* Generate a bool expression which is zero iff the original is
sewardje13074c2012-11-08 10:57:08 +00006493 zero, and nonzero otherwise. Ask for a CmpNE version which, if
6494 instrumented by Memcheck, is instrumented expensively, since
6495 this may be used on the output of a preceding movmskb insn,
6496 which has been known to be partially defined, and in need of
6497 careful handling. */
sewardj009230b2013-01-26 11:47:55 +00006498 assign( srcB, binop(mkSizedOp(ty,Iop_ExpCmpNE8),
6499 mkexpr(src), mkU(ty,0)) );
sewardjce646f22004-08-31 23:55:54 +00006500
6501 /* Flags: Z is 1 iff source value is zero. All others
6502 are undefined -- we force them to zero. */
sewardj2a9ad022004-11-25 02:46:58 +00006503 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(X86G_CC_OP_COPY) ));
sewardj2a2ba8b2004-11-08 13:14:06 +00006504 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
sewardjce646f22004-08-31 23:55:54 +00006505 stmt( IRStmt_Put(
sewardj2a2ba8b2004-11-08 13:14:06 +00006506 OFFB_CC_DEP1,
florian99dd03e2013-01-29 03:56:06 +00006507 IRExpr_ITE( mkexpr(srcB),
6508 /* src!=0 */
6509 mkU32(0),
6510 /* src==0 */
6511 mkU32(X86G_CC_MASK_Z)
sewardjce646f22004-08-31 23:55:54 +00006512 )
6513 ));
sewardja3b7e3a2005-04-05 01:54:19 +00006514 /* Set NDEP even though it isn't used. This makes redundant-PUT
6515 elimination of previous stores to this field work better. */
6516 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
sewardjce646f22004-08-31 23:55:54 +00006517
6518 /* Result: iff source value is zero, we can't use
6519 Iop_Clz32/Iop_Ctz32 as they have no defined result in that case.
6520 But anyway, Intel x86 semantics say the result is undefined in
6521 such situations. Hence handle the zero case specially. */
6522
6523 /* Bleh. What we compute:
6524
6525 bsf32: if src == 0 then 0 else Ctz32(src)
6526 bsr32: if src == 0 then 0 else 31 - Clz32(src)
6527
6528 bsf16: if src == 0 then 0 else Ctz32(16Uto32(src))
6529 bsr16: if src == 0 then 0 else 31 - Clz32(16Uto32(src))
6530
6531 First, widen src to 32 bits if it is not already.
sewardj37158712004-10-15 21:23:12 +00006532
6533 Postscript 15 Oct 04: it seems that at least VIA Nehemiah leaves the
6534 dst register unchanged when src == 0. Hence change accordingly.
sewardjce646f22004-08-31 23:55:54 +00006535 */
6536 if (sz == 2)
6537 assign( src32, unop(Iop_16Uto32, mkexpr(src)) );
6538 else
6539 assign( src32, mkexpr(src) );
6540
6541 /* The main computation, guarding against zero. */
6542 assign( dst32,
florian99dd03e2013-01-29 03:56:06 +00006543 IRExpr_ITE(
sewardj009230b2013-01-26 11:47:55 +00006544 mkexpr(srcB),
sewardjce646f22004-08-31 23:55:54 +00006545 /* src != 0 */
6546 fwds ? unop(Iop_Ctz32, mkexpr(src32))
6547 : binop(Iop_Sub32,
6548 mkU32(31),
florian99dd03e2013-01-29 03:56:06 +00006549 unop(Iop_Clz32, mkexpr(src32))),
6550 /* src == 0 -- leave dst unchanged */
6551 widenUto32( getIReg( sz, gregOfRM(modrm) ) )
sewardjce646f22004-08-31 23:55:54 +00006552 )
6553 );
6554
6555 if (sz == 2)
6556 assign( dst, unop(Iop_32to16, mkexpr(dst32)) );
6557 else
6558 assign( dst, mkexpr(dst32) );
6559
6560 /* dump result back */
6561 putIReg( sz, gregOfRM(modrm), mkexpr(dst) );
6562
6563 return delta;
6564}
sewardj64e1d652004-07-12 14:00:46 +00006565
6566
6567static
6568void codegen_xchg_eAX_Reg ( Int sz, Int reg )
6569{
6570 IRType ty = szToITy(sz);
6571 IRTemp t1 = newTemp(ty);
6572 IRTemp t2 = newTemp(ty);
6573 vassert(sz == 2 || sz == 4);
6574 assign( t1, getIReg(sz, R_EAX) );
6575 assign( t2, getIReg(sz, reg) );
6576 putIReg( sz, R_EAX, mkexpr(t2) );
6577 putIReg( sz, reg, mkexpr(t1) );
6578 DIP("xchg%c %s, %s\n",
6579 nameISize(sz), nameIReg(sz, R_EAX), nameIReg(sz, reg));
6580}
6581
6582
sewardjbdc7d212004-09-09 02:46:40 +00006583static
6584void codegen_SAHF ( void )
6585{
6586 /* Set the flags to:
sewardj2a9ad022004-11-25 02:46:58 +00006587 (x86g_calculate_flags_all() & X86G_CC_MASK_O) -- retain the old O flag
6588 | (%AH & (X86G_CC_MASK_S|X86G_CC_MASK_Z|X86G_CC_MASK_A
6589 |X86G_CC_MASK_P|X86G_CC_MASK_C)
sewardjbdc7d212004-09-09 02:46:40 +00006590 */
sewardj2a9ad022004-11-25 02:46:58 +00006591 UInt mask_SZACP = X86G_CC_MASK_S|X86G_CC_MASK_Z|X86G_CC_MASK_A
6592 |X86G_CC_MASK_C|X86G_CC_MASK_P;
sewardjbdc7d212004-09-09 02:46:40 +00006593 IRTemp oldflags = newTemp(Ity_I32);
sewardj2a9ad022004-11-25 02:46:58 +00006594 assign( oldflags, mk_x86g_calculate_eflags_all() );
6595 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(X86G_CC_OP_COPY) ));
sewardj905edbd2007-04-07 12:25:37 +00006596 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
sewardj2a2ba8b2004-11-08 13:14:06 +00006597 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
6598 stmt( IRStmt_Put( OFFB_CC_DEP1,
sewardjbdc7d212004-09-09 02:46:40 +00006599 binop(Iop_Or32,
sewardj2a9ad022004-11-25 02:46:58 +00006600 binop(Iop_And32, mkexpr(oldflags), mkU32(X86G_CC_MASK_O)),
sewardjbdc7d212004-09-09 02:46:40 +00006601 binop(Iop_And32,
6602 binop(Iop_Shr32, getIReg(4, R_EAX), mkU8(8)),
6603 mkU32(mask_SZACP))
6604 )
6605 ));
sewardja3b7e3a2005-04-05 01:54:19 +00006606 /* Set NDEP even though it isn't used. This makes redundant-PUT
6607 elimination of previous stores to this field work better. */
6608 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
sewardjbdc7d212004-09-09 02:46:40 +00006609}
6610
6611
sewardj8dfdc8a2005-10-03 11:39:02 +00006612static
6613void codegen_LAHF ( void )
6614{
6615 /* AH <- EFLAGS(SF:ZF:0:AF:0:PF:1:CF) */
6616 IRExpr* eax_with_hole;
6617 IRExpr* new_byte;
6618 IRExpr* new_eax;
6619 UInt mask_SZACP = X86G_CC_MASK_S|X86G_CC_MASK_Z|X86G_CC_MASK_A
6620 |X86G_CC_MASK_C|X86G_CC_MASK_P;
6621
6622 IRTemp flags = newTemp(Ity_I32);
6623 assign( flags, mk_x86g_calculate_eflags_all() );
6624
6625 eax_with_hole
6626 = binop(Iop_And32, getIReg(4, R_EAX), mkU32(0xFFFF00FF));
6627 new_byte
6628 = binop(Iop_Or32, binop(Iop_And32, mkexpr(flags), mkU32(mask_SZACP)),
6629 mkU32(1<<1));
6630 new_eax
6631 = binop(Iop_Or32, eax_with_hole,
6632 binop(Iop_Shl32, new_byte, mkU8(8)));
6633 putIReg(4, R_EAX, new_eax);
6634}
6635
sewardj458a6f82004-08-25 12:46:02 +00006636
6637static
6638UInt dis_cmpxchg_G_E ( UChar sorb,
sewardje9d8a262009-07-01 08:06:34 +00006639 Bool locked,
sewardj458a6f82004-08-25 12:46:02 +00006640 Int size,
sewardj52d04912005-07-03 00:52:48 +00006641 Int delta0 )
sewardj458a6f82004-08-25 12:46:02 +00006642{
sewardjc9a43662004-11-30 18:51:59 +00006643 HChar dis_buf[50];
sewardj458a6f82004-08-25 12:46:02 +00006644 Int len;
6645
6646 IRType ty = szToITy(size);
6647 IRTemp acc = newTemp(ty);
6648 IRTemp src = newTemp(ty);
6649 IRTemp dest = newTemp(ty);
6650 IRTemp dest2 = newTemp(ty);
6651 IRTemp acc2 = newTemp(ty);
sewardj009230b2013-01-26 11:47:55 +00006652 IRTemp cond = newTemp(Ity_I1);
sewardj92d168d2004-11-15 14:22:12 +00006653 IRTemp addr = IRTemp_INVALID;
sewardj458a6f82004-08-25 12:46:02 +00006654 UChar rm = getUChar(delta0);
6655
sewardje9d8a262009-07-01 08:06:34 +00006656 /* There are 3 cases to consider:
6657
6658 reg-reg: ignore any lock prefix, generate sequence based
florian99dd03e2013-01-29 03:56:06 +00006659 on ITE
sewardje9d8a262009-07-01 08:06:34 +00006660
6661 reg-mem, not locked: ignore any lock prefix, generate sequence
florian99dd03e2013-01-29 03:56:06 +00006662 based on ITE
sewardje9d8a262009-07-01 08:06:34 +00006663
6664 reg-mem, locked: use IRCAS
6665 */
sewardj458a6f82004-08-25 12:46:02 +00006666 if (epartIsReg(rm)) {
sewardje9d8a262009-07-01 08:06:34 +00006667 /* case 1 */
sewardj458a6f82004-08-25 12:46:02 +00006668 assign( dest, getIReg(size, eregOfRM(rm)) );
6669 delta0++;
sewardje9d8a262009-07-01 08:06:34 +00006670 assign( src, getIReg(size, gregOfRM(rm)) );
6671 assign( acc, getIReg(size, R_EAX) );
6672 setFlags_DEP1_DEP2(Iop_Sub8, acc, dest, ty);
sewardj009230b2013-01-26 11:47:55 +00006673 assign( cond, mk_x86g_calculate_condition(X86CondZ) );
florian99dd03e2013-01-29 03:56:06 +00006674 assign( dest2, IRExpr_ITE(mkexpr(cond), mkexpr(src), mkexpr(dest)) );
6675 assign( acc2, IRExpr_ITE(mkexpr(cond), mkexpr(acc), mkexpr(dest)) );
sewardje9d8a262009-07-01 08:06:34 +00006676 putIReg(size, R_EAX, mkexpr(acc2));
6677 putIReg(size, eregOfRM(rm), mkexpr(dest2));
sewardj458a6f82004-08-25 12:46:02 +00006678 DIP("cmpxchg%c %s,%s\n", nameISize(size),
6679 nameIReg(size,gregOfRM(rm)),
6680 nameIReg(size,eregOfRM(rm)) );
sewardje9d8a262009-07-01 08:06:34 +00006681 }
6682 else if (!epartIsReg(rm) && !locked) {
6683 /* case 2 */
sewardj458a6f82004-08-25 12:46:02 +00006684 addr = disAMode ( &len, sorb, delta0, dis_buf );
6685 assign( dest, loadLE(ty, mkexpr(addr)) );
6686 delta0 += len;
sewardje9d8a262009-07-01 08:06:34 +00006687 assign( src, getIReg(size, gregOfRM(rm)) );
6688 assign( acc, getIReg(size, R_EAX) );
6689 setFlags_DEP1_DEP2(Iop_Sub8, acc, dest, ty);
sewardj009230b2013-01-26 11:47:55 +00006690 assign( cond, mk_x86g_calculate_condition(X86CondZ) );
florian99dd03e2013-01-29 03:56:06 +00006691 assign( dest2, IRExpr_ITE(mkexpr(cond), mkexpr(src), mkexpr(dest)) );
6692 assign( acc2, IRExpr_ITE(mkexpr(cond), mkexpr(acc), mkexpr(dest)) );
sewardje9d8a262009-07-01 08:06:34 +00006693 putIReg(size, R_EAX, mkexpr(acc2));
6694 storeLE( mkexpr(addr), mkexpr(dest2) );
sewardj458a6f82004-08-25 12:46:02 +00006695 DIP("cmpxchg%c %s,%s\n", nameISize(size),
6696 nameIReg(size,gregOfRM(rm)), dis_buf);
6697 }
sewardje9d8a262009-07-01 08:06:34 +00006698 else if (!epartIsReg(rm) && locked) {
6699 /* case 3 */
6700 /* src is new value. acc is expected value. dest is old value.
6701 Compute success from the output of the IRCAS, and steer the
6702 new value for EAX accordingly: in case of success, EAX is
6703 unchanged. */
6704 addr = disAMode ( &len, sorb, delta0, dis_buf );
6705 delta0 += len;
6706 assign( src, getIReg(size, gregOfRM(rm)) );
6707 assign( acc, getIReg(size, R_EAX) );
6708 stmt( IRStmt_CAS(
6709 mkIRCAS( IRTemp_INVALID, dest, Iend_LE, mkexpr(addr),
6710 NULL, mkexpr(acc), NULL, mkexpr(src) )
6711 ));
6712 setFlags_DEP1_DEP2(Iop_Sub8, acc, dest, ty);
sewardj009230b2013-01-26 11:47:55 +00006713 assign( cond, mk_x86g_calculate_condition(X86CondZ) );
florian99dd03e2013-01-29 03:56:06 +00006714 assign( acc2, IRExpr_ITE(mkexpr(cond), mkexpr(acc), mkexpr(dest)) );
sewardje9d8a262009-07-01 08:06:34 +00006715 putIReg(size, R_EAX, mkexpr(acc2));
sewardj40d1d212009-07-12 13:01:17 +00006716 DIP("cmpxchg%c %s,%s\n", nameISize(size),
6717 nameIReg(size,gregOfRM(rm)), dis_buf);
sewardj458a6f82004-08-25 12:46:02 +00006718 }
sewardje9d8a262009-07-01 08:06:34 +00006719 else vassert(0);
sewardj458a6f82004-08-25 12:46:02 +00006720
6721 return delta0;
6722}
6723
6724
sewardj458a6f82004-08-25 12:46:02 +00006725/* Handle conditional move instructions of the form
6726 cmovcc E(reg-or-mem), G(reg)
6727
6728 E(src) is reg-or-mem
6729 G(dst) is reg.
6730
6731 If E is reg, --> GET %E, tmps
6732 GET %G, tmpd
6733 CMOVcc tmps, tmpd
6734 PUT tmpd, %G
6735
6736 If E is mem --> (getAddr E) -> tmpa
6737 LD (tmpa), tmps
6738 GET %G, tmpd
6739 CMOVcc tmps, tmpd
6740 PUT tmpd, %G
6741*/
6742static
6743UInt dis_cmov_E_G ( UChar sorb,
6744 Int sz,
sewardj2a9ad022004-11-25 02:46:58 +00006745 X86Condcode cond,
sewardj52d04912005-07-03 00:52:48 +00006746 Int delta0 )
sewardj458a6f82004-08-25 12:46:02 +00006747{
6748 UChar rm = getIByte(delta0);
sewardjc9a43662004-11-30 18:51:59 +00006749 HChar dis_buf[50];
sewardj458a6f82004-08-25 12:46:02 +00006750 Int len;
6751
sewardj883b00b2004-09-11 09:30:24 +00006752 IRType ty = szToITy(sz);
sewardj458a6f82004-08-25 12:46:02 +00006753 IRTemp tmps = newTemp(ty);
6754 IRTemp tmpd = newTemp(ty);
6755
6756 if (epartIsReg(rm)) {
6757 assign( tmps, getIReg(sz, eregOfRM(rm)) );
6758 assign( tmpd, getIReg(sz, gregOfRM(rm)) );
6759
6760 putIReg(sz, gregOfRM(rm),
florian99dd03e2013-01-29 03:56:06 +00006761 IRExpr_ITE( mk_x86g_calculate_condition(cond),
6762 mkexpr(tmps),
6763 mkexpr(tmpd) )
sewardj458a6f82004-08-25 12:46:02 +00006764 );
6765 DIP("cmov%c%s %s,%s\n", nameISize(sz),
sewardj2a9ad022004-11-25 02:46:58 +00006766 name_X86Condcode(cond),
sewardj458a6f82004-08-25 12:46:02 +00006767 nameIReg(sz,eregOfRM(rm)),
6768 nameIReg(sz,gregOfRM(rm)));
6769 return 1+delta0;
6770 }
6771
6772 /* E refers to memory */
6773 {
6774 IRTemp addr = disAMode ( &len, sorb, delta0, dis_buf );
6775 assign( tmps, loadLE(ty, mkexpr(addr)) );
6776 assign( tmpd, getIReg(sz, gregOfRM(rm)) );
6777
6778 putIReg(sz, gregOfRM(rm),
florian99dd03e2013-01-29 03:56:06 +00006779 IRExpr_ITE( mk_x86g_calculate_condition(cond),
6780 mkexpr(tmps),
6781 mkexpr(tmpd) )
sewardj458a6f82004-08-25 12:46:02 +00006782 );
6783
6784 DIP("cmov%c%s %s,%s\n", nameISize(sz),
sewardj2a9ad022004-11-25 02:46:58 +00006785 name_X86Condcode(cond),
sewardj458a6f82004-08-25 12:46:02 +00006786 dis_buf,
6787 nameIReg(sz,gregOfRM(rm)));
6788 return len+delta0;
6789 }
6790}
6791
6792
sewardj883b00b2004-09-11 09:30:24 +00006793static
sewardje9d8a262009-07-01 08:06:34 +00006794UInt dis_xadd_G_E ( UChar sorb, Bool locked, Int sz, Int delta0,
6795 Bool* decodeOK )
sewardj883b00b2004-09-11 09:30:24 +00006796{
6797 Int len;
6798 UChar rm = getIByte(delta0);
sewardjc9a43662004-11-30 18:51:59 +00006799 HChar dis_buf[50];
sewardj883b00b2004-09-11 09:30:24 +00006800
sewardj883b00b2004-09-11 09:30:24 +00006801 IRType ty = szToITy(sz);
6802 IRTemp tmpd = newTemp(ty);
6803 IRTemp tmpt0 = newTemp(ty);
6804 IRTemp tmpt1 = newTemp(ty);
6805
sewardje9d8a262009-07-01 08:06:34 +00006806 /* There are 3 cases to consider:
6807
sewardjc2433a82010-05-10 20:51:22 +00006808 reg-reg: ignore any lock prefix,
6809 generate 'naive' (non-atomic) sequence
sewardje9d8a262009-07-01 08:06:34 +00006810
6811 reg-mem, not locked: ignore any lock prefix, generate 'naive'
6812 (non-atomic) sequence
6813
6814 reg-mem, locked: use IRCAS
6815 */
6816
sewardj883b00b2004-09-11 09:30:24 +00006817 if (epartIsReg(rm)) {
sewardje9d8a262009-07-01 08:06:34 +00006818 /* case 1 */
sewardjc2433a82010-05-10 20:51:22 +00006819 assign( tmpd, getIReg(sz, eregOfRM(rm)));
6820 assign( tmpt0, getIReg(sz, gregOfRM(rm)) );
6821 assign( tmpt1, binop(mkSizedOp(ty,Iop_Add8),
6822 mkexpr(tmpd), mkexpr(tmpt0)) );
6823 setFlags_DEP1_DEP2( Iop_Add8, tmpd, tmpt0, ty );
6824 putIReg(sz, eregOfRM(rm), mkexpr(tmpt1));
6825 putIReg(sz, gregOfRM(rm), mkexpr(tmpd));
6826 DIP("xadd%c %s, %s\n",
6827 nameISize(sz), nameIReg(sz,gregOfRM(rm)),
6828 nameIReg(sz,eregOfRM(rm)));
6829 *decodeOK = True;
6830 return 1+delta0;
sewardje9d8a262009-07-01 08:06:34 +00006831 }
6832 else if (!epartIsReg(rm) && !locked) {
6833 /* case 2 */
sewardj883b00b2004-09-11 09:30:24 +00006834 IRTemp addr = disAMode ( &len, sorb, delta0, dis_buf );
6835 assign( tmpd, loadLE(ty, mkexpr(addr)) );
6836 assign( tmpt0, getIReg(sz, gregOfRM(rm)) );
sewardje9d8a262009-07-01 08:06:34 +00006837 assign( tmpt1, binop(mkSizedOp(ty,Iop_Add8),
6838 mkexpr(tmpd), mkexpr(tmpt0)) );
sewardj883b00b2004-09-11 09:30:24 +00006839 storeLE( mkexpr(addr), mkexpr(tmpt1) );
sewardje9d8a262009-07-01 08:06:34 +00006840 setFlags_DEP1_DEP2( Iop_Add8, tmpd, tmpt0, ty );
sewardj883b00b2004-09-11 09:30:24 +00006841 putIReg(sz, gregOfRM(rm), mkexpr(tmpd));
6842 DIP("xadd%c %s, %s\n",
6843 nameISize(sz), nameIReg(sz,gregOfRM(rm)), dis_buf);
sewardj0092e0d2006-03-06 13:35:42 +00006844 *decodeOK = True;
sewardj883b00b2004-09-11 09:30:24 +00006845 return len+delta0;
6846 }
sewardje9d8a262009-07-01 08:06:34 +00006847 else if (!epartIsReg(rm) && locked) {
6848 /* case 3 */
6849 IRTemp addr = disAMode ( &len, sorb, delta0, dis_buf );
6850 assign( tmpd, loadLE(ty, mkexpr(addr)) );
6851 assign( tmpt0, getIReg(sz, gregOfRM(rm)) );
6852 assign( tmpt1, binop(mkSizedOp(ty,Iop_Add8),
6853 mkexpr(tmpd), mkexpr(tmpt0)) );
6854 casLE( mkexpr(addr), mkexpr(tmpd)/*expVal*/,
6855 mkexpr(tmpt1)/*newVal*/, guest_EIP_curr_instr );
6856 setFlags_DEP1_DEP2( Iop_Add8, tmpd, tmpt0, ty );
6857 putIReg(sz, gregOfRM(rm), mkexpr(tmpd));
6858 DIP("xadd%c %s, %s\n",
6859 nameISize(sz), nameIReg(sz,gregOfRM(rm)), dis_buf);
6860 *decodeOK = True;
6861 return len+delta0;
6862 }
6863 /*UNREACHED*/
6864 vassert(0);
sewardj883b00b2004-09-11 09:30:24 +00006865}
6866
sewardjb64821b2004-12-14 10:00:16 +00006867/* Move 16 bits from Ew (ireg or mem) to G (a segment register). */
6868
sewardj7df596b2004-12-06 14:29:12 +00006869static
sewardj52d04912005-07-03 00:52:48 +00006870UInt dis_mov_Ew_Sw ( UChar sorb, Int delta0 )
sewardj7df596b2004-12-06 14:29:12 +00006871{
sewardjb64821b2004-12-14 10:00:16 +00006872 Int len;
6873 IRTemp addr;
6874 UChar rm = getIByte(delta0);
6875 HChar dis_buf[50];
sewardj7df596b2004-12-06 14:29:12 +00006876
6877 if (epartIsReg(rm)) {
6878 putSReg( gregOfRM(rm), getIReg(2, eregOfRM(rm)) );
6879 DIP("movw %s,%s\n", nameIReg(2,eregOfRM(rm)), nameSReg(gregOfRM(rm)));
6880 return 1+delta0;
sewardjb64821b2004-12-14 10:00:16 +00006881 } else {
6882 addr = disAMode ( &len, sorb, delta0, dis_buf );
6883 putSReg( gregOfRM(rm), loadLE(Ity_I16, mkexpr(addr)) );
6884 DIP("movw %s,%s\n", dis_buf, nameSReg(gregOfRM(rm)));
6885 return len+delta0;
sewardj7df596b2004-12-06 14:29:12 +00006886 }
6887}
6888
sewardjb64821b2004-12-14 10:00:16 +00006889/* Move 16 bits from G (a segment register) to Ew (ireg or mem). If
6890 dst is ireg and sz==4, zero out top half of it. */
6891
sewardj063f02f2004-10-20 12:36:12 +00006892static
6893UInt dis_mov_Sw_Ew ( UChar sorb,
6894 Int sz,
sewardj52d04912005-07-03 00:52:48 +00006895 Int delta0 )
sewardj063f02f2004-10-20 12:36:12 +00006896{
sewardjb64821b2004-12-14 10:00:16 +00006897 Int len;
6898 IRTemp addr;
6899 UChar rm = getIByte(delta0);
6900 HChar dis_buf[50];
sewardj063f02f2004-10-20 12:36:12 +00006901
6902 vassert(sz == 2 || sz == 4);
6903
6904 if (epartIsReg(rm)) {
6905 if (sz == 4)
6906 putIReg(4, eregOfRM(rm), unop(Iop_16Uto32, getSReg(gregOfRM(rm))));
6907 else
6908 putIReg(2, eregOfRM(rm), getSReg(gregOfRM(rm)));
6909
6910 DIP("mov %s,%s\n", nameSReg(gregOfRM(rm)), nameIReg(sz,eregOfRM(rm)));
6911 return 1+delta0;
sewardjb64821b2004-12-14 10:00:16 +00006912 } else {
6913 addr = disAMode ( &len, sorb, delta0, dis_buf );
6914 storeLE( mkexpr(addr), getSReg(gregOfRM(rm)) );
sewardj063f02f2004-10-20 12:36:12 +00006915 DIP("mov %s,%s\n", nameSReg(gregOfRM(rm)), dis_buf);
sewardjb64821b2004-12-14 10:00:16 +00006916 return len+delta0;
sewardj063f02f2004-10-20 12:36:12 +00006917 }
sewardj063f02f2004-10-20 12:36:12 +00006918}
6919
6920
sewardjb64821b2004-12-14 10:00:16 +00006921static
6922void dis_push_segreg ( UInt sreg, Int sz )
6923{
6924 IRTemp t1 = newTemp(Ity_I16);
6925 IRTemp ta = newTemp(Ity_I32);
6926 vassert(sz == 2 || sz == 4);
6927
6928 assign( t1, getSReg(sreg) );
6929 assign( ta, binop(Iop_Sub32, getIReg(4, R_ESP), mkU32(sz)) );
6930 putIReg(4, R_ESP, mkexpr(ta));
6931 storeLE( mkexpr(ta), mkexpr(t1) );
6932
sewardj5c5f72c2006-03-18 11:29:25 +00006933 DIP("push%c %s\n", sz==2 ? 'w' : 'l', nameSReg(sreg));
sewardjb64821b2004-12-14 10:00:16 +00006934}
6935
6936static
6937void dis_pop_segreg ( UInt sreg, Int sz )
6938{
6939 IRTemp t1 = newTemp(Ity_I16);
6940 IRTemp ta = newTemp(Ity_I32);
6941 vassert(sz == 2 || sz == 4);
6942
6943 assign( ta, getIReg(4, R_ESP) );
6944 assign( t1, loadLE(Ity_I16, mkexpr(ta)) );
6945
6946 putIReg(4, R_ESP, binop(Iop_Add32, mkexpr(ta), mkU32(sz)) );
6947 putSReg( sreg, mkexpr(t1) );
sewardj5c5f72c2006-03-18 11:29:25 +00006948 DIP("pop%c %s\n", sz==2 ? 'w' : 'l', nameSReg(sreg));
sewardjb64821b2004-12-14 10:00:16 +00006949}
sewardje05c42c2004-07-08 20:25:10 +00006950
6951static
sewardjc6f970f2012-04-02 21:54:49 +00006952void dis_ret ( /*MOD*/DisResult* dres, UInt d32 )
sewardje05c42c2004-07-08 20:25:10 +00006953{
sewardjc6f970f2012-04-02 21:54:49 +00006954 IRTemp t1 = newTemp(Ity_I32);
6955 IRTemp t2 = newTemp(Ity_I32);
sewardje05c42c2004-07-08 20:25:10 +00006956 assign(t1, getIReg(4,R_ESP));
6957 assign(t2, loadLE(Ity_I32,mkexpr(t1)));
6958 putIReg(4, R_ESP,binop(Iop_Add32, mkexpr(t1), mkU32(4+d32)));
sewardjc6f970f2012-04-02 21:54:49 +00006959 jmp_treg(dres, Ijk_Ret, t2);
6960 vassert(dres->whatNext == Dis_StopHere);
sewardje05c42c2004-07-08 20:25:10 +00006961}
6962
sewardj4cb918d2004-12-03 19:43:31 +00006963/*------------------------------------------------------------*/
6964/*--- SSE/SSE2/SSE3 helpers ---*/
6965/*------------------------------------------------------------*/
sewardjc9a43662004-11-30 18:51:59 +00006966
sewardj9571dc02014-01-26 18:34:23 +00006967/* Indicates whether the op requires a rounding-mode argument. Note
6968 that this covers only vector floating point arithmetic ops, and
6969 omits the scalar ones that need rounding modes. Note also that
6970 inconsistencies here will get picked up later by the IR sanity
6971 checker, so this isn't correctness-critical. */
6972static Bool requiresRMode ( IROp op )
6973{
6974 switch (op) {
6975 /* 128 bit ops */
6976 case Iop_Add32Fx4: case Iop_Sub32Fx4:
6977 case Iop_Mul32Fx4: case Iop_Div32Fx4:
6978 case Iop_Add64Fx2: case Iop_Sub64Fx2:
6979 case Iop_Mul64Fx2: case Iop_Div64Fx2:
6980 return True;
6981 default:
6982 break;
6983 }
6984 return False;
6985}
6986
6987
sewardj129b3d92004-12-05 15:42:05 +00006988/* Worker function; do not call directly.
6989 Handles full width G = G `op` E and G = (not G) `op` E.
6990*/
6991
6992static UInt dis_SSE_E_to_G_all_wrk (
sewardj52d04912005-07-03 00:52:48 +00006993 UChar sorb, Int delta,
florian55085f82012-11-21 00:36:55 +00006994 const HChar* opname, IROp op,
sewardj1e6ad742004-12-02 16:16:11 +00006995 Bool invertG
6996 )
sewardjc9a43662004-11-30 18:51:59 +00006997{
sewardj1e6ad742004-12-02 16:16:11 +00006998 HChar dis_buf[50];
6999 Int alen;
7000 IRTemp addr;
7001 UChar rm = getIByte(delta);
7002 IRExpr* gpart
sewardjf0c1c582005-02-07 23:47:38 +00007003 = invertG ? unop(Iop_NotV128, getXMMReg(gregOfRM(rm)))
sewardj1e6ad742004-12-02 16:16:11 +00007004 : getXMMReg(gregOfRM(rm));
sewardjc9a43662004-11-30 18:51:59 +00007005 if (epartIsReg(rm)) {
sewardj9571dc02014-01-26 18:34:23 +00007006 putXMMReg(
7007 gregOfRM(rm),
7008 requiresRMode(op)
7009 ? triop(op, get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
7010 gpart,
7011 getXMMReg(eregOfRM(rm)))
7012 : binop(op, gpart,
7013 getXMMReg(eregOfRM(rm)))
7014 );
sewardjc9a43662004-11-30 18:51:59 +00007015 DIP("%s %s,%s\n", opname,
7016 nameXMMReg(eregOfRM(rm)),
7017 nameXMMReg(gregOfRM(rm)) );
7018 return delta+1;
7019 } else {
sewardj1e6ad742004-12-02 16:16:11 +00007020 addr = disAMode ( &alen, sorb, delta, dis_buf );
sewardj9571dc02014-01-26 18:34:23 +00007021 putXMMReg(
7022 gregOfRM(rm),
7023 requiresRMode(op)
7024 ? triop(op, get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
7025 gpart,
7026 loadLE(Ity_V128, mkexpr(addr)))
7027 : binop(op, gpart,
7028 loadLE(Ity_V128, mkexpr(addr)))
7029 );
sewardj1e6ad742004-12-02 16:16:11 +00007030 DIP("%s %s,%s\n", opname,
7031 dis_buf,
7032 nameXMMReg(gregOfRM(rm)) );
7033 return delta+alen;
sewardjc9a43662004-11-30 18:51:59 +00007034 }
7035}
7036
sewardj129b3d92004-12-05 15:42:05 +00007037
7038/* All lanes SSE binary operation, G = G `op` E. */
sewardj1e6ad742004-12-02 16:16:11 +00007039
7040static
florian55085f82012-11-21 00:36:55 +00007041UInt dis_SSE_E_to_G_all ( UChar sorb, Int delta, const HChar* opname, IROp op )
sewardj1e6ad742004-12-02 16:16:11 +00007042{
sewardj129b3d92004-12-05 15:42:05 +00007043 return dis_SSE_E_to_G_all_wrk( sorb, delta, opname, op, False );
sewardj1e6ad742004-12-02 16:16:11 +00007044}
7045
sewardj129b3d92004-12-05 15:42:05 +00007046/* All lanes SSE binary operation, G = (not G) `op` E. */
7047
7048static
sewardj52d04912005-07-03 00:52:48 +00007049UInt dis_SSE_E_to_G_all_invG ( UChar sorb, Int delta,
florian55085f82012-11-21 00:36:55 +00007050 const HChar* opname, IROp op )
sewardj129b3d92004-12-05 15:42:05 +00007051{
7052 return dis_SSE_E_to_G_all_wrk( sorb, delta, opname, op, True );
7053}
7054
sewardj164f9272004-12-09 00:39:32 +00007055
sewardj129b3d92004-12-05 15:42:05 +00007056/* Lowest 32-bit lane only SSE binary operation, G = G `op` E. */
7057
sewardj52d04912005-07-03 00:52:48 +00007058static UInt dis_SSE_E_to_G_lo32 ( UChar sorb, Int delta,
florian55085f82012-11-21 00:36:55 +00007059 const HChar* opname, IROp op )
sewardj129b3d92004-12-05 15:42:05 +00007060{
7061 HChar dis_buf[50];
7062 Int alen;
7063 IRTemp addr;
7064 UChar rm = getIByte(delta);
7065 IRExpr* gpart = getXMMReg(gregOfRM(rm));
7066 if (epartIsReg(rm)) {
7067 putXMMReg( gregOfRM(rm),
7068 binop(op, gpart,
7069 getXMMReg(eregOfRM(rm))) );
7070 DIP("%s %s,%s\n", opname,
7071 nameXMMReg(eregOfRM(rm)),
7072 nameXMMReg(gregOfRM(rm)) );
7073 return delta+1;
7074 } else {
7075 /* We can only do a 32-bit memory read, so the upper 3/4 of the
7076 E operand needs to be made simply of zeroes. */
7077 IRTemp epart = newTemp(Ity_V128);
7078 addr = disAMode ( &alen, sorb, delta, dis_buf );
sewardjf0c1c582005-02-07 23:47:38 +00007079 assign( epart, unop( Iop_32UtoV128,
sewardj129b3d92004-12-05 15:42:05 +00007080 loadLE(Ity_I32, mkexpr(addr))) );
7081 putXMMReg( gregOfRM(rm),
7082 binop(op, gpart, mkexpr(epart)) );
7083 DIP("%s %s,%s\n", opname,
7084 dis_buf,
7085 nameXMMReg(gregOfRM(rm)) );
7086 return delta+alen;
7087 }
7088}
7089
sewardj164f9272004-12-09 00:39:32 +00007090
sewardj636ad762004-12-07 11:16:04 +00007091/* Lower 64-bit lane only SSE binary operation, G = G `op` E. */
7092
sewardj52d04912005-07-03 00:52:48 +00007093static UInt dis_SSE_E_to_G_lo64 ( UChar sorb, Int delta,
florian55085f82012-11-21 00:36:55 +00007094 const HChar* opname, IROp op )
sewardj636ad762004-12-07 11:16:04 +00007095{
7096 HChar dis_buf[50];
7097 Int alen;
7098 IRTemp addr;
7099 UChar rm = getIByte(delta);
7100 IRExpr* gpart = getXMMReg(gregOfRM(rm));
7101 if (epartIsReg(rm)) {
7102 putXMMReg( gregOfRM(rm),
7103 binop(op, gpart,
7104 getXMMReg(eregOfRM(rm))) );
7105 DIP("%s %s,%s\n", opname,
7106 nameXMMReg(eregOfRM(rm)),
7107 nameXMMReg(gregOfRM(rm)) );
7108 return delta+1;
7109 } else {
7110 /* We can only do a 64-bit memory read, so the upper half of the
7111 E operand needs to be made simply of zeroes. */
7112 IRTemp epart = newTemp(Ity_V128);
7113 addr = disAMode ( &alen, sorb, delta, dis_buf );
sewardjf0c1c582005-02-07 23:47:38 +00007114 assign( epart, unop( Iop_64UtoV128,
sewardj636ad762004-12-07 11:16:04 +00007115 loadLE(Ity_I64, mkexpr(addr))) );
7116 putXMMReg( gregOfRM(rm),
7117 binop(op, gpart, mkexpr(epart)) );
7118 DIP("%s %s,%s\n", opname,
7119 dis_buf,
7120 nameXMMReg(gregOfRM(rm)) );
7121 return delta+alen;
7122 }
7123}
7124
sewardj164f9272004-12-09 00:39:32 +00007125
sewardj129b3d92004-12-05 15:42:05 +00007126/* All lanes unary SSE operation, G = op(E). */
7127
7128static UInt dis_SSE_E_to_G_unary_all (
sewardj52d04912005-07-03 00:52:48 +00007129 UChar sorb, Int delta,
florian55085f82012-11-21 00:36:55 +00007130 const HChar* opname, IROp op
sewardj0bd7ce62004-12-05 02:47:40 +00007131 )
7132{
7133 HChar dis_buf[50];
7134 Int alen;
7135 IRTemp addr;
7136 UChar rm = getIByte(delta);
sewardj8bb1c9e2015-04-07 09:36:35 +00007137 // Sqrt32Fx4 and Sqrt64Fx2 take a rounding mode, which is faked
7138 // up in the usual way.
7139 Bool needsIRRM = op == Iop_Sqrt32Fx4 || op == Iop_Sqrt64Fx2;
sewardj0bd7ce62004-12-05 02:47:40 +00007140 if (epartIsReg(rm)) {
sewardj8bb1c9e2015-04-07 09:36:35 +00007141 IRExpr* src = getXMMReg(eregOfRM(rm));
7142 /* XXXROUNDINGFIXME */
7143 IRExpr* res = needsIRRM ? binop(op, get_FAKE_roundingmode(), src)
7144 : unop(op, src);
7145 putXMMReg( gregOfRM(rm), res );
sewardj0bd7ce62004-12-05 02:47:40 +00007146 DIP("%s %s,%s\n", opname,
7147 nameXMMReg(eregOfRM(rm)),
7148 nameXMMReg(gregOfRM(rm)) );
7149 return delta+1;
7150 } else {
7151 addr = disAMode ( &alen, sorb, delta, dis_buf );
sewardj8bb1c9e2015-04-07 09:36:35 +00007152 IRExpr* src = loadLE(Ity_V128, mkexpr(addr));
7153 /* XXXROUNDINGFIXME */
7154 IRExpr* res = needsIRRM ? binop(op, get_FAKE_roundingmode(), src)
7155 : unop(op, src);
7156 putXMMReg( gregOfRM(rm), res );
sewardj0bd7ce62004-12-05 02:47:40 +00007157 DIP("%s %s,%s\n", opname,
7158 dis_buf,
7159 nameXMMReg(gregOfRM(rm)) );
7160 return delta+alen;
7161 }
7162}
7163
sewardj164f9272004-12-09 00:39:32 +00007164
sewardj129b3d92004-12-05 15:42:05 +00007165/* Lowest 32-bit lane only unary SSE operation, G = op(E). */
sewardj0bd7ce62004-12-05 02:47:40 +00007166
sewardj129b3d92004-12-05 15:42:05 +00007167static UInt dis_SSE_E_to_G_unary_lo32 (
sewardj52d04912005-07-03 00:52:48 +00007168 UChar sorb, Int delta,
florian55085f82012-11-21 00:36:55 +00007169 const HChar* opname, IROp op
sewardj129b3d92004-12-05 15:42:05 +00007170 )
7171{
7172 /* First we need to get the old G value and patch the low 32 bits
7173 of the E operand into it. Then apply op and write back to G. */
7174 HChar dis_buf[50];
7175 Int alen;
7176 IRTemp addr;
7177 UChar rm = getIByte(delta);
7178 IRTemp oldG0 = newTemp(Ity_V128);
7179 IRTemp oldG1 = newTemp(Ity_V128);
7180
7181 assign( oldG0, getXMMReg(gregOfRM(rm)) );
7182
7183 if (epartIsReg(rm)) {
7184 assign( oldG1,
sewardjf0c1c582005-02-07 23:47:38 +00007185 binop( Iop_SetV128lo32,
sewardj129b3d92004-12-05 15:42:05 +00007186 mkexpr(oldG0),
sewardj35579be2004-12-06 00:36:25 +00007187 getXMMRegLane32(eregOfRM(rm), 0)) );
sewardj129b3d92004-12-05 15:42:05 +00007188 putXMMReg( gregOfRM(rm), unop(op, mkexpr(oldG1)) );
7189 DIP("%s %s,%s\n", opname,
7190 nameXMMReg(eregOfRM(rm)),
7191 nameXMMReg(gregOfRM(rm)) );
7192 return delta+1;
7193 } else {
7194 addr = disAMode ( &alen, sorb, delta, dis_buf );
7195 assign( oldG1,
sewardjf0c1c582005-02-07 23:47:38 +00007196 binop( Iop_SetV128lo32,
sewardj129b3d92004-12-05 15:42:05 +00007197 mkexpr(oldG0),
7198 loadLE(Ity_I32, mkexpr(addr)) ));
7199 putXMMReg( gregOfRM(rm), unop(op, mkexpr(oldG1)) );
7200 DIP("%s %s,%s\n", opname,
7201 dis_buf,
7202 nameXMMReg(gregOfRM(rm)) );
7203 return delta+alen;
7204 }
7205}
7206
sewardj164f9272004-12-09 00:39:32 +00007207
sewardj008754b2004-12-08 14:37:10 +00007208/* Lowest 64-bit lane only unary SSE operation, G = op(E). */
7209
7210static UInt dis_SSE_E_to_G_unary_lo64 (
sewardj52d04912005-07-03 00:52:48 +00007211 UChar sorb, Int delta,
florian55085f82012-11-21 00:36:55 +00007212 const HChar* opname, IROp op
sewardj008754b2004-12-08 14:37:10 +00007213 )
7214{
7215 /* First we need to get the old G value and patch the low 64 bits
7216 of the E operand into it. Then apply op and write back to G. */
7217 HChar dis_buf[50];
7218 Int alen;
7219 IRTemp addr;
7220 UChar rm = getIByte(delta);
7221 IRTemp oldG0 = newTemp(Ity_V128);
7222 IRTemp oldG1 = newTemp(Ity_V128);
7223
7224 assign( oldG0, getXMMReg(gregOfRM(rm)) );
7225
7226 if (epartIsReg(rm)) {
7227 assign( oldG1,
sewardjf0c1c582005-02-07 23:47:38 +00007228 binop( Iop_SetV128lo64,
sewardj008754b2004-12-08 14:37:10 +00007229 mkexpr(oldG0),
7230 getXMMRegLane64(eregOfRM(rm), 0)) );
7231 putXMMReg( gregOfRM(rm), unop(op, mkexpr(oldG1)) );
7232 DIP("%s %s,%s\n", opname,
7233 nameXMMReg(eregOfRM(rm)),
7234 nameXMMReg(gregOfRM(rm)) );
7235 return delta+1;
7236 } else {
7237 addr = disAMode ( &alen, sorb, delta, dis_buf );
7238 assign( oldG1,
sewardjf0c1c582005-02-07 23:47:38 +00007239 binop( Iop_SetV128lo64,
sewardj008754b2004-12-08 14:37:10 +00007240 mkexpr(oldG0),
7241 loadLE(Ity_I64, mkexpr(addr)) ));
7242 putXMMReg( gregOfRM(rm), unop(op, mkexpr(oldG1)) );
7243 DIP("%s %s,%s\n", opname,
7244 dis_buf,
7245 nameXMMReg(gregOfRM(rm)) );
7246 return delta+alen;
7247 }
7248}
7249
sewardj164f9272004-12-09 00:39:32 +00007250
7251/* SSE integer binary operation:
7252 G = G `op` E (eLeft == False)
7253 G = E `op` G (eLeft == True)
7254*/
7255static UInt dis_SSEint_E_to_G(
sewardj52d04912005-07-03 00:52:48 +00007256 UChar sorb, Int delta,
florian55085f82012-11-21 00:36:55 +00007257 const HChar* opname, IROp op,
sewardj164f9272004-12-09 00:39:32 +00007258 Bool eLeft
7259 )
7260{
7261 HChar dis_buf[50];
7262 Int alen;
7263 IRTemp addr;
7264 UChar rm = getIByte(delta);
7265 IRExpr* gpart = getXMMReg(gregOfRM(rm));
7266 IRExpr* epart = NULL;
7267 if (epartIsReg(rm)) {
7268 epart = getXMMReg(eregOfRM(rm));
7269 DIP("%s %s,%s\n", opname,
7270 nameXMMReg(eregOfRM(rm)),
7271 nameXMMReg(gregOfRM(rm)) );
7272 delta += 1;
7273 } else {
7274 addr = disAMode ( &alen, sorb, delta, dis_buf );
7275 epart = loadLE(Ity_V128, mkexpr(addr));
7276 DIP("%s %s,%s\n", opname,
7277 dis_buf,
7278 nameXMMReg(gregOfRM(rm)) );
7279 delta += alen;
7280 }
7281 putXMMReg( gregOfRM(rm),
7282 eLeft ? binop(op, epart, gpart)
7283 : binop(op, gpart, epart) );
7284 return delta;
7285}
7286
7287
sewardjfd226452004-12-07 19:02:18 +00007288/* Helper for doing SSE FP comparisons. */
sewardj0bd7ce62004-12-05 02:47:40 +00007289
sewardj1e6ad742004-12-02 16:16:11 +00007290static void findSSECmpOp ( Bool* needNot, IROp* op,
7291 Int imm8, Bool all_lanes, Int sz )
7292{
7293 imm8 &= 7;
7294 *needNot = False;
7295 *op = Iop_INVALID;
7296 if (imm8 >= 4) {
7297 *needNot = True;
7298 imm8 -= 4;
7299 }
7300
7301 if (sz == 4 && all_lanes) {
7302 switch (imm8) {
7303 case 0: *op = Iop_CmpEQ32Fx4; return;
7304 case 1: *op = Iop_CmpLT32Fx4; return;
7305 case 2: *op = Iop_CmpLE32Fx4; return;
7306 case 3: *op = Iop_CmpUN32Fx4; return;
7307 default: break;
7308 }
7309 }
7310 if (sz == 4 && !all_lanes) {
7311 switch (imm8) {
7312 case 0: *op = Iop_CmpEQ32F0x4; return;
7313 case 1: *op = Iop_CmpLT32F0x4; return;
7314 case 2: *op = Iop_CmpLE32F0x4; return;
7315 case 3: *op = Iop_CmpUN32F0x4; return;
7316 default: break;
7317 }
7318 }
sewardjfd226452004-12-07 19:02:18 +00007319 if (sz == 8 && all_lanes) {
7320 switch (imm8) {
7321 case 0: *op = Iop_CmpEQ64Fx2; return;
7322 case 1: *op = Iop_CmpLT64Fx2; return;
7323 case 2: *op = Iop_CmpLE64Fx2; return;
7324 case 3: *op = Iop_CmpUN64Fx2; return;
7325 default: break;
7326 }
7327 }
7328 if (sz == 8 && !all_lanes) {
7329 switch (imm8) {
7330 case 0: *op = Iop_CmpEQ64F0x2; return;
7331 case 1: *op = Iop_CmpLT64F0x2; return;
7332 case 2: *op = Iop_CmpLE64F0x2; return;
7333 case 3: *op = Iop_CmpUN64F0x2; return;
7334 default: break;
7335 }
sewardj1e6ad742004-12-02 16:16:11 +00007336 }
7337 vpanic("findSSECmpOp(x86,guest)");
7338}
7339
sewardj33c69e52006-01-01 17:15:19 +00007340/* Handles SSE 32F/64F comparisons. */
sewardj129b3d92004-12-05 15:42:05 +00007341
sewardj52d04912005-07-03 00:52:48 +00007342static UInt dis_SSEcmp_E_to_G ( UChar sorb, Int delta,
florian55085f82012-11-21 00:36:55 +00007343 const HChar* opname, Bool all_lanes, Int sz )
sewardj1e6ad742004-12-02 16:16:11 +00007344{
7345 HChar dis_buf[50];
7346 Int alen, imm8;
7347 IRTemp addr;
7348 Bool needNot = False;
7349 IROp op = Iop_INVALID;
7350 IRTemp plain = newTemp(Ity_V128);
7351 UChar rm = getIByte(delta);
7352 UShort mask = 0;
7353 vassert(sz == 4 || sz == 8);
7354 if (epartIsReg(rm)) {
7355 imm8 = getIByte(delta+1);
7356 findSSECmpOp(&needNot, &op, imm8, all_lanes, sz);
7357 assign( plain, binop(op, getXMMReg(gregOfRM(rm)),
7358 getXMMReg(eregOfRM(rm))) );
7359 delta += 2;
7360 DIP("%s $%d,%s,%s\n", opname,
florianb1737742015-08-03 16:03:13 +00007361 imm8,
sewardj1e6ad742004-12-02 16:16:11 +00007362 nameXMMReg(eregOfRM(rm)),
7363 nameXMMReg(gregOfRM(rm)) );
7364 } else {
7365 addr = disAMode ( &alen, sorb, delta, dis_buf );
7366 imm8 = getIByte(delta+alen);
7367 findSSECmpOp(&needNot, &op, imm8, all_lanes, sz);
sewardj33c69e52006-01-01 17:15:19 +00007368 assign( plain,
7369 binop(
7370 op,
7371 getXMMReg(gregOfRM(rm)),
7372 all_lanes ? loadLE(Ity_V128, mkexpr(addr))
7373 : sz == 8 ? unop( Iop_64UtoV128, loadLE(Ity_I64, mkexpr(addr)))
7374 : /*sz==4*/ unop( Iop_32UtoV128, loadLE(Ity_I32, mkexpr(addr)))
7375 )
7376 );
sewardj1e6ad742004-12-02 16:16:11 +00007377 delta += alen+1;
7378 DIP("%s $%d,%s,%s\n", opname,
florianb1737742015-08-03 16:03:13 +00007379 imm8,
sewardj1e6ad742004-12-02 16:16:11 +00007380 dis_buf,
7381 nameXMMReg(gregOfRM(rm)) );
7382 }
7383
sewardj2e383862004-12-12 16:46:47 +00007384 if (needNot && all_lanes) {
7385 putXMMReg( gregOfRM(rm),
sewardjf0c1c582005-02-07 23:47:38 +00007386 unop(Iop_NotV128, mkexpr(plain)) );
sewardj2e383862004-12-12 16:46:47 +00007387 }
7388 else
7389 if (needNot && !all_lanes) {
sewardj9b45b482005-02-07 01:42:18 +00007390 mask = toUShort( sz==4 ? 0x000F : 0x00FF );
sewardj2e383862004-12-12 16:46:47 +00007391 putXMMReg( gregOfRM(rm),
sewardjf0c1c582005-02-07 23:47:38 +00007392 binop(Iop_XorV128, mkexpr(plain), mkV128(mask)) );
sewardj2e383862004-12-12 16:46:47 +00007393 }
7394 else {
7395 putXMMReg( gregOfRM(rm), mkexpr(plain) );
7396 }
sewardj1e6ad742004-12-02 16:16:11 +00007397
sewardj1e6ad742004-12-02 16:16:11 +00007398 return delta;
7399}
7400
sewardjb9fa69b2004-12-09 23:25:14 +00007401
7402/* Vector by scalar shift of G by the amount specified at the bottom
7403 of E. */
7404
sewardj52d04912005-07-03 00:52:48 +00007405static UInt dis_SSE_shiftG_byE ( UChar sorb, Int delta,
florian55085f82012-11-21 00:36:55 +00007406 const HChar* opname, IROp op )
sewardjb9fa69b2004-12-09 23:25:14 +00007407{
7408 HChar dis_buf[50];
7409 Int alen, size;
7410 IRTemp addr;
7411 Bool shl, shr, sar;
7412 UChar rm = getIByte(delta);
7413 IRTemp g0 = newTemp(Ity_V128);
7414 IRTemp g1 = newTemp(Ity_V128);
7415 IRTemp amt = newTemp(Ity_I32);
7416 IRTemp amt8 = newTemp(Ity_I8);
7417 if (epartIsReg(rm)) {
7418 assign( amt, getXMMRegLane32(eregOfRM(rm), 0) );
7419 DIP("%s %s,%s\n", opname,
7420 nameXMMReg(eregOfRM(rm)),
7421 nameXMMReg(gregOfRM(rm)) );
7422 delta++;
7423 } else {
7424 addr = disAMode ( &alen, sorb, delta, dis_buf );
7425 assign( amt, loadLE(Ity_I32, mkexpr(addr)) );
7426 DIP("%s %s,%s\n", opname,
7427 dis_buf,
7428 nameXMMReg(gregOfRM(rm)) );
7429 delta += alen;
7430 }
7431 assign( g0, getXMMReg(gregOfRM(rm)) );
7432 assign( amt8, unop(Iop_32to8, mkexpr(amt)) );
7433
7434 shl = shr = sar = False;
7435 size = 0;
7436 switch (op) {
7437 case Iop_ShlN16x8: shl = True; size = 32; break;
7438 case Iop_ShlN32x4: shl = True; size = 32; break;
7439 case Iop_ShlN64x2: shl = True; size = 64; break;
7440 case Iop_SarN16x8: sar = True; size = 16; break;
7441 case Iop_SarN32x4: sar = True; size = 32; break;
7442 case Iop_ShrN16x8: shr = True; size = 16; break;
7443 case Iop_ShrN32x4: shr = True; size = 32; break;
7444 case Iop_ShrN64x2: shr = True; size = 64; break;
7445 default: vassert(0);
7446 }
7447
7448 if (shl || shr) {
7449 assign(
7450 g1,
florian99dd03e2013-01-29 03:56:06 +00007451 IRExpr_ITE(
sewardj009230b2013-01-26 11:47:55 +00007452 binop(Iop_CmpLT32U,mkexpr(amt),mkU32(size)),
florian99dd03e2013-01-29 03:56:06 +00007453 binop(op, mkexpr(g0), mkexpr(amt8)),
7454 mkV128(0x0000)
sewardjb9fa69b2004-12-09 23:25:14 +00007455 )
7456 );
7457 } else
7458 if (sar) {
7459 assign(
7460 g1,
florian99dd03e2013-01-29 03:56:06 +00007461 IRExpr_ITE(
sewardj009230b2013-01-26 11:47:55 +00007462 binop(Iop_CmpLT32U,mkexpr(amt),mkU32(size)),
florian99dd03e2013-01-29 03:56:06 +00007463 binop(op, mkexpr(g0), mkexpr(amt8)),
7464 binop(op, mkexpr(g0), mkU8(size-1))
sewardjb9fa69b2004-12-09 23:25:14 +00007465 )
7466 );
7467 } else {
sewardjba89f4c2005-04-07 17:31:27 +00007468 /*NOTREACHED*/
sewardjb9fa69b2004-12-09 23:25:14 +00007469 vassert(0);
7470 }
7471
7472 putXMMReg( gregOfRM(rm), mkexpr(g1) );
7473 return delta;
7474}
7475
7476
7477/* Vector by scalar shift of E by an immediate byte. */
7478
sewardj38a3f862005-01-13 15:06:51 +00007479static
florian55085f82012-11-21 00:36:55 +00007480UInt dis_SSE_shiftE_imm ( Int delta, const HChar* opname, IROp op )
sewardjb9fa69b2004-12-09 23:25:14 +00007481{
7482 Bool shl, shr, sar;
7483 UChar rm = getIByte(delta);
sewardj38a3f862005-01-13 15:06:51 +00007484 IRTemp e0 = newTemp(Ity_V128);
7485 IRTemp e1 = newTemp(Ity_V128);
sewardjb9fa69b2004-12-09 23:25:14 +00007486 UChar amt, size;
7487 vassert(epartIsReg(rm));
7488 vassert(gregOfRM(rm) == 2
7489 || gregOfRM(rm) == 4 || gregOfRM(rm) == 6);
sewardj2d49b432005-02-01 00:37:06 +00007490 amt = getIByte(delta+1);
sewardjb9fa69b2004-12-09 23:25:14 +00007491 delta += 2;
7492 DIP("%s $%d,%s\n", opname,
7493 (Int)amt,
7494 nameXMMReg(eregOfRM(rm)) );
sewardj38a3f862005-01-13 15:06:51 +00007495 assign( e0, getXMMReg(eregOfRM(rm)) );
sewardjb9fa69b2004-12-09 23:25:14 +00007496
7497 shl = shr = sar = False;
7498 size = 0;
7499 switch (op) {
7500 case Iop_ShlN16x8: shl = True; size = 16; break;
7501 case Iop_ShlN32x4: shl = True; size = 32; break;
7502 case Iop_ShlN64x2: shl = True; size = 64; break;
7503 case Iop_SarN16x8: sar = True; size = 16; break;
7504 case Iop_SarN32x4: sar = True; size = 32; break;
7505 case Iop_ShrN16x8: shr = True; size = 16; break;
7506 case Iop_ShrN32x4: shr = True; size = 32; break;
7507 case Iop_ShrN64x2: shr = True; size = 64; break;
7508 default: vassert(0);
7509 }
7510
7511 if (shl || shr) {
sewardjba89f4c2005-04-07 17:31:27 +00007512 assign( e1, amt >= size
7513 ? mkV128(0x0000)
7514 : binop(op, mkexpr(e0), mkU8(amt))
7515 );
sewardjb9fa69b2004-12-09 23:25:14 +00007516 } else
7517 if (sar) {
sewardjba89f4c2005-04-07 17:31:27 +00007518 assign( e1, amt >= size
7519 ? binop(op, mkexpr(e0), mkU8(size-1))
7520 : binop(op, mkexpr(e0), mkU8(amt))
7521 );
sewardjb9fa69b2004-12-09 23:25:14 +00007522 } else {
sewardjba89f4c2005-04-07 17:31:27 +00007523 /*NOTREACHED*/
sewardjb9fa69b2004-12-09 23:25:14 +00007524 vassert(0);
7525 }
7526
sewardj38a3f862005-01-13 15:06:51 +00007527 putXMMReg( eregOfRM(rm), mkexpr(e1) );
sewardjb9fa69b2004-12-09 23:25:14 +00007528 return delta;
7529}
7530
7531
sewardjc1e7dfc2004-12-05 19:29:45 +00007532/* Get the current SSE rounding mode. */
sewardjc9a65702004-07-07 16:32:57 +00007533
sewardj4cb918d2004-12-03 19:43:31 +00007534static IRExpr* /* :: Ity_I32 */ get_sse_roundingmode ( void )
7535{
7536 return binop( Iop_And32,
7537 IRExpr_Get( OFFB_SSEROUND, Ity_I32 ),
7538 mkU32(3) );
7539}
7540
sewardj636ad762004-12-07 11:16:04 +00007541static void put_sse_roundingmode ( IRExpr* sseround )
7542{
sewardjdd40fdf2006-12-24 02:20:24 +00007543 vassert(typeOfIRExpr(irsb->tyenv, sseround) == Ity_I32);
sewardj636ad762004-12-07 11:16:04 +00007544 stmt( IRStmt_Put( OFFB_SSEROUND, sseround ) );
7545}
7546
sewardjc1e7dfc2004-12-05 19:29:45 +00007547/* Break a 128-bit value up into four 32-bit ints. */
7548
7549static void breakup128to32s ( IRTemp t128,
7550 /*OUTs*/
7551 IRTemp* t3, IRTemp* t2,
7552 IRTemp* t1, IRTemp* t0 )
7553{
7554 IRTemp hi64 = newTemp(Ity_I64);
7555 IRTemp lo64 = newTemp(Ity_I64);
sewardjf0c1c582005-02-07 23:47:38 +00007556 assign( hi64, unop(Iop_V128HIto64, mkexpr(t128)) );
7557 assign( lo64, unop(Iop_V128to64, mkexpr(t128)) );
sewardjc1e7dfc2004-12-05 19:29:45 +00007558
7559 vassert(t0 && *t0 == IRTemp_INVALID);
7560 vassert(t1 && *t1 == IRTemp_INVALID);
7561 vassert(t2 && *t2 == IRTemp_INVALID);
7562 vassert(t3 && *t3 == IRTemp_INVALID);
7563
7564 *t0 = newTemp(Ity_I32);
7565 *t1 = newTemp(Ity_I32);
7566 *t2 = newTemp(Ity_I32);
7567 *t3 = newTemp(Ity_I32);
7568 assign( *t0, unop(Iop_64to32, mkexpr(lo64)) );
7569 assign( *t1, unop(Iop_64HIto32, mkexpr(lo64)) );
7570 assign( *t2, unop(Iop_64to32, mkexpr(hi64)) );
7571 assign( *t3, unop(Iop_64HIto32, mkexpr(hi64)) );
7572}
7573
7574/* Construct a 128-bit value from four 32-bit ints. */
7575
7576static IRExpr* mk128from32s ( IRTemp t3, IRTemp t2,
7577 IRTemp t1, IRTemp t0 )
7578{
7579 return
sewardjf0c1c582005-02-07 23:47:38 +00007580 binop( Iop_64HLtoV128,
sewardjc1e7dfc2004-12-05 19:29:45 +00007581 binop(Iop_32HLto64, mkexpr(t3), mkexpr(t2)),
7582 binop(Iop_32HLto64, mkexpr(t1), mkexpr(t0))
7583 );
7584}
7585
sewardjb9fa69b2004-12-09 23:25:14 +00007586/* Break a 64-bit value up into four 16-bit ints. */
7587
7588static void breakup64to16s ( IRTemp t64,
7589 /*OUTs*/
7590 IRTemp* t3, IRTemp* t2,
7591 IRTemp* t1, IRTemp* t0 )
7592{
7593 IRTemp hi32 = newTemp(Ity_I32);
7594 IRTemp lo32 = newTemp(Ity_I32);
7595 assign( hi32, unop(Iop_64HIto32, mkexpr(t64)) );
7596 assign( lo32, unop(Iop_64to32, mkexpr(t64)) );
7597
7598 vassert(t0 && *t0 == IRTemp_INVALID);
7599 vassert(t1 && *t1 == IRTemp_INVALID);
7600 vassert(t2 && *t2 == IRTemp_INVALID);
7601 vassert(t3 && *t3 == IRTemp_INVALID);
7602
7603 *t0 = newTemp(Ity_I16);
7604 *t1 = newTemp(Ity_I16);
7605 *t2 = newTemp(Ity_I16);
7606 *t3 = newTemp(Ity_I16);
7607 assign( *t0, unop(Iop_32to16, mkexpr(lo32)) );
7608 assign( *t1, unop(Iop_32HIto16, mkexpr(lo32)) );
7609 assign( *t2, unop(Iop_32to16, mkexpr(hi32)) );
7610 assign( *t3, unop(Iop_32HIto16, mkexpr(hi32)) );
7611}
7612
7613/* Construct a 64-bit value from four 16-bit ints. */
7614
7615static IRExpr* mk64from16s ( IRTemp t3, IRTemp t2,
7616 IRTemp t1, IRTemp t0 )
7617{
7618 return
7619 binop( Iop_32HLto64,
7620 binop(Iop_16HLto32, mkexpr(t3), mkexpr(t2)),
7621 binop(Iop_16HLto32, mkexpr(t1), mkexpr(t0))
7622 );
7623}
7624
sewardj0e9a0f52008-01-04 01:22:41 +00007625/* Generate IR to set the guest %EFLAGS from the pushfl-format image
7626 in the given 32-bit temporary. The flags that are set are: O S Z A
7627 C P D ID AC.
7628
7629 In all cases, code to set AC is generated. However, VEX actually
7630 ignores the AC value and so can optionally emit an emulation
7631 warning when it is enabled. In this routine, an emulation warning
7632 is only emitted if emit_AC_emwarn is True, in which case
7633 next_insn_EIP must be correct (this allows for correct code
7634 generation for popfl/popfw). If emit_AC_emwarn is False,
7635 next_insn_EIP is unimportant (this allows for easy if kludgey code
7636 generation for IRET.) */
7637
7638static
7639void set_EFLAGS_from_value ( IRTemp t1,
7640 Bool emit_AC_emwarn,
7641 Addr32 next_insn_EIP )
7642{
7643 vassert(typeOfIRTemp(irsb->tyenv,t1) == Ity_I32);
7644
7645 /* t1 is the flag word. Mask out everything except OSZACP and set
7646 the flags thunk to X86G_CC_OP_COPY. */
7647 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(X86G_CC_OP_COPY) ));
7648 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
7649 stmt( IRStmt_Put( OFFB_CC_DEP1,
7650 binop(Iop_And32,
7651 mkexpr(t1),
7652 mkU32( X86G_CC_MASK_C | X86G_CC_MASK_P
7653 | X86G_CC_MASK_A | X86G_CC_MASK_Z
7654 | X86G_CC_MASK_S| X86G_CC_MASK_O )
7655 )
7656 )
7657 );
7658 /* Set NDEP even though it isn't used. This makes redundant-PUT
7659 elimination of previous stores to this field work better. */
7660 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
7661
7662 /* Also need to set the D flag, which is held in bit 10 of t1.
7663 If zero, put 1 in OFFB_DFLAG, else -1 in OFFB_DFLAG. */
7664 stmt( IRStmt_Put(
7665 OFFB_DFLAG,
florian99dd03e2013-01-29 03:56:06 +00007666 IRExpr_ITE(
sewardj009230b2013-01-26 11:47:55 +00007667 unop(Iop_32to1,
sewardj0e9a0f52008-01-04 01:22:41 +00007668 binop(Iop_And32,
7669 binop(Iop_Shr32, mkexpr(t1), mkU8(10)),
7670 mkU32(1))),
florian99dd03e2013-01-29 03:56:06 +00007671 mkU32(0xFFFFFFFF),
7672 mkU32(1)))
sewardj0e9a0f52008-01-04 01:22:41 +00007673 );
7674
7675 /* Set the ID flag */
7676 stmt( IRStmt_Put(
7677 OFFB_IDFLAG,
florian99dd03e2013-01-29 03:56:06 +00007678 IRExpr_ITE(
sewardj009230b2013-01-26 11:47:55 +00007679 unop(Iop_32to1,
sewardj0e9a0f52008-01-04 01:22:41 +00007680 binop(Iop_And32,
7681 binop(Iop_Shr32, mkexpr(t1), mkU8(21)),
7682 mkU32(1))),
florian99dd03e2013-01-29 03:56:06 +00007683 mkU32(1),
7684 mkU32(0)))
sewardj0e9a0f52008-01-04 01:22:41 +00007685 );
7686
7687 /* And set the AC flag. If setting it 1 to, possibly emit an
7688 emulation warning. */
7689 stmt( IRStmt_Put(
7690 OFFB_ACFLAG,
florian99dd03e2013-01-29 03:56:06 +00007691 IRExpr_ITE(
sewardj009230b2013-01-26 11:47:55 +00007692 unop(Iop_32to1,
sewardj0e9a0f52008-01-04 01:22:41 +00007693 binop(Iop_And32,
7694 binop(Iop_Shr32, mkexpr(t1), mkU8(18)),
7695 mkU32(1))),
florian99dd03e2013-01-29 03:56:06 +00007696 mkU32(1),
7697 mkU32(0)))
sewardj0e9a0f52008-01-04 01:22:41 +00007698 );
7699
7700 if (emit_AC_emwarn) {
7701 put_emwarn( mkU32(EmWarn_X86_acFlag) );
7702 stmt(
7703 IRStmt_Exit(
7704 binop( Iop_CmpNE32,
7705 binop(Iop_And32, mkexpr(t1), mkU32(1<<18)),
7706 mkU32(0) ),
7707 Ijk_EmWarn,
sewardjc6f970f2012-04-02 21:54:49 +00007708 IRConst_U32( next_insn_EIP ),
7709 OFFB_EIP
sewardj0e9a0f52008-01-04 01:22:41 +00007710 )
7711 );
7712 }
7713}
7714
sewardj4cb918d2004-12-03 19:43:31 +00007715
sewardj150c9cd2008-02-09 01:16:02 +00007716/* Helper for the SSSE3 (not SSE3) PMULHRSW insns. Given two 64-bit
7717 values (aa,bb), computes, for each of the 4 16-bit lanes:
7718
7719 (((aa_lane *s32 bb_lane) >>u 14) + 1) >>u 1
7720*/
7721static IRExpr* dis_PMULHRSW_helper ( IRExpr* aax, IRExpr* bbx )
7722{
7723 IRTemp aa = newTemp(Ity_I64);
7724 IRTemp bb = newTemp(Ity_I64);
7725 IRTemp aahi32s = newTemp(Ity_I64);
7726 IRTemp aalo32s = newTemp(Ity_I64);
7727 IRTemp bbhi32s = newTemp(Ity_I64);
7728 IRTemp bblo32s = newTemp(Ity_I64);
7729 IRTemp rHi = newTemp(Ity_I64);
7730 IRTemp rLo = newTemp(Ity_I64);
7731 IRTemp one32x2 = newTemp(Ity_I64);
7732 assign(aa, aax);
7733 assign(bb, bbx);
7734 assign( aahi32s,
7735 binop(Iop_SarN32x2,
7736 binop(Iop_InterleaveHI16x4, mkexpr(aa), mkexpr(aa)),
7737 mkU8(16) ));
7738 assign( aalo32s,
7739 binop(Iop_SarN32x2,
7740 binop(Iop_InterleaveLO16x4, mkexpr(aa), mkexpr(aa)),
7741 mkU8(16) ));
7742 assign( bbhi32s,
7743 binop(Iop_SarN32x2,
7744 binop(Iop_InterleaveHI16x4, mkexpr(bb), mkexpr(bb)),
7745 mkU8(16) ));
7746 assign( bblo32s,
7747 binop(Iop_SarN32x2,
7748 binop(Iop_InterleaveLO16x4, mkexpr(bb), mkexpr(bb)),
7749 mkU8(16) ));
7750 assign(one32x2, mkU64( (1ULL << 32) + 1 ));
7751 assign(
7752 rHi,
7753 binop(
7754 Iop_ShrN32x2,
7755 binop(
7756 Iop_Add32x2,
7757 binop(
7758 Iop_ShrN32x2,
7759 binop(Iop_Mul32x2, mkexpr(aahi32s), mkexpr(bbhi32s)),
7760 mkU8(14)
7761 ),
7762 mkexpr(one32x2)
7763 ),
7764 mkU8(1)
7765 )
7766 );
7767 assign(
7768 rLo,
7769 binop(
7770 Iop_ShrN32x2,
7771 binop(
7772 Iop_Add32x2,
7773 binop(
7774 Iop_ShrN32x2,
7775 binop(Iop_Mul32x2, mkexpr(aalo32s), mkexpr(bblo32s)),
7776 mkU8(14)
7777 ),
7778 mkexpr(one32x2)
7779 ),
7780 mkU8(1)
7781 )
7782 );
7783 return
7784 binop(Iop_CatEvenLanes16x4, mkexpr(rHi), mkexpr(rLo));
7785}
7786
7787/* Helper for the SSSE3 (not SSE3) PSIGN{B,W,D} insns. Given two 64-bit
7788 values (aa,bb), computes, for each lane:
7789
7790 if aa_lane < 0 then - bb_lane
7791 else if aa_lane > 0 then bb_lane
7792 else 0
7793*/
7794static IRExpr* dis_PSIGN_helper ( IRExpr* aax, IRExpr* bbx, Int laneszB )
7795{
7796 IRTemp aa = newTemp(Ity_I64);
7797 IRTemp bb = newTemp(Ity_I64);
7798 IRTemp zero = newTemp(Ity_I64);
7799 IRTemp bbNeg = newTemp(Ity_I64);
7800 IRTemp negMask = newTemp(Ity_I64);
7801 IRTemp posMask = newTemp(Ity_I64);
7802 IROp opSub = Iop_INVALID;
7803 IROp opCmpGTS = Iop_INVALID;
7804
7805 switch (laneszB) {
7806 case 1: opSub = Iop_Sub8x8; opCmpGTS = Iop_CmpGT8Sx8; break;
7807 case 2: opSub = Iop_Sub16x4; opCmpGTS = Iop_CmpGT16Sx4; break;
7808 case 4: opSub = Iop_Sub32x2; opCmpGTS = Iop_CmpGT32Sx2; break;
7809 default: vassert(0);
7810 }
7811
7812 assign( aa, aax );
7813 assign( bb, bbx );
7814 assign( zero, mkU64(0) );
7815 assign( bbNeg, binop(opSub, mkexpr(zero), mkexpr(bb)) );
7816 assign( negMask, binop(opCmpGTS, mkexpr(zero), mkexpr(aa)) );
7817 assign( posMask, binop(opCmpGTS, mkexpr(aa), mkexpr(zero)) );
7818
7819 return
7820 binop(Iop_Or64,
7821 binop(Iop_And64, mkexpr(bb), mkexpr(posMask)),
7822 binop(Iop_And64, mkexpr(bbNeg), mkexpr(negMask)) );
7823
7824}
7825
7826/* Helper for the SSSE3 (not SSE3) PABS{B,W,D} insns. Given a 64-bit
7827 value aa, computes, for each lane
7828
7829 if aa < 0 then -aa else aa
7830
7831 Note that the result is interpreted as unsigned, so that the
7832 absolute value of the most negative signed input can be
7833 represented.
7834*/
7835static IRExpr* dis_PABS_helper ( IRExpr* aax, Int laneszB )
7836{
7837 IRTemp aa = newTemp(Ity_I64);
7838 IRTemp zero = newTemp(Ity_I64);
7839 IRTemp aaNeg = newTemp(Ity_I64);
7840 IRTemp negMask = newTemp(Ity_I64);
7841 IRTemp posMask = newTemp(Ity_I64);
7842 IROp opSub = Iop_INVALID;
7843 IROp opSarN = Iop_INVALID;
7844
7845 switch (laneszB) {
7846 case 1: opSub = Iop_Sub8x8; opSarN = Iop_SarN8x8; break;
7847 case 2: opSub = Iop_Sub16x4; opSarN = Iop_SarN16x4; break;
7848 case 4: opSub = Iop_Sub32x2; opSarN = Iop_SarN32x2; break;
7849 default: vassert(0);
7850 }
7851
7852 assign( aa, aax );
7853 assign( negMask, binop(opSarN, mkexpr(aa), mkU8(8*laneszB-1)) );
7854 assign( posMask, unop(Iop_Not64, mkexpr(negMask)) );
7855 assign( zero, mkU64(0) );
7856 assign( aaNeg, binop(opSub, mkexpr(zero), mkexpr(aa)) );
7857 return
7858 binop(Iop_Or64,
7859 binop(Iop_And64, mkexpr(aa), mkexpr(posMask)),
7860 binop(Iop_And64, mkexpr(aaNeg), mkexpr(negMask)) );
7861}
7862
7863static IRExpr* dis_PALIGNR_XMM_helper ( IRTemp hi64,
7864 IRTemp lo64, Int byteShift )
7865{
7866 vassert(byteShift >= 1 && byteShift <= 7);
7867 return
7868 binop(Iop_Or64,
7869 binop(Iop_Shl64, mkexpr(hi64), mkU8(8*(8-byteShift))),
7870 binop(Iop_Shr64, mkexpr(lo64), mkU8(8*byteShift))
7871 );
7872}
7873
7874/* Generate a SIGSEGV followed by a restart of the current instruction
7875 if effective_addr is not 16-aligned. This is required behaviour
7876 for some SSE3 instructions and all 128-bit SSSE3 instructions.
7877 This assumes that guest_RIP_curr_instr is set correctly! */
7878static void gen_SEGV_if_not_16_aligned ( IRTemp effective_addr )
7879{
7880 stmt(
7881 IRStmt_Exit(
7882 binop(Iop_CmpNE32,
7883 binop(Iop_And32,mkexpr(effective_addr),mkU32(0xF)),
7884 mkU32(0)),
7885 Ijk_SigSEGV,
sewardjc6f970f2012-04-02 21:54:49 +00007886 IRConst_U32(guest_EIP_curr_instr),
7887 OFFB_EIP
sewardj150c9cd2008-02-09 01:16:02 +00007888 )
7889 );
7890}
7891
7892
sewardjc4356f02007-11-09 21:15:04 +00007893/* Helper for deciding whether a given insn (starting at the opcode
7894 byte) may validly be used with a LOCK prefix. The following insns
7895 may be used with LOCK when their destination operand is in memory.
sewardje9d8a262009-07-01 08:06:34 +00007896 AFAICS this is exactly the same for both 32-bit and 64-bit mode.
sewardjc4356f02007-11-09 21:15:04 +00007897
sewardje9d8a262009-07-01 08:06:34 +00007898 ADD 80 /0, 81 /0, 82 /0, 83 /0, 00, 01
7899 OR 80 /1, 81 /1, 82 /x, 83 /1, 08, 09
7900 ADC 80 /2, 81 /2, 82 /2, 83 /2, 10, 11
7901 SBB 81 /3, 81 /3, 82 /x, 83 /3, 18, 19
7902 AND 80 /4, 81 /4, 82 /x, 83 /4, 20, 21
7903 SUB 80 /5, 81 /5, 82 /x, 83 /5, 28, 29
7904 XOR 80 /6, 81 /6, 82 /x, 83 /6, 30, 31
sewardjc4356f02007-11-09 21:15:04 +00007905
7906 DEC FE /1, FF /1
7907 INC FE /0, FF /0
7908
7909 NEG F6 /3, F7 /3
7910 NOT F6 /2, F7 /2
7911
sewardje9d8a262009-07-01 08:06:34 +00007912 XCHG 86, 87
sewardjc4356f02007-11-09 21:15:04 +00007913
7914 BTC 0F BB, 0F BA /7
7915 BTR 0F B3, 0F BA /6
7916 BTS 0F AB, 0F BA /5
7917
7918 CMPXCHG 0F B0, 0F B1
7919 CMPXCHG8B 0F C7 /1
7920
7921 XADD 0F C0, 0F C1
sewardje9d8a262009-07-01 08:06:34 +00007922
7923 ------------------------------
7924
7925 80 /0 = addb $imm8, rm8
7926 81 /0 = addl $imm32, rm32 and addw $imm16, rm16
7927 82 /0 = addb $imm8, rm8
7928 83 /0 = addl $simm8, rm32 and addw $simm8, rm16
7929
7930 00 = addb r8, rm8
7931 01 = addl r32, rm32 and addw r16, rm16
7932
7933 Same for ADD OR ADC SBB AND SUB XOR
7934
7935 FE /1 = dec rm8
7936 FF /1 = dec rm32 and dec rm16
7937
7938 FE /0 = inc rm8
7939 FF /0 = inc rm32 and inc rm16
7940
7941 F6 /3 = neg rm8
7942 F7 /3 = neg rm32 and neg rm16
7943
7944 F6 /2 = not rm8
7945 F7 /2 = not rm32 and not rm16
7946
7947 0F BB = btcw r16, rm16 and btcl r32, rm32
7948 OF BA /7 = btcw $imm8, rm16 and btcw $imm8, rm32
7949
7950 Same for BTS, BTR
sewardjc4356f02007-11-09 21:15:04 +00007951*/
florian8462d112014-09-24 15:18:09 +00007952static Bool can_be_used_with_LOCK_prefix ( const UChar* opc )
sewardjc4356f02007-11-09 21:15:04 +00007953{
7954 switch (opc[0]) {
sewardje9d8a262009-07-01 08:06:34 +00007955 case 0x00: case 0x01: case 0x08: case 0x09:
7956 case 0x10: case 0x11: case 0x18: case 0x19:
7957 case 0x20: case 0x21: case 0x28: case 0x29:
7958 case 0x30: case 0x31:
7959 if (!epartIsReg(opc[1]))
7960 return True;
7961 break;
sewardjc4356f02007-11-09 21:15:04 +00007962
sewardje9d8a262009-07-01 08:06:34 +00007963 case 0x80: case 0x81: case 0x82: case 0x83:
7964 if (gregOfRM(opc[1]) >= 0 && gregOfRM(opc[1]) <= 6
7965 && !epartIsReg(opc[1]))
sewardjc4356f02007-11-09 21:15:04 +00007966 return True;
7967 break;
7968
7969 case 0xFE: case 0xFF:
sewardje9d8a262009-07-01 08:06:34 +00007970 if (gregOfRM(opc[1]) >= 0 && gregOfRM(opc[1]) <= 1
7971 && !epartIsReg(opc[1]))
sewardjc4356f02007-11-09 21:15:04 +00007972 return True;
7973 break;
7974
7975 case 0xF6: case 0xF7:
sewardje9d8a262009-07-01 08:06:34 +00007976 if (gregOfRM(opc[1]) >= 2 && gregOfRM(opc[1]) <= 3
7977 && !epartIsReg(opc[1]))
sewardjc4356f02007-11-09 21:15:04 +00007978 return True;
7979 break;
7980
7981 case 0x86: case 0x87:
sewardje9d8a262009-07-01 08:06:34 +00007982 if (!epartIsReg(opc[1]))
7983 return True;
7984 break;
sewardjc4356f02007-11-09 21:15:04 +00007985
7986 case 0x0F: {
7987 switch (opc[1]) {
7988 case 0xBB: case 0xB3: case 0xAB:
sewardje9d8a262009-07-01 08:06:34 +00007989 if (!epartIsReg(opc[2]))
7990 return True;
7991 break;
sewardjc4356f02007-11-09 21:15:04 +00007992 case 0xBA:
sewardje9d8a262009-07-01 08:06:34 +00007993 if (gregOfRM(opc[2]) >= 5 && gregOfRM(opc[2]) <= 7
7994 && !epartIsReg(opc[2]))
sewardjc4356f02007-11-09 21:15:04 +00007995 return True;
7996 break;
7997 case 0xB0: case 0xB1:
sewardje9d8a262009-07-01 08:06:34 +00007998 if (!epartIsReg(opc[2]))
7999 return True;
8000 break;
sewardjc4356f02007-11-09 21:15:04 +00008001 case 0xC7:
sewardje9d8a262009-07-01 08:06:34 +00008002 if (gregOfRM(opc[2]) == 1 && !epartIsReg(opc[2]) )
sewardjc4356f02007-11-09 21:15:04 +00008003 return True;
8004 break;
8005 case 0xC0: case 0xC1:
sewardje9d8a262009-07-01 08:06:34 +00008006 if (!epartIsReg(opc[2]))
8007 return True;
8008 break;
sewardjc4356f02007-11-09 21:15:04 +00008009 default:
8010 break;
8011 } /* switch (opc[1]) */
8012 break;
8013 }
8014
8015 default:
8016 break;
8017 } /* switch (opc[0]) */
8018
8019 return False;
8020}
8021
sewardj021f6b42012-08-23 23:39:49 +00008022static IRTemp math_BSWAP ( IRTemp t1, IRType ty )
8023{
8024 IRTemp t2 = newTemp(ty);
8025 if (ty == Ity_I32) {
8026 assign( t2,
8027 binop(
8028 Iop_Or32,
8029 binop(Iop_Shl32, mkexpr(t1), mkU8(24)),
8030 binop(
8031 Iop_Or32,
8032 binop(Iop_And32, binop(Iop_Shl32, mkexpr(t1), mkU8(8)),
8033 mkU32(0x00FF0000)),
8034 binop(Iop_Or32,
8035 binop(Iop_And32, binop(Iop_Shr32, mkexpr(t1), mkU8(8)),
8036 mkU32(0x0000FF00)),
8037 binop(Iop_And32, binop(Iop_Shr32, mkexpr(t1), mkU8(24)),
8038 mkU32(0x000000FF) )
8039 )))
8040 );
8041 return t2;
8042 }
8043 if (ty == Ity_I16) {
8044 assign(t2,
8045 binop(Iop_Or16,
8046 binop(Iop_Shl16, mkexpr(t1), mkU8(8)),
8047 binop(Iop_Shr16, mkexpr(t1), mkU8(8)) ));
8048 return t2;
8049 }
8050 vassert(0);
8051 /*NOTREACHED*/
8052 return IRTemp_INVALID;
8053}
sewardjc4356f02007-11-09 21:15:04 +00008054
sewardjc9a65702004-07-07 16:32:57 +00008055/*------------------------------------------------------------*/
sewardjce70a5c2004-10-18 14:09:54 +00008056/*--- Disassemble a single instruction ---*/
sewardjc9a65702004-07-07 16:32:57 +00008057/*------------------------------------------------------------*/
8058
sewardje9d8a262009-07-01 08:06:34 +00008059/* Disassemble a single instruction into IR. The instruction is
8060 located in host memory at &guest_code[delta]. *expect_CAS is set
8061 to True if the resulting IR is expected to contain an IRCAS
8062 statement, and False if it's not expected to. This makes it
8063 possible for the caller of disInstr_X86_WRK to check that
8064 LOCK-prefixed instructions are at least plausibly translated, in
8065 that it becomes possible to check that a (validly) LOCK-prefixed
8066 instruction generates a translation containing an IRCAS, and
8067 instructions without LOCK prefixes don't generate translations
8068 containing an IRCAS.
8069*/
sewardj9e6491a2005-07-02 19:24:10 +00008070static
sewardje9d8a262009-07-01 08:06:34 +00008071DisResult disInstr_X86_WRK (
8072 /*OUT*/Bool* expect_CAS,
florianbeac5302014-12-31 12:09:38 +00008073 Bool (*resteerOkFn) ( /*opaque*/void*, Addr ),
sewardj984d9b12010-01-15 10:53:21 +00008074 Bool resteerCisOk,
sewardjc716aea2006-01-17 01:48:46 +00008075 void* callback_opaque,
sewardj9e6491a2005-07-02 19:24:10 +00008076 Long delta64,
floriancacba8e2014-12-15 18:58:07 +00008077 const VexArchInfo* archinfo,
8078 const VexAbiInfo* vbi,
sewardj442e51a2012-12-06 18:08:04 +00008079 Bool sigill_diag
sewardj9e6491a2005-07-02 19:24:10 +00008080 )
sewardjc9a65702004-07-07 16:32:57 +00008081{
sewardjce70a5c2004-10-18 14:09:54 +00008082 IRType ty;
sewardjb5452082004-12-04 20:33:02 +00008083 IRTemp addr, t0, t1, t2, t3, t4, t5, t6;
sewardjce70a5c2004-10-18 14:09:54 +00008084 Int alen;
sewardjc4356f02007-11-09 21:15:04 +00008085 UChar opc, modrm, abyte, pre;
sewardjce70a5c2004-10-18 14:09:54 +00008086 UInt d32;
sewardjc9a43662004-11-30 18:51:59 +00008087 HChar dis_buf[50];
sewardjc4356f02007-11-09 21:15:04 +00008088 Int am_sz, d_sz, n_prefixes;
sewardj9e6491a2005-07-02 19:24:10 +00008089 DisResult dres;
florian8462d112014-09-24 15:18:09 +00008090 const UChar* insn; /* used in SSE decoders */
sewardjce70a5c2004-10-18 14:09:54 +00008091
sewardj9e6491a2005-07-02 19:24:10 +00008092 /* The running delta */
8093 Int delta = (Int)delta64;
8094
sewardjc9a65702004-07-07 16:32:57 +00008095 /* Holds eip at the start of the insn, so that we can print
8096 consistent error messages for unimplemented insns. */
sewardj9e6491a2005-07-02 19:24:10 +00008097 Int delta_start = delta;
sewardjc9a65702004-07-07 16:32:57 +00008098
8099 /* sz denotes the nominal data-op size of the insn; we change it to
8100 2 if an 0x66 prefix is seen */
8101 Int sz = 4;
8102
8103 /* sorb holds the segment-override-prefix byte, if any. Zero if no
8104 prefix has been seen, else one of {0x26, 0x3E, 0x64, 0x65}
8105 indicating the prefix. */
8106 UChar sorb = 0;
8107
sewardjc4356f02007-11-09 21:15:04 +00008108 /* Gets set to True if a LOCK prefix is seen. */
8109 Bool pfx_lock = False;
8110
sewardj9e6491a2005-07-02 19:24:10 +00008111 /* Set result defaults. */
sewardjc6f970f2012-04-02 21:54:49 +00008112 dres.whatNext = Dis_Continue;
8113 dres.len = 0;
8114 dres.continueAt = 0;
8115 dres.jk_StopHere = Ijk_INVALID;
sewardjce70a5c2004-10-18 14:09:54 +00008116
sewardje9d8a262009-07-01 08:06:34 +00008117 *expect_CAS = False;
8118
sewardjb5452082004-12-04 20:33:02 +00008119 addr = t0 = t1 = t2 = t3 = t4 = t5 = t6 = IRTemp_INVALID;
sewardjc9a65702004-07-07 16:32:57 +00008120
sewardje9d8a262009-07-01 08:06:34 +00008121 vassert(guest_EIP_bbstart + delta == guest_EIP_curr_instr);
sewardj9e6491a2005-07-02 19:24:10 +00008122 DIP("\t0x%x: ", guest_EIP_bbstart+delta);
8123
sewardjce02aa72006-01-12 12:27:58 +00008124 /* Spot "Special" instructions (see comment at top of file). */
sewardj750f4072004-07-26 22:39:11 +00008125 {
florian8462d112014-09-24 15:18:09 +00008126 const UChar* code = guest_code + delta;
sewardjce02aa72006-01-12 12:27:58 +00008127 /* Spot the 12-byte preamble:
8128 C1C703 roll $3, %edi
8129 C1C70D roll $13, %edi
8130 C1C71D roll $29, %edi
8131 C1C713 roll $19, %edi
sewardj750f4072004-07-26 22:39:11 +00008132 */
sewardjce02aa72006-01-12 12:27:58 +00008133 if (code[ 0] == 0xC1 && code[ 1] == 0xC7 && code[ 2] == 0x03 &&
8134 code[ 3] == 0xC1 && code[ 4] == 0xC7 && code[ 5] == 0x0D &&
8135 code[ 6] == 0xC1 && code[ 7] == 0xC7 && code[ 8] == 0x1D &&
8136 code[ 9] == 0xC1 && code[10] == 0xC7 && code[11] == 0x13) {
8137 /* Got a "Special" instruction preamble. Which one is it? */
8138 if (code[12] == 0x87 && code[13] == 0xDB /* xchgl %ebx,%ebx */) {
8139 /* %EDX = client_request ( %EAX ) */
8140 DIP("%%edx = client_request ( %%eax )\n");
8141 delta += 14;
sewardjc6f970f2012-04-02 21:54:49 +00008142 jmp_lit(&dres, Ijk_ClientReq, guest_EIP_bbstart+delta);
8143 vassert(dres.whatNext == Dis_StopHere);
sewardjce02aa72006-01-12 12:27:58 +00008144 goto decode_success;
8145 }
8146 else
8147 if (code[12] == 0x87 && code[13] == 0xC9 /* xchgl %ecx,%ecx */) {
8148 /* %EAX = guest_NRADDR */
8149 DIP("%%eax = guest_NRADDR\n");
8150 delta += 14;
8151 putIReg(4, R_EAX, IRExpr_Get( OFFB_NRADDR, Ity_I32 ));
8152 goto decode_success;
8153 }
8154 else
8155 if (code[12] == 0x87 && code[13] == 0xD2 /* xchgl %edx,%edx */) {
8156 /* call-noredir *%EAX */
8157 DIP("call-noredir *%%eax\n");
8158 delta += 14;
8159 t1 = newTemp(Ity_I32);
8160 assign(t1, getIReg(4,R_EAX));
8161 t2 = newTemp(Ity_I32);
8162 assign(t2, binop(Iop_Sub32, getIReg(4,R_ESP), mkU32(4)));
8163 putIReg(4, R_ESP, mkexpr(t2));
8164 storeLE( mkexpr(t2), mkU32(guest_EIP_bbstart+delta));
sewardjc6f970f2012-04-02 21:54:49 +00008165 jmp_treg(&dres, Ijk_NoRedir, t1);
8166 vassert(dres.whatNext == Dis_StopHere);
sewardjce02aa72006-01-12 12:27:58 +00008167 goto decode_success;
8168 }
florian2245ce92012-08-28 16:49:30 +00008169 else
8170 if (code[12] == 0x87 && code[13] == 0xFF /* xchgl %edi,%edi */) {
8171 /* IR injection */
8172 DIP("IR injection\n");
8173 vex_inject_ir(irsb, Iend_LE);
8174
8175 // Invalidate the current insn. The reason is that the IRop we're
8176 // injecting here can change. In which case the translation has to
8177 // be redone. For ease of handling, we simply invalidate all the
8178 // time.
sewardj05f5e012014-05-04 10:52:11 +00008179 stmt(IRStmt_Put(OFFB_CMSTART, mkU32(guest_EIP_curr_instr)));
8180 stmt(IRStmt_Put(OFFB_CMLEN, mkU32(14)));
florian2245ce92012-08-28 16:49:30 +00008181
8182 delta += 14;
8183
8184 stmt( IRStmt_Put( OFFB_EIP, mkU32(guest_EIP_bbstart + delta) ) );
8185 dres.whatNext = Dis_StopHere;
sewardj05f5e012014-05-04 10:52:11 +00008186 dres.jk_StopHere = Ijk_InvalICache;
florian2245ce92012-08-28 16:49:30 +00008187 goto decode_success;
8188 }
sewardjce02aa72006-01-12 12:27:58 +00008189 /* We don't know what it is. */
8190 goto decode_failure;
8191 /*NOTREACHED*/
sewardj750f4072004-07-26 22:39:11 +00008192 }
8193 }
sewardjc9a65702004-07-07 16:32:57 +00008194
sewardjc4356f02007-11-09 21:15:04 +00008195 /* Handle a couple of weird-ass NOPs that have been observed in the
8196 wild. */
8197 {
florian8462d112014-09-24 15:18:09 +00008198 const UChar* code = guest_code + delta;
sewardjc4356f02007-11-09 21:15:04 +00008199 /* Sun's JVM 1.5.0 uses the following as a NOP:
8200 26 2E 64 65 90 %es:%cs:%fs:%gs:nop */
8201 if (code[0] == 0x26 && code[1] == 0x2E && code[2] == 0x64
8202 && code[3] == 0x65 && code[4] == 0x90) {
8203 DIP("%%es:%%cs:%%fs:%%gs:nop\n");
8204 delta += 5;
8205 goto decode_success;
sewardjbb3f52d2005-01-07 14:14:50 +00008206 }
sewardjdeceef82010-05-03 21:58:22 +00008207 /* Don't barf on recent binutils padding,
8208 all variants of which are: nopw %cs:0x0(%eax,%eax,1)
8209 66 2e 0f 1f 84 00 00 00 00 00
8210 66 66 2e 0f 1f 84 00 00 00 00 00
8211 66 66 66 2e 0f 1f 84 00 00 00 00 00
8212 66 66 66 66 2e 0f 1f 84 00 00 00 00 00
8213 66 66 66 66 66 2e 0f 1f 84 00 00 00 00 00
8214 66 66 66 66 66 66 2e 0f 1f 84 00 00 00 00 00
8215 */
8216 if (code[0] == 0x66) {
8217 Int data16_cnt;
8218 for (data16_cnt = 1; data16_cnt < 6; data16_cnt++)
8219 if (code[data16_cnt] != 0x66)
8220 break;
8221 if (code[data16_cnt] == 0x2E && code[data16_cnt + 1] == 0x0F
8222 && code[data16_cnt + 2] == 0x1F && code[data16_cnt + 3] == 0x84
8223 && code[data16_cnt + 4] == 0x00 && code[data16_cnt + 5] == 0x00
8224 && code[data16_cnt + 6] == 0x00 && code[data16_cnt + 7] == 0x00
8225 && code[data16_cnt + 8] == 0x00 ) {
8226 DIP("nopw %%cs:0x0(%%eax,%%eax,1)\n");
8227 delta += 9 + data16_cnt;
8228 goto decode_success;
8229 }
sewardjce4a2822005-01-07 13:25:28 +00008230 }
sewardjc4356f02007-11-09 21:15:04 +00008231 }
sewardjbb3f52d2005-01-07 14:14:50 +00008232
sewardjc4356f02007-11-09 21:15:04 +00008233 /* Normal instruction handling starts here. */
sewardjc9a65702004-07-07 16:32:57 +00008234
sewardjc4356f02007-11-09 21:15:04 +00008235 /* Deal with some but not all prefixes:
8236 66(oso)
8237 F0(lock)
8238 2E(cs:) 3E(ds:) 26(es:) 64(fs:) 65(gs:) 36(ss:)
8239 Not dealt with (left in place):
8240 F2 F3
8241 */
8242 n_prefixes = 0;
8243 while (True) {
8244 if (n_prefixes > 7) goto decode_failure;
8245 pre = getUChar(delta);
8246 switch (pre) {
8247 case 0x66:
8248 sz = 2;
8249 break;
8250 case 0xF0:
8251 pfx_lock = True;
sewardje9d8a262009-07-01 08:06:34 +00008252 *expect_CAS = True;
sewardjc4356f02007-11-09 21:15:04 +00008253 break;
8254 case 0x3E: /* %DS: */
8255 case 0x26: /* %ES: */
8256 case 0x64: /* %FS: */
8257 case 0x65: /* %GS: */
8258 if (sorb != 0)
8259 goto decode_failure; /* only one seg override allowed */
8260 sorb = pre;
8261 break;
8262 case 0x2E: { /* %CS: */
8263 /* 2E prefix on a conditional branch instruction is a
8264 branch-prediction hint, which can safely be ignored. */
sewardjc9a65702004-07-07 16:32:57 +00008265 UChar op1 = getIByte(delta+1);
8266 UChar op2 = getIByte(delta+2);
8267 if ((op1 >= 0x70 && op1 <= 0x7F)
8268 || (op1 == 0xE3)
8269 || (op1 == 0x0F && op2 >= 0x80 && op2 <= 0x8F)) {
sewardj4dfb1992005-03-13 18:56:28 +00008270 if (0) vex_printf("vex x86->IR: ignoring branch hint\n");
sewardjc4356f02007-11-09 21:15:04 +00008271 } else {
8272 /* All other CS override cases are not handled */
8273 goto decode_failure;
sewardjc9a65702004-07-07 16:32:57 +00008274 }
sewardjc4356f02007-11-09 21:15:04 +00008275 break;
sewardjc9a65702004-07-07 16:32:57 +00008276 }
sewardjc4356f02007-11-09 21:15:04 +00008277 case 0x36: /* %SS: */
8278 /* SS override cases are not handled */
8279 goto decode_failure;
8280 default:
8281 goto not_a_prefix;
8282 }
8283 n_prefixes++;
8284 delta++;
sewardjc9a65702004-07-07 16:32:57 +00008285 }
8286
sewardjc4356f02007-11-09 21:15:04 +00008287 not_a_prefix:
8288
8289 /* Now we should be looking at the primary opcode byte or the
8290 leading F2 or F3. Check that any LOCK prefix is actually
8291 allowed. */
8292
sewardjc4356f02007-11-09 21:15:04 +00008293 if (pfx_lock) {
florian8462d112014-09-24 15:18:09 +00008294 if (can_be_used_with_LOCK_prefix( &guest_code[delta] )) {
sewardjc4356f02007-11-09 21:15:04 +00008295 DIP("lock ");
8296 } else {
sewardje9d8a262009-07-01 08:06:34 +00008297 *expect_CAS = False;
sewardjc4356f02007-11-09 21:15:04 +00008298 goto decode_failure;
8299 }
8300 }
8301
8302
sewardjc9a43662004-11-30 18:51:59 +00008303 /* ---------------------------------------------------- */
8304 /* --- The SSE decoder. --- */
8305 /* ---------------------------------------------------- */
8306
sewardj4cb918d2004-12-03 19:43:31 +00008307 /* What did I do to deserve SSE ? Perhaps I was really bad in a
8308 previous life? */
8309
sewardj9df271d2004-12-31 22:37:42 +00008310 /* Note, this doesn't handle SSE2 or SSE3. That is handled in a
8311 later section, further on. */
8312
florian8462d112014-09-24 15:18:09 +00008313 insn = &guest_code[delta];
sewardja0e83b02005-01-06 12:36:38 +00008314
8315 /* Treat fxsave specially. It should be doable even on an SSE0
8316 (Pentium-II class) CPU. Hence be prepared to handle it on
8317 any subarchitecture variant.
8318 */
8319
8320 /* 0F AE /0 = FXSAVE m512 -- write x87 and SSE state to memory */
8321 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xAE
8322 && !epartIsReg(insn[2]) && gregOfRM(insn[2]) == 0) {
sewardj9a036bf2005-03-14 18:19:08 +00008323 IRDirty* d;
sewardja0e83b02005-01-06 12:36:38 +00008324 modrm = getIByte(delta+2);
8325 vassert(sz == 4);
8326 vassert(!epartIsReg(modrm));
8327
8328 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8329 delta += 2+alen;
sewardjec993de2011-01-21 18:02:54 +00008330 gen_SEGV_if_not_16_aligned(addr);
sewardja0e83b02005-01-06 12:36:38 +00008331
sewardj33dd31b2005-01-08 18:17:32 +00008332 DIP("fxsave %s\n", dis_buf);
sewardja0e83b02005-01-06 12:36:38 +00008333
8334 /* Uses dirty helper:
8335 void x86g_do_FXSAVE ( VexGuestX86State*, UInt ) */
sewardj9a036bf2005-03-14 18:19:08 +00008336 d = unsafeIRDirty_0_N (
8337 0/*regparms*/,
8338 "x86g_dirtyhelper_FXSAVE",
8339 &x86g_dirtyhelper_FXSAVE,
florian90419562013-08-15 20:54:52 +00008340 mkIRExprVec_2( IRExpr_BBPTR(), mkexpr(addr) )
sewardj9a036bf2005-03-14 18:19:08 +00008341 );
sewardja0e83b02005-01-06 12:36:38 +00008342
8343 /* declare we're writing memory */
8344 d->mFx = Ifx_Write;
8345 d->mAddr = mkexpr(addr);
sewardjc9069f22012-06-01 16:09:50 +00008346 d->mSize = 464; /* according to recent Intel docs */
sewardja0e83b02005-01-06 12:36:38 +00008347
8348 /* declare we're reading guest state */
8349 d->nFxState = 7;
sewardjc9069f22012-06-01 16:09:50 +00008350 vex_bzero(&d->fxState, sizeof(d->fxState));
sewardja0e83b02005-01-06 12:36:38 +00008351
8352 d->fxState[0].fx = Ifx_Read;
8353 d->fxState[0].offset = OFFB_FTOP;
8354 d->fxState[0].size = sizeof(UInt);
8355
8356 d->fxState[1].fx = Ifx_Read;
8357 d->fxState[1].offset = OFFB_FPREGS;
8358 d->fxState[1].size = 8 * sizeof(ULong);
8359
8360 d->fxState[2].fx = Ifx_Read;
8361 d->fxState[2].offset = OFFB_FPTAGS;
8362 d->fxState[2].size = 8 * sizeof(UChar);
8363
8364 d->fxState[3].fx = Ifx_Read;
8365 d->fxState[3].offset = OFFB_FPROUND;
8366 d->fxState[3].size = sizeof(UInt);
8367
8368 d->fxState[4].fx = Ifx_Read;
8369 d->fxState[4].offset = OFFB_FC3210;
8370 d->fxState[4].size = sizeof(UInt);
8371
8372 d->fxState[5].fx = Ifx_Read;
8373 d->fxState[5].offset = OFFB_XMM0;
8374 d->fxState[5].size = 8 * sizeof(U128);
8375
8376 d->fxState[6].fx = Ifx_Read;
8377 d->fxState[6].offset = OFFB_SSEROUND;
8378 d->fxState[6].size = sizeof(UInt);
8379
8380 /* Be paranoid ... this assertion tries to ensure the 8 %xmm
8381 images are packed back-to-back. If not, the value of
8382 d->fxState[5].size is wrong. */
8383 vassert(16 == sizeof(U128));
8384 vassert(OFFB_XMM7 == (OFFB_XMM0 + 7 * 16));
8385
8386 stmt( IRStmt_Dirty(d) );
8387
8388 goto decode_success;
8389 }
8390
sewardj3800e2d2008-05-09 13:24:43 +00008391 /* 0F AE /1 = FXRSTOR m512 -- read x87 and SSE state from memory */
8392 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xAE
8393 && !epartIsReg(insn[2]) && gregOfRM(insn[2]) == 1) {
8394 IRDirty* d;
8395 modrm = getIByte(delta+2);
8396 vassert(sz == 4);
8397 vassert(!epartIsReg(modrm));
8398
8399 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8400 delta += 2+alen;
sewardjec993de2011-01-21 18:02:54 +00008401 gen_SEGV_if_not_16_aligned(addr);
sewardj3800e2d2008-05-09 13:24:43 +00008402
8403 DIP("fxrstor %s\n", dis_buf);
8404
8405 /* Uses dirty helper:
florian6ef84be2012-08-26 03:20:07 +00008406 VexEmNote x86g_do_FXRSTOR ( VexGuestX86State*, UInt )
sewardjec993de2011-01-21 18:02:54 +00008407 NOTE:
florian6ef84be2012-08-26 03:20:07 +00008408 the VexEmNote value is simply ignored (unlike for FRSTOR)
sewardjec993de2011-01-21 18:02:54 +00008409 */
sewardj3800e2d2008-05-09 13:24:43 +00008410 d = unsafeIRDirty_0_N (
8411 0/*regparms*/,
8412 "x86g_dirtyhelper_FXRSTOR",
8413 &x86g_dirtyhelper_FXRSTOR,
florian90419562013-08-15 20:54:52 +00008414 mkIRExprVec_2( IRExpr_BBPTR(), mkexpr(addr) )
sewardj3800e2d2008-05-09 13:24:43 +00008415 );
sewardj3800e2d2008-05-09 13:24:43 +00008416
8417 /* declare we're reading memory */
8418 d->mFx = Ifx_Read;
8419 d->mAddr = mkexpr(addr);
sewardjc9069f22012-06-01 16:09:50 +00008420 d->mSize = 464; /* according to recent Intel docs */
sewardj3800e2d2008-05-09 13:24:43 +00008421
8422 /* declare we're writing guest state */
8423 d->nFxState = 7;
sewardjc9069f22012-06-01 16:09:50 +00008424 vex_bzero(&d->fxState, sizeof(d->fxState));
sewardj3800e2d2008-05-09 13:24:43 +00008425
8426 d->fxState[0].fx = Ifx_Write;
8427 d->fxState[0].offset = OFFB_FTOP;
8428 d->fxState[0].size = sizeof(UInt);
8429
8430 d->fxState[1].fx = Ifx_Write;
8431 d->fxState[1].offset = OFFB_FPREGS;
8432 d->fxState[1].size = 8 * sizeof(ULong);
8433
8434 d->fxState[2].fx = Ifx_Write;
8435 d->fxState[2].offset = OFFB_FPTAGS;
8436 d->fxState[2].size = 8 * sizeof(UChar);
8437
8438 d->fxState[3].fx = Ifx_Write;
8439 d->fxState[3].offset = OFFB_FPROUND;
8440 d->fxState[3].size = sizeof(UInt);
8441
8442 d->fxState[4].fx = Ifx_Write;
8443 d->fxState[4].offset = OFFB_FC3210;
8444 d->fxState[4].size = sizeof(UInt);
8445
8446 d->fxState[5].fx = Ifx_Write;
8447 d->fxState[5].offset = OFFB_XMM0;
8448 d->fxState[5].size = 8 * sizeof(U128);
8449
8450 d->fxState[6].fx = Ifx_Write;
8451 d->fxState[6].offset = OFFB_SSEROUND;
8452 d->fxState[6].size = sizeof(UInt);
8453
8454 /* Be paranoid ... this assertion tries to ensure the 8 %xmm
8455 images are packed back-to-back. If not, the value of
8456 d->fxState[5].size is wrong. */
8457 vassert(16 == sizeof(U128));
8458 vassert(OFFB_XMM7 == (OFFB_XMM0 + 7 * 16));
8459
8460 stmt( IRStmt_Dirty(d) );
8461
8462 goto decode_success;
8463 }
8464
sewardja0e83b02005-01-06 12:36:38 +00008465 /* ------ SSE decoder main ------ */
8466
sewardj9df271d2004-12-31 22:37:42 +00008467 /* Skip parts of the decoder which don't apply given the stated
8468 guest subarchitecture. */
sewardj5117ce12006-01-27 21:20:15 +00008469 if (archinfo->hwcaps == 0/*baseline, no sse at all*/)
sewardj9df271d2004-12-31 22:37:42 +00008470 goto after_sse_decoders;
mjw6c65c122013-08-27 10:19:03 +00008471
8472 /* With mmxext only some extended MMX instructions are recognized.
8473 The mmxext instructions are MASKMOVQ MOVNTQ PAVGB PAVGW PMAXSW
8474 PMAXUB PMINSW PMINUB PMULHUW PSADBW PSHUFW PEXTRW PINSRW PMOVMSKB
8475 PREFETCHNTA PREFETCHT0 PREFETCHT1 PREFETCHT2 SFENCE
8476
8477 http://support.amd.com/us/Embedded_TechDocs/22466.pdf
8478 https://en.wikipedia.org/wiki/3DNow!#3DNow.21_extensions */
8479
8480 if (archinfo->hwcaps == VEX_HWCAPS_X86_MMXEXT/*integer only sse1 subset*/)
8481 goto mmxext;
8482
sewardj9df271d2004-12-31 22:37:42 +00008483 /* Otherwise we must be doing sse1 or sse2, so we can at least try
8484 for SSE1 here. */
sewardjc9a43662004-11-30 18:51:59 +00008485
sewardjc9a43662004-11-30 18:51:59 +00008486 /* 0F 58 = ADDPS -- add 32Fx4 from R/M to R */
sewardj636ad762004-12-07 11:16:04 +00008487 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x58) {
sewardj129b3d92004-12-05 15:42:05 +00008488 delta = dis_SSE_E_to_G_all( sorb, delta+2, "addps", Iop_Add32Fx4 );
sewardjc9a43662004-11-30 18:51:59 +00008489 goto decode_success;
8490 }
8491
sewardj1e6ad742004-12-02 16:16:11 +00008492 /* F3 0F 58 = ADDSS -- add 32F0x4 from R/M to R */
8493 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x58) {
8494 vassert(sz == 4);
sewardj129b3d92004-12-05 15:42:05 +00008495 delta = dis_SSE_E_to_G_lo32( sorb, delta+3, "addss", Iop_Add32F0x4 );
sewardj1e6ad742004-12-02 16:16:11 +00008496 goto decode_success;
8497 }
8498
8499 /* 0F 55 = ANDNPS -- G = (not G) and E */
sewardj636ad762004-12-07 11:16:04 +00008500 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x55) {
sewardjf0c1c582005-02-07 23:47:38 +00008501 delta = dis_SSE_E_to_G_all_invG( sorb, delta+2, "andnps", Iop_AndV128 );
sewardj1e6ad742004-12-02 16:16:11 +00008502 goto decode_success;
8503 }
8504
8505 /* 0F 54 = ANDPS -- G = G and E */
sewardj636ad762004-12-07 11:16:04 +00008506 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x54) {
sewardjf0c1c582005-02-07 23:47:38 +00008507 delta = dis_SSE_E_to_G_all( sorb, delta+2, "andps", Iop_AndV128 );
sewardj1e6ad742004-12-02 16:16:11 +00008508 goto decode_success;
8509 }
8510
8511 /* 0F C2 = CMPPS -- 32Fx4 comparison from R/M to R */
sewardj636ad762004-12-07 11:16:04 +00008512 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xC2) {
sewardj1e6ad742004-12-02 16:16:11 +00008513 delta = dis_SSEcmp_E_to_G( sorb, delta+2, "cmpps", True, 4 );
8514 goto decode_success;
8515 }
8516
8517 /* F3 0F C2 = CMPSS -- 32F0x4 comparison from R/M to R */
8518 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0xC2) {
8519 vassert(sz == 4);
8520 delta = dis_SSEcmp_E_to_G( sorb, delta+3, "cmpss", False, 4 );
8521 goto decode_success;
8522 }
sewardjc9a43662004-11-30 18:51:59 +00008523
sewardjfd226452004-12-07 19:02:18 +00008524 /* 0F 2F = COMISS -- 32F0x4 comparison G,E, and set ZCP */
sewardjc1e7dfc2004-12-05 19:29:45 +00008525 /* 0F 2E = UCOMISS -- 32F0x4 comparison G,E, and set ZCP */
sewardjfd226452004-12-07 19:02:18 +00008526 if (sz == 4 && insn[0] == 0x0F && (insn[1] == 0x2F || insn[1] == 0x2E)) {
sewardj67e002d2004-12-02 18:16:33 +00008527 IRTemp argL = newTemp(Ity_F32);
8528 IRTemp argR = newTemp(Ity_F32);
sewardj67e002d2004-12-02 18:16:33 +00008529 modrm = getIByte(delta+2);
8530 if (epartIsReg(modrm)) {
8531 assign( argR, getXMMRegLane32F( eregOfRM(modrm), 0/*lowest lane*/ ) );
8532 delta += 2+1;
sewardjc1e7dfc2004-12-05 19:29:45 +00008533 DIP("[u]comiss %s,%s\n", nameXMMReg(eregOfRM(modrm)),
8534 nameXMMReg(gregOfRM(modrm)) );
sewardj67e002d2004-12-02 18:16:33 +00008535 } else {
8536 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8537 assign( argR, loadLE(Ity_F32, mkexpr(addr)) );
8538 delta += 2+alen;
sewardjc1e7dfc2004-12-05 19:29:45 +00008539 DIP("[u]comiss %s,%s\n", dis_buf,
8540 nameXMMReg(gregOfRM(modrm)) );
sewardj67e002d2004-12-02 18:16:33 +00008541 }
8542 assign( argL, getXMMRegLane32F( gregOfRM(modrm), 0/*lowest lane*/ ) );
8543
8544 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(X86G_CC_OP_COPY) ));
8545 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
8546 stmt( IRStmt_Put(
8547 OFFB_CC_DEP1,
8548 binop( Iop_And32,
8549 binop(Iop_CmpF64,
8550 unop(Iop_F32toF64,mkexpr(argL)),
8551 unop(Iop_F32toF64,mkexpr(argR))),
8552 mkU32(0x45)
8553 )));
sewardja3b7e3a2005-04-05 01:54:19 +00008554 /* Set NDEP even though it isn't used. This makes redundant-PUT
8555 elimination of previous stores to this field work better. */
8556 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
sewardj67e002d2004-12-02 18:16:33 +00008557 goto decode_success;
8558 }
sewardjc9a43662004-11-30 18:51:59 +00008559
sewardj4cb918d2004-12-03 19:43:31 +00008560 /* 0F 2A = CVTPI2PS -- convert 2 x I32 in mem/mmx to 2 x F32 in low
8561 half xmm */
sewardjfd226452004-12-07 19:02:18 +00008562 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x2A) {
sewardj4cb918d2004-12-03 19:43:31 +00008563 IRTemp arg64 = newTemp(Ity_I64);
8564 IRTemp rmode = newTemp(Ity_I32);
8565 vassert(sz == 4);
8566
8567 modrm = getIByte(delta+2);
sewardj4cb918d2004-12-03 19:43:31 +00008568 if (epartIsReg(modrm)) {
Elliott Hughesa0664b92017-04-18 17:46:52 -07008569 /* Only switch to MMX mode if the source is a MMX register.
8570 See comments on CVTPI2PD for details. Fixes #357059. */
8571 do_MMX_preamble();
sewardj4cb918d2004-12-03 19:43:31 +00008572 assign( arg64, getMMXReg(eregOfRM(modrm)) );
8573 delta += 2+1;
8574 DIP("cvtpi2ps %s,%s\n", nameMMXReg(eregOfRM(modrm)),
8575 nameXMMReg(gregOfRM(modrm)));
8576 } else {
8577 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8578 assign( arg64, loadLE(Ity_I64, mkexpr(addr)) );
8579 delta += 2+alen;
8580 DIP("cvtpi2ps %s,%s\n", dis_buf,
8581 nameXMMReg(gregOfRM(modrm)) );
8582 }
8583
8584 assign( rmode, get_sse_roundingmode() );
8585
8586 putXMMRegLane32F(
sewardj3bca9062004-12-04 14:36:09 +00008587 gregOfRM(modrm), 0,
8588 binop(Iop_F64toF32,
sewardj4cb918d2004-12-03 19:43:31 +00008589 mkexpr(rmode),
sewardj6c299f32009-12-31 18:00:12 +00008590 unop(Iop_I32StoF64,
sewardj3bca9062004-12-04 14:36:09 +00008591 unop(Iop_64to32, mkexpr(arg64)) )) );
sewardj4cb918d2004-12-03 19:43:31 +00008592
8593 putXMMRegLane32F(
8594 gregOfRM(modrm), 1,
sewardj3bca9062004-12-04 14:36:09 +00008595 binop(Iop_F64toF32,
sewardj4cb918d2004-12-03 19:43:31 +00008596 mkexpr(rmode),
sewardj6c299f32009-12-31 18:00:12 +00008597 unop(Iop_I32StoF64,
sewardj3bca9062004-12-04 14:36:09 +00008598 unop(Iop_64HIto32, mkexpr(arg64)) )) );
sewardj4cb918d2004-12-03 19:43:31 +00008599
8600 goto decode_success;
8601 }
8602
8603 /* F3 0F 2A = CVTSI2SS -- convert I32 in mem/ireg to F32 in low
8604 quarter xmm */
8605 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x2A) {
8606 IRTemp arg32 = newTemp(Ity_I32);
8607 IRTemp rmode = newTemp(Ity_I32);
8608 vassert(sz == 4);
8609
8610 modrm = getIByte(delta+3);
sewardj4cb918d2004-12-03 19:43:31 +00008611 if (epartIsReg(modrm)) {
8612 assign( arg32, getIReg(4, eregOfRM(modrm)) );
8613 delta += 3+1;
8614 DIP("cvtsi2ss %s,%s\n", nameIReg(4, eregOfRM(modrm)),
8615 nameXMMReg(gregOfRM(modrm)));
8616 } else {
8617 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
8618 assign( arg32, loadLE(Ity_I32, mkexpr(addr)) );
8619 delta += 3+alen;
8620 DIP("cvtsi2ss %s,%s\n", dis_buf,
8621 nameXMMReg(gregOfRM(modrm)) );
8622 }
8623
8624 assign( rmode, get_sse_roundingmode() );
8625
8626 putXMMRegLane32F(
sewardj3bca9062004-12-04 14:36:09 +00008627 gregOfRM(modrm), 0,
8628 binop(Iop_F64toF32,
8629 mkexpr(rmode),
sewardj6c299f32009-12-31 18:00:12 +00008630 unop(Iop_I32StoF64, mkexpr(arg32)) ) );
sewardj4cb918d2004-12-03 19:43:31 +00008631
8632 goto decode_success;
8633 }
8634
8635 /* 0F 2D = CVTPS2PI -- convert 2 x F32 in mem/low half xmm to 2 x
8636 I32 in mmx, according to prevailing SSE rounding mode */
8637 /* 0F 2C = CVTTPS2PI -- convert 2 x F32 in mem/low half xmm to 2 x
8638 I32 in mmx, rounding towards zero */
sewardjfd226452004-12-07 19:02:18 +00008639 if (sz == 4 && insn[0] == 0x0F && (insn[1] == 0x2D || insn[1] == 0x2C)) {
sewardj4cb918d2004-12-03 19:43:31 +00008640 IRTemp dst64 = newTemp(Ity_I64);
8641 IRTemp rmode = newTemp(Ity_I32);
8642 IRTemp f32lo = newTemp(Ity_F32);
8643 IRTemp f32hi = newTemp(Ity_F32);
sewardj2d49b432005-02-01 00:37:06 +00008644 Bool r2zero = toBool(insn[1] == 0x2C);
sewardj4cb918d2004-12-03 19:43:31 +00008645
8646 do_MMX_preamble();
8647 modrm = getIByte(delta+2);
8648
8649 if (epartIsReg(modrm)) {
8650 delta += 2+1;
8651 assign(f32lo, getXMMRegLane32F(eregOfRM(modrm), 0));
8652 assign(f32hi, getXMMRegLane32F(eregOfRM(modrm), 1));
8653 DIP("cvt%sps2pi %s,%s\n", r2zero ? "t" : "",
8654 nameXMMReg(eregOfRM(modrm)),
8655 nameMMXReg(gregOfRM(modrm)));
8656 } else {
8657 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8658 assign(f32lo, loadLE(Ity_F32, mkexpr(addr)));
8659 assign(f32hi, loadLE(Ity_F32, binop( Iop_Add32,
8660 mkexpr(addr),
8661 mkU32(4) )));
8662 delta += 2+alen;
8663 DIP("cvt%sps2pi %s,%s\n", r2zero ? "t" : "",
8664 dis_buf,
8665 nameMMXReg(gregOfRM(modrm)));
8666 }
8667
8668 if (r2zero) {
8669 assign(rmode, mkU32((UInt)Irrm_ZERO) );
8670 } else {
8671 assign( rmode, get_sse_roundingmode() );
8672 }
8673
8674 assign(
8675 dst64,
8676 binop( Iop_32HLto64,
sewardj6c299f32009-12-31 18:00:12 +00008677 binop( Iop_F64toI32S,
sewardj4cb918d2004-12-03 19:43:31 +00008678 mkexpr(rmode),
8679 unop( Iop_F32toF64, mkexpr(f32hi) ) ),
sewardj6c299f32009-12-31 18:00:12 +00008680 binop( Iop_F64toI32S,
sewardj4cb918d2004-12-03 19:43:31 +00008681 mkexpr(rmode),
8682 unop( Iop_F32toF64, mkexpr(f32lo) ) )
8683 )
8684 );
8685
8686 putMMXReg(gregOfRM(modrm), mkexpr(dst64));
8687 goto decode_success;
8688 }
8689
8690 /* F3 0F 2D = CVTSS2SI -- convert F32 in mem/low quarter xmm to
8691 I32 in ireg, according to prevailing SSE rounding mode */
8692 /* F3 0F 2C = CVTTSS2SI -- convert F32 in mem/low quarter xmm to
sewardj0b210442005-02-23 13:28:27 +00008693 I32 in ireg, rounding towards zero */
sewardj4cb918d2004-12-03 19:43:31 +00008694 if (insn[0] == 0xF3 && insn[1] == 0x0F
8695 && (insn[2] == 0x2D || insn[2] == 0x2C)) {
8696 IRTemp rmode = newTemp(Ity_I32);
8697 IRTemp f32lo = newTemp(Ity_F32);
sewardj2d49b432005-02-01 00:37:06 +00008698 Bool r2zero = toBool(insn[2] == 0x2C);
sewardj4cb918d2004-12-03 19:43:31 +00008699 vassert(sz == 4);
8700
sewardj4cb918d2004-12-03 19:43:31 +00008701 modrm = getIByte(delta+3);
sewardj4cb918d2004-12-03 19:43:31 +00008702 if (epartIsReg(modrm)) {
8703 delta += 3+1;
8704 assign(f32lo, getXMMRegLane32F(eregOfRM(modrm), 0));
8705 DIP("cvt%sss2si %s,%s\n", r2zero ? "t" : "",
8706 nameXMMReg(eregOfRM(modrm)),
8707 nameIReg(4, gregOfRM(modrm)));
8708 } else {
8709 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
8710 assign(f32lo, loadLE(Ity_F32, mkexpr(addr)));
8711 delta += 3+alen;
8712 DIP("cvt%sss2si %s,%s\n", r2zero ? "t" : "",
8713 dis_buf,
8714 nameIReg(4, gregOfRM(modrm)));
8715 }
8716
8717 if (r2zero) {
sewardj7df596b2004-12-06 14:29:12 +00008718 assign( rmode, mkU32((UInt)Irrm_ZERO) );
sewardj4cb918d2004-12-03 19:43:31 +00008719 } else {
8720 assign( rmode, get_sse_roundingmode() );
8721 }
8722
8723 putIReg(4, gregOfRM(modrm),
sewardj6c299f32009-12-31 18:00:12 +00008724 binop( Iop_F64toI32S,
sewardj4cb918d2004-12-03 19:43:31 +00008725 mkexpr(rmode),
8726 unop( Iop_F32toF64, mkexpr(f32lo) ) )
8727 );
8728
8729 goto decode_success;
8730 }
8731
sewardj176a59c2004-12-03 20:08:31 +00008732 /* 0F 5E = DIVPS -- div 32Fx4 from R/M to R */
sewardjfd226452004-12-07 19:02:18 +00008733 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x5E) {
sewardj129b3d92004-12-05 15:42:05 +00008734 delta = dis_SSE_E_to_G_all( sorb, delta+2, "divps", Iop_Div32Fx4 );
sewardj176a59c2004-12-03 20:08:31 +00008735 goto decode_success;
8736 }
8737
8738 /* F3 0F 5E = DIVSS -- div 32F0x4 from R/M to R */
8739 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x5E) {
8740 vassert(sz == 4);
sewardj129b3d92004-12-05 15:42:05 +00008741 delta = dis_SSE_E_to_G_lo32( sorb, delta+3, "divss", Iop_Div32F0x4 );
sewardj176a59c2004-12-03 20:08:31 +00008742 goto decode_success;
8743 }
8744
sewardj7df596b2004-12-06 14:29:12 +00008745 /* 0F AE /2 = LDMXCSR m32 -- load %mxcsr */
8746 if (insn[0] == 0x0F && insn[1] == 0xAE
8747 && !epartIsReg(insn[2]) && gregOfRM(insn[2]) == 2) {
8748
8749 IRTemp t64 = newTemp(Ity_I64);
8750 IRTemp ew = newTemp(Ity_I32);
8751
8752 modrm = getIByte(delta+2);
8753 vassert(!epartIsReg(modrm));
8754 vassert(sz == 4);
8755
8756 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8757 delta += 2+alen;
sewardj33dd31b2005-01-08 18:17:32 +00008758 DIP("ldmxcsr %s\n", dis_buf);
sewardj7df596b2004-12-06 14:29:12 +00008759
8760 /* The only thing we observe in %mxcsr is the rounding mode.
8761 Therefore, pass the 32-bit value (SSE native-format control
8762 word) to a clean helper, getting back a 64-bit value, the
8763 lower half of which is the SSEROUND value to store, and the
8764 upper half of which is the emulation-warning token which may
8765 be generated.
8766 */
8767 /* ULong x86h_check_ldmxcsr ( UInt ); */
8768 assign( t64, mkIRExprCCall(
8769 Ity_I64, 0/*regparms*/,
sewardj3bd6f3e2004-12-13 10:48:19 +00008770 "x86g_check_ldmxcsr",
8771 &x86g_check_ldmxcsr,
sewardj7df596b2004-12-06 14:29:12 +00008772 mkIRExprVec_1( loadLE(Ity_I32, mkexpr(addr)) )
8773 )
8774 );
8775
sewardj636ad762004-12-07 11:16:04 +00008776 put_sse_roundingmode( unop(Iop_64to32, mkexpr(t64)) );
sewardj7df596b2004-12-06 14:29:12 +00008777 assign( ew, unop(Iop_64HIto32, mkexpr(t64) ) );
8778 put_emwarn( mkexpr(ew) );
8779 /* Finally, if an emulation warning was reported, side-exit to
8780 the next insn, reporting the warning, so that Valgrind's
8781 dispatcher sees the warning. */
8782 stmt(
8783 IRStmt_Exit(
8784 binop(Iop_CmpNE32, mkexpr(ew), mkU32(0)),
8785 Ijk_EmWarn,
sewardjc6f970f2012-04-02 21:54:49 +00008786 IRConst_U32( ((Addr32)guest_EIP_bbstart)+delta),
8787 OFFB_EIP
sewardj7df596b2004-12-06 14:29:12 +00008788 )
8789 );
8790 goto decode_success;
8791 }
8792
mjw6c65c122013-08-27 10:19:03 +00008793
8794 /* mmxext sse1 subset starts here. mmxext only arches will parse
8795 only this subset of the sse1 instructions. */
8796 mmxext:
8797
sewardjd71ba832006-12-27 01:15:29 +00008798 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
8799 /* 0F F7 = MASKMOVQ -- 8x8 masked store */
8800 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xF7) {
8801 Bool ok = False;
8802 delta = dis_MMX( &ok, sorb, sz, delta+1 );
8803 if (!ok)
8804 goto decode_failure;
8805 goto decode_success;
8806 }
8807
sewardjc2feffc2004-12-08 12:31:22 +00008808 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
sewardj9636b442004-12-04 01:38:37 +00008809 /* 0F E7 = MOVNTQ -- for us, just a plain MMX store. Note, the
8810 Intel manual does not say anything about the usual business of
8811 the FP reg tags getting trashed whenever an MMX insn happens.
8812 So we just leave them alone.
8813 */
8814 if (insn[0] == 0x0F && insn[1] == 0xE7) {
8815 modrm = getIByte(delta+2);
sewardjc2feffc2004-12-08 12:31:22 +00008816 if (sz == 4 && !epartIsReg(modrm)) {
sewardj519d66f2004-12-15 11:57:58 +00008817 /* do_MMX_preamble(); Intel docs don't specify this */
sewardj9636b442004-12-04 01:38:37 +00008818 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8819 storeLE( mkexpr(addr), getMMXReg(gregOfRM(modrm)) );
8820 DIP("movntq %s,%s\n", dis_buf,
8821 nameMMXReg(gregOfRM(modrm)));
8822 delta += 2+alen;
8823 goto decode_success;
8824 }
8825 /* else fall through */
8826 }
8827
sewardj3bca9062004-12-04 14:36:09 +00008828 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
8829 /* 0F E0 = PAVGB -- 8x8 unsigned Packed Average, with rounding */
sewardj164f9272004-12-09 00:39:32 +00008830 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xE0) {
sewardjb5452082004-12-04 20:33:02 +00008831 do_MMX_preamble();
8832 delta = dis_MMXop_regmem_to_reg (
8833 sorb, delta+2, insn[1], "pavgb", False );
8834 goto decode_success;
sewardj3bca9062004-12-04 14:36:09 +00008835 }
8836
sewardjb5452082004-12-04 20:33:02 +00008837 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
8838 /* 0F E3 = PAVGW -- 16x4 unsigned Packed Average, with rounding */
sewardj164f9272004-12-09 00:39:32 +00008839 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xE3) {
sewardjb5452082004-12-04 20:33:02 +00008840 do_MMX_preamble();
8841 delta = dis_MMXop_regmem_to_reg (
8842 sorb, delta+2, insn[1], "pavgw", False );
8843 goto decode_success;
8844 }
8845
8846 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
8847 /* 0F C5 = PEXTRW -- extract 16-bit field from mmx(E) and put
8848 zero-extend of it in ireg(G). */
8849 if (insn[0] == 0x0F && insn[1] == 0xC5) {
8850 modrm = insn[2];
8851 if (sz == 4 && epartIsReg(modrm)) {
sewardjb9fa69b2004-12-09 23:25:14 +00008852 IRTemp sV = newTemp(Ity_I64);
8853 t5 = newTemp(Ity_I16);
sewardjb5452082004-12-04 20:33:02 +00008854 do_MMX_preamble();
sewardjb9fa69b2004-12-09 23:25:14 +00008855 assign(sV, getMMXReg(eregOfRM(modrm)));
8856 breakup64to16s( sV, &t3, &t2, &t1, &t0 );
sewardjb5452082004-12-04 20:33:02 +00008857 switch (insn[3] & 3) {
sewardjb9fa69b2004-12-09 23:25:14 +00008858 case 0: assign(t5, mkexpr(t0)); break;
8859 case 1: assign(t5, mkexpr(t1)); break;
8860 case 2: assign(t5, mkexpr(t2)); break;
8861 case 3: assign(t5, mkexpr(t3)); break;
sewardjba89f4c2005-04-07 17:31:27 +00008862 default: vassert(0); /*NOTREACHED*/
sewardjb5452082004-12-04 20:33:02 +00008863 }
sewardjb9fa69b2004-12-09 23:25:14 +00008864 putIReg(4, gregOfRM(modrm), unop(Iop_16Uto32, mkexpr(t5)));
sewardjb5452082004-12-04 20:33:02 +00008865 DIP("pextrw $%d,%s,%s\n",
8866 (Int)insn[3], nameMMXReg(eregOfRM(modrm)),
8867 nameIReg(4,gregOfRM(modrm)));
8868 delta += 4;
8869 goto decode_success;
8870 }
8871 /* else fall through */
8872 }
8873
8874 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
8875 /* 0F C4 = PINSRW -- get 16 bits from E(mem or low half ireg) and
8876 put it into the specified lane of mmx(G). */
sewardje5854d62004-12-09 03:44:34 +00008877 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xC4) {
8878 /* Use t0 .. t3 to hold the 4 original 16-bit lanes of the
8879 mmx reg. t4 is the new lane value. t5 is the original
8880 mmx value. t6 is the new mmx value. */
8881 Int lane;
sewardje5854d62004-12-09 03:44:34 +00008882 t4 = newTemp(Ity_I16);
8883 t5 = newTemp(Ity_I64);
8884 t6 = newTemp(Ity_I64);
8885 modrm = insn[2];
8886 do_MMX_preamble();
sewardjb5452082004-12-04 20:33:02 +00008887
sewardje5854d62004-12-09 03:44:34 +00008888 assign(t5, getMMXReg(gregOfRM(modrm)));
sewardjb9fa69b2004-12-09 23:25:14 +00008889 breakup64to16s( t5, &t3, &t2, &t1, &t0 );
sewardjb5452082004-12-04 20:33:02 +00008890
sewardje5854d62004-12-09 03:44:34 +00008891 if (epartIsReg(modrm)) {
8892 assign(t4, getIReg(2, eregOfRM(modrm)));
sewardjaac7e082005-03-17 14:03:46 +00008893 delta += 3+1;
8894 lane = insn[3+1-1];
florianb1737742015-08-03 16:03:13 +00008895 DIP("pinsrw $%d,%s,%s\n", lane,
sewardje5854d62004-12-09 03:44:34 +00008896 nameIReg(2,eregOfRM(modrm)),
8897 nameMMXReg(gregOfRM(modrm)));
8898 } else {
sewardj7420b092005-03-13 20:19:19 +00008899 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8900 delta += 3+alen;
8901 lane = insn[3+alen-1];
8902 assign(t4, loadLE(Ity_I16, mkexpr(addr)));
florianb1737742015-08-03 16:03:13 +00008903 DIP("pinsrw $%d,%s,%s\n", lane,
sewardj7420b092005-03-13 20:19:19 +00008904 dis_buf,
8905 nameMMXReg(gregOfRM(modrm)));
sewardjb5452082004-12-04 20:33:02 +00008906 }
sewardje5854d62004-12-09 03:44:34 +00008907
8908 switch (lane & 3) {
sewardjb9fa69b2004-12-09 23:25:14 +00008909 case 0: assign(t6, mk64from16s(t3,t2,t1,t4)); break;
8910 case 1: assign(t6, mk64from16s(t3,t2,t4,t0)); break;
8911 case 2: assign(t6, mk64from16s(t3,t4,t1,t0)); break;
8912 case 3: assign(t6, mk64from16s(t4,t2,t1,t0)); break;
sewardjba89f4c2005-04-07 17:31:27 +00008913 default: vassert(0); /*NOTREACHED*/
sewardje5854d62004-12-09 03:44:34 +00008914 }
8915 putMMXReg(gregOfRM(modrm), mkexpr(t6));
8916 goto decode_success;
sewardjb5452082004-12-04 20:33:02 +00008917 }
8918
8919 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
8920 /* 0F EE = PMAXSW -- 16x4 signed max */
sewardje5854d62004-12-09 03:44:34 +00008921 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xEE) {
sewardjb5452082004-12-04 20:33:02 +00008922 do_MMX_preamble();
8923 delta = dis_MMXop_regmem_to_reg (
8924 sorb, delta+2, insn[1], "pmaxsw", False );
8925 goto decode_success;
8926 }
8927
8928 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
8929 /* 0F DE = PMAXUB -- 8x8 unsigned max */
sewardje5854d62004-12-09 03:44:34 +00008930 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xDE) {
sewardjb5452082004-12-04 20:33:02 +00008931 do_MMX_preamble();
8932 delta = dis_MMXop_regmem_to_reg (
8933 sorb, delta+2, insn[1], "pmaxub", False );
8934 goto decode_success;
8935 }
8936
8937 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
8938 /* 0F EA = PMINSW -- 16x4 signed min */
sewardje5854d62004-12-09 03:44:34 +00008939 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xEA) {
sewardjb5452082004-12-04 20:33:02 +00008940 do_MMX_preamble();
8941 delta = dis_MMXop_regmem_to_reg (
8942 sorb, delta+2, insn[1], "pminsw", False );
8943 goto decode_success;
8944 }
8945
8946 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
8947 /* 0F DA = PMINUB -- 8x8 unsigned min */
sewardje5854d62004-12-09 03:44:34 +00008948 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xDA) {
sewardjb5452082004-12-04 20:33:02 +00008949 do_MMX_preamble();
8950 delta = dis_MMXop_regmem_to_reg (
8951 sorb, delta+2, insn[1], "pminub", False );
8952 goto decode_success;
8953 }
8954
8955 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
8956 /* 0F D7 = PMOVMSKB -- extract sign bits from each of 8 lanes in
sewardje13074c2012-11-08 10:57:08 +00008957 mmx(E), turn them into a byte, and put zero-extend of it in
sewardjb5452082004-12-04 20:33:02 +00008958 ireg(G). */
sewardje5854d62004-12-09 03:44:34 +00008959 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xD7) {
sewardjb5452082004-12-04 20:33:02 +00008960 modrm = insn[2];
sewardje5854d62004-12-09 03:44:34 +00008961 if (epartIsReg(modrm)) {
sewardjb5452082004-12-04 20:33:02 +00008962 do_MMX_preamble();
8963 t0 = newTemp(Ity_I64);
8964 t1 = newTemp(Ity_I32);
8965 assign(t0, getMMXReg(eregOfRM(modrm)));
sewardje13074c2012-11-08 10:57:08 +00008966 assign(t1, unop(Iop_8Uto32, unop(Iop_GetMSBs8x8, mkexpr(t0))));
sewardjb5452082004-12-04 20:33:02 +00008967 putIReg(4, gregOfRM(modrm), mkexpr(t1));
8968 DIP("pmovmskb %s,%s\n", nameMMXReg(eregOfRM(modrm)),
8969 nameIReg(4,gregOfRM(modrm)));
8970 delta += 3;
8971 goto decode_success;
8972 }
8973 /* else fall through */
8974 }
8975
sewardj0bd7ce62004-12-05 02:47:40 +00008976 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
8977 /* 0F E4 = PMULUH -- 16x4 hi-half of unsigned widening multiply */
sewardje5854d62004-12-09 03:44:34 +00008978 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xE4) {
sewardj0bd7ce62004-12-05 02:47:40 +00008979 do_MMX_preamble();
8980 delta = dis_MMXop_regmem_to_reg (
8981 sorb, delta+2, insn[1], "pmuluh", False );
8982 goto decode_success;
8983 }
8984
sewardj7df596b2004-12-06 14:29:12 +00008985 /* 0F 18 /0 = PREFETCHNTA -- prefetch into caches, */
8986 /* 0F 18 /1 = PREFETCH0 -- with various different hints */
8987 /* 0F 18 /2 = PREFETCH1 */
8988 /* 0F 18 /3 = PREFETCH2 */
8989 if (insn[0] == 0x0F && insn[1] == 0x18
8990 && !epartIsReg(insn[2])
8991 && gregOfRM(insn[2]) >= 0 && gregOfRM(insn[2]) <= 3) {
florian55085f82012-11-21 00:36:55 +00008992 const HChar* hintstr = "??";
sewardj7df596b2004-12-06 14:29:12 +00008993
8994 modrm = getIByte(delta+2);
8995 vassert(!epartIsReg(modrm));
8996
8997 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8998 delta += 2+alen;
8999
9000 switch (gregOfRM(modrm)) {
9001 case 0: hintstr = "nta"; break;
9002 case 1: hintstr = "t0"; break;
9003 case 2: hintstr = "t1"; break;
9004 case 3: hintstr = "t2"; break;
sewardjba89f4c2005-04-07 17:31:27 +00009005 default: vassert(0); /*NOTREACHED*/
sewardj7df596b2004-12-06 14:29:12 +00009006 }
9007
9008 DIP("prefetch%s %s\n", hintstr, dis_buf);
9009 goto decode_success;
9010 }
9011
sewardj85317682006-03-06 14:07:58 +00009012 /* 0F 0D /0 = PREFETCH m8 -- 3DNow! prefetch */
9013 /* 0F 0D /1 = PREFETCHW m8 -- ditto, with some other hint */
9014 if (insn[0] == 0x0F && insn[1] == 0x0D
9015 && !epartIsReg(insn[2])
9016 && gregOfRM(insn[2]) >= 0 && gregOfRM(insn[2]) <= 1) {
florian55085f82012-11-21 00:36:55 +00009017 const HChar* hintstr = "??";
sewardj85317682006-03-06 14:07:58 +00009018
9019 modrm = getIByte(delta+2);
9020 vassert(!epartIsReg(modrm));
9021
9022 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9023 delta += 2+alen;
9024
9025 switch (gregOfRM(modrm)) {
9026 case 0: hintstr = ""; break;
9027 case 1: hintstr = "w"; break;
9028 default: vassert(0); /*NOTREACHED*/
9029 }
9030
9031 DIP("prefetch%s %s\n", hintstr, dis_buf);
9032 goto decode_success;
9033 }
9034
sewardj0bd7ce62004-12-05 02:47:40 +00009035 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
9036 /* 0F F6 = PSADBW -- sum of 8Ux8 absolute differences */
sewardj7b5b9982005-10-04 11:43:37 +00009037 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xF6) {
sewardj0bd7ce62004-12-05 02:47:40 +00009038 do_MMX_preamble();
9039 delta = dis_MMXop_regmem_to_reg (
9040 sorb, delta+2, insn[1], "psadbw", False );
9041 goto decode_success;
9042 }
9043
9044 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
9045 /* 0F 70 = PSHUFW -- rearrange 4x16 from E(mmx or mem) to G(mmx) */
sewardjb9fa69b2004-12-09 23:25:14 +00009046 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x70) {
sewardj0bd7ce62004-12-05 02:47:40 +00009047 Int order;
sewardjb9fa69b2004-12-09 23:25:14 +00009048 IRTemp sV, dV, s3, s2, s1, s0;
9049 s3 = s2 = s1 = s0 = IRTemp_INVALID;
9050 sV = newTemp(Ity_I64);
9051 dV = newTemp(Ity_I64);
sewardj0bd7ce62004-12-05 02:47:40 +00009052 do_MMX_preamble();
9053 modrm = insn[2];
9054 if (epartIsReg(modrm)) {
sewardjb9fa69b2004-12-09 23:25:14 +00009055 assign( sV, getMMXReg(eregOfRM(modrm)) );
sewardj0bd7ce62004-12-05 02:47:40 +00009056 order = (Int)insn[3];
9057 delta += 2+2;
9058 DIP("pshufw $%d,%s,%s\n", order,
9059 nameMMXReg(eregOfRM(modrm)),
9060 nameMMXReg(gregOfRM(modrm)));
9061 } else {
9062 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
sewardjb9fa69b2004-12-09 23:25:14 +00009063 assign( sV, loadLE(Ity_I64, mkexpr(addr)) );
sewardj0bd7ce62004-12-05 02:47:40 +00009064 order = (Int)insn[2+alen];
9065 delta += 3+alen;
9066 DIP("pshufw $%d,%s,%s\n", order,
9067 dis_buf,
9068 nameMMXReg(gregOfRM(modrm)));
9069 }
sewardjb9fa69b2004-12-09 23:25:14 +00009070 breakup64to16s( sV, &s3, &s2, &s1, &s0 );
sewardj0bd7ce62004-12-05 02:47:40 +00009071
sewardjb9fa69b2004-12-09 23:25:14 +00009072# define SEL(n) \
9073 ((n)==0 ? s0 : ((n)==1 ? s1 : ((n)==2 ? s2 : s3)))
9074 assign(dV,
9075 mk64from16s( SEL((order>>6)&3), SEL((order>>4)&3),
9076 SEL((order>>2)&3), SEL((order>>0)&3) )
sewardj0bd7ce62004-12-05 02:47:40 +00009077 );
sewardjb9fa69b2004-12-09 23:25:14 +00009078 putMMXReg(gregOfRM(modrm), mkexpr(dV));
sewardj0bd7ce62004-12-05 02:47:40 +00009079# undef SEL
sewardj0bd7ce62004-12-05 02:47:40 +00009080 goto decode_success;
9081 }
9082
mjw6c65c122013-08-27 10:19:03 +00009083 /* 0F AE /7 = SFENCE -- flush pending operations to memory */
9084 if (insn[0] == 0x0F && insn[1] == 0xAE
9085 && epartIsReg(insn[2]) && gregOfRM(insn[2]) == 7) {
9086 vassert(sz == 4);
9087 delta += 3;
9088 /* Insert a memory fence. It's sometimes important that these
9089 are carried through to the generated code. */
9090 stmt( IRStmt_MBE(Imbe_Fence) );
9091 DIP("sfence\n");
9092 goto decode_success;
9093 }
9094
9095 /* End of mmxext sse1 subset. No more sse parsing for mmxext only arches. */
9096 if (archinfo->hwcaps == VEX_HWCAPS_X86_MMXEXT/*integer only sse1 subset*/)
9097 goto after_sse_decoders;
9098
9099
9100 /* 0F 5F = MAXPS -- max 32Fx4 from R/M to R */
9101 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x5F) {
9102 delta = dis_SSE_E_to_G_all( sorb, delta+2, "maxps", Iop_Max32Fx4 );
9103 goto decode_success;
9104 }
9105
9106 /* F3 0F 5F = MAXSS -- max 32F0x4 from R/M to R */
9107 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x5F) {
9108 vassert(sz == 4);
9109 delta = dis_SSE_E_to_G_lo32( sorb, delta+3, "maxss", Iop_Max32F0x4 );
9110 goto decode_success;
9111 }
9112
9113 /* 0F 5D = MINPS -- min 32Fx4 from R/M to R */
9114 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x5D) {
9115 delta = dis_SSE_E_to_G_all( sorb, delta+2, "minps", Iop_Min32Fx4 );
9116 goto decode_success;
9117 }
9118
9119 /* F3 0F 5D = MINSS -- min 32F0x4 from R/M to R */
9120 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x5D) {
9121 vassert(sz == 4);
9122 delta = dis_SSE_E_to_G_lo32( sorb, delta+3, "minss", Iop_Min32F0x4 );
9123 goto decode_success;
9124 }
9125
9126 /* 0F 28 = MOVAPS -- move from E (mem or xmm) to G (xmm). */
9127 /* 0F 10 = MOVUPS -- move from E (mem or xmm) to G (xmm). */
9128 if (sz == 4 && insn[0] == 0x0F && (insn[1] == 0x28 || insn[1] == 0x10)) {
9129 modrm = getIByte(delta+2);
9130 if (epartIsReg(modrm)) {
9131 putXMMReg( gregOfRM(modrm),
9132 getXMMReg( eregOfRM(modrm) ));
9133 DIP("mov[ua]ps %s,%s\n", nameXMMReg(eregOfRM(modrm)),
9134 nameXMMReg(gregOfRM(modrm)));
9135 delta += 2+1;
9136 } else {
9137 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9138 if (insn[1] == 0x28/*movaps*/)
9139 gen_SEGV_if_not_16_aligned( addr );
9140 putXMMReg( gregOfRM(modrm),
9141 loadLE(Ity_V128, mkexpr(addr)) );
9142 DIP("mov[ua]ps %s,%s\n", dis_buf,
9143 nameXMMReg(gregOfRM(modrm)));
9144 delta += 2+alen;
9145 }
9146 goto decode_success;
9147 }
9148
9149 /* 0F 29 = MOVAPS -- move from G (xmm) to E (mem or xmm). */
9150 /* 0F 11 = MOVUPS -- move from G (xmm) to E (mem or xmm). */
9151 if (sz == 4 && insn[0] == 0x0F
9152 && (insn[1] == 0x29 || insn[1] == 0x11)) {
9153 modrm = getIByte(delta+2);
9154 if (epartIsReg(modrm)) {
9155 /* fall through; awaiting test case */
9156 } else {
9157 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9158 if (insn[1] == 0x29/*movaps*/)
9159 gen_SEGV_if_not_16_aligned( addr );
9160 storeLE( mkexpr(addr), getXMMReg(gregOfRM(modrm)) );
9161 DIP("mov[ua]ps %s,%s\n", nameXMMReg(gregOfRM(modrm)),
9162 dis_buf );
9163 delta += 2+alen;
9164 goto decode_success;
9165 }
9166 }
9167
9168 /* 0F 16 = MOVHPS -- move from mem to high half of XMM. */
9169 /* 0F 16 = MOVLHPS -- move from lo half to hi half of XMM. */
9170 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x16) {
9171 modrm = getIByte(delta+2);
9172 if (epartIsReg(modrm)) {
9173 delta += 2+1;
9174 putXMMRegLane64( gregOfRM(modrm), 1/*upper lane*/,
9175 getXMMRegLane64( eregOfRM(modrm), 0 ) );
9176 DIP("movhps %s,%s\n", nameXMMReg(eregOfRM(modrm)),
9177 nameXMMReg(gregOfRM(modrm)));
9178 } else {
9179 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9180 delta += 2+alen;
9181 putXMMRegLane64( gregOfRM(modrm), 1/*upper lane*/,
9182 loadLE(Ity_I64, mkexpr(addr)) );
9183 DIP("movhps %s,%s\n", dis_buf,
9184 nameXMMReg( gregOfRM(modrm) ));
9185 }
9186 goto decode_success;
9187 }
9188
9189 /* 0F 17 = MOVHPS -- move from high half of XMM to mem. */
9190 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x17) {
9191 if (!epartIsReg(insn[2])) {
9192 delta += 2;
9193 addr = disAMode ( &alen, sorb, delta, dis_buf );
9194 delta += alen;
9195 storeLE( mkexpr(addr),
9196 getXMMRegLane64( gregOfRM(insn[2]),
9197 1/*upper lane*/ ) );
9198 DIP("movhps %s,%s\n", nameXMMReg( gregOfRM(insn[2]) ),
9199 dis_buf);
9200 goto decode_success;
9201 }
9202 /* else fall through */
9203 }
9204
9205 /* 0F 12 = MOVLPS -- move from mem to low half of XMM. */
9206 /* OF 12 = MOVHLPS -- from from hi half to lo half of XMM. */
9207 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x12) {
9208 modrm = getIByte(delta+2);
9209 if (epartIsReg(modrm)) {
9210 delta += 2+1;
9211 putXMMRegLane64( gregOfRM(modrm),
9212 0/*lower lane*/,
9213 getXMMRegLane64( eregOfRM(modrm), 1 ));
9214 DIP("movhlps %s, %s\n", nameXMMReg(eregOfRM(modrm)),
9215 nameXMMReg(gregOfRM(modrm)));
9216 } else {
9217 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9218 delta += 2+alen;
9219 putXMMRegLane64( gregOfRM(modrm), 0/*lower lane*/,
9220 loadLE(Ity_I64, mkexpr(addr)) );
9221 DIP("movlps %s, %s\n",
9222 dis_buf, nameXMMReg( gregOfRM(modrm) ));
9223 }
9224 goto decode_success;
9225 }
9226
9227 /* 0F 13 = MOVLPS -- move from low half of XMM to mem. */
9228 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x13) {
9229 if (!epartIsReg(insn[2])) {
9230 delta += 2;
9231 addr = disAMode ( &alen, sorb, delta, dis_buf );
9232 delta += alen;
9233 storeLE( mkexpr(addr),
9234 getXMMRegLane64( gregOfRM(insn[2]),
9235 0/*lower lane*/ ) );
9236 DIP("movlps %s, %s\n", nameXMMReg( gregOfRM(insn[2]) ),
9237 dis_buf);
9238 goto decode_success;
9239 }
9240 /* else fall through */
9241 }
9242
9243 /* 0F 50 = MOVMSKPS - move 4 sign bits from 4 x F32 in xmm(E)
9244 to 4 lowest bits of ireg(G) */
9245 if (insn[0] == 0x0F && insn[1] == 0x50) {
9246 modrm = getIByte(delta+2);
9247 if (sz == 4 && epartIsReg(modrm)) {
9248 Int src;
9249 t0 = newTemp(Ity_I32);
9250 t1 = newTemp(Ity_I32);
9251 t2 = newTemp(Ity_I32);
9252 t3 = newTemp(Ity_I32);
9253 delta += 2+1;
9254 src = eregOfRM(modrm);
9255 assign( t0, binop( Iop_And32,
9256 binop(Iop_Shr32, getXMMRegLane32(src,0), mkU8(31)),
9257 mkU32(1) ));
9258 assign( t1, binop( Iop_And32,
9259 binop(Iop_Shr32, getXMMRegLane32(src,1), mkU8(30)),
9260 mkU32(2) ));
9261 assign( t2, binop( Iop_And32,
9262 binop(Iop_Shr32, getXMMRegLane32(src,2), mkU8(29)),
9263 mkU32(4) ));
9264 assign( t3, binop( Iop_And32,
9265 binop(Iop_Shr32, getXMMRegLane32(src,3), mkU8(28)),
9266 mkU32(8) ));
9267 putIReg(4, gregOfRM(modrm),
9268 binop(Iop_Or32,
9269 binop(Iop_Or32, mkexpr(t0), mkexpr(t1)),
9270 binop(Iop_Or32, mkexpr(t2), mkexpr(t3))
9271 )
9272 );
9273 DIP("movmskps %s,%s\n", nameXMMReg(src),
9274 nameIReg(4, gregOfRM(modrm)));
9275 goto decode_success;
9276 }
9277 /* else fall through */
9278 }
9279
9280 /* 0F 2B = MOVNTPS -- for us, just a plain SSE store. */
9281 /* 66 0F 2B = MOVNTPD -- for us, just a plain SSE store. */
9282 if (insn[0] == 0x0F && insn[1] == 0x2B) {
9283 modrm = getIByte(delta+2);
9284 if (!epartIsReg(modrm)) {
9285 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9286 gen_SEGV_if_not_16_aligned( addr );
9287 storeLE( mkexpr(addr), getXMMReg(gregOfRM(modrm)) );
9288 DIP("movntp%s %s,%s\n", sz==2 ? "d" : "s",
9289 dis_buf,
9290 nameXMMReg(gregOfRM(modrm)));
9291 delta += 2+alen;
9292 goto decode_success;
9293 }
9294 /* else fall through */
9295 }
9296
9297 /* F3 0F 10 = MOVSS -- move 32 bits from E (mem or lo 1/4 xmm) to G
9298 (lo 1/4 xmm). If E is mem, upper 3/4 of G is zeroed out. */
9299 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x10) {
9300 vassert(sz == 4);
9301 modrm = getIByte(delta+3);
9302 if (epartIsReg(modrm)) {
9303 putXMMRegLane32( gregOfRM(modrm), 0,
9304 getXMMRegLane32( eregOfRM(modrm), 0 ));
9305 DIP("movss %s,%s\n", nameXMMReg(eregOfRM(modrm)),
9306 nameXMMReg(gregOfRM(modrm)));
9307 delta += 3+1;
9308 } else {
9309 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
9310 /* zero bits 127:64 */
9311 putXMMRegLane64( gregOfRM(modrm), 1, mkU64(0) );
9312 /* zero bits 63:32 */
9313 putXMMRegLane32( gregOfRM(modrm), 1, mkU32(0) );
9314 /* write bits 31:0 */
9315 putXMMRegLane32( gregOfRM(modrm), 0,
9316 loadLE(Ity_I32, mkexpr(addr)) );
9317 DIP("movss %s,%s\n", dis_buf,
9318 nameXMMReg(gregOfRM(modrm)));
9319 delta += 3+alen;
9320 }
9321 goto decode_success;
9322 }
9323
9324 /* F3 0F 11 = MOVSS -- move 32 bits from G (lo 1/4 xmm) to E (mem
9325 or lo 1/4 xmm). */
9326 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x11) {
9327 vassert(sz == 4);
9328 modrm = getIByte(delta+3);
9329 if (epartIsReg(modrm)) {
9330 /* fall through, we don't yet have a test case */
9331 } else {
9332 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
9333 storeLE( mkexpr(addr),
9334 getXMMRegLane32(gregOfRM(modrm), 0) );
9335 DIP("movss %s,%s\n", nameXMMReg(gregOfRM(modrm)),
9336 dis_buf);
9337 delta += 3+alen;
9338 goto decode_success;
9339 }
9340 }
9341
9342 /* 0F 59 = MULPS -- mul 32Fx4 from R/M to R */
9343 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x59) {
9344 delta = dis_SSE_E_to_G_all( sorb, delta+2, "mulps", Iop_Mul32Fx4 );
9345 goto decode_success;
9346 }
9347
9348 /* F3 0F 59 = MULSS -- mul 32F0x4 from R/M to R */
9349 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x59) {
9350 vassert(sz == 4);
9351 delta = dis_SSE_E_to_G_lo32( sorb, delta+3, "mulss", Iop_Mul32F0x4 );
9352 goto decode_success;
9353 }
9354
9355 /* 0F 56 = ORPS -- G = G and E */
9356 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x56) {
9357 delta = dis_SSE_E_to_G_all( sorb, delta+2, "orps", Iop_OrV128 );
9358 goto decode_success;
9359 }
9360
sewardj0bd7ce62004-12-05 02:47:40 +00009361 /* 0F 53 = RCPPS -- approx reciprocal 32Fx4 from R/M to R */
9362 if (insn[0] == 0x0F && insn[1] == 0x53) {
9363 vassert(sz == 4);
sewardj129b3d92004-12-05 15:42:05 +00009364 delta = dis_SSE_E_to_G_unary_all( sorb, delta+2,
sewardj1ddee212014-08-24 14:00:19 +00009365 "rcpps", Iop_RecipEst32Fx4 );
sewardj0bd7ce62004-12-05 02:47:40 +00009366 goto decode_success;
9367 }
9368
9369 /* F3 0F 53 = RCPSS -- approx reciprocal 32F0x4 from R/M to R */
9370 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x53) {
9371 vassert(sz == 4);
sewardj129b3d92004-12-05 15:42:05 +00009372 delta = dis_SSE_E_to_G_unary_lo32( sorb, delta+3,
sewardj1ddee212014-08-24 14:00:19 +00009373 "rcpss", Iop_RecipEst32F0x4 );
sewardj0bd7ce62004-12-05 02:47:40 +00009374 goto decode_success;
9375 }
sewardjb5452082004-12-04 20:33:02 +00009376
sewardjc1e7dfc2004-12-05 19:29:45 +00009377 /* 0F 52 = RSQRTPS -- approx reciprocal sqrt 32Fx4 from R/M to R */
9378 if (insn[0] == 0x0F && insn[1] == 0x52) {
9379 vassert(sz == 4);
9380 delta = dis_SSE_E_to_G_unary_all( sorb, delta+2,
sewardj1ddee212014-08-24 14:00:19 +00009381 "rsqrtps", Iop_RSqrtEst32Fx4 );
sewardjc1e7dfc2004-12-05 19:29:45 +00009382 goto decode_success;
9383 }
9384
9385 /* F3 0F 52 = RSQRTSS -- approx reciprocal sqrt 32F0x4 from R/M to R */
9386 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x52) {
9387 vassert(sz == 4);
9388 delta = dis_SSE_E_to_G_unary_lo32( sorb, delta+3,
sewardj1ddee212014-08-24 14:00:19 +00009389 "rsqrtss", Iop_RSqrtEst32F0x4 );
sewardjc1e7dfc2004-12-05 19:29:45 +00009390 goto decode_success;
9391 }
9392
sewardjc1e7dfc2004-12-05 19:29:45 +00009393 /* 0F C6 /r ib = SHUFPS -- shuffle packed F32s */
sewardj008754b2004-12-08 14:37:10 +00009394 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xC6) {
sewardjc1e7dfc2004-12-05 19:29:45 +00009395 Int select;
9396 IRTemp sV, dV;
9397 IRTemp s3, s2, s1, s0, d3, d2, d1, d0;
9398 sV = newTemp(Ity_V128);
9399 dV = newTemp(Ity_V128);
9400 s3 = s2 = s1 = s0 = d3 = d2 = d1 = d0 = IRTemp_INVALID;
sewardjc1e7dfc2004-12-05 19:29:45 +00009401 modrm = insn[2];
9402 assign( dV, getXMMReg(gregOfRM(modrm)) );
9403
9404 if (epartIsReg(modrm)) {
9405 assign( sV, getXMMReg(eregOfRM(modrm)) );
9406 select = (Int)insn[3];
9407 delta += 2+2;
9408 DIP("shufps $%d,%s,%s\n", select,
9409 nameXMMReg(eregOfRM(modrm)),
9410 nameXMMReg(gregOfRM(modrm)));
9411 } else {
9412 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9413 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
9414 select = (Int)insn[2+alen];
9415 delta += 3+alen;
9416 DIP("shufps $%d,%s,%s\n", select,
9417 dis_buf,
9418 nameXMMReg(gregOfRM(modrm)));
9419 }
9420
9421 breakup128to32s( dV, &d3, &d2, &d1, &d0 );
9422 breakup128to32s( sV, &s3, &s2, &s1, &s0 );
9423
9424# define SELD(n) ((n)==0 ? d0 : ((n)==1 ? d1 : ((n)==2 ? d2 : d3)))
9425# define SELS(n) ((n)==0 ? s0 : ((n)==1 ? s1 : ((n)==2 ? s2 : s3)))
9426
9427 putXMMReg(
9428 gregOfRM(modrm),
9429 mk128from32s( SELS((select>>6)&3), SELS((select>>4)&3),
9430 SELD((select>>2)&3), SELD((select>>0)&3) )
9431 );
9432
9433# undef SELD
9434# undef SELS
9435
9436 goto decode_success;
9437 }
9438
9439 /* 0F 51 = SQRTPS -- approx sqrt 32Fx4 from R/M to R */
sewardj008754b2004-12-08 14:37:10 +00009440 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x51) {
sewardjc1e7dfc2004-12-05 19:29:45 +00009441 delta = dis_SSE_E_to_G_unary_all( sorb, delta+2,
9442 "sqrtps", Iop_Sqrt32Fx4 );
9443 goto decode_success;
9444 }
9445
9446 /* F3 0F 51 = SQRTSS -- approx sqrt 32F0x4 from R/M to R */
9447 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x51) {
9448 vassert(sz == 4);
9449 delta = dis_SSE_E_to_G_unary_lo32( sorb, delta+3,
9450 "sqrtss", Iop_Sqrt32F0x4 );
9451 goto decode_success;
9452 }
9453
sewardja0e83b02005-01-06 12:36:38 +00009454 /* 0F AE /3 = STMXCSR m32 -- store %mxcsr */
sewardj7df596b2004-12-06 14:29:12 +00009455 if (insn[0] == 0x0F && insn[1] == 0xAE
9456 && !epartIsReg(insn[2]) && gregOfRM(insn[2]) == 3) {
9457 modrm = getIByte(delta+2);
9458 vassert(sz == 4);
9459 vassert(!epartIsReg(modrm));
9460
9461 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9462 delta += 2+alen;
9463
9464 /* Fake up a native SSE mxcsr word. The only thing it depends
9465 on is SSEROUND[1:0], so call a clean helper to cook it up.
9466 */
9467 /* UInt x86h_create_mxcsr ( UInt sseround ) */
sewardj33dd31b2005-01-08 18:17:32 +00009468 DIP("stmxcsr %s\n", dis_buf);
sewardj7df596b2004-12-06 14:29:12 +00009469 storeLE( mkexpr(addr),
9470 mkIRExprCCall(
9471 Ity_I32, 0/*regp*/,
sewardj3bd6f3e2004-12-13 10:48:19 +00009472 "x86g_create_mxcsr", &x86g_create_mxcsr,
sewardja0e83b02005-01-06 12:36:38 +00009473 mkIRExprVec_1( get_sse_roundingmode() )
sewardj7df596b2004-12-06 14:29:12 +00009474 )
9475 );
9476 goto decode_success;
9477 }
9478
sewardjc1e7dfc2004-12-05 19:29:45 +00009479 /* 0F 5C = SUBPS -- sub 32Fx4 from R/M to R */
sewardj008754b2004-12-08 14:37:10 +00009480 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x5C) {
sewardjc1e7dfc2004-12-05 19:29:45 +00009481 delta = dis_SSE_E_to_G_all( sorb, delta+2, "subps", Iop_Sub32Fx4 );
9482 goto decode_success;
9483 }
9484
sewardj008754b2004-12-08 14:37:10 +00009485 /* F3 0F 5C = SUBSS -- sub 32F0x4 from R/M to R */
sewardjc1e7dfc2004-12-05 19:29:45 +00009486 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x5C) {
9487 vassert(sz == 4);
9488 delta = dis_SSE_E_to_G_lo32( sorb, delta+3, "subss", Iop_Sub32F0x4 );
9489 goto decode_success;
9490 }
9491
9492 /* 0F 15 = UNPCKHPS -- unpack and interleave high part F32s */
9493 /* 0F 14 = UNPCKLPS -- unpack and interleave low part F32s */
9494 /* These just appear to be special cases of SHUFPS */
sewardj008754b2004-12-08 14:37:10 +00009495 if (sz == 4 && insn[0] == 0x0F && (insn[1] == 0x15 || insn[1] == 0x14)) {
sewardjc1e7dfc2004-12-05 19:29:45 +00009496 IRTemp sV, dV;
9497 IRTemp s3, s2, s1, s0, d3, d2, d1, d0;
sewardj2d49b432005-02-01 00:37:06 +00009498 Bool hi = toBool(insn[1] == 0x15);
sewardjc1e7dfc2004-12-05 19:29:45 +00009499 sV = newTemp(Ity_V128);
9500 dV = newTemp(Ity_V128);
9501 s3 = s2 = s1 = s0 = d3 = d2 = d1 = d0 = IRTemp_INVALID;
sewardjc1e7dfc2004-12-05 19:29:45 +00009502 modrm = insn[2];
9503 assign( dV, getXMMReg(gregOfRM(modrm)) );
9504
9505 if (epartIsReg(modrm)) {
9506 assign( sV, getXMMReg(eregOfRM(modrm)) );
9507 delta += 2+1;
9508 DIP("unpck%sps %s,%s\n", hi ? "h" : "l",
9509 nameXMMReg(eregOfRM(modrm)),
9510 nameXMMReg(gregOfRM(modrm)));
9511 } else {
9512 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9513 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
9514 delta += 2+alen;
9515 DIP("unpck%sps %s,%s\n", hi ? "h" : "l",
9516 dis_buf,
9517 nameXMMReg(gregOfRM(modrm)));
9518 }
9519
9520 breakup128to32s( dV, &d3, &d2, &d1, &d0 );
9521 breakup128to32s( sV, &s3, &s2, &s1, &s0 );
9522
9523 if (hi) {
9524 putXMMReg( gregOfRM(modrm), mk128from32s( s3, d3, s2, d2 ) );
9525 } else {
9526 putXMMReg( gregOfRM(modrm), mk128from32s( s1, d1, s0, d0 ) );
9527 }
9528
9529 goto decode_success;
9530 }
9531
9532 /* 0F 57 = XORPS -- G = G and E */
sewardj008754b2004-12-08 14:37:10 +00009533 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x57) {
sewardjf0c1c582005-02-07 23:47:38 +00009534 delta = dis_SSE_E_to_G_all( sorb, delta+2, "xorps", Iop_XorV128 );
sewardjc1e7dfc2004-12-05 19:29:45 +00009535 goto decode_success;
9536 }
9537
sewardj636ad762004-12-07 11:16:04 +00009538 /* ---------------------------------------------------- */
9539 /* --- end of the SSE decoder. --- */
9540 /* ---------------------------------------------------- */
9541
9542 /* ---------------------------------------------------- */
9543 /* --- start of the SSE2 decoder. --- */
9544 /* ---------------------------------------------------- */
9545
sewardj9df271d2004-12-31 22:37:42 +00009546 /* Skip parts of the decoder which don't apply given the stated
9547 guest subarchitecture. */
sewardj5117ce12006-01-27 21:20:15 +00009548 if (0 == (archinfo->hwcaps & VEX_HWCAPS_X86_SSE2))
9549 goto after_sse_decoders; /* no SSE2 capabilities */
sewardj9df271d2004-12-31 22:37:42 +00009550
florian8462d112014-09-24 15:18:09 +00009551 insn = &guest_code[delta];
sewardj636ad762004-12-07 11:16:04 +00009552
9553 /* 66 0F 58 = ADDPD -- add 32Fx4 from R/M to R */
9554 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x58) {
9555 delta = dis_SSE_E_to_G_all( sorb, delta+2, "addpd", Iop_Add64Fx2 );
9556 goto decode_success;
9557 }
9558
9559 /* F2 0F 58 = ADDSD -- add 64F0x2 from R/M to R */
9560 if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x58) {
9561 vassert(sz == 4);
9562 delta = dis_SSE_E_to_G_lo64( sorb, delta+3, "addsd", Iop_Add64F0x2 );
9563 goto decode_success;
9564 }
9565
9566 /* 66 0F 55 = ANDNPD -- G = (not G) and E */
9567 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x55) {
sewardjf0c1c582005-02-07 23:47:38 +00009568 delta = dis_SSE_E_to_G_all_invG( sorb, delta+2, "andnpd", Iop_AndV128 );
sewardj636ad762004-12-07 11:16:04 +00009569 goto decode_success;
9570 }
9571
9572 /* 66 0F 54 = ANDPD -- G = G and E */
9573 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x54) {
sewardjf0c1c582005-02-07 23:47:38 +00009574 delta = dis_SSE_E_to_G_all( sorb, delta+2, "andpd", Iop_AndV128 );
sewardj636ad762004-12-07 11:16:04 +00009575 goto decode_success;
9576 }
9577
sewardjfd226452004-12-07 19:02:18 +00009578 /* 66 0F C2 = CMPPD -- 64Fx2 comparison from R/M to R */
9579 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xC2) {
9580 delta = dis_SSEcmp_E_to_G( sorb, delta+2, "cmppd", True, 8 );
9581 goto decode_success;
9582 }
9583
9584 /* F2 0F C2 = CMPSD -- 64F0x2 comparison from R/M to R */
9585 if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0xC2) {
9586 vassert(sz == 4);
9587 delta = dis_SSEcmp_E_to_G( sorb, delta+3, "cmpsd", False, 8 );
9588 goto decode_success;
9589 }
9590
9591 /* 66 0F 2F = COMISD -- 64F0x2 comparison G,E, and set ZCP */
9592 /* 66 0F 2E = UCOMISD -- 64F0x2 comparison G,E, and set ZCP */
9593 if (sz == 2 && insn[0] == 0x0F && (insn[1] == 0x2F || insn[1] == 0x2E)) {
9594 IRTemp argL = newTemp(Ity_F64);
9595 IRTemp argR = newTemp(Ity_F64);
9596 modrm = getIByte(delta+2);
9597 if (epartIsReg(modrm)) {
9598 assign( argR, getXMMRegLane64F( eregOfRM(modrm), 0/*lowest lane*/ ) );
9599 delta += 2+1;
9600 DIP("[u]comisd %s,%s\n", nameXMMReg(eregOfRM(modrm)),
9601 nameXMMReg(gregOfRM(modrm)) );
9602 } else {
9603 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9604 assign( argR, loadLE(Ity_F64, mkexpr(addr)) );
9605 delta += 2+alen;
9606 DIP("[u]comisd %s,%s\n", dis_buf,
9607 nameXMMReg(gregOfRM(modrm)) );
9608 }
9609 assign( argL, getXMMRegLane64F( gregOfRM(modrm), 0/*lowest lane*/ ) );
9610
9611 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(X86G_CC_OP_COPY) ));
9612 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
9613 stmt( IRStmt_Put(
9614 OFFB_CC_DEP1,
9615 binop( Iop_And32,
9616 binop(Iop_CmpF64, mkexpr(argL), mkexpr(argR)),
9617 mkU32(0x45)
9618 )));
sewardja3b7e3a2005-04-05 01:54:19 +00009619 /* Set NDEP even though it isn't used. This makes redundant-PUT
9620 elimination of previous stores to this field work better. */
9621 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
sewardjfd226452004-12-07 19:02:18 +00009622 goto decode_success;
9623 }
9624
9625 /* F3 0F E6 = CVTDQ2PD -- convert 2 x I32 in mem/lo half xmm to 2 x
9626 F64 in xmm(G) */
9627 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0xE6) {
9628 IRTemp arg64 = newTemp(Ity_I64);
9629 vassert(sz == 4);
9630
9631 modrm = getIByte(delta+3);
9632 if (epartIsReg(modrm)) {
9633 assign( arg64, getXMMRegLane64(eregOfRM(modrm), 0) );
9634 delta += 3+1;
9635 DIP("cvtdq2pd %s,%s\n", nameXMMReg(eregOfRM(modrm)),
9636 nameXMMReg(gregOfRM(modrm)));
9637 } else {
9638 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
9639 assign( arg64, loadLE(Ity_I64, mkexpr(addr)) );
9640 delta += 3+alen;
9641 DIP("cvtdq2pd %s,%s\n", dis_buf,
9642 nameXMMReg(gregOfRM(modrm)) );
9643 }
9644
9645 putXMMRegLane64F(
9646 gregOfRM(modrm), 0,
sewardj6c299f32009-12-31 18:00:12 +00009647 unop(Iop_I32StoF64, unop(Iop_64to32, mkexpr(arg64)))
sewardjfd226452004-12-07 19:02:18 +00009648 );
9649
9650 putXMMRegLane64F(
9651 gregOfRM(modrm), 1,
sewardj6c299f32009-12-31 18:00:12 +00009652 unop(Iop_I32StoF64, unop(Iop_64HIto32, mkexpr(arg64)))
sewardjfd226452004-12-07 19:02:18 +00009653 );
9654
9655 goto decode_success;
9656 }
9657
9658 /* 0F 5B = CVTDQ2PS -- convert 4 x I32 in mem/xmm to 4 x F32 in
9659 xmm(G) */
9660 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x5B) {
9661 IRTemp argV = newTemp(Ity_V128);
9662 IRTemp rmode = newTemp(Ity_I32);
9663
9664 modrm = getIByte(delta+2);
9665 if (epartIsReg(modrm)) {
9666 assign( argV, getXMMReg(eregOfRM(modrm)) );
9667 delta += 2+1;
9668 DIP("cvtdq2ps %s,%s\n", nameXMMReg(eregOfRM(modrm)),
9669 nameXMMReg(gregOfRM(modrm)));
9670 } else {
9671 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9672 assign( argV, loadLE(Ity_V128, mkexpr(addr)) );
9673 delta += 2+alen;
9674 DIP("cvtdq2ps %s,%s\n", dis_buf,
9675 nameXMMReg(gregOfRM(modrm)) );
9676 }
9677
9678 assign( rmode, get_sse_roundingmode() );
9679 breakup128to32s( argV, &t3, &t2, &t1, &t0 );
9680
9681# define CVT(_t) binop( Iop_F64toF32, \
9682 mkexpr(rmode), \
sewardj6c299f32009-12-31 18:00:12 +00009683 unop(Iop_I32StoF64,mkexpr(_t)))
sewardjfd226452004-12-07 19:02:18 +00009684
9685 putXMMRegLane32F( gregOfRM(modrm), 3, CVT(t3) );
9686 putXMMRegLane32F( gregOfRM(modrm), 2, CVT(t2) );
9687 putXMMRegLane32F( gregOfRM(modrm), 1, CVT(t1) );
9688 putXMMRegLane32F( gregOfRM(modrm), 0, CVT(t0) );
9689
9690# undef CVT
9691
9692 goto decode_success;
9693 }
9694
9695 /* F2 0F E6 = CVTPD2DQ -- convert 2 x F64 in mem/xmm to 2 x I32 in
9696 lo half xmm(G), and zero upper half */
9697 if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0xE6) {
9698 IRTemp argV = newTemp(Ity_V128);
9699 IRTemp rmode = newTemp(Ity_I32);
9700 vassert(sz == 4);
9701
9702 modrm = getIByte(delta+3);
9703 if (epartIsReg(modrm)) {
9704 assign( argV, getXMMReg(eregOfRM(modrm)) );
9705 delta += 3+1;
9706 DIP("cvtpd2dq %s,%s\n", nameXMMReg(eregOfRM(modrm)),
9707 nameXMMReg(gregOfRM(modrm)));
9708 } else {
9709 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
9710 assign( argV, loadLE(Ity_V128, mkexpr(addr)) );
9711 delta += 3+alen;
9712 DIP("cvtpd2dq %s,%s\n", dis_buf,
9713 nameXMMReg(gregOfRM(modrm)) );
9714 }
9715
9716 assign( rmode, get_sse_roundingmode() );
9717 t0 = newTemp(Ity_F64);
9718 t1 = newTemp(Ity_F64);
9719 assign( t0, unop(Iop_ReinterpI64asF64,
sewardjf0c1c582005-02-07 23:47:38 +00009720 unop(Iop_V128to64, mkexpr(argV))) );
sewardjfd226452004-12-07 19:02:18 +00009721 assign( t1, unop(Iop_ReinterpI64asF64,
sewardjf0c1c582005-02-07 23:47:38 +00009722 unop(Iop_V128HIto64, mkexpr(argV))) );
sewardjfd226452004-12-07 19:02:18 +00009723
sewardj6c299f32009-12-31 18:00:12 +00009724# define CVT(_t) binop( Iop_F64toI32S, \
sewardjfd226452004-12-07 19:02:18 +00009725 mkexpr(rmode), \
9726 mkexpr(_t) )
9727
9728 putXMMRegLane32( gregOfRM(modrm), 3, mkU32(0) );
9729 putXMMRegLane32( gregOfRM(modrm), 2, mkU32(0) );
9730 putXMMRegLane32( gregOfRM(modrm), 1, CVT(t1) );
9731 putXMMRegLane32( gregOfRM(modrm), 0, CVT(t0) );
9732
9733# undef CVT
9734
9735 goto decode_success;
9736 }
9737
9738 /* 66 0F 2D = CVTPD2PI -- convert 2 x F64 in mem/xmm to 2 x
9739 I32 in mmx, according to prevailing SSE rounding mode */
9740 /* 66 0F 2C = CVTTPD2PI -- convert 2 x F64 in mem/xmm to 2 x
9741 I32 in mmx, rounding towards zero */
9742 if (sz == 2 && insn[0] == 0x0F && (insn[1] == 0x2D || insn[1] == 0x2C)) {
9743 IRTemp dst64 = newTemp(Ity_I64);
9744 IRTemp rmode = newTemp(Ity_I32);
9745 IRTemp f64lo = newTemp(Ity_F64);
9746 IRTemp f64hi = newTemp(Ity_F64);
sewardj2d49b432005-02-01 00:37:06 +00009747 Bool r2zero = toBool(insn[1] == 0x2C);
sewardjfd226452004-12-07 19:02:18 +00009748
9749 do_MMX_preamble();
9750 modrm = getIByte(delta+2);
9751
9752 if (epartIsReg(modrm)) {
9753 delta += 2+1;
9754 assign(f64lo, getXMMRegLane64F(eregOfRM(modrm), 0));
9755 assign(f64hi, getXMMRegLane64F(eregOfRM(modrm), 1));
9756 DIP("cvt%spd2pi %s,%s\n", r2zero ? "t" : "",
9757 nameXMMReg(eregOfRM(modrm)),
9758 nameMMXReg(gregOfRM(modrm)));
9759 } else {
9760 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9761 assign(f64lo, loadLE(Ity_F64, mkexpr(addr)));
9762 assign(f64hi, loadLE(Ity_F64, binop( Iop_Add32,
9763 mkexpr(addr),
9764 mkU32(8) )));
9765 delta += 2+alen;
9766 DIP("cvt%spf2pi %s,%s\n", r2zero ? "t" : "",
9767 dis_buf,
9768 nameMMXReg(gregOfRM(modrm)));
9769 }
9770
9771 if (r2zero) {
9772 assign(rmode, mkU32((UInt)Irrm_ZERO) );
9773 } else {
9774 assign( rmode, get_sse_roundingmode() );
9775 }
9776
9777 assign(
9778 dst64,
9779 binop( Iop_32HLto64,
sewardj6c299f32009-12-31 18:00:12 +00009780 binop( Iop_F64toI32S, mkexpr(rmode), mkexpr(f64hi) ),
9781 binop( Iop_F64toI32S, mkexpr(rmode), mkexpr(f64lo) )
sewardjfd226452004-12-07 19:02:18 +00009782 )
9783 );
9784
9785 putMMXReg(gregOfRM(modrm), mkexpr(dst64));
9786 goto decode_success;
9787 }
9788
9789 /* 66 0F 5A = CVTPD2PS -- convert 2 x F64 in mem/xmm to 2 x F32 in
9790 lo half xmm(G), and zero upper half */
9791 /* Note, this is practically identical to CVTPD2DQ. It would have
9792 been nicer to merge them together, but the insn[] offsets differ
9793 by one. */
9794 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x5A) {
9795 IRTemp argV = newTemp(Ity_V128);
9796 IRTemp rmode = newTemp(Ity_I32);
9797
9798 modrm = getIByte(delta+2);
9799 if (epartIsReg(modrm)) {
9800 assign( argV, getXMMReg(eregOfRM(modrm)) );
9801 delta += 2+1;
9802 DIP("cvtpd2ps %s,%s\n", nameXMMReg(eregOfRM(modrm)),
9803 nameXMMReg(gregOfRM(modrm)));
9804 } else {
9805 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9806 assign( argV, loadLE(Ity_V128, mkexpr(addr)) );
9807 delta += 2+alen;
9808 DIP("cvtpd2ps %s,%s\n", dis_buf,
9809 nameXMMReg(gregOfRM(modrm)) );
9810 }
9811
9812 assign( rmode, get_sse_roundingmode() );
9813 t0 = newTemp(Ity_F64);
9814 t1 = newTemp(Ity_F64);
9815 assign( t0, unop(Iop_ReinterpI64asF64,
sewardjf0c1c582005-02-07 23:47:38 +00009816 unop(Iop_V128to64, mkexpr(argV))) );
sewardjfd226452004-12-07 19:02:18 +00009817 assign( t1, unop(Iop_ReinterpI64asF64,
sewardjf0c1c582005-02-07 23:47:38 +00009818 unop(Iop_V128HIto64, mkexpr(argV))) );
sewardjfd226452004-12-07 19:02:18 +00009819
9820# define CVT(_t) binop( Iop_F64toF32, \
9821 mkexpr(rmode), \
9822 mkexpr(_t) )
9823
9824 putXMMRegLane32( gregOfRM(modrm), 3, mkU32(0) );
9825 putXMMRegLane32( gregOfRM(modrm), 2, mkU32(0) );
9826 putXMMRegLane32F( gregOfRM(modrm), 1, CVT(t1) );
9827 putXMMRegLane32F( gregOfRM(modrm), 0, CVT(t0) );
9828
9829# undef CVT
9830
9831 goto decode_success;
9832 }
9833
9834 /* 66 0F 2A = CVTPI2PD -- convert 2 x I32 in mem/mmx to 2 x F64 in
9835 xmm(G) */
9836 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x2A) {
9837 IRTemp arg64 = newTemp(Ity_I64);
9838
9839 modrm = getIByte(delta+2);
sewardjfd226452004-12-07 19:02:18 +00009840 if (epartIsReg(modrm)) {
sewardj30a20e92010-02-21 20:40:53 +00009841 /* Only switch to MMX mode if the source is a MMX register.
9842 This is inconsistent with all other instructions which
9843 convert between XMM and (M64 or MMX), which always switch
9844 to MMX mode even if 64-bit operand is M64 and not MMX. At
9845 least, that's what the Intel docs seem to me to say.
9846 Fixes #210264. */
9847 do_MMX_preamble();
sewardjfd226452004-12-07 19:02:18 +00009848 assign( arg64, getMMXReg(eregOfRM(modrm)) );
9849 delta += 2+1;
9850 DIP("cvtpi2pd %s,%s\n", nameMMXReg(eregOfRM(modrm)),
9851 nameXMMReg(gregOfRM(modrm)));
9852 } else {
9853 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9854 assign( arg64, loadLE(Ity_I64, mkexpr(addr)) );
9855 delta += 2+alen;
9856 DIP("cvtpi2pd %s,%s\n", dis_buf,
9857 nameXMMReg(gregOfRM(modrm)) );
9858 }
9859
9860 putXMMRegLane64F(
9861 gregOfRM(modrm), 0,
sewardj6c299f32009-12-31 18:00:12 +00009862 unop(Iop_I32StoF64, unop(Iop_64to32, mkexpr(arg64)) )
sewardjfd226452004-12-07 19:02:18 +00009863 );
9864
9865 putXMMRegLane64F(
9866 gregOfRM(modrm), 1,
sewardj6c299f32009-12-31 18:00:12 +00009867 unop(Iop_I32StoF64, unop(Iop_64HIto32, mkexpr(arg64)) )
sewardjfd226452004-12-07 19:02:18 +00009868 );
9869
9870 goto decode_success;
9871 }
9872
9873 /* 66 0F 5B = CVTPS2DQ -- convert 4 x F32 in mem/xmm to 4 x I32 in
9874 xmm(G) */
9875 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x5B) {
9876 IRTemp argV = newTemp(Ity_V128);
9877 IRTemp rmode = newTemp(Ity_I32);
9878
9879 modrm = getIByte(delta+2);
9880 if (epartIsReg(modrm)) {
9881 assign( argV, getXMMReg(eregOfRM(modrm)) );
9882 delta += 2+1;
9883 DIP("cvtps2dq %s,%s\n", nameXMMReg(eregOfRM(modrm)),
9884 nameXMMReg(gregOfRM(modrm)));
9885 } else {
9886 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9887 assign( argV, loadLE(Ity_V128, mkexpr(addr)) );
9888 delta += 2+alen;
9889 DIP("cvtps2dq %s,%s\n", dis_buf,
9890 nameXMMReg(gregOfRM(modrm)) );
9891 }
9892
9893 assign( rmode, get_sse_roundingmode() );
9894 breakup128to32s( argV, &t3, &t2, &t1, &t0 );
9895
9896 /* This is less than ideal. If it turns out to be a performance
9897 bottleneck it can be improved. */
9898# define CVT(_t) \
sewardj6c299f32009-12-31 18:00:12 +00009899 binop( Iop_F64toI32S, \
sewardjfd226452004-12-07 19:02:18 +00009900 mkexpr(rmode), \
9901 unop( Iop_F32toF64, \
9902 unop( Iop_ReinterpI32asF32, mkexpr(_t))) )
9903
9904 putXMMRegLane32( gregOfRM(modrm), 3, CVT(t3) );
9905 putXMMRegLane32( gregOfRM(modrm), 2, CVT(t2) );
9906 putXMMRegLane32( gregOfRM(modrm), 1, CVT(t1) );
9907 putXMMRegLane32( gregOfRM(modrm), 0, CVT(t0) );
9908
9909# undef CVT
9910
9911 goto decode_success;
9912 }
9913
9914 /* 0F 5A = CVTPS2PD -- convert 2 x F32 in low half mem/xmm to 2 x
9915 F64 in xmm(G). */
9916 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x5A) {
9917 IRTemp f32lo = newTemp(Ity_F32);
9918 IRTemp f32hi = newTemp(Ity_F32);
9919
9920 modrm = getIByte(delta+2);
9921 if (epartIsReg(modrm)) {
9922 assign( f32lo, getXMMRegLane32F(eregOfRM(modrm), 0) );
9923 assign( f32hi, getXMMRegLane32F(eregOfRM(modrm), 1) );
9924 delta += 2+1;
9925 DIP("cvtps2pd %s,%s\n", nameXMMReg(eregOfRM(modrm)),
9926 nameXMMReg(gregOfRM(modrm)));
9927 } else {
9928 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9929 assign( f32lo, loadLE(Ity_F32, mkexpr(addr)) );
9930 assign( f32hi, loadLE(Ity_F32,
9931 binop(Iop_Add32,mkexpr(addr),mkU32(4))) );
9932 delta += 2+alen;
9933 DIP("cvtps2pd %s,%s\n", dis_buf,
9934 nameXMMReg(gregOfRM(modrm)) );
9935 }
9936
9937 putXMMRegLane64F( gregOfRM(modrm), 1,
9938 unop(Iop_F32toF64, mkexpr(f32hi)) );
9939 putXMMRegLane64F( gregOfRM(modrm), 0,
9940 unop(Iop_F32toF64, mkexpr(f32lo)) );
9941
9942 goto decode_success;
9943 }
9944
9945 /* F2 0F 2D = CVTSD2SI -- convert F64 in mem/low half xmm to
9946 I32 in ireg, according to prevailing SSE rounding mode */
9947 /* F2 0F 2C = CVTTSD2SI -- convert F64 in mem/low half xmm to
sewardj0b210442005-02-23 13:28:27 +00009948 I32 in ireg, rounding towards zero */
sewardjfd226452004-12-07 19:02:18 +00009949 if (insn[0] == 0xF2 && insn[1] == 0x0F
9950 && (insn[2] == 0x2D || insn[2] == 0x2C)) {
9951 IRTemp rmode = newTemp(Ity_I32);
9952 IRTemp f64lo = newTemp(Ity_F64);
sewardj2d49b432005-02-01 00:37:06 +00009953 Bool r2zero = toBool(insn[2] == 0x2C);
sewardjfd226452004-12-07 19:02:18 +00009954 vassert(sz == 4);
9955
9956 modrm = getIByte(delta+3);
9957 if (epartIsReg(modrm)) {
9958 delta += 3+1;
9959 assign(f64lo, getXMMRegLane64F(eregOfRM(modrm), 0));
9960 DIP("cvt%ssd2si %s,%s\n", r2zero ? "t" : "",
9961 nameXMMReg(eregOfRM(modrm)),
9962 nameIReg(4, gregOfRM(modrm)));
9963 } else {
9964 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
9965 assign(f64lo, loadLE(Ity_F64, mkexpr(addr)));
9966 delta += 3+alen;
9967 DIP("cvt%ssd2si %s,%s\n", r2zero ? "t" : "",
9968 dis_buf,
9969 nameIReg(4, gregOfRM(modrm)));
9970 }
9971
9972 if (r2zero) {
9973 assign( rmode, mkU32((UInt)Irrm_ZERO) );
9974 } else {
9975 assign( rmode, get_sse_roundingmode() );
9976 }
9977
9978 putIReg(4, gregOfRM(modrm),
sewardj6c299f32009-12-31 18:00:12 +00009979 binop( Iop_F64toI32S, mkexpr(rmode), mkexpr(f64lo)) );
sewardjfd226452004-12-07 19:02:18 +00009980
9981 goto decode_success;
9982 }
9983
9984 /* F2 0F 5A = CVTSD2SS -- convert F64 in mem/low half xmm to F32 in
9985 low 1/4 xmm(G), according to prevailing SSE rounding mode */
9986 if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x5A) {
9987 IRTemp rmode = newTemp(Ity_I32);
9988 IRTemp f64lo = newTemp(Ity_F64);
9989 vassert(sz == 4);
9990
9991 modrm = getIByte(delta+3);
9992 if (epartIsReg(modrm)) {
9993 delta += 3+1;
9994 assign(f64lo, getXMMRegLane64F(eregOfRM(modrm), 0));
9995 DIP("cvtsd2ss %s,%s\n", nameXMMReg(eregOfRM(modrm)),
9996 nameXMMReg(gregOfRM(modrm)));
9997 } else {
9998 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
9999 assign(f64lo, loadLE(Ity_F64, mkexpr(addr)));
10000 delta += 3+alen;
10001 DIP("cvtsd2ss %s,%s\n", dis_buf,
10002 nameXMMReg(gregOfRM(modrm)));
10003 }
10004
10005 assign( rmode, get_sse_roundingmode() );
10006 putXMMRegLane32F(
10007 gregOfRM(modrm), 0,
10008 binop( Iop_F64toF32, mkexpr(rmode), mkexpr(f64lo) )
10009 );
10010
10011 goto decode_success;
10012 }
10013
10014 /* F2 0F 2A = CVTSI2SD -- convert I32 in mem/ireg to F64 in low
10015 half xmm */
10016 if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x2A) {
10017 IRTemp arg32 = newTemp(Ity_I32);
10018 vassert(sz == 4);
10019
10020 modrm = getIByte(delta+3);
sewardjfd226452004-12-07 19:02:18 +000010021 if (epartIsReg(modrm)) {
10022 assign( arg32, getIReg(4, eregOfRM(modrm)) );
10023 delta += 3+1;
10024 DIP("cvtsi2sd %s,%s\n", nameIReg(4, eregOfRM(modrm)),
10025 nameXMMReg(gregOfRM(modrm)));
10026 } else {
10027 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
10028 assign( arg32, loadLE(Ity_I32, mkexpr(addr)) );
10029 delta += 3+alen;
10030 DIP("cvtsi2sd %s,%s\n", dis_buf,
10031 nameXMMReg(gregOfRM(modrm)) );
10032 }
10033
10034 putXMMRegLane64F(
10035 gregOfRM(modrm), 0,
sewardj6c299f32009-12-31 18:00:12 +000010036 unop(Iop_I32StoF64, mkexpr(arg32)) );
sewardjfd226452004-12-07 19:02:18 +000010037
10038 goto decode_success;
10039 }
10040
10041 /* F3 0F 5A = CVTSS2SD -- convert F32 in mem/low 1/4 xmm to F64 in
10042 low half xmm(G) */
10043 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x5A) {
10044 IRTemp f32lo = newTemp(Ity_F32);
10045 vassert(sz == 4);
10046
10047 modrm = getIByte(delta+3);
10048 if (epartIsReg(modrm)) {
10049 delta += 3+1;
10050 assign(f32lo, getXMMRegLane32F(eregOfRM(modrm), 0));
10051 DIP("cvtss2sd %s,%s\n", nameXMMReg(eregOfRM(modrm)),
10052 nameXMMReg(gregOfRM(modrm)));
10053 } else {
10054 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
10055 assign(f32lo, loadLE(Ity_F32, mkexpr(addr)));
10056 delta += 3+alen;
10057 DIP("cvtss2sd %s,%s\n", dis_buf,
10058 nameXMMReg(gregOfRM(modrm)));
10059 }
10060
10061 putXMMRegLane64F( gregOfRM(modrm), 0,
10062 unop( Iop_F32toF64, mkexpr(f32lo) ) );
10063
10064 goto decode_success;
10065 }
10066
10067 /* 66 0F E6 = CVTTPD2DQ -- convert 2 x F64 in mem/xmm to 2 x I32 in
10068 lo half xmm(G), and zero upper half, rounding towards zero */
10069 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xE6) {
10070 IRTemp argV = newTemp(Ity_V128);
10071 IRTemp rmode = newTemp(Ity_I32);
10072
10073 modrm = getIByte(delta+2);
10074 if (epartIsReg(modrm)) {
10075 assign( argV, getXMMReg(eregOfRM(modrm)) );
10076 delta += 2+1;
10077 DIP("cvttpd2dq %s,%s\n", nameXMMReg(eregOfRM(modrm)),
10078 nameXMMReg(gregOfRM(modrm)));
10079 } else {
10080 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
10081 assign( argV, loadLE(Ity_V128, mkexpr(addr)) );
10082 delta += 2+alen;
10083 DIP("cvttpd2dq %s,%s\n", dis_buf,
10084 nameXMMReg(gregOfRM(modrm)) );
10085 }
10086
10087 assign( rmode, mkU32((UInt)Irrm_ZERO) );
10088
10089 t0 = newTemp(Ity_F64);
10090 t1 = newTemp(Ity_F64);
10091 assign( t0, unop(Iop_ReinterpI64asF64,
sewardjf0c1c582005-02-07 23:47:38 +000010092 unop(Iop_V128to64, mkexpr(argV))) );
sewardjfd226452004-12-07 19:02:18 +000010093 assign( t1, unop(Iop_ReinterpI64asF64,
sewardjf0c1c582005-02-07 23:47:38 +000010094 unop(Iop_V128HIto64, mkexpr(argV))) );
sewardjfd226452004-12-07 19:02:18 +000010095
sewardj6c299f32009-12-31 18:00:12 +000010096# define CVT(_t) binop( Iop_F64toI32S, \
sewardjfd226452004-12-07 19:02:18 +000010097 mkexpr(rmode), \
10098 mkexpr(_t) )
10099
10100 putXMMRegLane32( gregOfRM(modrm), 3, mkU32(0) );
10101 putXMMRegLane32( gregOfRM(modrm), 2, mkU32(0) );
10102 putXMMRegLane32( gregOfRM(modrm), 1, CVT(t1) );
10103 putXMMRegLane32( gregOfRM(modrm), 0, CVT(t0) );
10104
10105# undef CVT
10106
10107 goto decode_success;
10108 }
10109
10110 /* F3 0F 5B = CVTTPS2DQ -- convert 4 x F32 in mem/xmm to 4 x I32 in
10111 xmm(G), rounding towards zero */
10112 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x5B) {
10113 IRTemp argV = newTemp(Ity_V128);
10114 IRTemp rmode = newTemp(Ity_I32);
10115 vassert(sz == 4);
10116
10117 modrm = getIByte(delta+3);
10118 if (epartIsReg(modrm)) {
10119 assign( argV, getXMMReg(eregOfRM(modrm)) );
10120 delta += 3+1;
10121 DIP("cvttps2dq %s,%s\n", nameXMMReg(eregOfRM(modrm)),
10122 nameXMMReg(gregOfRM(modrm)));
10123 } else {
10124 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
10125 assign( argV, loadLE(Ity_V128, mkexpr(addr)) );
10126 delta += 3+alen;
10127 DIP("cvttps2dq %s,%s\n", dis_buf,
10128 nameXMMReg(gregOfRM(modrm)) );
10129 }
10130
10131 assign( rmode, mkU32((UInt)Irrm_ZERO) );
10132 breakup128to32s( argV, &t3, &t2, &t1, &t0 );
10133
10134 /* This is less than ideal. If it turns out to be a performance
10135 bottleneck it can be improved. */
10136# define CVT(_t) \
sewardj6c299f32009-12-31 18:00:12 +000010137 binop( Iop_F64toI32S, \
sewardjfd226452004-12-07 19:02:18 +000010138 mkexpr(rmode), \
10139 unop( Iop_F32toF64, \
10140 unop( Iop_ReinterpI32asF32, mkexpr(_t))) )
10141
10142 putXMMRegLane32( gregOfRM(modrm), 3, CVT(t3) );
10143 putXMMRegLane32( gregOfRM(modrm), 2, CVT(t2) );
10144 putXMMRegLane32( gregOfRM(modrm), 1, CVT(t1) );
10145 putXMMRegLane32( gregOfRM(modrm), 0, CVT(t0) );
10146
10147# undef CVT
10148
10149 goto decode_success;
10150 }
10151
10152 /* 66 0F 5E = DIVPD -- div 64Fx2 from R/M to R */
10153 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x5E) {
10154 delta = dis_SSE_E_to_G_all( sorb, delta+2, "divpd", Iop_Div64Fx2 );
10155 goto decode_success;
10156 }
10157
sewardjc2feffc2004-12-08 12:31:22 +000010158 /* F2 0F 5E = DIVSD -- div 64F0x2 from R/M to R */
10159 if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x5E) {
10160 vassert(sz == 4);
10161 delta = dis_SSE_E_to_G_lo64( sorb, delta+3, "divsd", Iop_Div64F0x2 );
10162 goto decode_success;
10163 }
10164
10165 /* 0F AE /5 = LFENCE -- flush pending operations to memory */
10166 /* 0F AE /6 = MFENCE -- flush pending operations to memory */
10167 if (insn[0] == 0x0F && insn[1] == 0xAE
10168 && epartIsReg(insn[2])
10169 && (gregOfRM(insn[2]) == 5 || gregOfRM(insn[2]) == 6)) {
10170 vassert(sz == 4);
10171 delta += 3;
sewardj3e838932005-01-07 12:09:15 +000010172 /* Insert a memory fence. It's sometimes important that these
10173 are carried through to the generated code. */
sewardjc4356f02007-11-09 21:15:04 +000010174 stmt( IRStmt_MBE(Imbe_Fence) );
sewardjc2feffc2004-12-08 12:31:22 +000010175 DIP("%sfence\n", gregOfRM(insn[2])==5 ? "l" : "m");
10176 goto decode_success;
10177 }
10178
10179 /* 66 0F 5F = MAXPD -- max 64Fx2 from R/M to R */
10180 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x5F) {
10181 delta = dis_SSE_E_to_G_all( sorb, delta+2, "maxpd", Iop_Max64Fx2 );
10182 goto decode_success;
10183 }
10184
10185 /* F2 0F 5F = MAXSD -- max 64F0x2 from R/M to R */
10186 if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x5F) {
10187 vassert(sz == 4);
10188 delta = dis_SSE_E_to_G_lo64( sorb, delta+3, "maxsd", Iop_Max64F0x2 );
10189 goto decode_success;
10190 }
10191
10192 /* 66 0F 5D = MINPD -- min 64Fx2 from R/M to R */
10193 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x5D) {
10194 delta = dis_SSE_E_to_G_all( sorb, delta+2, "minpd", Iop_Min64Fx2 );
10195 goto decode_success;
10196 }
10197
10198 /* F2 0F 5D = MINSD -- min 64F0x2 from R/M to R */
10199 if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x5D) {
10200 vassert(sz == 4);
10201 delta = dis_SSE_E_to_G_lo64( sorb, delta+3, "minsd", Iop_Min64F0x2 );
10202 goto decode_success;
10203 }
10204
10205 /* 66 0F 28 = MOVAPD -- move from E (mem or xmm) to G (xmm). */
10206 /* 66 0F 10 = MOVUPD -- move from E (mem or xmm) to G (xmm). */
10207 /* 66 0F 6F = MOVDQA -- move from E (mem or xmm) to G (xmm). */
10208 if (sz == 2 && insn[0] == 0x0F
10209 && (insn[1] == 0x28 || insn[1] == 0x10 || insn[1] == 0x6F)) {
florian55085f82012-11-21 00:36:55 +000010210 const HChar* wot = insn[1]==0x28 ? "apd" :
10211 insn[1]==0x10 ? "upd" : "dqa";
sewardjc2feffc2004-12-08 12:31:22 +000010212 modrm = getIByte(delta+2);
10213 if (epartIsReg(modrm)) {
10214 putXMMReg( gregOfRM(modrm),
10215 getXMMReg( eregOfRM(modrm) ));
10216 DIP("mov%s %s,%s\n", wot, nameXMMReg(eregOfRM(modrm)),
10217 nameXMMReg(gregOfRM(modrm)));
10218 delta += 2+1;
10219 } else {
10220 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
sewardj45ca0b92010-09-30 14:51:51 +000010221 if (insn[1] == 0x28/*movapd*/ || insn[1] == 0x6F/*movdqa*/)
10222 gen_SEGV_if_not_16_aligned( addr );
sewardjc2feffc2004-12-08 12:31:22 +000010223 putXMMReg( gregOfRM(modrm),
10224 loadLE(Ity_V128, mkexpr(addr)) );
10225 DIP("mov%s %s,%s\n", wot, dis_buf,
10226 nameXMMReg(gregOfRM(modrm)));
10227 delta += 2+alen;
10228 }
10229 goto decode_success;
10230 }
10231
sewardj95535fe2004-12-15 17:42:58 +000010232 /* 66 0F 29 = MOVAPD -- move from G (xmm) to E (mem or xmm). */
sewardj1c318772005-03-19 14:27:04 +000010233 /* 66 0F 11 = MOVUPD -- move from G (xmm) to E (mem or xmm). */
10234 if (sz == 2 && insn[0] == 0x0F
10235 && (insn[1] == 0x29 || insn[1] == 0x11)) {
florian55085f82012-11-21 00:36:55 +000010236 const HChar* wot = insn[1]==0x29 ? "apd" : "upd";
sewardj95535fe2004-12-15 17:42:58 +000010237 modrm = getIByte(delta+2);
10238 if (epartIsReg(modrm)) {
10239 /* fall through; awaiting test case */
10240 } else {
10241 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
sewardj45ca0b92010-09-30 14:51:51 +000010242 if (insn[1] == 0x29/*movapd*/)
10243 gen_SEGV_if_not_16_aligned( addr );
sewardj95535fe2004-12-15 17:42:58 +000010244 storeLE( mkexpr(addr), getXMMReg(gregOfRM(modrm)) );
sewardj1c318772005-03-19 14:27:04 +000010245 DIP("mov%s %s,%s\n", wot, nameXMMReg(gregOfRM(modrm)),
10246 dis_buf );
sewardj95535fe2004-12-15 17:42:58 +000010247 delta += 2+alen;
10248 goto decode_success;
10249 }
10250 }
10251
sewardjc2feffc2004-12-08 12:31:22 +000010252 /* 66 0F 6E = MOVD from r/m32 to xmm, zeroing high 3/4 of xmm. */
10253 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x6E) {
10254 modrm = getIByte(delta+2);
10255 if (epartIsReg(modrm)) {
10256 delta += 2+1;
10257 putXMMReg(
10258 gregOfRM(modrm),
sewardjf0c1c582005-02-07 23:47:38 +000010259 unop( Iop_32UtoV128, getIReg(4, eregOfRM(modrm)) )
sewardjc2feffc2004-12-08 12:31:22 +000010260 );
10261 DIP("movd %s, %s\n",
10262 nameIReg(4,eregOfRM(modrm)), nameXMMReg(gregOfRM(modrm)));
10263 } else {
10264 addr = disAMode( &alen, sorb, delta+2, dis_buf );
10265 delta += 2+alen;
10266 putXMMReg(
10267 gregOfRM(modrm),
sewardjf0c1c582005-02-07 23:47:38 +000010268 unop( Iop_32UtoV128,loadLE(Ity_I32, mkexpr(addr)) )
sewardjc2feffc2004-12-08 12:31:22 +000010269 );
10270 DIP("movd %s, %s\n", dis_buf, nameXMMReg(gregOfRM(modrm)));
10271 }
10272 goto decode_success;
10273 }
10274
10275 /* 66 0F 7E = MOVD from xmm low 1/4 to r/m32. */
10276 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x7E) {
10277 modrm = getIByte(delta+2);
10278 if (epartIsReg(modrm)) {
10279 delta += 2+1;
10280 putIReg( 4, eregOfRM(modrm),
10281 getXMMRegLane32(gregOfRM(modrm), 0) );
10282 DIP("movd %s, %s\n",
10283 nameXMMReg(gregOfRM(modrm)), nameIReg(4,eregOfRM(modrm)));
10284 } else {
10285 addr = disAMode( &alen, sorb, delta+2, dis_buf );
10286 delta += 2+alen;
10287 storeLE( mkexpr(addr),
10288 getXMMRegLane32(gregOfRM(modrm), 0) );
10289 DIP("movd %s, %s\n", nameXMMReg(gregOfRM(modrm)), dis_buf);
10290 }
10291 goto decode_success;
10292 }
10293
10294 /* 66 0F 7F = MOVDQA -- move from G (xmm) to E (mem or xmm). */
10295 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x7F) {
10296 modrm = getIByte(delta+2);
10297 if (epartIsReg(modrm)) {
10298 delta += 2+1;
10299 putXMMReg( eregOfRM(modrm),
10300 getXMMReg(gregOfRM(modrm)) );
10301 DIP("movdqa %s, %s\n", nameXMMReg(gregOfRM(modrm)),
10302 nameXMMReg(eregOfRM(modrm)));
10303 } else {
10304 addr = disAMode( &alen, sorb, delta+2, dis_buf );
10305 delta += 2+alen;
sewardj45ca0b92010-09-30 14:51:51 +000010306 gen_SEGV_if_not_16_aligned( addr );
sewardjc2feffc2004-12-08 12:31:22 +000010307 storeLE( mkexpr(addr), getXMMReg(gregOfRM(modrm)) );
10308 DIP("movdqa %s, %s\n", nameXMMReg(gregOfRM(modrm)), dis_buf);
10309 }
10310 goto decode_success;
10311 }
10312
10313 /* F3 0F 6F = MOVDQU -- move from E (mem or xmm) to G (xmm). */
10314 /* Unfortunately can't simply use the MOVDQA case since the
10315 prefix lengths are different (66 vs F3) */
10316 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x6F) {
10317 vassert(sz == 4);
10318 modrm = getIByte(delta+3);
10319 if (epartIsReg(modrm)) {
10320 putXMMReg( gregOfRM(modrm),
10321 getXMMReg( eregOfRM(modrm) ));
10322 DIP("movdqu %s,%s\n", nameXMMReg(eregOfRM(modrm)),
10323 nameXMMReg(gregOfRM(modrm)));
10324 delta += 3+1;
10325 } else {
10326 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
10327 putXMMReg( gregOfRM(modrm),
10328 loadLE(Ity_V128, mkexpr(addr)) );
10329 DIP("movdqu %s,%s\n", dis_buf,
10330 nameXMMReg(gregOfRM(modrm)));
10331 delta += 3+alen;
10332 }
10333 goto decode_success;
10334 }
10335
10336 /* F3 0F 7F = MOVDQU -- move from G (xmm) to E (mem or xmm). */
10337 /* Unfortunately can't simply use the MOVDQA case since the
10338 prefix lengths are different (66 vs F3) */
10339 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x7F) {
10340 vassert(sz == 4);
10341 modrm = getIByte(delta+3);
10342 if (epartIsReg(modrm)) {
10343 delta += 3+1;
10344 putXMMReg( eregOfRM(modrm),
10345 getXMMReg(gregOfRM(modrm)) );
10346 DIP("movdqu %s, %s\n", nameXMMReg(gregOfRM(modrm)),
10347 nameXMMReg(eregOfRM(modrm)));
10348 } else {
10349 addr = disAMode( &alen, sorb, delta+3, dis_buf );
10350 delta += 3+alen;
10351 storeLE( mkexpr(addr), getXMMReg(gregOfRM(modrm)) );
10352 DIP("movdqu %s, %s\n", nameXMMReg(gregOfRM(modrm)), dis_buf);
10353 }
10354 goto decode_success;
10355 }
10356
10357 /* F2 0F D6 = MOVDQ2Q -- move from E (lo half xmm, not mem) to G (mmx). */
10358 if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0xD6) {
10359 vassert(sz == 4);
10360 modrm = getIByte(delta+3);
10361 if (epartIsReg(modrm)) {
10362 do_MMX_preamble();
10363 putMMXReg( gregOfRM(modrm),
10364 getXMMRegLane64( eregOfRM(modrm), 0 ));
10365 DIP("movdq2q %s,%s\n", nameXMMReg(eregOfRM(modrm)),
10366 nameMMXReg(gregOfRM(modrm)));
10367 delta += 3+1;
10368 goto decode_success;
10369 } else {
10370 /* fall through, apparently no mem case for this insn */
10371 }
10372 }
10373
10374 /* 66 0F 16 = MOVHPD -- move from mem to high half of XMM. */
10375 /* These seems identical to MOVHPS. This instruction encoding is
10376 completely crazy. */
10377 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x16) {
10378 modrm = getIByte(delta+2);
10379 if (epartIsReg(modrm)) {
10380 /* fall through; apparently reg-reg is not possible */
10381 } else {
10382 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
10383 delta += 2+alen;
10384 putXMMRegLane64( gregOfRM(modrm), 1/*upper lane*/,
10385 loadLE(Ity_I64, mkexpr(addr)) );
10386 DIP("movhpd %s,%s\n", dis_buf,
10387 nameXMMReg( gregOfRM(modrm) ));
10388 goto decode_success;
10389 }
10390 }
10391
10392 /* 66 0F 17 = MOVHPD -- move from high half of XMM to mem. */
10393 /* Again, this seems identical to MOVHPS. */
10394 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x17) {
10395 if (!epartIsReg(insn[2])) {
10396 delta += 2;
10397 addr = disAMode ( &alen, sorb, delta, dis_buf );
10398 delta += alen;
10399 storeLE( mkexpr(addr),
10400 getXMMRegLane64( gregOfRM(insn[2]),
10401 1/*upper lane*/ ) );
10402 DIP("movhpd %s,%s\n", nameXMMReg( gregOfRM(insn[2]) ),
10403 dis_buf);
10404 goto decode_success;
10405 }
10406 /* else fall through */
10407 }
10408
10409 /* 66 0F 12 = MOVLPD -- move from mem to low half of XMM. */
10410 /* Identical to MOVLPS ? */
10411 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x12) {
10412 modrm = getIByte(delta+2);
10413 if (epartIsReg(modrm)) {
10414 /* fall through; apparently reg-reg is not possible */
10415 } else {
10416 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
10417 delta += 2+alen;
10418 putXMMRegLane64( gregOfRM(modrm), 0/*lower lane*/,
10419 loadLE(Ity_I64, mkexpr(addr)) );
10420 DIP("movlpd %s, %s\n",
10421 dis_buf, nameXMMReg( gregOfRM(modrm) ));
10422 goto decode_success;
10423 }
10424 }
10425
10426 /* 66 0F 13 = MOVLPD -- move from low half of XMM to mem. */
10427 /* Identical to MOVLPS ? */
10428 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x13) {
10429 if (!epartIsReg(insn[2])) {
10430 delta += 2;
10431 addr = disAMode ( &alen, sorb, delta, dis_buf );
10432 delta += alen;
10433 storeLE( mkexpr(addr),
10434 getXMMRegLane64( gregOfRM(insn[2]),
10435 0/*lower lane*/ ) );
10436 DIP("movlpd %s, %s\n", nameXMMReg( gregOfRM(insn[2]) ),
10437 dis_buf);
10438 goto decode_success;
10439 }
10440 /* else fall through */
10441 }
10442
10443 /* 66 0F 50 = MOVMSKPD - move 2 sign bits from 2 x F64 in xmm(E) to
10444 2 lowest bits of ireg(G) */
10445 if (insn[0] == 0x0F && insn[1] == 0x50) {
10446 modrm = getIByte(delta+2);
10447 if (sz == 2 && epartIsReg(modrm)) {
10448 Int src;
10449 t0 = newTemp(Ity_I32);
10450 t1 = newTemp(Ity_I32);
10451 delta += 2+1;
10452 src = eregOfRM(modrm);
10453 assign( t0, binop( Iop_And32,
10454 binop(Iop_Shr32, getXMMRegLane32(src,1), mkU8(31)),
10455 mkU32(1) ));
10456 assign( t1, binop( Iop_And32,
10457 binop(Iop_Shr32, getXMMRegLane32(src,3), mkU8(30)),
10458 mkU32(2) ));
10459 putIReg(4, gregOfRM(modrm),
10460 binop(Iop_Or32, mkexpr(t0), mkexpr(t1))
10461 );
10462 DIP("movmskpd %s,%s\n", nameXMMReg(src),
10463 nameIReg(4, gregOfRM(modrm)));
10464 goto decode_success;
10465 }
10466 /* else fall through */
10467 }
10468
sewardjd71ba832006-12-27 01:15:29 +000010469 /* 66 0F F7 = MASKMOVDQU -- store selected bytes of double quadword */
10470 if (insn[0] == 0x0F && insn[1] == 0xF7) {
10471 modrm = getIByte(delta+2);
10472 if (sz == 2 && epartIsReg(modrm)) {
10473 IRTemp regD = newTemp(Ity_V128);
10474 IRTemp mask = newTemp(Ity_V128);
10475 IRTemp olddata = newTemp(Ity_V128);
10476 IRTemp newdata = newTemp(Ity_V128);
10477 addr = newTemp(Ity_I32);
10478
10479 assign( addr, handleSegOverride( sorb, getIReg(4, R_EDI) ));
10480 assign( regD, getXMMReg( gregOfRM(modrm) ));
10481
10482 /* Unfortunately can't do the obvious thing with SarN8x16
10483 here since that can't be re-emitted as SSE2 code - no such
10484 insn. */
10485 assign(
10486 mask,
10487 binop(Iop_64HLtoV128,
10488 binop(Iop_SarN8x8,
10489 getXMMRegLane64( eregOfRM(modrm), 1 ),
10490 mkU8(7) ),
10491 binop(Iop_SarN8x8,
10492 getXMMRegLane64( eregOfRM(modrm), 0 ),
10493 mkU8(7) ) ));
10494 assign( olddata, loadLE( Ity_V128, mkexpr(addr) ));
10495 assign( newdata,
10496 binop(Iop_OrV128,
10497 binop(Iop_AndV128,
10498 mkexpr(regD),
10499 mkexpr(mask) ),
10500 binop(Iop_AndV128,
10501 mkexpr(olddata),
10502 unop(Iop_NotV128, mkexpr(mask)))) );
10503 storeLE( mkexpr(addr), mkexpr(newdata) );
10504
10505 delta += 2+1;
10506 DIP("maskmovdqu %s,%s\n", nameXMMReg( eregOfRM(modrm) ),
10507 nameXMMReg( gregOfRM(modrm) ) );
10508 goto decode_success;
10509 }
10510 /* else fall through */
10511 }
10512
sewardjc2feffc2004-12-08 12:31:22 +000010513 /* 66 0F E7 = MOVNTDQ -- for us, just a plain SSE store. */
10514 if (insn[0] == 0x0F && insn[1] == 0xE7) {
10515 modrm = getIByte(delta+2);
10516 if (sz == 2 && !epartIsReg(modrm)) {
10517 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
sewardj45ca0b92010-09-30 14:51:51 +000010518 gen_SEGV_if_not_16_aligned( addr );
sewardjc2feffc2004-12-08 12:31:22 +000010519 storeLE( mkexpr(addr), getXMMReg(gregOfRM(modrm)) );
10520 DIP("movntdq %s,%s\n", dis_buf,
10521 nameXMMReg(gregOfRM(modrm)));
10522 delta += 2+alen;
10523 goto decode_success;
10524 }
10525 /* else fall through */
10526 }
10527
10528 /* 0F C3 = MOVNTI -- for us, just a plain ireg store. */
10529 if (insn[0] == 0x0F && insn[1] == 0xC3) {
10530 vassert(sz == 4);
10531 modrm = getIByte(delta+2);
10532 if (!epartIsReg(modrm)) {
10533 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
10534 storeLE( mkexpr(addr), getIReg(4, gregOfRM(modrm)) );
10535 DIP("movnti %s,%s\n", dis_buf,
10536 nameIReg(4, gregOfRM(modrm)));
10537 delta += 2+alen;
10538 goto decode_success;
10539 }
10540 /* else fall through */
10541 }
10542
sewardj95535fe2004-12-15 17:42:58 +000010543 /* 66 0F D6 = MOVQ -- move 64 bits from G (lo half xmm) to E (mem
10544 or lo half xmm). */
sewardj9ee82862004-12-14 01:16:59 +000010545 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD6) {
10546 modrm = getIByte(delta+2);
10547 if (epartIsReg(modrm)) {
10548 /* fall through, awaiting test case */
sewardj6d7ccd52005-05-14 02:04:12 +000010549 /* dst: lo half copied, hi half zeroed */
sewardj9ee82862004-12-14 01:16:59 +000010550 } else {
10551 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
10552 storeLE( mkexpr(addr),
10553 getXMMRegLane64( gregOfRM(modrm), 0 ));
10554 DIP("movq %s,%s\n", nameXMMReg(gregOfRM(modrm)), dis_buf );
10555 delta += 2+alen;
10556 goto decode_success;
10557 }
10558 }
10559
sewardjc2feffc2004-12-08 12:31:22 +000010560 /* F3 0F D6 = MOVQ2DQ -- move from E (mmx) to G (lo half xmm, zero
10561 hi half). */
10562 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0xD6) {
10563 vassert(sz == 4);
10564 modrm = getIByte(delta+3);
10565 if (epartIsReg(modrm)) {
10566 do_MMX_preamble();
10567 putXMMReg( gregOfRM(modrm),
sewardjf0c1c582005-02-07 23:47:38 +000010568 unop(Iop_64UtoV128, getMMXReg( eregOfRM(modrm) )) );
sewardjc2feffc2004-12-08 12:31:22 +000010569 DIP("movq2dq %s,%s\n", nameMMXReg(eregOfRM(modrm)),
10570 nameXMMReg(gregOfRM(modrm)));
10571 delta += 3+1;
10572 goto decode_success;
10573 } else {
10574 /* fall through, apparently no mem case for this insn */
10575 }
10576 }
10577
sewardj95535fe2004-12-15 17:42:58 +000010578 /* F3 0F 7E = MOVQ -- move 64 bits from E (mem or lo half xmm) to
sewardj6d7ccd52005-05-14 02:04:12 +000010579 G (lo half xmm). Upper half of G is zeroed out. */
sewardj95535fe2004-12-15 17:42:58 +000010580 /* F2 0F 10 = MOVSD -- move 64 bits from E (mem or lo half xmm) to
10581 G (lo half xmm). If E is mem, upper half of G is zeroed out.
sewardj6d7ccd52005-05-14 02:04:12 +000010582 If E is reg, upper half of G is unchanged. */
sewardj95535fe2004-12-15 17:42:58 +000010583 if ((insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x10)
10584 || (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x7E)) {
sewardjc2feffc2004-12-08 12:31:22 +000010585 vassert(sz == 4);
10586 modrm = getIByte(delta+3);
10587 if (epartIsReg(modrm)) {
10588 putXMMRegLane64( gregOfRM(modrm), 0,
10589 getXMMRegLane64( eregOfRM(modrm), 0 ));
sewardj6d7ccd52005-05-14 02:04:12 +000010590 if (insn[0] == 0xF3/*MOVQ*/) {
10591 /* zero bits 127:64 */
10592 putXMMRegLane64( gregOfRM(modrm), 1, mkU64(0) );
10593 }
sewardjc2feffc2004-12-08 12:31:22 +000010594 DIP("movsd %s,%s\n", nameXMMReg(eregOfRM(modrm)),
10595 nameXMMReg(gregOfRM(modrm)));
10596 delta += 3+1;
10597 } else {
10598 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
sewardjad50db02005-04-06 01:45:44 +000010599 /* zero bits 127:64 */
sewardj5bf1fd42005-04-06 01:11:08 +000010600 putXMMRegLane64( gregOfRM(modrm), 1, mkU64(0) );
sewardjad50db02005-04-06 01:45:44 +000010601 /* write bits 63:0 */
sewardjc2feffc2004-12-08 12:31:22 +000010602 putXMMRegLane64( gregOfRM(modrm), 0,
10603 loadLE(Ity_I64, mkexpr(addr)) );
10604 DIP("movsd %s,%s\n", dis_buf,
10605 nameXMMReg(gregOfRM(modrm)));
10606 delta += 3+alen;
10607 }
10608 goto decode_success;
10609 }
10610
10611 /* F2 0F 11 = MOVSD -- move 64 bits from G (lo half xmm) to E (mem
10612 or lo half xmm). */
10613 if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x11) {
10614 vassert(sz == 4);
10615 modrm = getIByte(delta+3);
10616 if (epartIsReg(modrm)) {
sewardjb7ba04f2008-11-17 20:25:37 +000010617 putXMMRegLane64( eregOfRM(modrm), 0,
10618 getXMMRegLane64( gregOfRM(modrm), 0 ));
10619 DIP("movsd %s,%s\n", nameXMMReg(gregOfRM(modrm)),
10620 nameXMMReg(eregOfRM(modrm)));
10621 delta += 3+1;
sewardjc2feffc2004-12-08 12:31:22 +000010622 } else {
10623 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
10624 storeLE( mkexpr(addr),
sewardj519d66f2004-12-15 11:57:58 +000010625 getXMMRegLane64(gregOfRM(modrm), 0) );
10626 DIP("movsd %s,%s\n", nameXMMReg(gregOfRM(modrm)),
sewardjc2feffc2004-12-08 12:31:22 +000010627 dis_buf);
10628 delta += 3+alen;
sewardjc2feffc2004-12-08 12:31:22 +000010629 }
sewardjb7ba04f2008-11-17 20:25:37 +000010630 goto decode_success;
sewardjc2feffc2004-12-08 12:31:22 +000010631 }
sewardjfd226452004-12-07 19:02:18 +000010632
sewardj008754b2004-12-08 14:37:10 +000010633 /* 66 0F 59 = MULPD -- mul 64Fx2 from R/M to R */
10634 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x59) {
10635 delta = dis_SSE_E_to_G_all( sorb, delta+2, "mulpd", Iop_Mul64Fx2 );
10636 goto decode_success;
10637 }
10638
10639 /* F2 0F 59 = MULSD -- mul 64F0x2 from R/M to R */
10640 if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x59) {
10641 vassert(sz == 4);
10642 delta = dis_SSE_E_to_G_lo64( sorb, delta+3, "mulsd", Iop_Mul64F0x2 );
10643 goto decode_success;
10644 }
10645
10646 /* 66 0F 56 = ORPD -- G = G and E */
10647 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x56) {
sewardjf0c1c582005-02-07 23:47:38 +000010648 delta = dis_SSE_E_to_G_all( sorb, delta+2, "orpd", Iop_OrV128 );
sewardj008754b2004-12-08 14:37:10 +000010649 goto decode_success;
10650 }
10651
10652 /* 66 0F C6 /r ib = SHUFPD -- shuffle packed F64s */
10653 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xC6) {
10654 Int select;
10655 IRTemp sV = newTemp(Ity_V128);
10656 IRTemp dV = newTemp(Ity_V128);
10657 IRTemp s1 = newTemp(Ity_I64);
10658 IRTemp s0 = newTemp(Ity_I64);
10659 IRTemp d1 = newTemp(Ity_I64);
10660 IRTemp d0 = newTemp(Ity_I64);
10661
10662 modrm = insn[2];
10663 assign( dV, getXMMReg(gregOfRM(modrm)) );
10664
10665 if (epartIsReg(modrm)) {
10666 assign( sV, getXMMReg(eregOfRM(modrm)) );
10667 select = (Int)insn[3];
10668 delta += 2+2;
10669 DIP("shufpd $%d,%s,%s\n", select,
10670 nameXMMReg(eregOfRM(modrm)),
10671 nameXMMReg(gregOfRM(modrm)));
10672 } else {
10673 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
10674 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
10675 select = (Int)insn[2+alen];
10676 delta += 3+alen;
10677 DIP("shufpd $%d,%s,%s\n", select,
10678 dis_buf,
10679 nameXMMReg(gregOfRM(modrm)));
10680 }
10681
sewardjf0c1c582005-02-07 23:47:38 +000010682 assign( d1, unop(Iop_V128HIto64, mkexpr(dV)) );
10683 assign( d0, unop(Iop_V128to64, mkexpr(dV)) );
10684 assign( s1, unop(Iop_V128HIto64, mkexpr(sV)) );
10685 assign( s0, unop(Iop_V128to64, mkexpr(sV)) );
sewardj008754b2004-12-08 14:37:10 +000010686
10687# define SELD(n) mkexpr((n)==0 ? d0 : d1)
10688# define SELS(n) mkexpr((n)==0 ? s0 : s1)
10689
10690 putXMMReg(
10691 gregOfRM(modrm),
sewardjf0c1c582005-02-07 23:47:38 +000010692 binop(Iop_64HLtoV128, SELS((select>>1)&1), SELD((select>>0)&1) )
sewardj008754b2004-12-08 14:37:10 +000010693 );
10694
10695# undef SELD
10696# undef SELS
10697
10698 goto decode_success;
10699 }
10700
10701 /* 66 0F 51 = SQRTPD -- approx sqrt 64Fx2 from R/M to R */
10702 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x51) {
10703 delta = dis_SSE_E_to_G_unary_all( sorb, delta+2,
10704 "sqrtpd", Iop_Sqrt64Fx2 );
10705 goto decode_success;
10706 }
10707
10708 /* F2 0F 51 = SQRTSD -- approx sqrt 64F0x2 from R/M to R */
10709 if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x51) {
10710 vassert(sz == 4);
10711 delta = dis_SSE_E_to_G_unary_lo64( sorb, delta+3,
10712 "sqrtsd", Iop_Sqrt64F0x2 );
10713 goto decode_success;
10714 }
10715
10716 /* 66 0F 5C = SUBPD -- sub 64Fx2 from R/M to R */
10717 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x5C) {
10718 delta = dis_SSE_E_to_G_all( sorb, delta+2, "subpd", Iop_Sub64Fx2 );
10719 goto decode_success;
10720 }
10721
10722 /* F2 0F 5C = SUBSD -- sub 64F0x2 from R/M to R */
10723 if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x5C) {
10724 vassert(sz == 4);
10725 delta = dis_SSE_E_to_G_lo64( sorb, delta+3, "subsd", Iop_Sub64F0x2 );
10726 goto decode_success;
10727 }
10728
10729 /* 66 0F 15 = UNPCKHPD -- unpack and interleave high part F64s */
10730 /* 66 0F 14 = UNPCKLPD -- unpack and interleave low part F64s */
10731 /* These just appear to be special cases of SHUFPS */
10732 if (sz == 2 && insn[0] == 0x0F && (insn[1] == 0x15 || insn[1] == 0x14)) {
10733 IRTemp s1 = newTemp(Ity_I64);
10734 IRTemp s0 = newTemp(Ity_I64);
10735 IRTemp d1 = newTemp(Ity_I64);
10736 IRTemp d0 = newTemp(Ity_I64);
10737 IRTemp sV = newTemp(Ity_V128);
10738 IRTemp dV = newTemp(Ity_V128);
sewardj2d49b432005-02-01 00:37:06 +000010739 Bool hi = toBool(insn[1] == 0x15);
sewardj008754b2004-12-08 14:37:10 +000010740
10741 modrm = insn[2];
10742 assign( dV, getXMMReg(gregOfRM(modrm)) );
10743
10744 if (epartIsReg(modrm)) {
10745 assign( sV, getXMMReg(eregOfRM(modrm)) );
10746 delta += 2+1;
10747 DIP("unpck%sps %s,%s\n", hi ? "h" : "l",
10748 nameXMMReg(eregOfRM(modrm)),
10749 nameXMMReg(gregOfRM(modrm)));
10750 } else {
10751 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
10752 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
10753 delta += 2+alen;
10754 DIP("unpck%sps %s,%s\n", hi ? "h" : "l",
10755 dis_buf,
10756 nameXMMReg(gregOfRM(modrm)));
10757 }
10758
sewardjf0c1c582005-02-07 23:47:38 +000010759 assign( d1, unop(Iop_V128HIto64, mkexpr(dV)) );
10760 assign( d0, unop(Iop_V128to64, mkexpr(dV)) );
10761 assign( s1, unop(Iop_V128HIto64, mkexpr(sV)) );
10762 assign( s0, unop(Iop_V128to64, mkexpr(sV)) );
sewardj008754b2004-12-08 14:37:10 +000010763
10764 if (hi) {
10765 putXMMReg( gregOfRM(modrm),
sewardjf0c1c582005-02-07 23:47:38 +000010766 binop(Iop_64HLtoV128, mkexpr(s1), mkexpr(d1)) );
sewardj008754b2004-12-08 14:37:10 +000010767 } else {
10768 putXMMReg( gregOfRM(modrm),
sewardjf0c1c582005-02-07 23:47:38 +000010769 binop(Iop_64HLtoV128, mkexpr(s0), mkexpr(d0)) );
sewardj008754b2004-12-08 14:37:10 +000010770 }
10771
10772 goto decode_success;
10773 }
10774
10775 /* 66 0F 57 = XORPD -- G = G and E */
10776 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x57) {
sewardjf0c1c582005-02-07 23:47:38 +000010777 delta = dis_SSE_E_to_G_all( sorb, delta+2, "xorpd", Iop_XorV128 );
sewardj008754b2004-12-08 14:37:10 +000010778 goto decode_success;
10779 }
sewardj636ad762004-12-07 11:16:04 +000010780
sewardj164f9272004-12-09 00:39:32 +000010781 /* 66 0F 6B = PACKSSDW */
10782 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x6B) {
10783 delta = dis_SSEint_E_to_G( sorb, delta+2,
sewardjc9bff7d2011-06-15 15:09:37 +000010784 "packssdw",
sewardj5f438dd2011-06-16 11:36:23 +000010785 Iop_QNarrowBin32Sto16Sx8, True );
sewardj164f9272004-12-09 00:39:32 +000010786 goto decode_success;
10787 }
10788
10789 /* 66 0F 63 = PACKSSWB */
10790 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x63) {
10791 delta = dis_SSEint_E_to_G( sorb, delta+2,
sewardjc9bff7d2011-06-15 15:09:37 +000010792 "packsswb",
sewardj5f438dd2011-06-16 11:36:23 +000010793 Iop_QNarrowBin16Sto8Sx16, True );
sewardj164f9272004-12-09 00:39:32 +000010794 goto decode_success;
10795 }
10796
10797 /* 66 0F 67 = PACKUSWB */
10798 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x67) {
10799 delta = dis_SSEint_E_to_G( sorb, delta+2,
sewardjc9bff7d2011-06-15 15:09:37 +000010800 "packuswb",
sewardj5f438dd2011-06-16 11:36:23 +000010801 Iop_QNarrowBin16Sto8Ux16, True );
sewardj164f9272004-12-09 00:39:32 +000010802 goto decode_success;
10803 }
10804
10805 /* 66 0F FC = PADDB */
10806 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xFC) {
10807 delta = dis_SSEint_E_to_G( sorb, delta+2,
10808 "paddb", Iop_Add8x16, False );
10809 goto decode_success;
10810 }
10811
10812 /* 66 0F FE = PADDD */
10813 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xFE) {
10814 delta = dis_SSEint_E_to_G( sorb, delta+2,
10815 "paddd", Iop_Add32x4, False );
10816 goto decode_success;
10817 }
10818
10819 /* ***--- this is an MMX class insn introduced in SSE2 ---*** */
10820 /* 0F D4 = PADDQ -- add 64x1 */
10821 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xD4) {
10822 do_MMX_preamble();
10823 delta = dis_MMXop_regmem_to_reg (
10824 sorb, delta+2, insn[1], "paddq", False );
10825 goto decode_success;
10826 }
10827
10828 /* 66 0F D4 = PADDQ */
10829 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD4) {
10830 delta = dis_SSEint_E_to_G( sorb, delta+2,
10831 "paddq", Iop_Add64x2, False );
10832 goto decode_success;
10833 }
10834
10835 /* 66 0F FD = PADDW */
10836 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xFD) {
10837 delta = dis_SSEint_E_to_G( sorb, delta+2,
10838 "paddw", Iop_Add16x8, False );
10839 goto decode_success;
10840 }
10841
10842 /* 66 0F EC = PADDSB */
10843 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xEC) {
10844 delta = dis_SSEint_E_to_G( sorb, delta+2,
10845 "paddsb", Iop_QAdd8Sx16, False );
10846 goto decode_success;
10847 }
10848
10849 /* 66 0F ED = PADDSW */
10850 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xED) {
10851 delta = dis_SSEint_E_to_G( sorb, delta+2,
10852 "paddsw", Iop_QAdd16Sx8, False );
10853 goto decode_success;
10854 }
10855
10856 /* 66 0F DC = PADDUSB */
10857 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xDC) {
10858 delta = dis_SSEint_E_to_G( sorb, delta+2,
10859 "paddusb", Iop_QAdd8Ux16, False );
10860 goto decode_success;
10861 }
10862
10863 /* 66 0F DD = PADDUSW */
10864 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xDD) {
10865 delta = dis_SSEint_E_to_G( sorb, delta+2,
10866 "paddusw", Iop_QAdd16Ux8, False );
10867 goto decode_success;
10868 }
10869
10870 /* 66 0F DB = PAND */
10871 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xDB) {
sewardjf0c1c582005-02-07 23:47:38 +000010872 delta = dis_SSE_E_to_G_all( sorb, delta+2, "pand", Iop_AndV128 );
sewardj164f9272004-12-09 00:39:32 +000010873 goto decode_success;
10874 }
10875
10876 /* 66 0F DF = PANDN */
10877 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xDF) {
sewardjf0c1c582005-02-07 23:47:38 +000010878 delta = dis_SSE_E_to_G_all_invG( sorb, delta+2, "pandn", Iop_AndV128 );
sewardj164f9272004-12-09 00:39:32 +000010879 goto decode_success;
10880 }
10881
10882 /* 66 0F E0 = PAVGB */
10883 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xE0) {
10884 delta = dis_SSEint_E_to_G( sorb, delta+2,
10885 "pavgb", Iop_Avg8Ux16, False );
10886 goto decode_success;
10887 }
10888
10889 /* 66 0F E3 = PAVGW */
10890 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xE3) {
10891 delta = dis_SSEint_E_to_G( sorb, delta+2,
10892 "pavgw", Iop_Avg16Ux8, False );
10893 goto decode_success;
10894 }
10895
sewardje5854d62004-12-09 03:44:34 +000010896 /* 66 0F 74 = PCMPEQB */
10897 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x74) {
10898 delta = dis_SSEint_E_to_G( sorb, delta+2,
10899 "pcmpeqb", Iop_CmpEQ8x16, False );
10900 goto decode_success;
10901 }
10902
10903 /* 66 0F 76 = PCMPEQD */
10904 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x76) {
10905 delta = dis_SSEint_E_to_G( sorb, delta+2,
10906 "pcmpeqd", Iop_CmpEQ32x4, False );
10907 goto decode_success;
10908 }
10909
10910 /* 66 0F 75 = PCMPEQW */
10911 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x75) {
10912 delta = dis_SSEint_E_to_G( sorb, delta+2,
10913 "pcmpeqw", Iop_CmpEQ16x8, False );
10914 goto decode_success;
10915 }
10916
10917 /* 66 0F 64 = PCMPGTB */
10918 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x64) {
10919 delta = dis_SSEint_E_to_G( sorb, delta+2,
10920 "pcmpgtb", Iop_CmpGT8Sx16, False );
10921 goto decode_success;
10922 }
10923
10924 /* 66 0F 66 = PCMPGTD */
10925 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x66) {
10926 delta = dis_SSEint_E_to_G( sorb, delta+2,
10927 "pcmpgtd", Iop_CmpGT32Sx4, False );
10928 goto decode_success;
10929 }
10930
10931 /* 66 0F 65 = PCMPGTW */
10932 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x65) {
10933 delta = dis_SSEint_E_to_G( sorb, delta+2,
10934 "pcmpgtw", Iop_CmpGT16Sx8, False );
10935 goto decode_success;
10936 }
10937
10938 /* 66 0F C5 = PEXTRW -- extract 16-bit field from xmm(E) and put
10939 zero-extend of it in ireg(G). */
10940 if (insn[0] == 0x0F && insn[1] == 0xC5) {
10941 modrm = insn[2];
10942 if (sz == 2 && epartIsReg(modrm)) {
10943 t5 = newTemp(Ity_V128);
10944 t4 = newTemp(Ity_I16);
10945 assign(t5, getXMMReg(eregOfRM(modrm)));
10946 breakup128to32s( t5, &t3, &t2, &t1, &t0 );
10947 switch (insn[3] & 7) {
10948 case 0: assign(t4, unop(Iop_32to16, mkexpr(t0))); break;
10949 case 1: assign(t4, unop(Iop_32HIto16, mkexpr(t0))); break;
10950 case 2: assign(t4, unop(Iop_32to16, mkexpr(t1))); break;
10951 case 3: assign(t4, unop(Iop_32HIto16, mkexpr(t1))); break;
10952 case 4: assign(t4, unop(Iop_32to16, mkexpr(t2))); break;
10953 case 5: assign(t4, unop(Iop_32HIto16, mkexpr(t2))); break;
10954 case 6: assign(t4, unop(Iop_32to16, mkexpr(t3))); break;
10955 case 7: assign(t4, unop(Iop_32HIto16, mkexpr(t3))); break;
sewardjba89f4c2005-04-07 17:31:27 +000010956 default: vassert(0); /*NOTREACHED*/
sewardje5854d62004-12-09 03:44:34 +000010957 }
10958 putIReg(4, gregOfRM(modrm), unop(Iop_16Uto32, mkexpr(t4)));
10959 DIP("pextrw $%d,%s,%s\n",
10960 (Int)insn[3], nameXMMReg(eregOfRM(modrm)),
10961 nameIReg(4,gregOfRM(modrm)));
10962 delta += 4;
10963 goto decode_success;
10964 }
10965 /* else fall through */
10966 }
10967
10968 /* 66 0F C4 = PINSRW -- get 16 bits from E(mem or low half ireg) and
10969 put it into the specified lane of xmm(G). */
10970 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xC4) {
10971 Int lane;
10972 t4 = newTemp(Ity_I16);
10973 modrm = insn[2];
10974
10975 if (epartIsReg(modrm)) {
10976 assign(t4, getIReg(2, eregOfRM(modrm)));
sewardjaac7e082005-03-17 14:03:46 +000010977 delta += 3+1;
10978 lane = insn[3+1-1];
florianb1737742015-08-03 16:03:13 +000010979 DIP("pinsrw $%d,%s,%s\n", lane,
sewardje5854d62004-12-09 03:44:34 +000010980 nameIReg(2,eregOfRM(modrm)),
10981 nameXMMReg(gregOfRM(modrm)));
10982 } else {
sewardjaac7e082005-03-17 14:03:46 +000010983 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
10984 delta += 3+alen;
10985 lane = insn[3+alen-1];
10986 assign(t4, loadLE(Ity_I16, mkexpr(addr)));
florianb1737742015-08-03 16:03:13 +000010987 DIP("pinsrw $%d,%s,%s\n", lane,
sewardjaac7e082005-03-17 14:03:46 +000010988 dis_buf,
10989 nameXMMReg(gregOfRM(modrm)));
sewardje5854d62004-12-09 03:44:34 +000010990 }
10991
10992 putXMMRegLane16( gregOfRM(modrm), lane & 7, mkexpr(t4) );
10993 goto decode_success;
10994 }
10995
sewardjb8a3dea2005-10-04 20:00:49 +000010996 /* 66 0F F5 = PMADDWD -- Multiply and add packed integers from
10997 E(xmm or mem) to G(xmm) */
10998 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xF5) {
10999 IRTemp s1V = newTemp(Ity_V128);
11000 IRTemp s2V = newTemp(Ity_V128);
11001 IRTemp dV = newTemp(Ity_V128);
11002 IRTemp s1Hi = newTemp(Ity_I64);
11003 IRTemp s1Lo = newTemp(Ity_I64);
11004 IRTemp s2Hi = newTemp(Ity_I64);
11005 IRTemp s2Lo = newTemp(Ity_I64);
11006 IRTemp dHi = newTemp(Ity_I64);
11007 IRTemp dLo = newTemp(Ity_I64);
11008 modrm = insn[2];
11009 if (epartIsReg(modrm)) {
11010 assign( s1V, getXMMReg(eregOfRM(modrm)) );
11011 delta += 2+1;
11012 DIP("pmaddwd %s,%s\n", nameXMMReg(eregOfRM(modrm)),
11013 nameXMMReg(gregOfRM(modrm)));
11014 } else {
11015 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
11016 assign( s1V, loadLE(Ity_V128, mkexpr(addr)) );
11017 delta += 2+alen;
11018 DIP("pmaddwd %s,%s\n", dis_buf,
11019 nameXMMReg(gregOfRM(modrm)));
11020 }
11021 assign( s2V, getXMMReg(gregOfRM(modrm)) );
11022 assign( s1Hi, unop(Iop_V128HIto64, mkexpr(s1V)) );
11023 assign( s1Lo, unop(Iop_V128to64, mkexpr(s1V)) );
11024 assign( s2Hi, unop(Iop_V128HIto64, mkexpr(s2V)) );
11025 assign( s2Lo, unop(Iop_V128to64, mkexpr(s2V)) );
11026 assign( dHi, mkIRExprCCall(
11027 Ity_I64, 0/*regparms*/,
11028 "x86g_calculate_mmx_pmaddwd",
11029 &x86g_calculate_mmx_pmaddwd,
11030 mkIRExprVec_2( mkexpr(s1Hi), mkexpr(s2Hi))
11031 ));
11032 assign( dLo, mkIRExprCCall(
11033 Ity_I64, 0/*regparms*/,
11034 "x86g_calculate_mmx_pmaddwd",
11035 &x86g_calculate_mmx_pmaddwd,
11036 mkIRExprVec_2( mkexpr(s1Lo), mkexpr(s2Lo))
11037 ));
11038 assign( dV, binop(Iop_64HLtoV128, mkexpr(dHi), mkexpr(dLo))) ;
11039 putXMMReg(gregOfRM(modrm), mkexpr(dV));
11040 goto decode_success;
11041 }
11042
sewardje5854d62004-12-09 03:44:34 +000011043 /* 66 0F EE = PMAXSW -- 16x8 signed max */
11044 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xEE) {
11045 delta = dis_SSEint_E_to_G( sorb, delta+2,
11046 "pmaxsw", Iop_Max16Sx8, False );
11047 goto decode_success;
11048 }
11049
11050 /* 66 0F DE = PMAXUB -- 8x16 unsigned max */
11051 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xDE) {
11052 delta = dis_SSEint_E_to_G( sorb, delta+2,
11053 "pmaxub", Iop_Max8Ux16, False );
11054 goto decode_success;
11055 }
11056
11057 /* 66 0F EA = PMINSW -- 16x8 signed min */
11058 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xEA) {
11059 delta = dis_SSEint_E_to_G( sorb, delta+2,
11060 "pminsw", Iop_Min16Sx8, False );
11061 goto decode_success;
11062 }
11063
11064 /* 66 0F DA = PMINUB -- 8x16 unsigned min */
11065 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xDA) {
11066 delta = dis_SSEint_E_to_G( sorb, delta+2,
11067 "pminub", Iop_Min8Ux16, False );
11068 goto decode_success;
11069 }
11070
sewardje13074c2012-11-08 10:57:08 +000011071 /* 66 0F D7 = PMOVMSKB -- extract sign bits from each of 16 lanes
11072 in xmm(E), turn them into a byte, and put zero-extend of it in
11073 ireg(G). */
sewardje5854d62004-12-09 03:44:34 +000011074 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD7) {
11075 modrm = insn[2];
11076 if (epartIsReg(modrm)) {
11077 t0 = newTemp(Ity_I64);
11078 t1 = newTemp(Ity_I64);
11079 assign(t0, getXMMRegLane64(eregOfRM(modrm), 0));
11080 assign(t1, getXMMRegLane64(eregOfRM(modrm), 1));
11081 t5 = newTemp(Ity_I32);
sewardje13074c2012-11-08 10:57:08 +000011082 assign(t5,
11083 unop(Iop_16Uto32,
11084 binop(Iop_8HLto16,
11085 unop(Iop_GetMSBs8x8, mkexpr(t1)),
11086 unop(Iop_GetMSBs8x8, mkexpr(t0)))));
sewardje5854d62004-12-09 03:44:34 +000011087 putIReg(4, gregOfRM(modrm), mkexpr(t5));
11088 DIP("pmovmskb %s,%s\n", nameXMMReg(eregOfRM(modrm)),
11089 nameIReg(4,gregOfRM(modrm)));
11090 delta += 3;
11091 goto decode_success;
11092 }
11093 /* else fall through */
11094 }
11095
11096 /* 66 0F E4 = PMULHUW -- 16x8 hi-half of unsigned widening multiply */
11097 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xE4) {
11098 delta = dis_SSEint_E_to_G( sorb, delta+2,
11099 "pmulhuw", Iop_MulHi16Ux8, False );
11100 goto decode_success;
11101 }
11102
11103 /* 66 0F E5 = PMULHW -- 16x8 hi-half of signed widening multiply */
11104 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xE5) {
11105 delta = dis_SSEint_E_to_G( sorb, delta+2,
11106 "pmulhw", Iop_MulHi16Sx8, False );
11107 goto decode_success;
11108 }
11109
11110 /* 66 0F D5 = PMULHL -- 16x8 multiply */
11111 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD5) {
11112 delta = dis_SSEint_E_to_G( sorb, delta+2,
11113 "pmullw", Iop_Mul16x8, False );
11114 goto decode_success;
11115 }
11116
11117 /* ***--- this is an MMX class insn introduced in SSE2 ---*** */
11118 /* 0F F4 = PMULUDQ -- unsigned widening multiply of 32-lanes 0 x
11119 0 to form 64-bit result */
11120 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xF4) {
11121 IRTemp sV = newTemp(Ity_I64);
11122 IRTemp dV = newTemp(Ity_I64);
11123 t1 = newTemp(Ity_I32);
11124 t0 = newTemp(Ity_I32);
11125 modrm = insn[2];
11126
11127 do_MMX_preamble();
11128 assign( dV, getMMXReg(gregOfRM(modrm)) );
11129
11130 if (epartIsReg(modrm)) {
11131 assign( sV, getMMXReg(eregOfRM(modrm)) );
11132 delta += 2+1;
11133 DIP("pmuludq %s,%s\n", nameMMXReg(eregOfRM(modrm)),
11134 nameMMXReg(gregOfRM(modrm)));
11135 } else {
11136 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
11137 assign( sV, loadLE(Ity_I64, mkexpr(addr)) );
11138 delta += 2+alen;
11139 DIP("pmuludq %s,%s\n", dis_buf,
11140 nameMMXReg(gregOfRM(modrm)));
11141 }
11142
11143 assign( t0, unop(Iop_64to32, mkexpr(dV)) );
11144 assign( t1, unop(Iop_64to32, mkexpr(sV)) );
11145 putMMXReg( gregOfRM(modrm),
11146 binop( Iop_MullU32, mkexpr(t0), mkexpr(t1) ) );
11147 goto decode_success;
11148 }
11149
11150 /* 66 0F F4 = PMULUDQ -- unsigned widening multiply of 32-lanes 0 x
11151 0 to form lower 64-bit half and lanes 2 x 2 to form upper 64-bit
11152 half */
11153 /* This is a really poor translation -- could be improved if
11154 performance critical */
11155 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xF4) {
11156 IRTemp sV, dV;
11157 IRTemp s3, s2, s1, s0, d3, d2, d1, d0;
11158 sV = newTemp(Ity_V128);
11159 dV = newTemp(Ity_V128);
11160 s3 = s2 = s1 = s0 = d3 = d2 = d1 = d0 = IRTemp_INVALID;
11161 t1 = newTemp(Ity_I64);
11162 t0 = newTemp(Ity_I64);
11163 modrm = insn[2];
11164 assign( dV, getXMMReg(gregOfRM(modrm)) );
11165
11166 if (epartIsReg(modrm)) {
11167 assign( sV, getXMMReg(eregOfRM(modrm)) );
11168 delta += 2+1;
11169 DIP("pmuludq %s,%s\n", nameXMMReg(eregOfRM(modrm)),
11170 nameXMMReg(gregOfRM(modrm)));
11171 } else {
11172 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
11173 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
11174 delta += 2+alen;
11175 DIP("pmuludq %s,%s\n", dis_buf,
11176 nameXMMReg(gregOfRM(modrm)));
11177 }
11178
11179 breakup128to32s( dV, &d3, &d2, &d1, &d0 );
11180 breakup128to32s( sV, &s3, &s2, &s1, &s0 );
11181
11182 assign( t0, binop( Iop_MullU32, mkexpr(d0), mkexpr(s0)) );
11183 putXMMRegLane64( gregOfRM(modrm), 0, mkexpr(t0) );
11184 assign( t1, binop( Iop_MullU32, mkexpr(d2), mkexpr(s2)) );
11185 putXMMRegLane64( gregOfRM(modrm), 1, mkexpr(t1) );
11186 goto decode_success;
11187 }
11188
11189 /* 66 0F EB = POR */
11190 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xEB) {
sewardjf0c1c582005-02-07 23:47:38 +000011191 delta = dis_SSE_E_to_G_all( sorb, delta+2, "por", Iop_OrV128 );
sewardje5854d62004-12-09 03:44:34 +000011192 goto decode_success;
11193 }
11194
sewardj7b5b9982005-10-04 11:43:37 +000011195 /* 66 0F F6 = PSADBW -- 2 x (8x8 -> 48 zeroes ++ u16) Sum Abs Diffs
11196 from E(xmm or mem) to G(xmm) */
11197 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xF6) {
11198 IRTemp s1V = newTemp(Ity_V128);
11199 IRTemp s2V = newTemp(Ity_V128);
11200 IRTemp dV = newTemp(Ity_V128);
11201 IRTemp s1Hi = newTemp(Ity_I64);
11202 IRTemp s1Lo = newTemp(Ity_I64);
11203 IRTemp s2Hi = newTemp(Ity_I64);
11204 IRTemp s2Lo = newTemp(Ity_I64);
11205 IRTemp dHi = newTemp(Ity_I64);
11206 IRTemp dLo = newTemp(Ity_I64);
11207 modrm = insn[2];
11208 if (epartIsReg(modrm)) {
11209 assign( s1V, getXMMReg(eregOfRM(modrm)) );
11210 delta += 2+1;
11211 DIP("psadbw %s,%s\n", nameXMMReg(eregOfRM(modrm)),
11212 nameXMMReg(gregOfRM(modrm)));
11213 } else {
11214 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
11215 assign( s1V, loadLE(Ity_V128, mkexpr(addr)) );
11216 delta += 2+alen;
11217 DIP("psadbw %s,%s\n", dis_buf,
11218 nameXMMReg(gregOfRM(modrm)));
11219 }
11220 assign( s2V, getXMMReg(gregOfRM(modrm)) );
11221 assign( s1Hi, unop(Iop_V128HIto64, mkexpr(s1V)) );
11222 assign( s1Lo, unop(Iop_V128to64, mkexpr(s1V)) );
11223 assign( s2Hi, unop(Iop_V128HIto64, mkexpr(s2V)) );
11224 assign( s2Lo, unop(Iop_V128to64, mkexpr(s2V)) );
11225 assign( dHi, mkIRExprCCall(
11226 Ity_I64, 0/*regparms*/,
11227 "x86g_calculate_mmx_psadbw",
11228 &x86g_calculate_mmx_psadbw,
11229 mkIRExprVec_2( mkexpr(s1Hi), mkexpr(s2Hi))
11230 ));
11231 assign( dLo, mkIRExprCCall(
11232 Ity_I64, 0/*regparms*/,
11233 "x86g_calculate_mmx_psadbw",
11234 &x86g_calculate_mmx_psadbw,
11235 mkIRExprVec_2( mkexpr(s1Lo), mkexpr(s2Lo))
11236 ));
11237 assign( dV, binop(Iop_64HLtoV128, mkexpr(dHi), mkexpr(dLo))) ;
11238 putXMMReg(gregOfRM(modrm), mkexpr(dV));
11239 goto decode_success;
11240 }
11241
sewardjb9fa69b2004-12-09 23:25:14 +000011242 /* 66 0F 70 = PSHUFD -- rearrange 4x32 from E(xmm or mem) to G(xmm) */
11243 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x70) {
11244 Int order;
11245 IRTemp sV, dV, s3, s2, s1, s0;
11246 s3 = s2 = s1 = s0 = IRTemp_INVALID;
11247 sV = newTemp(Ity_V128);
11248 dV = newTemp(Ity_V128);
11249 modrm = insn[2];
11250 if (epartIsReg(modrm)) {
11251 assign( sV, getXMMReg(eregOfRM(modrm)) );
11252 order = (Int)insn[3];
11253 delta += 2+2;
11254 DIP("pshufd $%d,%s,%s\n", order,
11255 nameXMMReg(eregOfRM(modrm)),
11256 nameXMMReg(gregOfRM(modrm)));
11257 } else {
11258 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
11259 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
11260 order = (Int)insn[2+alen];
11261 delta += 3+alen;
11262 DIP("pshufd $%d,%s,%s\n", order,
11263 dis_buf,
11264 nameXMMReg(gregOfRM(modrm)));
11265 }
11266 breakup128to32s( sV, &s3, &s2, &s1, &s0 );
11267
11268# define SEL(n) \
11269 ((n)==0 ? s0 : ((n)==1 ? s1 : ((n)==2 ? s2 : s3)))
11270 assign(dV,
11271 mk128from32s( SEL((order>>6)&3), SEL((order>>4)&3),
11272 SEL((order>>2)&3), SEL((order>>0)&3) )
11273 );
11274 putXMMReg(gregOfRM(modrm), mkexpr(dV));
11275# undef SEL
11276 goto decode_success;
11277 }
11278
11279 /* F3 0F 70 = PSHUFHW -- rearrange upper half 4x16 from E(xmm or
11280 mem) to G(xmm), and copy lower half */
11281 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x70) {
11282 Int order;
11283 IRTemp sVhi, dVhi, sV, dV, s3, s2, s1, s0;
11284 s3 = s2 = s1 = s0 = IRTemp_INVALID;
11285 sV = newTemp(Ity_V128);
11286 dV = newTemp(Ity_V128);
11287 sVhi = newTemp(Ity_I64);
11288 dVhi = newTemp(Ity_I64);
11289 modrm = insn[3];
11290 if (epartIsReg(modrm)) {
11291 assign( sV, getXMMReg(eregOfRM(modrm)) );
11292 order = (Int)insn[4];
11293 delta += 4+1;
11294 DIP("pshufhw $%d,%s,%s\n", order,
11295 nameXMMReg(eregOfRM(modrm)),
11296 nameXMMReg(gregOfRM(modrm)));
11297 } else {
11298 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
11299 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
11300 order = (Int)insn[3+alen];
11301 delta += 4+alen;
11302 DIP("pshufhw $%d,%s,%s\n", order,
11303 dis_buf,
11304 nameXMMReg(gregOfRM(modrm)));
11305 }
sewardjf0c1c582005-02-07 23:47:38 +000011306 assign( sVhi, unop(Iop_V128HIto64, mkexpr(sV)) );
sewardjb9fa69b2004-12-09 23:25:14 +000011307 breakup64to16s( sVhi, &s3, &s2, &s1, &s0 );
11308
11309# define SEL(n) \
11310 ((n)==0 ? s0 : ((n)==1 ? s1 : ((n)==2 ? s2 : s3)))
11311 assign(dVhi,
11312 mk64from16s( SEL((order>>6)&3), SEL((order>>4)&3),
11313 SEL((order>>2)&3), SEL((order>>0)&3) )
11314 );
sewardjf0c1c582005-02-07 23:47:38 +000011315 assign(dV, binop( Iop_64HLtoV128,
sewardjb9fa69b2004-12-09 23:25:14 +000011316 mkexpr(dVhi),
sewardjf0c1c582005-02-07 23:47:38 +000011317 unop(Iop_V128to64, mkexpr(sV))) );
sewardjb9fa69b2004-12-09 23:25:14 +000011318 putXMMReg(gregOfRM(modrm), mkexpr(dV));
11319# undef SEL
11320 goto decode_success;
11321 }
11322
11323 /* F2 0F 70 = PSHUFLW -- rearrange lower half 4x16 from E(xmm or
11324 mem) to G(xmm), and copy upper half */
11325 if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x70) {
11326 Int order;
11327 IRTemp sVlo, dVlo, sV, dV, s3, s2, s1, s0;
11328 s3 = s2 = s1 = s0 = IRTemp_INVALID;
11329 sV = newTemp(Ity_V128);
11330 dV = newTemp(Ity_V128);
11331 sVlo = newTemp(Ity_I64);
11332 dVlo = newTemp(Ity_I64);
11333 modrm = insn[3];
11334 if (epartIsReg(modrm)) {
11335 assign( sV, getXMMReg(eregOfRM(modrm)) );
11336 order = (Int)insn[4];
11337 delta += 4+1;
11338 DIP("pshuflw $%d,%s,%s\n", order,
11339 nameXMMReg(eregOfRM(modrm)),
11340 nameXMMReg(gregOfRM(modrm)));
11341 } else {
11342 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
11343 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
11344 order = (Int)insn[3+alen];
11345 delta += 4+alen;
11346 DIP("pshuflw $%d,%s,%s\n", order,
11347 dis_buf,
11348 nameXMMReg(gregOfRM(modrm)));
11349 }
sewardjf0c1c582005-02-07 23:47:38 +000011350 assign( sVlo, unop(Iop_V128to64, mkexpr(sV)) );
sewardjb9fa69b2004-12-09 23:25:14 +000011351 breakup64to16s( sVlo, &s3, &s2, &s1, &s0 );
11352
11353# define SEL(n) \
11354 ((n)==0 ? s0 : ((n)==1 ? s1 : ((n)==2 ? s2 : s3)))
11355 assign(dVlo,
11356 mk64from16s( SEL((order>>6)&3), SEL((order>>4)&3),
11357 SEL((order>>2)&3), SEL((order>>0)&3) )
11358 );
sewardjf0c1c582005-02-07 23:47:38 +000011359 assign(dV, binop( Iop_64HLtoV128,
11360 unop(Iop_V128HIto64, mkexpr(sV)),
sewardjb9fa69b2004-12-09 23:25:14 +000011361 mkexpr(dVlo) ) );
11362 putXMMReg(gregOfRM(modrm), mkexpr(dV));
11363# undef SEL
11364 goto decode_success;
11365 }
11366
11367 /* 66 0F 72 /6 ib = PSLLD by immediate */
11368 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x72
11369 && epartIsReg(insn[2])
11370 && gregOfRM(insn[2]) == 6) {
sewardj38a3f862005-01-13 15:06:51 +000011371 delta = dis_SSE_shiftE_imm( delta+2, "pslld", Iop_ShlN32x4 );
sewardjb9fa69b2004-12-09 23:25:14 +000011372 goto decode_success;
11373 }
11374
11375 /* 66 0F F2 = PSLLD by E */
11376 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xF2) {
11377 delta = dis_SSE_shiftG_byE( sorb, delta+2, "pslld", Iop_ShlN32x4 );
11378 goto decode_success;
11379 }
11380
sewardjb9fa69b2004-12-09 23:25:14 +000011381 /* 66 0F 73 /7 ib = PSLLDQ by immediate */
11382 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x73
11383 && epartIsReg(insn[2])
11384 && gregOfRM(insn[2]) == 7) {
sewardj0c9907c2005-01-10 20:37:31 +000011385 IRTemp sV, dV, hi64, lo64, hi64r, lo64r;
11386 Int imm = (Int)insn[3];
11387 Int reg = eregOfRM(insn[2]);
11388 DIP("pslldq $%d,%s\n", imm, nameXMMReg(reg));
11389 vassert(imm >= 0 && imm <= 255);
11390 delta += 4;
11391
11392 sV = newTemp(Ity_V128);
11393 dV = newTemp(Ity_V128);
11394 hi64 = newTemp(Ity_I64);
11395 lo64 = newTemp(Ity_I64);
11396 hi64r = newTemp(Ity_I64);
11397 lo64r = newTemp(Ity_I64);
11398
11399 if (imm >= 16) {
sewardj0c9907c2005-01-10 20:37:31 +000011400 putXMMReg(reg, mkV128(0x0000));
11401 goto decode_success;
11402 }
11403
11404 assign( sV, getXMMReg(reg) );
sewardjf0c1c582005-02-07 23:47:38 +000011405 assign( hi64, unop(Iop_V128HIto64, mkexpr(sV)) );
11406 assign( lo64, unop(Iop_V128to64, mkexpr(sV)) );
sewardj0c9907c2005-01-10 20:37:31 +000011407
sewardjba89f4c2005-04-07 17:31:27 +000011408 if (imm == 0) {
11409 assign( lo64r, mkexpr(lo64) );
11410 assign( hi64r, mkexpr(hi64) );
11411 }
11412 else
sewardj0c9907c2005-01-10 20:37:31 +000011413 if (imm == 8) {
11414 assign( lo64r, mkU64(0) );
11415 assign( hi64r, mkexpr(lo64) );
11416 }
sewardjc02043c2005-01-11 15:03:53 +000011417 else
sewardj0c9907c2005-01-10 20:37:31 +000011418 if (imm > 8) {
sewardj0c9907c2005-01-10 20:37:31 +000011419 assign( lo64r, mkU64(0) );
11420 assign( hi64r, binop( Iop_Shl64,
11421 mkexpr(lo64),
11422 mkU8( 8*(imm-8) ) ));
11423 } else {
11424 assign( lo64r, binop( Iop_Shl64,
11425 mkexpr(lo64),
11426 mkU8(8 * imm) ));
11427 assign( hi64r,
11428 binop( Iop_Or64,
11429 binop(Iop_Shl64, mkexpr(hi64),
11430 mkU8(8 * imm)),
11431 binop(Iop_Shr64, mkexpr(lo64),
11432 mkU8(8 * (8 - imm)) )
11433 )
11434 );
11435 }
sewardjf0c1c582005-02-07 23:47:38 +000011436 assign( dV, binop(Iop_64HLtoV128, mkexpr(hi64r), mkexpr(lo64r)) );
sewardj0c9907c2005-01-10 20:37:31 +000011437 putXMMReg(reg, mkexpr(dV));
sewardjb9fa69b2004-12-09 23:25:14 +000011438 goto decode_success;
11439 }
sewardjb9fa69b2004-12-09 23:25:14 +000011440
11441 /* 66 0F 73 /6 ib = PSLLQ by immediate */
11442 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x73
11443 && epartIsReg(insn[2])
11444 && gregOfRM(insn[2]) == 6) {
sewardj38a3f862005-01-13 15:06:51 +000011445 delta = dis_SSE_shiftE_imm( delta+2, "psllq", Iop_ShlN64x2 );
sewardjb9fa69b2004-12-09 23:25:14 +000011446 goto decode_success;
11447 }
11448
11449 /* 66 0F F3 = PSLLQ by E */
11450 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xF3) {
11451 delta = dis_SSE_shiftG_byE( sorb, delta+2, "psllq", Iop_ShlN64x2 );
11452 goto decode_success;
11453 }
11454
11455 /* 66 0F 71 /6 ib = PSLLW by immediate */
11456 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x71
11457 && epartIsReg(insn[2])
11458 && gregOfRM(insn[2]) == 6) {
sewardj38a3f862005-01-13 15:06:51 +000011459 delta = dis_SSE_shiftE_imm( delta+2, "psllw", Iop_ShlN16x8 );
sewardjb9fa69b2004-12-09 23:25:14 +000011460 goto decode_success;
11461 }
11462
11463 /* 66 0F F1 = PSLLW by E */
11464 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xF1) {
11465 delta = dis_SSE_shiftG_byE( sorb, delta+2, "psllw", Iop_ShlN16x8 );
11466 goto decode_success;
11467 }
11468
11469 /* 66 0F 72 /4 ib = PSRAD by immediate */
11470 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x72
11471 && epartIsReg(insn[2])
11472 && gregOfRM(insn[2]) == 4) {
sewardj38a3f862005-01-13 15:06:51 +000011473 delta = dis_SSE_shiftE_imm( delta+2, "psrad", Iop_SarN32x4 );
sewardjb9fa69b2004-12-09 23:25:14 +000011474 goto decode_success;
11475 }
11476
11477 /* 66 0F E2 = PSRAD by E */
11478 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xE2) {
11479 delta = dis_SSE_shiftG_byE( sorb, delta+2, "psrad", Iop_SarN32x4 );
11480 goto decode_success;
11481 }
11482
11483 /* 66 0F 71 /4 ib = PSRAW by immediate */
11484 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x71
11485 && epartIsReg(insn[2])
11486 && gregOfRM(insn[2]) == 4) {
sewardj38a3f862005-01-13 15:06:51 +000011487 delta = dis_SSE_shiftE_imm( delta+2, "psraw", Iop_SarN16x8 );
sewardjb9fa69b2004-12-09 23:25:14 +000011488 goto decode_success;
11489 }
11490
11491 /* 66 0F E1 = PSRAW by E */
11492 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xE1) {
11493 delta = dis_SSE_shiftG_byE( sorb, delta+2, "psraw", Iop_SarN16x8 );
11494 goto decode_success;
11495 }
11496
11497 /* 66 0F 72 /2 ib = PSRLD by immediate */
11498 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x72
11499 && epartIsReg(insn[2])
11500 && gregOfRM(insn[2]) == 2) {
sewardj38a3f862005-01-13 15:06:51 +000011501 delta = dis_SSE_shiftE_imm( delta+2, "psrld", Iop_ShrN32x4 );
sewardjb9fa69b2004-12-09 23:25:14 +000011502 goto decode_success;
11503 }
11504
11505 /* 66 0F D2 = PSRLD by E */
11506 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD2) {
11507 delta = dis_SSE_shiftG_byE( sorb, delta+2, "psrld", Iop_ShrN32x4 );
11508 goto decode_success;
11509 }
11510
sewardj9ee82862004-12-14 01:16:59 +000011511 /* 66 0F 73 /3 ib = PSRLDQ by immediate */
11512 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x73
11513 && epartIsReg(insn[2])
sewardj95535fe2004-12-15 17:42:58 +000011514 && gregOfRM(insn[2]) == 3) {
11515 IRTemp sV, dV, hi64, lo64, hi64r, lo64r;
sewardj9ee82862004-12-14 01:16:59 +000011516 Int imm = (Int)insn[3];
11517 Int reg = eregOfRM(insn[2]);
sewardj9ee82862004-12-14 01:16:59 +000011518 DIP("psrldq $%d,%s\n", imm, nameXMMReg(reg));
sewardj95535fe2004-12-15 17:42:58 +000011519 vassert(imm >= 0 && imm <= 255);
11520 delta += 4;
11521
11522 sV = newTemp(Ity_V128);
11523 dV = newTemp(Ity_V128);
11524 hi64 = newTemp(Ity_I64);
11525 lo64 = newTemp(Ity_I64);
11526 hi64r = newTemp(Ity_I64);
11527 lo64r = newTemp(Ity_I64);
11528
11529 if (imm >= 16) {
sewardj95535fe2004-12-15 17:42:58 +000011530 putXMMReg(reg, mkV128(0x0000));
11531 goto decode_success;
11532 }
11533
11534 assign( sV, getXMMReg(reg) );
sewardjf0c1c582005-02-07 23:47:38 +000011535 assign( hi64, unop(Iop_V128HIto64, mkexpr(sV)) );
11536 assign( lo64, unop(Iop_V128to64, mkexpr(sV)) );
sewardj95535fe2004-12-15 17:42:58 +000011537
sewardjba89f4c2005-04-07 17:31:27 +000011538 if (imm == 0) {
11539 assign( lo64r, mkexpr(lo64) );
11540 assign( hi64r, mkexpr(hi64) );
11541 }
11542 else
sewardj95535fe2004-12-15 17:42:58 +000011543 if (imm == 8) {
11544 assign( hi64r, mkU64(0) );
11545 assign( lo64r, mkexpr(hi64) );
11546 }
11547 else
11548 if (imm > 8) {
sewardj95535fe2004-12-15 17:42:58 +000011549 assign( hi64r, mkU64(0) );
11550 assign( lo64r, binop( Iop_Shr64,
11551 mkexpr(hi64),
11552 mkU8( 8*(imm-8) ) ));
11553 } else {
11554 assign( hi64r, binop( Iop_Shr64,
11555 mkexpr(hi64),
11556 mkU8(8 * imm) ));
11557 assign( lo64r,
11558 binop( Iop_Or64,
11559 binop(Iop_Shr64, mkexpr(lo64),
11560 mkU8(8 * imm)),
11561 binop(Iop_Shl64, mkexpr(hi64),
11562 mkU8(8 * (8 - imm)) )
11563 )
11564 );
11565 }
11566
sewardjf0c1c582005-02-07 23:47:38 +000011567 assign( dV, binop(Iop_64HLtoV128, mkexpr(hi64r), mkexpr(lo64r)) );
sewardj95535fe2004-12-15 17:42:58 +000011568 putXMMReg(reg, mkexpr(dV));
sewardj9ee82862004-12-14 01:16:59 +000011569 goto decode_success;
11570 }
11571
sewardjb9fa69b2004-12-09 23:25:14 +000011572 /* 66 0F 73 /2 ib = PSRLQ by immediate */
11573 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x73
11574 && epartIsReg(insn[2])
11575 && gregOfRM(insn[2]) == 2) {
sewardj38a3f862005-01-13 15:06:51 +000011576 delta = dis_SSE_shiftE_imm( delta+2, "psrlq", Iop_ShrN64x2 );
sewardjb9fa69b2004-12-09 23:25:14 +000011577 goto decode_success;
11578 }
11579
11580 /* 66 0F D3 = PSRLQ by E */
11581 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD3) {
11582 delta = dis_SSE_shiftG_byE( sorb, delta+2, "psrlq", Iop_ShrN64x2 );
11583 goto decode_success;
11584 }
11585
11586 /* 66 0F 71 /2 ib = PSRLW by immediate */
11587 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x71
11588 && epartIsReg(insn[2])
11589 && gregOfRM(insn[2]) == 2) {
sewardj38a3f862005-01-13 15:06:51 +000011590 delta = dis_SSE_shiftE_imm( delta+2, "psrlw", Iop_ShrN16x8 );
sewardjb9fa69b2004-12-09 23:25:14 +000011591 goto decode_success;
11592 }
11593
11594 /* 66 0F D1 = PSRLW by E */
11595 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD1) {
11596 delta = dis_SSE_shiftG_byE( sorb, delta+2, "psrlw", Iop_ShrN16x8 );
11597 goto decode_success;
11598 }
11599
11600 /* 66 0F F8 = PSUBB */
11601 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xF8) {
11602 delta = dis_SSEint_E_to_G( sorb, delta+2,
11603 "psubb", Iop_Sub8x16, False );
11604 goto decode_success;
11605 }
11606
11607 /* 66 0F FA = PSUBD */
11608 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xFA) {
11609 delta = dis_SSEint_E_to_G( sorb, delta+2,
11610 "psubd", Iop_Sub32x4, False );
11611 goto decode_success;
11612 }
11613
11614 /* ***--- this is an MMX class insn introduced in SSE2 ---*** */
11615 /* 0F FB = PSUBQ -- sub 64x1 */
11616 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xFB) {
11617 do_MMX_preamble();
11618 delta = dis_MMXop_regmem_to_reg (
11619 sorb, delta+2, insn[1], "psubq", False );
11620 goto decode_success;
11621 }
11622
11623 /* 66 0F FB = PSUBQ */
11624 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xFB) {
11625 delta = dis_SSEint_E_to_G( sorb, delta+2,
11626 "psubq", Iop_Sub64x2, False );
11627 goto decode_success;
11628 }
11629
11630 /* 66 0F F9 = PSUBW */
11631 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xF9) {
11632 delta = dis_SSEint_E_to_G( sorb, delta+2,
11633 "psubw", Iop_Sub16x8, False );
11634 goto decode_success;
11635 }
11636
11637 /* 66 0F E8 = PSUBSB */
11638 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xE8) {
11639 delta = dis_SSEint_E_to_G( sorb, delta+2,
11640 "psubsb", Iop_QSub8Sx16, False );
11641 goto decode_success;
11642 }
11643
11644 /* 66 0F E9 = PSUBSW */
11645 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xE9) {
11646 delta = dis_SSEint_E_to_G( sorb, delta+2,
11647 "psubsw", Iop_QSub16Sx8, False );
11648 goto decode_success;
11649 }
11650
11651 /* 66 0F D8 = PSUBSB */
11652 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD8) {
11653 delta = dis_SSEint_E_to_G( sorb, delta+2,
11654 "psubusb", Iop_QSub8Ux16, False );
11655 goto decode_success;
11656 }
11657
11658 /* 66 0F D9 = PSUBSW */
11659 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD9) {
11660 delta = dis_SSEint_E_to_G( sorb, delta+2,
11661 "psubusw", Iop_QSub16Ux8, False );
11662 goto decode_success;
11663 }
11664
sewardj9e203592004-12-10 01:48:18 +000011665 /* 66 0F 68 = PUNPCKHBW */
11666 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x68) {
11667 delta = dis_SSEint_E_to_G( sorb, delta+2,
11668 "punpckhbw",
11669 Iop_InterleaveHI8x16, True );
11670 goto decode_success;
11671 }
11672
11673 /* 66 0F 6A = PUNPCKHDQ */
11674 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x6A) {
11675 delta = dis_SSEint_E_to_G( sorb, delta+2,
11676 "punpckhdq",
11677 Iop_InterleaveHI32x4, True );
11678 goto decode_success;
11679 }
11680
11681 /* 66 0F 6D = PUNPCKHQDQ */
11682 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x6D) {
11683 delta = dis_SSEint_E_to_G( sorb, delta+2,
11684 "punpckhqdq",
11685 Iop_InterleaveHI64x2, True );
11686 goto decode_success;
11687 }
11688
11689 /* 66 0F 69 = PUNPCKHWD */
11690 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x69) {
11691 delta = dis_SSEint_E_to_G( sorb, delta+2,
11692 "punpckhwd",
11693 Iop_InterleaveHI16x8, True );
11694 goto decode_success;
11695 }
11696
11697 /* 66 0F 60 = PUNPCKLBW */
11698 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x60) {
11699 delta = dis_SSEint_E_to_G( sorb, delta+2,
11700 "punpcklbw",
11701 Iop_InterleaveLO8x16, True );
11702 goto decode_success;
11703 }
11704
11705 /* 66 0F 62 = PUNPCKLDQ */
11706 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x62) {
11707 delta = dis_SSEint_E_to_G( sorb, delta+2,
11708 "punpckldq",
11709 Iop_InterleaveLO32x4, True );
11710 goto decode_success;
11711 }
11712
11713 /* 66 0F 6C = PUNPCKLQDQ */
11714 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x6C) {
11715 delta = dis_SSEint_E_to_G( sorb, delta+2,
11716 "punpcklqdq",
11717 Iop_InterleaveLO64x2, True );
11718 goto decode_success;
11719 }
11720
11721 /* 66 0F 61 = PUNPCKLWD */
11722 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x61) {
11723 delta = dis_SSEint_E_to_G( sorb, delta+2,
11724 "punpcklwd",
11725 Iop_InterleaveLO16x8, True );
11726 goto decode_success;
11727 }
11728
11729 /* 66 0F EF = PXOR */
11730 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xEF) {
sewardjf0c1c582005-02-07 23:47:38 +000011731 delta = dis_SSE_E_to_G_all( sorb, delta+2, "pxor", Iop_XorV128 );
sewardj9e203592004-12-10 01:48:18 +000011732 goto decode_success;
11733 }
11734
sewardjc9a65702004-07-07 16:32:57 +000011735//-- /* FXSAVE/FXRSTOR m32 -- load/store the FPU/MMX/SSE state. */
11736//-- if (insn[0] == 0x0F && insn[1] == 0xAE
11737//-- && (!epartIsReg(insn[2]))
11738//-- && (gregOfRM(insn[2]) == 1 || gregOfRM(insn[2]) == 0) ) {
11739//-- Bool store = gregOfRM(insn[2]) == 0;
11740//-- vg_assert(sz == 4);
11741//-- pair = disAMode ( cb, sorb, eip+2, dis_buf );
11742//-- t1 = LOW24(pair);
11743//-- eip += 2+HI8(pair);
11744//-- uInstr3(cb, store ? SSE2a_MemWr : SSE2a_MemRd, 512,
11745//-- Lit16, (((UShort)insn[0]) << 8) | (UShort)insn[1],
11746//-- Lit16, (UShort)insn[2],
11747//-- TempReg, t1 );
11748//-- DIP("fx%s %s\n", store ? "save" : "rstor", dis_buf );
11749//-- goto decode_success;
11750//-- }
sewardjc9a65702004-07-07 16:32:57 +000011751
sewardjbfceb082005-11-15 11:16:30 +000011752 /* 0F AE /7 = CLFLUSH -- flush cache line */
11753 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xAE
11754 && !epartIsReg(insn[2]) && gregOfRM(insn[2]) == 7) {
11755
11756 /* This is something of a hack. We need to know the size of the
11757 cache line containing addr. Since we don't (easily), assume
11758 256 on the basis that no real cache would have a line that
11759 big. It's safe to invalidate more stuff than we need, just
11760 inefficient. */
11761 UInt lineszB = 256;
11762
11763 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
11764 delta += 2+alen;
11765
11766 /* Round addr down to the start of the containing block. */
11767 stmt( IRStmt_Put(
sewardj05f5e012014-05-04 10:52:11 +000011768 OFFB_CMSTART,
sewardjbfceb082005-11-15 11:16:30 +000011769 binop( Iop_And32,
11770 mkexpr(addr),
11771 mkU32( ~(lineszB-1) ))) );
11772
sewardj05f5e012014-05-04 10:52:11 +000011773 stmt( IRStmt_Put(OFFB_CMLEN, mkU32(lineszB) ) );
sewardjbfceb082005-11-15 11:16:30 +000011774
sewardj05f5e012014-05-04 10:52:11 +000011775 jmp_lit(&dres, Ijk_InvalICache, (Addr32)(guest_EIP_bbstart+delta));
sewardjbfceb082005-11-15 11:16:30 +000011776
11777 DIP("clflush %s\n", dis_buf);
11778 goto decode_success;
11779 }
sewardjc9a65702004-07-07 16:32:57 +000011780
11781 /* ---------------------------------------------------- */
sewardj90e91ee2005-11-07 14:23:52 +000011782 /* --- end of the SSE2 decoder. --- */
11783 /* ---------------------------------------------------- */
11784
11785 /* ---------------------------------------------------- */
11786 /* --- start of the SSE3 decoder. --- */
11787 /* ---------------------------------------------------- */
11788
11789 /* Skip parts of the decoder which don't apply given the stated
11790 guest subarchitecture. */
florian9f07e862014-12-09 20:09:42 +000011791 if (0 == (archinfo->hwcaps & VEX_HWCAPS_X86_SSE3))
sewardj5117ce12006-01-27 21:20:15 +000011792 goto after_sse_decoders; /* no SSE3 capabilities */
sewardj90e91ee2005-11-07 14:23:52 +000011793
florian8462d112014-09-24 15:18:09 +000011794 insn = &guest_code[delta];
sewardj90e91ee2005-11-07 14:23:52 +000011795
11796 /* F3 0F 12 = MOVSLDUP -- move from E (mem or xmm) to G (xmm),
11797 duplicating some lanes (2:2:0:0). */
11798 /* F3 0F 16 = MOVSHDUP -- move from E (mem or xmm) to G (xmm),
11799 duplicating some lanes (3:3:1:1). */
11800 if (sz == 4 && insn[0] == 0xF3 && insn[1] == 0x0F
11801 && (insn[2] == 0x12 || insn[2] == 0x16)) {
11802 IRTemp s3, s2, s1, s0;
11803 IRTemp sV = newTemp(Ity_V128);
11804 Bool isH = insn[2] == 0x16;
11805 s3 = s2 = s1 = s0 = IRTemp_INVALID;
11806
11807 modrm = insn[3];
11808 if (epartIsReg(modrm)) {
11809 assign( sV, getXMMReg( eregOfRM(modrm)) );
11810 DIP("movs%cdup %s,%s\n", isH ? 'h' : 'l',
11811 nameXMMReg(eregOfRM(modrm)),
11812 nameXMMReg(gregOfRM(modrm)));
11813 delta += 3+1;
11814 } else {
11815 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
sewardj45ca0b92010-09-30 14:51:51 +000011816 gen_SEGV_if_not_16_aligned( addr );
sewardj90e91ee2005-11-07 14:23:52 +000011817 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
11818 DIP("movs%cdup %s,%s\n", isH ? 'h' : 'l',
11819 dis_buf,
11820 nameXMMReg(gregOfRM(modrm)));
11821 delta += 3+alen;
11822 }
11823
11824 breakup128to32s( sV, &s3, &s2, &s1, &s0 );
11825 putXMMReg( gregOfRM(modrm),
11826 isH ? mk128from32s( s3, s3, s1, s1 )
11827 : mk128from32s( s2, s2, s0, s0 ) );
11828 goto decode_success;
11829 }
11830
sewardjdd5d2042006-08-03 15:03:19 +000011831 /* F2 0F 12 = MOVDDUP -- move from E (mem or xmm) to G (xmm),
11832 duplicating some lanes (0:1:0:1). */
11833 if (sz == 4 && insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x12) {
11834 IRTemp sV = newTemp(Ity_V128);
11835 IRTemp d0 = newTemp(Ity_I64);
11836
11837 modrm = insn[3];
11838 if (epartIsReg(modrm)) {
11839 assign( sV, getXMMReg( eregOfRM(modrm)) );
11840 DIP("movddup %s,%s\n", nameXMMReg(eregOfRM(modrm)),
11841 nameXMMReg(gregOfRM(modrm)));
11842 delta += 3+1;
11843 assign ( d0, unop(Iop_V128to64, mkexpr(sV)) );
11844 } else {
11845 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
11846 assign( d0, loadLE(Ity_I64, mkexpr(addr)) );
11847 DIP("movddup %s,%s\n", dis_buf,
11848 nameXMMReg(gregOfRM(modrm)));
11849 delta += 3+alen;
11850 }
11851
11852 putXMMReg( gregOfRM(modrm), binop(Iop_64HLtoV128,mkexpr(d0),mkexpr(d0)) );
11853 goto decode_success;
11854 }
11855
sewardj90e91ee2005-11-07 14:23:52 +000011856 /* F2 0F D0 = ADDSUBPS -- 32x4 +/-/+/- from E (mem or xmm) to G (xmm). */
11857 if (sz == 4 && insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0xD0) {
11858 IRTemp a3, a2, a1, a0, s3, s2, s1, s0;
11859 IRTemp eV = newTemp(Ity_V128);
11860 IRTemp gV = newTemp(Ity_V128);
11861 IRTemp addV = newTemp(Ity_V128);
11862 IRTemp subV = newTemp(Ity_V128);
sewardj9571dc02014-01-26 18:34:23 +000011863 IRTemp rm = newTemp(Ity_I32);
sewardj90e91ee2005-11-07 14:23:52 +000011864 a3 = a2 = a1 = a0 = s3 = s2 = s1 = s0 = IRTemp_INVALID;
11865
11866 modrm = insn[3];
11867 if (epartIsReg(modrm)) {
11868 assign( eV, getXMMReg( eregOfRM(modrm)) );
11869 DIP("addsubps %s,%s\n", nameXMMReg(eregOfRM(modrm)),
11870 nameXMMReg(gregOfRM(modrm)));
11871 delta += 3+1;
11872 } else {
11873 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
11874 assign( eV, loadLE(Ity_V128, mkexpr(addr)) );
11875 DIP("addsubps %s,%s\n", dis_buf,
11876 nameXMMReg(gregOfRM(modrm)));
11877 delta += 3+alen;
11878 }
11879
11880 assign( gV, getXMMReg(gregOfRM(modrm)) );
11881
sewardj9571dc02014-01-26 18:34:23 +000011882 assign( rm, get_FAKE_roundingmode() ); /* XXXROUNDINGFIXME */
11883 assign( addV, triop(Iop_Add32Fx4, mkexpr(rm), mkexpr(gV), mkexpr(eV)) );
11884 assign( subV, triop(Iop_Sub32Fx4, mkexpr(rm), mkexpr(gV), mkexpr(eV)) );
sewardj90e91ee2005-11-07 14:23:52 +000011885
11886 breakup128to32s( addV, &a3, &a2, &a1, &a0 );
11887 breakup128to32s( subV, &s3, &s2, &s1, &s0 );
11888
11889 putXMMReg( gregOfRM(modrm), mk128from32s( a3, s2, a1, s0 ));
11890 goto decode_success;
11891 }
11892
sewardjdd5d2042006-08-03 15:03:19 +000011893 /* 66 0F D0 = ADDSUBPD -- 64x4 +/- from E (mem or xmm) to G (xmm). */
11894 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD0) {
11895 IRTemp eV = newTemp(Ity_V128);
11896 IRTemp gV = newTemp(Ity_V128);
11897 IRTemp addV = newTemp(Ity_V128);
11898 IRTemp subV = newTemp(Ity_V128);
11899 IRTemp a1 = newTemp(Ity_I64);
11900 IRTemp s0 = newTemp(Ity_I64);
sewardj9571dc02014-01-26 18:34:23 +000011901 IRTemp rm = newTemp(Ity_I32);
sewardjdd5d2042006-08-03 15:03:19 +000011902
11903 modrm = insn[2];
11904 if (epartIsReg(modrm)) {
11905 assign( eV, getXMMReg( eregOfRM(modrm)) );
11906 DIP("addsubpd %s,%s\n", nameXMMReg(eregOfRM(modrm)),
11907 nameXMMReg(gregOfRM(modrm)));
11908 delta += 2+1;
11909 } else {
11910 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
11911 assign( eV, loadLE(Ity_V128, mkexpr(addr)) );
11912 DIP("addsubpd %s,%s\n", dis_buf,
11913 nameXMMReg(gregOfRM(modrm)));
11914 delta += 2+alen;
11915 }
11916
11917 assign( gV, getXMMReg(gregOfRM(modrm)) );
11918
sewardj9571dc02014-01-26 18:34:23 +000011919 assign( rm, get_FAKE_roundingmode() ); /* XXXROUNDINGFIXME */
11920 assign( addV, triop(Iop_Add64Fx2, mkexpr(rm), mkexpr(gV), mkexpr(eV)) );
11921 assign( subV, triop(Iop_Sub64Fx2, mkexpr(rm), mkexpr(gV), mkexpr(eV)) );
sewardjdd5d2042006-08-03 15:03:19 +000011922
11923 assign( a1, unop(Iop_V128HIto64, mkexpr(addV) ));
11924 assign( s0, unop(Iop_V128to64, mkexpr(subV) ));
11925
11926 putXMMReg( gregOfRM(modrm),
11927 binop(Iop_64HLtoV128, mkexpr(a1), mkexpr(s0)) );
11928 goto decode_success;
11929 }
11930
11931 /* F2 0F 7D = HSUBPS -- 32x4 sub across from E (mem or xmm) to G (xmm). */
11932 /* F2 0F 7C = HADDPS -- 32x4 add across from E (mem or xmm) to G (xmm). */
11933 if (sz == 4 && insn[0] == 0xF2 && insn[1] == 0x0F
11934 && (insn[2] == 0x7C || insn[2] == 0x7D)) {
11935 IRTemp e3, e2, e1, e0, g3, g2, g1, g0;
11936 IRTemp eV = newTemp(Ity_V128);
11937 IRTemp gV = newTemp(Ity_V128);
11938 IRTemp leftV = newTemp(Ity_V128);
11939 IRTemp rightV = newTemp(Ity_V128);
sewardj9571dc02014-01-26 18:34:23 +000011940 IRTemp rm = newTemp(Ity_I32);
sewardjdd5d2042006-08-03 15:03:19 +000011941 Bool isAdd = insn[2] == 0x7C;
florian55085f82012-11-21 00:36:55 +000011942 const HChar* str = isAdd ? "add" : "sub";
sewardjdd5d2042006-08-03 15:03:19 +000011943 e3 = e2 = e1 = e0 = g3 = g2 = g1 = g0 = IRTemp_INVALID;
11944
11945 modrm = insn[3];
11946 if (epartIsReg(modrm)) {
11947 assign( eV, getXMMReg( eregOfRM(modrm)) );
11948 DIP("h%sps %s,%s\n", str, nameXMMReg(eregOfRM(modrm)),
11949 nameXMMReg(gregOfRM(modrm)));
11950 delta += 3+1;
11951 } else {
11952 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
11953 assign( eV, loadLE(Ity_V128, mkexpr(addr)) );
11954 DIP("h%sps %s,%s\n", str, dis_buf,
11955 nameXMMReg(gregOfRM(modrm)));
11956 delta += 3+alen;
11957 }
11958
11959 assign( gV, getXMMReg(gregOfRM(modrm)) );
11960
11961 breakup128to32s( eV, &e3, &e2, &e1, &e0 );
11962 breakup128to32s( gV, &g3, &g2, &g1, &g0 );
11963
11964 assign( leftV, mk128from32s( e2, e0, g2, g0 ) );
11965 assign( rightV, mk128from32s( e3, e1, g3, g1 ) );
11966
sewardj9571dc02014-01-26 18:34:23 +000011967 assign( rm, get_FAKE_roundingmode() ); /* XXXROUNDINGFIXME */
sewardjdd5d2042006-08-03 15:03:19 +000011968 putXMMReg( gregOfRM(modrm),
sewardj9571dc02014-01-26 18:34:23 +000011969 triop(isAdd ? Iop_Add32Fx4 : Iop_Sub32Fx4,
11970 mkexpr(rm), mkexpr(leftV), mkexpr(rightV) ) );
sewardjdd5d2042006-08-03 15:03:19 +000011971 goto decode_success;
11972 }
11973
11974 /* 66 0F 7D = HSUBPD -- 64x2 sub across from E (mem or xmm) to G (xmm). */
11975 /* 66 0F 7C = HADDPD -- 64x2 add across from E (mem or xmm) to G (xmm). */
11976 if (sz == 2 && insn[0] == 0x0F && (insn[1] == 0x7C || insn[1] == 0x7D)) {
11977 IRTemp e1 = newTemp(Ity_I64);
11978 IRTemp e0 = newTemp(Ity_I64);
11979 IRTemp g1 = newTemp(Ity_I64);
11980 IRTemp g0 = newTemp(Ity_I64);
11981 IRTemp eV = newTemp(Ity_V128);
11982 IRTemp gV = newTemp(Ity_V128);
11983 IRTemp leftV = newTemp(Ity_V128);
11984 IRTemp rightV = newTemp(Ity_V128);
sewardj9571dc02014-01-26 18:34:23 +000011985 IRTemp rm = newTemp(Ity_I32);
sewardjdd5d2042006-08-03 15:03:19 +000011986 Bool isAdd = insn[1] == 0x7C;
florian55085f82012-11-21 00:36:55 +000011987 const HChar* str = isAdd ? "add" : "sub";
sewardjdd5d2042006-08-03 15:03:19 +000011988
11989 modrm = insn[2];
11990 if (epartIsReg(modrm)) {
11991 assign( eV, getXMMReg( eregOfRM(modrm)) );
11992 DIP("h%spd %s,%s\n", str, nameXMMReg(eregOfRM(modrm)),
11993 nameXMMReg(gregOfRM(modrm)));
11994 delta += 2+1;
11995 } else {
11996 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
11997 assign( eV, loadLE(Ity_V128, mkexpr(addr)) );
11998 DIP("h%spd %s,%s\n", str, dis_buf,
11999 nameXMMReg(gregOfRM(modrm)));
12000 delta += 2+alen;
12001 }
12002
12003 assign( gV, getXMMReg(gregOfRM(modrm)) );
12004
12005 assign( e1, unop(Iop_V128HIto64, mkexpr(eV) ));
12006 assign( e0, unop(Iop_V128to64, mkexpr(eV) ));
12007 assign( g1, unop(Iop_V128HIto64, mkexpr(gV) ));
12008 assign( g0, unop(Iop_V128to64, mkexpr(gV) ));
12009
12010 assign( leftV, binop(Iop_64HLtoV128, mkexpr(e0),mkexpr(g0)) );
12011 assign( rightV, binop(Iop_64HLtoV128, mkexpr(e1),mkexpr(g1)) );
12012
sewardj9571dc02014-01-26 18:34:23 +000012013 assign( rm, get_FAKE_roundingmode() ); /* XXXROUNDINGFIXME */
sewardjdd5d2042006-08-03 15:03:19 +000012014 putXMMReg( gregOfRM(modrm),
sewardj9571dc02014-01-26 18:34:23 +000012015 triop(isAdd ? Iop_Add64Fx2 : Iop_Sub64Fx2,
12016 mkexpr(rm), mkexpr(leftV), mkexpr(rightV) ) );
sewardjdd5d2042006-08-03 15:03:19 +000012017 goto decode_success;
12018 }
12019
12020 /* F2 0F F0 = LDDQU -- move from E (mem or xmm) to G (xmm). */
12021 if (sz == 4 && insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0xF0) {
12022 modrm = getIByte(delta+3);
12023 if (epartIsReg(modrm)) {
12024 goto decode_failure;
12025 } else {
12026 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
12027 putXMMReg( gregOfRM(modrm),
12028 loadLE(Ity_V128, mkexpr(addr)) );
12029 DIP("lddqu %s,%s\n", dis_buf,
12030 nameXMMReg(gregOfRM(modrm)));
12031 delta += 3+alen;
12032 }
12033 goto decode_success;
12034 }
12035
sewardj90e91ee2005-11-07 14:23:52 +000012036 /* ---------------------------------------------------- */
12037 /* --- end of the SSE3 decoder. --- */
sewardjc9a65702004-07-07 16:32:57 +000012038 /* ---------------------------------------------------- */
12039
sewardj150c9cd2008-02-09 01:16:02 +000012040 /* ---------------------------------------------------- */
12041 /* --- start of the SSSE3 decoder. --- */
12042 /* ---------------------------------------------------- */
12043
12044 /* 0F 38 04 = PMADDUBSW -- Multiply and Add Packed Signed and
12045 Unsigned Bytes (MMX) */
12046 if (sz == 4
12047 && insn[0] == 0x0F && insn[1] == 0x38 && insn[2] == 0x04) {
12048 IRTemp sV = newTemp(Ity_I64);
12049 IRTemp dV = newTemp(Ity_I64);
12050 IRTemp sVoddsSX = newTemp(Ity_I64);
12051 IRTemp sVevensSX = newTemp(Ity_I64);
12052 IRTemp dVoddsZX = newTemp(Ity_I64);
12053 IRTemp dVevensZX = newTemp(Ity_I64);
12054
12055 modrm = insn[3];
12056 do_MMX_preamble();
12057 assign( dV, getMMXReg(gregOfRM(modrm)) );
12058
12059 if (epartIsReg(modrm)) {
12060 assign( sV, getMMXReg(eregOfRM(modrm)) );
12061 delta += 3+1;
12062 DIP("pmaddubsw %s,%s\n", nameMMXReg(eregOfRM(modrm)),
12063 nameMMXReg(gregOfRM(modrm)));
12064 } else {
12065 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
12066 assign( sV, loadLE(Ity_I64, mkexpr(addr)) );
12067 delta += 3+alen;
12068 DIP("pmaddubsw %s,%s\n", dis_buf,
12069 nameMMXReg(gregOfRM(modrm)));
12070 }
12071
12072 /* compute dV unsigned x sV signed */
12073 assign( sVoddsSX,
12074 binop(Iop_SarN16x4, mkexpr(sV), mkU8(8)) );
12075 assign( sVevensSX,
12076 binop(Iop_SarN16x4,
12077 binop(Iop_ShlN16x4, mkexpr(sV), mkU8(8)),
12078 mkU8(8)) );
12079 assign( dVoddsZX,
12080 binop(Iop_ShrN16x4, mkexpr(dV), mkU8(8)) );
12081 assign( dVevensZX,
12082 binop(Iop_ShrN16x4,
12083 binop(Iop_ShlN16x4, mkexpr(dV), mkU8(8)),
12084 mkU8(8)) );
12085
12086 putMMXReg(
12087 gregOfRM(modrm),
12088 binop(Iop_QAdd16Sx4,
12089 binop(Iop_Mul16x4, mkexpr(sVoddsSX), mkexpr(dVoddsZX)),
12090 binop(Iop_Mul16x4, mkexpr(sVevensSX), mkexpr(dVevensZX))
12091 )
12092 );
12093 goto decode_success;
12094 }
12095
12096 /* 66 0F 38 04 = PMADDUBSW -- Multiply and Add Packed Signed and
12097 Unsigned Bytes (XMM) */
12098 if (sz == 2
12099 && insn[0] == 0x0F && insn[1] == 0x38 && insn[2] == 0x04) {
12100 IRTemp sV = newTemp(Ity_V128);
12101 IRTemp dV = newTemp(Ity_V128);
12102 IRTemp sVoddsSX = newTemp(Ity_V128);
12103 IRTemp sVevensSX = newTemp(Ity_V128);
12104 IRTemp dVoddsZX = newTemp(Ity_V128);
12105 IRTemp dVevensZX = newTemp(Ity_V128);
12106
12107 modrm = insn[3];
12108 assign( dV, getXMMReg(gregOfRM(modrm)) );
12109
12110 if (epartIsReg(modrm)) {
12111 assign( sV, getXMMReg(eregOfRM(modrm)) );
12112 delta += 3+1;
12113 DIP("pmaddubsw %s,%s\n", nameXMMReg(eregOfRM(modrm)),
12114 nameXMMReg(gregOfRM(modrm)));
12115 } else {
12116 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
12117 gen_SEGV_if_not_16_aligned( addr );
12118 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
12119 delta += 3+alen;
12120 DIP("pmaddubsw %s,%s\n", dis_buf,
12121 nameXMMReg(gregOfRM(modrm)));
12122 }
12123
12124 /* compute dV unsigned x sV signed */
12125 assign( sVoddsSX,
12126 binop(Iop_SarN16x8, mkexpr(sV), mkU8(8)) );
12127 assign( sVevensSX,
12128 binop(Iop_SarN16x8,
12129 binop(Iop_ShlN16x8, mkexpr(sV), mkU8(8)),
12130 mkU8(8)) );
12131 assign( dVoddsZX,
12132 binop(Iop_ShrN16x8, mkexpr(dV), mkU8(8)) );
12133 assign( dVevensZX,
12134 binop(Iop_ShrN16x8,
12135 binop(Iop_ShlN16x8, mkexpr(dV), mkU8(8)),
12136 mkU8(8)) );
12137
12138 putXMMReg(
12139 gregOfRM(modrm),
12140 binop(Iop_QAdd16Sx8,
12141 binop(Iop_Mul16x8, mkexpr(sVoddsSX), mkexpr(dVoddsZX)),
12142 binop(Iop_Mul16x8, mkexpr(sVevensSX), mkexpr(dVevensZX))
12143 )
12144 );
12145 goto decode_success;
12146 }
12147
12148 /* ***--- these are MMX class insns introduced in SSSE3 ---*** */
12149 /* 0F 38 03 = PHADDSW -- 16x4 signed qadd across from E (mem or
12150 mmx) and G to G (mmx). */
12151 /* 0F 38 07 = PHSUBSW -- 16x4 signed qsub across from E (mem or
12152 mmx) and G to G (mmx). */
12153 /* 0F 38 01 = PHADDW -- 16x4 add across from E (mem or mmx) and G
12154 to G (mmx). */
12155 /* 0F 38 05 = PHSUBW -- 16x4 sub across from E (mem or mmx) and G
12156 to G (mmx). */
12157 /* 0F 38 02 = PHADDD -- 32x2 add across from E (mem or mmx) and G
12158 to G (mmx). */
12159 /* 0F 38 06 = PHSUBD -- 32x2 sub across from E (mem or mmx) and G
12160 to G (mmx). */
12161
12162 if (sz == 4
12163 && insn[0] == 0x0F && insn[1] == 0x38
12164 && (insn[2] == 0x03 || insn[2] == 0x07 || insn[2] == 0x01
12165 || insn[2] == 0x05 || insn[2] == 0x02 || insn[2] == 0x06)) {
florian55085f82012-11-21 00:36:55 +000012166 const HChar* str = "???";
sewardj150c9cd2008-02-09 01:16:02 +000012167 IROp opV64 = Iop_INVALID;
12168 IROp opCatO = Iop_CatOddLanes16x4;
12169 IROp opCatE = Iop_CatEvenLanes16x4;
12170 IRTemp sV = newTemp(Ity_I64);
12171 IRTemp dV = newTemp(Ity_I64);
12172
12173 modrm = insn[3];
12174
12175 switch (insn[2]) {
12176 case 0x03: opV64 = Iop_QAdd16Sx4; str = "addsw"; break;
12177 case 0x07: opV64 = Iop_QSub16Sx4; str = "subsw"; break;
12178 case 0x01: opV64 = Iop_Add16x4; str = "addw"; break;
12179 case 0x05: opV64 = Iop_Sub16x4; str = "subw"; break;
12180 case 0x02: opV64 = Iop_Add32x2; str = "addd"; break;
12181 case 0x06: opV64 = Iop_Sub32x2; str = "subd"; break;
12182 default: vassert(0);
12183 }
12184 if (insn[2] == 0x02 || insn[2] == 0x06) {
12185 opCatO = Iop_InterleaveHI32x2;
12186 opCatE = Iop_InterleaveLO32x2;
12187 }
12188
12189 do_MMX_preamble();
12190 assign( dV, getMMXReg(gregOfRM(modrm)) );
12191
12192 if (epartIsReg(modrm)) {
12193 assign( sV, getMMXReg(eregOfRM(modrm)) );
12194 delta += 3+1;
12195 DIP("ph%s %s,%s\n", str, nameMMXReg(eregOfRM(modrm)),
12196 nameMMXReg(gregOfRM(modrm)));
12197 } else {
12198 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
12199 assign( sV, loadLE(Ity_I64, mkexpr(addr)) );
12200 delta += 3+alen;
12201 DIP("ph%s %s,%s\n", str, dis_buf,
12202 nameMMXReg(gregOfRM(modrm)));
12203 }
12204
12205 putMMXReg(
12206 gregOfRM(modrm),
12207 binop(opV64,
12208 binop(opCatE,mkexpr(sV),mkexpr(dV)),
12209 binop(opCatO,mkexpr(sV),mkexpr(dV))
12210 )
12211 );
12212 goto decode_success;
12213 }
12214
12215 /* 66 0F 38 03 = PHADDSW -- 16x8 signed qadd across from E (mem or
12216 xmm) and G to G (xmm). */
12217 /* 66 0F 38 07 = PHSUBSW -- 16x8 signed qsub across from E (mem or
12218 xmm) and G to G (xmm). */
12219 /* 66 0F 38 01 = PHADDW -- 16x8 add across from E (mem or xmm) and
12220 G to G (xmm). */
12221 /* 66 0F 38 05 = PHSUBW -- 16x8 sub across from E (mem or xmm) and
12222 G to G (xmm). */
12223 /* 66 0F 38 02 = PHADDD -- 32x4 add across from E (mem or xmm) and
12224 G to G (xmm). */
12225 /* 66 0F 38 06 = PHSUBD -- 32x4 sub across from E (mem or xmm) and
12226 G to G (xmm). */
12227
12228 if (sz == 2
12229 && insn[0] == 0x0F && insn[1] == 0x38
12230 && (insn[2] == 0x03 || insn[2] == 0x07 || insn[2] == 0x01
12231 || insn[2] == 0x05 || insn[2] == 0x02 || insn[2] == 0x06)) {
florian55085f82012-11-21 00:36:55 +000012232 const HChar* str = "???";
sewardj150c9cd2008-02-09 01:16:02 +000012233 IROp opV64 = Iop_INVALID;
12234 IROp opCatO = Iop_CatOddLanes16x4;
12235 IROp opCatE = Iop_CatEvenLanes16x4;
12236 IRTemp sV = newTemp(Ity_V128);
12237 IRTemp dV = newTemp(Ity_V128);
12238 IRTemp sHi = newTemp(Ity_I64);
12239 IRTemp sLo = newTemp(Ity_I64);
12240 IRTemp dHi = newTemp(Ity_I64);
12241 IRTemp dLo = newTemp(Ity_I64);
12242
12243 modrm = insn[3];
12244
12245 switch (insn[2]) {
12246 case 0x03: opV64 = Iop_QAdd16Sx4; str = "addsw"; break;
12247 case 0x07: opV64 = Iop_QSub16Sx4; str = "subsw"; break;
12248 case 0x01: opV64 = Iop_Add16x4; str = "addw"; break;
12249 case 0x05: opV64 = Iop_Sub16x4; str = "subw"; break;
12250 case 0x02: opV64 = Iop_Add32x2; str = "addd"; break;
12251 case 0x06: opV64 = Iop_Sub32x2; str = "subd"; break;
12252 default: vassert(0);
12253 }
12254 if (insn[2] == 0x02 || insn[2] == 0x06) {
12255 opCatO = Iop_InterleaveHI32x2;
12256 opCatE = Iop_InterleaveLO32x2;
12257 }
12258
12259 assign( dV, getXMMReg(gregOfRM(modrm)) );
12260
12261 if (epartIsReg(modrm)) {
12262 assign( sV, getXMMReg( eregOfRM(modrm)) );
12263 DIP("ph%s %s,%s\n", str, nameXMMReg(eregOfRM(modrm)),
12264 nameXMMReg(gregOfRM(modrm)));
12265 delta += 3+1;
12266 } else {
12267 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
12268 gen_SEGV_if_not_16_aligned( addr );
12269 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
12270 DIP("ph%s %s,%s\n", str, dis_buf,
12271 nameXMMReg(gregOfRM(modrm)));
12272 delta += 3+alen;
12273 }
12274
12275 assign( dHi, unop(Iop_V128HIto64, mkexpr(dV)) );
12276 assign( dLo, unop(Iop_V128to64, mkexpr(dV)) );
12277 assign( sHi, unop(Iop_V128HIto64, mkexpr(sV)) );
12278 assign( sLo, unop(Iop_V128to64, mkexpr(sV)) );
12279
12280 /* This isn't a particularly efficient way to compute the
12281 result, but at least it avoids a proliferation of IROps,
12282 hence avoids complication all the backends. */
12283 putXMMReg(
12284 gregOfRM(modrm),
12285 binop(Iop_64HLtoV128,
12286 binop(opV64,
12287 binop(opCatE,mkexpr(sHi),mkexpr(sLo)),
12288 binop(opCatO,mkexpr(sHi),mkexpr(sLo))
12289 ),
12290 binop(opV64,
12291 binop(opCatE,mkexpr(dHi),mkexpr(dLo)),
12292 binop(opCatO,mkexpr(dHi),mkexpr(dLo))
12293 )
12294 )
12295 );
12296 goto decode_success;
12297 }
12298
12299 /* 0F 38 0B = PMULHRSW -- Packed Multiply High with Round and Scale
12300 (MMX) */
12301 if (sz == 4
12302 && insn[0] == 0x0F && insn[1] == 0x38 && insn[2] == 0x0B) {
12303 IRTemp sV = newTemp(Ity_I64);
12304 IRTemp dV = newTemp(Ity_I64);
12305
12306 modrm = insn[3];
12307 do_MMX_preamble();
12308 assign( dV, getMMXReg(gregOfRM(modrm)) );
12309
12310 if (epartIsReg(modrm)) {
12311 assign( sV, getMMXReg(eregOfRM(modrm)) );
12312 delta += 3+1;
12313 DIP("pmulhrsw %s,%s\n", nameMMXReg(eregOfRM(modrm)),
12314 nameMMXReg(gregOfRM(modrm)));
12315 } else {
12316 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
12317 assign( sV, loadLE(Ity_I64, mkexpr(addr)) );
12318 delta += 3+alen;
12319 DIP("pmulhrsw %s,%s\n", dis_buf,
12320 nameMMXReg(gregOfRM(modrm)));
12321 }
12322
12323 putMMXReg(
12324 gregOfRM(modrm),
12325 dis_PMULHRSW_helper( mkexpr(sV), mkexpr(dV) )
12326 );
12327 goto decode_success;
12328 }
12329
12330 /* 66 0F 38 0B = PMULHRSW -- Packed Multiply High with Round and
12331 Scale (XMM) */
12332 if (sz == 2
12333 && insn[0] == 0x0F && insn[1] == 0x38 && insn[2] == 0x0B) {
12334 IRTemp sV = newTemp(Ity_V128);
12335 IRTemp dV = newTemp(Ity_V128);
12336 IRTemp sHi = newTemp(Ity_I64);
12337 IRTemp sLo = newTemp(Ity_I64);
12338 IRTemp dHi = newTemp(Ity_I64);
12339 IRTemp dLo = newTemp(Ity_I64);
12340
12341 modrm = insn[3];
12342 assign( dV, getXMMReg(gregOfRM(modrm)) );
12343
12344 if (epartIsReg(modrm)) {
12345 assign( sV, getXMMReg(eregOfRM(modrm)) );
12346 delta += 3+1;
12347 DIP("pmulhrsw %s,%s\n", nameXMMReg(eregOfRM(modrm)),
12348 nameXMMReg(gregOfRM(modrm)));
12349 } else {
12350 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
12351 gen_SEGV_if_not_16_aligned( addr );
12352 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
12353 delta += 3+alen;
12354 DIP("pmulhrsw %s,%s\n", dis_buf,
12355 nameXMMReg(gregOfRM(modrm)));
12356 }
12357
12358 assign( dHi, unop(Iop_V128HIto64, mkexpr(dV)) );
12359 assign( dLo, unop(Iop_V128to64, mkexpr(dV)) );
12360 assign( sHi, unop(Iop_V128HIto64, mkexpr(sV)) );
12361 assign( sLo, unop(Iop_V128to64, mkexpr(sV)) );
12362
12363 putXMMReg(
12364 gregOfRM(modrm),
12365 binop(Iop_64HLtoV128,
12366 dis_PMULHRSW_helper( mkexpr(sHi), mkexpr(dHi) ),
12367 dis_PMULHRSW_helper( mkexpr(sLo), mkexpr(dLo) )
12368 )
12369 );
12370 goto decode_success;
12371 }
12372
12373 /* 0F 38 08 = PSIGNB -- Packed Sign 8x8 (MMX) */
12374 /* 0F 38 09 = PSIGNW -- Packed Sign 16x4 (MMX) */
12375 /* 0F 38 09 = PSIGND -- Packed Sign 32x2 (MMX) */
12376 if (sz == 4
12377 && insn[0] == 0x0F && insn[1] == 0x38
12378 && (insn[2] == 0x08 || insn[2] == 0x09 || insn[2] == 0x0A)) {
12379 IRTemp sV = newTemp(Ity_I64);
12380 IRTemp dV = newTemp(Ity_I64);
florian55085f82012-11-21 00:36:55 +000012381 const HChar* str = "???";
sewardj150c9cd2008-02-09 01:16:02 +000012382 Int laneszB = 0;
12383
12384 switch (insn[2]) {
12385 case 0x08: laneszB = 1; str = "b"; break;
12386 case 0x09: laneszB = 2; str = "w"; break;
12387 case 0x0A: laneszB = 4; str = "d"; break;
12388 default: vassert(0);
12389 }
12390
12391 modrm = insn[3];
12392 do_MMX_preamble();
12393 assign( dV, getMMXReg(gregOfRM(modrm)) );
12394
12395 if (epartIsReg(modrm)) {
12396 assign( sV, getMMXReg(eregOfRM(modrm)) );
12397 delta += 3+1;
12398 DIP("psign%s %s,%s\n", str, nameMMXReg(eregOfRM(modrm)),
12399 nameMMXReg(gregOfRM(modrm)));
12400 } else {
12401 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
12402 assign( sV, loadLE(Ity_I64, mkexpr(addr)) );
12403 delta += 3+alen;
12404 DIP("psign%s %s,%s\n", str, dis_buf,
12405 nameMMXReg(gregOfRM(modrm)));
12406 }
12407
12408 putMMXReg(
12409 gregOfRM(modrm),
12410 dis_PSIGN_helper( mkexpr(sV), mkexpr(dV), laneszB )
12411 );
12412 goto decode_success;
12413 }
12414
12415 /* 66 0F 38 08 = PSIGNB -- Packed Sign 8x16 (XMM) */
12416 /* 66 0F 38 09 = PSIGNW -- Packed Sign 16x8 (XMM) */
12417 /* 66 0F 38 09 = PSIGND -- Packed Sign 32x4 (XMM) */
12418 if (sz == 2
12419 && insn[0] == 0x0F && insn[1] == 0x38
12420 && (insn[2] == 0x08 || insn[2] == 0x09 || insn[2] == 0x0A)) {
12421 IRTemp sV = newTemp(Ity_V128);
12422 IRTemp dV = newTemp(Ity_V128);
12423 IRTemp sHi = newTemp(Ity_I64);
12424 IRTemp sLo = newTemp(Ity_I64);
12425 IRTemp dHi = newTemp(Ity_I64);
12426 IRTemp dLo = newTemp(Ity_I64);
florian55085f82012-11-21 00:36:55 +000012427 const HChar* str = "???";
sewardj150c9cd2008-02-09 01:16:02 +000012428 Int laneszB = 0;
12429
12430 switch (insn[2]) {
12431 case 0x08: laneszB = 1; str = "b"; break;
12432 case 0x09: laneszB = 2; str = "w"; break;
12433 case 0x0A: laneszB = 4; str = "d"; break;
12434 default: vassert(0);
12435 }
12436
12437 modrm = insn[3];
12438 assign( dV, getXMMReg(gregOfRM(modrm)) );
12439
12440 if (epartIsReg(modrm)) {
12441 assign( sV, getXMMReg(eregOfRM(modrm)) );
12442 delta += 3+1;
12443 DIP("psign%s %s,%s\n", str, nameXMMReg(eregOfRM(modrm)),
12444 nameXMMReg(gregOfRM(modrm)));
12445 } else {
12446 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
12447 gen_SEGV_if_not_16_aligned( addr );
12448 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
12449 delta += 3+alen;
12450 DIP("psign%s %s,%s\n", str, dis_buf,
12451 nameXMMReg(gregOfRM(modrm)));
12452 }
12453
12454 assign( dHi, unop(Iop_V128HIto64, mkexpr(dV)) );
12455 assign( dLo, unop(Iop_V128to64, mkexpr(dV)) );
12456 assign( sHi, unop(Iop_V128HIto64, mkexpr(sV)) );
12457 assign( sLo, unop(Iop_V128to64, mkexpr(sV)) );
12458
12459 putXMMReg(
12460 gregOfRM(modrm),
12461 binop(Iop_64HLtoV128,
12462 dis_PSIGN_helper( mkexpr(sHi), mkexpr(dHi), laneszB ),
12463 dis_PSIGN_helper( mkexpr(sLo), mkexpr(dLo), laneszB )
12464 )
12465 );
12466 goto decode_success;
12467 }
12468
12469 /* 0F 38 1C = PABSB -- Packed Absolute Value 8x8 (MMX) */
12470 /* 0F 38 1D = PABSW -- Packed Absolute Value 16x4 (MMX) */
12471 /* 0F 38 1E = PABSD -- Packed Absolute Value 32x2 (MMX) */
12472 if (sz == 4
12473 && insn[0] == 0x0F && insn[1] == 0x38
12474 && (insn[2] == 0x1C || insn[2] == 0x1D || insn[2] == 0x1E)) {
12475 IRTemp sV = newTemp(Ity_I64);
florian55085f82012-11-21 00:36:55 +000012476 const HChar* str = "???";
sewardj150c9cd2008-02-09 01:16:02 +000012477 Int laneszB = 0;
12478
12479 switch (insn[2]) {
12480 case 0x1C: laneszB = 1; str = "b"; break;
12481 case 0x1D: laneszB = 2; str = "w"; break;
12482 case 0x1E: laneszB = 4; str = "d"; break;
12483 default: vassert(0);
12484 }
12485
12486 modrm = insn[3];
12487 do_MMX_preamble();
12488
12489 if (epartIsReg(modrm)) {
12490 assign( sV, getMMXReg(eregOfRM(modrm)) );
12491 delta += 3+1;
12492 DIP("pabs%s %s,%s\n", str, nameMMXReg(eregOfRM(modrm)),
12493 nameMMXReg(gregOfRM(modrm)));
12494 } else {
12495 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
12496 assign( sV, loadLE(Ity_I64, mkexpr(addr)) );
12497 delta += 3+alen;
12498 DIP("pabs%s %s,%s\n", str, dis_buf,
12499 nameMMXReg(gregOfRM(modrm)));
12500 }
12501
12502 putMMXReg(
12503 gregOfRM(modrm),
12504 dis_PABS_helper( mkexpr(sV), laneszB )
12505 );
12506 goto decode_success;
12507 }
12508
12509 /* 66 0F 38 1C = PABSB -- Packed Absolute Value 8x16 (XMM) */
12510 /* 66 0F 38 1D = PABSW -- Packed Absolute Value 16x8 (XMM) */
12511 /* 66 0F 38 1E = PABSD -- Packed Absolute Value 32x4 (XMM) */
12512 if (sz == 2
12513 && insn[0] == 0x0F && insn[1] == 0x38
12514 && (insn[2] == 0x1C || insn[2] == 0x1D || insn[2] == 0x1E)) {
12515 IRTemp sV = newTemp(Ity_V128);
12516 IRTemp sHi = newTemp(Ity_I64);
12517 IRTemp sLo = newTemp(Ity_I64);
florian55085f82012-11-21 00:36:55 +000012518 const HChar* str = "???";
sewardj150c9cd2008-02-09 01:16:02 +000012519 Int laneszB = 0;
12520
12521 switch (insn[2]) {
12522 case 0x1C: laneszB = 1; str = "b"; break;
12523 case 0x1D: laneszB = 2; str = "w"; break;
12524 case 0x1E: laneszB = 4; str = "d"; break;
12525 default: vassert(0);
12526 }
12527
12528 modrm = insn[3];
12529
12530 if (epartIsReg(modrm)) {
12531 assign( sV, getXMMReg(eregOfRM(modrm)) );
12532 delta += 3+1;
12533 DIP("pabs%s %s,%s\n", str, nameXMMReg(eregOfRM(modrm)),
12534 nameXMMReg(gregOfRM(modrm)));
12535 } else {
12536 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
12537 gen_SEGV_if_not_16_aligned( addr );
12538 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
12539 delta += 3+alen;
12540 DIP("pabs%s %s,%s\n", str, dis_buf,
12541 nameXMMReg(gregOfRM(modrm)));
12542 }
12543
12544 assign( sHi, unop(Iop_V128HIto64, mkexpr(sV)) );
12545 assign( sLo, unop(Iop_V128to64, mkexpr(sV)) );
12546
12547 putXMMReg(
12548 gregOfRM(modrm),
12549 binop(Iop_64HLtoV128,
12550 dis_PABS_helper( mkexpr(sHi), laneszB ),
12551 dis_PABS_helper( mkexpr(sLo), laneszB )
12552 )
12553 );
12554 goto decode_success;
12555 }
12556
12557 /* 0F 3A 0F = PALIGNR -- Packed Align Right (MMX) */
12558 if (sz == 4
12559 && insn[0] == 0x0F && insn[1] == 0x3A && insn[2] == 0x0F) {
12560 IRTemp sV = newTemp(Ity_I64);
12561 IRTemp dV = newTemp(Ity_I64);
12562 IRTemp res = newTemp(Ity_I64);
12563
12564 modrm = insn[3];
12565 do_MMX_preamble();
12566 assign( dV, getMMXReg(gregOfRM(modrm)) );
12567
12568 if (epartIsReg(modrm)) {
12569 assign( sV, getMMXReg(eregOfRM(modrm)) );
12570 d32 = (UInt)insn[3+1];
12571 delta += 3+1+1;
florianb1737742015-08-03 16:03:13 +000012572 DIP("palignr $%u,%s,%s\n", d32,
sewardj150c9cd2008-02-09 01:16:02 +000012573 nameMMXReg(eregOfRM(modrm)),
12574 nameMMXReg(gregOfRM(modrm)));
12575 } else {
12576 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
12577 assign( sV, loadLE(Ity_I64, mkexpr(addr)) );
12578 d32 = (UInt)insn[3+alen];
12579 delta += 3+alen+1;
florianb1737742015-08-03 16:03:13 +000012580 DIP("palignr $%u%s,%s\n", d32,
sewardj150c9cd2008-02-09 01:16:02 +000012581 dis_buf,
12582 nameMMXReg(gregOfRM(modrm)));
12583 }
12584
12585 if (d32 == 0) {
12586 assign( res, mkexpr(sV) );
12587 }
12588 else if (d32 >= 1 && d32 <= 7) {
12589 assign(res,
12590 binop(Iop_Or64,
12591 binop(Iop_Shr64, mkexpr(sV), mkU8(8*d32)),
12592 binop(Iop_Shl64, mkexpr(dV), mkU8(8*(8-d32))
12593 )));
12594 }
12595 else if (d32 == 8) {
12596 assign( res, mkexpr(dV) );
12597 }
12598 else if (d32 >= 9 && d32 <= 15) {
12599 assign( res, binop(Iop_Shr64, mkexpr(dV), mkU8(8*(d32-8))) );
12600 }
12601 else if (d32 >= 16 && d32 <= 255) {
12602 assign( res, mkU64(0) );
12603 }
12604 else
12605 vassert(0);
12606
12607 putMMXReg( gregOfRM(modrm), mkexpr(res) );
12608 goto decode_success;
12609 }
12610
12611 /* 66 0F 3A 0F = PALIGNR -- Packed Align Right (XMM) */
12612 if (sz == 2
12613 && insn[0] == 0x0F && insn[1] == 0x3A && insn[2] == 0x0F) {
12614 IRTemp sV = newTemp(Ity_V128);
12615 IRTemp dV = newTemp(Ity_V128);
12616 IRTemp sHi = newTemp(Ity_I64);
12617 IRTemp sLo = newTemp(Ity_I64);
12618 IRTemp dHi = newTemp(Ity_I64);
12619 IRTemp dLo = newTemp(Ity_I64);
12620 IRTemp rHi = newTemp(Ity_I64);
12621 IRTemp rLo = newTemp(Ity_I64);
12622
12623 modrm = insn[3];
12624 assign( dV, getXMMReg(gregOfRM(modrm)) );
12625
12626 if (epartIsReg(modrm)) {
12627 assign( sV, getXMMReg(eregOfRM(modrm)) );
12628 d32 = (UInt)insn[3+1];
12629 delta += 3+1+1;
florianb1737742015-08-03 16:03:13 +000012630 DIP("palignr $%u,%s,%s\n", d32,
sewardj150c9cd2008-02-09 01:16:02 +000012631 nameXMMReg(eregOfRM(modrm)),
12632 nameXMMReg(gregOfRM(modrm)));
12633 } else {
12634 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
12635 gen_SEGV_if_not_16_aligned( addr );
12636 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
12637 d32 = (UInt)insn[3+alen];
12638 delta += 3+alen+1;
florianb1737742015-08-03 16:03:13 +000012639 DIP("palignr $%u,%s,%s\n", d32,
sewardj150c9cd2008-02-09 01:16:02 +000012640 dis_buf,
12641 nameXMMReg(gregOfRM(modrm)));
12642 }
12643
12644 assign( dHi, unop(Iop_V128HIto64, mkexpr(dV)) );
12645 assign( dLo, unop(Iop_V128to64, mkexpr(dV)) );
12646 assign( sHi, unop(Iop_V128HIto64, mkexpr(sV)) );
12647 assign( sLo, unop(Iop_V128to64, mkexpr(sV)) );
12648
12649 if (d32 == 0) {
12650 assign( rHi, mkexpr(sHi) );
12651 assign( rLo, mkexpr(sLo) );
12652 }
12653 else if (d32 >= 1 && d32 <= 7) {
12654 assign( rHi, dis_PALIGNR_XMM_helper(dLo, sHi, d32) );
12655 assign( rLo, dis_PALIGNR_XMM_helper(sHi, sLo, d32) );
12656 }
12657 else if (d32 == 8) {
12658 assign( rHi, mkexpr(dLo) );
12659 assign( rLo, mkexpr(sHi) );
12660 }
12661 else if (d32 >= 9 && d32 <= 15) {
12662 assign( rHi, dis_PALIGNR_XMM_helper(dHi, dLo, d32-8) );
12663 assign( rLo, dis_PALIGNR_XMM_helper(dLo, sHi, d32-8) );
12664 }
12665 else if (d32 == 16) {
12666 assign( rHi, mkexpr(dHi) );
12667 assign( rLo, mkexpr(dLo) );
12668 }
12669 else if (d32 >= 17 && d32 <= 23) {
12670 assign( rHi, binop(Iop_Shr64, mkexpr(dHi), mkU8(8*(d32-16))) );
12671 assign( rLo, dis_PALIGNR_XMM_helper(dHi, dLo, d32-16) );
12672 }
12673 else if (d32 == 24) {
12674 assign( rHi, mkU64(0) );
12675 assign( rLo, mkexpr(dHi) );
12676 }
12677 else if (d32 >= 25 && d32 <= 31) {
12678 assign( rHi, mkU64(0) );
12679 assign( rLo, binop(Iop_Shr64, mkexpr(dHi), mkU8(8*(d32-24))) );
12680 }
12681 else if (d32 >= 32 && d32 <= 255) {
12682 assign( rHi, mkU64(0) );
12683 assign( rLo, mkU64(0) );
12684 }
12685 else
12686 vassert(0);
12687
12688 putXMMReg(
12689 gregOfRM(modrm),
12690 binop(Iop_64HLtoV128, mkexpr(rHi), mkexpr(rLo))
12691 );
12692 goto decode_success;
12693 }
12694
12695 /* 0F 38 00 = PSHUFB -- Packed Shuffle Bytes 8x8 (MMX) */
12696 if (sz == 4
12697 && insn[0] == 0x0F && insn[1] == 0x38 && insn[2] == 0x00) {
12698 IRTemp sV = newTemp(Ity_I64);
12699 IRTemp dV = newTemp(Ity_I64);
12700
12701 modrm = insn[3];
12702 do_MMX_preamble();
12703 assign( dV, getMMXReg(gregOfRM(modrm)) );
12704
12705 if (epartIsReg(modrm)) {
12706 assign( sV, getMMXReg(eregOfRM(modrm)) );
12707 delta += 3+1;
12708 DIP("pshufb %s,%s\n", nameMMXReg(eregOfRM(modrm)),
12709 nameMMXReg(gregOfRM(modrm)));
12710 } else {
12711 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
12712 assign( sV, loadLE(Ity_I64, mkexpr(addr)) );
12713 delta += 3+alen;
12714 DIP("pshufb %s,%s\n", dis_buf,
12715 nameMMXReg(gregOfRM(modrm)));
12716 }
12717
12718 putMMXReg(
12719 gregOfRM(modrm),
12720 binop(
12721 Iop_And64,
12722 /* permute the lanes */
12723 binop(
12724 Iop_Perm8x8,
12725 mkexpr(dV),
12726 binop(Iop_And64, mkexpr(sV), mkU64(0x0707070707070707ULL))
12727 ),
12728 /* mask off lanes which have (index & 0x80) == 0x80 */
12729 unop(Iop_Not64, binop(Iop_SarN8x8, mkexpr(sV), mkU8(7)))
12730 )
12731 );
12732 goto decode_success;
12733 }
12734
12735 /* 66 0F 38 00 = PSHUFB -- Packed Shuffle Bytes 8x16 (XMM) */
12736 if (sz == 2
12737 && insn[0] == 0x0F && insn[1] == 0x38 && insn[2] == 0x00) {
12738 IRTemp sV = newTemp(Ity_V128);
12739 IRTemp dV = newTemp(Ity_V128);
12740 IRTemp sHi = newTemp(Ity_I64);
12741 IRTemp sLo = newTemp(Ity_I64);
12742 IRTemp dHi = newTemp(Ity_I64);
12743 IRTemp dLo = newTemp(Ity_I64);
12744 IRTemp rHi = newTemp(Ity_I64);
12745 IRTemp rLo = newTemp(Ity_I64);
12746 IRTemp sevens = newTemp(Ity_I64);
12747 IRTemp mask0x80hi = newTemp(Ity_I64);
12748 IRTemp mask0x80lo = newTemp(Ity_I64);
12749 IRTemp maskBit3hi = newTemp(Ity_I64);
12750 IRTemp maskBit3lo = newTemp(Ity_I64);
12751 IRTemp sAnd7hi = newTemp(Ity_I64);
12752 IRTemp sAnd7lo = newTemp(Ity_I64);
12753 IRTemp permdHi = newTemp(Ity_I64);
12754 IRTemp permdLo = newTemp(Ity_I64);
12755
12756 modrm = insn[3];
12757 assign( dV, getXMMReg(gregOfRM(modrm)) );
12758
12759 if (epartIsReg(modrm)) {
12760 assign( sV, getXMMReg(eregOfRM(modrm)) );
12761 delta += 3+1;
12762 DIP("pshufb %s,%s\n", nameXMMReg(eregOfRM(modrm)),
12763 nameXMMReg(gregOfRM(modrm)));
12764 } else {
12765 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
12766 gen_SEGV_if_not_16_aligned( addr );
12767 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
12768 delta += 3+alen;
12769 DIP("pshufb %s,%s\n", dis_buf,
12770 nameXMMReg(gregOfRM(modrm)));
12771 }
12772
12773 assign( dHi, unop(Iop_V128HIto64, mkexpr(dV)) );
12774 assign( dLo, unop(Iop_V128to64, mkexpr(dV)) );
12775 assign( sHi, unop(Iop_V128HIto64, mkexpr(sV)) );
12776 assign( sLo, unop(Iop_V128to64, mkexpr(sV)) );
12777
12778 assign( sevens, mkU64(0x0707070707070707ULL) );
12779
12780 /*
12781 mask0x80hi = Not(SarN8x8(sHi,7))
12782 maskBit3hi = SarN8x8(ShlN8x8(sHi,4),7)
12783 sAnd7hi = And(sHi,sevens)
12784 permdHi = Or( And(Perm8x8(dHi,sAnd7hi),maskBit3hi),
12785 And(Perm8x8(dLo,sAnd7hi),Not(maskBit3hi)) )
12786 rHi = And(permdHi,mask0x80hi)
12787 */
12788 assign(
12789 mask0x80hi,
12790 unop(Iop_Not64, binop(Iop_SarN8x8,mkexpr(sHi),mkU8(7))));
12791
12792 assign(
12793 maskBit3hi,
12794 binop(Iop_SarN8x8,
12795 binop(Iop_ShlN8x8,mkexpr(sHi),mkU8(4)),
12796 mkU8(7)));
12797
12798 assign(sAnd7hi, binop(Iop_And64,mkexpr(sHi),mkexpr(sevens)));
12799
12800 assign(
12801 permdHi,
12802 binop(
12803 Iop_Or64,
12804 binop(Iop_And64,
12805 binop(Iop_Perm8x8,mkexpr(dHi),mkexpr(sAnd7hi)),
12806 mkexpr(maskBit3hi)),
12807 binop(Iop_And64,
12808 binop(Iop_Perm8x8,mkexpr(dLo),mkexpr(sAnd7hi)),
12809 unop(Iop_Not64,mkexpr(maskBit3hi))) ));
12810
12811 assign(rHi, binop(Iop_And64,mkexpr(permdHi),mkexpr(mask0x80hi)) );
12812
12813 /* And the same for the lower half of the result. What fun. */
12814
12815 assign(
12816 mask0x80lo,
12817 unop(Iop_Not64, binop(Iop_SarN8x8,mkexpr(sLo),mkU8(7))));
12818
12819 assign(
12820 maskBit3lo,
12821 binop(Iop_SarN8x8,
12822 binop(Iop_ShlN8x8,mkexpr(sLo),mkU8(4)),
12823 mkU8(7)));
12824
12825 assign(sAnd7lo, binop(Iop_And64,mkexpr(sLo),mkexpr(sevens)));
12826
12827 assign(
12828 permdLo,
12829 binop(
12830 Iop_Or64,
12831 binop(Iop_And64,
12832 binop(Iop_Perm8x8,mkexpr(dHi),mkexpr(sAnd7lo)),
12833 mkexpr(maskBit3lo)),
12834 binop(Iop_And64,
12835 binop(Iop_Perm8x8,mkexpr(dLo),mkexpr(sAnd7lo)),
12836 unop(Iop_Not64,mkexpr(maskBit3lo))) ));
12837
12838 assign(rLo, binop(Iop_And64,mkexpr(permdLo),mkexpr(mask0x80lo)) );
12839
12840 putXMMReg(
12841 gregOfRM(modrm),
12842 binop(Iop_64HLtoV128, mkexpr(rHi), mkexpr(rLo))
12843 );
12844 goto decode_success;
12845 }
sewardj021f6b42012-08-23 23:39:49 +000012846
12847 /* 0F 38 F0 = MOVBE m16/32(E), r16/32(G) */
12848 /* 0F 38 F1 = MOVBE r16/32(G), m16/32(E) */
12849 if ((sz == 2 || sz == 4)
12850 && insn[0] == 0x0F && insn[1] == 0x38
12851 && (insn[2] == 0xF0 || insn[2] == 0xF1)
12852 && !epartIsReg(insn[3])) {
12853
12854 modrm = insn[3];
12855 addr = disAMode(&alen, sorb, delta + 3, dis_buf);
12856 delta += 3 + alen;
12857 ty = szToITy(sz);
12858 IRTemp src = newTemp(ty);
12859
12860 if (insn[2] == 0xF0) { /* LOAD */
12861 assign(src, loadLE(ty, mkexpr(addr)));
12862 IRTemp dst = math_BSWAP(src, ty);
12863 putIReg(sz, gregOfRM(modrm), mkexpr(dst));
12864 DIP("movbe %s,%s\n", dis_buf, nameIReg(sz, gregOfRM(modrm)));
12865 } else { /* STORE */
12866 assign(src, getIReg(sz, gregOfRM(modrm)));
12867 IRTemp dst = math_BSWAP(src, ty);
12868 storeLE(mkexpr(addr), mkexpr(dst));
12869 DIP("movbe %s,%s\n", nameIReg(sz, gregOfRM(modrm)), dis_buf);
12870 }
12871 goto decode_success;
12872 }
sewardj150c9cd2008-02-09 01:16:02 +000012873
12874 /* ---------------------------------------------------- */
12875 /* --- end of the SSSE3 decoder. --- */
12876 /* ---------------------------------------------------- */
12877
sewardjb7271612010-07-23 21:23:25 +000012878 /* ---------------------------------------------------- */
12879 /* --- start of the SSE4 decoder --- */
12880 /* ---------------------------------------------------- */
12881
12882 /* 66 0F 3A 0B /r ib = ROUNDSD imm8, xmm2/m64, xmm1
12883 (Partial implementation only -- only deal with cases where
12884 the rounding mode is specified directly by the immediate byte.)
12885 66 0F 3A 0A /r ib = ROUNDSS imm8, xmm2/m32, xmm1
12886 (Limitations ditto)
12887 */
12888 if (sz == 2
12889 && insn[0] == 0x0F && insn[1] == 0x3A
rhyskidde66a2472015-08-15 07:39:27 +000012890 && (insn[2] == 0x0B || insn[2] == 0x0A)) {
sewardjb7271612010-07-23 21:23:25 +000012891
12892 Bool isD = insn[2] == 0x0B;
12893 IRTemp src = newTemp(isD ? Ity_F64 : Ity_F32);
12894 IRTemp res = newTemp(isD ? Ity_F64 : Ity_F32);
12895 Int imm = 0;
12896
12897 modrm = insn[3];
12898
12899 if (epartIsReg(modrm)) {
12900 assign( src,
12901 isD ? getXMMRegLane64F( eregOfRM(modrm), 0 )
12902 : getXMMRegLane32F( eregOfRM(modrm), 0 ) );
12903 imm = insn[3+1];
12904 if (imm & ~3) goto decode_failure;
12905 delta += 3+1+1;
12906 DIP( "rounds%c $%d,%s,%s\n",
12907 isD ? 'd' : 's',
12908 imm, nameXMMReg( eregOfRM(modrm) ),
12909 nameXMMReg( gregOfRM(modrm) ) );
12910 } else {
12911 addr = disAMode( &alen, sorb, delta+3, dis_buf );
12912 assign( src, loadLE( isD ? Ity_F64 : Ity_F32, mkexpr(addr) ));
12913 imm = insn[3+alen];
12914 if (imm & ~3) goto decode_failure;
12915 delta += 3+alen+1;
12916 DIP( "roundsd $%d,%s,%s\n",
12917 imm, dis_buf, nameXMMReg( gregOfRM(modrm) ) );
12918 }
12919
12920 /* (imm & 3) contains an Intel-encoded rounding mode. Because
12921 that encoding is the same as the encoding for IRRoundingMode,
12922 we can use that value directly in the IR as a rounding
12923 mode. */
12924 assign(res, binop(isD ? Iop_RoundF64toInt : Iop_RoundF32toInt,
12925 mkU32(imm & 3), mkexpr(src)) );
12926
12927 if (isD)
12928 putXMMRegLane64F( gregOfRM(modrm), 0, mkexpr(res) );
12929 else
12930 putXMMRegLane32F( gregOfRM(modrm), 0, mkexpr(res) );
12931
12932 goto decode_success;
12933 }
12934
sewardj536fbab2010-07-29 15:39:05 +000012935 /* F3 0F BD -- LZCNT (count leading zeroes. An AMD extension,
12936 which we can only decode if we're sure this is an AMD cpu that
12937 supports LZCNT, since otherwise it's BSR, which behaves
12938 differently. */
12939 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0xBD
12940 && 0 != (archinfo->hwcaps & VEX_HWCAPS_X86_LZCNT)) {
sewardj9a660ea2010-07-29 11:34:38 +000012941 vassert(sz == 2 || sz == 4);
12942 /*IRType*/ ty = szToITy(sz);
12943 IRTemp src = newTemp(ty);
12944 modrm = insn[3];
12945 if (epartIsReg(modrm)) {
12946 assign(src, getIReg(sz, eregOfRM(modrm)));
12947 delta += 3+1;
12948 DIP("lzcnt%c %s, %s\n", nameISize(sz),
12949 nameIReg(sz, eregOfRM(modrm)),
12950 nameIReg(sz, gregOfRM(modrm)));
12951 } else {
12952 addr = disAMode( &alen, sorb, delta+3, dis_buf );
12953 assign(src, loadLE(ty, mkexpr(addr)));
12954 delta += 3+alen;
12955 DIP("lzcnt%c %s, %s\n", nameISize(sz), dis_buf,
12956 nameIReg(sz, gregOfRM(modrm)));
12957 }
12958
12959 IRTemp res = gen_LZCNT(ty, src);
12960 putIReg(sz, gregOfRM(modrm), mkexpr(res));
12961
12962 // Update flags. This is pretty lame .. perhaps can do better
12963 // if this turns out to be performance critical.
12964 // O S A P are cleared. Z is set if RESULT == 0.
12965 // C is set if SRC is zero.
12966 IRTemp src32 = newTemp(Ity_I32);
12967 IRTemp res32 = newTemp(Ity_I32);
12968 assign(src32, widenUto32(mkexpr(src)));
12969 assign(res32, widenUto32(mkexpr(res)));
12970
12971 IRTemp oszacp = newTemp(Ity_I32);
12972 assign(
12973 oszacp,
12974 binop(Iop_Or32,
12975 binop(Iop_Shl32,
12976 unop(Iop_1Uto32,
12977 binop(Iop_CmpEQ32, mkexpr(res32), mkU32(0))),
12978 mkU8(X86G_CC_SHIFT_Z)),
12979 binop(Iop_Shl32,
12980 unop(Iop_1Uto32,
12981 binop(Iop_CmpEQ32, mkexpr(src32), mkU32(0))),
12982 mkU8(X86G_CC_SHIFT_C))
12983 )
12984 );
12985
12986 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(X86G_CC_OP_COPY) ));
12987 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
12988 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
12989 stmt( IRStmt_Put( OFFB_CC_DEP1, mkexpr(oszacp) ));
12990
12991 goto decode_success;
12992 }
12993
sewardjb7271612010-07-23 21:23:25 +000012994 /* ---------------------------------------------------- */
12995 /* --- end of the SSE4 decoder --- */
12996 /* ---------------------------------------------------- */
12997
sewardj9df271d2004-12-31 22:37:42 +000012998 after_sse_decoders:
12999
sewardjdc5d0842006-11-16 10:42:02 +000013000 /* ---------------------------------------------------- */
13001 /* --- deal with misc 0x67 pfxs (addr size override) -- */
13002 /* ---------------------------------------------------- */
13003
13004 /* 67 E3 = JCXZ (for JECXZ see below) */
13005 if (insn[0] == 0x67 && insn[1] == 0xE3 && sz == 4) {
13006 delta += 2;
13007 d32 = (((Addr32)guest_EIP_bbstart)+delta+1) + getSDisp8(delta);
13008 delta ++;
13009 stmt( IRStmt_Exit(
13010 binop(Iop_CmpEQ16, getIReg(2,R_ECX), mkU16(0)),
13011 Ijk_Boring,
sewardjc6f970f2012-04-02 21:54:49 +000013012 IRConst_U32(d32),
13013 OFFB_EIP
sewardjdc5d0842006-11-16 10:42:02 +000013014 ));
13015 DIP("jcxz 0x%x\n", d32);
13016 goto decode_success;
13017 }
13018
13019 /* ---------------------------------------------------- */
13020 /* --- start of the baseline insn decoder -- */
13021 /* ---------------------------------------------------- */
13022
sewardjc9a65702004-07-07 16:32:57 +000013023 /* Get the primary opcode. */
13024 opc = getIByte(delta); delta++;
13025
13026 /* We get here if the current insn isn't SSE, or this CPU doesn't
13027 support SSE. */
13028
13029 switch (opc) {
13030
13031 /* ------------------------ Control flow --------------- */
sewardj940e8c92004-07-11 16:53:24 +000013032
13033 case 0xC2: /* RET imm16 */
13034 d32 = getUDisp16(delta);
13035 delta += 2;
sewardjc6f970f2012-04-02 21:54:49 +000013036 dis_ret(&dres, d32);
florianb1737742015-08-03 16:03:13 +000013037 DIP("ret %u\n", d32);
sewardj940e8c92004-07-11 16:53:24 +000013038 break;
sewardje05c42c2004-07-08 20:25:10 +000013039 case 0xC3: /* RET */
sewardjc6f970f2012-04-02 21:54:49 +000013040 dis_ret(&dres, 0);
sewardje05c42c2004-07-08 20:25:10 +000013041 DIP("ret\n");
13042 break;
sewardj0e9a0f52008-01-04 01:22:41 +000013043
13044 case 0xCF: /* IRET */
13045 /* Note, this is an extremely kludgey and limited implementation
13046 of iret. All it really does is:
13047 popl %EIP; popl %CS; popl %EFLAGS.
13048 %CS is set but ignored (as it is in (eg) popw %cs)". */
13049 t1 = newTemp(Ity_I32); /* ESP */
13050 t2 = newTemp(Ity_I32); /* new EIP */
13051 t3 = newTemp(Ity_I32); /* new CS */
13052 t4 = newTemp(Ity_I32); /* new EFLAGS */
13053 assign(t1, getIReg(4,R_ESP));
13054 assign(t2, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t1),mkU32(0) )));
13055 assign(t3, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t1),mkU32(4) )));
13056 assign(t4, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t1),mkU32(8) )));
13057 /* Get stuff off stack */
13058 putIReg(4, R_ESP,binop(Iop_Add32, mkexpr(t1), mkU32(12)));
13059 /* set %CS (which is ignored anyway) */
13060 putSReg( R_CS, unop(Iop_32to16, mkexpr(t3)) );
13061 /* set %EFLAGS */
13062 set_EFLAGS_from_value( t4, False/*!emit_AC_emwarn*/, 0/*unused*/ );
13063 /* goto new EIP value */
sewardjc6f970f2012-04-02 21:54:49 +000013064 jmp_treg(&dres, Ijk_Ret, t2);
13065 vassert(dres.whatNext == Dis_StopHere);
sewardj0e9a0f52008-01-04 01:22:41 +000013066 DIP("iret (very kludgey)\n");
13067 break;
13068
sewardjd1061ab2004-07-08 01:45:30 +000013069 case 0xE8: /* CALL J4 */
13070 d32 = getUDisp32(delta); delta += 4;
sewardj9e6491a2005-07-02 19:24:10 +000013071 d32 += (guest_EIP_bbstart+delta);
sewardjce70a5c2004-10-18 14:09:54 +000013072 /* (guest_eip_bbstart+delta) == return-to addr, d32 == call-to addr */
sewardj9e6491a2005-07-02 19:24:10 +000013073 if (d32 == guest_EIP_bbstart+delta && getIByte(delta) >= 0x58
sewardjce70a5c2004-10-18 14:09:54 +000013074 && getIByte(delta) <= 0x5F) {
sewardjd1061ab2004-07-08 01:45:30 +000013075 /* Specially treat the position-independent-code idiom
13076 call X
13077 X: popl %reg
13078 as
13079 movl %eip, %reg.
13080 since this generates better code, but for no other reason. */
13081 Int archReg = getIByte(delta) - 0x58;
sewardjc2ac51e2004-07-12 01:03:26 +000013082 /* vex_printf("-- fPIC thingy\n"); */
sewardj9e6491a2005-07-02 19:24:10 +000013083 putIReg(4, archReg, mkU32(guest_EIP_bbstart+delta));
sewardjd1061ab2004-07-08 01:45:30 +000013084 delta++; /* Step over the POP */
13085 DIP("call 0x%x ; popl %s\n",d32,nameIReg(4,archReg));
sewardjc2ac51e2004-07-12 01:03:26 +000013086 } else {
sewardjd1061ab2004-07-08 01:45:30 +000013087 /* The normal sequence for a call. */
13088 t1 = newTemp(Ity_I32);
sewardj41f43bc2004-07-08 14:23:22 +000013089 assign(t1, binop(Iop_Sub32, getIReg(4,R_ESP), mkU32(4)));
13090 putIReg(4, R_ESP, mkexpr(t1));
sewardj9e6491a2005-07-02 19:24:10 +000013091 storeLE( mkexpr(t1), mkU32(guest_EIP_bbstart+delta));
florianbeac5302014-12-31 12:09:38 +000013092 if (resteerOkFn( callback_opaque, (Addr32)d32 )) {
sewardjce70a5c2004-10-18 14:09:54 +000013093 /* follow into the call target. */
sewardj984d9b12010-01-15 10:53:21 +000013094 dres.whatNext = Dis_ResteerU;
florian0eaa35f2015-01-02 13:34:15 +000013095 dres.continueAt = (Addr32)d32;
sewardjce70a5c2004-10-18 14:09:54 +000013096 } else {
sewardjc6f970f2012-04-02 21:54:49 +000013097 jmp_lit(&dres, Ijk_Call, d32);
13098 vassert(dres.whatNext == Dis_StopHere);
sewardjce70a5c2004-10-18 14:09:54 +000013099 }
sewardjd1061ab2004-07-08 01:45:30 +000013100 DIP("call 0x%x\n",d32);
13101 }
13102 break;
13103
sewardjc9a65702004-07-07 16:32:57 +000013104//-- case 0xC8: /* ENTER */
13105//-- d32 = getUDisp16(eip); eip += 2;
13106//-- abyte = getIByte(delta); delta++;
13107//--
13108//-- vg_assert(sz == 4);
13109//-- vg_assert(abyte == 0);
13110//--
13111//-- t1 = newTemp(cb); t2 = newTemp(cb);
13112//-- uInstr2(cb, GET, sz, ArchReg, R_EBP, TempReg, t1);
13113//-- uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t2);
13114//-- uInstr2(cb, SUB, 4, Literal, 0, TempReg, t2);
13115//-- uLiteral(cb, sz);
13116//-- uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_ESP);
13117//-- uInstr2(cb, STORE, 4, TempReg, t1, TempReg, t2);
13118//-- uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_EBP);
13119//-- if (d32) {
13120//-- uInstr2(cb, SUB, 4, Literal, 0, TempReg, t2);
sewardj5bd4d162004-11-10 13:02:48 +000013121//-- uLiteral(cb, d32);
13122//-- uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_ESP);
sewardjc9a65702004-07-07 16:32:57 +000013123//-- }
13124//-- DIP("enter 0x%x, 0x%x", d32, abyte);
13125//-- break;
sewardjc2ac51e2004-07-12 01:03:26 +000013126
13127 case 0xC9: /* LEAVE */
13128 vassert(sz == 4);
13129 t1 = newTemp(Ity_I32); t2 = newTemp(Ity_I32);
13130 assign(t1, getIReg(4,R_EBP));
13131 /* First PUT ESP looks redundant, but need it because ESP must
13132 always be up-to-date for Memcheck to work... */
13133 putIReg(4, R_ESP, mkexpr(t1));
13134 assign(t2, loadLE(Ity_I32,mkexpr(t1)));
13135 putIReg(4, R_EBP, mkexpr(t2));
13136 putIReg(4, R_ESP, binop(Iop_Add32, mkexpr(t1), mkU32(4)) );
13137 DIP("leave\n");
13138 break;
13139
sewardj8edc36b2007-11-23 02:46:29 +000013140 /* ---------------- Misc weird-ass insns --------------- */
13141
13142 case 0x27: /* DAA */
13143 case 0x2F: /* DAS */
13144 case 0x37: /* AAA */
13145 case 0x3F: /* AAS */
13146 /* An ugly implementation for some ugly instructions. Oh
13147 well. */
13148 if (sz != 4) goto decode_failure;
13149 t1 = newTemp(Ity_I32);
13150 t2 = newTemp(Ity_I32);
13151 /* Make up a 32-bit value (t1), with the old value of AX in the
13152 bottom 16 bits, and the old OSZACP bitmask in the upper 16
13153 bits. */
13154 assign(t1,
13155 binop(Iop_16HLto32,
13156 unop(Iop_32to16,
13157 mk_x86g_calculate_eflags_all()),
13158 getIReg(2, R_EAX)
13159 ));
13160 /* Call the helper fn, to get a new AX and OSZACP value, and
13161 poke both back into the guest state. Also pass the helper
13162 the actual opcode so it knows which of the 4 instructions it
13163 is doing the computation for. */
13164 vassert(opc == 0x27 || opc == 0x2F || opc == 0x37 || opc == 0x3F);
13165 assign(t2,
13166 mkIRExprCCall(
13167 Ity_I32, 0/*regparm*/, "x86g_calculate_daa_das_aaa_aas",
13168 &x86g_calculate_daa_das_aaa_aas,
13169 mkIRExprVec_2( mkexpr(t1), mkU32( opc & 0xFF) )
13170 ));
13171 putIReg(2, R_EAX, unop(Iop_32to16, mkexpr(t2) ));
13172
13173 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(X86G_CC_OP_COPY) ));
13174 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
13175 stmt( IRStmt_Put( OFFB_CC_DEP1,
13176 binop(Iop_And32,
13177 binop(Iop_Shr32, mkexpr(t2), mkU8(16)),
13178 mkU32( X86G_CC_MASK_C | X86G_CC_MASK_P
13179 | X86G_CC_MASK_A | X86G_CC_MASK_Z
13180 | X86G_CC_MASK_S| X86G_CC_MASK_O )
13181 )
13182 )
13183 );
13184 /* Set NDEP even though it isn't used. This makes redundant-PUT
13185 elimination of previous stores to this field work better. */
13186 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
13187 switch (opc) {
13188 case 0x27: DIP("daa\n"); break;
13189 case 0x2F: DIP("das\n"); break;
13190 case 0x37: DIP("aaa\n"); break;
13191 case 0x3F: DIP("aas\n"); break;
13192 default: vassert(0);
13193 }
13194 break;
13195
sewardj321bbbf2011-01-17 12:32:25 +000013196 case 0xD4: /* AAM */
13197 case 0xD5: /* AAD */
13198 d32 = getIByte(delta); delta++;
13199 if (sz != 4 || d32 != 10) goto decode_failure;
13200 t1 = newTemp(Ity_I32);
13201 t2 = newTemp(Ity_I32);
13202 /* Make up a 32-bit value (t1), with the old value of AX in the
13203 bottom 16 bits, and the old OSZACP bitmask in the upper 16
13204 bits. */
13205 assign(t1,
13206 binop(Iop_16HLto32,
13207 unop(Iop_32to16,
13208 mk_x86g_calculate_eflags_all()),
13209 getIReg(2, R_EAX)
13210 ));
13211 /* Call the helper fn, to get a new AX and OSZACP value, and
13212 poke both back into the guest state. Also pass the helper
13213 the actual opcode so it knows which of the 2 instructions it
13214 is doing the computation for. */
13215 assign(t2,
13216 mkIRExprCCall(
13217 Ity_I32, 0/*regparm*/, "x86g_calculate_aad_aam",
13218 &x86g_calculate_aad_aam,
13219 mkIRExprVec_2( mkexpr(t1), mkU32( opc & 0xFF) )
13220 ));
13221 putIReg(2, R_EAX, unop(Iop_32to16, mkexpr(t2) ));
13222
13223 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(X86G_CC_OP_COPY) ));
13224 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
13225 stmt( IRStmt_Put( OFFB_CC_DEP1,
13226 binop(Iop_And32,
13227 binop(Iop_Shr32, mkexpr(t2), mkU8(16)),
13228 mkU32( X86G_CC_MASK_C | X86G_CC_MASK_P
13229 | X86G_CC_MASK_A | X86G_CC_MASK_Z
13230 | X86G_CC_MASK_S| X86G_CC_MASK_O )
13231 )
13232 )
13233 );
13234 /* Set NDEP even though it isn't used. This makes
13235 redundant-PUT elimination of previous stores to this field
13236 work better. */
13237 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
13238
13239 DIP(opc == 0xD4 ? "aam\n" : "aad\n");
13240 break;
sewardj1c6f9912004-09-07 10:15:24 +000013241
13242 /* ------------------------ CWD/CDQ -------------------- */
13243
13244 case 0x98: /* CBW */
13245 if (sz == 4) {
13246 putIReg(4, R_EAX, unop(Iop_16Sto32, getIReg(2, R_EAX)));
13247 DIP("cwde\n");
13248 } else {
sewardj47341042004-09-19 11:55:46 +000013249 vassert(sz == 2);
13250 putIReg(2, R_EAX, unop(Iop_8Sto16, getIReg(1, R_EAX)));
13251 DIP("cbw\n");
sewardj1c6f9912004-09-07 10:15:24 +000013252 }
13253 break;
sewardj64e1d652004-07-12 14:00:46 +000013254
13255 case 0x99: /* CWD/CDQ */
13256 ty = szToITy(sz);
13257 putIReg(sz, R_EDX,
13258 binop(mkSizedOp(ty,Iop_Sar8),
13259 getIReg(sz, R_EAX),
sewardj9ee82862004-12-14 01:16:59 +000013260 mkU8(sz == 2 ? 15 : 31)) );
sewardj64e1d652004-07-12 14:00:46 +000013261 DIP(sz == 2 ? "cwdq\n" : "cdqq\n");
13262 break;
13263
sewardjbdc7d212004-09-09 02:46:40 +000013264 /* ------------------------ FPU ops -------------------- */
13265
13266 case 0x9E: /* SAHF */
13267 codegen_SAHF();
13268 DIP("sahf\n");
13269 break;
13270
sewardj8dfdc8a2005-10-03 11:39:02 +000013271 case 0x9F: /* LAHF */
13272 codegen_LAHF();
13273 DIP("lahf\n");
13274 break;
13275
sewardjbdc7d212004-09-09 02:46:40 +000013276 case 0x9B: /* FWAIT */
13277 /* ignore? */
13278 DIP("fwait\n");
13279 break;
13280
sewardjd1725d12004-08-12 20:46:53 +000013281 case 0xD8:
13282 case 0xD9:
13283 case 0xDA:
13284 case 0xDB:
13285 case 0xDC:
13286 case 0xDD:
13287 case 0xDE:
13288 case 0xDF: {
sewardj52d04912005-07-03 00:52:48 +000013289 Int delta0 = delta;
sewardjd1725d12004-08-12 20:46:53 +000013290 Bool decode_OK = False;
13291 delta = dis_FPU ( &decode_OK, sorb, delta );
13292 if (!decode_OK) {
13293 delta = delta0;
13294 goto decode_failure;
13295 }
13296 break;
13297 }
sewardj0611d802004-07-11 02:37:54 +000013298
13299 /* ------------------------ INC & DEC ------------------ */
13300
13301 case 0x40: /* INC eAX */
13302 case 0x41: /* INC eCX */
13303 case 0x42: /* INC eDX */
13304 case 0x43: /* INC eBX */
13305 case 0x44: /* INC eSP */
13306 case 0x45: /* INC eBP */
13307 case 0x46: /* INC eSI */
13308 case 0x47: /* INC eDI */
13309 vassert(sz == 2 || sz == 4);
13310 ty = szToITy(sz);
13311 t1 = newTemp(ty);
13312 assign( t1, binop(mkSizedOp(ty,Iop_Add8),
13313 getIReg(sz, (UInt)(opc - 0x40)),
13314 mkU(ty,1)) );
13315 setFlags_INC_DEC( True, t1, ty );
13316 putIReg(sz, (UInt)(opc - 0x40), mkexpr(t1));
13317 DIP("inc%c %s\n", nameISize(sz), nameIReg(sz,opc-0x40));
13318 break;
13319
13320 case 0x48: /* DEC eAX */
13321 case 0x49: /* DEC eCX */
13322 case 0x4A: /* DEC eDX */
13323 case 0x4B: /* DEC eBX */
13324 case 0x4C: /* DEC eSP */
13325 case 0x4D: /* DEC eBP */
13326 case 0x4E: /* DEC eSI */
13327 case 0x4F: /* DEC eDI */
13328 vassert(sz == 2 || sz == 4);
13329 ty = szToITy(sz);
13330 t1 = newTemp(ty);
13331 assign( t1, binop(mkSizedOp(ty,Iop_Sub8),
13332 getIReg(sz, (UInt)(opc - 0x48)),
13333 mkU(ty,1)) );
13334 setFlags_INC_DEC( False, t1, ty );
13335 putIReg(sz, (UInt)(opc - 0x48), mkexpr(t1));
13336 DIP("dec%c %s\n", nameISize(sz), nameIReg(sz,opc-0x48));
13337 break;
13338
13339 /* ------------------------ INT ------------------------ */
13340
sewardj322bfa02007-02-28 23:31:42 +000013341 case 0xCC: /* INT 3 */
sewardjc6f970f2012-04-02 21:54:49 +000013342 jmp_lit(&dres, Ijk_SigTRAP, ((Addr32)guest_EIP_bbstart)+delta);
13343 vassert(dres.whatNext == Dis_StopHere);
sewardj322bfa02007-02-28 23:31:42 +000013344 DIP("int $0x3\n");
13345 break;
13346
sewardj0611d802004-07-11 02:37:54 +000013347 case 0xCD: /* INT imm8 */
13348 d32 = getIByte(delta); delta++;
sewardj0f500042007-08-29 09:09:17 +000013349
sewardjd660d412008-12-03 21:29:59 +000013350 /* For any of the cases where we emit a jump (that is, for all
13351 currently handled cases), it's important that all ArchRegs
13352 carry their up-to-date value at this point. So we declare an
13353 end-of-block here, which forces any TempRegs caching ArchRegs
13354 to be flushed. */
13355
sewardj84af6762012-02-16 12:36:47 +000013356 /* Handle int $0x3F .. $0x4F by synthesising a segfault and a
sewardj0f500042007-08-29 09:09:17 +000013357 restart of this instruction (hence the "-2" two lines below,
13358 to get the restart EIP to be this instruction. This is
13359 probably Linux-specific and it would be more correct to only
sewardj84af6762012-02-16 12:36:47 +000013360 do this if the VexAbiInfo says that is what we should do.
13361 This used to handle just 0x40-0x43; Jikes RVM uses a larger
13362 range (0x3F-0x49), and this allows some slack as well. */
13363 if (d32 >= 0x3F && d32 <= 0x4F) {
sewardjc6f970f2012-04-02 21:54:49 +000013364 jmp_lit(&dres, Ijk_SigSEGV, ((Addr32)guest_EIP_bbstart)+delta-2);
13365 vassert(dres.whatNext == Dis_StopHere);
florianb1737742015-08-03 16:03:13 +000013366 DIP("int $0x%x\n", d32);
sewardj0f500042007-08-29 09:09:17 +000013367 break;
13368 }
13369
sewardjd660d412008-12-03 21:29:59 +000013370 /* Handle int $0x80 (linux syscalls), int $0x81 and $0x82
sewardj3e5d82d2015-07-21 14:43:23 +000013371 (darwin syscalls), int $0x91 (Solaris syscalls) and int $0xD2
13372 (Solaris fasttrap syscalls). As part of this, note where we are, so we
sewardje86310f2009-03-19 22:21:40 +000013373 can back up the guest to this point if the syscall needs to
13374 be restarted. */
sewardj3e5d82d2015-07-21 14:43:23 +000013375 IRJumpKind jump_kind;
13376 switch (d32) {
13377 case 0x80:
13378 jump_kind = Ijk_Sys_int128;
sewardjd660d412008-12-03 21:29:59 +000013379 break;
sewardj3e5d82d2015-07-21 14:43:23 +000013380 case 0x81:
13381 jump_kind = Ijk_Sys_int129;
sewardjd660d412008-12-03 21:29:59 +000013382 break;
sewardj3e5d82d2015-07-21 14:43:23 +000013383 case 0x82:
13384 jump_kind = Ijk_Sys_int130;
sewardjd660d412008-12-03 21:29:59 +000013385 break;
sewardj3e5d82d2015-07-21 14:43:23 +000013386 case 0x91:
13387 jump_kind = Ijk_Sys_int145;
13388 break;
13389 case 0xD2:
13390 jump_kind = Ijk_Sys_int210;
13391 break;
13392 default:
13393 /* none of the above */
13394 goto decode_failure;
sewardjd660d412008-12-03 21:29:59 +000013395 }
13396
sewardj3e5d82d2015-07-21 14:43:23 +000013397 stmt( IRStmt_Put( OFFB_IP_AT_SYSCALL,
13398 mkU32(guest_EIP_curr_instr) ) );
13399 jmp_lit(&dres, jump_kind, ((Addr32)guest_EIP_bbstart)+delta);
13400 vassert(dres.whatNext == Dis_StopHere);
florianb1737742015-08-03 16:03:13 +000013401 DIP("int $0x%x\n", d32);
sewardj3e5d82d2015-07-21 14:43:23 +000013402 break;
sewardj0611d802004-07-11 02:37:54 +000013403
sewardj77b86be2004-07-11 13:28:24 +000013404 /* ------------------------ Jcond, byte offset --------- */
13405
13406 case 0xEB: /* Jb (jump, byte offset) */
sewardj9e6491a2005-07-02 19:24:10 +000013407 d32 = (((Addr32)guest_EIP_bbstart)+delta+1) + getSDisp8(delta);
sewardj77b86be2004-07-11 13:28:24 +000013408 delta++;
florianbeac5302014-12-31 12:09:38 +000013409 if (resteerOkFn( callback_opaque, (Addr32)d32) ) {
sewardj984d9b12010-01-15 10:53:21 +000013410 dres.whatNext = Dis_ResteerU;
florian0eaa35f2015-01-02 13:34:15 +000013411 dres.continueAt = (Addr32)d32;
sewardjce70a5c2004-10-18 14:09:54 +000013412 } else {
sewardjc6f970f2012-04-02 21:54:49 +000013413 jmp_lit(&dres, Ijk_Boring, d32);
13414 vassert(dres.whatNext == Dis_StopHere);
sewardjce70a5c2004-10-18 14:09:54 +000013415 }
sewardj77b86be2004-07-11 13:28:24 +000013416 DIP("jmp-8 0x%x\n", d32);
13417 break;
sewardj0611d802004-07-11 02:37:54 +000013418
13419 case 0xE9: /* Jv (jump, 16/32 offset) */
13420 vassert(sz == 4); /* JRS added 2004 July 11 */
sewardj9e6491a2005-07-02 19:24:10 +000013421 d32 = (((Addr32)guest_EIP_bbstart)+delta+sz) + getSDisp(sz,delta);
sewardj0611d802004-07-11 02:37:54 +000013422 delta += sz;
florianbeac5302014-12-31 12:09:38 +000013423 if (resteerOkFn( callback_opaque, (Addr32)d32) ) {
sewardj984d9b12010-01-15 10:53:21 +000013424 dres.whatNext = Dis_ResteerU;
florian0eaa35f2015-01-02 13:34:15 +000013425 dres.continueAt = (Addr32)d32;
sewardjce70a5c2004-10-18 14:09:54 +000013426 } else {
sewardjc6f970f2012-04-02 21:54:49 +000013427 jmp_lit(&dres, Ijk_Boring, d32);
13428 vassert(dres.whatNext == Dis_StopHere);
sewardjce70a5c2004-10-18 14:09:54 +000013429 }
sewardj0611d802004-07-11 02:37:54 +000013430 DIP("jmp 0x%x\n", d32);
13431 break;
sewardje87b4842004-07-10 12:23:30 +000013432
13433 case 0x70:
13434 case 0x71:
13435 case 0x72: /* JBb/JNAEb (jump below) */
13436 case 0x73: /* JNBb/JAEb (jump not below) */
13437 case 0x74: /* JZb/JEb (jump zero) */
13438 case 0x75: /* JNZb/JNEb (jump not zero) */
13439 case 0x76: /* JBEb/JNAb (jump below or equal) */
13440 case 0x77: /* JNBEb/JAb (jump not below or equal) */
13441 case 0x78: /* JSb (jump negative) */
13442 case 0x79: /* JSb (jump not negative) */
13443 case 0x7A: /* JP (jump parity even) */
13444 case 0x7B: /* JNP/JPO (jump parity odd) */
13445 case 0x7C: /* JLb/JNGEb (jump less) */
13446 case 0x7D: /* JGEb/JNLb (jump greater or equal) */
13447 case 0x7E: /* JLEb/JNGb (jump less or equal) */
13448 case 0x7F: /* JGb/JNLEb (jump greater) */
sewardj984d9b12010-01-15 10:53:21 +000013449 { Int jmpDelta;
florian55085f82012-11-21 00:36:55 +000013450 const HChar* comment = "";
sewardj984d9b12010-01-15 10:53:21 +000013451 jmpDelta = (Int)getSDisp8(delta);
13452 vassert(-128 <= jmpDelta && jmpDelta < 128);
13453 d32 = (((Addr32)guest_EIP_bbstart)+delta+1) + jmpDelta;
sewardje87b4842004-07-10 12:23:30 +000013454 delta++;
sewardj984d9b12010-01-15 10:53:21 +000013455 if (resteerCisOk
13456 && vex_control.guest_chase_cond
sewardj0d925b12010-01-17 15:47:01 +000013457 && (Addr32)d32 != (Addr32)guest_EIP_bbstart
sewardj984d9b12010-01-15 10:53:21 +000013458 && jmpDelta < 0
florianbeac5302014-12-31 12:09:38 +000013459 && resteerOkFn( callback_opaque, (Addr32)d32) ) {
sewardj984d9b12010-01-15 10:53:21 +000013460 /* Speculation: assume this backward branch is taken. So we
13461 need to emit a side-exit to the insn following this one,
13462 on the negation of the condition, and continue at the
sewardj0d925b12010-01-17 15:47:01 +000013463 branch target address (d32). If we wind up back at the
13464 first instruction of the trace, just stop; it's better to
13465 let the IR loop unroller handle that case. */
sewardjdbf550c2005-01-24 11:54:11 +000013466 stmt( IRStmt_Exit(
13467 mk_x86g_calculate_condition((X86Condcode)(1 ^ (opc - 0x70))),
13468 Ijk_Boring,
sewardjc6f970f2012-04-02 21:54:49 +000013469 IRConst_U32(guest_EIP_bbstart+delta),
13470 OFFB_EIP ) );
sewardj984d9b12010-01-15 10:53:21 +000013471 dres.whatNext = Dis_ResteerC;
florian0eaa35f2015-01-02 13:34:15 +000013472 dres.continueAt = (Addr32)d32;
sewardj984d9b12010-01-15 10:53:21 +000013473 comment = "(assumed taken)";
13474 }
13475 else
13476 if (resteerCisOk
13477 && vex_control.guest_chase_cond
sewardj0d925b12010-01-17 15:47:01 +000013478 && (Addr32)d32 != (Addr32)guest_EIP_bbstart
sewardj984d9b12010-01-15 10:53:21 +000013479 && jmpDelta >= 0
13480 && resteerOkFn( callback_opaque,
florianbeac5302014-12-31 12:09:38 +000013481 (Addr32)(guest_EIP_bbstart+delta)) ) {
sewardj984d9b12010-01-15 10:53:21 +000013482 /* Speculation: assume this forward branch is not taken. So
13483 we need to emit a side-exit to d32 (the dest) and continue
13484 disassembling at the insn immediately following this
13485 one. */
13486 stmt( IRStmt_Exit(
13487 mk_x86g_calculate_condition((X86Condcode)(opc - 0x70)),
13488 Ijk_Boring,
sewardjc6f970f2012-04-02 21:54:49 +000013489 IRConst_U32(d32),
13490 OFFB_EIP ) );
sewardj984d9b12010-01-15 10:53:21 +000013491 dres.whatNext = Dis_ResteerC;
florian0eaa35f2015-01-02 13:34:15 +000013492 dres.continueAt = guest_EIP_bbstart + delta;
sewardj984d9b12010-01-15 10:53:21 +000013493 comment = "(assumed not taken)";
13494 }
13495 else {
13496 /* Conservative default translation - end the block at this
13497 point. */
sewardjc6f970f2012-04-02 21:54:49 +000013498 jcc_01( &dres, (X86Condcode)(opc - 0x70),
sewardj984d9b12010-01-15 10:53:21 +000013499 (Addr32)(guest_EIP_bbstart+delta), d32);
sewardjc6f970f2012-04-02 21:54:49 +000013500 vassert(dres.whatNext == Dis_StopHere);
sewardjdbf550c2005-01-24 11:54:11 +000013501 }
sewardj984d9b12010-01-15 10:53:21 +000013502 DIP("j%s-8 0x%x %s\n", name_X86Condcode(opc - 0x70), d32, comment);
sewardje87b4842004-07-10 12:23:30 +000013503 break;
sewardj984d9b12010-01-15 10:53:21 +000013504 }
sewardje87b4842004-07-10 12:23:30 +000013505
sewardjdc5d0842006-11-16 10:42:02 +000013506 case 0xE3: /* JECXZ (for JCXZ see above) */
sewardjbaa66082005-08-23 17:29:27 +000013507 if (sz != 4) goto decode_failure;
sewardj9e6491a2005-07-02 19:24:10 +000013508 d32 = (((Addr32)guest_EIP_bbstart)+delta+1) + getSDisp8(delta);
sewardjdc5d0842006-11-16 10:42:02 +000013509 delta ++;
sewardj458a6f82004-08-25 12:46:02 +000013510 stmt( IRStmt_Exit(
sewardjdc5d0842006-11-16 10:42:02 +000013511 binop(Iop_CmpEQ32, getIReg(4,R_ECX), mkU32(0)),
sewardj893aada2004-11-29 19:57:54 +000013512 Ijk_Boring,
sewardjc6f970f2012-04-02 21:54:49 +000013513 IRConst_U32(d32),
13514 OFFB_EIP
sewardjdc5d0842006-11-16 10:42:02 +000013515 ));
13516 DIP("jecxz 0x%x\n", d32);
sewardj458a6f82004-08-25 12:46:02 +000013517 break;
13518
sewardjbaa66082005-08-23 17:29:27 +000013519 case 0xE0: /* LOOPNE disp8: decrement count, jump if count != 0 && ZF==0 */
13520 case 0xE1: /* LOOPE disp8: decrement count, jump if count != 0 && ZF==1 */
13521 case 0xE2: /* LOOP disp8: decrement count, jump if count != 0 */
13522 { /* Again, the docs say this uses ECX/CX as a count depending on
13523 the address size override, not the operand one. Since we
13524 don't handle address size overrides, I guess that means
13525 ECX. */
13526 IRExpr* zbit = NULL;
13527 IRExpr* count = NULL;
13528 IRExpr* cond = NULL;
florian55085f82012-11-21 00:36:55 +000013529 const HChar* xtra = NULL;
sewardjbaa66082005-08-23 17:29:27 +000013530
13531 if (sz != 4) goto decode_failure;
13532 d32 = (((Addr32)guest_EIP_bbstart)+delta+1) + getSDisp8(delta);
13533 delta++;
13534 putIReg(4, R_ECX, binop(Iop_Sub32, getIReg(4,R_ECX), mkU32(1)));
13535
13536 count = getIReg(4,R_ECX);
13537 cond = binop(Iop_CmpNE32, count, mkU32(0));
13538 switch (opc) {
13539 case 0xE2:
13540 xtra = "";
13541 break;
13542 case 0xE1:
13543 xtra = "e";
13544 zbit = mk_x86g_calculate_condition( X86CondZ );
13545 cond = mkAnd1(cond, zbit);
13546 break;
13547 case 0xE0:
13548 xtra = "ne";
13549 zbit = mk_x86g_calculate_condition( X86CondNZ );
13550 cond = mkAnd1(cond, zbit);
13551 break;
13552 default:
13553 vassert(0);
13554 }
sewardjc6f970f2012-04-02 21:54:49 +000013555 stmt( IRStmt_Exit(cond, Ijk_Boring, IRConst_U32(d32), OFFB_EIP) );
sewardjbaa66082005-08-23 17:29:27 +000013556
13557 DIP("loop%s 0x%x\n", xtra, d32);
13558 break;
13559 }
sewardj1813dbe2004-07-28 17:09:04 +000013560
13561 /* ------------------------ IMUL ----------------------- */
13562
13563 case 0x69: /* IMUL Iv, Ev, Gv */
13564 delta = dis_imul_I_E_G ( sorb, sz, delta, sz );
13565 break;
13566 case 0x6B: /* IMUL Ib, Ev, Gv */
13567 delta = dis_imul_I_E_G ( sorb, sz, delta, 1 );
13568 break;
sewardj0611d802004-07-11 02:37:54 +000013569
13570 /* ------------------------ MOV ------------------------ */
13571
13572 case 0x88: /* MOV Gb,Eb */
13573 delta = dis_mov_G_E(sorb, 1, delta);
13574 break;
sewardjc9a65702004-07-07 16:32:57 +000013575
13576 case 0x89: /* MOV Gv,Ev */
13577 delta = dis_mov_G_E(sorb, sz, delta);
13578 break;
13579
sewardjc2ac51e2004-07-12 01:03:26 +000013580 case 0x8A: /* MOV Eb,Gb */
13581 delta = dis_mov_E_G(sorb, 1, delta);
13582 break;
sewardje05c42c2004-07-08 20:25:10 +000013583
13584 case 0x8B: /* MOV Ev,Gv */
13585 delta = dis_mov_E_G(sorb, sz, delta);
13586 break;
13587
sewardje87b4842004-07-10 12:23:30 +000013588 case 0x8D: /* LEA M,Gv */
sewardje9460bd2005-01-28 13:45:42 +000013589 if (sz != 4)
13590 goto decode_failure;
sewardje05c42c2004-07-08 20:25:10 +000013591 modrm = getIByte(delta);
13592 if (epartIsReg(modrm))
sewardje9460bd2005-01-28 13:45:42 +000013593 goto decode_failure;
sewardje05c42c2004-07-08 20:25:10 +000013594 /* NOTE! this is the one place where a segment override prefix
13595 has no effect on the address calculation. Therefore we pass
13596 zero instead of sorb here. */
sewardje87b4842004-07-10 12:23:30 +000013597 addr = disAMode ( &alen, /*sorb*/ 0, delta, dis_buf );
13598 delta += alen;
sewardj940e8c92004-07-11 16:53:24 +000013599 putIReg(sz, gregOfRM(modrm), mkexpr(addr));
sewardje05c42c2004-07-08 20:25:10 +000013600 DIP("lea%c %s, %s\n", nameISize(sz), dis_buf,
13601 nameIReg(sz,gregOfRM(modrm)));
13602 break;
sewardje05c42c2004-07-08 20:25:10 +000013603
sewardj063f02f2004-10-20 12:36:12 +000013604 case 0x8C: /* MOV Sw,Ew -- MOV from a SEGMENT REGISTER */
13605 delta = dis_mov_Sw_Ew(sorb, sz, delta);
13606 break;
13607
sewardj7df596b2004-12-06 14:29:12 +000013608 case 0x8E: /* MOV Ew,Sw -- MOV to a SEGMENT REGISTER */
13609 delta = dis_mov_Ew_Sw(sorb, delta);
13610 break;
13611
sewardj43852812004-10-16 23:10:08 +000013612 case 0xA0: /* MOV Ob,AL */
13613 sz = 1;
13614 /* Fall through ... */
sewardj0c12ea82004-07-12 08:18:16 +000013615 case 0xA1: /* MOV Ov,eAX */
13616 d32 = getUDisp32(delta); delta += 4;
13617 ty = szToITy(sz);
13618 addr = newTemp(Ity_I32);
13619 assign( addr, handleSegOverride(sorb, mkU32(d32)) );
13620 putIReg(sz, R_EAX, loadLE(ty, mkexpr(addr)));
13621 DIP("mov%c %s0x%x, %s\n", nameISize(sz), sorbTxt(sorb),
13622 d32, nameIReg(sz,R_EAX));
13623 break;
13624
sewardj180e8b32004-07-29 01:40:11 +000013625 case 0xA2: /* MOV Ob,AL */
13626 sz = 1;
13627 /* Fall through ... */
sewardj750f4072004-07-26 22:39:11 +000013628 case 0xA3: /* MOV eAX,Ov */
13629 d32 = getUDisp32(delta); delta += 4;
13630 ty = szToITy(sz);
13631 addr = newTemp(Ity_I32);
13632 assign( addr, handleSegOverride(sorb, mkU32(d32)) );
13633 storeLE( mkexpr(addr), getIReg(sz,R_EAX) );
13634 DIP("mov%c %s, %s0x%x\n", nameISize(sz), nameIReg(sz,R_EAX),
13635 sorbTxt(sorb), d32);
13636 break;
sewardje87b4842004-07-10 12:23:30 +000013637
sewardjc2ac51e2004-07-12 01:03:26 +000013638 case 0xB0: /* MOV imm,AL */
13639 case 0xB1: /* MOV imm,CL */
13640 case 0xB2: /* MOV imm,DL */
13641 case 0xB3: /* MOV imm,BL */
13642 case 0xB4: /* MOV imm,AH */
13643 case 0xB5: /* MOV imm,CH */
13644 case 0xB6: /* MOV imm,DH */
13645 case 0xB7: /* MOV imm,BH */
13646 d32 = getIByte(delta); delta += 1;
13647 putIReg(1, opc-0xB0, mkU8(d32));
13648 DIP("movb $0x%x,%s\n", d32, nameIReg(1,opc-0xB0));
13649 break;
sewardj7ed22952004-07-29 00:09:58 +000013650
sewardje87b4842004-07-10 12:23:30 +000013651 case 0xB8: /* MOV imm,eAX */
13652 case 0xB9: /* MOV imm,eCX */
13653 case 0xBA: /* MOV imm,eDX */
13654 case 0xBB: /* MOV imm,eBX */
13655 case 0xBC: /* MOV imm,eSP */
13656 case 0xBD: /* MOV imm,eBP */
13657 case 0xBE: /* MOV imm,eSI */
13658 case 0xBF: /* MOV imm,eDI */
13659 d32 = getUDisp(sz,delta); delta += sz;
13660 putIReg(sz, opc-0xB8, mkU(szToITy(sz), d32));
13661 DIP("mov%c $0x%x,%s\n", nameISize(sz), d32, nameIReg(sz,opc-0xB8));
13662 break;
13663
sewardj1bf44e32013-09-18 18:27:55 +000013664 case 0xC6: /* C6 /0 = MOV Ib,Eb */
sewardj77b86be2004-07-11 13:28:24 +000013665 sz = 1;
sewardj1bf44e32013-09-18 18:27:55 +000013666 goto maybe_do_Mov_I_E;
13667 case 0xC7: /* C7 /0 = MOV Iv,Ev */
13668 goto maybe_do_Mov_I_E;
sewardje87b4842004-07-10 12:23:30 +000013669
sewardj1bf44e32013-09-18 18:27:55 +000013670 maybe_do_Mov_I_E:
sewardje87b4842004-07-10 12:23:30 +000013671 modrm = getIByte(delta);
sewardj1bf44e32013-09-18 18:27:55 +000013672 if (gregOfRM(modrm) == 0) {
13673 if (epartIsReg(modrm)) {
13674 delta++; /* mod/rm byte */
13675 d32 = getUDisp(sz,delta); delta += sz;
13676 putIReg(sz, eregOfRM(modrm), mkU(szToITy(sz), d32));
13677 DIP("mov%c $0x%x, %s\n", nameISize(sz), d32,
13678 nameIReg(sz,eregOfRM(modrm)));
13679 } else {
13680 addr = disAMode ( &alen, sorb, delta, dis_buf );
13681 delta += alen;
13682 d32 = getUDisp(sz,delta); delta += sz;
13683 storeLE(mkexpr(addr), mkU(szToITy(sz), d32));
13684 DIP("mov%c $0x%x, %s\n", nameISize(sz), d32, dis_buf);
13685 }
13686 break;
sewardje87b4842004-07-10 12:23:30 +000013687 }
sewardj1bf44e32013-09-18 18:27:55 +000013688 goto decode_failure;
sewardje87b4842004-07-10 12:23:30 +000013689
sewardj1813dbe2004-07-28 17:09:04 +000013690 /* ------------------------ opl imm, A ----------------- */
13691
13692 case 0x04: /* ADD Ib, AL */
sewardja718d5d2005-04-03 14:59:54 +000013693 delta = dis_op_imm_A( 1, False, Iop_Add8, True, delta, "add" );
sewardj1813dbe2004-07-28 17:09:04 +000013694 break;
sewardj77b86be2004-07-11 13:28:24 +000013695 case 0x05: /* ADD Iv, eAX */
sewardja718d5d2005-04-03 14:59:54 +000013696 delta = dis_op_imm_A( sz, False, Iop_Add8, True, delta, "add" );
sewardj77b86be2004-07-11 13:28:24 +000013697 break;
13698
sewardj940e8c92004-07-11 16:53:24 +000013699 case 0x0C: /* OR Ib, AL */
sewardja718d5d2005-04-03 14:59:54 +000013700 delta = dis_op_imm_A( 1, False, Iop_Or8, True, delta, "or" );
sewardj940e8c92004-07-11 16:53:24 +000013701 break;
sewardj82292882004-07-27 00:15:59 +000013702 case 0x0D: /* OR Iv, eAX */
sewardja718d5d2005-04-03 14:59:54 +000013703 delta = dis_op_imm_A( sz, False, Iop_Or8, True, delta, "or" );
sewardj82292882004-07-27 00:15:59 +000013704 break;
13705
sewardjeca20362005-08-24 09:22:39 +000013706 case 0x14: /* ADC Ib, AL */
13707 delta = dis_op_imm_A( 1, True, Iop_Add8, True, delta, "adc" );
13708 break;
sewardja718d5d2005-04-03 14:59:54 +000013709 case 0x15: /* ADC Iv, eAX */
sewardjeca20362005-08-24 09:22:39 +000013710 delta = dis_op_imm_A( sz, True, Iop_Add8, True, delta, "adc" );
sewardja718d5d2005-04-03 14:59:54 +000013711 break;
13712
sewardj2fbae082005-10-03 02:07:08 +000013713 case 0x1C: /* SBB Ib, AL */
13714 delta = dis_op_imm_A( 1, True, Iop_Sub8, True, delta, "sbb" );
13715 break;
13716 case 0x1D: /* SBB Iv, eAX */
13717 delta = dis_op_imm_A( sz, True, Iop_Sub8, True, delta, "sbb" );
13718 break;
13719
sewardj940e8c92004-07-11 16:53:24 +000013720 case 0x24: /* AND Ib, AL */
sewardja718d5d2005-04-03 14:59:54 +000013721 delta = dis_op_imm_A( 1, False, Iop_And8, True, delta, "and" );
sewardj940e8c92004-07-11 16:53:24 +000013722 break;
sewardjc2ac51e2004-07-12 01:03:26 +000013723 case 0x25: /* AND Iv, eAX */
sewardja718d5d2005-04-03 14:59:54 +000013724 delta = dis_op_imm_A( sz, False, Iop_And8, True, delta, "and" );
sewardjc2ac51e2004-07-12 01:03:26 +000013725 break;
sewardj0611d802004-07-11 02:37:54 +000013726
13727 case 0x2C: /* SUB Ib, AL */
sewardja718d5d2005-04-03 14:59:54 +000013728 delta = dis_op_imm_A( 1, False, Iop_Sub8, True, delta, "sub" );
sewardj0611d802004-07-11 02:37:54 +000013729 break;
sewardj68511542004-07-28 00:15:44 +000013730 case 0x2D: /* SUB Iv, eAX */
sewardja718d5d2005-04-03 14:59:54 +000013731 delta = dis_op_imm_A( sz, False, Iop_Sub8, True, delta, "sub" );
sewardj68511542004-07-28 00:15:44 +000013732 break;
13733
sewardj1c6f9912004-09-07 10:15:24 +000013734 case 0x34: /* XOR Ib, AL */
sewardja718d5d2005-04-03 14:59:54 +000013735 delta = dis_op_imm_A( 1, False, Iop_Xor8, True, delta, "xor" );
sewardj1c6f9912004-09-07 10:15:24 +000013736 break;
sewardjcaca9d02004-07-28 07:11:32 +000013737 case 0x35: /* XOR Iv, eAX */
sewardja718d5d2005-04-03 14:59:54 +000013738 delta = dis_op_imm_A( sz, False, Iop_Xor8, True, delta, "xor" );
sewardjcaca9d02004-07-28 07:11:32 +000013739 break;
13740
sewardj0611d802004-07-11 02:37:54 +000013741 case 0x3C: /* CMP Ib, AL */
sewardja718d5d2005-04-03 14:59:54 +000013742 delta = dis_op_imm_A( 1, False, Iop_Sub8, False, delta, "cmp" );
sewardj0611d802004-07-11 02:37:54 +000013743 break;
13744 case 0x3D: /* CMP Iv, eAX */
sewardja718d5d2005-04-03 14:59:54 +000013745 delta = dis_op_imm_A( sz, False, Iop_Sub8, False, delta, "cmp" );
sewardj0611d802004-07-11 02:37:54 +000013746 break;
13747
sewardj77b86be2004-07-11 13:28:24 +000013748 case 0xA8: /* TEST Ib, AL */
sewardja718d5d2005-04-03 14:59:54 +000013749 delta = dis_op_imm_A( 1, False, Iop_And8, False, delta, "test" );
sewardj77b86be2004-07-11 13:28:24 +000013750 break;
sewardjc2ac51e2004-07-12 01:03:26 +000013751 case 0xA9: /* TEST Iv, eAX */
sewardja718d5d2005-04-03 14:59:54 +000013752 delta = dis_op_imm_A( sz, False, Iop_And8, False, delta, "test" );
sewardjc2ac51e2004-07-12 01:03:26 +000013753 break;
13754
sewardj1c6f9912004-09-07 10:15:24 +000013755 /* ------------------------ opl Ev, Gv ----------------- */
13756
sewardj89cd0932004-09-08 18:23:25 +000013757 case 0x02: /* ADD Eb,Gb */
13758 delta = dis_op2_E_G ( sorb, False, Iop_Add8, True, 1, delta, "add" );
13759 break;
sewardj9334b0f2004-07-10 22:43:54 +000013760 case 0x03: /* ADD Ev,Gv */
sewardj180e8b32004-07-29 01:40:11 +000013761 delta = dis_op2_E_G ( sorb, False, Iop_Add8, True, sz, delta, "add" );
sewardj9334b0f2004-07-10 22:43:54 +000013762 break;
13763
sewardj7ed22952004-07-29 00:09:58 +000013764 case 0x0A: /* OR Eb,Gb */
sewardj180e8b32004-07-29 01:40:11 +000013765 delta = dis_op2_E_G ( sorb, False, Iop_Or8, True, 1, delta, "or" );
sewardj7ed22952004-07-29 00:09:58 +000013766 break;
sewardjc2ac51e2004-07-12 01:03:26 +000013767 case 0x0B: /* OR Ev,Gv */
sewardj180e8b32004-07-29 01:40:11 +000013768 delta = dis_op2_E_G ( sorb, False, Iop_Or8, True, sz, delta, "or" );
sewardjc2ac51e2004-07-12 01:03:26 +000013769 break;
sewardj2fbae082005-10-03 02:07:08 +000013770
13771 case 0x12: /* ADC Eb,Gb */
13772 delta = dis_op2_E_G ( sorb, True, Iop_Add8, True, 1, delta, "adc" );
13773 break;
sewardjc4eaff32004-09-10 20:25:11 +000013774 case 0x13: /* ADC Ev,Gv */
13775 delta = dis_op2_E_G ( sorb, True, Iop_Add8, True, sz, delta, "adc" );
13776 break;
13777
sewardj2fbae082005-10-03 02:07:08 +000013778 case 0x1A: /* SBB Eb,Gb */
13779 delta = dis_op2_E_G ( sorb, True, Iop_Sub8, True, 1, delta, "sbb" );
13780 break;
sewardj180e8b32004-07-29 01:40:11 +000013781 case 0x1B: /* SBB Ev,Gv */
13782 delta = dis_op2_E_G ( sorb, True, Iop_Sub8, True, sz, delta, "sbb" );
sewardj940e8c92004-07-11 16:53:24 +000013783 break;
13784
sewardj1c6f9912004-09-07 10:15:24 +000013785 case 0x22: /* AND Eb,Gb */
13786 delta = dis_op2_E_G ( sorb, False, Iop_And8, True, 1, delta, "and" );
13787 break;
sewardj180e8b32004-07-29 01:40:11 +000013788 case 0x23: /* AND Ev,Gv */
13789 delta = dis_op2_E_G ( sorb, False, Iop_And8, True, sz, delta, "and" );
13790 break;
13791
13792 case 0x2A: /* SUB Eb,Gb */
13793 delta = dis_op2_E_G ( sorb, False, Iop_Sub8, True, 1, delta, "sub" );
13794 break;
sewardj0611d802004-07-11 02:37:54 +000013795 case 0x2B: /* SUB Ev,Gv */
sewardj180e8b32004-07-29 01:40:11 +000013796 delta = dis_op2_E_G ( sorb, False, Iop_Sub8, True, sz, delta, "sub" );
sewardj0611d802004-07-11 02:37:54 +000013797 break;
sewardjc2ac51e2004-07-12 01:03:26 +000013798
13799 case 0x32: /* XOR Eb,Gb */
sewardj180e8b32004-07-29 01:40:11 +000013800 delta = dis_op2_E_G ( sorb, False, Iop_Xor8, True, 1, delta, "xor" );
sewardjc2ac51e2004-07-12 01:03:26 +000013801 break;
sewardj1813dbe2004-07-28 17:09:04 +000013802 case 0x33: /* XOR Ev,Gv */
sewardj180e8b32004-07-29 01:40:11 +000013803 delta = dis_op2_E_G ( sorb, False, Iop_Xor8, True, sz, delta, "xor" );
sewardj1813dbe2004-07-28 17:09:04 +000013804 break;
13805
sewardjc2ac51e2004-07-12 01:03:26 +000013806 case 0x3A: /* CMP Eb,Gb */
sewardj180e8b32004-07-29 01:40:11 +000013807 delta = dis_op2_E_G ( sorb, False, Iop_Sub8, False, 1, delta, "cmp" );
sewardjc2ac51e2004-07-12 01:03:26 +000013808 break;
sewardje90ad6a2004-07-10 19:02:10 +000013809 case 0x3B: /* CMP Ev,Gv */
sewardj180e8b32004-07-29 01:40:11 +000013810 delta = dis_op2_E_G ( sorb, False, Iop_Sub8, False, sz, delta, "cmp" );
sewardje90ad6a2004-07-10 19:02:10 +000013811 break;
13812
sewardj0611d802004-07-11 02:37:54 +000013813 case 0x84: /* TEST Eb,Gb */
sewardj180e8b32004-07-29 01:40:11 +000013814 delta = dis_op2_E_G ( sorb, False, Iop_And8, False, 1, delta, "test" );
sewardj0611d802004-07-11 02:37:54 +000013815 break;
sewardje05c42c2004-07-08 20:25:10 +000013816 case 0x85: /* TEST Ev,Gv */
sewardj180e8b32004-07-29 01:40:11 +000013817 delta = dis_op2_E_G ( sorb, False, Iop_And8, False, sz, delta, "test" );
sewardje05c42c2004-07-08 20:25:10 +000013818 break;
13819
sewardj180e8b32004-07-29 01:40:11 +000013820 /* ------------------------ opl Gv, Ev ----------------- */
13821
13822 case 0x00: /* ADD Gb,Eb */
sewardje9d8a262009-07-01 08:06:34 +000013823 delta = dis_op2_G_E ( sorb, pfx_lock, False,
13824 Iop_Add8, True, 1, delta, "add" );
sewardj180e8b32004-07-29 01:40:11 +000013825 break;
sewardje05c42c2004-07-08 20:25:10 +000013826 case 0x01: /* ADD Gv,Ev */
sewardje9d8a262009-07-01 08:06:34 +000013827 delta = dis_op2_G_E ( sorb, pfx_lock, False,
13828 Iop_Add8, True, sz, delta, "add" );
sewardje05c42c2004-07-08 20:25:10 +000013829 break;
13830
sewardj940e8c92004-07-11 16:53:24 +000013831 case 0x08: /* OR Gb,Eb */
sewardje9d8a262009-07-01 08:06:34 +000013832 delta = dis_op2_G_E ( sorb, pfx_lock, False,
13833 Iop_Or8, True, 1, delta, "or" );
sewardj940e8c92004-07-11 16:53:24 +000013834 break;
sewardj9334b0f2004-07-10 22:43:54 +000013835 case 0x09: /* OR Gv,Ev */
sewardje9d8a262009-07-01 08:06:34 +000013836 delta = dis_op2_G_E ( sorb, pfx_lock, False,
13837 Iop_Or8, True, sz, delta, "or" );
sewardj9334b0f2004-07-10 22:43:54 +000013838 break;
13839
sewardja2384712004-07-29 14:36:40 +000013840 case 0x10: /* ADC Gb,Eb */
sewardje9d8a262009-07-01 08:06:34 +000013841 delta = dis_op2_G_E ( sorb, pfx_lock, True,
13842 Iop_Add8, True, 1, delta, "adc" );
sewardja2384712004-07-29 14:36:40 +000013843 break;
sewardjcaca9d02004-07-28 07:11:32 +000013844 case 0x11: /* ADC Gv,Ev */
sewardje9d8a262009-07-01 08:06:34 +000013845 delta = dis_op2_G_E ( sorb, pfx_lock, True,
13846 Iop_Add8, True, sz, delta, "adc" );
sewardjcaca9d02004-07-28 07:11:32 +000013847 break;
13848
sewardja2384712004-07-29 14:36:40 +000013849 case 0x18: /* SBB Gb,Eb */
sewardje9d8a262009-07-01 08:06:34 +000013850 delta = dis_op2_G_E ( sorb, pfx_lock, True,
13851 Iop_Sub8, True, 1, delta, "sbb" );
sewardja2384712004-07-29 14:36:40 +000013852 break;
sewardjcaca9d02004-07-28 07:11:32 +000013853 case 0x19: /* SBB Gv,Ev */
sewardje9d8a262009-07-01 08:06:34 +000013854 delta = dis_op2_G_E ( sorb, pfx_lock, True,
13855 Iop_Sub8, True, sz, delta, "sbb" );
sewardjcaca9d02004-07-28 07:11:32 +000013856 break;
13857
sewardja2384712004-07-29 14:36:40 +000013858 case 0x20: /* AND Gb,Eb */
sewardje9d8a262009-07-01 08:06:34 +000013859 delta = dis_op2_G_E ( sorb, pfx_lock, False,
13860 Iop_And8, True, 1, delta, "and" );
sewardja2384712004-07-29 14:36:40 +000013861 break;
sewardj0611d802004-07-11 02:37:54 +000013862 case 0x21: /* AND Gv,Ev */
sewardje9d8a262009-07-01 08:06:34 +000013863 delta = dis_op2_G_E ( sorb, pfx_lock, False,
13864 Iop_And8, True, sz, delta, "and" );
sewardj0611d802004-07-11 02:37:54 +000013865 break;
13866
sewardj180e8b32004-07-29 01:40:11 +000013867 case 0x28: /* SUB Gb,Eb */
sewardje9d8a262009-07-01 08:06:34 +000013868 delta = dis_op2_G_E ( sorb, pfx_lock, False,
13869 Iop_Sub8, True, 1, delta, "sub" );
sewardj180e8b32004-07-29 01:40:11 +000013870 break;
sewardje05c42c2004-07-08 20:25:10 +000013871 case 0x29: /* SUB Gv,Ev */
sewardje9d8a262009-07-01 08:06:34 +000013872 delta = dis_op2_G_E ( sorb, pfx_lock, False,
13873 Iop_Sub8, True, sz, delta, "sub" );
sewardje05c42c2004-07-08 20:25:10 +000013874 break;
13875
sewardjc2ac51e2004-07-12 01:03:26 +000013876 case 0x30: /* XOR Gb,Eb */
sewardje9d8a262009-07-01 08:06:34 +000013877 delta = dis_op2_G_E ( sorb, pfx_lock, False,
13878 Iop_Xor8, True, 1, delta, "xor" );
sewardjc2ac51e2004-07-12 01:03:26 +000013879 break;
sewardje87b4842004-07-10 12:23:30 +000013880 case 0x31: /* XOR Gv,Ev */
sewardje9d8a262009-07-01 08:06:34 +000013881 delta = dis_op2_G_E ( sorb, pfx_lock, False,
13882 Iop_Xor8, True, sz, delta, "xor" );
sewardje87b4842004-07-10 12:23:30 +000013883 break;
13884
sewardj0611d802004-07-11 02:37:54 +000013885 case 0x38: /* CMP Gb,Eb */
sewardje9d8a262009-07-01 08:06:34 +000013886 delta = dis_op2_G_E ( sorb, pfx_lock, False,
13887 Iop_Sub8, False, 1, delta, "cmp" );
sewardj0611d802004-07-11 02:37:54 +000013888 break;
sewardje90ad6a2004-07-10 19:02:10 +000013889 case 0x39: /* CMP Gv,Ev */
sewardje9d8a262009-07-01 08:06:34 +000013890 delta = dis_op2_G_E ( sorb, pfx_lock, False,
13891 Iop_Sub8, False, sz, delta, "cmp" );
sewardje90ad6a2004-07-10 19:02:10 +000013892 break;
13893
sewardj9334b0f2004-07-10 22:43:54 +000013894 /* ------------------------ POP ------------------------ */
13895
13896 case 0x58: /* POP eAX */
13897 case 0x59: /* POP eCX */
13898 case 0x5A: /* POP eDX */
13899 case 0x5B: /* POP eBX */
13900 case 0x5D: /* POP eBP */
13901 case 0x5E: /* POP eSI */
13902 case 0x5F: /* POP eDI */
13903 case 0x5C: /* POP eSP */
13904 vassert(sz == 2 || sz == 4);
13905 t1 = newTemp(szToITy(sz)); t2 = newTemp(Ity_I32);
13906 assign(t2, getIReg(4, R_ESP));
13907 assign(t1, loadLE(szToITy(sz),mkexpr(t2)));
13908 putIReg(4, R_ESP, binop(Iop_Add32, mkexpr(t2), mkU32(sz)));
13909 putIReg(sz, opc-0x58, mkexpr(t1));
13910 DIP("pop%c %s\n", nameISize(sz), nameIReg(sz,opc-0x58));
13911 break;
13912
sewardja2384712004-07-29 14:36:40 +000013913 case 0x9D: /* POPF */
13914 vassert(sz == 2 || sz == 4);
sewardja2384712004-07-29 14:36:40 +000013915 t1 = newTemp(Ity_I32); t2 = newTemp(Ity_I32);
13916 assign(t2, getIReg(4, R_ESP));
sewardjc22a6fd2004-07-29 23:41:47 +000013917 assign(t1, widenUto32(loadLE(szToITy(sz),mkexpr(t2))));
sewardja2384712004-07-29 14:36:40 +000013918 putIReg(4, R_ESP, binop(Iop_Add32, mkexpr(t2), mkU32(sz)));
sewardja2384712004-07-29 14:36:40 +000013919
sewardj0e9a0f52008-01-04 01:22:41 +000013920 /* Generate IR to set %EFLAGS{O,S,Z,A,C,P,D,ID,AC} from the
13921 value in t1. */
13922 set_EFLAGS_from_value( t1, True/*emit_AC_emwarn*/,
13923 ((Addr32)guest_EIP_bbstart)+delta );
sewardj6d269842005-08-06 11:45:02 +000013924
sewardja2384712004-07-29 14:36:40 +000013925 DIP("popf%c\n", nameISize(sz));
13926 break;
13927
sewardjbbdc6222004-12-15 18:43:39 +000013928 case 0x61: /* POPA */
13929 /* This is almost certainly wrong for sz==2. So ... */
13930 if (sz != 4) goto decode_failure;
13931
13932 /* t5 is the old %ESP value. */
13933 t5 = newTemp(Ity_I32);
13934 assign( t5, getIReg(4, R_ESP) );
13935
13936 /* Reload all the registers, except %esp. */
13937 putIReg(4,R_EAX, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32(28)) ));
13938 putIReg(4,R_ECX, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32(24)) ));
13939 putIReg(4,R_EDX, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32(20)) ));
13940 putIReg(4,R_EBX, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32(16)) ));
13941 /* ignore saved %ESP */
13942 putIReg(4,R_EBP, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32( 8)) ));
13943 putIReg(4,R_ESI, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32( 4)) ));
13944 putIReg(4,R_EDI, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32( 0)) ));
13945
13946 /* and move %ESP back up */
13947 putIReg( 4, R_ESP, binop(Iop_Add32, mkexpr(t5), mkU32(8*4)) );
13948
sewardja3d1a662005-03-29 21:33:11 +000013949 DIP("popa%c\n", nameISize(sz));
sewardjbbdc6222004-12-15 18:43:39 +000013950 break;
sewardjfeeb8a82004-11-30 12:30:11 +000013951
13952 case 0x8F: /* POPL/POPW m32 */
sewardjfcff1782006-05-12 14:04:48 +000013953 { Int len;
13954 UChar rm = getIByte(delta);
sewardjfeeb8a82004-11-30 12:30:11 +000013955
13956 /* make sure this instruction is correct POP */
sewardjfcff1782006-05-12 14:04:48 +000013957 if (epartIsReg(rm) || gregOfRM(rm) != 0)
13958 goto decode_failure;
sewardjfeeb8a82004-11-30 12:30:11 +000013959 /* and has correct size */
sewardjfcff1782006-05-12 14:04:48 +000013960 if (sz != 4 && sz != 2)
13961 goto decode_failure;
13962 ty = szToITy(sz);
13963
13964 t1 = newTemp(Ity_I32); /* stack address */
13965 t3 = newTemp(ty); /* data */
sewardjfeeb8a82004-11-30 12:30:11 +000013966 /* set t1 to ESP: t1 = ESP */
13967 assign( t1, getIReg(4, R_ESP) );
13968 /* load M[ESP] to virtual register t3: t3 = M[t1] */
sewardjfcff1782006-05-12 14:04:48 +000013969 assign( t3, loadLE(ty, mkexpr(t1)) );
sewardjfeeb8a82004-11-30 12:30:11 +000013970
13971 /* increase ESP; must be done before the STORE. Intel manual says:
13972 If the ESP register is used as a base register for addressing
13973 a destination operand in memory, the POP instruction computes
13974 the effective address of the operand after it increments the
13975 ESP register.
13976 */
13977 putIReg(4, R_ESP, binop(Iop_Add32, mkexpr(t1), mkU32(sz)) );
13978
13979 /* resolve MODR/M */
13980 addr = disAMode ( &len, sorb, delta, dis_buf);
13981 storeLE( mkexpr(addr), mkexpr(t3) );
13982
sewardjfcff1782006-05-12 14:04:48 +000013983 DIP("pop%c %s\n", sz==2 ? 'w' : 'l', dis_buf);
sewardjfeeb8a82004-11-30 12:30:11 +000013984
13985 delta += len;
13986 break;
13987 }
13988
sewardj5c5f72c2006-03-18 11:29:25 +000013989 case 0x1F: /* POP %DS */
13990 dis_pop_segreg( R_DS, sz ); break;
13991 case 0x07: /* POP %ES */
13992 dis_pop_segreg( R_ES, sz ); break;
13993 case 0x17: /* POP %SS */
13994 dis_pop_segreg( R_SS, sz ); break;
sewardjd1061ab2004-07-08 01:45:30 +000013995
13996 /* ------------------------ PUSH ----------------------- */
13997
13998 case 0x50: /* PUSH eAX */
13999 case 0x51: /* PUSH eCX */
14000 case 0x52: /* PUSH eDX */
14001 case 0x53: /* PUSH eBX */
14002 case 0x55: /* PUSH eBP */
14003 case 0x56: /* PUSH eSI */
14004 case 0x57: /* PUSH eDI */
14005 case 0x54: /* PUSH eSP */
14006 /* This is the Right Way, in that the value to be pushed is
14007 established before %esp is changed, so that pushl %esp
14008 correctly pushes the old value. */
14009 vassert(sz == 2 || sz == 4);
14010 ty = sz==2 ? Ity_I16 : Ity_I32;
sewardj883b00b2004-09-11 09:30:24 +000014011 t1 = newTemp(ty); t2 = newTemp(Ity_I32);
sewardj41f43bc2004-07-08 14:23:22 +000014012 assign(t1, getIReg(sz, opc-0x50));
14013 assign(t2, binop(Iop_Sub32, getIReg(4, R_ESP), mkU32(sz)));
14014 putIReg(4, R_ESP, mkexpr(t2) );
14015 storeLE(mkexpr(t2),mkexpr(t1));
sewardjd1061ab2004-07-08 01:45:30 +000014016 DIP("push%c %s\n", nameISize(sz), nameIReg(sz,opc-0x50));
14017 break;
14018
14019
sewardj0c12ea82004-07-12 08:18:16 +000014020 case 0x68: /* PUSH Iv */
14021 d32 = getUDisp(sz,delta); delta += sz;
14022 goto do_push_I;
sewardj741153c2004-07-25 23:39:13 +000014023 case 0x6A: /* PUSH Ib, sign-extended to sz */
14024 d32 = getSDisp8(delta); delta += 1;
14025 goto do_push_I;
sewardj0c12ea82004-07-12 08:18:16 +000014026 do_push_I:
14027 ty = szToITy(sz);
14028 t1 = newTemp(Ity_I32); t2 = newTemp(ty);
14029 assign( t1, binop(Iop_Sub32,getIReg(4,R_ESP),mkU32(sz)) );
14030 putIReg(4, R_ESP, mkexpr(t1) );
sewardjc4255a02006-08-28 18:04:33 +000014031 /* stop mkU16 asserting if d32 is a negative 16-bit number
14032 (bug #132813) */
14033 if (ty == Ity_I16)
14034 d32 &= 0xFFFF;
sewardj0c12ea82004-07-12 08:18:16 +000014035 storeLE( mkexpr(t1), mkU(ty,d32) );
14036 DIP("push%c $0x%x\n", nameISize(sz), d32);
14037 break;
14038
sewardja2384712004-07-29 14:36:40 +000014039 case 0x9C: /* PUSHF */ {
sewardja2384712004-07-29 14:36:40 +000014040 vassert(sz == 2 || sz == 4);
sewardja2384712004-07-29 14:36:40 +000014041
14042 t1 = newTemp(Ity_I32);
14043 assign( t1, binop(Iop_Sub32,getIReg(4,R_ESP),mkU32(sz)) );
14044 putIReg(4, R_ESP, mkexpr(t1) );
14045
sewardjbc210942005-07-21 10:07:13 +000014046 /* Calculate OSZACP, and patch in fixed fields as per
14047 Intel docs.
14048 - bit 1 is always 1
14049 - bit 9 is Interrupt Enable (should always be 1 in user mode?)
14050 */
sewardja2384712004-07-29 14:36:40 +000014051 t2 = newTemp(Ity_I32);
sewardjbc210942005-07-21 10:07:13 +000014052 assign( t2, binop(Iop_Or32,
14053 mk_x86g_calculate_eflags_all(),
14054 mkU32( (1<<1)|(1<<9) ) ));
sewardja2384712004-07-29 14:36:40 +000014055
sewardjf9c74fe2004-12-16 02:54:54 +000014056 /* Patch in the D flag. This can simply be a copy of bit 10 of
14057 baseBlock[OFFB_DFLAG]. */
sewardja2384712004-07-29 14:36:40 +000014058 t3 = newTemp(Ity_I32);
14059 assign( t3, binop(Iop_Or32,
14060 mkexpr(t2),
14061 binop(Iop_And32,
sewardjf9c74fe2004-12-16 02:54:54 +000014062 IRExpr_Get(OFFB_DFLAG,Ity_I32),
sewardj5bd4d162004-11-10 13:02:48 +000014063 mkU32(1<<10)))
sewardja2384712004-07-29 14:36:40 +000014064 );
sewardj006a6a22004-10-26 00:50:52 +000014065
14066 /* And patch in the ID flag. */
14067 t4 = newTemp(Ity_I32);
14068 assign( t4, binop(Iop_Or32,
14069 mkexpr(t3),
14070 binop(Iop_And32,
sewardj5bd4d162004-11-10 13:02:48 +000014071 binop(Iop_Shl32, IRExpr_Get(OFFB_IDFLAG,Ity_I32),
sewardj006a6a22004-10-26 00:50:52 +000014072 mkU8(21)),
sewardj5bd4d162004-11-10 13:02:48 +000014073 mkU32(1<<21)))
sewardj006a6a22004-10-26 00:50:52 +000014074 );
14075
sewardj6d269842005-08-06 11:45:02 +000014076 /* And patch in the AC flag. */
14077 t5 = newTemp(Ity_I32);
14078 assign( t5, binop(Iop_Or32,
14079 mkexpr(t4),
14080 binop(Iop_And32,
14081 binop(Iop_Shl32, IRExpr_Get(OFFB_ACFLAG,Ity_I32),
14082 mkU8(18)),
14083 mkU32(1<<18)))
14084 );
14085
sewardja2384712004-07-29 14:36:40 +000014086 /* if sz==2, the stored value needs to be narrowed. */
14087 if (sz == 2)
sewardj6d269842005-08-06 11:45:02 +000014088 storeLE( mkexpr(t1), unop(Iop_32to16,mkexpr(t5)) );
sewardja2384712004-07-29 14:36:40 +000014089 else
sewardj6d269842005-08-06 11:45:02 +000014090 storeLE( mkexpr(t1), mkexpr(t5) );
sewardja2384712004-07-29 14:36:40 +000014091
14092 DIP("pushf%c\n", nameISize(sz));
14093 break;
14094 }
14095
sewardjbbdc6222004-12-15 18:43:39 +000014096 case 0x60: /* PUSHA */
14097 /* This is almost certainly wrong for sz==2. So ... */
14098 if (sz != 4) goto decode_failure;
14099
14100 /* This is the Right Way, in that the value to be pushed is
14101 established before %esp is changed, so that pusha
14102 correctly pushes the old %esp value. New value of %esp is
14103 pushed at start. */
14104 /* t0 is the %ESP value we're going to push. */
14105 t0 = newTemp(Ity_I32);
14106 assign( t0, getIReg(4, R_ESP) );
14107
14108 /* t5 will be the new %ESP value. */
14109 t5 = newTemp(Ity_I32);
14110 assign( t5, binop(Iop_Sub32, mkexpr(t0), mkU32(8*4)) );
14111
14112 /* Update guest state before prodding memory. */
14113 putIReg(4, R_ESP, mkexpr(t5));
14114
14115 /* Dump all the registers. */
14116 storeLE( binop(Iop_Add32,mkexpr(t5),mkU32(28)), getIReg(4,R_EAX) );
14117 storeLE( binop(Iop_Add32,mkexpr(t5),mkU32(24)), getIReg(4,R_ECX) );
14118 storeLE( binop(Iop_Add32,mkexpr(t5),mkU32(20)), getIReg(4,R_EDX) );
14119 storeLE( binop(Iop_Add32,mkexpr(t5),mkU32(16)), getIReg(4,R_EBX) );
14120 storeLE( binop(Iop_Add32,mkexpr(t5),mkU32(12)), mkexpr(t0) /*esp*/);
14121 storeLE( binop(Iop_Add32,mkexpr(t5),mkU32( 8)), getIReg(4,R_EBP) );
14122 storeLE( binop(Iop_Add32,mkexpr(t5),mkU32( 4)), getIReg(4,R_ESI) );
14123 storeLE( binop(Iop_Add32,mkexpr(t5),mkU32( 0)), getIReg(4,R_EDI) );
14124
14125 DIP("pusha%c\n", nameISize(sz));
14126 break;
14127
sewardj5c5f72c2006-03-18 11:29:25 +000014128 case 0x0E: /* PUSH %CS */
14129 dis_push_segreg( R_CS, sz ); break;
14130 case 0x1E: /* PUSH %DS */
14131 dis_push_segreg( R_DS, sz ); break;
14132 case 0x06: /* PUSH %ES */
14133 dis_push_segreg( R_ES, sz ); break;
14134 case 0x16: /* PUSH %SS */
14135 dis_push_segreg( R_SS, sz ); break;
sewardj458a6f82004-08-25 12:46:02 +000014136
14137 /* ------------------------ SCAS et al ----------------- */
14138
14139 case 0xA4: /* MOVS, no REP prefix */
14140 case 0xA5:
sewardj9c3b25a2007-04-05 15:06:56 +000014141 if (sorb != 0)
14142 goto decode_failure; /* else dis_string_op asserts */
sewardj458a6f82004-08-25 12:46:02 +000014143 dis_string_op( dis_MOVS, ( opc == 0xA4 ? 1 : sz ), "movs", sorb );
14144 break;
14145
sewardj8d4d2232005-01-20 10:47:46 +000014146 case 0xA6: /* CMPSb, no REP prefix */
sewardj33b53542005-03-11 14:00:27 +000014147 case 0xA7:
sewardj9c3b25a2007-04-05 15:06:56 +000014148 if (sorb != 0)
14149 goto decode_failure; /* else dis_string_op asserts */
14150 dis_string_op( dis_CMPS, ( opc == 0xA6 ? 1 : sz ), "cmps", sorb );
14151 break;
sewardj33b53542005-03-11 14:00:27 +000014152
sewardj883b00b2004-09-11 09:30:24 +000014153 case 0xAA: /* STOS, no REP prefix */
sewardj47341042004-09-19 11:55:46 +000014154 case 0xAB:
sewardj9c3b25a2007-04-05 15:06:56 +000014155 if (sorb != 0)
14156 goto decode_failure; /* else dis_string_op asserts */
sewardj883b00b2004-09-11 09:30:24 +000014157 dis_string_op( dis_STOS, ( opc == 0xAA ? 1 : sz ), "stos", sorb );
14158 break;
sewardj33b53542005-03-11 14:00:27 +000014159
sewardj10ca4eb2005-05-30 11:19:54 +000014160 case 0xAC: /* LODS, no REP prefix */
14161 case 0xAD:
sewardj9c3b25a2007-04-05 15:06:56 +000014162 if (sorb != 0)
14163 goto decode_failure; /* else dis_string_op asserts */
sewardj10ca4eb2005-05-30 11:19:54 +000014164 dis_string_op( dis_LODS, ( opc == 0xAC ? 1 : sz ), "lods", sorb );
14165 break;
sewardj2d4c3a02004-10-15 00:03:23 +000014166
14167 case 0xAE: /* SCAS, no REP prefix */
14168 case 0xAF:
sewardj9c3b25a2007-04-05 15:06:56 +000014169 if (sorb != 0)
14170 goto decode_failure; /* else dis_string_op asserts */
sewardj2d4c3a02004-10-15 00:03:23 +000014171 dis_string_op( dis_SCAS, ( opc == 0xAE ? 1 : sz ), "scas", sorb );
14172 break;
sewardj64e1d652004-07-12 14:00:46 +000014173
14174
14175 case 0xFC: /* CLD */
sewardjeeb9ef82004-07-15 12:39:03 +000014176 stmt( IRStmt_Put( OFFB_DFLAG, mkU32(1)) );
sewardj64e1d652004-07-12 14:00:46 +000014177 DIP("cld\n");
14178 break;
14179
sewardj1813dbe2004-07-28 17:09:04 +000014180 case 0xFD: /* STD */
14181 stmt( IRStmt_Put( OFFB_DFLAG, mkU32(0xFFFFFFFF)) );
14182 DIP("std\n");
14183 break;
14184
sewardjbc210942005-07-21 10:07:13 +000014185 case 0xF8: /* CLC */
14186 case 0xF9: /* STC */
14187 case 0xF5: /* CMC */
14188 t0 = newTemp(Ity_I32);
14189 t1 = newTemp(Ity_I32);
14190 assign( t0, mk_x86g_calculate_eflags_all() );
14191 switch (opc) {
14192 case 0xF8:
14193 assign( t1, binop(Iop_And32, mkexpr(t0),
14194 mkU32(~X86G_CC_MASK_C)));
14195 DIP("clc\n");
14196 break;
14197 case 0xF9:
14198 assign( t1, binop(Iop_Or32, mkexpr(t0),
14199 mkU32(X86G_CC_MASK_C)));
14200 DIP("stc\n");
14201 break;
14202 case 0xF5:
14203 assign( t1, binop(Iop_Xor32, mkexpr(t0),
14204 mkU32(X86G_CC_MASK_C)));
14205 DIP("cmc\n");
14206 break;
14207 default:
14208 vpanic("disInstr(x86)(clc/stc/cmc)");
14209 }
14210 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(X86G_CC_OP_COPY) ));
14211 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
14212 stmt( IRStmt_Put( OFFB_CC_DEP1, mkexpr(t1) ));
14213 /* Set NDEP even though it isn't used. This makes redundant-PUT
14214 elimination of previous stores to this field work better. */
14215 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
14216 break;
sewardj82292882004-07-27 00:15:59 +000014217
sewardja384eb92007-11-16 02:30:38 +000014218 case 0xD6: /* SALC */
14219 t0 = newTemp(Ity_I32);
14220 t1 = newTemp(Ity_I32);
14221 assign( t0, binop(Iop_And32,
14222 mk_x86g_calculate_eflags_c(),
14223 mkU32(1)) );
14224 assign( t1, binop(Iop_Sar32,
14225 binop(Iop_Shl32, mkexpr(t0), mkU8(31)),
14226 mkU8(31)) );
14227 putIReg(1, R_EAX, unop(Iop_32to8, mkexpr(t1)) );
14228 DIP("salc\n");
14229 break;
14230
sewardj82292882004-07-27 00:15:59 +000014231 /* REPNE prefix insn */
14232 case 0xF2: {
sewardj068baa22008-05-11 10:11:58 +000014233 Addr32 eip_orig = guest_EIP_bbstart + delta_start;
sewardj9c3b25a2007-04-05 15:06:56 +000014234 if (sorb != 0) goto decode_failure;
sewardj82292882004-07-27 00:15:59 +000014235 abyte = getIByte(delta); delta++;
14236
14237 if (abyte == 0x66) { sz = 2; abyte = getIByte(delta); delta++; }
sewardj82292882004-07-27 00:15:59 +000014238
14239 switch (abyte) {
14240 /* According to the Intel manual, "repne movs" should never occur, but
14241 * in practice it has happened, so allow for it here... */
sewardj180e8b32004-07-29 01:40:11 +000014242 case 0xA4: sz = 1; /* REPNE MOVS<sz> */
sewardjcea96622006-11-14 15:33:05 +000014243 case 0xA5:
sewardjc6f970f2012-04-02 21:54:49 +000014244 dis_REP_op ( &dres, X86CondNZ, dis_MOVS, sz, eip_orig,
14245 guest_EIP_bbstart+delta, "repne movs" );
sewardjcea96622006-11-14 15:33:05 +000014246 break;
sewardj842dfb42008-05-09 08:53:50 +000014247
14248 case 0xA6: sz = 1; /* REPNE CMP<sz> */
14249 case 0xA7:
sewardjc6f970f2012-04-02 21:54:49 +000014250 dis_REP_op ( &dres, X86CondNZ, dis_CMPS, sz, eip_orig,
14251 guest_EIP_bbstart+delta, "repne cmps" );
sewardj842dfb42008-05-09 08:53:50 +000014252 break;
14253
sewardjb69a6fa2006-11-14 15:13:55 +000014254 case 0xAA: sz = 1; /* REPNE STOS<sz> */
14255 case 0xAB:
sewardjc6f970f2012-04-02 21:54:49 +000014256 dis_REP_op ( &dres, X86CondNZ, dis_STOS, sz, eip_orig,
14257 guest_EIP_bbstart+delta, "repne stos" );
sewardjb69a6fa2006-11-14 15:13:55 +000014258 break;
14259
sewardj82292882004-07-27 00:15:59 +000014260 case 0xAE: sz = 1; /* REPNE SCAS<sz> */
sewardj2d4c3a02004-10-15 00:03:23 +000014261 case 0xAF:
sewardjc6f970f2012-04-02 21:54:49 +000014262 dis_REP_op ( &dres, X86CondNZ, dis_SCAS, sz, eip_orig,
14263 guest_EIP_bbstart+delta, "repne scas" );
sewardj82292882004-07-27 00:15:59 +000014264 break;
14265
14266 default:
14267 goto decode_failure;
14268 }
14269 break;
14270 }
sewardj64e1d652004-07-12 14:00:46 +000014271
14272 /* REP/REPE prefix insn (for SCAS and CMPS, 0xF3 means REPE,
14273 for the rest, it means REP) */
14274 case 0xF3: {
sewardj068baa22008-05-11 10:11:58 +000014275 Addr32 eip_orig = guest_EIP_bbstart + delta_start;
sewardj64e1d652004-07-12 14:00:46 +000014276 abyte = getIByte(delta); delta++;
14277
14278 if (abyte == 0x66) { sz = 2; abyte = getIByte(delta); delta++; }
sewardj64e1d652004-07-12 14:00:46 +000014279
sewardjc8851af2012-08-23 20:14:51 +000014280 if (sorb != 0 && abyte != 0x0F) goto decode_failure;
14281
sewardj64e1d652004-07-12 14:00:46 +000014282 switch (abyte) {
sewardjc8851af2012-08-23 20:14:51 +000014283 case 0x0F:
14284 switch (getIByte(delta)) {
14285 /* On older CPUs, TZCNT behaves the same as BSF. */
14286 case 0xBC: /* REP BSF Gv,Ev */
14287 delta = dis_bs_E_G ( sorb, sz, delta + 1, True );
14288 break;
14289 /* On older CPUs, LZCNT behaves the same as BSR. */
14290 case 0xBD: /* REP BSR Gv,Ev */
14291 delta = dis_bs_E_G ( sorb, sz, delta + 1, False );
14292 break;
14293 default:
14294 goto decode_failure;
14295 }
14296 break;
14297
sewardj64e1d652004-07-12 14:00:46 +000014298 case 0xA4: sz = 1; /* REP MOVS<sz> */
14299 case 0xA5:
sewardjc6f970f2012-04-02 21:54:49 +000014300 dis_REP_op ( &dres, X86CondAlways, dis_MOVS, sz, eip_orig,
14301 guest_EIP_bbstart+delta, "rep movs" );
sewardj64e1d652004-07-12 14:00:46 +000014302 break;
14303
14304 case 0xA6: sz = 1; /* REPE CMP<sz> */
sewardj2d4c3a02004-10-15 00:03:23 +000014305 case 0xA7:
sewardjc6f970f2012-04-02 21:54:49 +000014306 dis_REP_op ( &dres, X86CondZ, dis_CMPS, sz, eip_orig,
14307 guest_EIP_bbstart+delta, "repe cmps" );
sewardj64e1d652004-07-12 14:00:46 +000014308 break;
14309
14310 case 0xAA: sz = 1; /* REP STOS<sz> */
14311 case 0xAB:
sewardjc6f970f2012-04-02 21:54:49 +000014312 dis_REP_op ( &dres, X86CondAlways, dis_STOS, sz, eip_orig,
14313 guest_EIP_bbstart+delta, "rep stos" );
sewardj64e1d652004-07-12 14:00:46 +000014314 break;
sewardj576f3232006-04-12 17:30:46 +000014315
sewardjdfb038d2007-11-25 01:34:03 +000014316 case 0xAC: sz = 1; /* REP LODS<sz> */
14317 case 0xAD:
sewardjc6f970f2012-04-02 21:54:49 +000014318 dis_REP_op ( &dres, X86CondAlways, dis_LODS, sz, eip_orig,
14319 guest_EIP_bbstart+delta, "rep lods" );
sewardjdfb038d2007-11-25 01:34:03 +000014320 break;
14321
sewardj576f3232006-04-12 17:30:46 +000014322 case 0xAE: sz = 1; /* REPE SCAS<sz> */
14323 case 0xAF:
sewardjc6f970f2012-04-02 21:54:49 +000014324 dis_REP_op ( &dres, X86CondZ, dis_SCAS, sz, eip_orig,
14325 guest_EIP_bbstart+delta, "repe scas" );
sewardj576f3232006-04-12 17:30:46 +000014326 break;
sewardj43b8df12004-11-26 12:18:51 +000014327
14328 case 0x90: /* REP NOP (PAUSE) */
14329 /* a hint to the P4 re spin-wait loop */
14330 DIP("rep nop (P4 pause)\n");
sewardj7ec59f62005-03-12 16:47:18 +000014331 /* "observe" the hint. The Vex client needs to be careful not
14332 to cause very long delays as a result, though. */
sewardjc6f970f2012-04-02 21:54:49 +000014333 jmp_lit(&dres, Ijk_Yield, ((Addr32)guest_EIP_bbstart)+delta);
14334 vassert(dres.whatNext == Dis_StopHere);
sewardj43b8df12004-11-26 12:18:51 +000014335 break;
14336
sewardj7d3d3472005-08-12 23:51:31 +000014337 case 0xC3: /* REP RET -- same as normal ret? */
sewardjc6f970f2012-04-02 21:54:49 +000014338 dis_ret(&dres, 0);
sewardj7d3d3472005-08-12 23:51:31 +000014339 DIP("rep ret\n");
14340 break;
sewardj64e1d652004-07-12 14:00:46 +000014341
14342 default:
14343 goto decode_failure;
14344 }
14345 break;
14346 }
sewardj0611d802004-07-11 02:37:54 +000014347
14348 /* ------------------------ XCHG ----------------------- */
14349
sewardjc4356f02007-11-09 21:15:04 +000014350 /* XCHG reg,mem automatically asserts LOCK# even without a LOCK
sewardj1fb8c922009-07-12 12:56:53 +000014351 prefix; hence it must be translated with an IRCAS (at least, the
14352 memory variant). */
sewardj0611d802004-07-11 02:37:54 +000014353 case 0x86: /* XCHG Gb,Eb */
14354 sz = 1;
14355 /* Fall through ... */
14356 case 0x87: /* XCHG Gv,Ev */
14357 modrm = getIByte(delta);
14358 ty = szToITy(sz);
14359 t1 = newTemp(ty); t2 = newTemp(ty);
14360 if (epartIsReg(modrm)) {
sewardj5bd4d162004-11-10 13:02:48 +000014361 assign(t1, getIReg(sz, eregOfRM(modrm)));
14362 assign(t2, getIReg(sz, gregOfRM(modrm)));
14363 putIReg(sz, gregOfRM(modrm), mkexpr(t1));
14364 putIReg(sz, eregOfRM(modrm), mkexpr(t2));
sewardj0611d802004-07-11 02:37:54 +000014365 delta++;
14366 DIP("xchg%c %s, %s\n",
14367 nameISize(sz), nameIReg(sz,gregOfRM(modrm)),
14368 nameIReg(sz,eregOfRM(modrm)));
14369 } else {
sewardje9d8a262009-07-01 08:06:34 +000014370 *expect_CAS = True;
sewardj0c12ea82004-07-12 08:18:16 +000014371 addr = disAMode ( &alen, sorb, delta, dis_buf );
sewardj5bd4d162004-11-10 13:02:48 +000014372 assign( t1, loadLE(ty,mkexpr(addr)) );
14373 assign( t2, getIReg(sz,gregOfRM(modrm)) );
sewardje9d8a262009-07-01 08:06:34 +000014374 casLE( mkexpr(addr),
14375 mkexpr(t1), mkexpr(t2), guest_EIP_curr_instr );
sewardj5bd4d162004-11-10 13:02:48 +000014376 putIReg( sz, gregOfRM(modrm), mkexpr(t1) );
14377 delta += alen;
sewardj0611d802004-07-11 02:37:54 +000014378 DIP("xchg%c %s, %s\n", nameISize(sz),
14379 nameIReg(sz,gregOfRM(modrm)), dis_buf);
sewardj0611d802004-07-11 02:37:54 +000014380 }
14381 break;
sewardje87b4842004-07-10 12:23:30 +000014382
14383 case 0x90: /* XCHG eAX,eAX */
14384 DIP("nop\n");
14385 break;
sewardj64e1d652004-07-12 14:00:46 +000014386 case 0x91: /* XCHG eAX,eCX */
14387 case 0x92: /* XCHG eAX,eDX */
14388 case 0x93: /* XCHG eAX,eBX */
14389 case 0x94: /* XCHG eAX,eSP */
14390 case 0x95: /* XCHG eAX,eBP */
14391 case 0x96: /* XCHG eAX,eSI */
14392 case 0x97: /* XCHG eAX,eDI */
14393 codegen_xchg_eAX_Reg ( sz, opc - 0x90 );
14394 break;
14395
sewardj048de4d2006-11-12 22:25:21 +000014396 /* ------------------------ XLAT ----------------------- */
14397
14398 case 0xD7: /* XLAT */
14399 if (sz != 4) goto decode_failure; /* sz == 2 is also allowed (0x66) */
14400 putIReg(
14401 1,
14402 R_EAX/*AL*/,
14403 loadLE(Ity_I8,
14404 handleSegOverride(
14405 sorb,
14406 binop(Iop_Add32,
14407 getIReg(4, R_EBX),
14408 unop(Iop_8Uto32, getIReg(1, R_EAX/*AL*/))))));
14409
14410 DIP("xlat%c [ebx]\n", nameISize(sz));
14411 break;
sewardjd14c5702005-10-29 19:19:51 +000014412
14413 /* ------------------------ IN / OUT ----------------------- */
14414
14415 case 0xE4: /* IN imm8, AL */
14416 sz = 1;
14417 t1 = newTemp(Ity_I32);
14418 abyte = getIByte(delta); delta++;
14419 assign(t1, mkU32( abyte & 0xFF ));
florianb1737742015-08-03 16:03:13 +000014420 DIP("in%c $%d,%s\n", nameISize(sz), abyte, nameIReg(sz,R_EAX));
sewardjd14c5702005-10-29 19:19:51 +000014421 goto do_IN;
14422 case 0xE5: /* IN imm8, eAX */
14423 vassert(sz == 2 || sz == 4);
14424 t1 = newTemp(Ity_I32);
14425 abyte = getIByte(delta); delta++;
14426 assign(t1, mkU32( abyte & 0xFF ));
florianb1737742015-08-03 16:03:13 +000014427 DIP("in%c $%d,%s\n", nameISize(sz), abyte, nameIReg(sz,R_EAX));
sewardjd14c5702005-10-29 19:19:51 +000014428 goto do_IN;
14429 case 0xEC: /* IN %DX, AL */
14430 sz = 1;
14431 t1 = newTemp(Ity_I32);
14432 assign(t1, unop(Iop_16Uto32, getIReg(2, R_EDX)));
14433 DIP("in%c %s,%s\n", nameISize(sz), nameIReg(2,R_EDX),
14434 nameIReg(sz,R_EAX));
14435 goto do_IN;
14436 case 0xED: /* IN %DX, eAX */
14437 vassert(sz == 2 || sz == 4);
14438 t1 = newTemp(Ity_I32);
14439 assign(t1, unop(Iop_16Uto32, getIReg(2, R_EDX)));
14440 DIP("in%c %s,%s\n", nameISize(sz), nameIReg(2,R_EDX),
14441 nameIReg(sz,R_EAX));
14442 goto do_IN;
14443 do_IN: {
14444 /* At this point, sz indicates the width, and t1 is a 32-bit
14445 value giving port number. */
14446 IRDirty* d;
14447 vassert(sz == 1 || sz == 2 || sz == 4);
14448 ty = szToITy(sz);
14449 t2 = newTemp(Ity_I32);
14450 d = unsafeIRDirty_1_N(
14451 t2,
14452 0/*regparms*/,
14453 "x86g_dirtyhelper_IN",
14454 &x86g_dirtyhelper_IN,
14455 mkIRExprVec_2( mkexpr(t1), mkU32(sz) )
14456 );
14457 /* do the call, dumping the result in t2. */
14458 stmt( IRStmt_Dirty(d) );
14459 putIReg(sz, R_EAX, narrowTo( ty, mkexpr(t2) ) );
14460 break;
14461 }
14462
14463 case 0xE6: /* OUT AL, imm8 */
14464 sz = 1;
14465 t1 = newTemp(Ity_I32);
14466 abyte = getIByte(delta); delta++;
14467 assign( t1, mkU32( abyte & 0xFF ) );
florianb1737742015-08-03 16:03:13 +000014468 DIP("out%c %s,$%d\n", nameISize(sz), nameIReg(sz,R_EAX), abyte);
sewardjd14c5702005-10-29 19:19:51 +000014469 goto do_OUT;
14470 case 0xE7: /* OUT eAX, imm8 */
14471 vassert(sz == 2 || sz == 4);
14472 t1 = newTemp(Ity_I32);
14473 abyte = getIByte(delta); delta++;
14474 assign( t1, mkU32( abyte & 0xFF ) );
florianb1737742015-08-03 16:03:13 +000014475 DIP("out%c %s,$%d\n", nameISize(sz), nameIReg(sz,R_EAX), abyte);
sewardjd14c5702005-10-29 19:19:51 +000014476 goto do_OUT;
14477 case 0xEE: /* OUT AL, %DX */
14478 sz = 1;
14479 t1 = newTemp(Ity_I32);
14480 assign( t1, unop(Iop_16Uto32, getIReg(2, R_EDX)) );
14481 DIP("out%c %s,%s\n", nameISize(sz), nameIReg(sz,R_EAX),
14482 nameIReg(2,R_EDX));
14483 goto do_OUT;
14484 case 0xEF: /* OUT eAX, %DX */
14485 vassert(sz == 2 || sz == 4);
14486 t1 = newTemp(Ity_I32);
14487 assign( t1, unop(Iop_16Uto32, getIReg(2, R_EDX)) );
14488 DIP("out%c %s,%s\n", nameISize(sz), nameIReg(sz,R_EAX),
14489 nameIReg(2,R_EDX));
14490 goto do_OUT;
14491 do_OUT: {
14492 /* At this point, sz indicates the width, and t1 is a 32-bit
14493 value giving port number. */
14494 IRDirty* d;
14495 vassert(sz == 1 || sz == 2 || sz == 4);
14496 ty = szToITy(sz);
14497 d = unsafeIRDirty_0_N(
14498 0/*regparms*/,
14499 "x86g_dirtyhelper_OUT",
14500 &x86g_dirtyhelper_OUT,
14501 mkIRExprVec_3( mkexpr(t1),
14502 widenUto32( getIReg(sz, R_EAX) ),
14503 mkU32(sz) )
14504 );
14505 stmt( IRStmt_Dirty(d) );
14506 break;
14507 }
sewardj0611d802004-07-11 02:37:54 +000014508
14509 /* ------------------------ (Grp1 extensions) ---------- */
14510
sewardj792d7712008-10-31 21:27:38 +000014511 case 0x82: /* Grp1 Ib,Eb too. Apparently this is the same as
14512 case 0x80, but only in 32-bit mode. */
14513 /* fallthru */
sewardj0611d802004-07-11 02:37:54 +000014514 case 0x80: /* Grp1 Ib,Eb */
14515 modrm = getIByte(delta);
14516 am_sz = lengthAMode(delta);
14517 sz = 1;
14518 d_sz = 1;
sewardjc2ac51e2004-07-12 01:03:26 +000014519 d32 = getUChar(delta + am_sz);
sewardje9d8a262009-07-01 08:06:34 +000014520 delta = dis_Grp1 ( sorb, pfx_lock, delta, modrm, am_sz, d_sz, sz, d32 );
sewardj0611d802004-07-11 02:37:54 +000014521 break;
sewardje05c42c2004-07-08 20:25:10 +000014522
14523 case 0x81: /* Grp1 Iv,Ev */
14524 modrm = getIByte(delta);
14525 am_sz = lengthAMode(delta);
14526 d_sz = sz;
14527 d32 = getUDisp(d_sz, delta + am_sz);
sewardje9d8a262009-07-01 08:06:34 +000014528 delta = dis_Grp1 ( sorb, pfx_lock, delta, modrm, am_sz, d_sz, sz, d32 );
sewardje05c42c2004-07-08 20:25:10 +000014529 break;
sewardjd1061ab2004-07-08 01:45:30 +000014530
14531 case 0x83: /* Grp1 Ib,Ev */
14532 modrm = getIByte(delta);
14533 am_sz = lengthAMode(delta);
14534 d_sz = 1;
14535 d32 = getSDisp8(delta + am_sz);
sewardje9d8a262009-07-01 08:06:34 +000014536 delta = dis_Grp1 ( sorb, pfx_lock, delta, modrm, am_sz, d_sz, sz, d32 );
sewardjd1061ab2004-07-08 01:45:30 +000014537 break;
14538
sewardjc2ac51e2004-07-12 01:03:26 +000014539 /* ------------------------ (Grp2 extensions) ---------- */
14540
sewardjd51dc812007-03-20 14:18:45 +000014541 case 0xC0: { /* Grp2 Ib,Eb */
14542 Bool decode_OK = True;
sewardjc2ac51e2004-07-12 01:03:26 +000014543 modrm = getIByte(delta);
14544 am_sz = lengthAMode(delta);
14545 d_sz = 1;
sewardj180e8b32004-07-29 01:40:11 +000014546 d32 = getUChar(delta + am_sz);
sewardjc2ac51e2004-07-12 01:03:26 +000014547 sz = 1;
sewardj6d2638e2004-07-15 09:38:27 +000014548 delta = dis_Grp2 ( sorb, delta, modrm, am_sz, d_sz, sz,
sewardjd51dc812007-03-20 14:18:45 +000014549 mkU8(d32 & 0xFF), NULL, &decode_OK );
14550 if (!decode_OK)
14551 goto decode_failure;
sewardjc2ac51e2004-07-12 01:03:26 +000014552 break;
sewardjd51dc812007-03-20 14:18:45 +000014553 }
14554 case 0xC1: { /* Grp2 Ib,Ev */
14555 Bool decode_OK = True;
sewardjc2ac51e2004-07-12 01:03:26 +000014556 modrm = getIByte(delta);
sewardje90ad6a2004-07-10 19:02:10 +000014557 am_sz = lengthAMode(delta);
14558 d_sz = 1;
sewardj180e8b32004-07-29 01:40:11 +000014559 d32 = getUChar(delta + am_sz);
sewardj6d2638e2004-07-15 09:38:27 +000014560 delta = dis_Grp2 ( sorb, delta, modrm, am_sz, d_sz, sz,
sewardjd51dc812007-03-20 14:18:45 +000014561 mkU8(d32 & 0xFF), NULL, &decode_OK );
14562 if (!decode_OK)
14563 goto decode_failure;
sewardje90ad6a2004-07-10 19:02:10 +000014564 break;
sewardjd51dc812007-03-20 14:18:45 +000014565 }
14566 case 0xD0: { /* Grp2 1,Eb */
14567 Bool decode_OK = True;
sewardj180e8b32004-07-29 01:40:11 +000014568 modrm = getIByte(delta);
14569 am_sz = lengthAMode(delta);
14570 d_sz = 0;
14571 d32 = 1;
14572 sz = 1;
14573 delta = dis_Grp2 ( sorb, delta, modrm, am_sz, d_sz, sz,
sewardjd51dc812007-03-20 14:18:45 +000014574 mkU8(d32), NULL, &decode_OK );
14575 if (!decode_OK)
14576 goto decode_failure;
sewardj180e8b32004-07-29 01:40:11 +000014577 break;
sewardjd51dc812007-03-20 14:18:45 +000014578 }
14579 case 0xD1: { /* Grp2 1,Ev */
14580 Bool decode_OK = True;
sewardjc2ac51e2004-07-12 01:03:26 +000014581 modrm = getUChar(delta);
14582 am_sz = lengthAMode(delta);
14583 d_sz = 0;
14584 d32 = 1;
sewardj6d2638e2004-07-15 09:38:27 +000014585 delta = dis_Grp2 ( sorb, delta, modrm, am_sz, d_sz, sz,
sewardjd51dc812007-03-20 14:18:45 +000014586 mkU8(d32), NULL, &decode_OK );
14587 if (!decode_OK)
14588 goto decode_failure;
sewardjc2ac51e2004-07-12 01:03:26 +000014589 break;
sewardjd51dc812007-03-20 14:18:45 +000014590 }
14591 case 0xD2: { /* Grp2 CL,Eb */
14592 Bool decode_OK = True;
sewardj8c7f1ab2004-07-29 20:31:09 +000014593 modrm = getUChar(delta);
14594 am_sz = lengthAMode(delta);
14595 d_sz = 0;
14596 sz = 1;
14597 delta = dis_Grp2 ( sorb, delta, modrm, am_sz, d_sz, sz,
sewardjd51dc812007-03-20 14:18:45 +000014598 getIReg(1,R_ECX), "%cl", &decode_OK );
14599 if (!decode_OK)
14600 goto decode_failure;
sewardj8c7f1ab2004-07-29 20:31:09 +000014601 break;
sewardjd51dc812007-03-20 14:18:45 +000014602 }
14603 case 0xD3: { /* Grp2 CL,Ev */
14604 Bool decode_OK = True;
sewardj9334b0f2004-07-10 22:43:54 +000014605 modrm = getIByte(delta);
14606 am_sz = lengthAMode(delta);
14607 d_sz = 0;
14608 delta = dis_Grp2 ( sorb, delta, modrm, am_sz, d_sz, sz,
sewardjd51dc812007-03-20 14:18:45 +000014609 getIReg(1,R_ECX), "%cl", &decode_OK );
14610 if (!decode_OK)
14611 goto decode_failure;
sewardj9334b0f2004-07-10 22:43:54 +000014612 break;
sewardjd51dc812007-03-20 14:18:45 +000014613 }
sewardj9334b0f2004-07-10 22:43:54 +000014614
sewardj940e8c92004-07-11 16:53:24 +000014615 /* ------------------------ (Grp3 extensions) ---------- */
14616
sewardjd51dc812007-03-20 14:18:45 +000014617 case 0xF6: { /* Grp3 Eb */
14618 Bool decode_OK = True;
sewardje9d8a262009-07-01 08:06:34 +000014619 delta = dis_Grp3 ( sorb, pfx_lock, 1, delta, &decode_OK );
sewardjd51dc812007-03-20 14:18:45 +000014620 if (!decode_OK)
14621 goto decode_failure;
sewardj940e8c92004-07-11 16:53:24 +000014622 break;
sewardjd51dc812007-03-20 14:18:45 +000014623 }
14624 case 0xF7: { /* Grp3 Ev */
14625 Bool decode_OK = True;
sewardje9d8a262009-07-01 08:06:34 +000014626 delta = dis_Grp3 ( sorb, pfx_lock, sz, delta, &decode_OK );
sewardjd51dc812007-03-20 14:18:45 +000014627 if (!decode_OK)
14628 goto decode_failure;
sewardj940e8c92004-07-11 16:53:24 +000014629 break;
sewardjd51dc812007-03-20 14:18:45 +000014630 }
sewardj940e8c92004-07-11 16:53:24 +000014631
sewardjc2ac51e2004-07-12 01:03:26 +000014632 /* ------------------------ (Grp4 extensions) ---------- */
14633
sewardjd51dc812007-03-20 14:18:45 +000014634 case 0xFE: { /* Grp4 Eb */
14635 Bool decode_OK = True;
sewardje9d8a262009-07-01 08:06:34 +000014636 delta = dis_Grp4 ( sorb, pfx_lock, delta, &decode_OK );
sewardjd51dc812007-03-20 14:18:45 +000014637 if (!decode_OK)
14638 goto decode_failure;
sewardjc2ac51e2004-07-12 01:03:26 +000014639 break;
sewardjd51dc812007-03-20 14:18:45 +000014640 }
sewardj0611d802004-07-11 02:37:54 +000014641
14642 /* ------------------------ (Grp5 extensions) ---------- */
14643
sewardjd51dc812007-03-20 14:18:45 +000014644 case 0xFF: { /* Grp5 Ev */
14645 Bool decode_OK = True;
sewardje9d8a262009-07-01 08:06:34 +000014646 delta = dis_Grp5 ( sorb, pfx_lock, sz, delta, &dres, &decode_OK );
sewardjd51dc812007-03-20 14:18:45 +000014647 if (!decode_OK)
14648 goto decode_failure;
sewardj0611d802004-07-11 02:37:54 +000014649 break;
sewardjd51dc812007-03-20 14:18:45 +000014650 }
sewardje87b4842004-07-10 12:23:30 +000014651
14652 /* ------------------------ Escapes to 2-byte opcodes -- */
14653
14654 case 0x0F: {
14655 opc = getIByte(delta); delta++;
14656 switch (opc) {
14657
sewardj490ad382005-03-13 17:25:53 +000014658 /* =-=-=-=-=-=-=-=-=- Grp8 =-=-=-=-=-=-=-=-=-=-=-= */
14659
14660 case 0xBA: { /* Grp8 Ib,Ev */
14661 Bool decode_OK = False;
14662 modrm = getUChar(delta);
14663 am_sz = lengthAMode(delta);
14664 d32 = getSDisp8(delta + am_sz);
sewardje9d8a262009-07-01 08:06:34 +000014665 delta = dis_Grp8_Imm ( sorb, pfx_lock, delta, modrm,
14666 am_sz, sz, d32, &decode_OK );
sewardj490ad382005-03-13 17:25:53 +000014667 if (!decode_OK)
14668 goto decode_failure;
14669 break;
14670 }
sewardjce646f22004-08-31 23:55:54 +000014671
14672 /* =-=-=-=-=-=-=-=-=- BSF/BSR -=-=-=-=-=-=-=-=-=-= */
14673
14674 case 0xBC: /* BSF Gv,Ev */
14675 delta = dis_bs_E_G ( sorb, sz, delta, True );
14676 break;
14677 case 0xBD: /* BSR Gv,Ev */
14678 delta = dis_bs_E_G ( sorb, sz, delta, False );
14679 break;
sewardj1c4208f2004-08-25 13:25:29 +000014680
14681 /* =-=-=-=-=-=-=-=-=- BSWAP -=-=-=-=-=-=-=-=-=-=-= */
14682
14683 case 0xC8: /* BSWAP %eax */
14684 case 0xC9:
14685 case 0xCA:
sewardjb4666cf2004-10-23 00:21:50 +000014686 case 0xCB:
14687 case 0xCC:
14688 case 0xCD:
sewardj1c4208f2004-08-25 13:25:29 +000014689 case 0xCE:
sewardj1c6f9912004-09-07 10:15:24 +000014690 case 0xCF: /* BSWAP %edi */
sewardj1c4208f2004-08-25 13:25:29 +000014691 /* AFAICS from the Intel docs, this only exists at size 4. */
sewardj021f6b42012-08-23 23:39:49 +000014692 if (sz != 4) goto decode_failure;
14693
sewardj1c4208f2004-08-25 13:25:29 +000014694 t1 = newTemp(Ity_I32);
sewardj1c4208f2004-08-25 13:25:29 +000014695 assign( t1, getIReg(4, opc-0xC8) );
sewardj021f6b42012-08-23 23:39:49 +000014696 t2 = math_BSWAP(t1, Ity_I32);
sewardj1c4208f2004-08-25 13:25:29 +000014697
14698 putIReg(4, opc-0xC8, mkexpr(t2));
sewardj1c4208f2004-08-25 13:25:29 +000014699 DIP("bswapl %s\n", nameIReg(4, opc-0xC8));
14700 break;
14701
sewardj1c6f9912004-09-07 10:15:24 +000014702 /* =-=-=-=-=-=-=-=-=- BT/BTS/BTR/BTC =-=-=-=-=-=-= */
14703
14704 case 0xA3: /* BT Gv,Ev */
sewardj02834302010-07-29 18:10:51 +000014705 delta = dis_bt_G_E ( vbi, sorb, pfx_lock, sz, delta, BtOpNone );
sewardj1c6f9912004-09-07 10:15:24 +000014706 break;
sewardje6709112004-09-10 18:37:18 +000014707 case 0xB3: /* BTR Gv,Ev */
sewardj02834302010-07-29 18:10:51 +000014708 delta = dis_bt_G_E ( vbi, sorb, pfx_lock, sz, delta, BtOpReset );
sewardje6709112004-09-10 18:37:18 +000014709 break;
sewardj1c6f9912004-09-07 10:15:24 +000014710 case 0xAB: /* BTS Gv,Ev */
sewardj02834302010-07-29 18:10:51 +000014711 delta = dis_bt_G_E ( vbi, sorb, pfx_lock, sz, delta, BtOpSet );
sewardj1c6f9912004-09-07 10:15:24 +000014712 break;
sewardj4963a422004-10-14 23:34:03 +000014713 case 0xBB: /* BTC Gv,Ev */
sewardj02834302010-07-29 18:10:51 +000014714 delta = dis_bt_G_E ( vbi, sorb, pfx_lock, sz, delta, BtOpComp );
sewardj4963a422004-10-14 23:34:03 +000014715 break;
sewardj458a6f82004-08-25 12:46:02 +000014716
14717 /* =-=-=-=-=-=-=-=-=- CMOV =-=-=-=-=-=-=-=-=-=-=-= */
14718
sewardj2d4c3a02004-10-15 00:03:23 +000014719 case 0x40:
14720 case 0x41:
sewardj458a6f82004-08-25 12:46:02 +000014721 case 0x42: /* CMOVBb/CMOVNAEb (cmov below) */
14722 case 0x43: /* CMOVNBb/CMOVAEb (cmov not below) */
14723 case 0x44: /* CMOVZb/CMOVEb (cmov zero) */
14724 case 0x45: /* CMOVNZb/CMOVNEb (cmov not zero) */
14725 case 0x46: /* CMOVBEb/CMOVNAb (cmov below or equal) */
14726 case 0x47: /* CMOVNBEb/CMOVAb (cmov not below or equal) */
sewardjce646f22004-08-31 23:55:54 +000014727 case 0x48: /* CMOVSb (cmov negative) */
sewardj458a6f82004-08-25 12:46:02 +000014728 case 0x49: /* CMOVSb (cmov not negative) */
sewardj2d4c3a02004-10-15 00:03:23 +000014729 case 0x4A: /* CMOVP (cmov parity even) */
14730 case 0x4B: /* CMOVNP (cmov parity odd) */
sewardj458a6f82004-08-25 12:46:02 +000014731 case 0x4C: /* CMOVLb/CMOVNGEb (cmov less) */
14732 case 0x4D: /* CMOVGEb/CMOVNLb (cmov greater or equal) */
14733 case 0x4E: /* CMOVLEb/CMOVNGb (cmov less or equal) */
14734 case 0x4F: /* CMOVGb/CMOVNLEb (cmov greater) */
sewardj2a9ad022004-11-25 02:46:58 +000014735 delta = dis_cmov_E_G(sorb, sz, (X86Condcode)(opc - 0x40), delta);
sewardj458a6f82004-08-25 12:46:02 +000014736 break;
14737
14738 /* =-=-=-=-=-=-=-=-=- CMPXCHG -=-=-=-=-=-=-=-=-=-= */
14739
sewardjc744e872004-08-26 11:24:39 +000014740 case 0xB0: /* CMPXCHG Gb,Eb */
sewardje9d8a262009-07-01 08:06:34 +000014741 delta = dis_cmpxchg_G_E ( sorb, pfx_lock, 1, delta );
sewardjc744e872004-08-26 11:24:39 +000014742 break;
sewardj458a6f82004-08-25 12:46:02 +000014743 case 0xB1: /* CMPXCHG Gv,Ev */
sewardje9d8a262009-07-01 08:06:34 +000014744 delta = dis_cmpxchg_G_E ( sorb, pfx_lock, sz, delta );
sewardj458a6f82004-08-25 12:46:02 +000014745 break;
sewardj300bb872005-08-12 23:04:48 +000014746
14747 case 0xC7: { /* CMPXCHG8B Gv (0F C7 /1) */
sewardje9d8a262009-07-01 08:06:34 +000014748 IRTemp expdHi = newTemp(Ity_I32);
14749 IRTemp expdLo = newTemp(Ity_I32);
14750 IRTemp dataHi = newTemp(Ity_I32);
14751 IRTemp dataLo = newTemp(Ity_I32);
14752 IRTemp oldHi = newTemp(Ity_I32);
14753 IRTemp oldLo = newTemp(Ity_I32);
sewardj300bb872005-08-12 23:04:48 +000014754 IRTemp flags_old = newTemp(Ity_I32);
14755 IRTemp flags_new = newTemp(Ity_I32);
sewardje9d8a262009-07-01 08:06:34 +000014756 IRTemp success = newTemp(Ity_I1);
14757
14758 /* Translate this using a DCAS, even if there is no LOCK
14759 prefix. Life is too short to bother with generating two
14760 different translations for the with/without-LOCK-prefix
14761 cases. */
14762 *expect_CAS = True;
sewardj300bb872005-08-12 23:04:48 +000014763
14764 /* Decode, and generate address. */
sewardje9d8a262009-07-01 08:06:34 +000014765 if (sz != 4) goto decode_failure;
sewardj300bb872005-08-12 23:04:48 +000014766 modrm = getIByte(delta);
14767 if (epartIsReg(modrm)) goto decode_failure;
14768 if (gregOfRM(modrm) != 1) goto decode_failure;
14769 addr = disAMode ( &alen, sorb, delta, dis_buf );
14770 delta += alen;
14771
sewardje9d8a262009-07-01 08:06:34 +000014772 /* Get the expected and new values. */
14773 assign( expdHi, getIReg(4,R_EDX) );
14774 assign( expdLo, getIReg(4,R_EAX) );
14775 assign( dataHi, getIReg(4,R_ECX) );
14776 assign( dataLo, getIReg(4,R_EBX) );
sewardj300bb872005-08-12 23:04:48 +000014777
sewardje9d8a262009-07-01 08:06:34 +000014778 /* Do the DCAS */
14779 stmt( IRStmt_CAS(
14780 mkIRCAS( oldHi, oldLo,
14781 Iend_LE, mkexpr(addr),
14782 mkexpr(expdHi), mkexpr(expdLo),
14783 mkexpr(dataHi), mkexpr(dataLo)
14784 )));
sewardj300bb872005-08-12 23:04:48 +000014785
sewardje9d8a262009-07-01 08:06:34 +000014786 /* success when oldHi:oldLo == expdHi:expdLo */
14787 assign( success,
sewardj1fb8c922009-07-12 12:56:53 +000014788 binop(Iop_CasCmpEQ32,
sewardje9d8a262009-07-01 08:06:34 +000014789 binop(Iop_Or32,
14790 binop(Iop_Xor32, mkexpr(oldHi), mkexpr(expdHi)),
14791 binop(Iop_Xor32, mkexpr(oldLo), mkexpr(expdLo))
14792 ),
14793 mkU32(0)
14794 ));
sewardj300bb872005-08-12 23:04:48 +000014795
sewardje9d8a262009-07-01 08:06:34 +000014796 /* If the DCAS is successful, that is to say oldHi:oldLo ==
14797 expdHi:expdLo, then put expdHi:expdLo back in EDX:EAX,
14798 which is where they came from originally. Both the actual
14799 contents of these two regs, and any shadow values, are
14800 unchanged. If the DCAS fails then we're putting into
14801 EDX:EAX the value seen in memory. */
14802 putIReg(4, R_EDX,
florian99dd03e2013-01-29 03:56:06 +000014803 IRExpr_ITE( mkexpr(success),
14804 mkexpr(expdHi), mkexpr(oldHi)
sewardje9d8a262009-07-01 08:06:34 +000014805 ));
14806 putIReg(4, R_EAX,
florian99dd03e2013-01-29 03:56:06 +000014807 IRExpr_ITE( mkexpr(success),
14808 mkexpr(expdLo), mkexpr(oldLo)
sewardje9d8a262009-07-01 08:06:34 +000014809 ));
sewardj300bb872005-08-12 23:04:48 +000014810
sewardje9d8a262009-07-01 08:06:34 +000014811 /* Copy the success bit into the Z flag and leave the others
14812 unchanged */
sewardj300bb872005-08-12 23:04:48 +000014813 assign( flags_old, widenUto32(mk_x86g_calculate_eflags_all()));
14814 assign(
14815 flags_new,
14816 binop(Iop_Or32,
14817 binop(Iop_And32, mkexpr(flags_old),
14818 mkU32(~X86G_CC_MASK_Z)),
14819 binop(Iop_Shl32,
14820 binop(Iop_And32,
sewardje9d8a262009-07-01 08:06:34 +000014821 unop(Iop_1Uto32, mkexpr(success)), mkU32(1)),
sewardj300bb872005-08-12 23:04:48 +000014822 mkU8(X86G_CC_SHIFT_Z)) ));
14823
14824 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(X86G_CC_OP_COPY) ));
14825 stmt( IRStmt_Put( OFFB_CC_DEP1, mkexpr(flags_new) ));
14826 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
14827 /* Set NDEP even though it isn't used. This makes
14828 redundant-PUT elimination of previous stores to this field
14829 work better. */
14830 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
14831
14832 /* Sheesh. Aren't you glad it was me and not you that had to
14833 write and validate all this grunge? */
14834
14835 DIP("cmpxchg8b %s\n", dis_buf);
14836 break;
14837 }
14838
sewardj588ea762004-09-10 18:56:32 +000014839 /* =-=-=-=-=-=-=-=-=- CPUID -=-=-=-=-=-=-=-=-=-=-= */
14840
sewardj7cb49d72004-10-24 22:31:25 +000014841 case 0xA2: { /* CPUID */
14842 /* Uses dirty helper:
sewardj9df271d2004-12-31 22:37:42 +000014843 void dirtyhelper_CPUID_sse[012] ( VexGuestX86State* )
sewardj7cb49d72004-10-24 22:31:25 +000014844 declared to mod eax, wr ebx, ecx, edx
14845 */
sewardj9df271d2004-12-31 22:37:42 +000014846 IRDirty* d = NULL;
sewardj9df271d2004-12-31 22:37:42 +000014847 void* fAddr = NULL;
florian55085f82012-11-21 00:36:55 +000014848 const HChar* fName = NULL;
philippe6d7c8e42015-06-17 21:33:19 +000014849 if (archinfo->hwcaps & VEX_HWCAPS_X86_SSE3) {
14850 fName = "x86g_dirtyhelper_CPUID_sse3";
14851 fAddr = &x86g_dirtyhelper_CPUID_sse3;
sewardj5117ce12006-01-27 21:20:15 +000014852 }
14853 else
philippe7ffce012015-06-18 21:31:32 +000014854 if (archinfo->hwcaps & VEX_HWCAPS_X86_SSE2) {
14855 fName = "x86g_dirtyhelper_CPUID_sse2";
14856 fAddr = &x86g_dirtyhelper_CPUID_sse2;
14857 }
14858 else
sewardj5117ce12006-01-27 21:20:15 +000014859 if (archinfo->hwcaps & VEX_HWCAPS_X86_SSE1) {
14860 fName = "x86g_dirtyhelper_CPUID_sse1";
14861 fAddr = &x86g_dirtyhelper_CPUID_sse1;
14862 }
14863 else
mjw6c65c122013-08-27 10:19:03 +000014864 if (archinfo->hwcaps & VEX_HWCAPS_X86_MMXEXT) {
14865 fName = "x86g_dirtyhelper_CPUID_mmxext";
14866 fAddr = &x86g_dirtyhelper_CPUID_mmxext;
14867 }
14868 else
sewardj5117ce12006-01-27 21:20:15 +000014869 if (archinfo->hwcaps == 0/*no SSE*/) {
14870 fName = "x86g_dirtyhelper_CPUID_sse0";
14871 fAddr = &x86g_dirtyhelper_CPUID_sse0;
14872 } else
14873 vpanic("disInstr(x86)(cpuid)");
14874
sewardj9df271d2004-12-31 22:37:42 +000014875 vassert(fName); vassert(fAddr);
14876 d = unsafeIRDirty_0_N ( 0/*regparms*/,
florian90419562013-08-15 20:54:52 +000014877 fName, fAddr, mkIRExprVec_1(IRExpr_BBPTR()) );
sewardj7cb49d72004-10-24 22:31:25 +000014878 /* declare guest state effects */
14879 d->nFxState = 4;
sewardjc9069f22012-06-01 16:09:50 +000014880 vex_bzero(&d->fxState, sizeof(d->fxState));
sewardj7cb49d72004-10-24 22:31:25 +000014881 d->fxState[0].fx = Ifx_Modify;
14882 d->fxState[0].offset = OFFB_EAX;
14883 d->fxState[0].size = 4;
14884 d->fxState[1].fx = Ifx_Write;
14885 d->fxState[1].offset = OFFB_EBX;
14886 d->fxState[1].size = 4;
sewardj32bfd3e2008-02-10 13:29:19 +000014887 d->fxState[2].fx = Ifx_Modify;
sewardj7cb49d72004-10-24 22:31:25 +000014888 d->fxState[2].offset = OFFB_ECX;
14889 d->fxState[2].size = 4;
14890 d->fxState[3].fx = Ifx_Write;
14891 d->fxState[3].offset = OFFB_EDX;
14892 d->fxState[3].size = 4;
14893 /* execute the dirty call, side-effecting guest state */
14894 stmt( IRStmt_Dirty(d) );
sewardj55860d82005-01-08 18:25:05 +000014895 /* CPUID is a serialising insn. So, just in case someone is
14896 using it as a memory fence ... */
sewardjc4356f02007-11-09 21:15:04 +000014897 stmt( IRStmt_MBE(Imbe_Fence) );
sewardj517a7d62004-10-25 09:52:18 +000014898 DIP("cpuid\n");
sewardj588ea762004-09-10 18:56:32 +000014899 break;
sewardj7cb49d72004-10-24 22:31:25 +000014900 }
14901
sewardj5bd4d162004-11-10 13:02:48 +000014902//-- if (!VG_(cpu_has_feature)(VG_X86_FEAT_CPUID))
14903//-- goto decode_failure;
sewardjc9a65702004-07-07 16:32:57 +000014904//--
14905//-- t1 = newTemp(cb);
14906//-- t2 = newTemp(cb);
14907//-- t3 = newTemp(cb);
14908//-- t4 = newTemp(cb);
14909//-- uInstr0(cb, CALLM_S, 0);
14910//--
14911//-- uInstr2(cb, GET, 4, ArchReg, R_EAX, TempReg, t1);
14912//-- uInstr1(cb, PUSH, 4, TempReg, t1);
14913//--
14914//-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t2);
14915//-- uLiteral(cb, 0);
14916//-- uInstr1(cb, PUSH, 4, TempReg, t2);
14917//--
14918//-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t3);
14919//-- uLiteral(cb, 0);
14920//-- uInstr1(cb, PUSH, 4, TempReg, t3);
14921//--
14922//-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t4);
14923//-- uLiteral(cb, 0);
14924//-- uInstr1(cb, PUSH, 4, TempReg, t4);
14925//--
14926//-- uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_CPUID));
14927//-- uFlagsRWU(cb, FlagsEmpty, FlagsEmpty, FlagsEmpty);
14928//--
14929//-- uInstr1(cb, POP, 4, TempReg, t4);
14930//-- uInstr2(cb, PUT, 4, TempReg, t4, ArchReg, R_EDX);
14931//--
14932//-- uInstr1(cb, POP, 4, TempReg, t3);
14933//-- uInstr2(cb, PUT, 4, TempReg, t3, ArchReg, R_ECX);
14934//--
14935//-- uInstr1(cb, POP, 4, TempReg, t2);
14936//-- uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_EBX);
14937//--
14938//-- uInstr1(cb, POP, 4, TempReg, t1);
14939//-- uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, R_EAX);
14940//--
14941//-- uInstr0(cb, CALLM_E, 0);
14942//-- DIP("cpuid\n");
14943//-- break;
14944//--
sewardj9334b0f2004-07-10 22:43:54 +000014945 /* =-=-=-=-=-=-=-=-=- MOVZX, MOVSX =-=-=-=-=-=-=-= */
14946
14947 case 0xB6: /* MOVZXb Eb,Gv */
sewardj6ba982f2006-05-03 17:57:15 +000014948 if (sz != 2 && sz != 4)
14949 goto decode_failure;
14950 delta = dis_movx_E_G ( sorb, delta, 1, sz, False );
sewardj9334b0f2004-07-10 22:43:54 +000014951 break;
sewardj6ba982f2006-05-03 17:57:15 +000014952
sewardj940e8c92004-07-11 16:53:24 +000014953 case 0xB7: /* MOVZXw Ew,Gv */
sewardj6ba982f2006-05-03 17:57:15 +000014954 if (sz != 4)
14955 goto decode_failure;
sewardj940e8c92004-07-11 16:53:24 +000014956 delta = dis_movx_E_G ( sorb, delta, 2, 4, False );
14957 break;
14958
sewardj0611d802004-07-11 02:37:54 +000014959 case 0xBE: /* MOVSXb Eb,Gv */
sewardj6ba982f2006-05-03 17:57:15 +000014960 if (sz != 2 && sz != 4)
14961 goto decode_failure;
14962 delta = dis_movx_E_G ( sorb, delta, 1, sz, True );
sewardj0611d802004-07-11 02:37:54 +000014963 break;
sewardj6ba982f2006-05-03 17:57:15 +000014964
sewardj7ed22952004-07-29 00:09:58 +000014965 case 0xBF: /* MOVSXw Ew,Gv */
sewardj33ca4ac2010-09-30 13:37:31 +000014966 if (sz != 4 && /* accept movsww, sigh, see #250799 */sz != 2)
sewardj6ba982f2006-05-03 17:57:15 +000014967 goto decode_failure;
sewardj33ca4ac2010-09-30 13:37:31 +000014968 delta = dis_movx_E_G ( sorb, delta, 2, sz, True );
sewardj7ed22952004-07-29 00:09:58 +000014969 break;
14970
sewardjc9a65702004-07-07 16:32:57 +000014971//-- /* =-=-=-=-=-=-=-=-=-=-= MOVNTI -=-=-=-=-=-=-=-=-= */
14972//--
14973//-- case 0xC3: /* MOVNTI Gv,Ev */
14974//-- vg_assert(sz == 4);
14975//-- modrm = getUChar(eip);
14976//-- vg_assert(!epartIsReg(modrm));
14977//-- t1 = newTemp(cb);
14978//-- uInstr2(cb, GET, 4, ArchReg, gregOfRM(modrm), TempReg, t1);
14979//-- pair = disAMode ( cb, sorb, eip, dis_buf );
14980//-- t2 = LOW24(pair);
14981//-- eip += HI8(pair);
14982//-- uInstr2(cb, STORE, 4, TempReg, t1, TempReg, t2);
14983//-- DIP("movnti %s,%s\n", nameIReg(4,gregOfRM(modrm)), dis_buf);
14984//-- break;
sewardjcf780b42004-07-13 18:42:17 +000014985
14986 /* =-=-=-=-=-=-=-=-=- MUL/IMUL =-=-=-=-=-=-=-=-=-= */
14987
14988 case 0xAF: /* IMUL Ev, Gv */
sewardj2a2ba8b2004-11-08 13:14:06 +000014989 delta = dis_mul_E_G ( sorb, sz, delta );
sewardjcf780b42004-07-13 18:42:17 +000014990 break;
sewardje87b4842004-07-10 12:23:30 +000014991
sewardjec387ca2006-08-01 18:36:25 +000014992 /* =-=-=-=-=-=-=-=-=- NOPs =-=-=-=-=-=-=-=-=-=-=-= */
14993
14994 case 0x1F:
14995 modrm = getUChar(delta);
14996 if (epartIsReg(modrm)) goto decode_failure;
14997 addr = disAMode ( &alen, sorb, delta, dis_buf );
14998 delta += alen;
14999 DIP("nop%c %s\n", nameISize(sz), dis_buf);
15000 break;
15001
sewardje87b4842004-07-10 12:23:30 +000015002 /* =-=-=-=-=-=-=-=-=- Jcond d32 -=-=-=-=-=-=-=-=-= */
15003 case 0x80:
15004 case 0x81:
15005 case 0x82: /* JBb/JNAEb (jump below) */
15006 case 0x83: /* JNBb/JAEb (jump not below) */
15007 case 0x84: /* JZb/JEb (jump zero) */
15008 case 0x85: /* JNZb/JNEb (jump not zero) */
15009 case 0x86: /* JBEb/JNAb (jump below or equal) */
15010 case 0x87: /* JNBEb/JAb (jump not below or equal) */
15011 case 0x88: /* JSb (jump negative) */
15012 case 0x89: /* JSb (jump not negative) */
15013 case 0x8A: /* JP (jump parity even) */
15014 case 0x8B: /* JNP/JPO (jump parity odd) */
15015 case 0x8C: /* JLb/JNGEb (jump less) */
15016 case 0x8D: /* JGEb/JNLb (jump greater or equal) */
15017 case 0x8E: /* JLEb/JNGb (jump less or equal) */
15018 case 0x8F: /* JGb/JNLEb (jump greater) */
sewardj984d9b12010-01-15 10:53:21 +000015019 { Int jmpDelta;
florian55085f82012-11-21 00:36:55 +000015020 const HChar* comment = "";
sewardj984d9b12010-01-15 10:53:21 +000015021 jmpDelta = (Int)getUDisp32(delta);
15022 d32 = (((Addr32)guest_EIP_bbstart)+delta+4) + jmpDelta;
sewardje87b4842004-07-10 12:23:30 +000015023 delta += 4;
sewardj984d9b12010-01-15 10:53:21 +000015024 if (resteerCisOk
15025 && vex_control.guest_chase_cond
sewardj0d925b12010-01-17 15:47:01 +000015026 && (Addr32)d32 != (Addr32)guest_EIP_bbstart
sewardj984d9b12010-01-15 10:53:21 +000015027 && jmpDelta < 0
florianbeac5302014-12-31 12:09:38 +000015028 && resteerOkFn( callback_opaque, (Addr32)d32) ) {
sewardj984d9b12010-01-15 10:53:21 +000015029 /* Speculation: assume this backward branch is taken. So
15030 we need to emit a side-exit to the insn following this
15031 one, on the negation of the condition, and continue at
sewardj0d925b12010-01-17 15:47:01 +000015032 the branch target address (d32). If we wind up back at
15033 the first instruction of the trace, just stop; it's
15034 better to let the IR loop unroller handle that case.*/
sewardj984d9b12010-01-15 10:53:21 +000015035 stmt( IRStmt_Exit(
sewardj0d925b12010-01-17 15:47:01 +000015036 mk_x86g_calculate_condition((X86Condcode)
15037 (1 ^ (opc - 0x80))),
sewardj984d9b12010-01-15 10:53:21 +000015038 Ijk_Boring,
sewardjc6f970f2012-04-02 21:54:49 +000015039 IRConst_U32(guest_EIP_bbstart+delta),
15040 OFFB_EIP ) );
sewardj984d9b12010-01-15 10:53:21 +000015041 dres.whatNext = Dis_ResteerC;
florian0eaa35f2015-01-02 13:34:15 +000015042 dres.continueAt = (Addr32)d32;
sewardj984d9b12010-01-15 10:53:21 +000015043 comment = "(assumed taken)";
15044 }
15045 else
15046 if (resteerCisOk
15047 && vex_control.guest_chase_cond
sewardj0d925b12010-01-17 15:47:01 +000015048 && (Addr32)d32 != (Addr32)guest_EIP_bbstart
sewardj984d9b12010-01-15 10:53:21 +000015049 && jmpDelta >= 0
15050 && resteerOkFn( callback_opaque,
florianbeac5302014-12-31 12:09:38 +000015051 (Addr32)(guest_EIP_bbstart+delta)) ) {
sewardj984d9b12010-01-15 10:53:21 +000015052 /* Speculation: assume this forward branch is not taken.
15053 So we need to emit a side-exit to d32 (the dest) and
15054 continue disassembling at the insn immediately
15055 following this one. */
15056 stmt( IRStmt_Exit(
15057 mk_x86g_calculate_condition((X86Condcode)(opc - 0x80)),
15058 Ijk_Boring,
sewardjc6f970f2012-04-02 21:54:49 +000015059 IRConst_U32(d32),
15060 OFFB_EIP ) );
sewardj984d9b12010-01-15 10:53:21 +000015061 dres.whatNext = Dis_ResteerC;
florian0eaa35f2015-01-02 13:34:15 +000015062 dres.continueAt = guest_EIP_bbstart + delta;
sewardj984d9b12010-01-15 10:53:21 +000015063 comment = "(assumed not taken)";
15064 }
15065 else {
15066 /* Conservative default translation - end the block at
15067 this point. */
sewardjc6f970f2012-04-02 21:54:49 +000015068 jcc_01( &dres, (X86Condcode)(opc - 0x80),
sewardj984d9b12010-01-15 10:53:21 +000015069 (Addr32)(guest_EIP_bbstart+delta), d32);
sewardjc6f970f2012-04-02 21:54:49 +000015070 vassert(dres.whatNext == Dis_StopHere);
sewardj984d9b12010-01-15 10:53:21 +000015071 }
15072 DIP("j%s-32 0x%x %s\n", name_X86Condcode(opc - 0x80), d32, comment);
sewardje87b4842004-07-10 12:23:30 +000015073 break;
sewardj984d9b12010-01-15 10:53:21 +000015074 }
sewardje87b4842004-07-10 12:23:30 +000015075
sewardj89cd0932004-09-08 18:23:25 +000015076 /* =-=-=-=-=-=-=-=-=- RDTSC -=-=-=-=-=-=-=-=-=-=-= */
sewardj4ed64292005-08-23 19:24:29 +000015077 case 0x31: { /* RDTSC */
15078 IRTemp val = newTemp(Ity_I64);
15079 IRExpr** args = mkIRExprVec_0();
15080 IRDirty* d = unsafeIRDirty_1_N (
15081 val,
15082 0/*regparms*/,
15083 "x86g_dirtyhelper_RDTSC",
15084 &x86g_dirtyhelper_RDTSC,
15085 args
15086 );
sewardja5cbbdc2005-08-23 23:17:38 +000015087 /* execute the dirty call, dumping the result in val. */
15088 stmt( IRStmt_Dirty(d) );
15089 putIReg(4, R_EDX, unop(Iop_64HIto32, mkexpr(val)));
15090 putIReg(4, R_EAX, unop(Iop_64to32, mkexpr(val)));
15091 DIP("rdtsc\n");
15092 break;
sewardj4ed64292005-08-23 19:24:29 +000015093 }
sewardj77b86be2004-07-11 13:28:24 +000015094
sewardjb64821b2004-12-14 10:00:16 +000015095 /* =-=-=-=-=-=-=-=-=- PUSH/POP Sreg =-=-=-=-=-=-=-=-=-= */
15096
15097 case 0xA1: /* POP %FS */
15098 dis_pop_segreg( R_FS, sz ); break;
15099 case 0xA9: /* POP %GS */
15100 dis_pop_segreg( R_GS, sz ); break;
15101
15102 case 0xA0: /* PUSH %FS */
15103 dis_push_segreg( R_FS, sz ); break;
15104 case 0xA8: /* PUSH %GS */
15105 dis_push_segreg( R_GS, sz ); break;
15106
sewardj77b86be2004-07-11 13:28:24 +000015107 /* =-=-=-=-=-=-=-=-=- SETcc Eb =-=-=-=-=-=-=-=-=-= */
15108 case 0x90:
15109 case 0x91:
15110 case 0x92: /* set-Bb/set-NAEb (jump below) */
15111 case 0x93: /* set-NBb/set-AEb (jump not below) */
15112 case 0x94: /* set-Zb/set-Eb (jump zero) */
15113 case 0x95: /* set-NZb/set-NEb (jump not zero) */
15114 case 0x96: /* set-BEb/set-NAb (jump below or equal) */
15115 case 0x97: /* set-NBEb/set-Ab (jump not below or equal) */
15116 case 0x98: /* set-Sb (jump negative) */
15117 case 0x99: /* set-Sb (jump not negative) */
15118 case 0x9A: /* set-P (jump parity even) */
15119 case 0x9B: /* set-NP (jump parity odd) */
15120 case 0x9C: /* set-Lb/set-NGEb (jump less) */
15121 case 0x9D: /* set-GEb/set-NLb (jump greater or equal) */
15122 case 0x9E: /* set-LEb/set-NGb (jump less or equal) */
15123 case 0x9F: /* set-Gb/set-NLEb (jump greater) */
sewardj5bd4d162004-11-10 13:02:48 +000015124 t1 = newTemp(Ity_I8);
sewardj2a9ad022004-11-25 02:46:58 +000015125 assign( t1, unop(Iop_1Uto8,mk_x86g_calculate_condition(opc-0x90)) );
sewardj77b86be2004-07-11 13:28:24 +000015126 modrm = getIByte(delta);
15127 if (epartIsReg(modrm)) {
15128 delta++;
sewardj5bd4d162004-11-10 13:02:48 +000015129 putIReg(1, eregOfRM(modrm), mkexpr(t1));
sewardj2a9ad022004-11-25 02:46:58 +000015130 DIP("set%s %s\n", name_X86Condcode(opc-0x90),
sewardj77b86be2004-07-11 13:28:24 +000015131 nameIReg(1,eregOfRM(modrm)));
15132 } else {
sewardj750f4072004-07-26 22:39:11 +000015133 addr = disAMode ( &alen, sorb, delta, dis_buf );
15134 delta += alen;
15135 storeLE( mkexpr(addr), mkexpr(t1) );
sewardj2a9ad022004-11-25 02:46:58 +000015136 DIP("set%s %s\n", name_X86Condcode(opc-0x90), dis_buf);
sewardj77b86be2004-07-11 13:28:24 +000015137 }
15138 break;
15139
sewardj180e8b32004-07-29 01:40:11 +000015140 /* =-=-=-=-=-=-=-=-=- SHLD/SHRD -=-=-=-=-=-=-=-=-= */
15141
15142 case 0xA4: /* SHLDv imm8,Gv,Ev */
15143 modrm = getIByte(delta);
15144 d32 = delta + lengthAMode(delta);
sewardj2d49b432005-02-01 00:37:06 +000015145 vex_sprintf(dis_buf, "$%d", getIByte(d32));
sewardj180e8b32004-07-29 01:40:11 +000015146 delta = dis_SHLRD_Gv_Ev (
15147 sorb, delta, modrm, sz,
15148 mkU8(getIByte(d32)), True, /* literal */
15149 dis_buf, True );
15150 break;
sewardja06e5562004-07-14 13:18:05 +000015151 case 0xA5: /* SHLDv %cl,Gv,Ev */
15152 modrm = getIByte(delta);
15153 delta = dis_SHLRD_Gv_Ev (
15154 sorb, delta, modrm, sz,
15155 getIReg(1,R_ECX), False, /* not literal */
15156 "%cl", True );
15157 break;
15158
sewardj68511542004-07-28 00:15:44 +000015159 case 0xAC: /* SHRDv imm8,Gv,Ev */
15160 modrm = getIByte(delta);
15161 d32 = delta + lengthAMode(delta);
sewardj2d49b432005-02-01 00:37:06 +000015162 vex_sprintf(dis_buf, "$%d", getIByte(d32));
sewardj68511542004-07-28 00:15:44 +000015163 delta = dis_SHLRD_Gv_Ev (
15164 sorb, delta, modrm, sz,
15165 mkU8(getIByte(d32)), True, /* literal */
15166 dis_buf, False );
15167 break;
sewardja511afc2004-07-29 22:26:03 +000015168 case 0xAD: /* SHRDv %cl,Gv,Ev */
15169 modrm = getIByte(delta);
15170 delta = dis_SHLRD_Gv_Ev (
15171 sorb, delta, modrm, sz,
15172 getIReg(1,R_ECX), False, /* not literal */
15173 "%cl", False );
15174 break;
15175
sewardjf07ed032005-08-07 14:48:03 +000015176 /* =-=-=-=-=-=-=-=-=- SYSENTER -=-=-=-=-=-=-=-=-=-= */
15177
15178 case 0x34:
15179 /* Simple implementation needing a long explaination.
15180
15181 sysenter is a kind of syscall entry. The key thing here
15182 is that the return address is not known -- that is
15183 something that is beyond Vex's knowledge. So this IR
15184 forces a return to the scheduler, which can do what it
sewardj4fa325a2005-11-03 13:27:24 +000015185 likes to simulate the systenter, but it MUST set this
sewardjf07ed032005-08-07 14:48:03 +000015186 thread's guest_EIP field with the continuation address
15187 before resuming execution. If that doesn't happen, the
15188 thread will jump to address zero, which is probably
15189 fatal.
sewardje86310f2009-03-19 22:21:40 +000015190 */
15191
15192 /* Note where we are, so we can back up the guest to this
15193 point if the syscall needs to be restarted. */
15194 stmt( IRStmt_Put( OFFB_IP_AT_SYSCALL,
15195 mkU32(guest_EIP_curr_instr) ) );
sewardjc6f970f2012-04-02 21:54:49 +000015196 jmp_lit(&dres, Ijk_Sys_sysenter, 0/*bogus next EIP value*/);
15197 vassert(dres.whatNext == Dis_StopHere);
sewardjf07ed032005-08-07 14:48:03 +000015198 DIP("sysenter");
15199 break;
15200
sewardj464efa42004-11-19 22:17:29 +000015201 /* =-=-=-=-=-=-=-=-=- XADD -=-=-=-=-=-=-=-=-=-= */
15202
sewardj0092e0d2006-03-06 13:35:42 +000015203 case 0xC0: { /* XADD Gb,Eb */
15204 Bool decodeOK;
sewardje9d8a262009-07-01 08:06:34 +000015205 delta = dis_xadd_G_E ( sorb, pfx_lock, 1, delta, &decodeOK );
sewardj0092e0d2006-03-06 13:35:42 +000015206 if (!decodeOK) goto decode_failure;
sewardj883b00b2004-09-11 09:30:24 +000015207 break;
sewardj0092e0d2006-03-06 13:35:42 +000015208 }
15209 case 0xC1: { /* XADD Gv,Ev */
15210 Bool decodeOK;
sewardje9d8a262009-07-01 08:06:34 +000015211 delta = dis_xadd_G_E ( sorb, pfx_lock, sz, delta, &decodeOK );
sewardj0092e0d2006-03-06 13:35:42 +000015212 if (!decodeOK) goto decode_failure;
15213 break;
15214 }
sewardj883b00b2004-09-11 09:30:24 +000015215
sewardjf13f37b2004-12-08 17:01:23 +000015216 /* =-=-=-=-=-=-=-=-=- MMXery =-=-=-=-=-=-=-=-=-=-= */
sewardj464efa42004-11-19 22:17:29 +000015217
sewardj2b7a9202004-11-26 19:15:38 +000015218 case 0x71:
15219 case 0x72:
sewardj38a3f862005-01-13 15:06:51 +000015220 case 0x73: /* PSLLgg/PSRAgg/PSRLgg mmxreg by imm8 */
sewardj2b7a9202004-11-26 19:15:38 +000015221
15222 case 0x6E: /* MOVD (src)ireg-or-mem, (dst)mmxreg */
15223 case 0x7E: /* MOVD (src)mmxreg, (dst)ireg-or-mem */
sewardj464efa42004-11-19 22:17:29 +000015224 case 0x7F: /* MOVQ (src)mmxreg, (dst)mmxreg-or-mem */
sewardj2b7a9202004-11-26 19:15:38 +000015225 case 0x6F: /* MOVQ (src)mmxreg-or-mem, (dst)mmxreg */
sewardj464efa42004-11-19 22:17:29 +000015226
15227 case 0xFC:
15228 case 0xFD:
15229 case 0xFE: /* PADDgg (src)mmxreg-or-mem, (dst)mmxreg */
15230
15231 case 0xEC:
15232 case 0xED: /* PADDSgg (src)mmxreg-or-mem, (dst)mmxreg */
15233
15234 case 0xDC:
15235 case 0xDD: /* PADDUSgg (src)mmxreg-or-mem, (dst)mmxreg */
15236
15237 case 0xF8:
15238 case 0xF9:
15239 case 0xFA: /* PSUBgg (src)mmxreg-or-mem, (dst)mmxreg */
15240
15241 case 0xE8:
15242 case 0xE9: /* PSUBSgg (src)mmxreg-or-mem, (dst)mmxreg */
15243
15244 case 0xD8:
15245 case 0xD9: /* PSUBUSgg (src)mmxreg-or-mem, (dst)mmxreg */
15246
15247 case 0xE5: /* PMULHW (src)mmxreg-or-mem, (dst)mmxreg */
15248 case 0xD5: /* PMULLW (src)mmxreg-or-mem, (dst)mmxreg */
15249
sewardj4340dac2004-11-20 13:17:04 +000015250 case 0xF5: /* PMADDWD (src)mmxreg-or-mem, (dst)mmxreg */
15251
15252 case 0x74:
15253 case 0x75:
15254 case 0x76: /* PCMPEQgg (src)mmxreg-or-mem, (dst)mmxreg */
15255
15256 case 0x64:
15257 case 0x65:
15258 case 0x66: /* PCMPGTgg (src)mmxreg-or-mem, (dst)mmxreg */
15259
sewardj63ba4092004-11-21 12:30:18 +000015260 case 0x6B: /* PACKSSDW (src)mmxreg-or-mem, (dst)mmxreg */
15261 case 0x63: /* PACKSSWB (src)mmxreg-or-mem, (dst)mmxreg */
15262 case 0x67: /* PACKUSWB (src)mmxreg-or-mem, (dst)mmxreg */
15263
15264 case 0x68:
15265 case 0x69:
15266 case 0x6A: /* PUNPCKHgg (src)mmxreg-or-mem, (dst)mmxreg */
15267
15268 case 0x60:
15269 case 0x61:
15270 case 0x62: /* PUNPCKLgg (src)mmxreg-or-mem, (dst)mmxreg */
15271
15272 case 0xDB: /* PAND (src)mmxreg-or-mem, (dst)mmxreg */
15273 case 0xDF: /* PANDN (src)mmxreg-or-mem, (dst)mmxreg */
15274 case 0xEB: /* POR (src)mmxreg-or-mem, (dst)mmxreg */
15275 case 0xEF: /* PXOR (src)mmxreg-or-mem, (dst)mmxreg */
15276
sewardj38a3f862005-01-13 15:06:51 +000015277 case 0xF1: /* PSLLgg (src)mmxreg-or-mem, (dst)mmxreg */
sewardj8d14a592004-11-21 17:04:50 +000015278 case 0xF2:
sewardj38a3f862005-01-13 15:06:51 +000015279 case 0xF3:
sewardj8d14a592004-11-21 17:04:50 +000015280
sewardj38a3f862005-01-13 15:06:51 +000015281 case 0xD1: /* PSRLgg (src)mmxreg-or-mem, (dst)mmxreg */
sewardj8d14a592004-11-21 17:04:50 +000015282 case 0xD2:
sewardj38a3f862005-01-13 15:06:51 +000015283 case 0xD3:
sewardj8d14a592004-11-21 17:04:50 +000015284
sewardj38a3f862005-01-13 15:06:51 +000015285 case 0xE1: /* PSRAgg (src)mmxreg-or-mem, (dst)mmxreg */
15286 case 0xE2:
sewardj464efa42004-11-19 22:17:29 +000015287 {
sewardj52d04912005-07-03 00:52:48 +000015288 Int delta0 = delta-1;
sewardj464efa42004-11-19 22:17:29 +000015289 Bool decode_OK = False;
sewardj38a3f862005-01-13 15:06:51 +000015290
15291 /* If sz==2 this is SSE, and we assume sse idec has
15292 already spotted those cases by now. */
15293 if (sz != 4)
15294 goto decode_failure;
15295
sewardj464efa42004-11-19 22:17:29 +000015296 delta = dis_MMX ( &decode_OK, sorb, sz, delta-1 );
15297 if (!decode_OK) {
15298 delta = delta0;
15299 goto decode_failure;
15300 }
15301 break;
15302 }
15303
tome3aa0162011-08-11 14:43:12 +000015304 case 0x0E: /* FEMMS */
sewardj8d14a592004-11-21 17:04:50 +000015305 case 0x77: /* EMMS */
sewardj38a3f862005-01-13 15:06:51 +000015306 if (sz != 4)
15307 goto decode_failure;
sewardj4cb918d2004-12-03 19:43:31 +000015308 do_EMMS_preamble();
tome3aa0162011-08-11 14:43:12 +000015309 DIP("{f}emms\n");
sewardj8d14a592004-11-21 17:04:50 +000015310 break;
15311
sewardjb9dc2432010-06-07 16:22:22 +000015312 /* =-=-=-=-=-=-=-=-=- SGDT and SIDT =-=-=-=-=-=-=-=-=-=-= */
15313 case 0x01: /* 0F 01 /0 -- SGDT */
15314 /* 0F 01 /1 -- SIDT */
15315 {
15316 /* This is really revolting, but ... since each processor
15317 (core) only has one IDT and one GDT, just let the guest
15318 see it (pass-through semantics). I can't see any way to
15319 construct a faked-up value, so don't bother to try. */
15320 modrm = getUChar(delta);
15321 addr = disAMode ( &alen, sorb, delta, dis_buf );
15322 delta += alen;
15323 if (epartIsReg(modrm)) goto decode_failure;
15324 if (gregOfRM(modrm) != 0 && gregOfRM(modrm) != 1)
15325 goto decode_failure;
15326 switch (gregOfRM(modrm)) {
15327 case 0: DIP("sgdt %s\n", dis_buf); break;
15328 case 1: DIP("sidt %s\n", dis_buf); break;
15329 default: vassert(0); /*NOTREACHED*/
15330 }
15331
15332 IRDirty* d = unsafeIRDirty_0_N (
15333 0/*regparms*/,
15334 "x86g_dirtyhelper_SxDT",
15335 &x86g_dirtyhelper_SxDT,
15336 mkIRExprVec_2( mkexpr(addr),
15337 mkU32(gregOfRM(modrm)) )
15338 );
15339 /* declare we're writing memory */
15340 d->mFx = Ifx_Write;
15341 d->mAddr = mkexpr(addr);
15342 d->mSize = 6;
15343 stmt( IRStmt_Dirty(d) );
15344 break;
15345 }
15346
tomf0bb6792014-02-09 11:40:20 +000015347 case 0x05: /* AMD's syscall */
15348 stmt( IRStmt_Put( OFFB_IP_AT_SYSCALL,
sewardj3e5d82d2015-07-21 14:43:23 +000015349 mkU32(guest_EIP_curr_instr) ) );
tomf0bb6792014-02-09 11:40:20 +000015350 jmp_lit(&dres, Ijk_Sys_syscall, ((Addr32)guest_EIP_bbstart)+delta);
15351 vassert(dres.whatNext == Dis_StopHere);
15352 DIP("syscall\n");
15353 break;
15354
sewardje87b4842004-07-10 12:23:30 +000015355 /* =-=-=-=-=-=-=-=-=- unimp2 =-=-=-=-=-=-=-=-=-=-= */
15356
15357 default:
15358 goto decode_failure;
15359 } /* switch (opc) for the 2-byte opcodes */
15360 goto decode_success;
15361 } /* case 0x0F: of primary opcode */
sewardjc9a65702004-07-07 16:32:57 +000015362
15363 /* ------------------------ ??? ------------------------ */
15364
15365 default:
sewardje87b4842004-07-10 12:23:30 +000015366 decode_failure:
sewardjc9a65702004-07-07 16:32:57 +000015367 /* All decode failures end up here. */
sewardj442e51a2012-12-06 18:08:04 +000015368 if (sigill_diag) {
15369 vex_printf("vex x86->IR: unhandled instruction bytes: "
15370 "0x%x 0x%x 0x%x 0x%x\n",
florianb1737742015-08-03 16:03:13 +000015371 getIByte(delta_start+0),
15372 getIByte(delta_start+1),
15373 getIByte(delta_start+2),
15374 getIByte(delta_start+3));
sewardj442e51a2012-12-06 18:08:04 +000015375 }
sewardj52444cb2004-12-13 14:09:01 +000015376
sewardjb64821b2004-12-14 10:00:16 +000015377 /* Tell the dispatcher that this insn cannot be decoded, and so has
15378 not been executed, and (is currently) the next to be executed.
15379 EIP should be up-to-date since it made so at the start of each
15380 insn, but nevertheless be paranoid and update it again right
15381 now. */
sewardj9e6491a2005-07-02 19:24:10 +000015382 stmt( IRStmt_Put( OFFB_EIP, mkU32(guest_EIP_curr_instr) ) );
sewardjc6f970f2012-04-02 21:54:49 +000015383 jmp_lit(&dres, Ijk_NoDecode, guest_EIP_curr_instr);
15384 vassert(dres.whatNext == Dis_StopHere);
sewardj9e6491a2005-07-02 19:24:10 +000015385 dres.len = 0;
sewardje9d8a262009-07-01 08:06:34 +000015386 /* We also need to say that a CAS is not expected now, regardless
15387 of what it might have been set to at the start of the function,
15388 since the IR that we've emitted just above (to synthesis a
15389 SIGILL) does not involve any CAS, and presumably no other IR has
15390 been emitted for this (non-decoded) insn. */
15391 *expect_CAS = False;
sewardj9e6491a2005-07-02 19:24:10 +000015392 return dres;
sewardj52444cb2004-12-13 14:09:01 +000015393
sewardjc9a65702004-07-07 16:32:57 +000015394 } /* switch (opc) for the main (primary) opcode switch. */
15395
sewardje87b4842004-07-10 12:23:30 +000015396 decode_success:
sewardjc9a65702004-07-07 16:32:57 +000015397 /* All decode successes end up here. */
sewardjc6f970f2012-04-02 21:54:49 +000015398 switch (dres.whatNext) {
15399 case Dis_Continue:
15400 stmt( IRStmt_Put( OFFB_EIP, mkU32(guest_EIP_bbstart + delta) ) );
15401 break;
15402 case Dis_ResteerU:
15403 case Dis_ResteerC:
15404 stmt( IRStmt_Put( OFFB_EIP, mkU32(dres.continueAt) ) );
15405 break;
15406 case Dis_StopHere:
15407 break;
15408 default:
15409 vassert(0);
15410 }
15411
sewardjc9a65702004-07-07 16:32:57 +000015412 DIP("\n");
sewardj9e6491a2005-07-02 19:24:10 +000015413 dres.len = delta - delta_start;
15414 return dres;
sewardjc9a65702004-07-07 16:32:57 +000015415}
15416
15417#undef DIP
15418#undef DIS
15419
sewardj9e6491a2005-07-02 19:24:10 +000015420
15421/*------------------------------------------------------------*/
15422/*--- Top-level fn ---*/
15423/*------------------------------------------------------------*/
15424
15425/* Disassemble a single instruction into IR. The instruction
15426 is located in host memory at &guest_code[delta]. */
15427
sewardjdd40fdf2006-12-24 02:20:24 +000015428DisResult disInstr_X86 ( IRSB* irsb_IN,
florianbeac5302014-12-31 12:09:38 +000015429 Bool (*resteerOkFn) ( void*, Addr ),
sewardj984d9b12010-01-15 10:53:21 +000015430 Bool resteerCisOk,
sewardjc716aea2006-01-17 01:48:46 +000015431 void* callback_opaque,
florian8462d112014-09-24 15:18:09 +000015432 const UChar* guest_code_IN,
sewardj9e6491a2005-07-02 19:24:10 +000015433 Long delta,
floriand4cc0de2015-01-02 11:44:12 +000015434 Addr guest_IP,
sewardja5f55da2006-04-30 23:37:32 +000015435 VexArch guest_arch,
floriancacba8e2014-12-15 18:58:07 +000015436 const VexArchInfo* archinfo,
15437 const VexAbiInfo* abiinfo,
sewardj9b769162014-07-24 12:42:03 +000015438 VexEndness host_endness_IN,
sewardj442e51a2012-12-06 18:08:04 +000015439 Bool sigill_diag_IN )
sewardj9e6491a2005-07-02 19:24:10 +000015440{
sewardje9d8a262009-07-01 08:06:34 +000015441 Int i, x1, x2;
15442 Bool expect_CAS, has_CAS;
sewardj9e6491a2005-07-02 19:24:10 +000015443 DisResult dres;
15444
15445 /* Set globals (see top of this file) */
sewardja5f55da2006-04-30 23:37:32 +000015446 vassert(guest_arch == VexArchX86);
sewardj9e6491a2005-07-02 19:24:10 +000015447 guest_code = guest_code_IN;
sewardjdd40fdf2006-12-24 02:20:24 +000015448 irsb = irsb_IN;
sewardj9b769162014-07-24 12:42:03 +000015449 host_endness = host_endness_IN;
sewardj9e6491a2005-07-02 19:24:10 +000015450 guest_EIP_curr_instr = (Addr32)guest_IP;
15451 guest_EIP_bbstart = (Addr32)toUInt(guest_IP - delta);
15452
sewardje9d8a262009-07-01 08:06:34 +000015453 x1 = irsb_IN->stmts_used;
15454 expect_CAS = False;
sewardjc6f970f2012-04-02 21:54:49 +000015455 dres = disInstr_X86_WRK ( &expect_CAS, resteerOkFn,
sewardj984d9b12010-01-15 10:53:21 +000015456 resteerCisOk,
sewardj02834302010-07-29 18:10:51 +000015457 callback_opaque,
sewardj442e51a2012-12-06 18:08:04 +000015458 delta, archinfo, abiinfo, sigill_diag_IN );
sewardje9d8a262009-07-01 08:06:34 +000015459 x2 = irsb_IN->stmts_used;
15460 vassert(x2 >= x1);
15461
15462 /* See comment at the top of disInstr_X86_WRK for meaning of
15463 expect_CAS. Here, we (sanity-)check for the presence/absence of
15464 IRCAS as directed by the returned expect_CAS value. */
15465 has_CAS = False;
15466 for (i = x1; i < x2; i++) {
15467 if (irsb_IN->stmts[i]->tag == Ist_CAS)
15468 has_CAS = True;
15469 }
15470
15471 if (expect_CAS != has_CAS) {
15472 /* inconsistency detected. re-disassemble the instruction so as
15473 to generate a useful error message; then assert. */
15474 vex_traceflags |= VEX_TRACE_FE;
sewardjc6f970f2012-04-02 21:54:49 +000015475 dres = disInstr_X86_WRK ( &expect_CAS, resteerOkFn,
sewardj984d9b12010-01-15 10:53:21 +000015476 resteerCisOk,
sewardj02834302010-07-29 18:10:51 +000015477 callback_opaque,
sewardj442e51a2012-12-06 18:08:04 +000015478 delta, archinfo, abiinfo, sigill_diag_IN );
sewardje9d8a262009-07-01 08:06:34 +000015479 for (i = x1; i < x2; i++) {
15480 vex_printf("\t\t");
15481 ppIRStmt(irsb_IN->stmts[i]);
15482 vex_printf("\n");
15483 }
15484 /* Failure of this assertion is serious and denotes a bug in
15485 disInstr. */
15486 vpanic("disInstr_X86: inconsistency in LOCK prefix handling");
15487 }
sewardj9e6491a2005-07-02 19:24:10 +000015488
15489 return dres;
15490}
15491
15492
sewardjc9a65702004-07-07 16:32:57 +000015493/*--------------------------------------------------------------------*/
sewardjcef7d3e2009-07-02 12:21:59 +000015494/*--- end guest_x86_toIR.c ---*/
sewardjc9a65702004-07-07 16:32:57 +000015495/*--------------------------------------------------------------------*/