blob: 9f6a41abf9942e3cb824bd82639a0438fb35e2cc [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
Elliott Hughesed398002017-06-21 14:41:24 -070010 Copyright (C) 2004-2017 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:";
Elliott Hughesed398002017-06-21 14:41:24 -07001412 case 0x36: return "%ss:";
sewardj7df596b2004-12-06 14:29:12 +00001413 default: vpanic("sorbTxt(x86,guest)");
sewardjd1061ab2004-07-08 01:45:30 +00001414 }
1415}
1416
1417
sewardj7df596b2004-12-06 14:29:12 +00001418/* 'virtual' is an IRExpr* holding a virtual address. Convert it to a
1419 linear address by adding any required segment override as indicated
1420 by sorb. */
sewardjd1061ab2004-07-08 01:45:30 +00001421static
1422IRExpr* handleSegOverride ( UChar sorb, IRExpr* virtual )
1423{
sewardj3bd6f3e2004-12-13 10:48:19 +00001424 Int sreg;
1425 IRType hWordTy;
1426 IRTemp ldt_ptr, gdt_ptr, seg_selector, r64;
sewardjd1061ab2004-07-08 01:45:30 +00001427
1428 if (sorb == 0)
1429 /* the common case - no override */
1430 return virtual;
1431
sewardjd1061ab2004-07-08 01:45:30 +00001432 switch (sorb) {
1433 case 0x3E: sreg = R_DS; break;
1434 case 0x26: sreg = R_ES; break;
1435 case 0x64: sreg = R_FS; break;
1436 case 0x65: sreg = R_GS; break;
Elliott Hughesed398002017-06-21 14:41:24 -07001437 case 0x36: sreg = R_SS; break;
sewardj7df596b2004-12-06 14:29:12 +00001438 default: vpanic("handleSegOverride(x86,guest)");
sewardjd1061ab2004-07-08 01:45:30 +00001439 }
1440
sewardj3bd6f3e2004-12-13 10:48:19 +00001441 hWordTy = sizeof(HWord)==4 ? Ity_I32 : Ity_I64;
sewardjd1061ab2004-07-08 01:45:30 +00001442
sewardj3bd6f3e2004-12-13 10:48:19 +00001443 seg_selector = newTemp(Ity_I32);
1444 ldt_ptr = newTemp(hWordTy);
1445 gdt_ptr = newTemp(hWordTy);
1446 r64 = newTemp(Ity_I64);
sewardjd1061ab2004-07-08 01:45:30 +00001447
sewardj3bd6f3e2004-12-13 10:48:19 +00001448 assign( seg_selector, unop(Iop_16Uto32, getSReg(sreg)) );
1449 assign( ldt_ptr, IRExpr_Get( OFFB_LDT, hWordTy ));
1450 assign( gdt_ptr, IRExpr_Get( OFFB_GDT, hWordTy ));
sewardj7df596b2004-12-06 14:29:12 +00001451
sewardj3bd6f3e2004-12-13 10:48:19 +00001452 /*
1453 Call this to do the translation and limit checks:
1454 ULong x86g_use_seg_selector ( HWord ldt, HWord gdt,
1455 UInt seg_selector, UInt virtual_addr )
1456 */
1457 assign(
1458 r64,
1459 mkIRExprCCall(
1460 Ity_I64,
1461 0/*regparms*/,
1462 "x86g_use_seg_selector",
1463 &x86g_use_seg_selector,
1464 mkIRExprVec_4( mkexpr(ldt_ptr), mkexpr(gdt_ptr),
1465 mkexpr(seg_selector), virtual)
1466 )
1467 );
sewardj7df596b2004-12-06 14:29:12 +00001468
sewardj52444cb2004-12-13 14:09:01 +00001469 /* If the high 32 of the result are non-zero, there was a
1470 failure in address translation. In which case, make a
1471 quick exit.
1472 */
1473 stmt(
1474 IRStmt_Exit(
1475 binop(Iop_CmpNE32, unop(Iop_64HIto32, mkexpr(r64)), mkU32(0)),
1476 Ijk_MapFail,
sewardjc6f970f2012-04-02 21:54:49 +00001477 IRConst_U32( guest_EIP_curr_instr ),
1478 OFFB_EIP
sewardj52444cb2004-12-13 14:09:01 +00001479 )
1480 );
1481
1482 /* otherwise, here's the translated result. */
sewardj3bd6f3e2004-12-13 10:48:19 +00001483 return unop(Iop_64to32, mkexpr(r64));
sewardjd1061ab2004-07-08 01:45:30 +00001484}
1485
1486
1487/* Generate IR to calculate an address indicated by a ModRM and
1488 following SIB bytes. The expression, and the number of bytes in
1489 the address mode, are returned. Note that this fn should not be
1490 called if the R/M part of the address denotes a register instead of
1491 memory. If print_codegen is true, text of the addressing mode is
sewardj940e8c92004-07-11 16:53:24 +00001492 placed in buf.
1493
1494 The computed address is stored in a new tempreg, and the
1495 identity of the tempreg is returned. */
1496
1497static IRTemp disAMode_copy2tmp ( IRExpr* addr32 )
1498{
1499 IRTemp tmp = newTemp(Ity_I32);
1500 assign( tmp, addr32 );
1501 return tmp;
1502}
sewardjd1061ab2004-07-08 01:45:30 +00001503
1504static
sewardj52d04912005-07-03 00:52:48 +00001505IRTemp disAMode ( Int* len, UChar sorb, Int delta, HChar* buf )
sewardjd1061ab2004-07-08 01:45:30 +00001506{
1507 UChar mod_reg_rm = getIByte(delta);
1508 delta++;
1509
sewardj9ee82862004-12-14 01:16:59 +00001510 buf[0] = (UChar)0;
1511
sewardjd1061ab2004-07-08 01:45:30 +00001512 /* squeeze out the reg field from mod_reg_rm, since a 256-entry
1513 jump table seems a bit excessive.
1514 */
sewardj9b45b482005-02-07 01:42:18 +00001515 mod_reg_rm &= 0xC7; /* is now XX000YYY */
1516 mod_reg_rm = toUChar(mod_reg_rm | (mod_reg_rm >> 3));
1517 /* is now XX0XXYYY */
1518 mod_reg_rm &= 0x1F; /* is now 000XXYYY */
sewardjd1061ab2004-07-08 01:45:30 +00001519 switch (mod_reg_rm) {
1520
1521 /* (%eax) .. (%edi), not including (%esp) or (%ebp).
1522 --> GET %reg, t
1523 */
1524 case 0x00: case 0x01: case 0x02: case 0x03:
1525 /* ! 04 */ /* ! 05 */ case 0x06: case 0x07:
1526 { UChar rm = mod_reg_rm;
1527 DIS(buf, "%s(%s)", sorbTxt(sorb), nameIReg(4,rm));
1528 *len = 1;
sewardj5bd4d162004-11-10 13:02:48 +00001529 return disAMode_copy2tmp(
sewardj940e8c92004-07-11 16:53:24 +00001530 handleSegOverride(sorb, getIReg(4,rm)));
sewardjd1061ab2004-07-08 01:45:30 +00001531 }
1532
1533 /* d8(%eax) ... d8(%edi), not including d8(%esp)
1534 --> GET %reg, t ; ADDL d8, t
1535 */
1536 case 0x08: case 0x09: case 0x0A: case 0x0B:
1537 /* ! 0C */ case 0x0D: case 0x0E: case 0x0F:
sewardj9b45b482005-02-07 01:42:18 +00001538 { UChar rm = toUChar(mod_reg_rm & 7);
sewardjd1061ab2004-07-08 01:45:30 +00001539 UInt d = getSDisp8(delta);
sewardj2d49b432005-02-01 00:37:06 +00001540 DIS(buf, "%s%d(%s)", sorbTxt(sorb), (Int)d, nameIReg(4,rm));
sewardj5bd4d162004-11-10 13:02:48 +00001541 *len = 2;
1542 return disAMode_copy2tmp(
sewardj940e8c92004-07-11 16:53:24 +00001543 handleSegOverride(sorb,
1544 binop(Iop_Add32,getIReg(4,rm),mkU32(d))));
sewardjd1061ab2004-07-08 01:45:30 +00001545 }
1546
1547 /* d32(%eax) ... d32(%edi), not including d32(%esp)
1548 --> GET %reg, t ; ADDL d8, t
1549 */
1550 case 0x10: case 0x11: case 0x12: case 0x13:
1551 /* ! 14 */ case 0x15: case 0x16: case 0x17:
sewardj9b45b482005-02-07 01:42:18 +00001552 { UChar rm = toUChar(mod_reg_rm & 7);
sewardjd1061ab2004-07-08 01:45:30 +00001553 UInt d = getUDisp32(delta);
florianb1737742015-08-03 16:03:13 +00001554 DIS(buf, "%s0x%x(%s)", sorbTxt(sorb), d, nameIReg(4,rm));
sewardj5bd4d162004-11-10 13:02:48 +00001555 *len = 5;
1556 return disAMode_copy2tmp(
sewardj940e8c92004-07-11 16:53:24 +00001557 handleSegOverride(sorb,
1558 binop(Iop_Add32,getIReg(4,rm),mkU32(d))));
sewardjd1061ab2004-07-08 01:45:30 +00001559 }
1560
1561 /* a register, %eax .. %edi. This shouldn't happen. */
1562 case 0x18: case 0x19: case 0x1A: case 0x1B:
1563 case 0x1C: case 0x1D: case 0x1E: case 0x1F:
1564 vpanic("disAMode(x86): not an addr!");
1565
1566 /* a 32-bit literal address
1567 --> MOV d32, tmp
1568 */
1569 case 0x05:
1570 { UInt d = getUDisp32(delta);
1571 *len = 5;
1572 DIS(buf, "%s(0x%x)", sorbTxt(sorb), d);
sewardj940e8c92004-07-11 16:53:24 +00001573 return disAMode_copy2tmp(
1574 handleSegOverride(sorb, mkU32(d)));
sewardjd1061ab2004-07-08 01:45:30 +00001575 }
1576
1577 case 0x04: {
1578 /* SIB, with no displacement. Special cases:
1579 -- %esp cannot act as an index value.
1580 If index_r indicates %esp, zero is used for the index.
1581 -- when mod is zero and base indicates EBP, base is instead
1582 a 32-bit literal.
1583 It's all madness, I tell you. Extract %index, %base and
1584 scale from the SIB byte. The value denoted is then:
1585 | %index == %ESP && %base == %EBP
1586 = d32 following SIB byte
1587 | %index == %ESP && %base != %EBP
1588 = %base
1589 | %index != %ESP && %base == %EBP
1590 = d32 following SIB byte + (%index << scale)
1591 | %index != %ESP && %base != %ESP
1592 = %base + (%index << scale)
1593
1594 What happens to the souls of CPU architects who dream up such
1595 horrendous schemes, do you suppose?
1596 */
1597 UChar sib = getIByte(delta);
sewardj9b45b482005-02-07 01:42:18 +00001598 UChar scale = toUChar((sib >> 6) & 3);
1599 UChar index_r = toUChar((sib >> 3) & 7);
1600 UChar base_r = toUChar(sib & 7);
sewardj5bd4d162004-11-10 13:02:48 +00001601 delta++;
sewardjd1061ab2004-07-08 01:45:30 +00001602
1603 if (index_r != R_ESP && base_r != R_EBP) {
1604 DIS(buf, "%s(%s,%s,%d)", sorbTxt(sorb),
1605 nameIReg(4,base_r), nameIReg(4,index_r), 1<<scale);
sewardj5bd4d162004-11-10 13:02:48 +00001606 *len = 2;
sewardj940e8c92004-07-11 16:53:24 +00001607 return
1608 disAMode_copy2tmp(
sewardj5bd4d162004-11-10 13:02:48 +00001609 handleSegOverride(sorb,
1610 binop(Iop_Add32,
sewardjd1061ab2004-07-08 01:45:30 +00001611 getIReg(4,base_r),
1612 binop(Iop_Shl32, getIReg(4,index_r),
sewardj6d2638e2004-07-15 09:38:27 +00001613 mkU8(scale)))));
sewardjd1061ab2004-07-08 01:45:30 +00001614 }
1615
1616 if (index_r != R_ESP && base_r == R_EBP) {
1617 UInt d = getUDisp32(delta);
1618 DIS(buf, "%s0x%x(,%s,%d)", sorbTxt(sorb), d,
1619 nameIReg(4,index_r), 1<<scale);
1620 *len = 6;
1621 return
sewardj940e8c92004-07-11 16:53:24 +00001622 disAMode_copy2tmp(
sewardjd1061ab2004-07-08 01:45:30 +00001623 handleSegOverride(sorb,
sewardj5bd4d162004-11-10 13:02:48 +00001624 binop(Iop_Add32,
1625 binop(Iop_Shl32, getIReg(4,index_r), mkU8(scale)),
sewardj940e8c92004-07-11 16:53:24 +00001626 mkU32(d))));
sewardjd1061ab2004-07-08 01:45:30 +00001627 }
1628
1629 if (index_r == R_ESP && base_r != R_EBP) {
1630 DIS(buf, "%s(%s,,)", sorbTxt(sorb), nameIReg(4,base_r));
sewardj5bd4d162004-11-10 13:02:48 +00001631 *len = 2;
1632 return disAMode_copy2tmp(
sewardj940e8c92004-07-11 16:53:24 +00001633 handleSegOverride(sorb, getIReg(4,base_r)));
sewardjd1061ab2004-07-08 01:45:30 +00001634 }
1635
1636 if (index_r == R_ESP && base_r == R_EBP) {
1637 UInt d = getUDisp32(delta);
sewardj9c3b25a2007-04-05 15:06:56 +00001638 DIS(buf, "%s0x%x(,,)", sorbTxt(sorb), d);
sewardj5bd4d162004-11-10 13:02:48 +00001639 *len = 6;
sewardj5bd4d162004-11-10 13:02:48 +00001640 return disAMode_copy2tmp(
sewardj940e8c92004-07-11 16:53:24 +00001641 handleSegOverride(sorb, mkU32(d)));
sewardjd1061ab2004-07-08 01:45:30 +00001642 }
sewardjba89f4c2005-04-07 17:31:27 +00001643 /*NOTREACHED*/
sewardjd1061ab2004-07-08 01:45:30 +00001644 vassert(0);
1645 }
1646
1647 /* SIB, with 8-bit displacement. Special cases:
1648 -- %esp cannot act as an index value.
1649 If index_r indicates %esp, zero is used for the index.
1650 Denoted value is:
1651 | %index == %ESP
1652 = d8 + %base
1653 | %index != %ESP
1654 = d8 + %base + (%index << scale)
1655 */
1656 case 0x0C: {
1657 UChar sib = getIByte(delta);
sewardj9b45b482005-02-07 01:42:18 +00001658 UChar scale = toUChar((sib >> 6) & 3);
1659 UChar index_r = toUChar((sib >> 3) & 7);
1660 UChar base_r = toUChar(sib & 7);
sewardjd1061ab2004-07-08 01:45:30 +00001661 UInt d = getSDisp8(delta+1);
1662
1663 if (index_r == R_ESP) {
sewardj2d49b432005-02-01 00:37:06 +00001664 DIS(buf, "%s%d(%s,,)", sorbTxt(sorb),
1665 (Int)d, nameIReg(4,base_r));
sewardj5bd4d162004-11-10 13:02:48 +00001666 *len = 3;
1667 return disAMode_copy2tmp(
sewardj940e8c92004-07-11 16:53:24 +00001668 handleSegOverride(sorb,
1669 binop(Iop_Add32, getIReg(4,base_r), mkU32(d)) ));
sewardjd1061ab2004-07-08 01:45:30 +00001670 } else {
sewardj2d49b432005-02-01 00:37:06 +00001671 DIS(buf, "%s%d(%s,%s,%d)", sorbTxt(sorb), (Int)d,
sewardjd1061ab2004-07-08 01:45:30 +00001672 nameIReg(4,base_r), nameIReg(4,index_r), 1<<scale);
sewardj5bd4d162004-11-10 13:02:48 +00001673 *len = 3;
1674 return
sewardj940e8c92004-07-11 16:53:24 +00001675 disAMode_copy2tmp(
1676 handleSegOverride(sorb,
sewardj77b86be2004-07-11 13:28:24 +00001677 binop(Iop_Add32,
1678 binop(Iop_Add32,
1679 getIReg(4,base_r),
1680 binop(Iop_Shl32,
sewardj6d2638e2004-07-15 09:38:27 +00001681 getIReg(4,index_r), mkU8(scale))),
sewardj940e8c92004-07-11 16:53:24 +00001682 mkU32(d))));
sewardjd1061ab2004-07-08 01:45:30 +00001683 }
sewardjba89f4c2005-04-07 17:31:27 +00001684 /*NOTREACHED*/
sewardjd1061ab2004-07-08 01:45:30 +00001685 vassert(0);
1686 }
1687
1688 /* SIB, with 32-bit displacement. Special cases:
1689 -- %esp cannot act as an index value.
1690 If index_r indicates %esp, zero is used for the index.
1691 Denoted value is:
1692 | %index == %ESP
1693 = d32 + %base
1694 | %index != %ESP
1695 = d32 + %base + (%index << scale)
1696 */
1697 case 0x14: {
1698 UChar sib = getIByte(delta);
sewardj9b45b482005-02-07 01:42:18 +00001699 UChar scale = toUChar((sib >> 6) & 3);
1700 UChar index_r = toUChar((sib >> 3) & 7);
1701 UChar base_r = toUChar(sib & 7);
sewardjd1061ab2004-07-08 01:45:30 +00001702 UInt d = getUDisp32(delta+1);
1703
1704 if (index_r == R_ESP) {
sewardj2d49b432005-02-01 00:37:06 +00001705 DIS(buf, "%s%d(%s,,)", sorbTxt(sorb),
1706 (Int)d, nameIReg(4,base_r));
sewardj5bd4d162004-11-10 13:02:48 +00001707 *len = 6;
1708 return disAMode_copy2tmp(
sewardj940e8c92004-07-11 16:53:24 +00001709 handleSegOverride(sorb,
1710 binop(Iop_Add32, getIReg(4,base_r), mkU32(d)) ));
sewardjd1061ab2004-07-08 01:45:30 +00001711 } else {
sewardj2d49b432005-02-01 00:37:06 +00001712 DIS(buf, "%s%d(%s,%s,%d)", sorbTxt(sorb), (Int)d,
1713 nameIReg(4,base_r), nameIReg(4,index_r), 1<<scale);
sewardj5bd4d162004-11-10 13:02:48 +00001714 *len = 6;
1715 return
sewardj940e8c92004-07-11 16:53:24 +00001716 disAMode_copy2tmp(
1717 handleSegOverride(sorb,
sewardj9334b0f2004-07-10 22:43:54 +00001718 binop(Iop_Add32,
1719 binop(Iop_Add32,
1720 getIReg(4,base_r),
1721 binop(Iop_Shl32,
sewardj6d2638e2004-07-15 09:38:27 +00001722 getIReg(4,index_r), mkU8(scale))),
sewardj940e8c92004-07-11 16:53:24 +00001723 mkU32(d))));
sewardjd1061ab2004-07-08 01:45:30 +00001724 }
sewardjba89f4c2005-04-07 17:31:27 +00001725 /*NOTREACHED*/
sewardjd1061ab2004-07-08 01:45:30 +00001726 vassert(0);
1727 }
1728
1729 default:
1730 vpanic("disAMode(x86)");
1731 return 0; /*notreached*/
1732 }
1733}
1734
1735
1736/* Figure out the number of (insn-stream) bytes constituting the amode
1737 beginning at delta. Is useful for getting hold of literals beyond
1738 the end of the amode before it has been disassembled. */
1739
sewardj52d04912005-07-03 00:52:48 +00001740static UInt lengthAMode ( Int delta )
sewardjd1061ab2004-07-08 01:45:30 +00001741{
1742 UChar mod_reg_rm = getIByte(delta); delta++;
1743
1744 /* squeeze out the reg field from mod_reg_rm, since a 256-entry
1745 jump table seems a bit excessive.
1746 */
1747 mod_reg_rm &= 0xC7; /* is now XX000YYY */
sewardj9b45b482005-02-07 01:42:18 +00001748 mod_reg_rm = toUChar(mod_reg_rm | (mod_reg_rm >> 3));
1749 /* is now XX0XXYYY */
sewardjd1061ab2004-07-08 01:45:30 +00001750 mod_reg_rm &= 0x1F; /* is now 000XXYYY */
1751 switch (mod_reg_rm) {
1752
1753 /* (%eax) .. (%edi), not including (%esp) or (%ebp). */
1754 case 0x00: case 0x01: case 0x02: case 0x03:
1755 /* ! 04 */ /* ! 05 */ case 0x06: case 0x07:
1756 return 1;
1757
1758 /* d8(%eax) ... d8(%edi), not including d8(%esp). */
1759 case 0x08: case 0x09: case 0x0A: case 0x0B:
1760 /* ! 0C */ case 0x0D: case 0x0E: case 0x0F:
1761 return 2;
1762
1763 /* d32(%eax) ... d32(%edi), not including d32(%esp). */
1764 case 0x10: case 0x11: case 0x12: case 0x13:
1765 /* ! 14 */ case 0x15: case 0x16: case 0x17:
1766 return 5;
1767
1768 /* a register, %eax .. %edi. (Not an addr, but still handled.) */
1769 case 0x18: case 0x19: case 0x1A: case 0x1B:
1770 case 0x1C: case 0x1D: case 0x1E: case 0x1F:
1771 return 1;
1772
1773 /* a 32-bit literal address. */
1774 case 0x05: return 5;
1775
1776 /* SIB, no displacement. */
1777 case 0x04: {
1778 UChar sib = getIByte(delta);
sewardj9b45b482005-02-07 01:42:18 +00001779 UChar base_r = toUChar(sib & 7);
sewardjd1061ab2004-07-08 01:45:30 +00001780 if (base_r == R_EBP) return 6; else return 2;
1781 }
1782 /* SIB, with 8-bit displacement. */
1783 case 0x0C: return 3;
1784
1785 /* SIB, with 32-bit displacement. */
1786 case 0x14: return 6;
1787
1788 default:
1789 vpanic("lengthAMode");
1790 return 0; /*notreached*/
1791 }
1792}
1793
1794/*------------------------------------------------------------*/
1795/*--- Disassembling common idioms ---*/
1796/*------------------------------------------------------------*/
1797
sewardje87b4842004-07-10 12:23:30 +00001798/* Handle binary integer instructions of the form
1799 op E, G meaning
1800 op reg-or-mem, reg
1801 Is passed the a ptr to the modRM byte, the actual operation, and the
1802 data size. Returns the address advanced completely over this
1803 instruction.
1804
1805 E(src) is reg-or-mem
1806 G(dst) is reg.
1807
1808 If E is reg, --> GET %G, tmp
1809 OP %E, tmp
1810 PUT tmp, %G
1811
1812 If E is mem and OP is not reversible,
1813 --> (getAddr E) -> tmpa
1814 LD (tmpa), tmpa
1815 GET %G, tmp2
1816 OP tmpa, tmp2
1817 PUT tmp2, %G
1818
1819 If E is mem and OP is reversible
1820 --> (getAddr E) -> tmpa
1821 LD (tmpa), tmpa
1822 OP %G, tmpa
1823 PUT tmpa, %G
1824*/
1825static
1826UInt dis_op2_E_G ( UChar sorb,
sewardj180e8b32004-07-29 01:40:11 +00001827 Bool addSubCarry,
sewardje87b4842004-07-10 12:23:30 +00001828 IROp op8,
1829 Bool keep,
1830 Int size,
sewardj52d04912005-07-03 00:52:48 +00001831 Int delta0,
florian55085f82012-11-21 00:36:55 +00001832 const HChar* t_x86opc )
sewardje87b4842004-07-10 12:23:30 +00001833{
sewardjc9a43662004-11-30 18:51:59 +00001834 HChar dis_buf[50];
sewardj9334b0f2004-07-10 22:43:54 +00001835 Int len;
sewardje87b4842004-07-10 12:23:30 +00001836 IRType ty = szToITy(size);
1837 IRTemp dst1 = newTemp(ty);
1838 IRTemp src = newTemp(ty);
1839 IRTemp dst0 = newTemp(ty);
1840 UChar rm = getUChar(delta0);
sewardj92d168d2004-11-15 14:22:12 +00001841 IRTemp addr = IRTemp_INVALID;
sewardje87b4842004-07-10 12:23:30 +00001842
sewardj180e8b32004-07-29 01:40:11 +00001843 /* addSubCarry == True indicates the intended operation is
1844 add-with-carry or subtract-with-borrow. */
1845 if (addSubCarry) {
1846 vassert(op8 == Iop_Add8 || op8 == Iop_Sub8);
1847 vassert(keep);
1848 }
1849
sewardje87b4842004-07-10 12:23:30 +00001850 if (epartIsReg(rm)) {
sewardje87b4842004-07-10 12:23:30 +00001851 /* Specially handle XOR reg,reg, because that doesn't really
1852 depend on reg, and doing the obvious thing potentially
1853 generates a spurious value check failure due to the bogus
sewardj55efbdf2005-05-02 17:07:02 +00001854 dependency. Ditto SBB reg,reg. */
1855 if ((op8 == Iop_Xor8 || (op8 == Iop_Sub8 && addSubCarry))
1856 && gregOfRM(rm) == eregOfRM(rm)) {
1857 putIReg(size, gregOfRM(rm), mkU(ty,0));
sewardje87b4842004-07-10 12:23:30 +00001858 }
sewardje87b4842004-07-10 12:23:30 +00001859 assign( dst0, getIReg(size,gregOfRM(rm)) );
1860 assign( src, getIReg(size,eregOfRM(rm)) );
sewardje87b4842004-07-10 12:23:30 +00001861
sewardj180e8b32004-07-29 01:40:11 +00001862 if (addSubCarry && op8 == Iop_Add8) {
sewardje9d8a262009-07-01 08:06:34 +00001863 helper_ADC( size, dst1, dst0, src,
1864 /*no store*/IRTemp_INVALID, IRTemp_INVALID, 0 );
sewardje87b4842004-07-10 12:23:30 +00001865 putIReg(size, gregOfRM(rm), mkexpr(dst1));
sewardj180e8b32004-07-29 01:40:11 +00001866 } else
1867 if (addSubCarry && op8 == Iop_Sub8) {
sewardje9d8a262009-07-01 08:06:34 +00001868 helper_SBB( size, dst1, dst0, src,
1869 /*no store*/IRTemp_INVALID, IRTemp_INVALID, 0 );
sewardj180e8b32004-07-29 01:40:11 +00001870 putIReg(size, gregOfRM(rm), mkexpr(dst1));
1871 } else {
1872 assign( dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)) );
sewardj5bd4d162004-11-10 13:02:48 +00001873 if (isAddSub(op8))
sewardj2a2ba8b2004-11-08 13:14:06 +00001874 setFlags_DEP1_DEP2(op8, dst0, src, ty);
sewardjb9c5cf62004-08-24 15:10:38 +00001875 else
sewardj2a2ba8b2004-11-08 13:14:06 +00001876 setFlags_DEP1(op8, dst1, ty);
sewardj180e8b32004-07-29 01:40:11 +00001877 if (keep)
1878 putIReg(size, gregOfRM(rm), mkexpr(dst1));
1879 }
sewardje87b4842004-07-10 12:23:30 +00001880
1881 DIP("%s%c %s,%s\n", t_x86opc, nameISize(size),
1882 nameIReg(size,eregOfRM(rm)),
1883 nameIReg(size,gregOfRM(rm)));
1884 return 1+delta0;
sewardje87b4842004-07-10 12:23:30 +00001885 } else {
sewardj9334b0f2004-07-10 22:43:54 +00001886 /* E refers to memory */
1887 addr = disAMode ( &len, sorb, delta0, dis_buf);
1888 assign( dst0, getIReg(size,gregOfRM(rm)) );
sewardj940e8c92004-07-11 16:53:24 +00001889 assign( src, loadLE(szToITy(size), mkexpr(addr)) );
sewardj9334b0f2004-07-10 22:43:54 +00001890
sewardj180e8b32004-07-29 01:40:11 +00001891 if (addSubCarry && op8 == Iop_Add8) {
sewardje9d8a262009-07-01 08:06:34 +00001892 helper_ADC( size, dst1, dst0, src,
1893 /*no store*/IRTemp_INVALID, IRTemp_INVALID, 0 );
sewardj9334b0f2004-07-10 22:43:54 +00001894 putIReg(size, gregOfRM(rm), mkexpr(dst1));
sewardj180e8b32004-07-29 01:40:11 +00001895 } else
1896 if (addSubCarry && op8 == Iop_Sub8) {
sewardje9d8a262009-07-01 08:06:34 +00001897 helper_SBB( size, dst1, dst0, src,
1898 /*no store*/IRTemp_INVALID, IRTemp_INVALID, 0 );
sewardj180e8b32004-07-29 01:40:11 +00001899 putIReg(size, gregOfRM(rm), mkexpr(dst1));
1900 } else {
1901 assign( dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)) );
sewardj5bd4d162004-11-10 13:02:48 +00001902 if (isAddSub(op8))
sewardj2a2ba8b2004-11-08 13:14:06 +00001903 setFlags_DEP1_DEP2(op8, dst0, src, ty);
sewardjb9c5cf62004-08-24 15:10:38 +00001904 else
sewardj2a2ba8b2004-11-08 13:14:06 +00001905 setFlags_DEP1(op8, dst1, ty);
sewardj180e8b32004-07-29 01:40:11 +00001906 if (keep)
1907 putIReg(size, gregOfRM(rm), mkexpr(dst1));
1908 }
sewardj9334b0f2004-07-10 22:43:54 +00001909
sewardje87b4842004-07-10 12:23:30 +00001910 DIP("%s%c %s,%s\n", t_x86opc, nameISize(size),
1911 dis_buf,nameIReg(size,gregOfRM(rm)));
sewardj9334b0f2004-07-10 22:43:54 +00001912 return len+delta0;
sewardje87b4842004-07-10 12:23:30 +00001913 }
sewardje87b4842004-07-10 12:23:30 +00001914}
sewardje05c42c2004-07-08 20:25:10 +00001915
1916
1917
1918/* Handle binary integer instructions of the form
1919 op G, E meaning
1920 op reg, reg-or-mem
1921 Is passed the a ptr to the modRM byte, the actual operation, and the
1922 data size. Returns the address advanced completely over this
1923 instruction.
1924
1925 G(src) is reg.
1926 E(dst) is reg-or-mem
1927
1928 If E is reg, --> GET %E, tmp
1929 OP %G, tmp
1930 PUT tmp, %E
1931
1932 If E is mem, --> (getAddr E) -> tmpa
1933 LD (tmpa), tmpv
1934 OP %G, tmpv
1935 ST tmpv, (tmpa)
1936*/
1937static
1938UInt dis_op2_G_E ( UChar sorb,
sewardje9d8a262009-07-01 08:06:34 +00001939 Bool locked,
sewardjcaca9d02004-07-28 07:11:32 +00001940 Bool addSubCarry,
sewardje05c42c2004-07-08 20:25:10 +00001941 IROp op8,
1942 Bool keep,
1943 Int size,
sewardj52d04912005-07-03 00:52:48 +00001944 Int delta0,
florian55085f82012-11-21 00:36:55 +00001945 const HChar* t_x86opc )
sewardje05c42c2004-07-08 20:25:10 +00001946{
sewardjc9a43662004-11-30 18:51:59 +00001947 HChar dis_buf[50];
sewardje87b4842004-07-10 12:23:30 +00001948 Int len;
sewardje05c42c2004-07-08 20:25:10 +00001949 IRType ty = szToITy(size);
1950 IRTemp dst1 = newTemp(ty);
1951 IRTemp src = newTemp(ty);
1952 IRTemp dst0 = newTemp(ty);
1953 UChar rm = getIByte(delta0);
sewardj92d168d2004-11-15 14:22:12 +00001954 IRTemp addr = IRTemp_INVALID;
sewardje05c42c2004-07-08 20:25:10 +00001955
sewardjcaca9d02004-07-28 07:11:32 +00001956 /* addSubCarry == True indicates the intended operation is
1957 add-with-carry or subtract-with-borrow. */
1958 if (addSubCarry) {
1959 vassert(op8 == Iop_Add8 || op8 == Iop_Sub8);
1960 vassert(keep);
1961 }
1962
sewardje05c42c2004-07-08 20:25:10 +00001963 if (epartIsReg(rm)) {
sewardje05c42c2004-07-08 20:25:10 +00001964 /* Specially handle XOR reg,reg, because that doesn't really
1965 depend on reg, and doing the obvious thing potentially
1966 generates a spurious value check failure due to the bogus
sewardj55efbdf2005-05-02 17:07:02 +00001967 dependency. Ditto SBB reg,reg.*/
1968 if ((op8 == Iop_Xor8 || (op8 == Iop_Sub8 && addSubCarry))
1969 && gregOfRM(rm) == eregOfRM(rm)) {
1970 putIReg(size, eregOfRM(rm), mkU(ty,0));
sewardje05c42c2004-07-08 20:25:10 +00001971 }
sewardje05c42c2004-07-08 20:25:10 +00001972 assign(dst0, getIReg(size,eregOfRM(rm)));
1973 assign(src, getIReg(size,gregOfRM(rm)));
sewardje05c42c2004-07-08 20:25:10 +00001974
sewardjcaca9d02004-07-28 07:11:32 +00001975 if (addSubCarry && op8 == Iop_Add8) {
sewardje9d8a262009-07-01 08:06:34 +00001976 helper_ADC( size, dst1, dst0, src,
1977 /*no store*/IRTemp_INVALID, IRTemp_INVALID, 0 );
sewardj1813dbe2004-07-28 17:09:04 +00001978 putIReg(size, eregOfRM(rm), mkexpr(dst1));
sewardjcaca9d02004-07-28 07:11:32 +00001979 } else
1980 if (addSubCarry && op8 == Iop_Sub8) {
sewardje9d8a262009-07-01 08:06:34 +00001981 helper_SBB( size, dst1, dst0, src,
1982 /*no store*/IRTemp_INVALID, IRTemp_INVALID, 0 );
sewardje05c42c2004-07-08 20:25:10 +00001983 putIReg(size, eregOfRM(rm), mkexpr(dst1));
sewardjcaca9d02004-07-28 07:11:32 +00001984 } else {
1985 assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)));
sewardj5bd4d162004-11-10 13:02:48 +00001986 if (isAddSub(op8))
sewardj2a2ba8b2004-11-08 13:14:06 +00001987 setFlags_DEP1_DEP2(op8, dst0, src, ty);
sewardjb9c5cf62004-08-24 15:10:38 +00001988 else
sewardj2a2ba8b2004-11-08 13:14:06 +00001989 setFlags_DEP1(op8, dst1, ty);
sewardjcaca9d02004-07-28 07:11:32 +00001990 if (keep)
1991 putIReg(size, eregOfRM(rm), mkexpr(dst1));
1992 }
sewardje05c42c2004-07-08 20:25:10 +00001993
1994 DIP("%s%c %s,%s\n", t_x86opc, nameISize(size),
1995 nameIReg(size,gregOfRM(rm)),
1996 nameIReg(size,eregOfRM(rm)));
1997 return 1+delta0;
1998 }
1999
2000 /* E refers to memory */
2001 {
sewardje87b4842004-07-10 12:23:30 +00002002 addr = disAMode ( &len, sorb, delta0, dis_buf);
sewardj940e8c92004-07-11 16:53:24 +00002003 assign(dst0, loadLE(ty,mkexpr(addr)));
sewardje87b4842004-07-10 12:23:30 +00002004 assign(src, getIReg(size,gregOfRM(rm)));
sewardje05c42c2004-07-08 20:25:10 +00002005
sewardjcaca9d02004-07-28 07:11:32 +00002006 if (addSubCarry && op8 == Iop_Add8) {
sewardje9d8a262009-07-01 08:06:34 +00002007 if (locked) {
2008 /* cas-style store */
2009 helper_ADC( size, dst1, dst0, src,
2010 /*store*/addr, dst0/*expVal*/, guest_EIP_curr_instr );
2011 } else {
2012 /* normal store */
2013 helper_ADC( size, dst1, dst0, src,
2014 /*store*/addr, IRTemp_INVALID, 0 );
2015 }
sewardjcaca9d02004-07-28 07:11:32 +00002016 } else
2017 if (addSubCarry && op8 == Iop_Sub8) {
sewardje9d8a262009-07-01 08:06:34 +00002018 if (locked) {
2019 /* cas-style store */
2020 helper_SBB( size, dst1, dst0, src,
2021 /*store*/addr, dst0/*expVal*/, guest_EIP_curr_instr );
2022 } else {
2023 /* normal store */
2024 helper_SBB( size, dst1, dst0, src,
2025 /*store*/addr, IRTemp_INVALID, 0 );
2026 }
sewardjcaca9d02004-07-28 07:11:32 +00002027 } else {
2028 assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)));
sewardje9d8a262009-07-01 08:06:34 +00002029 if (keep) {
2030 if (locked) {
2031 if (0) vex_printf("locked case\n" );
2032 casLE( mkexpr(addr),
2033 mkexpr(dst0)/*expval*/,
2034 mkexpr(dst1)/*newval*/, guest_EIP_curr_instr );
2035 } else {
2036 if (0) vex_printf("nonlocked case\n");
2037 storeLE(mkexpr(addr), mkexpr(dst1));
2038 }
2039 }
sewardj5bd4d162004-11-10 13:02:48 +00002040 if (isAddSub(op8))
sewardj2a2ba8b2004-11-08 13:14:06 +00002041 setFlags_DEP1_DEP2(op8, dst0, src, ty);
sewardjb9c5cf62004-08-24 15:10:38 +00002042 else
sewardj2a2ba8b2004-11-08 13:14:06 +00002043 setFlags_DEP1(op8, dst1, ty);
sewardjcaca9d02004-07-28 07:11:32 +00002044 }
sewardje87b4842004-07-10 12:23:30 +00002045
sewardje05c42c2004-07-08 20:25:10 +00002046 DIP("%s%c %s,%s\n", t_x86opc, nameISize(size),
2047 nameIReg(size,gregOfRM(rm)), dis_buf);
sewardje87b4842004-07-10 12:23:30 +00002048 return len+delta0;
sewardje05c42c2004-07-08 20:25:10 +00002049 }
2050}
2051
2052
2053/* Handle move instructions of the form
2054 mov E, G meaning
2055 mov reg-or-mem, reg
2056 Is passed the a ptr to the modRM byte, and the data size. Returns
2057 the address advanced completely over this instruction.
2058
2059 E(src) is reg-or-mem
2060 G(dst) is reg.
2061
2062 If E is reg, --> GET %E, tmpv
2063 PUT tmpv, %G
2064
2065 If E is mem --> (getAddr E) -> tmpa
2066 LD (tmpa), tmpb
2067 PUT tmpb, %G
2068*/
2069static
2070UInt dis_mov_E_G ( UChar sorb,
2071 Int size,
sewardj52d04912005-07-03 00:52:48 +00002072 Int delta0 )
sewardje05c42c2004-07-08 20:25:10 +00002073{
2074 Int len;
2075 UChar rm = getIByte(delta0);
sewardjc9a43662004-11-30 18:51:59 +00002076 HChar dis_buf[50];
sewardje05c42c2004-07-08 20:25:10 +00002077
2078 if (epartIsReg(rm)) {
sewardj7ca37d92004-10-25 02:58:30 +00002079 putIReg(size, gregOfRM(rm), getIReg(size, eregOfRM(rm)));
sewardje05c42c2004-07-08 20:25:10 +00002080 DIP("mov%c %s,%s\n", nameISize(size),
2081 nameIReg(size,eregOfRM(rm)),
2082 nameIReg(size,gregOfRM(rm)));
sewardj7ca37d92004-10-25 02:58:30 +00002083 return 1+delta0;
sewardje05c42c2004-07-08 20:25:10 +00002084 }
2085
2086 /* E refers to memory */
2087 {
sewardj940e8c92004-07-11 16:53:24 +00002088 IRTemp addr = disAMode ( &len, sorb, delta0, dis_buf );
2089 putIReg(size, gregOfRM(rm), loadLE(szToITy(size), mkexpr(addr)));
sewardje05c42c2004-07-08 20:25:10 +00002090 DIP("mov%c %s,%s\n", nameISize(size),
2091 dis_buf,nameIReg(size,gregOfRM(rm)));
2092 return delta0+len;
2093 }
2094}
2095
2096
2097/* Handle move instructions of the form
2098 mov G, E meaning
2099 mov reg, reg-or-mem
2100 Is passed the a ptr to the modRM byte, and the data size. Returns
2101 the address advanced completely over this instruction.
2102
2103 G(src) is reg.
2104 E(dst) is reg-or-mem
2105
2106 If E is reg, --> GET %G, tmp
2107 PUT tmp, %E
2108
2109 If E is mem, --> (getAddr E) -> tmpa
2110 GET %G, tmpv
2111 ST tmpv, (tmpa)
2112*/
sewardjc9a65702004-07-07 16:32:57 +00002113static
2114UInt dis_mov_G_E ( UChar sorb,
2115 Int size,
sewardj52d04912005-07-03 00:52:48 +00002116 Int delta0 )
sewardjc9a65702004-07-07 16:32:57 +00002117{
sewardje05c42c2004-07-08 20:25:10 +00002118 Int len;
sewardjc9a65702004-07-07 16:32:57 +00002119 UChar rm = getIByte(delta0);
sewardjc9a43662004-11-30 18:51:59 +00002120 HChar dis_buf[50];
sewardjc9a65702004-07-07 16:32:57 +00002121
2122 if (epartIsReg(rm)) {
sewardj41f43bc2004-07-08 14:23:22 +00002123 putIReg(size, eregOfRM(rm), getIReg(size, gregOfRM(rm)));
sewardjc9a65702004-07-07 16:32:57 +00002124 DIP("mov%c %s,%s\n", nameISize(size),
2125 nameIReg(size,gregOfRM(rm)),
2126 nameIReg(size,eregOfRM(rm)));
2127 return 1+delta0;
2128 }
2129
sewardjc9a65702004-07-07 16:32:57 +00002130 /* E refers to memory */
2131 {
sewardj940e8c92004-07-11 16:53:24 +00002132 IRTemp addr = disAMode ( &len, sorb, delta0, dis_buf);
2133 storeLE( mkexpr(addr), getIReg(size, gregOfRM(rm)) );
sewardjc9a65702004-07-07 16:32:57 +00002134 DIP("mov%c %s,%s\n", nameISize(size),
2135 nameIReg(size,gregOfRM(rm)), dis_buf);
sewardje05c42c2004-07-08 20:25:10 +00002136 return len+delta0;
sewardjc9a65702004-07-07 16:32:57 +00002137 }
sewardjc9a65702004-07-07 16:32:57 +00002138}
2139
2140
sewardj0611d802004-07-11 02:37:54 +00002141/* op $immediate, AL/AX/EAX. */
2142static
2143UInt dis_op_imm_A ( Int size,
sewardja718d5d2005-04-03 14:59:54 +00002144 Bool carrying,
sewardj0611d802004-07-11 02:37:54 +00002145 IROp op8,
2146 Bool keep,
sewardj52d04912005-07-03 00:52:48 +00002147 Int delta,
florian55085f82012-11-21 00:36:55 +00002148 const HChar* t_x86opc )
sewardj0611d802004-07-11 02:37:54 +00002149{
2150 IRType ty = szToITy(size);
2151 IRTemp dst0 = newTemp(ty);
2152 IRTemp src = newTemp(ty);
2153 IRTemp dst1 = newTemp(ty);
2154 UInt lit = getUDisp(size,delta);
2155 assign(dst0, getIReg(size,R_EAX));
2156 assign(src, mkU(ty,lit));
sewardja718d5d2005-04-03 14:59:54 +00002157
2158 if (isAddSub(op8) && !carrying) {
2159 assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)) );
sewardj2a2ba8b2004-11-08 13:14:06 +00002160 setFlags_DEP1_DEP2(op8, dst0, src, ty);
sewardja718d5d2005-04-03 14:59:54 +00002161 }
sewardjb9c5cf62004-08-24 15:10:38 +00002162 else
sewardja718d5d2005-04-03 14:59:54 +00002163 if (isLogic(op8)) {
2164 vassert(!carrying);
2165 assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)) );
sewardj2a2ba8b2004-11-08 13:14:06 +00002166 setFlags_DEP1(op8, dst1, ty);
sewardja718d5d2005-04-03 14:59:54 +00002167 }
2168 else
2169 if (op8 == Iop_Add8 && carrying) {
sewardje9d8a262009-07-01 08:06:34 +00002170 helper_ADC( size, dst1, dst0, src,
2171 /*no store*/IRTemp_INVALID, IRTemp_INVALID, 0 );
sewardja718d5d2005-04-03 14:59:54 +00002172 }
sewardj2a2ba8b2004-11-08 13:14:06 +00002173 else
sewardj2fbae082005-10-03 02:07:08 +00002174 if (op8 == Iop_Sub8 && carrying) {
sewardje9d8a262009-07-01 08:06:34 +00002175 helper_SBB( size, dst1, dst0, src,
2176 /*no store*/IRTemp_INVALID, IRTemp_INVALID, 0 );
sewardj2fbae082005-10-03 02:07:08 +00002177 }
2178 else
sewardj2a2ba8b2004-11-08 13:14:06 +00002179 vpanic("dis_op_imm_A(x86,guest)");
sewardj0611d802004-07-11 02:37:54 +00002180
2181 if (keep)
2182 putIReg(size, R_EAX, mkexpr(dst1));
2183
2184 DIP("%s%c $0x%x, %s\n", t_x86opc, nameISize(size),
2185 lit, nameIReg(size,R_EAX));
2186 return delta+size;
2187}
sewardj9334b0f2004-07-10 22:43:54 +00002188
2189
2190/* Sign- and Zero-extending moves. */
2191static
sewardj52d04912005-07-03 00:52:48 +00002192UInt dis_movx_E_G ( UChar sorb,
2193 Int delta, Int szs, Int szd, Bool sign_extend )
sewardj9334b0f2004-07-10 22:43:54 +00002194{
sewardj9334b0f2004-07-10 22:43:54 +00002195 UChar rm = getIByte(delta);
2196 if (epartIsReg(rm)) {
sewardj33ca4ac2010-09-30 13:37:31 +00002197 if (szd == szs) {
2198 // mutant case. See #250799
2199 putIReg(szd, gregOfRM(rm),
2200 getIReg(szs,eregOfRM(rm)));
2201 } else {
2202 // normal case
2203 putIReg(szd, gregOfRM(rm),
2204 unop(mkWidenOp(szs,szd,sign_extend),
2205 getIReg(szs,eregOfRM(rm))));
2206 }
sewardj9334b0f2004-07-10 22:43:54 +00002207 DIP("mov%c%c%c %s,%s\n", sign_extend ? 's' : 'z',
2208 nameISize(szs), nameISize(szd),
2209 nameIReg(szs,eregOfRM(rm)),
2210 nameIReg(szd,gregOfRM(rm)));
2211 return 1+delta;
2212 }
2213
2214 /* E refers to memory */
2215 {
sewardj940e8c92004-07-11 16:53:24 +00002216 Int len;
sewardjc9a43662004-11-30 18:51:59 +00002217 HChar dis_buf[50];
sewardj940e8c92004-07-11 16:53:24 +00002218 IRTemp addr = disAMode ( &len, sorb, delta, dis_buf );
sewardj33ca4ac2010-09-30 13:37:31 +00002219 if (szd == szs) {
2220 // mutant case. See #250799
2221 putIReg(szd, gregOfRM(rm),
2222 loadLE(szToITy(szs),mkexpr(addr)));
2223 } else {
2224 // normal case
2225 putIReg(szd, gregOfRM(rm),
2226 unop(mkWidenOp(szs,szd,sign_extend),
2227 loadLE(szToITy(szs),mkexpr(addr))));
2228 }
sewardj9334b0f2004-07-10 22:43:54 +00002229 DIP("mov%c%c%c %s,%s\n", sign_extend ? 's' : 'z',
2230 nameISize(szs), nameISize(szd),
2231 dis_buf, nameIReg(szd,gregOfRM(rm)));
sewardj0611d802004-07-11 02:37:54 +00002232 return len+delta;
sewardj9334b0f2004-07-10 22:43:54 +00002233 }
2234}
2235
sewardj9690d922004-07-14 01:39:17 +00002236
2237/* Generate code to divide ArchRegs EDX:EAX / DX:AX / AX by the 32 /
2238 16 / 8 bit quantity in the given IRTemp. */
2239static
2240void codegen_div ( Int sz, IRTemp t, Bool signed_divide )
2241{
sewardje5427e82004-09-11 19:43:51 +00002242 IROp op = signed_divide ? Iop_DivModS64to32 : Iop_DivModU64to32;
2243 IRTemp src64 = newTemp(Ity_I64);
2244 IRTemp dst64 = newTemp(Ity_I64);
sewardj9690d922004-07-14 01:39:17 +00002245 switch (sz) {
sewardje5427e82004-09-11 19:43:51 +00002246 case 4:
sewardj9690d922004-07-14 01:39:17 +00002247 assign( src64, binop(Iop_32HLto64,
sewardje5427e82004-09-11 19:43:51 +00002248 getIReg(4,R_EDX), getIReg(4,R_EAX)) );
sewardj9690d922004-07-14 01:39:17 +00002249 assign( dst64, binop(op, mkexpr(src64), mkexpr(t)) );
sewardj8c7f1ab2004-07-29 20:31:09 +00002250 putIReg( 4, R_EAX, unop(Iop_64to32,mkexpr(dst64)) );
sewardj9690d922004-07-14 01:39:17 +00002251 putIReg( 4, R_EDX, unop(Iop_64HIto32,mkexpr(dst64)) );
2252 break;
sewardje5427e82004-09-11 19:43:51 +00002253 case 2: {
2254 IROp widen3264 = signed_divide ? Iop_32Sto64 : Iop_32Uto64;
2255 IROp widen1632 = signed_divide ? Iop_16Sto32 : Iop_16Uto32;
2256 assign( src64, unop(widen3264,
2257 binop(Iop_16HLto32,
2258 getIReg(2,R_EDX), getIReg(2,R_EAX))) );
2259 assign( dst64, binop(op, mkexpr(src64), unop(widen1632,mkexpr(t))) );
2260 putIReg( 2, R_EAX, unop(Iop_32to16,unop(Iop_64to32,mkexpr(dst64))) );
2261 putIReg( 2, R_EDX, unop(Iop_32to16,unop(Iop_64HIto32,mkexpr(dst64))) );
2262 break;
sewardj9690d922004-07-14 01:39:17 +00002263 }
sewardj4e82db72004-10-16 11:32:15 +00002264 case 1: {
2265 IROp widen3264 = signed_divide ? Iop_32Sto64 : Iop_32Uto64;
2266 IROp widen1632 = signed_divide ? Iop_16Sto32 : Iop_16Uto32;
2267 IROp widen816 = signed_divide ? Iop_8Sto16 : Iop_8Uto16;
2268 assign( src64, unop(widen3264, unop(widen1632, getIReg(2,R_EAX))) );
2269 assign( dst64,
2270 binop(op, mkexpr(src64),
2271 unop(widen1632, unop(widen816, mkexpr(t)))) );
2272 putIReg( 1, R_AL, unop(Iop_16to8, unop(Iop_32to16,
2273 unop(Iop_64to32,mkexpr(dst64)))) );
2274 putIReg( 1, R_AH, unop(Iop_16to8, unop(Iop_32to16,
2275 unop(Iop_64HIto32,mkexpr(dst64)))) );
2276 break;
2277 }
sewardj9690d922004-07-14 01:39:17 +00002278 default: vpanic("codegen_div(x86)");
2279 }
2280}
sewardj41f43bc2004-07-08 14:23:22 +00002281
2282
2283static
sewardje9d8a262009-07-01 08:06:34 +00002284UInt dis_Grp1 ( UChar sorb, Bool locked,
sewardj52d04912005-07-03 00:52:48 +00002285 Int delta, UChar modrm,
sewardj41f43bc2004-07-08 14:23:22 +00002286 Int am_sz, Int d_sz, Int sz, UInt d32 )
2287{
sewardj41f43bc2004-07-08 14:23:22 +00002288 Int len;
sewardjc9a43662004-11-30 18:51:59 +00002289 HChar dis_buf[50];
sewardje05c42c2004-07-08 20:25:10 +00002290 IRType ty = szToITy(sz);
2291 IRTemp dst1 = newTemp(ty);
2292 IRTemp src = newTemp(ty);
2293 IRTemp dst0 = newTemp(ty);
sewardj92d168d2004-11-15 14:22:12 +00002294 IRTemp addr = IRTemp_INVALID;
sewardj66de2272004-07-16 21:19:05 +00002295 IROp op8 = Iop_INVALID;
sewardj180e8b32004-07-29 01:40:11 +00002296 UInt mask = sz==1 ? 0xFF : (sz==2 ? 0xFFFF : 0xFFFFFFFF);
sewardj41f43bc2004-07-08 14:23:22 +00002297
2298 switch (gregOfRM(modrm)) {
sewardje05c42c2004-07-08 20:25:10 +00002299 case 0: op8 = Iop_Add8; break; case 1: op8 = Iop_Or8; break;
sewardj66de2272004-07-16 21:19:05 +00002300 case 2: break; // ADC
2301 case 3: break; // SBB
sewardje05c42c2004-07-08 20:25:10 +00002302 case 4: op8 = Iop_And8; break; case 5: op8 = Iop_Sub8; break;
2303 case 6: op8 = Iop_Xor8; break; case 7: op8 = Iop_Sub8; break;
sewardjd51dc812007-03-20 14:18:45 +00002304 /*NOTREACHED*/
sewardj41f43bc2004-07-08 14:23:22 +00002305 default: vpanic("dis_Grp1: unhandled case");
2306 }
sewardj41f43bc2004-07-08 14:23:22 +00002307
2308 if (epartIsReg(modrm)) {
2309 vassert(am_sz == 1);
2310
2311 assign(dst0, getIReg(sz,eregOfRM(modrm)));
sewardj180e8b32004-07-29 01:40:11 +00002312 assign(src, mkU(ty,d32 & mask));
sewardj41f43bc2004-07-08 14:23:22 +00002313
sewardj180e8b32004-07-29 01:40:11 +00002314 if (gregOfRM(modrm) == 2 /* ADC */) {
sewardje9d8a262009-07-01 08:06:34 +00002315 helper_ADC( sz, dst1, dst0, src,
2316 /*no store*/IRTemp_INVALID, IRTemp_INVALID, 0 );
sewardj180e8b32004-07-29 01:40:11 +00002317 } else
2318 if (gregOfRM(modrm) == 3 /* SBB */) {
sewardje9d8a262009-07-01 08:06:34 +00002319 helper_SBB( sz, dst1, dst0, src,
2320 /*no store*/IRTemp_INVALID, IRTemp_INVALID, 0 );
sewardj180e8b32004-07-29 01:40:11 +00002321 } else {
2322 assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)));
sewardj5bd4d162004-11-10 13:02:48 +00002323 if (isAddSub(op8))
sewardj2a2ba8b2004-11-08 13:14:06 +00002324 setFlags_DEP1_DEP2(op8, dst0, src, ty);
sewardjb9c5cf62004-08-24 15:10:38 +00002325 else
sewardj2a2ba8b2004-11-08 13:14:06 +00002326 setFlags_DEP1(op8, dst1, ty);
sewardj180e8b32004-07-29 01:40:11 +00002327 }
sewardj41f43bc2004-07-08 14:23:22 +00002328
2329 if (gregOfRM(modrm) < 7)
sewardje05c42c2004-07-08 20:25:10 +00002330 putIReg(sz, eregOfRM(modrm), mkexpr(dst1));
sewardj41f43bc2004-07-08 14:23:22 +00002331
2332 delta += (am_sz + d_sz);
2333 DIP("%s%c $0x%x, %s\n", nameGrp1(gregOfRM(modrm)), nameISize(sz), d32,
2334 nameIReg(sz,eregOfRM(modrm)));
2335 } else {
sewardje87b4842004-07-10 12:23:30 +00002336 addr = disAMode ( &len, sorb, delta, dis_buf);
sewardj41f43bc2004-07-08 14:23:22 +00002337
sewardj940e8c92004-07-11 16:53:24 +00002338 assign(dst0, loadLE(ty,mkexpr(addr)));
sewardj180e8b32004-07-29 01:40:11 +00002339 assign(src, mkU(ty,d32 & mask));
sewardj41f43bc2004-07-08 14:23:22 +00002340
sewardj66de2272004-07-16 21:19:05 +00002341 if (gregOfRM(modrm) == 2 /* ADC */) {
sewardje9d8a262009-07-01 08:06:34 +00002342 if (locked) {
2343 /* cas-style store */
2344 helper_ADC( sz, dst1, dst0, src,
2345 /*store*/addr, dst0/*expVal*/, guest_EIP_curr_instr );
2346 } else {
2347 /* normal store */
2348 helper_ADC( sz, dst1, dst0, src,
2349 /*store*/addr, IRTemp_INVALID, 0 );
2350 }
sewardj3af115f2004-07-14 02:46:52 +00002351 } else
sewardj66de2272004-07-16 21:19:05 +00002352 if (gregOfRM(modrm) == 3 /* SBB */) {
sewardje9d8a262009-07-01 08:06:34 +00002353 if (locked) {
2354 /* cas-style store */
2355 helper_SBB( sz, dst1, dst0, src,
2356 /*store*/addr, dst0/*expVal*/, guest_EIP_curr_instr );
2357 } else {
2358 /* normal store */
2359 helper_SBB( sz, dst1, dst0, src,
2360 /*store*/addr, IRTemp_INVALID, 0 );
2361 }
sewardj3af115f2004-07-14 02:46:52 +00002362 } else {
2363 assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)));
sewardje9d8a262009-07-01 08:06:34 +00002364 if (gregOfRM(modrm) < 7) {
2365 if (locked) {
2366 casLE( mkexpr(addr), mkexpr(dst0)/*expVal*/,
2367 mkexpr(dst1)/*newVal*/,
2368 guest_EIP_curr_instr );
2369 } else {
2370 storeLE(mkexpr(addr), mkexpr(dst1));
2371 }
2372 }
sewardj5bd4d162004-11-10 13:02:48 +00002373 if (isAddSub(op8))
sewardj2a2ba8b2004-11-08 13:14:06 +00002374 setFlags_DEP1_DEP2(op8, dst0, src, ty);
sewardjb9c5cf62004-08-24 15:10:38 +00002375 else
sewardj2a2ba8b2004-11-08 13:14:06 +00002376 setFlags_DEP1(op8, dst1, ty);
sewardj3af115f2004-07-14 02:46:52 +00002377 }
sewardj41f43bc2004-07-08 14:23:22 +00002378
sewardj41f43bc2004-07-08 14:23:22 +00002379 delta += (len+d_sz);
2380 DIP("%s%c $0x%x, %s\n", nameGrp1(gregOfRM(modrm)), nameISize(sz),
2381 d32, dis_buf);
2382 }
2383 return delta;
2384}
2385
2386
sewardj6d2638e2004-07-15 09:38:27 +00002387/* Group 2 extended opcodes. shift_expr must be an 8-bit typed
2388 expression. */
2389
sewardje90ad6a2004-07-10 19:02:10 +00002390static
sewardj52d04912005-07-03 00:52:48 +00002391UInt dis_Grp2 ( UChar sorb,
2392 Int delta, UChar modrm,
sewardj6d2638e2004-07-15 09:38:27 +00002393 Int am_sz, Int d_sz, Int sz, IRExpr* shift_expr,
florian55085f82012-11-21 00:36:55 +00002394 const HChar* shift_expr_txt, Bool* decode_OK )
sewardje90ad6a2004-07-10 19:02:10 +00002395{
2396 /* delta on entry points at the modrm byte. */
sewardjc9a43662004-11-30 18:51:59 +00002397 HChar dis_buf[50];
sewardj6d2638e2004-07-15 09:38:27 +00002398 Int len;
sewardj2eef7732005-08-23 15:41:14 +00002399 Bool isShift, isRotate, isRotateC;
sewardj6d2638e2004-07-15 09:38:27 +00002400 IRType ty = szToITy(sz);
2401 IRTemp dst0 = newTemp(ty);
2402 IRTemp dst1 = newTemp(ty);
sewardj92d168d2004-11-15 14:22:12 +00002403 IRTemp addr = IRTemp_INVALID;
sewardje90ad6a2004-07-10 19:02:10 +00002404
sewardjd51dc812007-03-20 14:18:45 +00002405 *decode_OK = True;
2406
sewardje90ad6a2004-07-10 19:02:10 +00002407 vassert(sz == 1 || sz == 2 || sz == 4);
2408
sewardje90ad6a2004-07-10 19:02:10 +00002409 /* Put value to shift/rotate in dst0. */
2410 if (epartIsReg(modrm)) {
2411 assign(dst0, getIReg(sz, eregOfRM(modrm)));
sewardj940e8c92004-07-11 16:53:24 +00002412 delta += (am_sz + d_sz);
sewardje90ad6a2004-07-10 19:02:10 +00002413 } else {
sewardj940e8c92004-07-11 16:53:24 +00002414 addr = disAMode ( &len, sorb, delta, dis_buf);
2415 assign(dst0, loadLE(ty,mkexpr(addr)));
2416 delta += len + d_sz;
sewardje90ad6a2004-07-10 19:02:10 +00002417 }
2418
2419 isShift = False;
tomd6b43fd2011-08-19 16:06:52 +00002420 switch (gregOfRM(modrm)) { case 4: case 5: case 6: case 7: isShift = True; }
sewardje90ad6a2004-07-10 19:02:10 +00002421
sewardj750f4072004-07-26 22:39:11 +00002422 isRotate = False;
2423 switch (gregOfRM(modrm)) { case 0: case 1: isRotate = True; }
2424
sewardj2eef7732005-08-23 15:41:14 +00002425 isRotateC = False;
2426 switch (gregOfRM(modrm)) { case 2: case 3: isRotateC = True; }
sewardj9aebb0c2004-10-24 19:20:43 +00002427
sewardj2eef7732005-08-23 15:41:14 +00002428 if (!isShift && !isRotate && !isRotateC) {
sewardjd51dc812007-03-20 14:18:45 +00002429 /*NOTREACHED*/
sewardj8c7f1ab2004-07-29 20:31:09 +00002430 vpanic("dis_Grp2(Reg): unhandled case(x86)");
2431 }
2432
sewardj2eef7732005-08-23 15:41:14 +00002433 if (isRotateC) {
2434 /* call a helper; these insns are so ridiculous they do not
2435 deserve better */
2436 Bool left = toBool(gregOfRM(modrm) == 2);
sewardj9aebb0c2004-10-24 19:20:43 +00002437 IRTemp r64 = newTemp(Ity_I64);
sewardjf9655262004-10-31 20:02:16 +00002438 IRExpr** args
2439 = mkIRExprVec_4( widenUto32(mkexpr(dst0)), /* thing to rotate */
2440 widenUto32(shift_expr), /* rotate amount */
sewardj2a9ad022004-11-25 02:46:58 +00002441 widenUto32(mk_x86g_calculate_eflags_all()),
sewardjf9655262004-10-31 20:02:16 +00002442 mkU32(sz) );
2443 assign( r64, mkIRExprCCall(
sewardj8ea867b2004-10-30 19:03:02 +00002444 Ity_I64,
sewardjf9655262004-10-31 20:02:16 +00002445 0/*regparm*/,
sewardj2eef7732005-08-23 15:41:14 +00002446 left ? "x86g_calculate_RCL" : "x86g_calculate_RCR",
2447 left ? &x86g_calculate_RCL : &x86g_calculate_RCR,
sewardj8ea867b2004-10-30 19:03:02 +00002448 args
sewardjf9655262004-10-31 20:02:16 +00002449 )
2450 );
sewardj9aebb0c2004-10-24 19:20:43 +00002451 /* new eflags in hi half r64; new value in lo half r64 */
2452 assign( dst1, narrowTo(ty, unop(Iop_64to32, mkexpr(r64))) );
sewardj2a9ad022004-11-25 02:46:58 +00002453 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(X86G_CC_OP_COPY) ));
sewardj2a2ba8b2004-11-08 13:14:06 +00002454 stmt( IRStmt_Put( OFFB_CC_DEP1, unop(Iop_64HIto32, mkexpr(r64)) ));
2455 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
sewardja3b7e3a2005-04-05 01:54:19 +00002456 /* Set NDEP even though it isn't used. This makes redundant-PUT
2457 elimination of previous stores to this field work better. */
2458 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
sewardj9aebb0c2004-10-24 19:20:43 +00002459 }
2460
sewardje90ad6a2004-07-10 19:02:10 +00002461 if (isShift) {
2462
sewardjc22a6fd2004-07-29 23:41:47 +00002463 IRTemp pre32 = newTemp(Ity_I32);
2464 IRTemp res32 = newTemp(Ity_I32);
2465 IRTemp res32ss = newTemp(Ity_I32);
sewardj6d2638e2004-07-15 09:38:27 +00002466 IRTemp shift_amt = newTemp(Ity_I8);
sewardjc22a6fd2004-07-29 23:41:47 +00002467 IROp op32;
sewardje90ad6a2004-07-10 19:02:10 +00002468
2469 switch (gregOfRM(modrm)) {
sewardjc22a6fd2004-07-29 23:41:47 +00002470 case 4: op32 = Iop_Shl32; break;
2471 case 5: op32 = Iop_Shr32; break;
tomd6b43fd2011-08-19 16:06:52 +00002472 case 6: op32 = Iop_Shl32; break;
sewardjc22a6fd2004-07-29 23:41:47 +00002473 case 7: op32 = Iop_Sar32; break;
sewardjd51dc812007-03-20 14:18:45 +00002474 /*NOTREACHED*/
sewardje90ad6a2004-07-10 19:02:10 +00002475 default: vpanic("dis_Grp2:shift"); break;
2476 }
2477
sewardjc22a6fd2004-07-29 23:41:47 +00002478 /* Widen the value to be shifted to 32 bits, do the shift, and
2479 narrow back down. This seems surprisingly long-winded, but
2480 unfortunately the Intel semantics requires that 8/16-bit
2481 shifts give defined results for shift values all the way up
2482 to 31, and this seems the simplest way to do it. It has the
2483 advantage that the only IR level shifts generated are of 32
2484 bit values, and the shift amount is guaranteed to be in the
2485 range 0 .. 31, thereby observing the IR semantics requiring
2486 all shift values to be in the range 0 .. 2^word_size-1. */
2487
2488 /* shift_amt = shift_expr & 31, regardless of operation size */
2489 assign( shift_amt, binop(Iop_And8, shift_expr, mkU8(31)) );
2490
2491 /* suitably widen the value to be shifted to 32 bits. */
2492 assign( pre32, op32==Iop_Sar32 ? widenSto32(mkexpr(dst0))
2493 : widenUto32(mkexpr(dst0)) );
2494
2495 /* res32 = pre32 `shift` shift_amt */
2496 assign( res32, binop(op32, mkexpr(pre32), mkexpr(shift_amt)) );
2497
2498 /* res32ss = pre32 `shift` ((shift_amt - 1) & 31) */
2499 assign( res32ss,
2500 binop(op32,
2501 mkexpr(pre32),
2502 binop(Iop_And8,
2503 binop(Iop_Sub8,
2504 mkexpr(shift_amt), mkU8(1)),
2505 mkU8(31))) );
sewardje90ad6a2004-07-10 19:02:10 +00002506
2507 /* Build the flags thunk. */
sewardj2a2ba8b2004-11-08 13:14:06 +00002508 setFlags_DEP1_DEP2_shift(op32, res32, res32ss, ty, shift_amt);
sewardjc22a6fd2004-07-29 23:41:47 +00002509
2510 /* Narrow the result back down. */
2511 assign( dst1, narrowTo(ty, mkexpr(res32)) );
sewardj750f4072004-07-26 22:39:11 +00002512
sewardj1813dbe2004-07-28 17:09:04 +00002513 } /* if (isShift) */
2514
2515 else
sewardj750f4072004-07-26 22:39:11 +00002516 if (isRotate) {
sewardj7ebbdae2004-08-26 12:30:48 +00002517 Int ccOp = ty==Ity_I8 ? 0 : (ty==Ity_I16 ? 1 : 2);
sewardj2d49b432005-02-01 00:37:06 +00002518 Bool left = toBool(gregOfRM(modrm) == 0);
sewardj7ebbdae2004-08-26 12:30:48 +00002519 IRTemp rot_amt = newTemp(Ity_I8);
2520 IRTemp rot_amt32 = newTemp(Ity_I8);
2521 IRTemp oldFlags = newTemp(Ity_I32);
sewardj750f4072004-07-26 22:39:11 +00002522
2523 /* rot_amt = shift_expr & mask */
sewardjc22a6fd2004-07-29 23:41:47 +00002524 /* By masking the rotate amount thusly, the IR-level Shl/Shr
2525 expressions never shift beyond the word size and thus remain
2526 well defined. */
sewardj7ebbdae2004-08-26 12:30:48 +00002527 assign(rot_amt32, binop(Iop_And8, shift_expr, mkU8(31)));
2528
2529 if (ty == Ity_I32)
2530 assign(rot_amt, mkexpr(rot_amt32));
2531 else
2532 assign(rot_amt, binop(Iop_And8, mkexpr(rot_amt32), mkU8(8*sz-1)));
sewardj750f4072004-07-26 22:39:11 +00002533
2534 if (left) {
sewardj1813dbe2004-07-28 17:09:04 +00002535
sewardj750f4072004-07-26 22:39:11 +00002536 /* dst1 = (dst0 << rot_amt) | (dst0 >>u (wordsize-rot_amt)) */
2537 assign(dst1,
2538 binop( mkSizedOp(ty,Iop_Or8),
2539 binop( mkSizedOp(ty,Iop_Shl8),
2540 mkexpr(dst0),
2541 mkexpr(rot_amt)
2542 ),
2543 binop( mkSizedOp(ty,Iop_Shr8),
2544 mkexpr(dst0),
2545 binop(Iop_Sub8,mkU8(8*sz), mkexpr(rot_amt))
2546 )
2547 )
2548 );
sewardj2a9ad022004-11-25 02:46:58 +00002549 ccOp += X86G_CC_OP_ROLB;
sewardj750f4072004-07-26 22:39:11 +00002550
sewardj1813dbe2004-07-28 17:09:04 +00002551 } else { /* right */
sewardj750f4072004-07-26 22:39:11 +00002552
sewardj1813dbe2004-07-28 17:09:04 +00002553 /* dst1 = (dst0 >>u rot_amt) | (dst0 << (wordsize-rot_amt)) */
2554 assign(dst1,
2555 binop( mkSizedOp(ty,Iop_Or8),
2556 binop( mkSizedOp(ty,Iop_Shr8),
2557 mkexpr(dst0),
2558 mkexpr(rot_amt)
2559 ),
2560 binop( mkSizedOp(ty,Iop_Shl8),
2561 mkexpr(dst0),
2562 binop(Iop_Sub8,mkU8(8*sz), mkexpr(rot_amt))
sewardj750f4072004-07-26 22:39:11 +00002563 )
2564 )
2565 );
sewardj2a9ad022004-11-25 02:46:58 +00002566 ccOp += X86G_CC_OP_RORB;
sewardjc22a6fd2004-07-29 23:41:47 +00002567
sewardj750f4072004-07-26 22:39:11 +00002568 }
sewardjc22a6fd2004-07-29 23:41:47 +00002569
sewardj1813dbe2004-07-28 17:09:04 +00002570 /* dst1 now holds the rotated value. Build flag thunk. We
2571 need the resulting value for this, and the previous flags.
2572 Except don't set it if the rotate count is zero. */
2573
sewardj2a9ad022004-11-25 02:46:58 +00002574 assign(oldFlags, mk_x86g_calculate_eflags_all());
sewardj1813dbe2004-07-28 17:09:04 +00002575
sewardj009230b2013-01-26 11:47:55 +00002576 /* rot_amt32 :: Ity_I8. We need to convert it to I1. */
2577 IRTemp rot_amt32b = newTemp(Ity_I1);
2578 assign(rot_amt32b, binop(Iop_CmpNE8, mkexpr(rot_amt32), mkU8(0)) );
2579
sewardj2a2ba8b2004-11-08 13:14:06 +00002580 /* CC_DEP1 is the rotated value. CC_NDEP is flags before. */
sewardj1813dbe2004-07-28 17:09:04 +00002581 stmt( IRStmt_Put( OFFB_CC_OP,
florian99dd03e2013-01-29 03:56:06 +00002582 IRExpr_ITE( mkexpr(rot_amt32b),
2583 mkU32(ccOp),
2584 IRExpr_Get(OFFB_CC_OP,Ity_I32) ) ));
sewardj2a2ba8b2004-11-08 13:14:06 +00002585 stmt( IRStmt_Put( OFFB_CC_DEP1,
florian99dd03e2013-01-29 03:56:06 +00002586 IRExpr_ITE( mkexpr(rot_amt32b),
2587 widenUto32(mkexpr(dst1)),
2588 IRExpr_Get(OFFB_CC_DEP1,Ity_I32) ) ));
sewardj2a2ba8b2004-11-08 13:14:06 +00002589 stmt( IRStmt_Put( OFFB_CC_DEP2,
florian99dd03e2013-01-29 03:56:06 +00002590 IRExpr_ITE( mkexpr(rot_amt32b),
2591 mkU32(0),
2592 IRExpr_Get(OFFB_CC_DEP2,Ity_I32) ) ));
sewardj2a2ba8b2004-11-08 13:14:06 +00002593 stmt( IRStmt_Put( OFFB_CC_NDEP,
florian99dd03e2013-01-29 03:56:06 +00002594 IRExpr_ITE( mkexpr(rot_amt32b),
2595 mkexpr(oldFlags),
2596 IRExpr_Get(OFFB_CC_NDEP,Ity_I32) ) ));
sewardj1813dbe2004-07-28 17:09:04 +00002597 } /* if (isRotate) */
sewardje90ad6a2004-07-10 19:02:10 +00002598
2599 /* Save result, and finish up. */
2600 if (epartIsReg(modrm)) {
2601 putIReg(sz, eregOfRM(modrm), mkexpr(dst1));
sewardjf48ac192004-10-29 00:41:29 +00002602 if (vex_traceflags & VEX_TRACE_FE) {
sewardje90ad6a2004-07-10 19:02:10 +00002603 vex_printf("%s%c ",
2604 nameGrp2(gregOfRM(modrm)), nameISize(sz) );
sewardj6d2638e2004-07-15 09:38:27 +00002605 if (shift_expr_txt)
2606 vex_printf("%s", shift_expr_txt);
2607 else
2608 ppIRExpr(shift_expr);
sewardje90ad6a2004-07-10 19:02:10 +00002609 vex_printf(", %s\n", nameIReg(sz,eregOfRM(modrm)));
2610 }
sewardje90ad6a2004-07-10 19:02:10 +00002611 } else {
sewardj940e8c92004-07-11 16:53:24 +00002612 storeLE(mkexpr(addr), mkexpr(dst1));
sewardjf48ac192004-10-29 00:41:29 +00002613 if (vex_traceflags & VEX_TRACE_FE) {
sewardj940e8c92004-07-11 16:53:24 +00002614 vex_printf("%s%c ",
2615 nameGrp2(gregOfRM(modrm)), nameISize(sz) );
sewardj6d2638e2004-07-15 09:38:27 +00002616 if (shift_expr_txt)
2617 vex_printf("%s", shift_expr_txt);
2618 else
2619 ppIRExpr(shift_expr);
sewardj940e8c92004-07-11 16:53:24 +00002620 vex_printf(", %s\n", dis_buf);
2621 }
sewardje90ad6a2004-07-10 19:02:10 +00002622 }
sewardje90ad6a2004-07-10 19:02:10 +00002623 return delta;
2624}
2625
2626
sewardj490ad382005-03-13 17:25:53 +00002627/* Group 8 extended opcodes (but BT/BTS/BTC/BTR only). */
2628static
sewardj52d04912005-07-03 00:52:48 +00002629UInt dis_Grp8_Imm ( UChar sorb,
sewardje9d8a262009-07-01 08:06:34 +00002630 Bool locked,
sewardj52d04912005-07-03 00:52:48 +00002631 Int delta, UChar modrm,
sewardj490ad382005-03-13 17:25:53 +00002632 Int am_sz, Int sz, UInt src_val,
2633 Bool* decode_OK )
2634{
2635 /* src_val denotes a d8.
2636 And delta on entry points at the modrm byte. */
sewardje90ad6a2004-07-10 19:02:10 +00002637
sewardj490ad382005-03-13 17:25:53 +00002638 IRType ty = szToITy(sz);
2639 IRTemp t2 = newTemp(Ity_I32);
2640 IRTemp t2m = newTemp(Ity_I32);
2641 IRTemp t_addr = IRTemp_INVALID;
2642 HChar dis_buf[50];
2643 UInt mask;
sewardjd1061ab2004-07-08 01:45:30 +00002644
sewardj490ad382005-03-13 17:25:53 +00002645 /* we're optimists :-) */
2646 *decode_OK = True;
sewardjd1061ab2004-07-08 01:45:30 +00002647
sewardj490ad382005-03-13 17:25:53 +00002648 /* Limit src_val -- the bit offset -- to something within a word.
2649 The Intel docs say that literal offsets larger than a word are
2650 masked in this way. */
2651 switch (sz) {
2652 case 2: src_val &= 15; break;
2653 case 4: src_val &= 31; break;
2654 default: *decode_OK = False; return delta;
2655 }
sewardjcf780b42004-07-13 18:42:17 +00002656
sewardj490ad382005-03-13 17:25:53 +00002657 /* Invent a mask suitable for the operation. */
2658 switch (gregOfRM(modrm)) {
2659 case 4: /* BT */ mask = 0; break;
2660 case 5: /* BTS */ mask = 1 << src_val; break;
2661 case 6: /* BTR */ mask = ~(1 << src_val); break;
2662 case 7: /* BTC */ mask = 1 << src_val; break;
2663 /* If this needs to be extended, probably simplest to make a
2664 new function to handle the other cases (0 .. 3). The
2665 Intel docs do however not indicate any use for 0 .. 3, so
2666 we don't expect this to happen. */
2667 default: *decode_OK = False; return delta;
2668 }
2669
2670 /* Fetch the value to be tested and modified into t2, which is
2671 32-bits wide regardless of sz. */
2672 if (epartIsReg(modrm)) {
2673 vassert(am_sz == 1);
sewardj5a8334e2005-03-13 19:52:45 +00002674 assign( t2, widenUto32(getIReg(sz, eregOfRM(modrm))) );
sewardj490ad382005-03-13 17:25:53 +00002675 delta += (am_sz + 1);
2676 DIP("%s%c $0x%x, %s\n", nameGrp8(gregOfRM(modrm)), nameISize(sz),
2677 src_val, nameIReg(sz,eregOfRM(modrm)));
2678 } else {
2679 Int len;
2680 t_addr = disAMode ( &len, sorb, delta, dis_buf);
2681 delta += (len+1);
2682 assign( t2, widenUto32(loadLE(ty, mkexpr(t_addr))) );
2683 DIP("%s%c $0x%x, %s\n", nameGrp8(gregOfRM(modrm)), nameISize(sz),
2684 src_val, dis_buf);
2685 }
2686
sewardj490ad382005-03-13 17:25:53 +00002687 /* Compute the new value into t2m, if non-BT. */
2688 switch (gregOfRM(modrm)) {
2689 case 4: /* BT */
2690 break;
2691 case 5: /* BTS */
2692 assign( t2m, binop(Iop_Or32, mkU32(mask), mkexpr(t2)) );
2693 break;
2694 case 6: /* BTR */
2695 assign( t2m, binop(Iop_And32, mkU32(mask), mkexpr(t2)) );
2696 break;
2697 case 7: /* BTC */
2698 assign( t2m, binop(Iop_Xor32, mkU32(mask), mkexpr(t2)) );
2699 break;
sewardjba89f4c2005-04-07 17:31:27 +00002700 default:
2701 /*NOTREACHED*/ /*the previous switch guards this*/
sewardj490ad382005-03-13 17:25:53 +00002702 vassert(0);
2703 }
2704
sewardje9d8a262009-07-01 08:06:34 +00002705 /* Write the result back, if non-BT. If the CAS fails then we
2706 side-exit from the trace at this point, and so the flag state is
2707 not affected. This is of course as required. */
sewardj490ad382005-03-13 17:25:53 +00002708 if (gregOfRM(modrm) != 4 /* BT */) {
2709 if (epartIsReg(modrm)) {
sewardje9d8a262009-07-01 08:06:34 +00002710 putIReg(sz, eregOfRM(modrm), narrowTo(ty, mkexpr(t2m)));
sewardj490ad382005-03-13 17:25:53 +00002711 } else {
sewardje9d8a262009-07-01 08:06:34 +00002712 if (locked) {
2713 casLE( mkexpr(t_addr),
2714 narrowTo(ty, mkexpr(t2))/*expd*/,
2715 narrowTo(ty, mkexpr(t2m))/*new*/,
2716 guest_EIP_curr_instr );
2717 } else {
2718 storeLE(mkexpr(t_addr), narrowTo(ty, mkexpr(t2m)));
2719 }
sewardj490ad382005-03-13 17:25:53 +00002720 }
2721 }
2722
sewardje9d8a262009-07-01 08:06:34 +00002723 /* Copy relevant bit from t2 into the carry flag. */
2724 /* Flags: C=selected bit, O,S,Z,A,P undefined, so are set to zero. */
2725 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(X86G_CC_OP_COPY) ));
2726 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
2727 stmt( IRStmt_Put(
2728 OFFB_CC_DEP1,
2729 binop(Iop_And32,
2730 binop(Iop_Shr32, mkexpr(t2), mkU8(src_val)),
2731 mkU32(1))
2732 ));
2733 /* Set NDEP even though it isn't used. This makes redundant-PUT
2734 elimination of previous stores to this field work better. */
2735 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
2736
sewardj490ad382005-03-13 17:25:53 +00002737 return delta;
2738}
sewardjcf780b42004-07-13 18:42:17 +00002739
2740
sewardj1813dbe2004-07-28 17:09:04 +00002741/* Signed/unsigned widening multiply. Generate IR to multiply the
2742 value in EAX/AX/AL by the given IRTemp, and park the result in
2743 EDX:EAX/DX:AX/AX.
sewardjcf780b42004-07-13 18:42:17 +00002744*/
sewardj1813dbe2004-07-28 17:09:04 +00002745static void codegen_mulL_A_D ( Int sz, Bool syned,
florian55085f82012-11-21 00:36:55 +00002746 IRTemp tmp, const HChar* tmp_txt )
sewardjcf780b42004-07-13 18:42:17 +00002747{
sewardjcf780b42004-07-13 18:42:17 +00002748 IRType ty = szToITy(sz);
2749 IRTemp t1 = newTemp(ty);
sewardjcf780b42004-07-13 18:42:17 +00002750
sewardj1813dbe2004-07-28 17:09:04 +00002751 assign( t1, getIReg(sz, R_EAX) );
sewardjcf780b42004-07-13 18:42:17 +00002752
2753 switch (ty) {
sewardjb81f8b32004-07-30 10:17:50 +00002754 case Ity_I32: {
2755 IRTemp res64 = newTemp(Ity_I64);
sewardj948d48b2004-11-05 19:49:09 +00002756 IRTemp resHi = newTemp(Ity_I32);
2757 IRTemp resLo = newTemp(Ity_I32);
sewardjb81f8b32004-07-30 10:17:50 +00002758 IROp mulOp = syned ? Iop_MullS32 : Iop_MullU32;
sewardj2a9ad022004-11-25 02:46:58 +00002759 UInt tBaseOp = syned ? X86G_CC_OP_SMULB : X86G_CC_OP_UMULB;
sewardj2a2ba8b2004-11-08 13:14:06 +00002760 setFlags_MUL ( Ity_I32, t1, tmp, tBaseOp );
sewardjb81f8b32004-07-30 10:17:50 +00002761 assign( res64, binop(mulOp, mkexpr(t1), mkexpr(tmp)) );
sewardj948d48b2004-11-05 19:49:09 +00002762 assign( resHi, unop(Iop_64HIto32,mkexpr(res64)));
2763 assign( resLo, unop(Iop_64to32,mkexpr(res64)));
sewardj948d48b2004-11-05 19:49:09 +00002764 putIReg(4, R_EDX, mkexpr(resHi));
2765 putIReg(4, R_EAX, mkexpr(resLo));
sewardjb81f8b32004-07-30 10:17:50 +00002766 break;
2767 }
2768 case Ity_I16: {
2769 IRTemp res32 = newTemp(Ity_I32);
sewardj948d48b2004-11-05 19:49:09 +00002770 IRTemp resHi = newTemp(Ity_I16);
2771 IRTemp resLo = newTemp(Ity_I16);
sewardjb81f8b32004-07-30 10:17:50 +00002772 IROp mulOp = syned ? Iop_MullS16 : Iop_MullU16;
sewardj2a9ad022004-11-25 02:46:58 +00002773 UInt tBaseOp = syned ? X86G_CC_OP_SMULB : X86G_CC_OP_UMULB;
sewardj2a2ba8b2004-11-08 13:14:06 +00002774 setFlags_MUL ( Ity_I16, t1, tmp, tBaseOp );
sewardjb81f8b32004-07-30 10:17:50 +00002775 assign( res32, binop(mulOp, mkexpr(t1), mkexpr(tmp)) );
sewardj948d48b2004-11-05 19:49:09 +00002776 assign( resHi, unop(Iop_32HIto16,mkexpr(res32)));
2777 assign( resLo, unop(Iop_32to16,mkexpr(res32)));
sewardj948d48b2004-11-05 19:49:09 +00002778 putIReg(2, R_EDX, mkexpr(resHi));
2779 putIReg(2, R_EAX, mkexpr(resLo));
sewardjb81f8b32004-07-30 10:17:50 +00002780 break;
2781 }
2782 case Ity_I8: {
2783 IRTemp res16 = newTemp(Ity_I16);
sewardj948d48b2004-11-05 19:49:09 +00002784 IRTemp resHi = newTemp(Ity_I8);
2785 IRTemp resLo = newTemp(Ity_I8);
sewardjb81f8b32004-07-30 10:17:50 +00002786 IROp mulOp = syned ? Iop_MullS8 : Iop_MullU8;
sewardj2a9ad022004-11-25 02:46:58 +00002787 UInt tBaseOp = syned ? X86G_CC_OP_SMULB : X86G_CC_OP_UMULB;
sewardj2a2ba8b2004-11-08 13:14:06 +00002788 setFlags_MUL ( Ity_I8, t1, tmp, tBaseOp );
sewardjb81f8b32004-07-30 10:17:50 +00002789 assign( res16, binop(mulOp, mkexpr(t1), mkexpr(tmp)) );
sewardj948d48b2004-11-05 19:49:09 +00002790 assign( resHi, unop(Iop_16HIto8,mkexpr(res16)));
2791 assign( resLo, unop(Iop_16to8,mkexpr(res16)));
sewardjb81f8b32004-07-30 10:17:50 +00002792 putIReg(2, R_EAX, mkexpr(res16));
2793 break;
2794 }
2795 default:
2796 vpanic("codegen_mulL_A_D(x86)");
sewardjcf780b42004-07-13 18:42:17 +00002797 }
sewardj1813dbe2004-07-28 17:09:04 +00002798 DIP("%s%c %s\n", syned ? "imul" : "mul", nameISize(sz), tmp_txt);
sewardjcf780b42004-07-13 18:42:17 +00002799}
2800
sewardj940e8c92004-07-11 16:53:24 +00002801
2802/* Group 3 extended opcodes. */
2803static
sewardje9d8a262009-07-01 08:06:34 +00002804UInt dis_Grp3 ( UChar sorb, Bool locked, Int sz, Int delta, Bool* decode_OK )
sewardj940e8c92004-07-11 16:53:24 +00002805{
sewardjc9a43662004-11-30 18:51:59 +00002806 UInt d32;
2807 UChar modrm;
2808 HChar dis_buf[50];
2809 Int len;
sewardjc2ac51e2004-07-12 01:03:26 +00002810 IRTemp addr;
sewardj940e8c92004-07-11 16:53:24 +00002811 IRType ty = szToITy(sz);
2812 IRTemp t1 = newTemp(ty);
sewardj940e8c92004-07-11 16:53:24 +00002813 IRTemp dst1, src, dst0;
sewardjd51dc812007-03-20 14:18:45 +00002814
2815 *decode_OK = True; /* may change this later */
2816
sewardj940e8c92004-07-11 16:53:24 +00002817 modrm = getIByte(delta);
sewardje9d8a262009-07-01 08:06:34 +00002818
2819 if (locked && (gregOfRM(modrm) != 2 && gregOfRM(modrm) != 3)) {
2820 /* LOCK prefix only allowed with not and neg subopcodes */
2821 *decode_OK = False;
2822 return delta;
2823 }
2824
sewardj940e8c92004-07-11 16:53:24 +00002825 if (epartIsReg(modrm)) {
2826 switch (gregOfRM(modrm)) {
sewardjc2ac51e2004-07-12 01:03:26 +00002827 case 0: { /* TEST */
2828 delta++; d32 = getUDisp(sz, delta); delta += sz;
sewardj5bd4d162004-11-10 13:02:48 +00002829 dst1 = newTemp(ty);
2830 assign(dst1, binop(mkSizedOp(ty,Iop_And8),
2831 getIReg(sz,eregOfRM(modrm)),
sewardjc2ac51e2004-07-12 01:03:26 +00002832 mkU(ty,d32)));
sewardj5bd4d162004-11-10 13:02:48 +00002833 setFlags_DEP1( Iop_And8, dst1, ty );
sewardjc2ac51e2004-07-12 01:03:26 +00002834 DIP("test%c $0x%x, %s\n", nameISize(sz), d32,
2835 nameIReg(sz, eregOfRM(modrm)));
2836 break;
2837 }
sewardjd51dc812007-03-20 14:18:45 +00002838 case 1: /* UNDEFINED */
2839 /* The Intel docs imply this insn is undefined and binutils
2840 agrees. Unfortunately Core 2 will run it (with who
2841 knows what result?) sandpile.org reckons it's an alias
2842 for case 0. We play safe. */
2843 *decode_OK = False;
2844 break;
sewardj940e8c92004-07-11 16:53:24 +00002845 case 2: /* NOT */
2846 delta++;
2847 putIReg(sz, eregOfRM(modrm),
2848 unop(mkSizedOp(ty,Iop_Not8),
2849 getIReg(sz, eregOfRM(modrm))));
2850 DIP("not%c %s\n", nameISize(sz), nameIReg(sz, eregOfRM(modrm)));
2851 break;
2852 case 3: /* NEG */
2853 delta++;
2854 dst0 = newTemp(ty);
2855 src = newTemp(ty);
2856 dst1 = newTemp(ty);
sewardj5bd4d162004-11-10 13:02:48 +00002857 assign(dst0, mkU(ty,0));
sewardja511afc2004-07-29 22:26:03 +00002858 assign(src, getIReg(sz,eregOfRM(modrm)));
sewardjeb17e492007-08-25 23:07:44 +00002859 assign(dst1, binop(mkSizedOp(ty,Iop_Sub8), mkexpr(dst0), mkexpr(src)));
sewardj2a2ba8b2004-11-08 13:14:06 +00002860 setFlags_DEP1_DEP2(Iop_Sub8, dst0, src, ty);
sewardj5bd4d162004-11-10 13:02:48 +00002861 putIReg(sz, eregOfRM(modrm), mkexpr(dst1));
sewardj940e8c92004-07-11 16:53:24 +00002862 DIP("neg%c %s\n", nameISize(sz), nameIReg(sz, eregOfRM(modrm)));
2863 break;
sewardjcf780b42004-07-13 18:42:17 +00002864 case 4: /* MUL (unsigned widening) */
2865 delta++;
sewardj1813dbe2004-07-28 17:09:04 +00002866 src = newTemp(ty);
sewardj5bd4d162004-11-10 13:02:48 +00002867 assign(src, getIReg(sz,eregOfRM(modrm)));
sewardj1813dbe2004-07-28 17:09:04 +00002868 codegen_mulL_A_D ( sz, False, src, nameIReg(sz,eregOfRM(modrm)) );
sewardjcf780b42004-07-13 18:42:17 +00002869 break;
sewardjcaca9d02004-07-28 07:11:32 +00002870 case 5: /* IMUL (signed widening) */
2871 delta++;
sewardj1813dbe2004-07-28 17:09:04 +00002872 src = newTemp(ty);
sewardj5bd4d162004-11-10 13:02:48 +00002873 assign(src, getIReg(sz,eregOfRM(modrm)));
sewardj1813dbe2004-07-28 17:09:04 +00002874 codegen_mulL_A_D ( sz, True, src, nameIReg(sz,eregOfRM(modrm)) );
sewardjcaca9d02004-07-28 07:11:32 +00002875 break;
sewardj68511542004-07-28 00:15:44 +00002876 case 6: /* DIV */
2877 delta++;
2878 assign( t1, getIReg(sz, eregOfRM(modrm)) );
2879 codegen_div ( sz, t1, False );
2880 DIP("div%c %s\n", nameISize(sz), nameIReg(sz, eregOfRM(modrm)));
2881 break;
sewardjcaca9d02004-07-28 07:11:32 +00002882 case 7: /* IDIV */
2883 delta++;
2884 assign( t1, getIReg(sz, eregOfRM(modrm)) );
2885 codegen_div ( sz, t1, True );
2886 DIP("idiv%c %s\n", nameISize(sz), nameIReg(sz, eregOfRM(modrm)));
2887 break;
sewardj940e8c92004-07-11 16:53:24 +00002888 default:
sewardjd51dc812007-03-20 14:18:45 +00002889 /* This can't happen - gregOfRM should return 0 .. 7 only */
sewardj940e8c92004-07-11 16:53:24 +00002890 vpanic("Grp3(x86)");
2891 }
2892 } else {
sewardjc2ac51e2004-07-12 01:03:26 +00002893 addr = disAMode ( &len, sorb, delta, dis_buf );
2894 t1 = newTemp(ty);
2895 delta += len;
2896 assign(t1, loadLE(ty,mkexpr(addr)));
2897 switch (gregOfRM(modrm)) {
2898 case 0: { /* TEST */
2899 d32 = getUDisp(sz, delta); delta += sz;
sewardj5bd4d162004-11-10 13:02:48 +00002900 dst1 = newTemp(ty);
2901 assign(dst1, binop(mkSizedOp(ty,Iop_And8),
2902 mkexpr(t1), mkU(ty,d32)));
2903 setFlags_DEP1( Iop_And8, dst1, ty );
sewardjc2ac51e2004-07-12 01:03:26 +00002904 DIP("test%c $0x%x, %s\n", nameISize(sz), d32, dis_buf);
2905 break;
2906 }
sewardjd51dc812007-03-20 14:18:45 +00002907 case 1: /* UNDEFINED */
2908 /* See comment above on R case */
2909 *decode_OK = False;
2910 break;
sewardj78fe7912004-08-20 23:38:07 +00002911 case 2: /* NOT */
sewardje9d8a262009-07-01 08:06:34 +00002912 dst1 = newTemp(ty);
2913 assign(dst1, unop(mkSizedOp(ty,Iop_Not8), mkexpr(t1)));
2914 if (locked) {
2915 casLE( mkexpr(addr), mkexpr(t1)/*expd*/, mkexpr(dst1)/*new*/,
2916 guest_EIP_curr_instr );
2917 } else {
2918 storeLE( mkexpr(addr), mkexpr(dst1) );
2919 }
sewardj78fe7912004-08-20 23:38:07 +00002920 DIP("not%c %s\n", nameISize(sz), dis_buf);
2921 break;
sewardj0c12ea82004-07-12 08:18:16 +00002922 case 3: /* NEG */
2923 dst0 = newTemp(ty);
2924 src = newTemp(ty);
2925 dst1 = newTemp(ty);
sewardj5bd4d162004-11-10 13:02:48 +00002926 assign(dst0, mkU(ty,0));
sewardja511afc2004-07-29 22:26:03 +00002927 assign(src, mkexpr(t1));
sewardje9d8a262009-07-01 08:06:34 +00002928 assign(dst1, binop(mkSizedOp(ty,Iop_Sub8),
2929 mkexpr(dst0), mkexpr(src)));
2930 if (locked) {
2931 casLE( mkexpr(addr), mkexpr(t1)/*expd*/, mkexpr(dst1)/*new*/,
2932 guest_EIP_curr_instr );
2933 } else {
2934 storeLE( mkexpr(addr), mkexpr(dst1) );
2935 }
sewardj2a2ba8b2004-11-08 13:14:06 +00002936 setFlags_DEP1_DEP2(Iop_Sub8, dst0, src, ty);
sewardj0c12ea82004-07-12 08:18:16 +00002937 DIP("neg%c %s\n", nameISize(sz), dis_buf);
2938 break;
sewardj1813dbe2004-07-28 17:09:04 +00002939 case 4: /* MUL */
2940 codegen_mulL_A_D ( sz, False, t1, dis_buf );
2941 break;
2942 case 5: /* IMUL */
2943 codegen_mulL_A_D ( sz, True, t1, dis_buf );
2944 break;
sewardj9690d922004-07-14 01:39:17 +00002945 case 6: /* DIV */
2946 codegen_div ( sz, t1, False );
2947 DIP("div%c %s\n", nameISize(sz), dis_buf);
2948 break;
sewardj1813dbe2004-07-28 17:09:04 +00002949 case 7: /* IDIV */
2950 codegen_div ( sz, t1, True );
2951 DIP("idiv%c %s\n", nameISize(sz), dis_buf);
2952 break;
sewardjc2ac51e2004-07-12 01:03:26 +00002953 default:
sewardjd51dc812007-03-20 14:18:45 +00002954 /* This can't happen - gregOfRM should return 0 .. 7 only */
sewardjc2ac51e2004-07-12 01:03:26 +00002955 vpanic("Grp3(x86)");
2956 }
sewardj940e8c92004-07-11 16:53:24 +00002957 }
2958 return delta;
2959}
2960
2961
sewardjc2ac51e2004-07-12 01:03:26 +00002962/* Group 4 extended opcodes. */
2963static
sewardje9d8a262009-07-01 08:06:34 +00002964UInt dis_Grp4 ( UChar sorb, Bool locked, Int delta, Bool* decode_OK )
sewardjc2ac51e2004-07-12 01:03:26 +00002965{
sewardjc9a43662004-11-30 18:51:59 +00002966 Int alen;
sewardjc2ac51e2004-07-12 01:03:26 +00002967 UChar modrm;
sewardjc9a43662004-11-30 18:51:59 +00002968 HChar dis_buf[50];
sewardjc2ac51e2004-07-12 01:03:26 +00002969 IRType ty = Ity_I8;
sewardj7ed22952004-07-29 00:09:58 +00002970 IRTemp t1 = newTemp(ty);
2971 IRTemp t2 = newTemp(ty);
sewardjc2ac51e2004-07-12 01:03:26 +00002972
sewardjd51dc812007-03-20 14:18:45 +00002973 *decode_OK = True;
2974
sewardjc2ac51e2004-07-12 01:03:26 +00002975 modrm = getIByte(delta);
sewardje9d8a262009-07-01 08:06:34 +00002976
2977 if (locked && (gregOfRM(modrm) != 0 && gregOfRM(modrm) != 1)) {
2978 /* LOCK prefix only allowed with inc and dec subopcodes */
2979 *decode_OK = False;
2980 return delta;
2981 }
2982
sewardjc2ac51e2004-07-12 01:03:26 +00002983 if (epartIsReg(modrm)) {
sewardjc2ac51e2004-07-12 01:03:26 +00002984 assign(t1, getIReg(1, eregOfRM(modrm)));
2985 switch (gregOfRM(modrm)) {
sewardj7ed22952004-07-29 00:09:58 +00002986 case 0: /* INC */
2987 assign(t2, binop(Iop_Add8, mkexpr(t1), mkU8(1)));
2988 putIReg(1, eregOfRM(modrm), mkexpr(t2));
2989 setFlags_INC_DEC( True, t2, ty );
2990 break;
sewardjc2ac51e2004-07-12 01:03:26 +00002991 case 1: /* DEC */
sewardjc2ac51e2004-07-12 01:03:26 +00002992 assign(t2, binop(Iop_Sub8, mkexpr(t1), mkU8(1)));
2993 putIReg(1, eregOfRM(modrm), mkexpr(t2));
2994 setFlags_INC_DEC( False, t2, ty );
2995 break;
2996 default:
sewardjd51dc812007-03-20 14:18:45 +00002997 *decode_OK = False;
2998 return delta;
sewardjc2ac51e2004-07-12 01:03:26 +00002999 }
3000 delta++;
3001 DIP("%sb %s\n", nameGrp4(gregOfRM(modrm)),
3002 nameIReg(1, eregOfRM(modrm)));
3003 } else {
sewardj7ed22952004-07-29 00:09:58 +00003004 IRTemp addr = disAMode ( &alen, sorb, delta, dis_buf );
3005 assign( t1, loadLE(ty, mkexpr(addr)) );
3006 switch (gregOfRM(modrm)) {
sewardj588ea762004-09-10 18:56:32 +00003007 case 0: /* INC */
3008 assign(t2, binop(Iop_Add8, mkexpr(t1), mkU8(1)));
sewardje9d8a262009-07-01 08:06:34 +00003009 if (locked) {
3010 casLE( mkexpr(addr), mkexpr(t1)/*expd*/, mkexpr(t2)/*new*/,
3011 guest_EIP_curr_instr );
3012 } else {
3013 storeLE( mkexpr(addr), mkexpr(t2) );
3014 }
sewardj588ea762004-09-10 18:56:32 +00003015 setFlags_INC_DEC( True, t2, ty );
3016 break;
sewardj7ed22952004-07-29 00:09:58 +00003017 case 1: /* DEC */
3018 assign(t2, binop(Iop_Sub8, mkexpr(t1), mkU8(1)));
sewardje9d8a262009-07-01 08:06:34 +00003019 if (locked) {
3020 casLE( mkexpr(addr), mkexpr(t1)/*expd*/, mkexpr(t2)/*new*/,
3021 guest_EIP_curr_instr );
3022 } else {
3023 storeLE( mkexpr(addr), mkexpr(t2) );
3024 }
sewardj7ed22952004-07-29 00:09:58 +00003025 setFlags_INC_DEC( False, t2, ty );
3026 break;
3027 default:
sewardjd51dc812007-03-20 14:18:45 +00003028 *decode_OK = False;
3029 return delta;
sewardj7ed22952004-07-29 00:09:58 +00003030 }
3031 delta += alen;
3032 DIP("%sb %s\n", nameGrp4(gregOfRM(modrm)), dis_buf);
sewardjc2ac51e2004-07-12 01:03:26 +00003033 }
3034 return delta;
3035}
sewardj0611d802004-07-11 02:37:54 +00003036
3037
3038/* Group 5 extended opcodes. */
3039static
sewardje9d8a262009-07-01 08:06:34 +00003040UInt dis_Grp5 ( UChar sorb, Bool locked, Int sz, Int delta,
sewardjc6f970f2012-04-02 21:54:49 +00003041 /*MOD*/DisResult* dres, /*OUT*/Bool* decode_OK )
sewardj0611d802004-07-11 02:37:54 +00003042{
3043 Int len;
3044 UChar modrm;
sewardjc9a43662004-11-30 18:51:59 +00003045 HChar dis_buf[50];
sewardj92d168d2004-11-15 14:22:12 +00003046 IRTemp addr = IRTemp_INVALID;
sewardj0611d802004-07-11 02:37:54 +00003047 IRType ty = szToITy(sz);
3048 IRTemp t1 = newTemp(ty);
sewardj92d168d2004-11-15 14:22:12 +00003049 IRTemp t2 = IRTemp_INVALID;
sewardj0611d802004-07-11 02:37:54 +00003050
sewardjd51dc812007-03-20 14:18:45 +00003051 *decode_OK = True;
3052
sewardj0611d802004-07-11 02:37:54 +00003053 modrm = getIByte(delta);
sewardje9d8a262009-07-01 08:06:34 +00003054
3055 if (locked && (gregOfRM(modrm) != 0 && gregOfRM(modrm) != 1)) {
3056 /* LOCK prefix only allowed with inc and dec subopcodes */
3057 *decode_OK = False;
3058 return delta;
3059 }
3060
sewardj0611d802004-07-11 02:37:54 +00003061 if (epartIsReg(modrm)) {
sewardj940e8c92004-07-11 16:53:24 +00003062 assign(t1, getIReg(sz,eregOfRM(modrm)));
sewardj0611d802004-07-11 02:37:54 +00003063 switch (gregOfRM(modrm)) {
sewardj59ff5d42005-10-05 10:39:58 +00003064 case 0: /* INC */
3065 vassert(sz == 2 || sz == 4);
3066 t2 = newTemp(ty);
3067 assign(t2, binop(mkSizedOp(ty,Iop_Add8),
3068 mkexpr(t1), mkU(ty,1)));
3069 setFlags_INC_DEC( True, t2, ty );
3070 putIReg(sz,eregOfRM(modrm),mkexpr(t2));
3071 break;
3072 case 1: /* DEC */
3073 vassert(sz == 2 || sz == 4);
3074 t2 = newTemp(ty);
3075 assign(t2, binop(mkSizedOp(ty,Iop_Sub8),
3076 mkexpr(t1), mkU(ty,1)));
3077 setFlags_INC_DEC( False, t2, ty );
3078 putIReg(sz,eregOfRM(modrm),mkexpr(t2));
3079 break;
sewardjc2ac51e2004-07-12 01:03:26 +00003080 case 2: /* call Ev */
3081 vassert(sz == 4);
3082 t2 = newTemp(Ity_I32);
3083 assign(t2, binop(Iop_Sub32, getIReg(4,R_ESP), mkU32(4)));
3084 putIReg(4, R_ESP, mkexpr(t2));
sewardj9e6491a2005-07-02 19:24:10 +00003085 storeLE( mkexpr(t2), mkU32(guest_EIP_bbstart+delta+1));
sewardjc6f970f2012-04-02 21:54:49 +00003086 jmp_treg(dres, Ijk_Call, t1);
3087 vassert(dres->whatNext == Dis_StopHere);
sewardjc2ac51e2004-07-12 01:03:26 +00003088 break;
sewardj0611d802004-07-11 02:37:54 +00003089 case 4: /* jmp Ev */
3090 vassert(sz == 4);
sewardjc6f970f2012-04-02 21:54:49 +00003091 jmp_treg(dres, Ijk_Boring, t1);
3092 vassert(dres->whatNext == Dis_StopHere);
sewardj0611d802004-07-11 02:37:54 +00003093 break;
sewardj28905822006-11-18 22:56:46 +00003094 case 6: /* PUSH Ev */
3095 vassert(sz == 4 || sz == 2);
3096 t2 = newTemp(Ity_I32);
3097 assign( t2, binop(Iop_Sub32,getIReg(4,R_ESP),mkU32(sz)) );
3098 putIReg(4, R_ESP, mkexpr(t2) );
3099 storeLE( mkexpr(t2), mkexpr(t1) );
3100 break;
sewardj0611d802004-07-11 02:37:54 +00003101 default:
sewardjd51dc812007-03-20 14:18:45 +00003102 *decode_OK = False;
3103 return delta;
sewardj0611d802004-07-11 02:37:54 +00003104 }
3105 delta++;
3106 DIP("%s%c %s\n", nameGrp5(gregOfRM(modrm)),
3107 nameISize(sz), nameIReg(sz, eregOfRM(modrm)));
3108 } else {
3109 addr = disAMode ( &len, sorb, delta, dis_buf );
sewardj940e8c92004-07-11 16:53:24 +00003110 assign(t1, loadLE(ty,mkexpr(addr)));
sewardj0611d802004-07-11 02:37:54 +00003111 switch (gregOfRM(modrm)) {
3112 case 0: /* INC */
3113 t2 = newTemp(ty);
3114 assign(t2, binop(mkSizedOp(ty,Iop_Add8),
3115 mkexpr(t1), mkU(ty,1)));
sewardje9d8a262009-07-01 08:06:34 +00003116 if (locked) {
3117 casLE( mkexpr(addr),
3118 mkexpr(t1), mkexpr(t2), guest_EIP_curr_instr );
3119 } else {
3120 storeLE(mkexpr(addr),mkexpr(t2));
3121 }
sewardj0611d802004-07-11 02:37:54 +00003122 setFlags_INC_DEC( True, t2, ty );
sewardj0611d802004-07-11 02:37:54 +00003123 break;
sewardjc2ac51e2004-07-12 01:03:26 +00003124 case 1: /* DEC */
3125 t2 = newTemp(ty);
3126 assign(t2, binop(mkSizedOp(ty,Iop_Sub8),
3127 mkexpr(t1), mkU(ty,1)));
sewardje9d8a262009-07-01 08:06:34 +00003128 if (locked) {
3129 casLE( mkexpr(addr),
3130 mkexpr(t1), mkexpr(t2), guest_EIP_curr_instr );
3131 } else {
3132 storeLE(mkexpr(addr),mkexpr(t2));
3133 }
sewardjc2ac51e2004-07-12 01:03:26 +00003134 setFlags_INC_DEC( False, t2, ty );
sewardjc2ac51e2004-07-12 01:03:26 +00003135 break;
sewardj77b86be2004-07-11 13:28:24 +00003136 case 2: /* call Ev */
3137 vassert(sz == 4);
3138 t2 = newTemp(Ity_I32);
3139 assign(t2, binop(Iop_Sub32, getIReg(4,R_ESP), mkU32(4)));
3140 putIReg(4, R_ESP, mkexpr(t2));
sewardj9e6491a2005-07-02 19:24:10 +00003141 storeLE( mkexpr(t2), mkU32(guest_EIP_bbstart+delta+len));
sewardjc6f970f2012-04-02 21:54:49 +00003142 jmp_treg(dres, Ijk_Call, t1);
3143 vassert(dres->whatNext == Dis_StopHere);
sewardj77b86be2004-07-11 13:28:24 +00003144 break;
3145 case 4: /* JMP Ev */
3146 vassert(sz == 4);
sewardjc6f970f2012-04-02 21:54:49 +00003147 jmp_treg(dres, Ijk_Boring, t1);
3148 vassert(dres->whatNext == Dis_StopHere);
sewardj77b86be2004-07-11 13:28:24 +00003149 break;
sewardj0c12ea82004-07-12 08:18:16 +00003150 case 6: /* PUSH Ev */
3151 vassert(sz == 4 || sz == 2);
3152 t2 = newTemp(Ity_I32);
3153 assign( t2, binop(Iop_Sub32,getIReg(4,R_ESP),mkU32(sz)) );
3154 putIReg(4, R_ESP, mkexpr(t2) );
sewardj5bd4d162004-11-10 13:02:48 +00003155 storeLE( mkexpr(t2), mkexpr(t1) );
sewardj0c12ea82004-07-12 08:18:16 +00003156 break;
sewardj0611d802004-07-11 02:37:54 +00003157 default:
sewardjd51dc812007-03-20 14:18:45 +00003158 *decode_OK = False;
3159 return delta;
sewardj0611d802004-07-11 02:37:54 +00003160 }
3161 delta += len;
3162 DIP("%s%c %s\n", nameGrp5(gregOfRM(modrm)),
3163 nameISize(sz), dis_buf);
3164 }
3165 return delta;
3166}
3167
sewardj464efa42004-11-19 22:17:29 +00003168
sewardj64e1d652004-07-12 14:00:46 +00003169/*------------------------------------------------------------*/
3170/*--- Disassembling string ops (including REP prefixes) ---*/
3171/*------------------------------------------------------------*/
3172
3173/* Code shared by all the string ops */
3174static
Elliott Hughesed398002017-06-21 14:41:24 -07003175void dis_string_op_increment(Int sz, IRTemp t_inc)
sewardj64e1d652004-07-12 14:00:46 +00003176{
3177 if (sz == 4 || sz == 2) {
3178 assign( t_inc,
3179 binop(Iop_Shl32, IRExpr_Get( OFFB_DFLAG, Ity_I32 ),
sewardj6d2638e2004-07-15 09:38:27 +00003180 mkU8(sz/2) ) );
sewardj64e1d652004-07-12 14:00:46 +00003181 } else {
3182 assign( t_inc,
3183 IRExpr_Get( OFFB_DFLAG, Ity_I32 ) );
3184 }
3185}
3186
sewardj64e1d652004-07-12 14:00:46 +00003187static
3188void dis_string_op( void (*dis_OP)( Int, IRTemp ),
florian55085f82012-11-21 00:36:55 +00003189 Int sz, const HChar* name, UChar sorb )
sewardj64e1d652004-07-12 14:00:46 +00003190{
3191 IRTemp t_inc = newTemp(Ity_I32);
sewardj9c3b25a2007-04-05 15:06:56 +00003192 vassert(sorb == 0); /* hmm. so what was the point of passing it in? */
sewardj64e1d652004-07-12 14:00:46 +00003193 dis_string_op_increment(sz, t_inc);
3194 dis_OP( sz, t_inc );
3195 DIP("%s%c\n", name, nameISize(sz));
3196}
sewardj64e1d652004-07-12 14:00:46 +00003197
3198static
3199void dis_MOVS ( Int sz, IRTemp t_inc )
3200{
3201 IRType ty = szToITy(sz);
sewardj64e1d652004-07-12 14:00:46 +00003202 IRTemp td = newTemp(Ity_I32); /* EDI */
3203 IRTemp ts = newTemp(Ity_I32); /* ESI */
3204
sewardj64e1d652004-07-12 14:00:46 +00003205 assign( td, getIReg(4, R_EDI) );
3206 assign( ts, getIReg(4, R_ESI) );
3207
sewardj64e1d652004-07-12 14:00:46 +00003208 storeLE( mkexpr(td), loadLE(ty,mkexpr(ts)) );
3209
sewardj64e1d652004-07-12 14:00:46 +00003210 putIReg( 4, R_EDI, binop(Iop_Add32, mkexpr(td), mkexpr(t_inc)) );
3211 putIReg( 4, R_ESI, binop(Iop_Add32, mkexpr(ts), mkexpr(t_inc)) );
3212}
3213
sewardj10ca4eb2005-05-30 11:19:54 +00003214static
3215void dis_LODS ( Int sz, IRTemp t_inc )
3216{
3217 IRType ty = szToITy(sz);
3218 IRTemp ts = newTemp(Ity_I32); /* ESI */
3219
3220 assign( ts, getIReg(4, R_ESI) );
3221
3222 putIReg( sz, R_EAX, loadLE(ty, mkexpr(ts)) );
3223
3224 putIReg( 4, R_ESI, binop(Iop_Add32, mkexpr(ts), mkexpr(t_inc)) );
3225}
sewardj64e1d652004-07-12 14:00:46 +00003226
3227static
3228void dis_STOS ( Int sz, IRTemp t_inc )
3229{
3230 IRType ty = szToITy(sz);
3231 IRTemp ta = newTemp(ty); /* EAX */
3232 IRTemp td = newTemp(Ity_I32); /* EDI */
3233
sewardj64e1d652004-07-12 14:00:46 +00003234 assign( ta, getIReg(sz, R_EAX) );
sewardj64e1d652004-07-12 14:00:46 +00003235 assign( td, getIReg(4, R_EDI) );
3236
sewardj6d2638e2004-07-15 09:38:27 +00003237 storeLE( mkexpr(td), mkexpr(ta) );
sewardj64e1d652004-07-12 14:00:46 +00003238
sewardj64e1d652004-07-12 14:00:46 +00003239 putIReg( 4, R_EDI, binop(Iop_Add32, mkexpr(td), mkexpr(t_inc)) );
3240}
3241
3242static
3243void dis_CMPS ( Int sz, IRTemp t_inc )
3244{
3245 IRType ty = szToITy(sz);
sewardj6d2638e2004-07-15 09:38:27 +00003246 IRTemp tdv = newTemp(ty); /* (EDI) */
3247 IRTemp tsv = newTemp(ty); /* (ESI) */
sewardj64e1d652004-07-12 14:00:46 +00003248 IRTemp td = newTemp(Ity_I32); /* EDI */
3249 IRTemp ts = newTemp(Ity_I32); /* ESI */
3250
sewardj64e1d652004-07-12 14:00:46 +00003251 assign( td, getIReg(4, R_EDI) );
sewardj64e1d652004-07-12 14:00:46 +00003252 assign( ts, getIReg(4, R_ESI) );
3253
sewardj64e1d652004-07-12 14:00:46 +00003254 assign( tdv, loadLE(ty,mkexpr(td)) );
sewardjb9c5cf62004-08-24 15:10:38 +00003255 assign( tsv, loadLE(ty,mkexpr(ts)) );
sewardj64e1d652004-07-12 14:00:46 +00003256
sewardj2a2ba8b2004-11-08 13:14:06 +00003257 setFlags_DEP1_DEP2 ( Iop_Sub8, tsv, tdv, ty );
sewardj64e1d652004-07-12 14:00:46 +00003258
sewardj64e1d652004-07-12 14:00:46 +00003259 putIReg(4, R_EDI, binop(Iop_Add32, mkexpr(td), mkexpr(t_inc)) );
sewardj64e1d652004-07-12 14:00:46 +00003260 putIReg(4, R_ESI, binop(Iop_Add32, mkexpr(ts), mkexpr(t_inc)) );
3261}
3262
sewardj64e1d652004-07-12 14:00:46 +00003263static
3264void dis_SCAS ( Int sz, IRTemp t_inc )
3265{
3266 IRType ty = szToITy(sz);
sewardj82292882004-07-27 00:15:59 +00003267 IRTemp ta = newTemp(ty); /* EAX */
sewardj64e1d652004-07-12 14:00:46 +00003268 IRTemp td = newTemp(Ity_I32); /* EDI */
3269 IRTemp tdv = newTemp(ty); /* (EDI) */
3270
sewardjb9c5cf62004-08-24 15:10:38 +00003271 assign( ta, getIReg(sz, R_EAX) );
sewardj64e1d652004-07-12 14:00:46 +00003272 assign( td, getIReg(4, R_EDI) );
3273
sewardj64e1d652004-07-12 14:00:46 +00003274 assign( tdv, loadLE(ty,mkexpr(td)) );
sewardj2a2ba8b2004-11-08 13:14:06 +00003275 setFlags_DEP1_DEP2 ( Iop_Sub8, ta, tdv, ty );
sewardj64e1d652004-07-12 14:00:46 +00003276
sewardj64e1d652004-07-12 14:00:46 +00003277 putIReg(4, R_EDI, binop(Iop_Add32, mkexpr(td), mkexpr(t_inc)) );
3278}
sewardj82292882004-07-27 00:15:59 +00003279
sewardj64e1d652004-07-12 14:00:46 +00003280
3281/* Wrap the appropriate string op inside a REP/REPE/REPNE.
3282 We assume the insn is the last one in the basic block, and so emit a jump
3283 to the next insn, rather than just falling through. */
3284static
sewardjc6f970f2012-04-02 21:54:49 +00003285void dis_REP_op ( /*MOD*/DisResult* dres,
3286 X86Condcode cond,
sewardj64e1d652004-07-12 14:00:46 +00003287 void (*dis_OP)(Int, IRTemp),
florian55085f82012-11-21 00:36:55 +00003288 Int sz, Addr32 eip, Addr32 eip_next, const HChar* name )
sewardj64e1d652004-07-12 14:00:46 +00003289{
3290 IRTemp t_inc = newTemp(Ity_I32);
3291 IRTemp tc = newTemp(Ity_I32); /* ECX */
3292
sewardj64e1d652004-07-12 14:00:46 +00003293 assign( tc, getIReg(4,R_ECX) );
3294
sewardj64e1d652004-07-12 14:00:46 +00003295 stmt( IRStmt_Exit( binop(Iop_CmpEQ32,mkexpr(tc),mkU32(0)),
sewardj893aada2004-11-29 19:57:54 +00003296 Ijk_Boring,
sewardjc6f970f2012-04-02 21:54:49 +00003297 IRConst_U32(eip_next), OFFB_EIP ) );
sewardj64e1d652004-07-12 14:00:46 +00003298
sewardj64e1d652004-07-12 14:00:46 +00003299 putIReg(4, R_ECX, binop(Iop_Sub32, mkexpr(tc), mkU32(1)) );
3300
3301 dis_string_op_increment(sz, t_inc);
3302 dis_OP (sz, t_inc);
3303
sewardj2a9ad022004-11-25 02:46:58 +00003304 if (cond == X86CondAlways) {
sewardjc6f970f2012-04-02 21:54:49 +00003305 jmp_lit(dres, Ijk_Boring, eip);
3306 vassert(dres->whatNext == Dis_StopHere);
sewardj64e1d652004-07-12 14:00:46 +00003307 } else {
sewardj2a9ad022004-11-25 02:46:58 +00003308 stmt( IRStmt_Exit( mk_x86g_calculate_condition(cond),
sewardj893aada2004-11-29 19:57:54 +00003309 Ijk_Boring,
sewardjc6f970f2012-04-02 21:54:49 +00003310 IRConst_U32(eip), OFFB_EIP ) );
3311 jmp_lit(dres, Ijk_Boring, eip_next);
3312 vassert(dres->whatNext == Dis_StopHere);
sewardj64e1d652004-07-12 14:00:46 +00003313 }
3314 DIP("%s%c\n", name, nameISize(sz));
3315}
3316
sewardj464efa42004-11-19 22:17:29 +00003317
sewardj64e1d652004-07-12 14:00:46 +00003318/*------------------------------------------------------------*/
3319/*--- Arithmetic, etc. ---*/
3320/*------------------------------------------------------------*/
3321
sewardj2a2ba8b2004-11-08 13:14:06 +00003322/* IMUL E, G. Supplied eip points to the modR/M byte. */
sewardjcf780b42004-07-13 18:42:17 +00003323static
3324UInt dis_mul_E_G ( UChar sorb,
3325 Int size,
sewardj52d04912005-07-03 00:52:48 +00003326 Int delta0 )
sewardjcf780b42004-07-13 18:42:17 +00003327{
sewardj71a65362004-07-28 01:48:34 +00003328 Int alen;
sewardjc9a43662004-11-30 18:51:59 +00003329 HChar dis_buf[50];
sewardjcf780b42004-07-13 18:42:17 +00003330 UChar rm = getIByte(delta0);
3331 IRType ty = szToITy(size);
sewardj6d2638e2004-07-15 09:38:27 +00003332 IRTemp te = newTemp(ty);
3333 IRTemp tg = newTemp(ty);
sewardj948d48b2004-11-05 19:49:09 +00003334 IRTemp resLo = newTemp(ty);
sewardj71a65362004-07-28 01:48:34 +00003335
sewardj948d48b2004-11-05 19:49:09 +00003336 assign( tg, getIReg(size, gregOfRM(rm)) );
sewardjcf780b42004-07-13 18:42:17 +00003337 if (epartIsReg(rm)) {
sewardjcf780b42004-07-13 18:42:17 +00003338 assign( te, getIReg(size, eregOfRM(rm)) );
sewardj948d48b2004-11-05 19:49:09 +00003339 } else {
3340 IRTemp addr = disAMode( &alen, sorb, delta0, dis_buf );
3341 assign( te, loadLE(ty,mkexpr(addr)) );
3342 }
sewardjcf780b42004-07-13 18:42:17 +00003343
sewardj2a9ad022004-11-25 02:46:58 +00003344 setFlags_MUL ( ty, te, tg, X86G_CC_OP_SMULB );
sewardj948d48b2004-11-05 19:49:09 +00003345
sewardj2a2ba8b2004-11-08 13:14:06 +00003346 assign( resLo, binop( mkSizedOp(ty, Iop_Mul8), mkexpr(te), mkexpr(tg) ) );
sewardj948d48b2004-11-05 19:49:09 +00003347
3348 putIReg(size, gregOfRM(rm), mkexpr(resLo) );
3349
3350 if (epartIsReg(rm)) {
sewardj2a2ba8b2004-11-08 13:14:06 +00003351 DIP("imul%c %s, %s\n", nameISize(size),
3352 nameIReg(size,eregOfRM(rm)),
3353 nameIReg(size,gregOfRM(rm)));
sewardjcf780b42004-07-13 18:42:17 +00003354 return 1+delta0;
3355 } else {
sewardj2a2ba8b2004-11-08 13:14:06 +00003356 DIP("imul%c %s, %s\n", nameISize(size),
3357 dis_buf, nameIReg(size,gregOfRM(rm)));
sewardj71a65362004-07-28 01:48:34 +00003358 return alen+delta0;
sewardjcf780b42004-07-13 18:42:17 +00003359 }
3360}
3361
3362
sewardj1813dbe2004-07-28 17:09:04 +00003363/* IMUL I * E -> G. Supplied eip points to the modR/M byte. */
3364static
3365UInt dis_imul_I_E_G ( UChar sorb,
3366 Int size,
sewardj52d04912005-07-03 00:52:48 +00003367 Int delta,
sewardj1813dbe2004-07-28 17:09:04 +00003368 Int litsize )
3369{
sewardj883b00b2004-09-11 09:30:24 +00003370 Int d32, alen;
sewardjc9a43662004-11-30 18:51:59 +00003371 HChar dis_buf[50];
sewardjb81f8b32004-07-30 10:17:50 +00003372 UChar rm = getIByte(delta);
sewardj1813dbe2004-07-28 17:09:04 +00003373 IRType ty = szToITy(size);
3374 IRTemp te = newTemp(ty);
3375 IRTemp tl = newTemp(ty);
sewardj948d48b2004-11-05 19:49:09 +00003376 IRTemp resLo = newTemp(ty);
sewardj1813dbe2004-07-28 17:09:04 +00003377
sewardjb81f8b32004-07-30 10:17:50 +00003378 vassert(size == 1 || size == 2 || size == 4);
3379
sewardj1813dbe2004-07-28 17:09:04 +00003380 if (epartIsReg(rm)) {
3381 assign(te, getIReg(size, eregOfRM(rm)));
3382 delta++;
3383 } else {
sewardj883b00b2004-09-11 09:30:24 +00003384 IRTemp addr = disAMode( &alen, sorb, delta, dis_buf );
3385 assign(te, loadLE(ty, mkexpr(addr)));
3386 delta += alen;
sewardj1813dbe2004-07-28 17:09:04 +00003387 }
3388 d32 = getSDisp(litsize,delta);
3389 delta += litsize;
3390
sewardjb81f8b32004-07-30 10:17:50 +00003391 if (size == 1) d32 &= 0xFF;
3392 if (size == 2) d32 &= 0xFFFF;
3393
sewardj1813dbe2004-07-28 17:09:04 +00003394 assign(tl, mkU(ty,d32));
sewardj948d48b2004-11-05 19:49:09 +00003395
sewardj2a2ba8b2004-11-08 13:14:06 +00003396 assign( resLo, binop( mkSizedOp(ty, Iop_Mul8), mkexpr(te), mkexpr(tl) ));
sewardj948d48b2004-11-05 19:49:09 +00003397
sewardj2a9ad022004-11-25 02:46:58 +00003398 setFlags_MUL ( ty, te, tl, X86G_CC_OP_SMULB );
sewardj948d48b2004-11-05 19:49:09 +00003399
3400 putIReg(size, gregOfRM(rm), mkexpr(resLo));
sewardj1813dbe2004-07-28 17:09:04 +00003401
3402 DIP("imul %d, %s, %s\n", d32,
3403 ( epartIsReg(rm) ? nameIReg(size,eregOfRM(rm)) : dis_buf ),
3404 nameIReg(size,gregOfRM(rm)) );
3405 return delta;
sewardj948d48b2004-11-05 19:49:09 +00003406}
sewardj1813dbe2004-07-28 17:09:04 +00003407
3408
sewardj9a660ea2010-07-29 11:34:38 +00003409/* Generate an IR sequence to do a count-leading-zeroes operation on
3410 the supplied IRTemp, and return a new IRTemp holding the result.
3411 'ty' may be Ity_I16 or Ity_I32 only. In the case where the
3412 argument is zero, return the number of bits in the word (the
3413 natural semantics). */
3414static IRTemp gen_LZCNT ( IRType ty, IRTemp src )
3415{
3416 vassert(ty == Ity_I32 || ty == Ity_I16);
3417
3418 IRTemp src32 = newTemp(Ity_I32);
3419 assign(src32, widenUto32( mkexpr(src) ));
3420
3421 IRTemp src32x = newTemp(Ity_I32);
3422 assign(src32x,
3423 binop(Iop_Shl32, mkexpr(src32),
3424 mkU8(32 - 8 * sizeofIRType(ty))));
3425
3426 // Clz32 has undefined semantics when its input is zero, so
3427 // special-case around that.
3428 IRTemp res32 = newTemp(Ity_I32);
3429 assign(res32,
florian99dd03e2013-01-29 03:56:06 +00003430 IRExpr_ITE(
sewardj009230b2013-01-26 11:47:55 +00003431 binop(Iop_CmpEQ32, mkexpr(src32x), mkU32(0)),
florian99dd03e2013-01-29 03:56:06 +00003432 mkU32(8 * sizeofIRType(ty)),
3433 unop(Iop_Clz32, mkexpr(src32x))
sewardj9a660ea2010-07-29 11:34:38 +00003434 ));
3435
3436 IRTemp res = newTemp(ty);
3437 assign(res, narrowTo(ty, mkexpr(res32)));
3438 return res;
3439}
3440
3441
sewardjd1725d12004-08-12 20:46:53 +00003442/*------------------------------------------------------------*/
sewardj464efa42004-11-19 22:17:29 +00003443/*--- ---*/
3444/*--- x87 FLOATING POINT INSTRUCTIONS ---*/
3445/*--- ---*/
sewardjd1725d12004-08-12 20:46:53 +00003446/*------------------------------------------------------------*/
3447
sewardj207557a2004-08-27 12:00:18 +00003448/* --- Helper functions for dealing with the register stack. --- */
3449
sewardj893aada2004-11-29 19:57:54 +00003450/* --- Set the emulation-warning pseudo-register. --- */
3451
3452static void put_emwarn ( IRExpr* e /* :: Ity_I32 */ )
3453{
sewardjdd40fdf2006-12-24 02:20:24 +00003454 vassert(typeOfIRExpr(irsb->tyenv, e) == Ity_I32);
florian6ef84be2012-08-26 03:20:07 +00003455 stmt( IRStmt_Put( OFFB_EMNOTE, e ) );
sewardj893aada2004-11-29 19:57:54 +00003456}
3457
sewardj17442fe2004-09-20 14:54:28 +00003458/* --- Produce an IRExpr* denoting a 64-bit QNaN. --- */
sewardj207557a2004-08-27 12:00:18 +00003459
sewardj17442fe2004-09-20 14:54:28 +00003460static IRExpr* mkQNaN64 ( void )
sewardj207557a2004-08-27 12:00:18 +00003461{
sewardj17442fe2004-09-20 14:54:28 +00003462 /* QNaN is 0 2047 1 0(51times)
3463 == 0b 11111111111b 1 0(51times)
3464 == 0x7FF8 0000 0000 0000
3465 */
3466 return IRExpr_Const(IRConst_F64i(0x7FF8000000000000ULL));
sewardj207557a2004-08-27 12:00:18 +00003467}
3468
sewardj893aada2004-11-29 19:57:54 +00003469/* --------- Get/put the top-of-stack pointer. --------- */
sewardjd1725d12004-08-12 20:46:53 +00003470
3471static IRExpr* get_ftop ( void )
3472{
3473 return IRExpr_Get( OFFB_FTOP, Ity_I32 );
3474}
3475
sewardj207557a2004-08-27 12:00:18 +00003476static void put_ftop ( IRExpr* e )
sewardjd1725d12004-08-12 20:46:53 +00003477{
sewardjdd40fdf2006-12-24 02:20:24 +00003478 vassert(typeOfIRExpr(irsb->tyenv, e) == Ity_I32);
sewardj207557a2004-08-27 12:00:18 +00003479 stmt( IRStmt_Put( OFFB_FTOP, e ) );
sewardjd1725d12004-08-12 20:46:53 +00003480}
3481
sewardj893aada2004-11-29 19:57:54 +00003482/* --------- Get/put the C3210 bits. --------- */
sewardjbdc7d212004-09-09 02:46:40 +00003483
sewardjc4be80c2004-09-10 16:17:45 +00003484static IRExpr* get_C3210 ( void )
sewardjbdc7d212004-09-09 02:46:40 +00003485{
sewardjc4be80c2004-09-10 16:17:45 +00003486 return IRExpr_Get( OFFB_FC3210, Ity_I32 );
sewardjbdc7d212004-09-09 02:46:40 +00003487}
3488
sewardjc4be80c2004-09-10 16:17:45 +00003489static void put_C3210 ( IRExpr* e )
sewardjbdc7d212004-09-09 02:46:40 +00003490{
sewardjc4be80c2004-09-10 16:17:45 +00003491 stmt( IRStmt_Put( OFFB_FC3210, e ) );
sewardjbdc7d212004-09-09 02:46:40 +00003492}
sewardjd1725d12004-08-12 20:46:53 +00003493
sewardj893aada2004-11-29 19:57:54 +00003494/* --------- Get/put the FPU rounding mode. --------- */
sewardjd01a9632004-11-30 13:18:37 +00003495static IRExpr* /* :: Ity_I32 */ get_fpround ( void )
sewardj8f3debf2004-09-08 23:42:23 +00003496{
sewardjd01a9632004-11-30 13:18:37 +00003497 return IRExpr_Get( OFFB_FPROUND, Ity_I32 );
sewardj8f3debf2004-09-08 23:42:23 +00003498}
3499
sewardjd01a9632004-11-30 13:18:37 +00003500static void put_fpround ( IRExpr* /* :: Ity_I32 */ e )
sewardj8f3debf2004-09-08 23:42:23 +00003501{
sewardjd01a9632004-11-30 13:18:37 +00003502 stmt( IRStmt_Put( OFFB_FPROUND, e ) );
sewardj8f3debf2004-09-08 23:42:23 +00003503}
3504
3505
sewardj893aada2004-11-29 19:57:54 +00003506/* --------- Synthesise a 2-bit FPU rounding mode. --------- */
sewardj8f3debf2004-09-08 23:42:23 +00003507/* Produces a value in 0 .. 3, which is encoded as per the type
sewardjd01a9632004-11-30 13:18:37 +00003508 IRRoundingMode. Since the guest_FPROUND value is also encoded as
3509 per IRRoundingMode, we merely need to get it and mask it for
3510 safety.
sewardj8f3debf2004-09-08 23:42:23 +00003511*/
3512static IRExpr* /* :: Ity_I32 */ get_roundingmode ( void )
3513{
sewardjd01a9632004-11-30 13:18:37 +00003514 return binop( Iop_And32, get_fpround(), mkU32(3) );
sewardj8f3debf2004-09-08 23:42:23 +00003515}
3516
sewardjf1b5b1a2006-02-03 22:54:17 +00003517static IRExpr* /* :: Ity_I32 */ get_FAKE_roundingmode ( void )
3518{
3519 return mkU32(Irrm_NEAREST);
3520}
3521
sewardj8f3debf2004-09-08 23:42:23 +00003522
sewardj207557a2004-08-27 12:00:18 +00003523/* --------- Get/set FP register tag bytes. --------- */
3524
sewardj207557a2004-08-27 12:00:18 +00003525/* Given i, and some expression e, generate 'ST_TAG(i) = e'. */
3526
3527static void put_ST_TAG ( Int i, IRExpr* value )
3528{
sewardjdd40fdf2006-12-24 02:20:24 +00003529 IRRegArray* descr;
3530 vassert(typeOfIRExpr(irsb->tyenv, value) == Ity_I8);
3531 descr = mkIRRegArray( OFFB_FPTAGS, Ity_I8, 8 );
floriand6f38b32012-05-31 15:46:18 +00003532 stmt( IRStmt_PutI( mkIRPutI(descr, get_ftop(), i, value) ) );
sewardj207557a2004-08-27 12:00:18 +00003533}
3534
3535/* Given i, generate an expression yielding 'ST_TAG(i)'. This will be
sewardjdb199622004-09-06 23:19:03 +00003536 zero to indicate "Empty" and nonzero to indicate "NonEmpty". */
sewardj207557a2004-08-27 12:00:18 +00003537
3538static IRExpr* get_ST_TAG ( Int i )
3539{
sewardjdd40fdf2006-12-24 02:20:24 +00003540 IRRegArray* descr = mkIRRegArray( OFFB_FPTAGS, Ity_I8, 8 );
sewardj2d3f77c2004-09-22 23:49:09 +00003541 return IRExpr_GetI( descr, get_ftop(), i );
sewardj207557a2004-08-27 12:00:18 +00003542}
3543
3544
3545/* --------- Get/set FP registers. --------- */
3546
sewardj2d3f77c2004-09-22 23:49:09 +00003547/* Given i, and some expression e, emit 'ST(i) = e' and set the
3548 register's tag to indicate the register is full. The previous
3549 state of the register is not checked. */
sewardj207557a2004-08-27 12:00:18 +00003550
3551static void put_ST_UNCHECKED ( Int i, IRExpr* value )
sewardjd1725d12004-08-12 20:46:53 +00003552{
sewardjdd40fdf2006-12-24 02:20:24 +00003553 IRRegArray* descr;
3554 vassert(typeOfIRExpr(irsb->tyenv, value) == Ity_F64);
3555 descr = mkIRRegArray( OFFB_FPREGS, Ity_F64, 8 );
floriand6f38b32012-05-31 15:46:18 +00003556 stmt( IRStmt_PutI( mkIRPutI(descr, get_ftop(), i, value) ) );
sewardj207557a2004-08-27 12:00:18 +00003557 /* Mark the register as in-use. */
3558 put_ST_TAG(i, mkU8(1));
sewardjd1725d12004-08-12 20:46:53 +00003559}
3560
sewardj207557a2004-08-27 12:00:18 +00003561/* Given i, and some expression e, emit
3562 ST(i) = is_full(i) ? NaN : e
3563 and set the tag accordingly.
3564*/
3565
3566static void put_ST ( Int i, IRExpr* value )
3567{
sewardj009230b2013-01-26 11:47:55 +00003568 put_ST_UNCHECKED(
3569 i,
florian99dd03e2013-01-29 03:56:06 +00003570 IRExpr_ITE( binop(Iop_CmpNE8, get_ST_TAG(i), mkU8(0)),
3571 /* non-0 means full */
3572 mkQNaN64(),
3573 /* 0 means empty */
3574 value
sewardj009230b2013-01-26 11:47:55 +00003575 )
sewardj207557a2004-08-27 12:00:18 +00003576 );
3577}
3578
3579
sewardjd1725d12004-08-12 20:46:53 +00003580/* Given i, generate an expression yielding 'ST(i)'. */
3581
sewardj207557a2004-08-27 12:00:18 +00003582static IRExpr* get_ST_UNCHECKED ( Int i )
sewardjd1725d12004-08-12 20:46:53 +00003583{
sewardjdd40fdf2006-12-24 02:20:24 +00003584 IRRegArray* descr = mkIRRegArray( OFFB_FPREGS, Ity_F64, 8 );
sewardj2d3f77c2004-09-22 23:49:09 +00003585 return IRExpr_GetI( descr, get_ftop(), i );
sewardjd1725d12004-08-12 20:46:53 +00003586}
3587
sewardjc4be80c2004-09-10 16:17:45 +00003588
sewardj207557a2004-08-27 12:00:18 +00003589/* Given i, generate an expression yielding
3590 is_full(i) ? ST(i) : NaN
3591*/
3592
3593static IRExpr* get_ST ( Int i )
3594{
3595 return
florian99dd03e2013-01-29 03:56:06 +00003596 IRExpr_ITE( binop(Iop_CmpNE8, get_ST_TAG(i), mkU8(0)),
3597 /* non-0 means full */
3598 get_ST_UNCHECKED(i),
3599 /* 0 means empty */
3600 mkQNaN64());
sewardj207557a2004-08-27 12:00:18 +00003601}
3602
3603
sewardje9c51c92014-04-30 22:50:34 +00003604/* Given i, and some expression e, and a condition cond, generate IR
3605 which has the same effect as put_ST(i,e) when cond is true and has
3606 no effect when cond is false. Given the lack of proper
3607 if-then-else in the IR, this is pretty tricky.
3608*/
3609
3610static void maybe_put_ST ( IRTemp cond, Int i, IRExpr* value )
3611{
3612 // new_tag = if cond then FULL else old_tag
3613 // new_val = if cond then (if old_tag==FULL then NaN else val)
3614 // else old_val
3615
3616 IRTemp old_tag = newTemp(Ity_I8);
3617 assign(old_tag, get_ST_TAG(i));
3618 IRTemp new_tag = newTemp(Ity_I8);
3619 assign(new_tag,
3620 IRExpr_ITE(mkexpr(cond), mkU8(1)/*FULL*/, mkexpr(old_tag)));
3621
3622 IRTemp old_val = newTemp(Ity_F64);
3623 assign(old_val, get_ST_UNCHECKED(i));
3624 IRTemp new_val = newTemp(Ity_F64);
3625 assign(new_val,
3626 IRExpr_ITE(mkexpr(cond),
3627 IRExpr_ITE(binop(Iop_CmpNE8, mkexpr(old_tag), mkU8(0)),
3628 /* non-0 means full */
3629 mkQNaN64(),
3630 /* 0 means empty */
3631 value),
3632 mkexpr(old_val)));
3633
3634 put_ST_UNCHECKED(i, mkexpr(new_val));
3635 // put_ST_UNCHECKED incorrectly sets tag(i) to always be FULL. So
3636 // now set it to new_tag instead.
3637 put_ST_TAG(i, mkexpr(new_tag));
3638}
3639
sewardjd1725d12004-08-12 20:46:53 +00003640/* Adjust FTOP downwards by one register. */
3641
sewardj207557a2004-08-27 12:00:18 +00003642static void fp_push ( void )
sewardjd1725d12004-08-12 20:46:53 +00003643{
sewardj2d3f77c2004-09-22 23:49:09 +00003644 put_ftop( binop(Iop_Sub32, get_ftop(), mkU32(1)) );
sewardjd1725d12004-08-12 20:46:53 +00003645}
3646
sewardje9c51c92014-04-30 22:50:34 +00003647/* Adjust FTOP downwards by one register when COND is 1:I1. Else
3648 don't change it. */
3649
3650static void maybe_fp_push ( IRTemp cond )
3651{
3652 put_ftop( binop(Iop_Sub32, get_ftop(), unop(Iop_1Uto32,mkexpr(cond))) );
3653}
3654
sewardj207557a2004-08-27 12:00:18 +00003655/* Adjust FTOP upwards by one register, and mark the vacated register
3656 as empty. */
sewardja58ea662004-08-15 03:12:41 +00003657
sewardj207557a2004-08-27 12:00:18 +00003658static void fp_pop ( void )
sewardja58ea662004-08-15 03:12:41 +00003659{
sewardjdb199622004-09-06 23:19:03 +00003660 put_ST_TAG(0, mkU8(0));
sewardj2d3f77c2004-09-22 23:49:09 +00003661 put_ftop( binop(Iop_Add32, get_ftop(), mkU32(1)) );
sewardja58ea662004-08-15 03:12:41 +00003662}
3663
sewardje9c51c92014-04-30 22:50:34 +00003664/* Set the C2 bit of the FPU status register to e[0]. Assumes that
3665 e[31:1] == 0.
3666*/
3667static void set_C2 ( IRExpr* e )
sewardj3f61ddb2004-10-16 20:51:05 +00003668{
sewardje9c51c92014-04-30 22:50:34 +00003669 IRExpr* cleared = binop(Iop_And32, get_C3210(), mkU32(~X86G_FC_MASK_C2));
3670 put_C3210( binop(Iop_Or32,
3671 cleared,
3672 binop(Iop_Shl32, e, mkU8(X86G_FC_SHIFT_C2))) );
3673}
3674
3675/* Generate code to check that abs(d64) < 2^63 and is finite. This is
3676 used to do the range checks for FSIN, FCOS, FSINCOS and FPTAN. The
3677 test is simple, but the derivation of it is not so simple.
3678
3679 The exponent field for an IEEE754 double is 11 bits. That means it
3680 can take values 0 through 0x7FF. If the exponent has value 0x7FF,
3681 the number is either a NaN or an Infinity and so is not finite.
3682 Furthermore, a finite value of exactly 2^63 is the smallest value
3683 that has exponent value 0x43E. Hence, what we need to do is
3684 extract the exponent, ignoring the sign bit and mantissa, and check
3685 it is < 0x43E, or <= 0x43D.
3686
3687 To make this easily applicable to 32- and 64-bit targets, a
3688 roundabout approach is used. First the number is converted to I64,
3689 then the top 32 bits are taken. Shifting them right by 20 bits
3690 places the sign bit and exponent in the bottom 12 bits. Anding
3691 with 0x7FF gets rid of the sign bit, leaving just the exponent
3692 available for comparison.
3693*/
3694static IRTemp math_IS_TRIG_ARG_FINITE_AND_IN_RANGE ( IRTemp d64 )
3695{
3696 IRTemp i64 = newTemp(Ity_I64);
3697 assign(i64, unop(Iop_ReinterpF64asI64, mkexpr(d64)) );
3698 IRTemp exponent = newTemp(Ity_I32);
3699 assign(exponent,
3700 binop(Iop_And32,
3701 binop(Iop_Shr32, unop(Iop_64HIto32, mkexpr(i64)), mkU8(20)),
3702 mkU32(0x7FF)));
3703 IRTemp in_range_and_finite = newTemp(Ity_I1);
3704 assign(in_range_and_finite,
3705 binop(Iop_CmpLE32U, mkexpr(exponent), mkU32(0x43D)));
3706 return in_range_and_finite;
sewardj3f61ddb2004-10-16 20:51:05 +00003707}
3708
sewardjd24931d2005-03-20 12:51:39 +00003709/* Invent a plausible-looking FPU status word value:
3710 ((ftop & 7) << 11) | (c3210 & 0x4700)
3711 */
3712static IRExpr* get_FPU_sw ( void )
3713{
3714 return
3715 unop(Iop_32to16,
3716 binop(Iop_Or32,
3717 binop(Iop_Shl32,
3718 binop(Iop_And32, get_ftop(), mkU32(7)),
3719 mkU8(11)),
3720 binop(Iop_And32, get_C3210(), mkU32(0x4700))
3721 ));
3722}
3723
sewardj3f61ddb2004-10-16 20:51:05 +00003724
sewardj207557a2004-08-27 12:00:18 +00003725/* ------------------------------------------------------- */
3726/* Given all that stack-mangling junk, we can now go ahead
3727 and describe FP instructions.
3728*/
3729
sewardj3fd5e572004-09-09 22:43:51 +00003730/* ST(0) = ST(0) `op` mem64/32(addr)
sewardj207557a2004-08-27 12:00:18 +00003731 Need to check ST(0)'s tag on read, but not on write.
3732*/
sewardja58ea662004-08-15 03:12:41 +00003733static
florian55085f82012-11-21 00:36:55 +00003734void fp_do_op_mem_ST_0 ( IRTemp addr, const HChar* op_txt, HChar* dis_buf,
sewardja58ea662004-08-15 03:12:41 +00003735 IROp op, Bool dbl )
3736{
sewardj33dd31b2005-01-08 18:17:32 +00003737 DIP("f%s%c %s\n", op_txt, dbl?'l':'s', dis_buf);
sewardja58ea662004-08-15 03:12:41 +00003738 if (dbl) {
sewardj3fd5e572004-09-09 22:43:51 +00003739 put_ST_UNCHECKED(0,
sewardjf1b5b1a2006-02-03 22:54:17 +00003740 triop( op,
3741 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
sewardj3fd5e572004-09-09 22:43:51 +00003742 get_ST(0),
3743 loadLE(Ity_F64,mkexpr(addr))
3744 ));
sewardja58ea662004-08-15 03:12:41 +00003745 } else {
sewardj3fd5e572004-09-09 22:43:51 +00003746 put_ST_UNCHECKED(0,
sewardjf1b5b1a2006-02-03 22:54:17 +00003747 triop( op,
3748 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
sewardj3fd5e572004-09-09 22:43:51 +00003749 get_ST(0),
3750 unop(Iop_F32toF64, loadLE(Ity_F32,mkexpr(addr)))
3751 ));
3752 }
3753}
3754
3755
3756/* ST(0) = mem64/32(addr) `op` ST(0)
3757 Need to check ST(0)'s tag on read, but not on write.
3758*/
3759static
florian55085f82012-11-21 00:36:55 +00003760void fp_do_oprev_mem_ST_0 ( IRTemp addr, const HChar* op_txt, HChar* dis_buf,
sewardj883b00b2004-09-11 09:30:24 +00003761 IROp op, Bool dbl )
sewardj3fd5e572004-09-09 22:43:51 +00003762{
sewardj33dd31b2005-01-08 18:17:32 +00003763 DIP("f%s%c %s\n", op_txt, dbl?'l':'s', dis_buf);
sewardj3fd5e572004-09-09 22:43:51 +00003764 if (dbl) {
3765 put_ST_UNCHECKED(0,
sewardjf1b5b1a2006-02-03 22:54:17 +00003766 triop( op,
3767 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
sewardj3fd5e572004-09-09 22:43:51 +00003768 loadLE(Ity_F64,mkexpr(addr)),
3769 get_ST(0)
3770 ));
3771 } else {
3772 put_ST_UNCHECKED(0,
sewardjf1b5b1a2006-02-03 22:54:17 +00003773 triop( op,
3774 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
sewardj3fd5e572004-09-09 22:43:51 +00003775 unop(Iop_F32toF64, loadLE(Ity_F32,mkexpr(addr))),
3776 get_ST(0)
3777 ));
sewardja58ea662004-08-15 03:12:41 +00003778 }
3779}
3780
sewardjd1725d12004-08-12 20:46:53 +00003781
sewardjdb199622004-09-06 23:19:03 +00003782/* ST(dst) = ST(dst) `op` ST(src).
3783 Check dst and src tags when reading but not on write.
3784*/
3785static
florian55085f82012-11-21 00:36:55 +00003786void fp_do_op_ST_ST ( const HChar* op_txt, IROp op, UInt st_src, UInt st_dst,
sewardjbdc7d212004-09-09 02:46:40 +00003787 Bool pop_after )
sewardjdb199622004-09-06 23:19:03 +00003788{
florianb1737742015-08-03 16:03:13 +00003789 DIP("f%s%s st(%u), st(%u)\n", op_txt, pop_after?"p":"",
3790 st_src, st_dst);
sewardjdb199622004-09-06 23:19:03 +00003791 put_ST_UNCHECKED(
3792 st_dst,
sewardjf1b5b1a2006-02-03 22:54:17 +00003793 triop( op,
3794 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
3795 get_ST(st_dst),
3796 get_ST(st_src) )
sewardjdb199622004-09-06 23:19:03 +00003797 );
sewardjbdc7d212004-09-09 02:46:40 +00003798 if (pop_after)
3799 fp_pop();
3800}
3801
3802/* ST(dst) = ST(src) `op` ST(dst).
3803 Check dst and src tags when reading but not on write.
3804*/
3805static
florian55085f82012-11-21 00:36:55 +00003806void fp_do_oprev_ST_ST ( const HChar* op_txt, IROp op, UInt st_src,
3807 UInt st_dst, Bool pop_after )
sewardjbdc7d212004-09-09 02:46:40 +00003808{
florianb1737742015-08-03 16:03:13 +00003809 DIP("f%s%s st(%u), st(%u)\n", op_txt, pop_after?"p":"",
3810 st_src, st_dst);
sewardjbdc7d212004-09-09 02:46:40 +00003811 put_ST_UNCHECKED(
3812 st_dst,
sewardjf1b5b1a2006-02-03 22:54:17 +00003813 triop( op,
3814 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
3815 get_ST(st_src),
3816 get_ST(st_dst) )
sewardjbdc7d212004-09-09 02:46:40 +00003817 );
3818 if (pop_after)
3819 fp_pop();
sewardjdb199622004-09-06 23:19:03 +00003820}
3821
sewardj8308aad2004-09-12 11:09:54 +00003822/* %eflags(Z,P,C) = UCOMI( st(0), st(i) ) */
3823static void fp_do_ucomi_ST0_STi ( UInt i, Bool pop_after )
3824{
florianb1737742015-08-03 16:03:13 +00003825 DIP("fucomi%s %%st(0),%%st(%u)\n", pop_after ? "p" : "", i);
sewardj8308aad2004-09-12 11:09:54 +00003826 /* This is a bit of a hack (and isn't really right). It sets
3827 Z,P,C,O correctly, but forces A and S to zero, whereas the Intel
3828 documentation implies A and S are unchanged.
3829 */
sewardjfeeb8a82004-11-30 12:30:11 +00003830 /* It's also fishy in that it is used both for COMIP and
3831 UCOMIP, and they aren't the same (although similar). */
sewardj2a9ad022004-11-25 02:46:58 +00003832 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(X86G_CC_OP_COPY) ));
sewardj2a2ba8b2004-11-08 13:14:06 +00003833 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
3834 stmt( IRStmt_Put( OFFB_CC_DEP1,
sewardj8308aad2004-09-12 11:09:54 +00003835 binop( Iop_And32,
3836 binop(Iop_CmpF64, get_ST(0), get_ST(i)),
3837 mkU32(0x45)
3838 )));
sewardja3b7e3a2005-04-05 01:54:19 +00003839 /* Set NDEP even though it isn't used. This makes redundant-PUT
3840 elimination of previous stores to this field work better. */
3841 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
sewardj8308aad2004-09-12 11:09:54 +00003842 if (pop_after)
3843 fp_pop();
3844}
3845
sewardjdb199622004-09-06 23:19:03 +00003846
sewardjd1725d12004-08-12 20:46:53 +00003847static
sewardj52d04912005-07-03 00:52:48 +00003848UInt dis_FPU ( Bool* decode_ok, UChar sorb, Int delta )
sewardjd1725d12004-08-12 20:46:53 +00003849{
sewardja58ea662004-08-15 03:12:41 +00003850 Int len;
3851 UInt r_src, r_dst;
sewardjc9a43662004-11-30 18:51:59 +00003852 HChar dis_buf[50];
sewardj89cd0932004-09-08 18:23:25 +00003853 IRTemp t1, t2;
sewardjd1725d12004-08-12 20:46:53 +00003854
3855 /* On entry, delta points at the second byte of the insn (the modrm
3856 byte).*/
3857 UChar first_opcode = getIByte(delta-1);
3858 UChar modrm = getIByte(delta+0);
3859
3860 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xD8 opcodes +-+-+-+-+-+-+-+ */
3861
3862 if (first_opcode == 0xD8) {
sewardjdb199622004-09-06 23:19:03 +00003863 if (modrm < 0xC0) {
sewardj89cd0932004-09-08 18:23:25 +00003864
3865 /* bits 5,4,3 are an opcode extension, and the modRM also
3866 specifies an address. */
3867 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
3868 delta += len;
3869
3870 switch (gregOfRM(modrm)) {
3871
sewardj3fd5e572004-09-09 22:43:51 +00003872 case 0: /* FADD single-real */
3873 fp_do_op_mem_ST_0 ( addr, "add", dis_buf, Iop_AddF64, False );
3874 break;
3875
sewardj89cd0932004-09-08 18:23:25 +00003876 case 1: /* FMUL single-real */
3877 fp_do_op_mem_ST_0 ( addr, "mul", dis_buf, Iop_MulF64, False );
3878 break;
3879
sewardj7ca37d92004-10-25 02:58:30 +00003880 case 2: /* FCOM single-real */
3881 DIP("fcoms %s\n", dis_buf);
3882 /* This forces C1 to zero, which isn't right. */
3883 put_C3210(
3884 binop( Iop_And32,
3885 binop(Iop_Shl32,
3886 binop(Iop_CmpF64,
3887 get_ST(0),
3888 unop(Iop_F32toF64,
3889 loadLE(Ity_F32,mkexpr(addr)))),
3890 mkU8(8)),
3891 mkU32(0x4500)
3892 ));
3893 break;
3894
3895 case 3: /* FCOMP single-real */
sewardje166ed02004-10-25 02:27:01 +00003896 DIP("fcomps %s\n", dis_buf);
3897 /* This forces C1 to zero, which isn't right. */
3898 put_C3210(
3899 binop( Iop_And32,
3900 binop(Iop_Shl32,
3901 binop(Iop_CmpF64,
3902 get_ST(0),
3903 unop(Iop_F32toF64,
3904 loadLE(Ity_F32,mkexpr(addr)))),
3905 mkU8(8)),
3906 mkU32(0x4500)
3907 ));
3908 fp_pop();
3909 break;
3910
sewardj588ea762004-09-10 18:56:32 +00003911 case 4: /* FSUB single-real */
3912 fp_do_op_mem_ST_0 ( addr, "sub", dis_buf, Iop_SubF64, False );
3913 break;
3914
3915 case 5: /* FSUBR single-real */
3916 fp_do_oprev_mem_ST_0 ( addr, "subr", dis_buf, Iop_SubF64, False );
3917 break;
3918
sewardjbdc7d212004-09-09 02:46:40 +00003919 case 6: /* FDIV single-real */
3920 fp_do_op_mem_ST_0 ( addr, "div", dis_buf, Iop_DivF64, False );
3921 break;
3922
sewardj8308aad2004-09-12 11:09:54 +00003923 case 7: /* FDIVR single-real */
3924 fp_do_oprev_mem_ST_0 ( addr, "divr", dis_buf, Iop_DivF64, False );
3925 break;
3926
sewardj89cd0932004-09-08 18:23:25 +00003927 default:
florianb1737742015-08-03 16:03:13 +00003928 vex_printf("unhandled opc_aux = 0x%2x\n", (UInt)gregOfRM(modrm));
sewardj89cd0932004-09-08 18:23:25 +00003929 vex_printf("first_opcode == 0xD8\n");
3930 goto decode_fail;
3931 }
sewardjdb199622004-09-06 23:19:03 +00003932 } else {
3933 delta++;
3934 switch (modrm) {
sewardj89cd0932004-09-08 18:23:25 +00003935
sewardjdb199622004-09-06 23:19:03 +00003936 case 0xC0 ... 0xC7: /* FADD %st(?),%st(0) */
sewardjbdc7d212004-09-09 02:46:40 +00003937 fp_do_op_ST_ST ( "add", Iop_AddF64, modrm - 0xC0, 0, False );
sewardjdb199622004-09-06 23:19:03 +00003938 break;
sewardj89cd0932004-09-08 18:23:25 +00003939
sewardj3fd5e572004-09-09 22:43:51 +00003940 case 0xC8 ... 0xCF: /* FMUL %st(?),%st(0) */
3941 fp_do_op_ST_ST ( "mul", Iop_MulF64, modrm - 0xC8, 0, False );
3942 break;
3943
sewardje166ed02004-10-25 02:27:01 +00003944 /* Dunno if this is right */
3945 case 0xD0 ... 0xD7: /* FCOM %st(?),%st(0) */
3946 r_dst = (UInt)modrm - 0xD0;
florianb1737742015-08-03 16:03:13 +00003947 DIP("fcom %%st(0),%%st(%u)\n", r_dst);
sewardje166ed02004-10-25 02:27:01 +00003948 /* This forces C1 to zero, which isn't right. */
3949 put_C3210(
3950 binop( Iop_And32,
3951 binop(Iop_Shl32,
3952 binop(Iop_CmpF64, get_ST(0), get_ST(r_dst)),
3953 mkU8(8)),
3954 mkU32(0x4500)
3955 ));
3956 break;
sewardj2d49b432005-02-01 00:37:06 +00003957
sewardj98169c52004-10-24 13:11:39 +00003958 /* Dunno if this is right */
3959 case 0xD8 ... 0xDF: /* FCOMP %st(?),%st(0) */
3960 r_dst = (UInt)modrm - 0xD8;
florianb1737742015-08-03 16:03:13 +00003961 DIP("fcomp %%st(0),%%st(%u)\n", r_dst);
sewardj98169c52004-10-24 13:11:39 +00003962 /* This forces C1 to zero, which isn't right. */
3963 put_C3210(
3964 binop( Iop_And32,
3965 binop(Iop_Shl32,
3966 binop(Iop_CmpF64, get_ST(0), get_ST(r_dst)),
3967 mkU8(8)),
3968 mkU32(0x4500)
3969 ));
3970 fp_pop();
3971 break;
sewardj2d49b432005-02-01 00:37:06 +00003972
sewardj89cd0932004-09-08 18:23:25 +00003973 case 0xE0 ... 0xE7: /* FSUB %st(?),%st(0) */
sewardjbdc7d212004-09-09 02:46:40 +00003974 fp_do_op_ST_ST ( "sub", Iop_SubF64, modrm - 0xE0, 0, False );
sewardj89cd0932004-09-08 18:23:25 +00003975 break;
3976
sewardj8308aad2004-09-12 11:09:54 +00003977 case 0xE8 ... 0xEF: /* FSUBR %st(?),%st(0) */
3978 fp_do_oprev_ST_ST ( "subr", Iop_SubF64, modrm - 0xE8, 0, False );
3979 break;
3980
sewardj3fd5e572004-09-09 22:43:51 +00003981 case 0xF0 ... 0xF7: /* FDIV %st(?),%st(0) */
3982 fp_do_op_ST_ST ( "div", Iop_DivF64, modrm - 0xF0, 0, False );
3983 break;
3984
3985 case 0xF8 ... 0xFF: /* FDIVR %st(?),%st(0) */
3986 fp_do_oprev_ST_ST ( "divr", Iop_DivF64, modrm - 0xF8, 0, False );
3987 break;
3988
sewardjdb199622004-09-06 23:19:03 +00003989 default:
3990 goto decode_fail;
3991 }
3992 }
sewardjd1725d12004-08-12 20:46:53 +00003993 }
3994
3995 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xD9 opcodes +-+-+-+-+-+-+-+ */
3996 else
3997 if (first_opcode == 0xD9) {
sewardjbb53f8c2004-08-14 11:50:01 +00003998 if (modrm < 0xC0) {
sewardj89cd0932004-09-08 18:23:25 +00003999
4000 /* bits 5,4,3 are an opcode extension, and the modRM also
sewardjfeeb8a82004-11-30 12:30:11 +00004001 specifies an address. */
sewardj89cd0932004-09-08 18:23:25 +00004002 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
4003 delta += len;
4004
4005 switch (gregOfRM(modrm)) {
4006
4007 case 0: /* FLD single-real */
sewardj33dd31b2005-01-08 18:17:32 +00004008 DIP("flds %s\n", dis_buf);
sewardj89cd0932004-09-08 18:23:25 +00004009 fp_push();
4010 put_ST(0, unop(Iop_F32toF64,
sewardj8f3debf2004-09-08 23:42:23 +00004011 loadLE(Ity_F32, mkexpr(addr))));
sewardj89cd0932004-09-08 18:23:25 +00004012 break;
4013
sewardj588ea762004-09-10 18:56:32 +00004014 case 2: /* FST single-real */
sewardj33dd31b2005-01-08 18:17:32 +00004015 DIP("fsts %s\n", dis_buf);
sewardj3bca9062004-12-04 14:36:09 +00004016 storeLE(mkexpr(addr),
4017 binop(Iop_F64toF32, get_roundingmode(), get_ST(0)));
sewardj588ea762004-09-10 18:56:32 +00004018 break;
4019
sewardj89cd0932004-09-08 18:23:25 +00004020 case 3: /* FSTP single-real */
sewardj33dd31b2005-01-08 18:17:32 +00004021 DIP("fstps %s\n", dis_buf);
sewardj3bca9062004-12-04 14:36:09 +00004022 storeLE(mkexpr(addr),
4023 binop(Iop_F64toF32, get_roundingmode(), get_ST(0)));
sewardj5bd4d162004-11-10 13:02:48 +00004024 fp_pop();
sewardj89cd0932004-09-08 18:23:25 +00004025 break;
4026
sewardjd24931d2005-03-20 12:51:39 +00004027 case 4: { /* FLDENV m28 */
sewardj7df596b2004-12-06 14:29:12 +00004028 /* Uses dirty helper:
florian6ef84be2012-08-26 03:20:07 +00004029 VexEmNote x86g_do_FLDENV ( VexGuestX86State*, HWord ) */
sewardj7df596b2004-12-06 14:29:12 +00004030 IRTemp ew = newTemp(Ity_I32);
4031 IRDirty* d = unsafeIRDirty_0_N (
4032 0/*regparms*/,
4033 "x86g_dirtyhelper_FLDENV",
4034 &x86g_dirtyhelper_FLDENV,
Elliott Hughesed398002017-06-21 14:41:24 -07004035 mkIRExprVec_2( IRExpr_GSPTR(), mkexpr(addr) )
sewardj7df596b2004-12-06 14:29:12 +00004036 );
sewardj74142b82013-08-08 10:28:59 +00004037 d->tmp = ew;
sewardj7df596b2004-12-06 14:29:12 +00004038 /* declare we're reading memory */
4039 d->mFx = Ifx_Read;
4040 d->mAddr = mkexpr(addr);
4041 d->mSize = 28;
4042
4043 /* declare we're writing guest state */
sewardj46813fc2005-06-13 12:33:36 +00004044 d->nFxState = 4;
sewardjc9069f22012-06-01 16:09:50 +00004045 vex_bzero(&d->fxState, sizeof(d->fxState));
sewardj7df596b2004-12-06 14:29:12 +00004046
4047 d->fxState[0].fx = Ifx_Write;
4048 d->fxState[0].offset = OFFB_FTOP;
4049 d->fxState[0].size = sizeof(UInt);
4050
4051 d->fxState[1].fx = Ifx_Write;
sewardj46813fc2005-06-13 12:33:36 +00004052 d->fxState[1].offset = OFFB_FPTAGS;
4053 d->fxState[1].size = 8 * sizeof(UChar);
sewardj7df596b2004-12-06 14:29:12 +00004054
4055 d->fxState[2].fx = Ifx_Write;
sewardj46813fc2005-06-13 12:33:36 +00004056 d->fxState[2].offset = OFFB_FPROUND;
4057 d->fxState[2].size = sizeof(UInt);
sewardj7df596b2004-12-06 14:29:12 +00004058
4059 d->fxState[3].fx = Ifx_Write;
sewardj46813fc2005-06-13 12:33:36 +00004060 d->fxState[3].offset = OFFB_FC3210;
sewardj7df596b2004-12-06 14:29:12 +00004061 d->fxState[3].size = sizeof(UInt);
4062
sewardj7df596b2004-12-06 14:29:12 +00004063 stmt( IRStmt_Dirty(d) );
4064
4065 /* ew contains any emulation warning we may need to
4066 issue. If needed, side-exit to the next insn,
4067 reporting the warning, so that Valgrind's dispatcher
4068 sees the warning. */
4069 put_emwarn( mkexpr(ew) );
4070 stmt(
4071 IRStmt_Exit(
4072 binop(Iop_CmpNE32, mkexpr(ew), mkU32(0)),
4073 Ijk_EmWarn,
sewardjc6f970f2012-04-02 21:54:49 +00004074 IRConst_U32( ((Addr32)guest_EIP_bbstart)+delta),
4075 OFFB_EIP
sewardj7df596b2004-12-06 14:29:12 +00004076 )
4077 );
4078
sewardj33dd31b2005-01-08 18:17:32 +00004079 DIP("fldenv %s\n", dis_buf);
sewardj7df596b2004-12-06 14:29:12 +00004080 break;
4081 }
4082
sewardj893aada2004-11-29 19:57:54 +00004083 case 5: {/* FLDCW */
4084 /* The only thing we observe in the control word is the
sewardjd01a9632004-11-30 13:18:37 +00004085 rounding mode. Therefore, pass the 16-bit value
4086 (x87 native-format control word) to a clean helper,
4087 getting back a 64-bit value, the lower half of which
4088 is the FPROUND value to store, and the upper half of
4089 which is the emulation-warning token which may be
4090 generated.
sewardj893aada2004-11-29 19:57:54 +00004091 */
4092 /* ULong x86h_check_fldcw ( UInt ); */
4093 IRTemp t64 = newTemp(Ity_I64);
4094 IRTemp ew = newTemp(Ity_I32);
sewardj33dd31b2005-01-08 18:17:32 +00004095 DIP("fldcw %s\n", dis_buf);
sewardj893aada2004-11-29 19:57:54 +00004096 assign( t64, mkIRExprCCall(
4097 Ity_I64, 0/*regparms*/,
sewardj3bd6f3e2004-12-13 10:48:19 +00004098 "x86g_check_fldcw",
4099 &x86g_check_fldcw,
sewardj893aada2004-11-29 19:57:54 +00004100 mkIRExprVec_1(
4101 unop( Iop_16Uto32,
4102 loadLE(Ity_I16, mkexpr(addr)))
4103 )
4104 )
4105 );
4106
sewardjd01a9632004-11-30 13:18:37 +00004107 put_fpround( unop(Iop_64to32, mkexpr(t64)) );
sewardj893aada2004-11-29 19:57:54 +00004108 assign( ew, unop(Iop_64HIto32, mkexpr(t64) ) );
4109 put_emwarn( mkexpr(ew) );
4110 /* Finally, if an emulation warning was reported,
4111 side-exit to the next insn, reporting the warning,
4112 so that Valgrind's dispatcher sees the warning. */
4113 stmt(
4114 IRStmt_Exit(
4115 binop(Iop_CmpNE32, mkexpr(ew), mkU32(0)),
4116 Ijk_EmWarn,
sewardjc6f970f2012-04-02 21:54:49 +00004117 IRConst_U32( ((Addr32)guest_EIP_bbstart)+delta),
4118 OFFB_EIP
sewardj893aada2004-11-29 19:57:54 +00004119 )
4120 );
sewardj89cd0932004-09-08 18:23:25 +00004121 break;
sewardj893aada2004-11-29 19:57:54 +00004122 }
sewardj89cd0932004-09-08 18:23:25 +00004123
sewardj7df596b2004-12-06 14:29:12 +00004124 case 6: { /* FNSTENV m28 */
4125 /* Uses dirty helper:
sewardj4017a3b2005-06-13 12:17:27 +00004126 void x86g_do_FSTENV ( VexGuestX86State*, HWord ) */
sewardj7df596b2004-12-06 14:29:12 +00004127 IRDirty* d = unsafeIRDirty_0_N (
4128 0/*regparms*/,
4129 "x86g_dirtyhelper_FSTENV",
4130 &x86g_dirtyhelper_FSTENV,
Elliott Hughesed398002017-06-21 14:41:24 -07004131 mkIRExprVec_2( IRExpr_GSPTR(), mkexpr(addr) )
sewardj7df596b2004-12-06 14:29:12 +00004132 );
sewardj7df596b2004-12-06 14:29:12 +00004133 /* declare we're writing memory */
4134 d->mFx = Ifx_Write;
4135 d->mAddr = mkexpr(addr);
4136 d->mSize = 28;
4137
4138 /* declare we're reading guest state */
4139 d->nFxState = 4;
sewardjc9069f22012-06-01 16:09:50 +00004140 vex_bzero(&d->fxState, sizeof(d->fxState));
sewardj7df596b2004-12-06 14:29:12 +00004141
4142 d->fxState[0].fx = Ifx_Read;
4143 d->fxState[0].offset = OFFB_FTOP;
4144 d->fxState[0].size = sizeof(UInt);
4145
4146 d->fxState[1].fx = Ifx_Read;
4147 d->fxState[1].offset = OFFB_FPTAGS;
4148 d->fxState[1].size = 8 * sizeof(UChar);
4149
4150 d->fxState[2].fx = Ifx_Read;
4151 d->fxState[2].offset = OFFB_FPROUND;
4152 d->fxState[2].size = sizeof(UInt);
4153
4154 d->fxState[3].fx = Ifx_Read;
4155 d->fxState[3].offset = OFFB_FC3210;
4156 d->fxState[3].size = sizeof(UInt);
4157
4158 stmt( IRStmt_Dirty(d) );
4159
sewardj33dd31b2005-01-08 18:17:32 +00004160 DIP("fnstenv %s\n", dis_buf);
sewardj7df596b2004-12-06 14:29:12 +00004161 break;
4162 }
4163
sewardj588ea762004-09-10 18:56:32 +00004164 case 7: /* FNSTCW */
sewardj893aada2004-11-29 19:57:54 +00004165 /* Fake up a native x87 FPU control word. The only
sewardjd01a9632004-11-30 13:18:37 +00004166 thing it depends on is FPROUND[1:0], so call a clean
sewardj893aada2004-11-29 19:57:54 +00004167 helper to cook it up. */
sewardjd01a9632004-11-30 13:18:37 +00004168 /* UInt x86h_create_fpucw ( UInt fpround ) */
sewardj33dd31b2005-01-08 18:17:32 +00004169 DIP("fnstcw %s\n", dis_buf);
sewardj893aada2004-11-29 19:57:54 +00004170 storeLE(
4171 mkexpr(addr),
4172 unop( Iop_32to16,
4173 mkIRExprCCall(
4174 Ity_I32, 0/*regp*/,
sewardj3bd6f3e2004-12-13 10:48:19 +00004175 "x86g_create_fpucw", &x86g_create_fpucw,
sewardjd01a9632004-11-30 13:18:37 +00004176 mkIRExprVec_1( get_fpround() )
sewardj893aada2004-11-29 19:57:54 +00004177 )
4178 )
4179 );
sewardj89cd0932004-09-08 18:23:25 +00004180 break;
4181
4182 default:
florianb1737742015-08-03 16:03:13 +00004183 vex_printf("unhandled opc_aux = 0x%2x\n", (UInt)gregOfRM(modrm));
sewardj89cd0932004-09-08 18:23:25 +00004184 vex_printf("first_opcode == 0xD9\n");
4185 goto decode_fail;
4186 }
4187
sewardjbb53f8c2004-08-14 11:50:01 +00004188 } else {
4189 delta++;
4190 switch (modrm) {
sewardj89cd0932004-09-08 18:23:25 +00004191
sewardjbb53f8c2004-08-14 11:50:01 +00004192 case 0xC0 ... 0xC7: /* FLD %st(?) */
sewardja58ea662004-08-15 03:12:41 +00004193 r_src = (UInt)modrm - 0xC0;
florianb1737742015-08-03 16:03:13 +00004194 DIP("fld %%st(%u)\n", r_src);
sewardj5bd4d162004-11-10 13:02:48 +00004195 t1 = newTemp(Ity_F64);
4196 assign(t1, get_ST(r_src));
4197 fp_push();
4198 put_ST(0, mkexpr(t1));
sewardjbb53f8c2004-08-14 11:50:01 +00004199 break;
4200
sewardj89cd0932004-09-08 18:23:25 +00004201 case 0xC8 ... 0xCF: /* FXCH %st(?) */
4202 r_src = (UInt)modrm - 0xC8;
florianb1737742015-08-03 16:03:13 +00004203 DIP("fxch %%st(%u)\n", r_src);
sewardj89cd0932004-09-08 18:23:25 +00004204 t1 = newTemp(Ity_F64);
4205 t2 = newTemp(Ity_F64);
4206 assign(t1, get_ST(0));
4207 assign(t2, get_ST(r_src));
4208 put_ST_UNCHECKED(0, mkexpr(t2));
4209 put_ST_UNCHECKED(r_src, mkexpr(t1));
4210 break;
4211
sewardjcfded9a2004-09-09 11:44:16 +00004212 case 0xE0: /* FCHS */
4213 DIP("fchs\n");
4214 put_ST_UNCHECKED(0, unop(Iop_NegF64, get_ST(0)));
4215 break;
4216
sewardj883b00b2004-09-11 09:30:24 +00004217 case 0xE1: /* FABS */
4218 DIP("fabs\n");
4219 put_ST_UNCHECKED(0, unop(Iop_AbsF64, get_ST(0)));
4220 break;
sewardjc4be80c2004-09-10 16:17:45 +00004221
sewardj1c318772005-03-19 14:27:04 +00004222 case 0xE4: /* FTST */
4223 DIP("ftst\n");
4224 /* This forces C1 to zero, which isn't right. */
4225 /* Well, in fact the Intel docs say (bizarrely): "C1 is
4226 set to 0 if stack underflow occurred; otherwise, set
4227 to 0" which is pretty nonsensical. I guess it's a
4228 typo. */
4229 put_C3210(
4230 binop( Iop_And32,
4231 binop(Iop_Shl32,
4232 binop(Iop_CmpF64,
4233 get_ST(0),
4234 IRExpr_Const(IRConst_F64i(0x0ULL))),
4235 mkU8(8)),
4236 mkU32(0x4500)
4237 ));
4238 break;
4239
sewardj883b00b2004-09-11 09:30:24 +00004240 case 0xE5: { /* FXAM */
4241 /* This is an interesting one. It examines %st(0),
4242 regardless of whether the tag says it's empty or not.
4243 Here, just pass both the tag (in our format) and the
4244 value (as a double, actually a ULong) to a helper
4245 function. */
sewardjf9655262004-10-31 20:02:16 +00004246 IRExpr** args
4247 = mkIRExprVec_2( unop(Iop_8Uto32, get_ST_TAG(0)),
4248 unop(Iop_ReinterpF64asI64,
4249 get_ST_UNCHECKED(0)) );
4250 put_C3210(mkIRExprCCall(
sewardj8ea867b2004-10-30 19:03:02 +00004251 Ity_I32,
sewardjf9655262004-10-31 20:02:16 +00004252 0/*regparm*/,
sewardj2a9ad022004-11-25 02:46:58 +00004253 "x86g_calculate_FXAM", &x86g_calculate_FXAM,
sewardj8ea867b2004-10-30 19:03:02 +00004254 args
4255 ));
sewardj33dd31b2005-01-08 18:17:32 +00004256 DIP("fxam\n");
sewardj883b00b2004-09-11 09:30:24 +00004257 break;
4258 }
4259
4260 case 0xE8: /* FLD1 */
sewardj33dd31b2005-01-08 18:17:32 +00004261 DIP("fld1\n");
sewardjce646f22004-08-31 23:55:54 +00004262 fp_push();
sewardj9c323762005-01-10 16:49:19 +00004263 /* put_ST(0, IRExpr_Const(IRConst_F64(1.0))); */
4264 put_ST(0, IRExpr_Const(IRConst_F64i(0x3ff0000000000000ULL)));
sewardjce646f22004-08-31 23:55:54 +00004265 break;
4266
sewardj37158712004-10-15 21:23:12 +00004267 case 0xE9: /* FLDL2T */
sewardj33dd31b2005-01-08 18:17:32 +00004268 DIP("fldl2t\n");
sewardj37158712004-10-15 21:23:12 +00004269 fp_push();
sewardj9c323762005-01-10 16:49:19 +00004270 /* put_ST(0, IRExpr_Const(IRConst_F64(3.32192809488736234781))); */
4271 put_ST(0, IRExpr_Const(IRConst_F64i(0x400a934f0979a371ULL)));
sewardj37158712004-10-15 21:23:12 +00004272 break;
4273
sewardj8308aad2004-09-12 11:09:54 +00004274 case 0xEA: /* FLDL2E */
sewardj33dd31b2005-01-08 18:17:32 +00004275 DIP("fldl2e\n");
sewardj8308aad2004-09-12 11:09:54 +00004276 fp_push();
sewardj9c323762005-01-10 16:49:19 +00004277 /* put_ST(0, IRExpr_Const(IRConst_F64(1.44269504088896340739))); */
4278 put_ST(0, IRExpr_Const(IRConst_F64i(0x3ff71547652b82feULL)));
sewardj8308aad2004-09-12 11:09:54 +00004279 break;
4280
sewardja0d48d62004-09-20 21:19:03 +00004281 case 0xEB: /* FLDPI */
sewardj33dd31b2005-01-08 18:17:32 +00004282 DIP("fldpi\n");
sewardja0d48d62004-09-20 21:19:03 +00004283 fp_push();
sewardj9c323762005-01-10 16:49:19 +00004284 /* put_ST(0, IRExpr_Const(IRConst_F64(3.14159265358979323851))); */
4285 put_ST(0, IRExpr_Const(IRConst_F64i(0x400921fb54442d18ULL)));
sewardja0d48d62004-09-20 21:19:03 +00004286 break;
4287
sewardjdb199622004-09-06 23:19:03 +00004288 case 0xEC: /* FLDLG2 */
sewardj33dd31b2005-01-08 18:17:32 +00004289 DIP("fldlg2\n");
sewardjdb199622004-09-06 23:19:03 +00004290 fp_push();
sewardj9c323762005-01-10 16:49:19 +00004291 /* put_ST(0, IRExpr_Const(IRConst_F64(0.301029995663981143))); */
4292 put_ST(0, IRExpr_Const(IRConst_F64i(0x3fd34413509f79ffULL)));
sewardjdb199622004-09-06 23:19:03 +00004293 break;
4294
4295 case 0xED: /* FLDLN2 */
sewardj33dd31b2005-01-08 18:17:32 +00004296 DIP("fldln2\n");
sewardjdb199622004-09-06 23:19:03 +00004297 fp_push();
sewardj9c323762005-01-10 16:49:19 +00004298 /* put_ST(0, IRExpr_Const(IRConst_F64(0.69314718055994530942))); */
4299 put_ST(0, IRExpr_Const(IRConst_F64i(0x3fe62e42fefa39efULL)));
sewardjdb199622004-09-06 23:19:03 +00004300 break;
4301
sewardja58ea662004-08-15 03:12:41 +00004302 case 0xEE: /* FLDZ */
sewardj33dd31b2005-01-08 18:17:32 +00004303 DIP("fldz\n");
sewardj207557a2004-08-27 12:00:18 +00004304 fp_push();
sewardj9c323762005-01-10 16:49:19 +00004305 /* put_ST(0, IRExpr_Const(IRConst_F64(0.0))); */
4306 put_ST(0, IRExpr_Const(IRConst_F64i(0x0000000000000000ULL)));
sewardja58ea662004-08-15 03:12:41 +00004307 break;
4308
sewardj06c32a02004-09-12 12:07:34 +00004309 case 0xF0: /* F2XM1 */
4310 DIP("f2xm1\n");
sewardjf1b5b1a2006-02-03 22:54:17 +00004311 put_ST_UNCHECKED(0,
4312 binop(Iop_2xm1F64,
4313 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4314 get_ST(0)));
sewardj06c32a02004-09-12 12:07:34 +00004315 break;
4316
sewardj52ace3e2004-09-11 17:10:08 +00004317 case 0xF1: /* FYL2X */
4318 DIP("fyl2x\n");
sewardjf1b5b1a2006-02-03 22:54:17 +00004319 put_ST_UNCHECKED(1,
4320 triop(Iop_Yl2xF64,
4321 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4322 get_ST(1),
4323 get_ST(0)));
sewardj52ace3e2004-09-11 17:10:08 +00004324 fp_pop();
4325 break;
4326
sewardje9c51c92014-04-30 22:50:34 +00004327 case 0xF2: { /* FPTAN */
4328 DIP("fptan\n");
4329 IRTemp argD = newTemp(Ity_F64);
4330 assign(argD, get_ST(0));
4331 IRTemp argOK = math_IS_TRIG_ARG_FINITE_AND_IN_RANGE(argD);
4332 IRTemp resD = newTemp(Ity_F64);
4333 assign(resD,
4334 IRExpr_ITE(
4335 mkexpr(argOK),
4336 binop(Iop_TanF64,
4337 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4338 mkexpr(argD)),
4339 mkexpr(argD))
4340 );
4341 put_ST_UNCHECKED(0, mkexpr(resD));
4342 /* Conditionally push 1.0 on the stack, if the arg is
4343 in range */
4344 maybe_fp_push(argOK);
4345 maybe_put_ST(argOK, 0,
4346 IRExpr_Const(IRConst_F64(1.0)));
4347 set_C2( binop(Iop_Xor32,
4348 unop(Iop_1Uto32, mkexpr(argOK)),
4349 mkU32(1)) );
sewardj99016a72004-10-15 22:09:17 +00004350 break;
sewardje9c51c92014-04-30 22:50:34 +00004351 }
sewardj99016a72004-10-15 22:09:17 +00004352
sewardjcfded9a2004-09-09 11:44:16 +00004353 case 0xF3: /* FPATAN */
4354 DIP("fpatan\n");
sewardjf1b5b1a2006-02-03 22:54:17 +00004355 put_ST_UNCHECKED(1,
4356 triop(Iop_AtanF64,
4357 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4358 get_ST(1),
4359 get_ST(0)));
sewardjcfded9a2004-09-09 11:44:16 +00004360 fp_pop();
4361 break;
4362
sewardjf1b5b1a2006-02-03 22:54:17 +00004363 case 0xF4: { /* FXTRACT */
sewardjfda10af2005-10-03 01:02:40 +00004364 IRTemp argF = newTemp(Ity_F64);
4365 IRTemp sigF = newTemp(Ity_F64);
4366 IRTemp expF = newTemp(Ity_F64);
4367 IRTemp argI = newTemp(Ity_I64);
4368 IRTemp sigI = newTemp(Ity_I64);
4369 IRTemp expI = newTemp(Ity_I64);
4370 DIP("fxtract\n");
4371 assign( argF, get_ST(0) );
4372 assign( argI, unop(Iop_ReinterpF64asI64, mkexpr(argF)));
4373 assign( sigI,
sewardj879cee02006-03-07 01:15:50 +00004374 mkIRExprCCall(
4375 Ity_I64, 0/*regparms*/,
4376 "x86amd64g_calculate_FXTRACT",
4377 &x86amd64g_calculate_FXTRACT,
4378 mkIRExprVec_2( mkexpr(argI),
4379 mkIRExpr_HWord(0)/*sig*/ ))
4380 );
sewardjfda10af2005-10-03 01:02:40 +00004381 assign( expI,
sewardj879cee02006-03-07 01:15:50 +00004382 mkIRExprCCall(
4383 Ity_I64, 0/*regparms*/,
4384 "x86amd64g_calculate_FXTRACT",
4385 &x86amd64g_calculate_FXTRACT,
4386 mkIRExprVec_2( mkexpr(argI),
4387 mkIRExpr_HWord(1)/*exp*/ ))
4388 );
sewardjfda10af2005-10-03 01:02:40 +00004389 assign( sigF, unop(Iop_ReinterpI64asF64, mkexpr(sigI)) );
4390 assign( expF, unop(Iop_ReinterpI64asF64, mkexpr(expI)) );
4391 /* exponent */
4392 put_ST_UNCHECKED(0, mkexpr(expF) );
4393 fp_push();
4394 /* significand */
4395 put_ST(0, mkexpr(sigF) );
4396 break;
4397 }
4398
sewardj442d0be2004-10-15 22:57:13 +00004399 case 0xF5: { /* FPREM1 -- IEEE compliant */
4400 IRTemp a1 = newTemp(Ity_F64);
4401 IRTemp a2 = newTemp(Ity_F64);
4402 DIP("fprem1\n");
4403 /* Do FPREM1 twice, once to get the remainder, and once
4404 to get the C3210 flag values. */
4405 assign( a1, get_ST(0) );
4406 assign( a2, get_ST(1) );
sewardjf47286e2006-02-04 15:20:13 +00004407 put_ST_UNCHECKED(0,
4408 triop(Iop_PRem1F64,
4409 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4410 mkexpr(a1),
4411 mkexpr(a2)));
4412 put_C3210(
4413 triop(Iop_PRem1C3210F64,
4414 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4415 mkexpr(a1),
4416 mkexpr(a2)) );
sewardj442d0be2004-10-15 22:57:13 +00004417 break;
4418 }
4419
sewardjfeeb8a82004-11-30 12:30:11 +00004420 case 0xF7: /* FINCSTP */
4421 DIP("fprem\n");
4422 put_ftop( binop(Iop_Add32, get_ftop(), mkU32(1)) );
4423 break;
4424
sewardj46de4072004-09-11 19:23:24 +00004425 case 0xF8: { /* FPREM -- not IEEE compliant */
4426 IRTemp a1 = newTemp(Ity_F64);
4427 IRTemp a2 = newTemp(Ity_F64);
4428 DIP("fprem\n");
4429 /* Do FPREM twice, once to get the remainder, and once
4430 to get the C3210 flag values. */
4431 assign( a1, get_ST(0) );
4432 assign( a2, get_ST(1) );
sewardjf47286e2006-02-04 15:20:13 +00004433 put_ST_UNCHECKED(0,
4434 triop(Iop_PRemF64,
4435 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4436 mkexpr(a1),
4437 mkexpr(a2)));
4438 put_C3210(
4439 triop(Iop_PRemC3210F64,
4440 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4441 mkexpr(a1),
4442 mkexpr(a2)) );
sewardj46de4072004-09-11 19:23:24 +00004443 break;
4444 }
4445
sewardj8308aad2004-09-12 11:09:54 +00004446 case 0xF9: /* FYL2XP1 */
4447 DIP("fyl2xp1\n");
sewardjf1b5b1a2006-02-03 22:54:17 +00004448 put_ST_UNCHECKED(1,
4449 triop(Iop_Yl2xp1F64,
4450 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4451 get_ST(1),
4452 get_ST(0)));
sewardj8308aad2004-09-12 11:09:54 +00004453 fp_pop();
4454 break;
4455
sewardjc4be80c2004-09-10 16:17:45 +00004456 case 0xFA: /* FSQRT */
4457 DIP("fsqrt\n");
sewardjf1b5b1a2006-02-03 22:54:17 +00004458 put_ST_UNCHECKED(0,
4459 binop(Iop_SqrtF64,
4460 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4461 get_ST(0)));
sewardjc4be80c2004-09-10 16:17:45 +00004462 break;
4463
sewardj519d66f2004-12-15 11:57:58 +00004464 case 0xFB: { /* FSINCOS */
sewardj519d66f2004-12-15 11:57:58 +00004465 DIP("fsincos\n");
sewardje9c51c92014-04-30 22:50:34 +00004466 IRTemp argD = newTemp(Ity_F64);
4467 assign(argD, get_ST(0));
4468 IRTemp argOK = math_IS_TRIG_ARG_FINITE_AND_IN_RANGE(argD);
4469 IRTemp resD = newTemp(Ity_F64);
4470 assign(resD,
4471 IRExpr_ITE(
4472 mkexpr(argOK),
4473 binop(Iop_SinF64,
4474 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4475 mkexpr(argD)),
4476 mkexpr(argD))
4477 );
4478 put_ST_UNCHECKED(0, mkexpr(resD));
4479 /* Conditionally push the cos value on the stack, if
4480 the arg is in range */
4481 maybe_fp_push(argOK);
4482 maybe_put_ST(argOK, 0,
sewardjf1b5b1a2006-02-03 22:54:17 +00004483 binop(Iop_CosF64,
4484 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
sewardje9c51c92014-04-30 22:50:34 +00004485 mkexpr(argD)));
4486 set_C2( binop(Iop_Xor32,
4487 unop(Iop_1Uto32, mkexpr(argOK)),
4488 mkU32(1)) );
sewardj519d66f2004-12-15 11:57:58 +00004489 break;
4490 }
4491
sewardje6709112004-09-10 18:37:18 +00004492 case 0xFC: /* FRNDINT */
4493 DIP("frndint\n");
4494 put_ST_UNCHECKED(0,
sewardjb183b852006-02-03 16:08:03 +00004495 binop(Iop_RoundF64toInt, get_roundingmode(), get_ST(0)) );
sewardje6709112004-09-10 18:37:18 +00004496 break;
4497
sewardj06c32a02004-09-12 12:07:34 +00004498 case 0xFD: /* FSCALE */
4499 DIP("fscale\n");
sewardjf1b5b1a2006-02-03 22:54:17 +00004500 put_ST_UNCHECKED(0,
4501 triop(Iop_ScaleF64,
4502 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4503 get_ST(0),
4504 get_ST(1)));
sewardj06c32a02004-09-12 12:07:34 +00004505 break;
4506
sewardje9c51c92014-04-30 22:50:34 +00004507 case 0xFE: /* FSIN */
4508 case 0xFF: { /* FCOS */
4509 Bool isSIN = modrm == 0xFE;
4510 DIP("%s\n", isSIN ? "fsin" : "fcos");
4511 IRTemp argD = newTemp(Ity_F64);
4512 assign(argD, get_ST(0));
4513 IRTemp argOK = math_IS_TRIG_ARG_FINITE_AND_IN_RANGE(argD);
4514 IRTemp resD = newTemp(Ity_F64);
4515 assign(resD,
4516 IRExpr_ITE(
4517 mkexpr(argOK),
4518 binop(isSIN ? Iop_SinF64 : Iop_CosF64,
4519 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4520 mkexpr(argD)),
4521 mkexpr(argD))
4522 );
4523 put_ST_UNCHECKED(0, mkexpr(resD));
4524 set_C2( binop(Iop_Xor32,
4525 unop(Iop_1Uto32, mkexpr(argOK)),
4526 mkU32(1)) );
sewardjcfded9a2004-09-09 11:44:16 +00004527 break;
sewardje9c51c92014-04-30 22:50:34 +00004528 }
sewardjcfded9a2004-09-09 11:44:16 +00004529
sewardjbb53f8c2004-08-14 11:50:01 +00004530 default:
4531 goto decode_fail;
4532 }
4533 }
sewardjd1725d12004-08-12 20:46:53 +00004534 }
4535
4536 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDA opcodes +-+-+-+-+-+-+-+ */
4537 else
4538 if (first_opcode == 0xDA) {
sewardjbb53f8c2004-08-14 11:50:01 +00004539
4540 if (modrm < 0xC0) {
4541
sewardjfeeb8a82004-11-30 12:30:11 +00004542 /* bits 5,4,3 are an opcode extension, and the modRM also
sewardjbb53f8c2004-08-14 11:50:01 +00004543 specifies an address. */
sewardjce646f22004-08-31 23:55:54 +00004544 IROp fop;
sewardjbb53f8c2004-08-14 11:50:01 +00004545 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
4546 delta += len;
sewardjbb53f8c2004-08-14 11:50:01 +00004547 switch (gregOfRM(modrm)) {
sewardjce646f22004-08-31 23:55:54 +00004548
sewardjdb199622004-09-06 23:19:03 +00004549 case 0: /* FIADD m32int */ /* ST(0) += m32int */
sewardj33dd31b2005-01-08 18:17:32 +00004550 DIP("fiaddl %s\n", dis_buf);
sewardj5bd4d162004-11-10 13:02:48 +00004551 fop = Iop_AddF64;
4552 goto do_fop_m32;
sewardjdb199622004-09-06 23:19:03 +00004553
sewardj207557a2004-08-27 12:00:18 +00004554 case 1: /* FIMUL m32int */ /* ST(0) *= m32int */
sewardj33dd31b2005-01-08 18:17:32 +00004555 DIP("fimull %s\n", dis_buf);
sewardj5bd4d162004-11-10 13:02:48 +00004556 fop = Iop_MulF64;
4557 goto do_fop_m32;
sewardjce646f22004-08-31 23:55:54 +00004558
sewardj071895f2005-07-29 11:28:38 +00004559 case 2: /* FICOM m32int */
4560 DIP("ficoml %s\n", dis_buf);
4561 /* This forces C1 to zero, which isn't right. */
4562 put_C3210(
4563 binop( Iop_And32,
4564 binop(Iop_Shl32,
4565 binop(Iop_CmpF64,
4566 get_ST(0),
sewardj6c299f32009-12-31 18:00:12 +00004567 unop(Iop_I32StoF64,
sewardj071895f2005-07-29 11:28:38 +00004568 loadLE(Ity_I32,mkexpr(addr)))),
4569 mkU8(8)),
4570 mkU32(0x4500)
4571 ));
4572 break;
4573
4574 case 3: /* FICOMP m32int */
4575 DIP("ficompl %s\n", dis_buf);
4576 /* This forces C1 to zero, which isn't right. */
4577 put_C3210(
4578 binop( Iop_And32,
4579 binop(Iop_Shl32,
4580 binop(Iop_CmpF64,
4581 get_ST(0),
sewardj6c299f32009-12-31 18:00:12 +00004582 unop(Iop_I32StoF64,
sewardj071895f2005-07-29 11:28:38 +00004583 loadLE(Ity_I32,mkexpr(addr)))),
4584 mkU8(8)),
4585 mkU32(0x4500)
4586 ));
4587 fp_pop();
4588 break;
4589
sewardjce646f22004-08-31 23:55:54 +00004590 case 4: /* FISUB m32int */ /* ST(0) -= m32int */
sewardj33dd31b2005-01-08 18:17:32 +00004591 DIP("fisubl %s\n", dis_buf);
sewardj5bd4d162004-11-10 13:02:48 +00004592 fop = Iop_SubF64;
4593 goto do_fop_m32;
sewardjce646f22004-08-31 23:55:54 +00004594
sewardj8308aad2004-09-12 11:09:54 +00004595 case 5: /* FISUBR m32int */ /* ST(0) = m32int - ST(0) */
sewardj33dd31b2005-01-08 18:17:32 +00004596 DIP("fisubrl %s\n", dis_buf);
sewardj5bd4d162004-11-10 13:02:48 +00004597 fop = Iop_SubF64;
4598 goto do_foprev_m32;
sewardj8308aad2004-09-12 11:09:54 +00004599
sewardjce646f22004-08-31 23:55:54 +00004600 case 6: /* FIDIV m32int */ /* ST(0) /= m32int */
sewardj36917e92005-03-21 00:12:15 +00004601 DIP("fidivl %s\n", dis_buf);
sewardj5bd4d162004-11-10 13:02:48 +00004602 fop = Iop_DivF64;
4603 goto do_fop_m32;
sewardjce646f22004-08-31 23:55:54 +00004604
sewardjc4eaff32004-09-10 20:25:11 +00004605 case 7: /* FIDIVR m32int */ /* ST(0) = m32int / ST(0) */
sewardj33dd31b2005-01-08 18:17:32 +00004606 DIP("fidivrl %s\n", dis_buf);
sewardj5bd4d162004-11-10 13:02:48 +00004607 fop = Iop_DivF64;
4608 goto do_foprev_m32;
sewardjc4eaff32004-09-10 20:25:11 +00004609
sewardjce646f22004-08-31 23:55:54 +00004610 do_fop_m32:
sewardj207557a2004-08-27 12:00:18 +00004611 put_ST_UNCHECKED(0,
sewardjf1b5b1a2006-02-03 22:54:17 +00004612 triop(fop,
4613 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
sewardj207557a2004-08-27 12:00:18 +00004614 get_ST(0),
sewardj6c299f32009-12-31 18:00:12 +00004615 unop(Iop_I32StoF64,
sewardj89cd0932004-09-08 18:23:25 +00004616 loadLE(Ity_I32, mkexpr(addr)))));
sewardjbb53f8c2004-08-14 11:50:01 +00004617 break;
4618
sewardjc4eaff32004-09-10 20:25:11 +00004619 do_foprev_m32:
4620 put_ST_UNCHECKED(0,
sewardjf1b5b1a2006-02-03 22:54:17 +00004621 triop(fop,
4622 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
sewardj6c299f32009-12-31 18:00:12 +00004623 unop(Iop_I32StoF64,
sewardjc4eaff32004-09-10 20:25:11 +00004624 loadLE(Ity_I32, mkexpr(addr))),
4625 get_ST(0)));
4626 break;
4627
sewardjbb53f8c2004-08-14 11:50:01 +00004628 default:
florianb1737742015-08-03 16:03:13 +00004629 vex_printf("unhandled opc_aux = 0x%2x\n", (UInt)gregOfRM(modrm));
sewardjbb53f8c2004-08-14 11:50:01 +00004630 vex_printf("first_opcode == 0xDA\n");
4631 goto decode_fail;
4632 }
sewardj4cb918d2004-12-03 19:43:31 +00004633
sewardjbb53f8c2004-08-14 11:50:01 +00004634 } else {
sewardjbdc7d212004-09-09 02:46:40 +00004635
4636 delta++;
4637 switch (modrm) {
4638
sewardj519d66f2004-12-15 11:57:58 +00004639 case 0xC0 ... 0xC7: /* FCMOVB ST(i), ST(0) */
4640 r_src = (UInt)modrm - 0xC0;
florianb1737742015-08-03 16:03:13 +00004641 DIP("fcmovb %%st(%u), %%st(0)\n", r_src);
sewardj519d66f2004-12-15 11:57:58 +00004642 put_ST_UNCHECKED(0,
florian99dd03e2013-01-29 03:56:06 +00004643 IRExpr_ITE(
sewardj009230b2013-01-26 11:47:55 +00004644 mk_x86g_calculate_condition(X86CondB),
florian99dd03e2013-01-29 03:56:06 +00004645 get_ST(r_src), get_ST(0)) );
sewardj519d66f2004-12-15 11:57:58 +00004646 break;
4647
sewardj3fd5e572004-09-09 22:43:51 +00004648 case 0xC8 ... 0xCF: /* FCMOVE(Z) ST(i), ST(0) */
4649 r_src = (UInt)modrm - 0xC8;
florianb1737742015-08-03 16:03:13 +00004650 DIP("fcmovz %%st(%u), %%st(0)\n", r_src);
sewardj5bd4d162004-11-10 13:02:48 +00004651 put_ST_UNCHECKED(0,
florian99dd03e2013-01-29 03:56:06 +00004652 IRExpr_ITE(
sewardj009230b2013-01-26 11:47:55 +00004653 mk_x86g_calculate_condition(X86CondZ),
florian99dd03e2013-01-29 03:56:06 +00004654 get_ST(r_src), get_ST(0)) );
sewardj3fd5e572004-09-09 22:43:51 +00004655 break;
4656
sewardj519d66f2004-12-15 11:57:58 +00004657 case 0xD0 ... 0xD7: /* FCMOVBE ST(i), ST(0) */
4658 r_src = (UInt)modrm - 0xD0;
florianb1737742015-08-03 16:03:13 +00004659 DIP("fcmovbe %%st(%u), %%st(0)\n", r_src);
sewardj519d66f2004-12-15 11:57:58 +00004660 put_ST_UNCHECKED(0,
florian99dd03e2013-01-29 03:56:06 +00004661 IRExpr_ITE(
sewardj009230b2013-01-26 11:47:55 +00004662 mk_x86g_calculate_condition(X86CondBE),
florian99dd03e2013-01-29 03:56:06 +00004663 get_ST(r_src), get_ST(0)) );
sewardj519d66f2004-12-15 11:57:58 +00004664 break;
4665
sewardj8253ad32005-07-04 10:26:32 +00004666 case 0xD8 ... 0xDF: /* FCMOVU ST(i), ST(0) */
4667 r_src = (UInt)modrm - 0xD8;
florianb1737742015-08-03 16:03:13 +00004668 DIP("fcmovu %%st(%u), %%st(0)\n", r_src);
sewardj8253ad32005-07-04 10:26:32 +00004669 put_ST_UNCHECKED(0,
florian99dd03e2013-01-29 03:56:06 +00004670 IRExpr_ITE(
sewardj009230b2013-01-26 11:47:55 +00004671 mk_x86g_calculate_condition(X86CondP),
florian99dd03e2013-01-29 03:56:06 +00004672 get_ST(r_src), get_ST(0)) );
sewardj8253ad32005-07-04 10:26:32 +00004673 break;
4674
sewardjbdc7d212004-09-09 02:46:40 +00004675 case 0xE9: /* FUCOMPP %st(0),%st(1) */
4676 DIP("fucompp %%st(0),%%st(1)\n");
sewardjc4be80c2004-09-10 16:17:45 +00004677 /* This forces C1 to zero, which isn't right. */
4678 put_C3210(
4679 binop( Iop_And32,
4680 binop(Iop_Shl32,
4681 binop(Iop_CmpF64, get_ST(0), get_ST(1)),
4682 mkU8(8)),
4683 mkU32(0x4500)
4684 ));
sewardjbdc7d212004-09-09 02:46:40 +00004685 fp_pop();
4686 fp_pop();
4687 break;
4688
sewardj5bd4d162004-11-10 13:02:48 +00004689 default:
sewardjbdc7d212004-09-09 02:46:40 +00004690 goto decode_fail;
sewardj5bd4d162004-11-10 13:02:48 +00004691 }
sewardjbdc7d212004-09-09 02:46:40 +00004692
sewardjbb53f8c2004-08-14 11:50:01 +00004693 }
sewardjd1725d12004-08-12 20:46:53 +00004694 }
4695
4696 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDB opcodes +-+-+-+-+-+-+-+ */
4697 else
4698 if (first_opcode == 0xDB) {
sewardj89cd0932004-09-08 18:23:25 +00004699 if (modrm < 0xC0) {
4700
sewardjfeeb8a82004-11-30 12:30:11 +00004701 /* bits 5,4,3 are an opcode extension, and the modRM also
sewardj89cd0932004-09-08 18:23:25 +00004702 specifies an address. */
4703 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
4704 delta += len;
4705
4706 switch (gregOfRM(modrm)) {
4707
4708 case 0: /* FILD m32int */
4709 DIP("fildl %s\n", dis_buf);
4710 fp_push();
sewardj6c299f32009-12-31 18:00:12 +00004711 put_ST(0, unop(Iop_I32StoF64,
sewardj89cd0932004-09-08 18:23:25 +00004712 loadLE(Ity_I32, mkexpr(addr))));
4713 break;
4714
sewardjdd5d2042006-08-03 15:03:19 +00004715 case 1: /* FISTTPL m32 (SSE3) */
4716 DIP("fisttpl %s\n", dis_buf);
4717 storeLE( mkexpr(addr),
sewardj6c299f32009-12-31 18:00:12 +00004718 binop(Iop_F64toI32S, mkU32(Irrm_ZERO), get_ST(0)) );
sewardjdd5d2042006-08-03 15:03:19 +00004719 fp_pop();
4720 break;
4721
sewardj8f3debf2004-09-08 23:42:23 +00004722 case 2: /* FIST m32 */
sewardj33dd31b2005-01-08 18:17:32 +00004723 DIP("fistl %s\n", dis_buf);
sewardj8f3debf2004-09-08 23:42:23 +00004724 storeLE( mkexpr(addr),
sewardj6c299f32009-12-31 18:00:12 +00004725 binop(Iop_F64toI32S, get_roundingmode(), get_ST(0)) );
sewardj8f3debf2004-09-08 23:42:23 +00004726 break;
4727
sewardj89cd0932004-09-08 18:23:25 +00004728 case 3: /* FISTP m32 */
sewardj33dd31b2005-01-08 18:17:32 +00004729 DIP("fistpl %s\n", dis_buf);
sewardj8f3debf2004-09-08 23:42:23 +00004730 storeLE( mkexpr(addr),
sewardj6c299f32009-12-31 18:00:12 +00004731 binop(Iop_F64toI32S, get_roundingmode(), get_ST(0)) );
sewardj5bd4d162004-11-10 13:02:48 +00004732 fp_pop();
sewardj89cd0932004-09-08 18:23:25 +00004733 break;
sewardj17442fe2004-09-20 14:54:28 +00004734
sewardjb3bce0e2004-09-14 23:20:10 +00004735 case 5: { /* FLD extended-real */
sewardj7cb49d72004-10-24 22:31:25 +00004736 /* Uses dirty helper:
sewardj56579232005-03-26 21:49:42 +00004737 ULong x86g_loadF80le ( UInt )
sewardj7cb49d72004-10-24 22:31:25 +00004738 addr holds the address. First, do a dirty call to
sewardjb3bce0e2004-09-14 23:20:10 +00004739 get hold of the data. */
sewardjc5fc7aa2004-10-27 23:00:55 +00004740 IRTemp val = newTemp(Ity_I64);
4741 IRExpr** args = mkIRExprVec_1 ( mkexpr(addr) );
4742
sewardj8ea867b2004-10-30 19:03:02 +00004743 IRDirty* d = unsafeIRDirty_1_N (
4744 val,
sewardj2a9ad022004-11-25 02:46:58 +00004745 0/*regparms*/,
sewardj8f40b072005-08-23 19:30:58 +00004746 "x86g_dirtyhelper_loadF80le",
4747 &x86g_dirtyhelper_loadF80le,
sewardj8ea867b2004-10-30 19:03:02 +00004748 args
4749 );
sewardjb3bce0e2004-09-14 23:20:10 +00004750 /* declare that we're reading memory */
4751 d->mFx = Ifx_Read;
sewardj17442fe2004-09-20 14:54:28 +00004752 d->mAddr = mkexpr(addr);
sewardjb3bce0e2004-09-14 23:20:10 +00004753 d->mSize = 10;
sewardjc5fc7aa2004-10-27 23:00:55 +00004754
4755 /* execute the dirty call, dumping the result in val. */
sewardjb3bce0e2004-09-14 23:20:10 +00004756 stmt( IRStmt_Dirty(d) );
4757 fp_push();
sewardjc5fc7aa2004-10-27 23:00:55 +00004758 put_ST(0, unop(Iop_ReinterpI64asF64, mkexpr(val)));
4759
sewardj33dd31b2005-01-08 18:17:32 +00004760 DIP("fldt %s\n", dis_buf);
sewardjb3bce0e2004-09-14 23:20:10 +00004761 break;
4762 }
sewardj17442fe2004-09-20 14:54:28 +00004763
4764 case 7: { /* FSTP extended-real */
sewardj9fc9e782004-11-26 17:57:40 +00004765 /* Uses dirty helper: void x86g_storeF80le ( UInt, ULong ) */
sewardjc5fc7aa2004-10-27 23:00:55 +00004766 IRExpr** args
4767 = mkIRExprVec_2( mkexpr(addr),
4768 unop(Iop_ReinterpF64asI64, get_ST(0)) );
4769
sewardj8ea867b2004-10-30 19:03:02 +00004770 IRDirty* d = unsafeIRDirty_0_N (
sewardjf9655262004-10-31 20:02:16 +00004771 0/*regparms*/,
sewardj8f40b072005-08-23 19:30:58 +00004772 "x86g_dirtyhelper_storeF80le",
4773 &x86g_dirtyhelper_storeF80le,
sewardj8ea867b2004-10-30 19:03:02 +00004774 args
4775 );
sewardj17442fe2004-09-20 14:54:28 +00004776 /* declare we're writing memory */
4777 d->mFx = Ifx_Write;
4778 d->mAddr = mkexpr(addr);
4779 d->mSize = 10;
sewardjc5fc7aa2004-10-27 23:00:55 +00004780
sewardj17442fe2004-09-20 14:54:28 +00004781 /* execute the dirty call. */
4782 stmt( IRStmt_Dirty(d) );
4783 fp_pop();
sewardjc5fc7aa2004-10-27 23:00:55 +00004784
sewardj33dd31b2005-01-08 18:17:32 +00004785 DIP("fstpt\n %s", dis_buf);
sewardj17442fe2004-09-20 14:54:28 +00004786 break;
4787 }
4788
sewardjb3bce0e2004-09-14 23:20:10 +00004789 default:
florianb1737742015-08-03 16:03:13 +00004790 vex_printf("unhandled opc_aux = 0x%2x\n", (UInt)gregOfRM(modrm));
sewardj89cd0932004-09-08 18:23:25 +00004791 vex_printf("first_opcode == 0xDB\n");
4792 goto decode_fail;
4793 }
4794
4795 } else {
sewardj8308aad2004-09-12 11:09:54 +00004796
4797 delta++;
4798 switch (modrm) {
4799
sewardj519d66f2004-12-15 11:57:58 +00004800 case 0xC0 ... 0xC7: /* FCMOVNB ST(i), ST(0) */
4801 r_src = (UInt)modrm - 0xC0;
florianb1737742015-08-03 16:03:13 +00004802 DIP("fcmovnb %%st(%u), %%st(0)\n", r_src);
sewardj519d66f2004-12-15 11:57:58 +00004803 put_ST_UNCHECKED(0,
florian99dd03e2013-01-29 03:56:06 +00004804 IRExpr_ITE(
sewardj009230b2013-01-26 11:47:55 +00004805 mk_x86g_calculate_condition(X86CondNB),
florian99dd03e2013-01-29 03:56:06 +00004806 get_ST(r_src), get_ST(0)) );
sewardj519d66f2004-12-15 11:57:58 +00004807 break;
4808
sewardj4e82db72004-10-16 11:32:15 +00004809 case 0xC8 ... 0xCF: /* FCMOVNE(NZ) ST(i), ST(0) */
4810 r_src = (UInt)modrm - 0xC8;
florianb1737742015-08-03 16:03:13 +00004811 DIP("fcmovnz %%st(%u), %%st(0)\n", r_src);
sewardj5bd4d162004-11-10 13:02:48 +00004812 put_ST_UNCHECKED(0,
florian99dd03e2013-01-29 03:56:06 +00004813 IRExpr_ITE(
sewardj009230b2013-01-26 11:47:55 +00004814 mk_x86g_calculate_condition(X86CondNZ),
florian99dd03e2013-01-29 03:56:06 +00004815 get_ST(r_src), get_ST(0)) );
sewardj4e82db72004-10-16 11:32:15 +00004816 break;
4817
sewardj519d66f2004-12-15 11:57:58 +00004818 case 0xD0 ... 0xD7: /* FCMOVNBE ST(i), ST(0) */
4819 r_src = (UInt)modrm - 0xD0;
florianb1737742015-08-03 16:03:13 +00004820 DIP("fcmovnbe %%st(%u), %%st(0)\n", r_src);
sewardj519d66f2004-12-15 11:57:58 +00004821 put_ST_UNCHECKED(0,
florian99dd03e2013-01-29 03:56:06 +00004822 IRExpr_ITE(
sewardj009230b2013-01-26 11:47:55 +00004823 mk_x86g_calculate_condition(X86CondNBE),
florian99dd03e2013-01-29 03:56:06 +00004824 get_ST(r_src), get_ST(0)) );
sewardj519d66f2004-12-15 11:57:58 +00004825 break;
4826
sewardj8253ad32005-07-04 10:26:32 +00004827 case 0xD8 ... 0xDF: /* FCMOVNU ST(i), ST(0) */
4828 r_src = (UInt)modrm - 0xD8;
florianb1737742015-08-03 16:03:13 +00004829 DIP("fcmovnu %%st(%u), %%st(0)\n", r_src);
sewardj8253ad32005-07-04 10:26:32 +00004830 put_ST_UNCHECKED(0,
florian99dd03e2013-01-29 03:56:06 +00004831 IRExpr_ITE(
sewardj009230b2013-01-26 11:47:55 +00004832 mk_x86g_calculate_condition(X86CondNP),
florian99dd03e2013-01-29 03:56:06 +00004833 get_ST(r_src), get_ST(0)) );
sewardj8253ad32005-07-04 10:26:32 +00004834 break;
4835
sewardj7df596b2004-12-06 14:29:12 +00004836 case 0xE2:
4837 DIP("fnclex\n");
4838 break;
4839
sewardja0e83b02005-01-06 12:36:38 +00004840 case 0xE3: {
4841 /* Uses dirty helper:
4842 void x86g_do_FINIT ( VexGuestX86State* ) */
4843 IRDirty* d = unsafeIRDirty_0_N (
4844 0/*regparms*/,
4845 "x86g_dirtyhelper_FINIT",
4846 &x86g_dirtyhelper_FINIT,
Elliott Hughesed398002017-06-21 14:41:24 -07004847 mkIRExprVec_1(IRExpr_GSPTR())
sewardja0e83b02005-01-06 12:36:38 +00004848 );
sewardja0e83b02005-01-06 12:36:38 +00004849
4850 /* declare we're writing guest state */
4851 d->nFxState = 5;
sewardjc9069f22012-06-01 16:09:50 +00004852 vex_bzero(&d->fxState, sizeof(d->fxState));
sewardja0e83b02005-01-06 12:36:38 +00004853
4854 d->fxState[0].fx = Ifx_Write;
4855 d->fxState[0].offset = OFFB_FTOP;
4856 d->fxState[0].size = sizeof(UInt);
4857
4858 d->fxState[1].fx = Ifx_Write;
4859 d->fxState[1].offset = OFFB_FPREGS;
4860 d->fxState[1].size = 8 * sizeof(ULong);
4861
4862 d->fxState[2].fx = Ifx_Write;
4863 d->fxState[2].offset = OFFB_FPTAGS;
4864 d->fxState[2].size = 8 * sizeof(UChar);
4865
4866 d->fxState[3].fx = Ifx_Write;
4867 d->fxState[3].offset = OFFB_FPROUND;
4868 d->fxState[3].size = sizeof(UInt);
4869
4870 d->fxState[4].fx = Ifx_Write;
4871 d->fxState[4].offset = OFFB_FC3210;
4872 d->fxState[4].size = sizeof(UInt);
4873
4874 stmt( IRStmt_Dirty(d) );
4875
sewardj33dd31b2005-01-08 18:17:32 +00004876 DIP("fninit\n");
sewardja0e83b02005-01-06 12:36:38 +00004877 break;
4878 }
4879
sewardj8308aad2004-09-12 11:09:54 +00004880 case 0xE8 ... 0xEF: /* FUCOMI %st(0),%st(?) */
4881 fp_do_ucomi_ST0_STi( (UInt)modrm - 0xE8, False );
4882 break;
4883
sewardj37158712004-10-15 21:23:12 +00004884 case 0xF0 ... 0xF7: /* FCOMI %st(0),%st(?) */
4885 fp_do_ucomi_ST0_STi( (UInt)modrm - 0xF0, False );
4886 break;
4887
sewardj8308aad2004-09-12 11:09:54 +00004888 default:
4889 goto decode_fail;
sewardj17442fe2004-09-20 14:54:28 +00004890 }
sewardj89cd0932004-09-08 18:23:25 +00004891 }
sewardjd1725d12004-08-12 20:46:53 +00004892 }
4893
4894 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDC opcodes +-+-+-+-+-+-+-+ */
4895 else
4896 if (first_opcode == 0xDC) {
sewardja58ea662004-08-15 03:12:41 +00004897 if (modrm < 0xC0) {
4898
sewardj89cd0932004-09-08 18:23:25 +00004899 /* bits 5,4,3 are an opcode extension, and the modRM also
sewardjfeeb8a82004-11-30 12:30:11 +00004900 specifies an address. */
sewardja58ea662004-08-15 03:12:41 +00004901 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
4902 delta += len;
4903
4904 switch (gregOfRM(modrm)) {
4905
4906 case 0: /* FADD double-real */
4907 fp_do_op_mem_ST_0 ( addr, "add", dis_buf, Iop_AddF64, True );
4908 break;
4909
sewardjcfded9a2004-09-09 11:44:16 +00004910 case 1: /* FMUL double-real */
4911 fp_do_op_mem_ST_0 ( addr, "mul", dis_buf, Iop_MulF64, True );
4912 break;
4913
sewardje166ed02004-10-25 02:27:01 +00004914 case 2: /* FCOM double-real */
4915 DIP("fcoml %s\n", dis_buf);
4916 /* This forces C1 to zero, which isn't right. */
4917 put_C3210(
4918 binop( Iop_And32,
4919 binop(Iop_Shl32,
4920 binop(Iop_CmpF64,
4921 get_ST(0),
4922 loadLE(Ity_F64,mkexpr(addr))),
4923 mkU8(8)),
4924 mkU32(0x4500)
4925 ));
4926 break;
4927
sewardj883b00b2004-09-11 09:30:24 +00004928 case 3: /* FCOMP double-real */
sewardje166ed02004-10-25 02:27:01 +00004929 DIP("fcompl %s\n", dis_buf);
sewardj883b00b2004-09-11 09:30:24 +00004930 /* This forces C1 to zero, which isn't right. */
4931 put_C3210(
4932 binop( Iop_And32,
4933 binop(Iop_Shl32,
4934 binop(Iop_CmpF64,
4935 get_ST(0),
4936 loadLE(Ity_F64,mkexpr(addr))),
4937 mkU8(8)),
4938 mkU32(0x4500)
4939 ));
4940 fp_pop();
4941 break;
4942
sewardjcfded9a2004-09-09 11:44:16 +00004943 case 4: /* FSUB double-real */
4944 fp_do_op_mem_ST_0 ( addr, "sub", dis_buf, Iop_SubF64, True );
4945 break;
4946
sewardj3fd5e572004-09-09 22:43:51 +00004947 case 5: /* FSUBR double-real */
4948 fp_do_oprev_mem_ST_0 ( addr, "subr", dis_buf, Iop_SubF64, True );
4949 break;
4950
sewardjcfded9a2004-09-09 11:44:16 +00004951 case 6: /* FDIV double-real */
4952 fp_do_op_mem_ST_0 ( addr, "div", dis_buf, Iop_DivF64, True );
4953 break;
4954
sewardj883b00b2004-09-11 09:30:24 +00004955 case 7: /* FDIVR double-real */
4956 fp_do_oprev_mem_ST_0 ( addr, "divr", dis_buf, Iop_DivF64, True );
4957 break;
4958
sewardja58ea662004-08-15 03:12:41 +00004959 default:
florianb1737742015-08-03 16:03:13 +00004960 vex_printf("unhandled opc_aux = 0x%2x\n", (UInt)gregOfRM(modrm));
sewardja58ea662004-08-15 03:12:41 +00004961 vex_printf("first_opcode == 0xDC\n");
4962 goto decode_fail;
4963 }
4964
4965 } else {
sewardjbdc7d212004-09-09 02:46:40 +00004966
4967 delta++;
4968 switch (modrm) {
4969
sewardj3fd5e572004-09-09 22:43:51 +00004970 case 0xC0 ... 0xC7: /* FADD %st(0),%st(?) */
4971 fp_do_op_ST_ST ( "add", Iop_AddF64, 0, modrm - 0xC0, False );
4972 break;
4973
sewardjcfded9a2004-09-09 11:44:16 +00004974 case 0xC8 ... 0xCF: /* FMUL %st(0),%st(?) */
4975 fp_do_op_ST_ST ( "mul", Iop_MulF64, 0, modrm - 0xC8, False );
4976 break;
4977
sewardj47341042004-09-19 11:55:46 +00004978 case 0xE0 ... 0xE7: /* FSUBR %st(0),%st(?) */
4979 fp_do_oprev_ST_ST ( "subr", Iop_SubF64, 0, modrm - 0xE0, False );
4980 break;
4981
sewardjcfded9a2004-09-09 11:44:16 +00004982 case 0xE8 ... 0xEF: /* FSUB %st(0),%st(?) */
4983 fp_do_op_ST_ST ( "sub", Iop_SubF64, 0, modrm - 0xE8, False );
4984 break;
4985
sewardja0d48d62004-09-20 21:19:03 +00004986 case 0xF0 ... 0xF7: /* FDIVR %st(0),%st(?) */
4987 fp_do_oprev_ST_ST ( "divr", Iop_DivF64, 0, modrm - 0xF0, False );
4988 break;
4989
sewardjbdc7d212004-09-09 02:46:40 +00004990 case 0xF8 ... 0xFF: /* FDIV %st(0),%st(?) */
4991 fp_do_op_ST_ST ( "div", Iop_DivF64, 0, modrm - 0xF8, False );
4992 break;
4993
4994 default:
4995 goto decode_fail;
sewardj5bd4d162004-11-10 13:02:48 +00004996 }
sewardjbdc7d212004-09-09 02:46:40 +00004997
sewardja58ea662004-08-15 03:12:41 +00004998 }
sewardjd1725d12004-08-12 20:46:53 +00004999 }
5000
5001 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDD opcodes +-+-+-+-+-+-+-+ */
5002 else
5003 if (first_opcode == 0xDD) {
5004
5005 if (modrm < 0xC0) {
5006
sewardjfeeb8a82004-11-30 12:30:11 +00005007 /* bits 5,4,3 are an opcode extension, and the modRM also
sewardjd1725d12004-08-12 20:46:53 +00005008 specifies an address. */
sewardjbb53f8c2004-08-14 11:50:01 +00005009 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
5010 delta += len;
sewardjd1725d12004-08-12 20:46:53 +00005011
5012 switch (gregOfRM(modrm)) {
5013
5014 case 0: /* FLD double-real */
sewardj33dd31b2005-01-08 18:17:32 +00005015 DIP("fldl %s\n", dis_buf);
sewardj207557a2004-08-27 12:00:18 +00005016 fp_push();
sewardjaf1ceca2005-06-30 23:31:27 +00005017 put_ST(0, loadLE(Ity_F64, mkexpr(addr)));
sewardjbb53f8c2004-08-14 11:50:01 +00005018 break;
sewardjd1725d12004-08-12 20:46:53 +00005019
sewardjdd5d2042006-08-03 15:03:19 +00005020 case 1: /* FISTTPQ m64 (SSE3) */
5021 DIP("fistppll %s\n", dis_buf);
5022 storeLE( mkexpr(addr),
sewardj6c299f32009-12-31 18:00:12 +00005023 binop(Iop_F64toI64S, mkU32(Irrm_ZERO), get_ST(0)) );
sewardjdd5d2042006-08-03 15:03:19 +00005024 fp_pop();
5025 break;
5026
sewardjd1725d12004-08-12 20:46:53 +00005027 case 2: /* FST double-real */
sewardj33dd31b2005-01-08 18:17:32 +00005028 DIP("fstl %s\n", dis_buf);
sewardj5bd4d162004-11-10 13:02:48 +00005029 storeLE(mkexpr(addr), get_ST(0));
sewardjd1725d12004-08-12 20:46:53 +00005030 break;
sewardj89cd0932004-09-08 18:23:25 +00005031
sewardja58ea662004-08-15 03:12:41 +00005032 case 3: /* FSTP double-real */
sewardj33dd31b2005-01-08 18:17:32 +00005033 DIP("fstpl %s\n", dis_buf);
sewardj5bd4d162004-11-10 13:02:48 +00005034 storeLE(mkexpr(addr), get_ST(0));
5035 fp_pop();
sewardja58ea662004-08-15 03:12:41 +00005036 break;
sewardjd1725d12004-08-12 20:46:53 +00005037
sewardj9fc9e782004-11-26 17:57:40 +00005038 case 4: { /* FRSTOR m108 */
sewardj893aada2004-11-29 19:57:54 +00005039 /* Uses dirty helper:
florian6ef84be2012-08-26 03:20:07 +00005040 VexEmNote x86g_do_FRSTOR ( VexGuestX86State*, Addr32 ) */
sewardj893aada2004-11-29 19:57:54 +00005041 IRTemp ew = newTemp(Ity_I32);
5042 IRDirty* d = unsafeIRDirty_0_N (
5043 0/*regparms*/,
5044 "x86g_dirtyhelper_FRSTOR",
5045 &x86g_dirtyhelper_FRSTOR,
Elliott Hughesed398002017-06-21 14:41:24 -07005046 mkIRExprVec_2( IRExpr_GSPTR(), mkexpr(addr) )
sewardj893aada2004-11-29 19:57:54 +00005047 );
sewardj74142b82013-08-08 10:28:59 +00005048 d->tmp = ew;
sewardj9fc9e782004-11-26 17:57:40 +00005049 /* declare we're reading memory */
5050 d->mFx = Ifx_Read;
5051 d->mAddr = mkexpr(addr);
5052 d->mSize = 108;
5053
5054 /* declare we're writing guest state */
sewardj893aada2004-11-29 19:57:54 +00005055 d->nFxState = 5;
sewardjc9069f22012-06-01 16:09:50 +00005056 vex_bzero(&d->fxState, sizeof(d->fxState));
sewardj9fc9e782004-11-26 17:57:40 +00005057
5058 d->fxState[0].fx = Ifx_Write;
sewardjc9a43662004-11-30 18:51:59 +00005059 d->fxState[0].offset = OFFB_FTOP;
sewardj9fc9e782004-11-26 17:57:40 +00005060 d->fxState[0].size = sizeof(UInt);
5061
5062 d->fxState[1].fx = Ifx_Write;
sewardjc9a43662004-11-30 18:51:59 +00005063 d->fxState[1].offset = OFFB_FPREGS;
sewardj9fc9e782004-11-26 17:57:40 +00005064 d->fxState[1].size = 8 * sizeof(ULong);
5065
5066 d->fxState[2].fx = Ifx_Write;
sewardjc9a43662004-11-30 18:51:59 +00005067 d->fxState[2].offset = OFFB_FPTAGS;
sewardj9fc9e782004-11-26 17:57:40 +00005068 d->fxState[2].size = 8 * sizeof(UChar);
5069
5070 d->fxState[3].fx = Ifx_Write;
sewardjc9a43662004-11-30 18:51:59 +00005071 d->fxState[3].offset = OFFB_FPROUND;
sewardj9fc9e782004-11-26 17:57:40 +00005072 d->fxState[3].size = sizeof(UInt);
5073
5074 d->fxState[4].fx = Ifx_Write;
sewardjc9a43662004-11-30 18:51:59 +00005075 d->fxState[4].offset = OFFB_FC3210;
sewardj9fc9e782004-11-26 17:57:40 +00005076 d->fxState[4].size = sizeof(UInt);
5077
5078 stmt( IRStmt_Dirty(d) );
5079
sewardj893aada2004-11-29 19:57:54 +00005080 /* ew contains any emulation warning we may need to
5081 issue. If needed, side-exit to the next insn,
5082 reporting the warning, so that Valgrind's dispatcher
5083 sees the warning. */
5084 put_emwarn( mkexpr(ew) );
5085 stmt(
5086 IRStmt_Exit(
5087 binop(Iop_CmpNE32, mkexpr(ew), mkU32(0)),
5088 Ijk_EmWarn,
sewardjc6f970f2012-04-02 21:54:49 +00005089 IRConst_U32( ((Addr32)guest_EIP_bbstart)+delta),
5090 OFFB_EIP
sewardj893aada2004-11-29 19:57:54 +00005091 )
5092 );
5093
sewardj33dd31b2005-01-08 18:17:32 +00005094 DIP("frstor %s\n", dis_buf);
sewardj9fc9e782004-11-26 17:57:40 +00005095 break;
5096 }
5097
5098 case 6: { /* FNSAVE m108 */
sewardj893aada2004-11-29 19:57:54 +00005099 /* Uses dirty helper:
5100 void x86g_do_FSAVE ( VexGuestX86State*, UInt ) */
sewardj9fc9e782004-11-26 17:57:40 +00005101 IRDirty* d = unsafeIRDirty_0_N (
5102 0/*regparms*/,
5103 "x86g_dirtyhelper_FSAVE",
5104 &x86g_dirtyhelper_FSAVE,
Elliott Hughesed398002017-06-21 14:41:24 -07005105 mkIRExprVec_2( IRExpr_GSPTR(), mkexpr(addr) )
sewardj9fc9e782004-11-26 17:57:40 +00005106 );
sewardj9fc9e782004-11-26 17:57:40 +00005107 /* declare we're writing memory */
5108 d->mFx = Ifx_Write;
5109 d->mAddr = mkexpr(addr);
5110 d->mSize = 108;
5111
5112 /* declare we're reading guest state */
sewardj893aada2004-11-29 19:57:54 +00005113 d->nFxState = 5;
sewardjc9069f22012-06-01 16:09:50 +00005114 vex_bzero(&d->fxState, sizeof(d->fxState));
sewardj9fc9e782004-11-26 17:57:40 +00005115
5116 d->fxState[0].fx = Ifx_Read;
sewardjc9a43662004-11-30 18:51:59 +00005117 d->fxState[0].offset = OFFB_FTOP;
sewardj9fc9e782004-11-26 17:57:40 +00005118 d->fxState[0].size = sizeof(UInt);
5119
5120 d->fxState[1].fx = Ifx_Read;
sewardjc9a43662004-11-30 18:51:59 +00005121 d->fxState[1].offset = OFFB_FPREGS;
sewardj9fc9e782004-11-26 17:57:40 +00005122 d->fxState[1].size = 8 * sizeof(ULong);
5123
5124 d->fxState[2].fx = Ifx_Read;
sewardjc9a43662004-11-30 18:51:59 +00005125 d->fxState[2].offset = OFFB_FPTAGS;
sewardj9fc9e782004-11-26 17:57:40 +00005126 d->fxState[2].size = 8 * sizeof(UChar);
5127
5128 d->fxState[3].fx = Ifx_Read;
sewardjc9a43662004-11-30 18:51:59 +00005129 d->fxState[3].offset = OFFB_FPROUND;
sewardj9fc9e782004-11-26 17:57:40 +00005130 d->fxState[3].size = sizeof(UInt);
5131
5132 d->fxState[4].fx = Ifx_Read;
sewardjc9a43662004-11-30 18:51:59 +00005133 d->fxState[4].offset = OFFB_FC3210;
sewardj9fc9e782004-11-26 17:57:40 +00005134 d->fxState[4].size = sizeof(UInt);
5135
5136 stmt( IRStmt_Dirty(d) );
5137
sewardj33dd31b2005-01-08 18:17:32 +00005138 DIP("fnsave %s\n", dis_buf);
sewardj9fc9e782004-11-26 17:57:40 +00005139 break;
5140 }
5141
sewardjd24931d2005-03-20 12:51:39 +00005142 case 7: { /* FNSTSW m16 */
5143 IRExpr* sw = get_FPU_sw();
sewardjdd40fdf2006-12-24 02:20:24 +00005144 vassert(typeOfIRExpr(irsb->tyenv, sw) == Ity_I16);
sewardjd24931d2005-03-20 12:51:39 +00005145 storeLE( mkexpr(addr), sw );
5146 DIP("fnstsw %s\n", dis_buf);
5147 break;
5148 }
5149
sewardjd1725d12004-08-12 20:46:53 +00005150 default:
florianb1737742015-08-03 16:03:13 +00005151 vex_printf("unhandled opc_aux = 0x%2x\n", (UInt)gregOfRM(modrm));
sewardjbb53f8c2004-08-14 11:50:01 +00005152 vex_printf("first_opcode == 0xDD\n");
sewardjd1725d12004-08-12 20:46:53 +00005153 goto decode_fail;
sewardjbb53f8c2004-08-14 11:50:01 +00005154 }
sewardjd1725d12004-08-12 20:46:53 +00005155 } else {
sewardja58ea662004-08-15 03:12:41 +00005156 delta++;
5157 switch (modrm) {
sewardjbdc7d212004-09-09 02:46:40 +00005158
sewardj3ddedc42005-03-25 20:30:00 +00005159 case 0xC0 ... 0xC7: /* FFREE %st(?) */
5160 r_dst = (UInt)modrm - 0xC0;
florianb1737742015-08-03 16:03:13 +00005161 DIP("ffree %%st(%u)\n", r_dst);
sewardj3ddedc42005-03-25 20:30:00 +00005162 put_ST_TAG ( r_dst, mkU8(0) );
5163 break;
5164
sewardj06c32a02004-09-12 12:07:34 +00005165 case 0xD0 ... 0xD7: /* FST %st(0),%st(?) */
5166 r_dst = (UInt)modrm - 0xD0;
florianb1737742015-08-03 16:03:13 +00005167 DIP("fst %%st(0),%%st(%u)\n", r_dst);
sewardj5bd4d162004-11-10 13:02:48 +00005168 /* P4 manual says: "If the destination operand is a
sewardj06c32a02004-09-12 12:07:34 +00005169 non-empty register, the invalid-operation exception
5170 is not generated. Hence put_ST_UNCHECKED. */
5171 put_ST_UNCHECKED(r_dst, get_ST(0));
5172 break;
5173
sewardja58ea662004-08-15 03:12:41 +00005174 case 0xD8 ... 0xDF: /* FSTP %st(0),%st(?) */
5175 r_dst = (UInt)modrm - 0xD8;
florianb1737742015-08-03 16:03:13 +00005176 DIP("fstp %%st(0),%%st(%u)\n", r_dst);
sewardj5bd4d162004-11-10 13:02:48 +00005177 /* P4 manual says: "If the destination operand is a
sewardj207557a2004-08-27 12:00:18 +00005178 non-empty register, the invalid-operation exception
5179 is not generated. Hence put_ST_UNCHECKED. */
5180 put_ST_UNCHECKED(r_dst, get_ST(0));
5181 fp_pop();
sewardja58ea662004-08-15 03:12:41 +00005182 break;
sewardjbdc7d212004-09-09 02:46:40 +00005183
5184 case 0xE0 ... 0xE7: /* FUCOM %st(0),%st(?) */
5185 r_dst = (UInt)modrm - 0xE0;
florianb1737742015-08-03 16:03:13 +00005186 DIP("fucom %%st(0),%%st(%u)\n", r_dst);
sewardjc4be80c2004-09-10 16:17:45 +00005187 /* This forces C1 to zero, which isn't right. */
5188 put_C3210(
5189 binop( Iop_And32,
5190 binop(Iop_Shl32,
5191 binop(Iop_CmpF64, get_ST(0), get_ST(r_dst)),
5192 mkU8(8)),
5193 mkU32(0x4500)
5194 ));
sewardjbdc7d212004-09-09 02:46:40 +00005195 break;
5196
5197 case 0xE8 ... 0xEF: /* FUCOMP %st(0),%st(?) */
5198 r_dst = (UInt)modrm - 0xE8;
florianb1737742015-08-03 16:03:13 +00005199 DIP("fucomp %%st(0),%%st(%u)\n", r_dst);
sewardjc4be80c2004-09-10 16:17:45 +00005200 /* This forces C1 to zero, which isn't right. */
5201 put_C3210(
5202 binop( Iop_And32,
5203 binop(Iop_Shl32,
5204 binop(Iop_CmpF64, get_ST(0), get_ST(r_dst)),
5205 mkU8(8)),
5206 mkU32(0x4500)
5207 ));
sewardjbdc7d212004-09-09 02:46:40 +00005208 fp_pop();
5209 break;
5210
sewardj5bd4d162004-11-10 13:02:48 +00005211 default:
sewardja58ea662004-08-15 03:12:41 +00005212 goto decode_fail;
sewardj5bd4d162004-11-10 13:02:48 +00005213 }
sewardjd1725d12004-08-12 20:46:53 +00005214 }
5215 }
5216
5217 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDE opcodes +-+-+-+-+-+-+-+ */
5218 else
5219 if (first_opcode == 0xDE) {
sewardjbdc7d212004-09-09 02:46:40 +00005220
5221 if (modrm < 0xC0) {
sewardjfeeb8a82004-11-30 12:30:11 +00005222
5223 /* bits 5,4,3 are an opcode extension, and the modRM also
5224 specifies an address. */
5225 IROp fop;
5226 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
5227 delta += len;
5228
5229 switch (gregOfRM(modrm)) {
5230
5231 case 0: /* FIADD m16int */ /* ST(0) += m16int */
sewardj33dd31b2005-01-08 18:17:32 +00005232 DIP("fiaddw %s\n", dis_buf);
sewardjfeeb8a82004-11-30 12:30:11 +00005233 fop = Iop_AddF64;
5234 goto do_fop_m16;
5235
5236 case 1: /* FIMUL m16int */ /* ST(0) *= m16int */
sewardj33dd31b2005-01-08 18:17:32 +00005237 DIP("fimulw %s\n", dis_buf);
sewardjfeeb8a82004-11-30 12:30:11 +00005238 fop = Iop_MulF64;
5239 goto do_fop_m16;
5240
sewardj071895f2005-07-29 11:28:38 +00005241 case 2: /* FICOM m16int */
5242 DIP("ficomw %s\n", dis_buf);
5243 /* This forces C1 to zero, which isn't right. */
5244 put_C3210(
5245 binop( Iop_And32,
5246 binop(Iop_Shl32,
5247 binop(Iop_CmpF64,
5248 get_ST(0),
sewardj6c299f32009-12-31 18:00:12 +00005249 unop(Iop_I32StoF64,
sewardj071895f2005-07-29 11:28:38 +00005250 unop(Iop_16Sto32,
5251 loadLE(Ity_I16,mkexpr(addr))))),
5252 mkU8(8)),
5253 mkU32(0x4500)
5254 ));
5255 break;
5256
5257 case 3: /* FICOMP m16int */
5258 DIP("ficompw %s\n", dis_buf);
5259 /* This forces C1 to zero, which isn't right. */
5260 put_C3210(
5261 binop( Iop_And32,
5262 binop(Iop_Shl32,
5263 binop(Iop_CmpF64,
5264 get_ST(0),
sewardj6c299f32009-12-31 18:00:12 +00005265 unop(Iop_I32StoF64,
sewardj071895f2005-07-29 11:28:38 +00005266 unop(Iop_16Sto32,
sewardjf1b5b1a2006-02-03 22:54:17 +00005267 loadLE(Ity_I16,mkexpr(addr))))),
sewardj071895f2005-07-29 11:28:38 +00005268 mkU8(8)),
5269 mkU32(0x4500)
5270 ));
5271 fp_pop();
5272 break;
5273
sewardjfeeb8a82004-11-30 12:30:11 +00005274 case 4: /* FISUB m16int */ /* ST(0) -= m16int */
sewardj33dd31b2005-01-08 18:17:32 +00005275 DIP("fisubw %s\n", dis_buf);
sewardjfeeb8a82004-11-30 12:30:11 +00005276 fop = Iop_SubF64;
5277 goto do_fop_m16;
5278
5279 case 5: /* FISUBR m16int */ /* ST(0) = m16int - ST(0) */
sewardj33dd31b2005-01-08 18:17:32 +00005280 DIP("fisubrw %s\n", dis_buf);
sewardjfeeb8a82004-11-30 12:30:11 +00005281 fop = Iop_SubF64;
5282 goto do_foprev_m16;
5283
5284 case 6: /* FIDIV m16int */ /* ST(0) /= m16int */
sewardj33dd31b2005-01-08 18:17:32 +00005285 DIP("fisubw %s\n", dis_buf);
sewardjfeeb8a82004-11-30 12:30:11 +00005286 fop = Iop_DivF64;
5287 goto do_fop_m16;
5288
5289 case 7: /* FIDIVR m16int */ /* ST(0) = m16int / ST(0) */
sewardj33dd31b2005-01-08 18:17:32 +00005290 DIP("fidivrw %s\n", dis_buf);
sewardjfeeb8a82004-11-30 12:30:11 +00005291 fop = Iop_DivF64;
5292 goto do_foprev_m16;
5293
5294 do_fop_m16:
5295 put_ST_UNCHECKED(0,
sewardjf1b5b1a2006-02-03 22:54:17 +00005296 triop(fop,
5297 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
sewardjfeeb8a82004-11-30 12:30:11 +00005298 get_ST(0),
sewardj6c299f32009-12-31 18:00:12 +00005299 unop(Iop_I32StoF64,
sewardjfeeb8a82004-11-30 12:30:11 +00005300 unop(Iop_16Sto32,
5301 loadLE(Ity_I16, mkexpr(addr))))));
5302 break;
5303
5304 do_foprev_m16:
5305 put_ST_UNCHECKED(0,
sewardjf1b5b1a2006-02-03 22:54:17 +00005306 triop(fop,
5307 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
sewardj6c299f32009-12-31 18:00:12 +00005308 unop(Iop_I32StoF64,
sewardjfeeb8a82004-11-30 12:30:11 +00005309 unop(Iop_16Sto32,
5310 loadLE(Ity_I16, mkexpr(addr)))),
5311 get_ST(0)));
5312 break;
5313
5314 default:
florianb1737742015-08-03 16:03:13 +00005315 vex_printf("unhandled opc_aux = 0x%2x\n", (UInt)gregOfRM(modrm));
sewardjfeeb8a82004-11-30 12:30:11 +00005316 vex_printf("first_opcode == 0xDE\n");
5317 goto decode_fail;
5318 }
sewardjbdc7d212004-09-09 02:46:40 +00005319
5320 } else {
5321
5322 delta++;
sewardj5bd4d162004-11-10 13:02:48 +00005323 switch (modrm) {
sewardjbdc7d212004-09-09 02:46:40 +00005324
sewardjcfded9a2004-09-09 11:44:16 +00005325 case 0xC0 ... 0xC7: /* FADDP %st(0),%st(?) */
5326 fp_do_op_ST_ST ( "add", Iop_AddF64, 0, modrm - 0xC0, True );
5327 break;
5328
sewardjbdc7d212004-09-09 02:46:40 +00005329 case 0xC8 ... 0xCF: /* FMULP %st(0),%st(?) */
5330 fp_do_op_ST_ST ( "mul", Iop_MulF64, 0, modrm - 0xC8, True );
5331 break;
5332
sewardje166ed02004-10-25 02:27:01 +00005333 case 0xD9: /* FCOMPP %st(0),%st(1) */
5334 DIP("fuompp %%st(0),%%st(1)\n");
5335 /* This forces C1 to zero, which isn't right. */
5336 put_C3210(
5337 binop( Iop_And32,
5338 binop(Iop_Shl32,
5339 binop(Iop_CmpF64, get_ST(0), get_ST(1)),
5340 mkU8(8)),
5341 mkU32(0x4500)
5342 ));
5343 fp_pop();
5344 fp_pop();
5345 break;
5346
sewardjcfded9a2004-09-09 11:44:16 +00005347 case 0xE0 ... 0xE7: /* FSUBRP %st(0),%st(?) */
5348 fp_do_oprev_ST_ST ( "subr", Iop_SubF64, 0, modrm - 0xE0, True );
5349 break;
5350
sewardj3fd5e572004-09-09 22:43:51 +00005351 case 0xE8 ... 0xEF: /* FSUBP %st(0),%st(?) */
5352 fp_do_op_ST_ST ( "sub", Iop_SubF64, 0, modrm - 0xE8, True );
5353 break;
5354
sewardjbdc7d212004-09-09 02:46:40 +00005355 case 0xF0 ... 0xF7: /* FDIVRP %st(0),%st(?) */
5356 fp_do_oprev_ST_ST ( "divr", Iop_DivF64, 0, modrm - 0xF0, True );
5357 break;
5358
5359 case 0xF8 ... 0xFF: /* FDIVP %st(0),%st(?) */
5360 fp_do_op_ST_ST ( "div", Iop_DivF64, 0, modrm - 0xF8, True );
5361 break;
5362
5363 default:
5364 goto decode_fail;
sewardj5bd4d162004-11-10 13:02:48 +00005365 }
sewardjbdc7d212004-09-09 02:46:40 +00005366
5367 }
sewardjd1725d12004-08-12 20:46:53 +00005368 }
5369
5370 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDF opcodes +-+-+-+-+-+-+-+ */
5371 else
5372 if (first_opcode == 0xDF) {
sewardj89cd0932004-09-08 18:23:25 +00005373
5374 if (modrm < 0xC0) {
5375
sewardjfeeb8a82004-11-30 12:30:11 +00005376 /* bits 5,4,3 are an opcode extension, and the modRM also
sewardj89cd0932004-09-08 18:23:25 +00005377 specifies an address. */
5378 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
5379 delta += len;
5380
5381 switch (gregOfRM(modrm)) {
5382
sewardj883b00b2004-09-11 09:30:24 +00005383 case 0: /* FILD m16int */
5384 DIP("fildw %s\n", dis_buf);
5385 fp_push();
sewardj6c299f32009-12-31 18:00:12 +00005386 put_ST(0, unop(Iop_I32StoF64,
sewardj883b00b2004-09-11 09:30:24 +00005387 unop(Iop_16Sto32,
5388 loadLE(Ity_I16, mkexpr(addr)))));
5389 break;
5390
sewardjdd5d2042006-08-03 15:03:19 +00005391 case 1: /* FISTTPS m16 (SSE3) */
5392 DIP("fisttps %s\n", dis_buf);
5393 storeLE( mkexpr(addr),
sewardj6c299f32009-12-31 18:00:12 +00005394 binop(Iop_F64toI16S, mkU32(Irrm_ZERO), get_ST(0)) );
sewardjdd5d2042006-08-03 15:03:19 +00005395 fp_pop();
5396 break;
5397
sewardj37158712004-10-15 21:23:12 +00005398 case 2: /* FIST m16 */
sewardj33dd31b2005-01-08 18:17:32 +00005399 DIP("fistp %s\n", dis_buf);
sewardj37158712004-10-15 21:23:12 +00005400 storeLE( mkexpr(addr),
sewardj6c299f32009-12-31 18:00:12 +00005401 binop(Iop_F64toI16S, get_roundingmode(), get_ST(0)) );
sewardj37158712004-10-15 21:23:12 +00005402 break;
5403
sewardj89cd0932004-09-08 18:23:25 +00005404 case 3: /* FISTP m16 */
sewardj33dd31b2005-01-08 18:17:32 +00005405 DIP("fistps %s\n", dis_buf);
sewardj8f3debf2004-09-08 23:42:23 +00005406 storeLE( mkexpr(addr),
sewardj6c299f32009-12-31 18:00:12 +00005407 binop(Iop_F64toI16S, get_roundingmode(), get_ST(0)) );
sewardj8f3debf2004-09-08 23:42:23 +00005408 fp_pop();
sewardj89cd0932004-09-08 18:23:25 +00005409 break;
5410
sewardj89cd0932004-09-08 18:23:25 +00005411 case 5: /* FILD m64 */
5412 DIP("fildll %s\n", dis_buf);
5413 fp_push();
sewardj6c299f32009-12-31 18:00:12 +00005414 put_ST(0, binop(Iop_I64StoF64,
sewardj4cb918d2004-12-03 19:43:31 +00005415 get_roundingmode(),
5416 loadLE(Ity_I64, mkexpr(addr))));
sewardj89cd0932004-09-08 18:23:25 +00005417 break;
sewardj89cd0932004-09-08 18:23:25 +00005418
sewardjcfded9a2004-09-09 11:44:16 +00005419 case 7: /* FISTP m64 */
sewardj33dd31b2005-01-08 18:17:32 +00005420 DIP("fistpll %s\n", dis_buf);
sewardjcfded9a2004-09-09 11:44:16 +00005421 storeLE( mkexpr(addr),
sewardj6c299f32009-12-31 18:00:12 +00005422 binop(Iop_F64toI64S, get_roundingmode(), get_ST(0)) );
sewardjcfded9a2004-09-09 11:44:16 +00005423 fp_pop();
5424 break;
5425
sewardj89cd0932004-09-08 18:23:25 +00005426 default:
florianb1737742015-08-03 16:03:13 +00005427 vex_printf("unhandled opc_aux = 0x%2x\n", (UInt)gregOfRM(modrm));
sewardj89cd0932004-09-08 18:23:25 +00005428 vex_printf("first_opcode == 0xDF\n");
5429 goto decode_fail;
5430 }
5431
5432 } else {
sewardjbdc7d212004-09-09 02:46:40 +00005433
5434 delta++;
sewardj5bd4d162004-11-10 13:02:48 +00005435 switch (modrm) {
sewardjbdc7d212004-09-09 02:46:40 +00005436
sewardj8fb88692005-07-29 11:57:00 +00005437 case 0xC0: /* FFREEP %st(0) */
5438 DIP("ffreep %%st(%d)\n", 0);
5439 put_ST_TAG ( 0, mkU8(0) );
5440 fp_pop();
5441 break;
5442
sewardjbdc7d212004-09-09 02:46:40 +00005443 case 0xE0: /* FNSTSW %ax */
5444 DIP("fnstsw %%ax\n");
sewardjd24931d2005-03-20 12:51:39 +00005445 /* Get the FPU status word value and dump it in %AX. */
sewardj1d2e77f2008-06-04 09:10:38 +00005446 if (0) {
5447 /* The obvious thing to do is simply dump the 16-bit
5448 status word value in %AX. However, due to a
5449 limitation in Memcheck's origin tracking
5450 machinery, this causes Memcheck not to track the
5451 origin of any undefinedness into %AH (only into
5452 %AL/%AX/%EAX), which means origins are lost in
5453 the sequence "fnstsw %ax; test $M,%ah; jcond .." */
5454 putIReg(2, R_EAX, get_FPU_sw());
5455 } else {
5456 /* So a somewhat lame kludge is to make it very
5457 clear to Memcheck that the value is written to
5458 both %AH and %AL. This generates marginally
5459 worse code, but I don't think it matters much. */
5460 IRTemp t16 = newTemp(Ity_I16);
5461 assign(t16, get_FPU_sw());
5462 putIReg( 1, R_AL, unop(Iop_16to8, mkexpr(t16)) );
5463 putIReg( 1, R_AH, unop(Iop_16HIto8, mkexpr(t16)) );
5464 }
sewardjbdc7d212004-09-09 02:46:40 +00005465 break;
5466
sewardj883b00b2004-09-11 09:30:24 +00005467 case 0xE8 ... 0xEF: /* FUCOMIP %st(0),%st(?) */
sewardj8308aad2004-09-12 11:09:54 +00005468 fp_do_ucomi_ST0_STi( (UInt)modrm - 0xE8, True );
sewardj883b00b2004-09-11 09:30:24 +00005469 break;
5470
sewardjfeeb8a82004-11-30 12:30:11 +00005471 case 0xF0 ... 0xF7: /* FCOMIP %st(0),%st(?) */
5472 /* not really right since COMIP != UCOMIP */
5473 fp_do_ucomi_ST0_STi( (UInt)modrm - 0xF0, True );
5474 break;
5475
sewardjbdc7d212004-09-09 02:46:40 +00005476 default:
5477 goto decode_fail;
sewardj5bd4d162004-11-10 13:02:48 +00005478 }
sewardj89cd0932004-09-08 18:23:25 +00005479 }
5480
sewardjd1725d12004-08-12 20:46:53 +00005481 }
5482
5483 else
5484 vpanic("dis_FPU(x86): invalid primary opcode");
5485
sewardj69d9d662004-10-14 21:58:52 +00005486 *decode_ok = True;
5487 return delta;
5488
sewardjd1725d12004-08-12 20:46:53 +00005489 decode_fail:
5490 *decode_ok = False;
5491 return delta;
5492}
5493
5494
sewardj464efa42004-11-19 22:17:29 +00005495/*------------------------------------------------------------*/
5496/*--- ---*/
5497/*--- MMX INSTRUCTIONS ---*/
5498/*--- ---*/
5499/*------------------------------------------------------------*/
sewardja06e5562004-07-14 13:18:05 +00005500
sewardj464efa42004-11-19 22:17:29 +00005501/* Effect of MMX insns on x87 FPU state (table 11-2 of
5502 IA32 arch manual, volume 3):
5503
5504 Read from, or write to MMX register (viz, any insn except EMMS):
5505 * All tags set to Valid (non-empty) -- FPTAGS[i] := nonzero
5506 * FP stack pointer set to zero
5507
5508 EMMS:
5509 * All tags set to Invalid (empty) -- FPTAGS[i] := zero
5510 * FP stack pointer set to zero
5511*/
5512
sewardj4cb918d2004-12-03 19:43:31 +00005513static void do_MMX_preamble ( void )
sewardj464efa42004-11-19 22:17:29 +00005514{
sewardjdd40fdf2006-12-24 02:20:24 +00005515 Int i;
5516 IRRegArray* descr = mkIRRegArray( OFFB_FPTAGS, Ity_I8, 8 );
5517 IRExpr* zero = mkU32(0);
5518 IRExpr* tag1 = mkU8(1);
sewardj464efa42004-11-19 22:17:29 +00005519 put_ftop(zero);
5520 for (i = 0; i < 8; i++)
floriand6f38b32012-05-31 15:46:18 +00005521 stmt( IRStmt_PutI( mkIRPutI(descr, zero, i, tag1) ) );
sewardj464efa42004-11-19 22:17:29 +00005522}
5523
sewardj4cb918d2004-12-03 19:43:31 +00005524static void do_EMMS_preamble ( void )
sewardj464efa42004-11-19 22:17:29 +00005525{
sewardjdd40fdf2006-12-24 02:20:24 +00005526 Int i;
5527 IRRegArray* descr = mkIRRegArray( OFFB_FPTAGS, Ity_I8, 8 );
5528 IRExpr* zero = mkU32(0);
5529 IRExpr* tag0 = mkU8(0);
sewardj464efa42004-11-19 22:17:29 +00005530 put_ftop(zero);
5531 for (i = 0; i < 8; i++)
floriand6f38b32012-05-31 15:46:18 +00005532 stmt( IRStmt_PutI( mkIRPutI(descr, zero, i, tag0) ) );
sewardj464efa42004-11-19 22:17:29 +00005533}
5534
5535
5536static IRExpr* getMMXReg ( UInt archreg )
5537{
5538 vassert(archreg < 8);
5539 return IRExpr_Get( OFFB_FPREGS + 8 * archreg, Ity_I64 );
5540}
5541
5542
5543static void putMMXReg ( UInt archreg, IRExpr* e )
5544{
5545 vassert(archreg < 8);
sewardjdd40fdf2006-12-24 02:20:24 +00005546 vassert(typeOfIRExpr(irsb->tyenv,e) == Ity_I64);
sewardj464efa42004-11-19 22:17:29 +00005547 stmt( IRStmt_Put( OFFB_FPREGS + 8 * archreg, e ) );
5548}
5549
5550
sewardj38a3f862005-01-13 15:06:51 +00005551/* Helper for non-shift MMX insns. Note this is incomplete in the
5552 sense that it does not first call do_MMX_preamble() -- that is the
5553 responsibility of its caller. */
5554
sewardj464efa42004-11-19 22:17:29 +00005555static
sewardj2d49b432005-02-01 00:37:06 +00005556UInt dis_MMXop_regmem_to_reg ( UChar sorb,
sewardj52d04912005-07-03 00:52:48 +00005557 Int delta,
sewardj2d49b432005-02-01 00:37:06 +00005558 UChar opc,
florian55085f82012-11-21 00:36:55 +00005559 const HChar* name,
sewardj2d49b432005-02-01 00:37:06 +00005560 Bool show_granularity )
sewardj464efa42004-11-19 22:17:29 +00005561{
sewardjc9a43662004-11-30 18:51:59 +00005562 HChar dis_buf[50];
sewardj63ba4092004-11-21 12:30:18 +00005563 UChar modrm = getIByte(delta);
5564 Bool isReg = epartIsReg(modrm);
5565 IRExpr* argL = NULL;
5566 IRExpr* argR = NULL;
sewardj38a3f862005-01-13 15:06:51 +00005567 IRExpr* argG = NULL;
5568 IRExpr* argE = NULL;
sewardj63ba4092004-11-21 12:30:18 +00005569 IRTemp res = newTemp(Ity_I64);
sewardj464efa42004-11-19 22:17:29 +00005570
sewardj38a3f862005-01-13 15:06:51 +00005571 Bool invG = False;
5572 IROp op = Iop_INVALID;
5573 void* hAddr = NULL;
sewardj38a3f862005-01-13 15:06:51 +00005574 Bool eLeft = False;
florian55085f82012-11-21 00:36:55 +00005575 const HChar* hName = NULL;
sewardj38a3f862005-01-13 15:06:51 +00005576
sewardj2b7a9202004-11-26 19:15:38 +00005577# define XXX(_name) do { hAddr = &_name; hName = #_name; } while (0)
sewardj464efa42004-11-19 22:17:29 +00005578
sewardj464efa42004-11-19 22:17:29 +00005579 switch (opc) {
sewardjb5452082004-12-04 20:33:02 +00005580 /* Original MMX ones */
sewardj38a3f862005-01-13 15:06:51 +00005581 case 0xFC: op = Iop_Add8x8; break;
5582 case 0xFD: op = Iop_Add16x4; break;
5583 case 0xFE: op = Iop_Add32x2; break;
sewardj464efa42004-11-19 22:17:29 +00005584
sewardj38a3f862005-01-13 15:06:51 +00005585 case 0xEC: op = Iop_QAdd8Sx8; break;
5586 case 0xED: op = Iop_QAdd16Sx4; break;
sewardj464efa42004-11-19 22:17:29 +00005587
sewardj38a3f862005-01-13 15:06:51 +00005588 case 0xDC: op = Iop_QAdd8Ux8; break;
5589 case 0xDD: op = Iop_QAdd16Ux4; break;
sewardj464efa42004-11-19 22:17:29 +00005590
sewardj38a3f862005-01-13 15:06:51 +00005591 case 0xF8: op = Iop_Sub8x8; break;
5592 case 0xF9: op = Iop_Sub16x4; break;
5593 case 0xFA: op = Iop_Sub32x2; break;
sewardj464efa42004-11-19 22:17:29 +00005594
sewardj38a3f862005-01-13 15:06:51 +00005595 case 0xE8: op = Iop_QSub8Sx8; break;
5596 case 0xE9: op = Iop_QSub16Sx4; break;
sewardj464efa42004-11-19 22:17:29 +00005597
sewardj38a3f862005-01-13 15:06:51 +00005598 case 0xD8: op = Iop_QSub8Ux8; break;
5599 case 0xD9: op = Iop_QSub16Ux4; break;
sewardj464efa42004-11-19 22:17:29 +00005600
sewardj38a3f862005-01-13 15:06:51 +00005601 case 0xE5: op = Iop_MulHi16Sx4; break;
5602 case 0xD5: op = Iop_Mul16x4; break;
5603 case 0xF5: XXX(x86g_calculate_mmx_pmaddwd); break;
sewardj4340dac2004-11-20 13:17:04 +00005604
sewardj38a3f862005-01-13 15:06:51 +00005605 case 0x74: op = Iop_CmpEQ8x8; break;
5606 case 0x75: op = Iop_CmpEQ16x4; break;
5607 case 0x76: op = Iop_CmpEQ32x2; break;
sewardj4340dac2004-11-20 13:17:04 +00005608
sewardj38a3f862005-01-13 15:06:51 +00005609 case 0x64: op = Iop_CmpGT8Sx8; break;
5610 case 0x65: op = Iop_CmpGT16Sx4; break;
5611 case 0x66: op = Iop_CmpGT32Sx2; break;
sewardj63ba4092004-11-21 12:30:18 +00005612
sewardj5f438dd2011-06-16 11:36:23 +00005613 case 0x6B: op = Iop_QNarrowBin32Sto16Sx4; eLeft = True; break;
5614 case 0x63: op = Iop_QNarrowBin16Sto8Sx8; eLeft = True; break;
5615 case 0x67: op = Iop_QNarrowBin16Sto8Ux8; eLeft = True; break;
sewardj63ba4092004-11-21 12:30:18 +00005616
sewardj38a3f862005-01-13 15:06:51 +00005617 case 0x68: op = Iop_InterleaveHI8x8; eLeft = True; break;
5618 case 0x69: op = Iop_InterleaveHI16x4; eLeft = True; break;
5619 case 0x6A: op = Iop_InterleaveHI32x2; eLeft = True; break;
sewardj63ba4092004-11-21 12:30:18 +00005620
sewardj38a3f862005-01-13 15:06:51 +00005621 case 0x60: op = Iop_InterleaveLO8x8; eLeft = True; break;
5622 case 0x61: op = Iop_InterleaveLO16x4; eLeft = True; break;
5623 case 0x62: op = Iop_InterleaveLO32x2; eLeft = True; break;
sewardj63ba4092004-11-21 12:30:18 +00005624
sewardj38a3f862005-01-13 15:06:51 +00005625 case 0xDB: op = Iop_And64; break;
5626 case 0xDF: op = Iop_And64; invG = True; break;
5627 case 0xEB: op = Iop_Or64; break;
5628 case 0xEF: /* Possibly do better here if argL and argR are the
5629 same reg */
5630 op = Iop_Xor64; break;
sewardj464efa42004-11-19 22:17:29 +00005631
sewardjb5452082004-12-04 20:33:02 +00005632 /* Introduced in SSE1 */
sewardj38a3f862005-01-13 15:06:51 +00005633 case 0xE0: op = Iop_Avg8Ux8; break;
5634 case 0xE3: op = Iop_Avg16Ux4; break;
5635 case 0xEE: op = Iop_Max16Sx4; break;
5636 case 0xDE: op = Iop_Max8Ux8; break;
5637 case 0xEA: op = Iop_Min16Sx4; break;
5638 case 0xDA: op = Iop_Min8Ux8; break;
5639 case 0xE4: op = Iop_MulHi16Ux4; break;
5640 case 0xF6: XXX(x86g_calculate_mmx_psadbw); break;
sewardjb5452082004-12-04 20:33:02 +00005641
sewardj164f9272004-12-09 00:39:32 +00005642 /* Introduced in SSE2 */
sewardj38a3f862005-01-13 15:06:51 +00005643 case 0xD4: op = Iop_Add64; break;
5644 case 0xFB: op = Iop_Sub64; break;
sewardj164f9272004-12-09 00:39:32 +00005645
sewardj464efa42004-11-19 22:17:29 +00005646 default:
florianb1737742015-08-03 16:03:13 +00005647 vex_printf("\n0x%x\n", opc);
sewardj464efa42004-11-19 22:17:29 +00005648 vpanic("dis_MMXop_regmem_to_reg");
5649 }
5650
5651# undef XXX
5652
sewardj38a3f862005-01-13 15:06:51 +00005653 argG = getMMXReg(gregOfRM(modrm));
5654 if (invG)
5655 argG = unop(Iop_Not64, argG);
sewardj63ba4092004-11-21 12:30:18 +00005656
sewardj464efa42004-11-19 22:17:29 +00005657 if (isReg) {
sewardj464efa42004-11-19 22:17:29 +00005658 delta++;
sewardj38a3f862005-01-13 15:06:51 +00005659 argE = getMMXReg(eregOfRM(modrm));
sewardj464efa42004-11-19 22:17:29 +00005660 } else {
5661 Int len;
5662 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
5663 delta += len;
sewardj38a3f862005-01-13 15:06:51 +00005664 argE = loadLE(Ity_I64, mkexpr(addr));
sewardj464efa42004-11-19 22:17:29 +00005665 }
5666
sewardj38a3f862005-01-13 15:06:51 +00005667 if (eLeft) {
5668 argL = argE;
5669 argR = argG;
5670 } else {
5671 argL = argG;
5672 argR = argE;
5673 }
5674
5675 if (op != Iop_INVALID) {
5676 vassert(hName == NULL);
5677 vassert(hAddr == NULL);
5678 assign(res, binop(op, argL, argR));
5679 } else {
5680 vassert(hName != NULL);
5681 vassert(hAddr != NULL);
5682 assign( res,
5683 mkIRExprCCall(
5684 Ity_I64,
5685 0/*regparms*/, hName, hAddr,
5686 mkIRExprVec_2( argL, argR )
5687 )
5688 );
sewardj63ba4092004-11-21 12:30:18 +00005689 }
5690
5691 putMMXReg( gregOfRM(modrm), mkexpr(res) );
5692
sewardj464efa42004-11-19 22:17:29 +00005693 DIP("%s%s %s, %s\n",
sewardj2d49b432005-02-01 00:37:06 +00005694 name, show_granularity ? nameMMXGran(opc & 3) : "",
sewardj464efa42004-11-19 22:17:29 +00005695 ( isReg ? nameMMXReg(eregOfRM(modrm)) : dis_buf ),
5696 nameMMXReg(gregOfRM(modrm)) );
5697
5698 return delta;
5699}
5700
5701
sewardj38a3f862005-01-13 15:06:51 +00005702/* Vector by scalar shift of G by the amount specified at the bottom
5703 of E. This is a straight copy of dis_SSE_shiftG_byE. */
5704
sewardj52d04912005-07-03 00:52:48 +00005705static UInt dis_MMX_shiftG_byE ( UChar sorb, Int delta,
florian55085f82012-11-21 00:36:55 +00005706 const HChar* opname, IROp op )
sewardj38a3f862005-01-13 15:06:51 +00005707{
5708 HChar dis_buf[50];
5709 Int alen, size;
5710 IRTemp addr;
5711 Bool shl, shr, sar;
5712 UChar rm = getIByte(delta);
5713 IRTemp g0 = newTemp(Ity_I64);
5714 IRTemp g1 = newTemp(Ity_I64);
5715 IRTemp amt = newTemp(Ity_I32);
5716 IRTemp amt8 = newTemp(Ity_I8);
5717
5718 if (epartIsReg(rm)) {
5719 assign( amt, unop(Iop_64to32, getMMXReg(eregOfRM(rm))) );
5720 DIP("%s %s,%s\n", opname,
5721 nameMMXReg(eregOfRM(rm)),
5722 nameMMXReg(gregOfRM(rm)) );
5723 delta++;
5724 } else {
5725 addr = disAMode ( &alen, sorb, delta, dis_buf );
5726 assign( amt, loadLE(Ity_I32, mkexpr(addr)) );
5727 DIP("%s %s,%s\n", opname,
5728 dis_buf,
5729 nameMMXReg(gregOfRM(rm)) );
5730 delta += alen;
5731 }
5732 assign( g0, getMMXReg(gregOfRM(rm)) );
5733 assign( amt8, unop(Iop_32to8, mkexpr(amt)) );
5734
5735 shl = shr = sar = False;
5736 size = 0;
5737 switch (op) {
5738 case Iop_ShlN16x4: shl = True; size = 32; break;
5739 case Iop_ShlN32x2: shl = True; size = 32; break;
5740 case Iop_Shl64: shl = True; size = 64; break;
5741 case Iop_ShrN16x4: shr = True; size = 16; break;
5742 case Iop_ShrN32x2: shr = True; size = 32; break;
5743 case Iop_Shr64: shr = True; size = 64; break;
5744 case Iop_SarN16x4: sar = True; size = 16; break;
5745 case Iop_SarN32x2: sar = True; size = 32; break;
5746 default: vassert(0);
5747 }
5748
5749 if (shl || shr) {
5750 assign(
5751 g1,
florian99dd03e2013-01-29 03:56:06 +00005752 IRExpr_ITE(
sewardj009230b2013-01-26 11:47:55 +00005753 binop(Iop_CmpLT32U,mkexpr(amt),mkU32(size)),
florian99dd03e2013-01-29 03:56:06 +00005754 binop(op, mkexpr(g0), mkexpr(amt8)),
5755 mkU64(0)
sewardj38a3f862005-01-13 15:06:51 +00005756 )
5757 );
5758 } else
5759 if (sar) {
5760 assign(
5761 g1,
florian99dd03e2013-01-29 03:56:06 +00005762 IRExpr_ITE(
sewardj009230b2013-01-26 11:47:55 +00005763 binop(Iop_CmpLT32U,mkexpr(amt),mkU32(size)),
florian99dd03e2013-01-29 03:56:06 +00005764 binop(op, mkexpr(g0), mkexpr(amt8)),
5765 binop(op, mkexpr(g0), mkU8(size-1))
sewardj38a3f862005-01-13 15:06:51 +00005766 )
5767 );
5768 } else {
sewardjba89f4c2005-04-07 17:31:27 +00005769 /*NOTREACHED*/
sewardj38a3f862005-01-13 15:06:51 +00005770 vassert(0);
5771 }
5772
5773 putMMXReg( gregOfRM(rm), mkexpr(g1) );
5774 return delta;
5775}
5776
5777
5778/* Vector by scalar shift of E by an immediate byte. This is a
5779 straight copy of dis_SSE_shiftE_imm. */
5780
5781static
florian55085f82012-11-21 00:36:55 +00005782UInt dis_MMX_shiftE_imm ( Int delta, const HChar* opname, IROp op )
sewardj38a3f862005-01-13 15:06:51 +00005783{
5784 Bool shl, shr, sar;
5785 UChar rm = getIByte(delta);
5786 IRTemp e0 = newTemp(Ity_I64);
5787 IRTemp e1 = newTemp(Ity_I64);
5788 UChar amt, size;
5789 vassert(epartIsReg(rm));
5790 vassert(gregOfRM(rm) == 2
5791 || gregOfRM(rm) == 4 || gregOfRM(rm) == 6);
sewardj2d49b432005-02-01 00:37:06 +00005792 amt = getIByte(delta+1);
sewardj38a3f862005-01-13 15:06:51 +00005793 delta += 2;
5794 DIP("%s $%d,%s\n", opname,
5795 (Int)amt,
5796 nameMMXReg(eregOfRM(rm)) );
5797
5798 assign( e0, getMMXReg(eregOfRM(rm)) );
5799
5800 shl = shr = sar = False;
5801 size = 0;
5802 switch (op) {
5803 case Iop_ShlN16x4: shl = True; size = 16; break;
5804 case Iop_ShlN32x2: shl = True; size = 32; break;
5805 case Iop_Shl64: shl = True; size = 64; break;
5806 case Iop_SarN16x4: sar = True; size = 16; break;
5807 case Iop_SarN32x2: sar = True; size = 32; break;
5808 case Iop_ShrN16x4: shr = True; size = 16; break;
5809 case Iop_ShrN32x2: shr = True; size = 32; break;
5810 case Iop_Shr64: shr = True; size = 64; break;
5811 default: vassert(0);
5812 }
5813
5814 if (shl || shr) {
sewardjba89f4c2005-04-07 17:31:27 +00005815 assign( e1, amt >= size
5816 ? mkU64(0)
5817 : binop(op, mkexpr(e0), mkU8(amt))
5818 );
sewardj38a3f862005-01-13 15:06:51 +00005819 } else
5820 if (sar) {
sewardjba89f4c2005-04-07 17:31:27 +00005821 assign( e1, amt >= size
5822 ? binop(op, mkexpr(e0), mkU8(size-1))
5823 : binop(op, mkexpr(e0), mkU8(amt))
5824 );
sewardj38a3f862005-01-13 15:06:51 +00005825 } else {
sewardjba89f4c2005-04-07 17:31:27 +00005826 /*NOTREACHED*/
sewardj38a3f862005-01-13 15:06:51 +00005827 vassert(0);
5828 }
5829
5830 putMMXReg( eregOfRM(rm), mkexpr(e1) );
5831 return delta;
5832}
5833
5834
5835/* Completely handle all MMX instructions except emms. */
sewardj464efa42004-11-19 22:17:29 +00005836
5837static
sewardj52d04912005-07-03 00:52:48 +00005838UInt dis_MMX ( Bool* decode_ok, UChar sorb, Int sz, Int delta )
sewardj464efa42004-11-19 22:17:29 +00005839{
5840 Int len;
5841 UChar modrm;
sewardjc9a43662004-11-30 18:51:59 +00005842 HChar dis_buf[50];
sewardj464efa42004-11-19 22:17:29 +00005843 UChar opc = getIByte(delta);
5844 delta++;
5845
sewardj4cb918d2004-12-03 19:43:31 +00005846 /* dis_MMX handles all insns except emms. */
5847 do_MMX_preamble();
sewardj464efa42004-11-19 22:17:29 +00005848
5849 switch (opc) {
5850
sewardj2b7a9202004-11-26 19:15:38 +00005851 case 0x6E:
5852 /* MOVD (src)ireg-or-mem (E), (dst)mmxreg (G)*/
sewardj9df271d2004-12-31 22:37:42 +00005853 if (sz != 4)
5854 goto mmx_decode_failure;
sewardj2b7a9202004-11-26 19:15:38 +00005855 modrm = getIByte(delta);
5856 if (epartIsReg(modrm)) {
5857 delta++;
5858 putMMXReg(
5859 gregOfRM(modrm),
5860 binop( Iop_32HLto64,
5861 mkU32(0),
5862 getIReg(4, eregOfRM(modrm)) ) );
5863 DIP("movd %s, %s\n",
5864 nameIReg(4,eregOfRM(modrm)), nameMMXReg(gregOfRM(modrm)));
5865 } else {
5866 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
5867 delta += len;
5868 putMMXReg(
5869 gregOfRM(modrm),
5870 binop( Iop_32HLto64,
5871 mkU32(0),
5872 loadLE(Ity_I32, mkexpr(addr)) ) );
5873 DIP("movd %s, %s\n", dis_buf, nameMMXReg(gregOfRM(modrm)));
5874 }
5875 break;
5876
5877 case 0x7E: /* MOVD (src)mmxreg (G), (dst)ireg-or-mem (E) */
sewardj9df271d2004-12-31 22:37:42 +00005878 if (sz != 4)
5879 goto mmx_decode_failure;
sewardj2b7a9202004-11-26 19:15:38 +00005880 modrm = getIByte(delta);
5881 if (epartIsReg(modrm)) {
5882 delta++;
5883 putIReg( 4, eregOfRM(modrm),
5884 unop(Iop_64to32, getMMXReg(gregOfRM(modrm)) ) );
5885 DIP("movd %s, %s\n",
5886 nameMMXReg(gregOfRM(modrm)), nameIReg(4,eregOfRM(modrm)));
5887 } else {
5888 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
5889 delta += len;
5890 storeLE( mkexpr(addr),
5891 unop(Iop_64to32, getMMXReg(gregOfRM(modrm)) ) );
5892 DIP("movd %s, %s\n", nameMMXReg(gregOfRM(modrm)), dis_buf);
5893 }
5894 break;
5895
sewardj464efa42004-11-19 22:17:29 +00005896 case 0x6F:
5897 /* MOVQ (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00005898 if (sz != 4)
5899 goto mmx_decode_failure;
sewardj464efa42004-11-19 22:17:29 +00005900 modrm = getIByte(delta);
5901 if (epartIsReg(modrm)) {
5902 delta++;
5903 putMMXReg( gregOfRM(modrm), getMMXReg(eregOfRM(modrm)) );
5904 DIP("movq %s, %s\n",
5905 nameMMXReg(eregOfRM(modrm)), nameMMXReg(gregOfRM(modrm)));
5906 } else {
5907 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
5908 delta += len;
5909 putMMXReg( gregOfRM(modrm), loadLE(Ity_I64, mkexpr(addr)) );
5910 DIP("movq %s, %s\n",
5911 dis_buf, nameMMXReg(gregOfRM(modrm)));
5912 }
5913 break;
5914
5915 case 0x7F:
5916 /* MOVQ (src)mmxreg, (dst)mmxreg-or-mem */
sewardj9df271d2004-12-31 22:37:42 +00005917 if (sz != 4)
5918 goto mmx_decode_failure;
sewardj464efa42004-11-19 22:17:29 +00005919 modrm = getIByte(delta);
5920 if (epartIsReg(modrm)) {
sewardj9ca26402005-10-03 02:44:01 +00005921 delta++;
5922 putMMXReg( eregOfRM(modrm), getMMXReg(gregOfRM(modrm)) );
5923 DIP("movq %s, %s\n",
5924 nameMMXReg(gregOfRM(modrm)), nameMMXReg(eregOfRM(modrm)));
sewardj464efa42004-11-19 22:17:29 +00005925 } else {
5926 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
5927 delta += len;
sewardj893aada2004-11-29 19:57:54 +00005928 storeLE( mkexpr(addr), getMMXReg(gregOfRM(modrm)) );
sewardj464efa42004-11-19 22:17:29 +00005929 DIP("mov(nt)q %s, %s\n",
5930 nameMMXReg(gregOfRM(modrm)), dis_buf);
5931 }
5932 break;
5933
sewardj4340dac2004-11-20 13:17:04 +00005934 case 0xFC:
5935 case 0xFD:
5936 case 0xFE: /* PADDgg (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00005937 if (sz != 4)
5938 goto mmx_decode_failure;
sewardj464efa42004-11-19 22:17:29 +00005939 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "padd", True );
5940 break;
5941
sewardj4340dac2004-11-20 13:17:04 +00005942 case 0xEC:
5943 case 0xED: /* PADDSgg (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00005944 if (sz != 4)
5945 goto mmx_decode_failure;
sewardj464efa42004-11-19 22:17:29 +00005946 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "padds", True );
5947 break;
5948
sewardj4340dac2004-11-20 13:17:04 +00005949 case 0xDC:
5950 case 0xDD: /* PADDUSgg (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00005951 if (sz != 4)
5952 goto mmx_decode_failure;
sewardj464efa42004-11-19 22:17:29 +00005953 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "paddus", True );
5954 break;
5955
sewardj4340dac2004-11-20 13:17:04 +00005956 case 0xF8:
5957 case 0xF9:
5958 case 0xFA: /* PSUBgg (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00005959 if (sz != 4)
5960 goto mmx_decode_failure;
sewardj464efa42004-11-19 22:17:29 +00005961 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "psub", True );
5962 break;
5963
sewardj4340dac2004-11-20 13:17:04 +00005964 case 0xE8:
5965 case 0xE9: /* PSUBSgg (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00005966 if (sz != 4)
5967 goto mmx_decode_failure;
sewardj464efa42004-11-19 22:17:29 +00005968 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "psubs", True );
5969 break;
5970
sewardj4340dac2004-11-20 13:17:04 +00005971 case 0xD8:
5972 case 0xD9: /* PSUBUSgg (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00005973 if (sz != 4)
5974 goto mmx_decode_failure;
sewardj464efa42004-11-19 22:17:29 +00005975 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "psubus", True );
5976 break;
5977
5978 case 0xE5: /* PMULHW (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00005979 if (sz != 4)
5980 goto mmx_decode_failure;
sewardj464efa42004-11-19 22:17:29 +00005981 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "pmulhw", False );
5982 break;
5983
5984 case 0xD5: /* PMULLW (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00005985 if (sz != 4)
5986 goto mmx_decode_failure;
sewardj464efa42004-11-19 22:17:29 +00005987 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "pmullw", False );
5988 break;
5989
sewardj4340dac2004-11-20 13:17:04 +00005990 case 0xF5: /* PMADDWD (src)mmxreg-or-mem, (dst)mmxreg */
5991 vassert(sz == 4);
5992 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "pmaddwd", False );
5993 break;
5994
5995 case 0x74:
5996 case 0x75:
5997 case 0x76: /* PCMPEQgg (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00005998 if (sz != 4)
5999 goto mmx_decode_failure;
sewardj4340dac2004-11-20 13:17:04 +00006000 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "pcmpeq", True );
6001 break;
6002
6003 case 0x64:
6004 case 0x65:
6005 case 0x66: /* PCMPGTgg (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00006006 if (sz != 4)
6007 goto mmx_decode_failure;
sewardj4340dac2004-11-20 13:17:04 +00006008 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "pcmpgt", True );
6009 break;
6010
sewardj63ba4092004-11-21 12:30:18 +00006011 case 0x6B: /* PACKSSDW (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00006012 if (sz != 4)
6013 goto mmx_decode_failure;
sewardj63ba4092004-11-21 12:30:18 +00006014 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "packssdw", False );
6015 break;
6016
6017 case 0x63: /* PACKSSWB (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00006018 if (sz != 4)
6019 goto mmx_decode_failure;
sewardj63ba4092004-11-21 12:30:18 +00006020 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "packsswb", False );
6021 break;
6022
6023 case 0x67: /* PACKUSWB (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00006024 if (sz != 4)
6025 goto mmx_decode_failure;
sewardj63ba4092004-11-21 12:30:18 +00006026 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "packuswb", False );
6027 break;
6028
6029 case 0x68:
6030 case 0x69:
6031 case 0x6A: /* PUNPCKHgg (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00006032 if (sz != 4)
6033 goto mmx_decode_failure;
sewardj63ba4092004-11-21 12:30:18 +00006034 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "punpckh", True );
6035 break;
6036
6037 case 0x60:
6038 case 0x61:
6039 case 0x62: /* PUNPCKLgg (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00006040 if (sz != 4)
6041 goto mmx_decode_failure;
sewardj63ba4092004-11-21 12:30:18 +00006042 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "punpckl", True );
6043 break;
6044
6045 case 0xDB: /* PAND (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00006046 if (sz != 4)
6047 goto mmx_decode_failure;
sewardj63ba4092004-11-21 12:30:18 +00006048 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "pand", False );
6049 break;
6050
6051 case 0xDF: /* PANDN (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00006052 if (sz != 4)
6053 goto mmx_decode_failure;
sewardj63ba4092004-11-21 12:30:18 +00006054 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "pandn", False );
6055 break;
6056
6057 case 0xEB: /* POR (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00006058 if (sz != 4)
6059 goto mmx_decode_failure;
sewardj63ba4092004-11-21 12:30:18 +00006060 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "por", False );
6061 break;
6062
6063 case 0xEF: /* PXOR (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00006064 if (sz != 4)
6065 goto mmx_decode_failure;
sewardj63ba4092004-11-21 12:30:18 +00006066 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "pxor", False );
sewardj38a3f862005-01-13 15:06:51 +00006067 break;
sewardj63ba4092004-11-21 12:30:18 +00006068
sewardj38a3f862005-01-13 15:06:51 +00006069# define SHIFT_BY_REG(_name,_op) \
6070 delta = dis_MMX_shiftG_byE(sorb, delta, _name, _op); \
6071 break;
sewardj8d14a592004-11-21 17:04:50 +00006072
sewardj38a3f862005-01-13 15:06:51 +00006073 /* PSLLgg (src)mmxreg-or-mem, (dst)mmxreg */
6074 case 0xF1: SHIFT_BY_REG("psllw", Iop_ShlN16x4);
6075 case 0xF2: SHIFT_BY_REG("pslld", Iop_ShlN32x2);
6076 case 0xF3: SHIFT_BY_REG("psllq", Iop_Shl64);
sewardj8d14a592004-11-21 17:04:50 +00006077
sewardj38a3f862005-01-13 15:06:51 +00006078 /* PSRLgg (src)mmxreg-or-mem, (dst)mmxreg */
6079 case 0xD1: SHIFT_BY_REG("psrlw", Iop_ShrN16x4);
6080 case 0xD2: SHIFT_BY_REG("psrld", Iop_ShrN32x2);
6081 case 0xD3: SHIFT_BY_REG("psrlq", Iop_Shr64);
6082
6083 /* PSRAgg (src)mmxreg-or-mem, (dst)mmxreg */
6084 case 0xE1: SHIFT_BY_REG("psraw", Iop_SarN16x4);
6085 case 0xE2: SHIFT_BY_REG("psrad", Iop_SarN32x2);
6086
6087# undef SHIFT_BY_REG
sewardj8d14a592004-11-21 17:04:50 +00006088
sewardj2b7a9202004-11-26 19:15:38 +00006089 case 0x71:
6090 case 0x72:
6091 case 0x73: {
6092 /* (sz==4): PSLLgg/PSRAgg/PSRLgg mmxreg by imm8 */
sewardja8415ff2005-01-21 20:55:36 +00006093 UChar byte2, subopc;
sewardj38a3f862005-01-13 15:06:51 +00006094 if (sz != 4)
6095 goto mmx_decode_failure;
sewardj38a3f862005-01-13 15:06:51 +00006096 byte2 = getIByte(delta); /* amode / sub-opcode */
sewardj9b45b482005-02-07 01:42:18 +00006097 subopc = toUChar( (byte2 >> 3) & 7 );
sewardj2b7a9202004-11-26 19:15:38 +00006098
sewardj38a3f862005-01-13 15:06:51 +00006099# define SHIFT_BY_IMM(_name,_op) \
6100 do { delta = dis_MMX_shiftE_imm(delta,_name,_op); \
6101 } while (0)
sewardj2b7a9202004-11-26 19:15:38 +00006102
sewardj2b7a9202004-11-26 19:15:38 +00006103 if (subopc == 2 /*SRL*/ && opc == 0x71)
sewardj38a3f862005-01-13 15:06:51 +00006104 SHIFT_BY_IMM("psrlw", Iop_ShrN16x4);
sewardj2b7a9202004-11-26 19:15:38 +00006105 else if (subopc == 2 /*SRL*/ && opc == 0x72)
sewardj38a3f862005-01-13 15:06:51 +00006106 SHIFT_BY_IMM("psrld", Iop_ShrN32x2);
sewardj2b7a9202004-11-26 19:15:38 +00006107 else if (subopc == 2 /*SRL*/ && opc == 0x73)
sewardj38a3f862005-01-13 15:06:51 +00006108 SHIFT_BY_IMM("psrlq", Iop_Shr64);
sewardj2b7a9202004-11-26 19:15:38 +00006109
6110 else if (subopc == 4 /*SAR*/ && opc == 0x71)
sewardj38a3f862005-01-13 15:06:51 +00006111 SHIFT_BY_IMM("psraw", Iop_SarN16x4);
sewardj2b7a9202004-11-26 19:15:38 +00006112 else if (subopc == 4 /*SAR*/ && opc == 0x72)
sewardj38a3f862005-01-13 15:06:51 +00006113 SHIFT_BY_IMM("psrad", Iop_SarN32x2);
sewardj2b7a9202004-11-26 19:15:38 +00006114
6115 else if (subopc == 6 /*SHL*/ && opc == 0x71)
sewardj38a3f862005-01-13 15:06:51 +00006116 SHIFT_BY_IMM("psllw", Iop_ShlN16x4);
sewardj2b7a9202004-11-26 19:15:38 +00006117 else if (subopc == 6 /*SHL*/ && opc == 0x72)
sewardj38a3f862005-01-13 15:06:51 +00006118 SHIFT_BY_IMM("pslld", Iop_ShlN32x2);
sewardj2b7a9202004-11-26 19:15:38 +00006119 else if (subopc == 6 /*SHL*/ && opc == 0x73)
sewardj38a3f862005-01-13 15:06:51 +00006120 SHIFT_BY_IMM("psllq", Iop_Shl64);
sewardj2b7a9202004-11-26 19:15:38 +00006121
6122 else goto mmx_decode_failure;
6123
sewardj38a3f862005-01-13 15:06:51 +00006124# undef SHIFT_BY_IMM
sewardj2b7a9202004-11-26 19:15:38 +00006125 break;
6126 }
6127
sewardjd71ba832006-12-27 01:15:29 +00006128 case 0xF7: {
6129 IRTemp addr = newTemp(Ity_I32);
6130 IRTemp regD = newTemp(Ity_I64);
6131 IRTemp regM = newTemp(Ity_I64);
6132 IRTemp mask = newTemp(Ity_I64);
6133 IRTemp olddata = newTemp(Ity_I64);
6134 IRTemp newdata = newTemp(Ity_I64);
6135
6136 modrm = getIByte(delta);
6137 if (sz != 4 || (!epartIsReg(modrm)))
6138 goto mmx_decode_failure;
6139 delta++;
6140
6141 assign( addr, handleSegOverride( sorb, getIReg(4, R_EDI) ));
6142 assign( regM, getMMXReg( eregOfRM(modrm) ));
6143 assign( regD, getMMXReg( gregOfRM(modrm) ));
6144 assign( mask, binop(Iop_SarN8x8, mkexpr(regM), mkU8(7)) );
6145 assign( olddata, loadLE( Ity_I64, mkexpr(addr) ));
6146 assign( newdata,
6147 binop(Iop_Or64,
6148 binop(Iop_And64,
6149 mkexpr(regD),
6150 mkexpr(mask) ),
6151 binop(Iop_And64,
6152 mkexpr(olddata),
6153 unop(Iop_Not64, mkexpr(mask)))) );
6154 storeLE( mkexpr(addr), mkexpr(newdata) );
6155 DIP("maskmovq %s,%s\n", nameMMXReg( eregOfRM(modrm) ),
6156 nameMMXReg( gregOfRM(modrm) ) );
6157 break;
6158 }
6159
sewardj2b7a9202004-11-26 19:15:38 +00006160 /* --- MMX decode failure --- */
sewardj464efa42004-11-19 22:17:29 +00006161 default:
sewardj2b7a9202004-11-26 19:15:38 +00006162 mmx_decode_failure:
sewardj464efa42004-11-19 22:17:29 +00006163 *decode_ok = False;
6164 return delta; /* ignored */
6165
6166 }
6167
6168 *decode_ok = True;
6169 return delta;
6170}
6171
6172
6173/*------------------------------------------------------------*/
6174/*--- More misc arithmetic and other obscure insns. ---*/
6175/*------------------------------------------------------------*/
sewardja06e5562004-07-14 13:18:05 +00006176
6177/* Double length left and right shifts. Apparently only required in
6178 v-size (no b- variant). */
6179static
6180UInt dis_SHLRD_Gv_Ev ( UChar sorb,
sewardj52d04912005-07-03 00:52:48 +00006181 Int delta, UChar modrm,
sewardja06e5562004-07-14 13:18:05 +00006182 Int sz,
6183 IRExpr* shift_amt,
6184 Bool amt_is_literal,
florian55085f82012-11-21 00:36:55 +00006185 const HChar* shift_amt_txt,
sewardja06e5562004-07-14 13:18:05 +00006186 Bool left_shift )
6187{
6188 /* shift_amt :: Ity_I8 is the amount to shift. shift_amt_txt is used
6189 for printing it. And eip on entry points at the modrm byte. */
6190 Int len;
sewardjc9a43662004-11-30 18:51:59 +00006191 HChar dis_buf[50];
sewardja06e5562004-07-14 13:18:05 +00006192
sewardj6d2638e2004-07-15 09:38:27 +00006193 IRType ty = szToITy(sz);
6194 IRTemp gsrc = newTemp(ty);
6195 IRTemp esrc = newTemp(ty);
sewardj92d168d2004-11-15 14:22:12 +00006196 IRTemp addr = IRTemp_INVALID;
sewardj6d2638e2004-07-15 09:38:27 +00006197 IRTemp tmpSH = newTemp(Ity_I8);
sewardj92d168d2004-11-15 14:22:12 +00006198 IRTemp tmpL = IRTemp_INVALID;
6199 IRTemp tmpRes = IRTemp_INVALID;
6200 IRTemp tmpSubSh = IRTemp_INVALID;
sewardja06e5562004-07-14 13:18:05 +00006201 IROp mkpair;
6202 IROp getres;
6203 IROp shift;
sewardja06e5562004-07-14 13:18:05 +00006204 IRExpr* mask = NULL;
6205
6206 vassert(sz == 2 || sz == 4);
6207
6208 /* The E-part is the destination; this is shifted. The G-part
6209 supplies bits to be shifted into the E-part, but is not
6210 changed.
6211
6212 If shifting left, form a double-length word with E at the top
6213 and G at the bottom, and shift this left. The result is then in
6214 the high part.
6215
6216 If shifting right, form a double-length word with G at the top
6217 and E at the bottom, and shift this right. The result is then
6218 at the bottom. */
6219
6220 /* Fetch the operands. */
6221
6222 assign( gsrc, getIReg(sz, gregOfRM(modrm)) );
6223
6224 if (epartIsReg(modrm)) {
6225 delta++;
6226 assign( esrc, getIReg(sz, eregOfRM(modrm)) );
sewardj68511542004-07-28 00:15:44 +00006227 DIP("sh%cd%c %s, %s, %s\n",
sewardja06e5562004-07-14 13:18:05 +00006228 ( left_shift ? 'l' : 'r' ), nameISize(sz),
sewardj68511542004-07-28 00:15:44 +00006229 shift_amt_txt,
sewardja06e5562004-07-14 13:18:05 +00006230 nameIReg(sz, gregOfRM(modrm)), nameIReg(sz, eregOfRM(modrm)));
6231 } else {
6232 addr = disAMode ( &len, sorb, delta, dis_buf );
6233 delta += len;
6234 assign( esrc, loadLE(ty, mkexpr(addr)) );
sewardj68511542004-07-28 00:15:44 +00006235 DIP("sh%cd%c %s, %s, %s\n",
6236 ( left_shift ? 'l' : 'r' ), nameISize(sz),
6237 shift_amt_txt,
6238 nameIReg(sz, gregOfRM(modrm)), dis_buf);
sewardja06e5562004-07-14 13:18:05 +00006239 }
6240
6241 /* Round up the relevant primops. */
6242
6243 if (sz == 4) {
6244 tmpL = newTemp(Ity_I64);
6245 tmpRes = newTemp(Ity_I32);
6246 tmpSubSh = newTemp(Ity_I32);
sewardje539a402004-07-14 18:24:17 +00006247 mkpair = Iop_32HLto64;
sewardj8c7f1ab2004-07-29 20:31:09 +00006248 getres = left_shift ? Iop_64HIto32 : Iop_64to32;
sewardje539a402004-07-14 18:24:17 +00006249 shift = left_shift ? Iop_Shl64 : Iop_Shr64;
6250 mask = mkU8(31);
sewardja06e5562004-07-14 13:18:05 +00006251 } else {
6252 /* sz == 2 */
sewardj8c7f1ab2004-07-29 20:31:09 +00006253 tmpL = newTemp(Ity_I32);
6254 tmpRes = newTemp(Ity_I16);
6255 tmpSubSh = newTemp(Ity_I16);
6256 mkpair = Iop_16HLto32;
6257 getres = left_shift ? Iop_32HIto16 : Iop_32to16;
6258 shift = left_shift ? Iop_Shl32 : Iop_Shr32;
6259 mask = mkU8(15);
sewardja06e5562004-07-14 13:18:05 +00006260 }
6261
6262 /* Do the shift, calculate the subshift value, and set
6263 the flag thunk. */
6264
sewardj8c7f1ab2004-07-29 20:31:09 +00006265 assign( tmpSH, binop(Iop_And8, shift_amt, mask) );
6266
sewardja06e5562004-07-14 13:18:05 +00006267 if (left_shift)
6268 assign( tmpL, binop(mkpair, mkexpr(esrc), mkexpr(gsrc)) );
6269 else
6270 assign( tmpL, binop(mkpair, mkexpr(gsrc), mkexpr(esrc)) );
6271
6272 assign( tmpRes, unop(getres, binop(shift, mkexpr(tmpL), mkexpr(tmpSH)) ) );
6273 assign( tmpSubSh,
6274 unop(getres,
6275 binop(shift,
6276 mkexpr(tmpL),
6277 binop(Iop_And8,
6278 binop(Iop_Sub8, mkexpr(tmpSH), mkU8(1) ),
6279 mask))) );
sewardja06e5562004-07-14 13:18:05 +00006280
sewardj2a2ba8b2004-11-08 13:14:06 +00006281 setFlags_DEP1_DEP2_shift ( left_shift ? Iop_Shl32 : Iop_Sar32,
6282 tmpRes, tmpSubSh, ty, tmpSH );
sewardja06e5562004-07-14 13:18:05 +00006283
6284 /* Put result back. */
6285
6286 if (epartIsReg(modrm)) {
6287 putIReg(sz, eregOfRM(modrm), mkexpr(tmpRes));
6288 } else {
6289 storeLE( mkexpr(addr), mkexpr(tmpRes) );
6290 }
6291
6292 if (amt_is_literal) delta++;
6293 return delta;
6294}
6295
6296
sewardj1c6f9912004-09-07 10:15:24 +00006297/* Handle BT/BTS/BTR/BTC Gv, Ev. Apparently b-size is not
6298 required. */
6299
6300typedef enum { BtOpNone, BtOpSet, BtOpReset, BtOpComp } BtOp;
6301
florian55085f82012-11-21 00:36:55 +00006302static const HChar* nameBtOp ( BtOp op )
sewardj1c6f9912004-09-07 10:15:24 +00006303{
6304 switch (op) {
6305 case BtOpNone: return "";
6306 case BtOpSet: return "s";
6307 case BtOpReset: return "r";
6308 case BtOpComp: return "c";
6309 default: vpanic("nameBtOp(x86)");
6310 }
6311}
6312
6313
6314static
floriancacba8e2014-12-15 18:58:07 +00006315UInt dis_bt_G_E ( const VexAbiInfo* vbi,
sewardj02834302010-07-29 18:10:51 +00006316 UChar sorb, Bool locked, Int sz, Int delta, BtOp op )
sewardj1c6f9912004-09-07 10:15:24 +00006317{
sewardjc9a43662004-11-30 18:51:59 +00006318 HChar dis_buf[50];
sewardj1c6f9912004-09-07 10:15:24 +00006319 UChar modrm;
6320 Int len;
6321 IRTemp t_fetched, t_bitno0, t_bitno1, t_bitno2, t_addr0,
sewardje9d8a262009-07-01 08:06:34 +00006322 t_addr1, t_esp, t_mask, t_new;
sewardj1c6f9912004-09-07 10:15:24 +00006323
6324 vassert(sz == 2 || sz == 4);
6325
6326 t_fetched = t_bitno0 = t_bitno1 = t_bitno2
sewardje9d8a262009-07-01 08:06:34 +00006327 = t_addr0 = t_addr1 = t_esp
6328 = t_mask = t_new = IRTemp_INVALID;
sewardj1c6f9912004-09-07 10:15:24 +00006329
6330 t_fetched = newTemp(Ity_I8);
sewardje9d8a262009-07-01 08:06:34 +00006331 t_new = newTemp(Ity_I8);
sewardj1c6f9912004-09-07 10:15:24 +00006332 t_bitno0 = newTemp(Ity_I32);
6333 t_bitno1 = newTemp(Ity_I32);
6334 t_bitno2 = newTemp(Ity_I8);
6335 t_addr1 = newTemp(Ity_I32);
6336 modrm = getIByte(delta);
6337
sewardj9ed16802005-08-24 10:46:19 +00006338 assign( t_bitno0, widenSto32(getIReg(sz, gregOfRM(modrm))) );
sewardj1c6f9912004-09-07 10:15:24 +00006339
6340 if (epartIsReg(modrm)) {
sewardj1c6f9912004-09-07 10:15:24 +00006341 delta++;
6342 /* Get it onto the client's stack. */
6343 t_esp = newTemp(Ity_I32);
6344 t_addr0 = newTemp(Ity_I32);
6345
sewardj02834302010-07-29 18:10:51 +00006346 /* For the choice of the value 128, see comment in dis_bt_G_E in
6347 guest_amd64_toIR.c. We point out here only that 128 is
6348 fast-cased in Memcheck and is > 0, so seems like a good
6349 choice. */
6350 vassert(vbi->guest_stack_redzone_size == 0);
6351 assign( t_esp, binop(Iop_Sub32, getIReg(4, R_ESP), mkU32(128)) );
sewardj1c6f9912004-09-07 10:15:24 +00006352 putIReg(4, R_ESP, mkexpr(t_esp));
6353
6354 storeLE( mkexpr(t_esp), getIReg(sz, eregOfRM(modrm)) );
6355
6356 /* Make t_addr0 point at it. */
6357 assign( t_addr0, mkexpr(t_esp) );
6358
6359 /* Mask out upper bits of the shift amount, since we're doing a
6360 reg. */
6361 assign( t_bitno1, binop(Iop_And32,
6362 mkexpr(t_bitno0),
6363 mkU32(sz == 4 ? 31 : 15)) );
6364
6365 } else {
6366 t_addr0 = disAMode ( &len, sorb, delta, dis_buf );
6367 delta += len;
6368 assign( t_bitno1, mkexpr(t_bitno0) );
6369 }
6370
6371 /* At this point: t_addr0 is the address being operated on. If it
6372 was a reg, we will have pushed it onto the client's stack.
6373 t_bitno1 is the bit number, suitably masked in the case of a
6374 reg. */
6375
6376 /* Now the main sequence. */
6377 assign( t_addr1,
6378 binop(Iop_Add32,
6379 mkexpr(t_addr0),
6380 binop(Iop_Sar32, mkexpr(t_bitno1), mkU8(3))) );
6381
6382 /* t_addr1 now holds effective address */
6383
6384 assign( t_bitno2,
6385 unop(Iop_32to8,
6386 binop(Iop_And32, mkexpr(t_bitno1), mkU32(7))) );
6387
6388 /* t_bitno2 contains offset of bit within byte */
6389
6390 if (op != BtOpNone) {
6391 t_mask = newTemp(Ity_I8);
6392 assign( t_mask, binop(Iop_Shl8, mkU8(1), mkexpr(t_bitno2)) );
6393 }
sewardj4963a422004-10-14 23:34:03 +00006394
sewardj1c6f9912004-09-07 10:15:24 +00006395 /* t_mask is now a suitable byte mask */
6396
6397 assign( t_fetched, loadLE(Ity_I8, mkexpr(t_addr1)) );
6398
6399 if (op != BtOpNone) {
6400 switch (op) {
sewardje9d8a262009-07-01 08:06:34 +00006401 case BtOpSet:
6402 assign( t_new,
6403 binop(Iop_Or8, mkexpr(t_fetched), mkexpr(t_mask)) );
sewardj1c6f9912004-09-07 10:15:24 +00006404 break;
sewardje9d8a262009-07-01 08:06:34 +00006405 case BtOpComp:
6406 assign( t_new,
6407 binop(Iop_Xor8, mkexpr(t_fetched), mkexpr(t_mask)) );
sewardj1c6f9912004-09-07 10:15:24 +00006408 break;
sewardje9d8a262009-07-01 08:06:34 +00006409 case BtOpReset:
6410 assign( t_new,
6411 binop(Iop_And8, mkexpr(t_fetched),
6412 unop(Iop_Not8, mkexpr(t_mask))) );
sewardj1c6f9912004-09-07 10:15:24 +00006413 break;
6414 default:
6415 vpanic("dis_bt_G_E(x86)");
6416 }
sewardje9d8a262009-07-01 08:06:34 +00006417 if (locked && !epartIsReg(modrm)) {
6418 casLE( mkexpr(t_addr1), mkexpr(t_fetched)/*expd*/,
6419 mkexpr(t_new)/*new*/,
6420 guest_EIP_curr_instr );
6421 } else {
6422 storeLE( mkexpr(t_addr1), mkexpr(t_new) );
6423 }
sewardj1c6f9912004-09-07 10:15:24 +00006424 }
6425
6426 /* Side effect done; now get selected bit into Carry flag */
sewardj2a2ba8b2004-11-08 13:14:06 +00006427 /* Flags: C=selected bit, O,S,Z,A,P undefined, so are set to zero. */
sewardj2a9ad022004-11-25 02:46:58 +00006428 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(X86G_CC_OP_COPY) ));
sewardj2a2ba8b2004-11-08 13:14:06 +00006429 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
sewardj1c6f9912004-09-07 10:15:24 +00006430 stmt( IRStmt_Put(
sewardj2a2ba8b2004-11-08 13:14:06 +00006431 OFFB_CC_DEP1,
sewardj1c6f9912004-09-07 10:15:24 +00006432 binop(Iop_And32,
6433 binop(Iop_Shr32,
6434 unop(Iop_8Uto32, mkexpr(t_fetched)),
sewardj5bd4d162004-11-10 13:02:48 +00006435 mkexpr(t_bitno2)),
6436 mkU32(1)))
sewardj1c6f9912004-09-07 10:15:24 +00006437 );
sewardja3b7e3a2005-04-05 01:54:19 +00006438 /* Set NDEP even though it isn't used. This makes redundant-PUT
6439 elimination of previous stores to this field work better. */
6440 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
sewardj1c6f9912004-09-07 10:15:24 +00006441
6442 /* Move reg operand from stack back to reg */
6443 if (epartIsReg(modrm)) {
6444 /* t_esp still points at it. */
sewardj4963a422004-10-14 23:34:03 +00006445 putIReg(sz, eregOfRM(modrm), loadLE(szToITy(sz), mkexpr(t_esp)) );
sewardj02834302010-07-29 18:10:51 +00006446 putIReg(4, R_ESP, binop(Iop_Add32, mkexpr(t_esp), mkU32(128)) );
sewardj1c6f9912004-09-07 10:15:24 +00006447 }
6448
6449 DIP("bt%s%c %s, %s\n",
6450 nameBtOp(op), nameISize(sz), nameIReg(sz, gregOfRM(modrm)),
6451 ( epartIsReg(modrm) ? nameIReg(sz, eregOfRM(modrm)) : dis_buf ) );
6452
6453 return delta;
6454}
sewardjce646f22004-08-31 23:55:54 +00006455
6456
6457
6458/* Handle BSF/BSR. Only v-size seems necessary. */
6459static
sewardj52d04912005-07-03 00:52:48 +00006460UInt dis_bs_E_G ( UChar sorb, Int sz, Int delta, Bool fwds )
sewardjce646f22004-08-31 23:55:54 +00006461{
6462 Bool isReg;
6463 UChar modrm;
sewardjc9a43662004-11-30 18:51:59 +00006464 HChar dis_buf[50];
sewardjce646f22004-08-31 23:55:54 +00006465
6466 IRType ty = szToITy(sz);
6467 IRTemp src = newTemp(ty);
6468 IRTemp dst = newTemp(ty);
6469
6470 IRTemp src32 = newTemp(Ity_I32);
6471 IRTemp dst32 = newTemp(Ity_I32);
sewardj009230b2013-01-26 11:47:55 +00006472 IRTemp srcB = newTemp(Ity_I1);
sewardjce646f22004-08-31 23:55:54 +00006473
6474 vassert(sz == 4 || sz == 2);
sewardjce646f22004-08-31 23:55:54 +00006475
6476 modrm = getIByte(delta);
6477
6478 isReg = epartIsReg(modrm);
6479 if (isReg) {
6480 delta++;
6481 assign( src, getIReg(sz, eregOfRM(modrm)) );
6482 } else {
6483 Int len;
6484 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
6485 delta += len;
6486 assign( src, loadLE(ty, mkexpr(addr)) );
6487 }
6488
6489 DIP("bs%c%c %s, %s\n",
6490 fwds ? 'f' : 'r', nameISize(sz),
6491 ( isReg ? nameIReg(sz, eregOfRM(modrm)) : dis_buf ),
6492 nameIReg(sz, gregOfRM(modrm)));
6493
sewardj009230b2013-01-26 11:47:55 +00006494 /* Generate a bool expression which is zero iff the original is
sewardje13074c2012-11-08 10:57:08 +00006495 zero, and nonzero otherwise. Ask for a CmpNE version which, if
6496 instrumented by Memcheck, is instrumented expensively, since
6497 this may be used on the output of a preceding movmskb insn,
6498 which has been known to be partially defined, and in need of
6499 careful handling. */
sewardj009230b2013-01-26 11:47:55 +00006500 assign( srcB, binop(mkSizedOp(ty,Iop_ExpCmpNE8),
6501 mkexpr(src), mkU(ty,0)) );
sewardjce646f22004-08-31 23:55:54 +00006502
6503 /* Flags: Z is 1 iff source value is zero. All others
6504 are undefined -- we force them to zero. */
sewardj2a9ad022004-11-25 02:46:58 +00006505 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(X86G_CC_OP_COPY) ));
sewardj2a2ba8b2004-11-08 13:14:06 +00006506 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
sewardjce646f22004-08-31 23:55:54 +00006507 stmt( IRStmt_Put(
sewardj2a2ba8b2004-11-08 13:14:06 +00006508 OFFB_CC_DEP1,
florian99dd03e2013-01-29 03:56:06 +00006509 IRExpr_ITE( mkexpr(srcB),
6510 /* src!=0 */
6511 mkU32(0),
6512 /* src==0 */
6513 mkU32(X86G_CC_MASK_Z)
sewardjce646f22004-08-31 23:55:54 +00006514 )
6515 ));
sewardja3b7e3a2005-04-05 01:54:19 +00006516 /* Set NDEP even though it isn't used. This makes redundant-PUT
6517 elimination of previous stores to this field work better. */
6518 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
sewardjce646f22004-08-31 23:55:54 +00006519
6520 /* Result: iff source value is zero, we can't use
6521 Iop_Clz32/Iop_Ctz32 as they have no defined result in that case.
6522 But anyway, Intel x86 semantics say the result is undefined in
6523 such situations. Hence handle the zero case specially. */
6524
6525 /* Bleh. What we compute:
6526
6527 bsf32: if src == 0 then 0 else Ctz32(src)
6528 bsr32: if src == 0 then 0 else 31 - Clz32(src)
6529
6530 bsf16: if src == 0 then 0 else Ctz32(16Uto32(src))
6531 bsr16: if src == 0 then 0 else 31 - Clz32(16Uto32(src))
6532
6533 First, widen src to 32 bits if it is not already.
sewardj37158712004-10-15 21:23:12 +00006534
6535 Postscript 15 Oct 04: it seems that at least VIA Nehemiah leaves the
6536 dst register unchanged when src == 0. Hence change accordingly.
sewardjce646f22004-08-31 23:55:54 +00006537 */
6538 if (sz == 2)
6539 assign( src32, unop(Iop_16Uto32, mkexpr(src)) );
6540 else
6541 assign( src32, mkexpr(src) );
6542
6543 /* The main computation, guarding against zero. */
6544 assign( dst32,
florian99dd03e2013-01-29 03:56:06 +00006545 IRExpr_ITE(
sewardj009230b2013-01-26 11:47:55 +00006546 mkexpr(srcB),
sewardjce646f22004-08-31 23:55:54 +00006547 /* src != 0 */
6548 fwds ? unop(Iop_Ctz32, mkexpr(src32))
6549 : binop(Iop_Sub32,
6550 mkU32(31),
florian99dd03e2013-01-29 03:56:06 +00006551 unop(Iop_Clz32, mkexpr(src32))),
6552 /* src == 0 -- leave dst unchanged */
6553 widenUto32( getIReg( sz, gregOfRM(modrm) ) )
sewardjce646f22004-08-31 23:55:54 +00006554 )
6555 );
6556
6557 if (sz == 2)
6558 assign( dst, unop(Iop_32to16, mkexpr(dst32)) );
6559 else
6560 assign( dst, mkexpr(dst32) );
6561
6562 /* dump result back */
6563 putIReg( sz, gregOfRM(modrm), mkexpr(dst) );
6564
6565 return delta;
6566}
sewardj64e1d652004-07-12 14:00:46 +00006567
6568
6569static
6570void codegen_xchg_eAX_Reg ( Int sz, Int reg )
6571{
6572 IRType ty = szToITy(sz);
6573 IRTemp t1 = newTemp(ty);
6574 IRTemp t2 = newTemp(ty);
6575 vassert(sz == 2 || sz == 4);
6576 assign( t1, getIReg(sz, R_EAX) );
6577 assign( t2, getIReg(sz, reg) );
6578 putIReg( sz, R_EAX, mkexpr(t2) );
6579 putIReg( sz, reg, mkexpr(t1) );
6580 DIP("xchg%c %s, %s\n",
6581 nameISize(sz), nameIReg(sz, R_EAX), nameIReg(sz, reg));
6582}
6583
6584
sewardjbdc7d212004-09-09 02:46:40 +00006585static
6586void codegen_SAHF ( void )
6587{
6588 /* Set the flags to:
sewardj2a9ad022004-11-25 02:46:58 +00006589 (x86g_calculate_flags_all() & X86G_CC_MASK_O) -- retain the old O flag
6590 | (%AH & (X86G_CC_MASK_S|X86G_CC_MASK_Z|X86G_CC_MASK_A
6591 |X86G_CC_MASK_P|X86G_CC_MASK_C)
sewardjbdc7d212004-09-09 02:46:40 +00006592 */
sewardj2a9ad022004-11-25 02:46:58 +00006593 UInt mask_SZACP = X86G_CC_MASK_S|X86G_CC_MASK_Z|X86G_CC_MASK_A
6594 |X86G_CC_MASK_C|X86G_CC_MASK_P;
sewardjbdc7d212004-09-09 02:46:40 +00006595 IRTemp oldflags = newTemp(Ity_I32);
sewardj2a9ad022004-11-25 02:46:58 +00006596 assign( oldflags, mk_x86g_calculate_eflags_all() );
6597 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(X86G_CC_OP_COPY) ));
sewardj905edbd2007-04-07 12:25:37 +00006598 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
sewardj2a2ba8b2004-11-08 13:14:06 +00006599 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
6600 stmt( IRStmt_Put( OFFB_CC_DEP1,
sewardjbdc7d212004-09-09 02:46:40 +00006601 binop(Iop_Or32,
sewardj2a9ad022004-11-25 02:46:58 +00006602 binop(Iop_And32, mkexpr(oldflags), mkU32(X86G_CC_MASK_O)),
sewardjbdc7d212004-09-09 02:46:40 +00006603 binop(Iop_And32,
6604 binop(Iop_Shr32, getIReg(4, R_EAX), mkU8(8)),
6605 mkU32(mask_SZACP))
6606 )
6607 ));
sewardja3b7e3a2005-04-05 01:54:19 +00006608 /* Set NDEP even though it isn't used. This makes redundant-PUT
6609 elimination of previous stores to this field work better. */
6610 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
sewardjbdc7d212004-09-09 02:46:40 +00006611}
6612
6613
sewardj8dfdc8a2005-10-03 11:39:02 +00006614static
6615void codegen_LAHF ( void )
6616{
6617 /* AH <- EFLAGS(SF:ZF:0:AF:0:PF:1:CF) */
6618 IRExpr* eax_with_hole;
6619 IRExpr* new_byte;
6620 IRExpr* new_eax;
6621 UInt mask_SZACP = X86G_CC_MASK_S|X86G_CC_MASK_Z|X86G_CC_MASK_A
6622 |X86G_CC_MASK_C|X86G_CC_MASK_P;
6623
6624 IRTemp flags = newTemp(Ity_I32);
6625 assign( flags, mk_x86g_calculate_eflags_all() );
6626
6627 eax_with_hole
6628 = binop(Iop_And32, getIReg(4, R_EAX), mkU32(0xFFFF00FF));
6629 new_byte
6630 = binop(Iop_Or32, binop(Iop_And32, mkexpr(flags), mkU32(mask_SZACP)),
6631 mkU32(1<<1));
6632 new_eax
6633 = binop(Iop_Or32, eax_with_hole,
6634 binop(Iop_Shl32, new_byte, mkU8(8)));
6635 putIReg(4, R_EAX, new_eax);
6636}
6637
sewardj458a6f82004-08-25 12:46:02 +00006638
6639static
6640UInt dis_cmpxchg_G_E ( UChar sorb,
sewardje9d8a262009-07-01 08:06:34 +00006641 Bool locked,
sewardj458a6f82004-08-25 12:46:02 +00006642 Int size,
sewardj52d04912005-07-03 00:52:48 +00006643 Int delta0 )
sewardj458a6f82004-08-25 12:46:02 +00006644{
sewardjc9a43662004-11-30 18:51:59 +00006645 HChar dis_buf[50];
sewardj458a6f82004-08-25 12:46:02 +00006646 Int len;
6647
6648 IRType ty = szToITy(size);
6649 IRTemp acc = newTemp(ty);
6650 IRTemp src = newTemp(ty);
6651 IRTemp dest = newTemp(ty);
6652 IRTemp dest2 = newTemp(ty);
6653 IRTemp acc2 = newTemp(ty);
sewardj009230b2013-01-26 11:47:55 +00006654 IRTemp cond = newTemp(Ity_I1);
sewardj92d168d2004-11-15 14:22:12 +00006655 IRTemp addr = IRTemp_INVALID;
sewardj458a6f82004-08-25 12:46:02 +00006656 UChar rm = getUChar(delta0);
6657
sewardje9d8a262009-07-01 08:06:34 +00006658 /* There are 3 cases to consider:
6659
6660 reg-reg: ignore any lock prefix, generate sequence based
florian99dd03e2013-01-29 03:56:06 +00006661 on ITE
sewardje9d8a262009-07-01 08:06:34 +00006662
6663 reg-mem, not locked: ignore any lock prefix, generate sequence
florian99dd03e2013-01-29 03:56:06 +00006664 based on ITE
sewardje9d8a262009-07-01 08:06:34 +00006665
6666 reg-mem, locked: use IRCAS
6667 */
sewardj458a6f82004-08-25 12:46:02 +00006668 if (epartIsReg(rm)) {
sewardje9d8a262009-07-01 08:06:34 +00006669 /* case 1 */
sewardj458a6f82004-08-25 12:46:02 +00006670 assign( dest, getIReg(size, eregOfRM(rm)) );
6671 delta0++;
sewardje9d8a262009-07-01 08:06:34 +00006672 assign( src, getIReg(size, gregOfRM(rm)) );
6673 assign( acc, getIReg(size, R_EAX) );
6674 setFlags_DEP1_DEP2(Iop_Sub8, acc, dest, ty);
sewardj009230b2013-01-26 11:47:55 +00006675 assign( cond, mk_x86g_calculate_condition(X86CondZ) );
florian99dd03e2013-01-29 03:56:06 +00006676 assign( dest2, IRExpr_ITE(mkexpr(cond), mkexpr(src), mkexpr(dest)) );
6677 assign( acc2, IRExpr_ITE(mkexpr(cond), mkexpr(acc), mkexpr(dest)) );
sewardje9d8a262009-07-01 08:06:34 +00006678 putIReg(size, R_EAX, mkexpr(acc2));
6679 putIReg(size, eregOfRM(rm), mkexpr(dest2));
sewardj458a6f82004-08-25 12:46:02 +00006680 DIP("cmpxchg%c %s,%s\n", nameISize(size),
6681 nameIReg(size,gregOfRM(rm)),
6682 nameIReg(size,eregOfRM(rm)) );
sewardje9d8a262009-07-01 08:06:34 +00006683 }
6684 else if (!epartIsReg(rm) && !locked) {
6685 /* case 2 */
sewardj458a6f82004-08-25 12:46:02 +00006686 addr = disAMode ( &len, sorb, delta0, dis_buf );
6687 assign( dest, loadLE(ty, mkexpr(addr)) );
6688 delta0 += len;
sewardje9d8a262009-07-01 08:06:34 +00006689 assign( src, getIReg(size, gregOfRM(rm)) );
6690 assign( acc, getIReg(size, R_EAX) );
6691 setFlags_DEP1_DEP2(Iop_Sub8, acc, dest, ty);
sewardj009230b2013-01-26 11:47:55 +00006692 assign( cond, mk_x86g_calculate_condition(X86CondZ) );
florian99dd03e2013-01-29 03:56:06 +00006693 assign( dest2, IRExpr_ITE(mkexpr(cond), mkexpr(src), mkexpr(dest)) );
6694 assign( acc2, IRExpr_ITE(mkexpr(cond), mkexpr(acc), mkexpr(dest)) );
sewardje9d8a262009-07-01 08:06:34 +00006695 putIReg(size, R_EAX, mkexpr(acc2));
6696 storeLE( mkexpr(addr), mkexpr(dest2) );
sewardj458a6f82004-08-25 12:46:02 +00006697 DIP("cmpxchg%c %s,%s\n", nameISize(size),
6698 nameIReg(size,gregOfRM(rm)), dis_buf);
6699 }
sewardje9d8a262009-07-01 08:06:34 +00006700 else if (!epartIsReg(rm) && locked) {
6701 /* case 3 */
6702 /* src is new value. acc is expected value. dest is old value.
6703 Compute success from the output of the IRCAS, and steer the
6704 new value for EAX accordingly: in case of success, EAX is
6705 unchanged. */
6706 addr = disAMode ( &len, sorb, delta0, dis_buf );
6707 delta0 += len;
6708 assign( src, getIReg(size, gregOfRM(rm)) );
6709 assign( acc, getIReg(size, R_EAX) );
6710 stmt( IRStmt_CAS(
6711 mkIRCAS( IRTemp_INVALID, dest, Iend_LE, mkexpr(addr),
6712 NULL, mkexpr(acc), NULL, mkexpr(src) )
6713 ));
6714 setFlags_DEP1_DEP2(Iop_Sub8, acc, dest, ty);
sewardj009230b2013-01-26 11:47:55 +00006715 assign( cond, mk_x86g_calculate_condition(X86CondZ) );
florian99dd03e2013-01-29 03:56:06 +00006716 assign( acc2, IRExpr_ITE(mkexpr(cond), mkexpr(acc), mkexpr(dest)) );
sewardje9d8a262009-07-01 08:06:34 +00006717 putIReg(size, R_EAX, mkexpr(acc2));
sewardj40d1d212009-07-12 13:01:17 +00006718 DIP("cmpxchg%c %s,%s\n", nameISize(size),
6719 nameIReg(size,gregOfRM(rm)), dis_buf);
sewardj458a6f82004-08-25 12:46:02 +00006720 }
sewardje9d8a262009-07-01 08:06:34 +00006721 else vassert(0);
sewardj458a6f82004-08-25 12:46:02 +00006722
6723 return delta0;
6724}
6725
6726
sewardj458a6f82004-08-25 12:46:02 +00006727/* Handle conditional move instructions of the form
6728 cmovcc E(reg-or-mem), G(reg)
6729
6730 E(src) is reg-or-mem
6731 G(dst) is reg.
6732
6733 If E is reg, --> GET %E, tmps
6734 GET %G, tmpd
6735 CMOVcc tmps, tmpd
6736 PUT tmpd, %G
6737
6738 If E is mem --> (getAddr E) -> tmpa
6739 LD (tmpa), tmps
6740 GET %G, tmpd
6741 CMOVcc tmps, tmpd
6742 PUT tmpd, %G
6743*/
6744static
6745UInt dis_cmov_E_G ( UChar sorb,
6746 Int sz,
sewardj2a9ad022004-11-25 02:46:58 +00006747 X86Condcode cond,
sewardj52d04912005-07-03 00:52:48 +00006748 Int delta0 )
sewardj458a6f82004-08-25 12:46:02 +00006749{
6750 UChar rm = getIByte(delta0);
sewardjc9a43662004-11-30 18:51:59 +00006751 HChar dis_buf[50];
sewardj458a6f82004-08-25 12:46:02 +00006752 Int len;
6753
sewardj883b00b2004-09-11 09:30:24 +00006754 IRType ty = szToITy(sz);
sewardj458a6f82004-08-25 12:46:02 +00006755 IRTemp tmps = newTemp(ty);
6756 IRTemp tmpd = newTemp(ty);
6757
6758 if (epartIsReg(rm)) {
6759 assign( tmps, getIReg(sz, eregOfRM(rm)) );
6760 assign( tmpd, getIReg(sz, gregOfRM(rm)) );
6761
6762 putIReg(sz, gregOfRM(rm),
florian99dd03e2013-01-29 03:56:06 +00006763 IRExpr_ITE( mk_x86g_calculate_condition(cond),
6764 mkexpr(tmps),
6765 mkexpr(tmpd) )
sewardj458a6f82004-08-25 12:46:02 +00006766 );
6767 DIP("cmov%c%s %s,%s\n", nameISize(sz),
sewardj2a9ad022004-11-25 02:46:58 +00006768 name_X86Condcode(cond),
sewardj458a6f82004-08-25 12:46:02 +00006769 nameIReg(sz,eregOfRM(rm)),
6770 nameIReg(sz,gregOfRM(rm)));
6771 return 1+delta0;
6772 }
6773
6774 /* E refers to memory */
6775 {
6776 IRTemp addr = disAMode ( &len, sorb, delta0, dis_buf );
6777 assign( tmps, loadLE(ty, mkexpr(addr)) );
6778 assign( tmpd, getIReg(sz, gregOfRM(rm)) );
6779
6780 putIReg(sz, gregOfRM(rm),
florian99dd03e2013-01-29 03:56:06 +00006781 IRExpr_ITE( mk_x86g_calculate_condition(cond),
6782 mkexpr(tmps),
6783 mkexpr(tmpd) )
sewardj458a6f82004-08-25 12:46:02 +00006784 );
6785
6786 DIP("cmov%c%s %s,%s\n", nameISize(sz),
sewardj2a9ad022004-11-25 02:46:58 +00006787 name_X86Condcode(cond),
sewardj458a6f82004-08-25 12:46:02 +00006788 dis_buf,
6789 nameIReg(sz,gregOfRM(rm)));
6790 return len+delta0;
6791 }
6792}
6793
6794
sewardj883b00b2004-09-11 09:30:24 +00006795static
sewardje9d8a262009-07-01 08:06:34 +00006796UInt dis_xadd_G_E ( UChar sorb, Bool locked, Int sz, Int delta0,
6797 Bool* decodeOK )
sewardj883b00b2004-09-11 09:30:24 +00006798{
6799 Int len;
6800 UChar rm = getIByte(delta0);
sewardjc9a43662004-11-30 18:51:59 +00006801 HChar dis_buf[50];
sewardj883b00b2004-09-11 09:30:24 +00006802
sewardj883b00b2004-09-11 09:30:24 +00006803 IRType ty = szToITy(sz);
6804 IRTemp tmpd = newTemp(ty);
6805 IRTemp tmpt0 = newTemp(ty);
6806 IRTemp tmpt1 = newTemp(ty);
6807
sewardje9d8a262009-07-01 08:06:34 +00006808 /* There are 3 cases to consider:
6809
sewardjc2433a82010-05-10 20:51:22 +00006810 reg-reg: ignore any lock prefix,
6811 generate 'naive' (non-atomic) sequence
sewardje9d8a262009-07-01 08:06:34 +00006812
6813 reg-mem, not locked: ignore any lock prefix, generate 'naive'
6814 (non-atomic) sequence
6815
6816 reg-mem, locked: use IRCAS
6817 */
6818
sewardj883b00b2004-09-11 09:30:24 +00006819 if (epartIsReg(rm)) {
sewardje9d8a262009-07-01 08:06:34 +00006820 /* case 1 */
sewardjc2433a82010-05-10 20:51:22 +00006821 assign( tmpd, getIReg(sz, eregOfRM(rm)));
6822 assign( tmpt0, getIReg(sz, gregOfRM(rm)) );
6823 assign( tmpt1, binop(mkSizedOp(ty,Iop_Add8),
6824 mkexpr(tmpd), mkexpr(tmpt0)) );
6825 setFlags_DEP1_DEP2( Iop_Add8, tmpd, tmpt0, ty );
6826 putIReg(sz, eregOfRM(rm), mkexpr(tmpt1));
6827 putIReg(sz, gregOfRM(rm), mkexpr(tmpd));
6828 DIP("xadd%c %s, %s\n",
6829 nameISize(sz), nameIReg(sz,gregOfRM(rm)),
6830 nameIReg(sz,eregOfRM(rm)));
6831 *decodeOK = True;
6832 return 1+delta0;
sewardje9d8a262009-07-01 08:06:34 +00006833 }
6834 else if (!epartIsReg(rm) && !locked) {
6835 /* case 2 */
sewardj883b00b2004-09-11 09:30:24 +00006836 IRTemp addr = disAMode ( &len, sorb, delta0, dis_buf );
6837 assign( tmpd, loadLE(ty, mkexpr(addr)) );
6838 assign( tmpt0, getIReg(sz, gregOfRM(rm)) );
sewardje9d8a262009-07-01 08:06:34 +00006839 assign( tmpt1, binop(mkSizedOp(ty,Iop_Add8),
6840 mkexpr(tmpd), mkexpr(tmpt0)) );
sewardj883b00b2004-09-11 09:30:24 +00006841 storeLE( mkexpr(addr), mkexpr(tmpt1) );
sewardje9d8a262009-07-01 08:06:34 +00006842 setFlags_DEP1_DEP2( Iop_Add8, tmpd, tmpt0, ty );
sewardj883b00b2004-09-11 09:30:24 +00006843 putIReg(sz, gregOfRM(rm), mkexpr(tmpd));
6844 DIP("xadd%c %s, %s\n",
6845 nameISize(sz), nameIReg(sz,gregOfRM(rm)), dis_buf);
sewardj0092e0d2006-03-06 13:35:42 +00006846 *decodeOK = True;
sewardj883b00b2004-09-11 09:30:24 +00006847 return len+delta0;
6848 }
sewardje9d8a262009-07-01 08:06:34 +00006849 else if (!epartIsReg(rm) && locked) {
6850 /* case 3 */
6851 IRTemp addr = disAMode ( &len, sorb, delta0, dis_buf );
6852 assign( tmpd, loadLE(ty, mkexpr(addr)) );
6853 assign( tmpt0, getIReg(sz, gregOfRM(rm)) );
6854 assign( tmpt1, binop(mkSizedOp(ty,Iop_Add8),
6855 mkexpr(tmpd), mkexpr(tmpt0)) );
6856 casLE( mkexpr(addr), mkexpr(tmpd)/*expVal*/,
6857 mkexpr(tmpt1)/*newVal*/, guest_EIP_curr_instr );
6858 setFlags_DEP1_DEP2( Iop_Add8, tmpd, tmpt0, ty );
6859 putIReg(sz, gregOfRM(rm), mkexpr(tmpd));
6860 DIP("xadd%c %s, %s\n",
6861 nameISize(sz), nameIReg(sz,gregOfRM(rm)), dis_buf);
6862 *decodeOK = True;
6863 return len+delta0;
6864 }
6865 /*UNREACHED*/
6866 vassert(0);
sewardj883b00b2004-09-11 09:30:24 +00006867}
6868
sewardjb64821b2004-12-14 10:00:16 +00006869/* Move 16 bits from Ew (ireg or mem) to G (a segment register). */
6870
sewardj7df596b2004-12-06 14:29:12 +00006871static
sewardj52d04912005-07-03 00:52:48 +00006872UInt dis_mov_Ew_Sw ( UChar sorb, Int delta0 )
sewardj7df596b2004-12-06 14:29:12 +00006873{
sewardjb64821b2004-12-14 10:00:16 +00006874 Int len;
6875 IRTemp addr;
6876 UChar rm = getIByte(delta0);
6877 HChar dis_buf[50];
sewardj7df596b2004-12-06 14:29:12 +00006878
6879 if (epartIsReg(rm)) {
6880 putSReg( gregOfRM(rm), getIReg(2, eregOfRM(rm)) );
6881 DIP("movw %s,%s\n", nameIReg(2,eregOfRM(rm)), nameSReg(gregOfRM(rm)));
6882 return 1+delta0;
sewardjb64821b2004-12-14 10:00:16 +00006883 } else {
6884 addr = disAMode ( &len, sorb, delta0, dis_buf );
6885 putSReg( gregOfRM(rm), loadLE(Ity_I16, mkexpr(addr)) );
6886 DIP("movw %s,%s\n", dis_buf, nameSReg(gregOfRM(rm)));
6887 return len+delta0;
sewardj7df596b2004-12-06 14:29:12 +00006888 }
6889}
6890
sewardjb64821b2004-12-14 10:00:16 +00006891/* Move 16 bits from G (a segment register) to Ew (ireg or mem). If
6892 dst is ireg and sz==4, zero out top half of it. */
6893
sewardj063f02f2004-10-20 12:36:12 +00006894static
6895UInt dis_mov_Sw_Ew ( UChar sorb,
6896 Int sz,
sewardj52d04912005-07-03 00:52:48 +00006897 Int delta0 )
sewardj063f02f2004-10-20 12:36:12 +00006898{
sewardjb64821b2004-12-14 10:00:16 +00006899 Int len;
6900 IRTemp addr;
6901 UChar rm = getIByte(delta0);
6902 HChar dis_buf[50];
sewardj063f02f2004-10-20 12:36:12 +00006903
6904 vassert(sz == 2 || sz == 4);
6905
6906 if (epartIsReg(rm)) {
6907 if (sz == 4)
6908 putIReg(4, eregOfRM(rm), unop(Iop_16Uto32, getSReg(gregOfRM(rm))));
6909 else
6910 putIReg(2, eregOfRM(rm), getSReg(gregOfRM(rm)));
6911
6912 DIP("mov %s,%s\n", nameSReg(gregOfRM(rm)), nameIReg(sz,eregOfRM(rm)));
6913 return 1+delta0;
sewardjb64821b2004-12-14 10:00:16 +00006914 } else {
6915 addr = disAMode ( &len, sorb, delta0, dis_buf );
6916 storeLE( mkexpr(addr), getSReg(gregOfRM(rm)) );
sewardj063f02f2004-10-20 12:36:12 +00006917 DIP("mov %s,%s\n", nameSReg(gregOfRM(rm)), dis_buf);
sewardjb64821b2004-12-14 10:00:16 +00006918 return len+delta0;
sewardj063f02f2004-10-20 12:36:12 +00006919 }
sewardj063f02f2004-10-20 12:36:12 +00006920}
6921
6922
sewardjb64821b2004-12-14 10:00:16 +00006923static
6924void dis_push_segreg ( UInt sreg, Int sz )
6925{
6926 IRTemp t1 = newTemp(Ity_I16);
6927 IRTemp ta = newTemp(Ity_I32);
6928 vassert(sz == 2 || sz == 4);
6929
6930 assign( t1, getSReg(sreg) );
6931 assign( ta, binop(Iop_Sub32, getIReg(4, R_ESP), mkU32(sz)) );
6932 putIReg(4, R_ESP, mkexpr(ta));
6933 storeLE( mkexpr(ta), mkexpr(t1) );
6934
sewardj5c5f72c2006-03-18 11:29:25 +00006935 DIP("push%c %s\n", sz==2 ? 'w' : 'l', nameSReg(sreg));
sewardjb64821b2004-12-14 10:00:16 +00006936}
6937
6938static
6939void dis_pop_segreg ( UInt sreg, Int sz )
6940{
6941 IRTemp t1 = newTemp(Ity_I16);
6942 IRTemp ta = newTemp(Ity_I32);
6943 vassert(sz == 2 || sz == 4);
6944
6945 assign( ta, getIReg(4, R_ESP) );
6946 assign( t1, loadLE(Ity_I16, mkexpr(ta)) );
6947
6948 putIReg(4, R_ESP, binop(Iop_Add32, mkexpr(ta), mkU32(sz)) );
6949 putSReg( sreg, mkexpr(t1) );
sewardj5c5f72c2006-03-18 11:29:25 +00006950 DIP("pop%c %s\n", sz==2 ? 'w' : 'l', nameSReg(sreg));
sewardjb64821b2004-12-14 10:00:16 +00006951}
sewardje05c42c2004-07-08 20:25:10 +00006952
6953static
sewardjc6f970f2012-04-02 21:54:49 +00006954void dis_ret ( /*MOD*/DisResult* dres, UInt d32 )
sewardje05c42c2004-07-08 20:25:10 +00006955{
sewardjc6f970f2012-04-02 21:54:49 +00006956 IRTemp t1 = newTemp(Ity_I32);
6957 IRTemp t2 = newTemp(Ity_I32);
sewardje05c42c2004-07-08 20:25:10 +00006958 assign(t1, getIReg(4,R_ESP));
6959 assign(t2, loadLE(Ity_I32,mkexpr(t1)));
6960 putIReg(4, R_ESP,binop(Iop_Add32, mkexpr(t1), mkU32(4+d32)));
sewardjc6f970f2012-04-02 21:54:49 +00006961 jmp_treg(dres, Ijk_Ret, t2);
6962 vassert(dres->whatNext == Dis_StopHere);
sewardje05c42c2004-07-08 20:25:10 +00006963}
6964
sewardj4cb918d2004-12-03 19:43:31 +00006965/*------------------------------------------------------------*/
6966/*--- SSE/SSE2/SSE3 helpers ---*/
6967/*------------------------------------------------------------*/
sewardjc9a43662004-11-30 18:51:59 +00006968
sewardj9571dc02014-01-26 18:34:23 +00006969/* Indicates whether the op requires a rounding-mode argument. Note
6970 that this covers only vector floating point arithmetic ops, and
6971 omits the scalar ones that need rounding modes. Note also that
6972 inconsistencies here will get picked up later by the IR sanity
6973 checker, so this isn't correctness-critical. */
6974static Bool requiresRMode ( IROp op )
6975{
6976 switch (op) {
6977 /* 128 bit ops */
6978 case Iop_Add32Fx4: case Iop_Sub32Fx4:
6979 case Iop_Mul32Fx4: case Iop_Div32Fx4:
6980 case Iop_Add64Fx2: case Iop_Sub64Fx2:
6981 case Iop_Mul64Fx2: case Iop_Div64Fx2:
6982 return True;
6983 default:
6984 break;
6985 }
6986 return False;
6987}
6988
6989
sewardj129b3d92004-12-05 15:42:05 +00006990/* Worker function; do not call directly.
6991 Handles full width G = G `op` E and G = (not G) `op` E.
6992*/
6993
6994static UInt dis_SSE_E_to_G_all_wrk (
sewardj52d04912005-07-03 00:52:48 +00006995 UChar sorb, Int delta,
florian55085f82012-11-21 00:36:55 +00006996 const HChar* opname, IROp op,
sewardj1e6ad742004-12-02 16:16:11 +00006997 Bool invertG
6998 )
sewardjc9a43662004-11-30 18:51:59 +00006999{
sewardj1e6ad742004-12-02 16:16:11 +00007000 HChar dis_buf[50];
7001 Int alen;
7002 IRTemp addr;
7003 UChar rm = getIByte(delta);
7004 IRExpr* gpart
sewardjf0c1c582005-02-07 23:47:38 +00007005 = invertG ? unop(Iop_NotV128, getXMMReg(gregOfRM(rm)))
sewardj1e6ad742004-12-02 16:16:11 +00007006 : getXMMReg(gregOfRM(rm));
sewardjc9a43662004-11-30 18:51:59 +00007007 if (epartIsReg(rm)) {
sewardj9571dc02014-01-26 18:34:23 +00007008 putXMMReg(
7009 gregOfRM(rm),
7010 requiresRMode(op)
7011 ? triop(op, get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
7012 gpart,
7013 getXMMReg(eregOfRM(rm)))
7014 : binop(op, gpart,
7015 getXMMReg(eregOfRM(rm)))
7016 );
sewardjc9a43662004-11-30 18:51:59 +00007017 DIP("%s %s,%s\n", opname,
7018 nameXMMReg(eregOfRM(rm)),
7019 nameXMMReg(gregOfRM(rm)) );
7020 return delta+1;
7021 } else {
sewardj1e6ad742004-12-02 16:16:11 +00007022 addr = disAMode ( &alen, sorb, delta, dis_buf );
sewardj9571dc02014-01-26 18:34:23 +00007023 putXMMReg(
7024 gregOfRM(rm),
7025 requiresRMode(op)
7026 ? triop(op, get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
7027 gpart,
7028 loadLE(Ity_V128, mkexpr(addr)))
7029 : binop(op, gpart,
7030 loadLE(Ity_V128, mkexpr(addr)))
7031 );
sewardj1e6ad742004-12-02 16:16:11 +00007032 DIP("%s %s,%s\n", opname,
7033 dis_buf,
7034 nameXMMReg(gregOfRM(rm)) );
7035 return delta+alen;
sewardjc9a43662004-11-30 18:51:59 +00007036 }
7037}
7038
sewardj129b3d92004-12-05 15:42:05 +00007039
7040/* All lanes SSE binary operation, G = G `op` E. */
sewardj1e6ad742004-12-02 16:16:11 +00007041
7042static
florian55085f82012-11-21 00:36:55 +00007043UInt dis_SSE_E_to_G_all ( UChar sorb, Int delta, const HChar* opname, IROp op )
sewardj1e6ad742004-12-02 16:16:11 +00007044{
sewardj129b3d92004-12-05 15:42:05 +00007045 return dis_SSE_E_to_G_all_wrk( sorb, delta, opname, op, False );
sewardj1e6ad742004-12-02 16:16:11 +00007046}
7047
sewardj129b3d92004-12-05 15:42:05 +00007048/* All lanes SSE binary operation, G = (not G) `op` E. */
7049
7050static
sewardj52d04912005-07-03 00:52:48 +00007051UInt dis_SSE_E_to_G_all_invG ( UChar sorb, Int delta,
florian55085f82012-11-21 00:36:55 +00007052 const HChar* opname, IROp op )
sewardj129b3d92004-12-05 15:42:05 +00007053{
7054 return dis_SSE_E_to_G_all_wrk( sorb, delta, opname, op, True );
7055}
7056
sewardj164f9272004-12-09 00:39:32 +00007057
sewardj129b3d92004-12-05 15:42:05 +00007058/* Lowest 32-bit lane only SSE binary operation, G = G `op` E. */
7059
sewardj52d04912005-07-03 00:52:48 +00007060static UInt dis_SSE_E_to_G_lo32 ( UChar sorb, Int delta,
florian55085f82012-11-21 00:36:55 +00007061 const HChar* opname, IROp op )
sewardj129b3d92004-12-05 15:42:05 +00007062{
7063 HChar dis_buf[50];
7064 Int alen;
7065 IRTemp addr;
7066 UChar rm = getIByte(delta);
7067 IRExpr* gpart = getXMMReg(gregOfRM(rm));
7068 if (epartIsReg(rm)) {
7069 putXMMReg( gregOfRM(rm),
7070 binop(op, gpart,
7071 getXMMReg(eregOfRM(rm))) );
7072 DIP("%s %s,%s\n", opname,
7073 nameXMMReg(eregOfRM(rm)),
7074 nameXMMReg(gregOfRM(rm)) );
7075 return delta+1;
7076 } else {
7077 /* We can only do a 32-bit memory read, so the upper 3/4 of the
7078 E operand needs to be made simply of zeroes. */
7079 IRTemp epart = newTemp(Ity_V128);
7080 addr = disAMode ( &alen, sorb, delta, dis_buf );
sewardjf0c1c582005-02-07 23:47:38 +00007081 assign( epart, unop( Iop_32UtoV128,
sewardj129b3d92004-12-05 15:42:05 +00007082 loadLE(Ity_I32, mkexpr(addr))) );
7083 putXMMReg( gregOfRM(rm),
7084 binop(op, gpart, mkexpr(epart)) );
7085 DIP("%s %s,%s\n", opname,
7086 dis_buf,
7087 nameXMMReg(gregOfRM(rm)) );
7088 return delta+alen;
7089 }
7090}
7091
sewardj164f9272004-12-09 00:39:32 +00007092
sewardj636ad762004-12-07 11:16:04 +00007093/* Lower 64-bit lane only SSE binary operation, G = G `op` E. */
7094
sewardj52d04912005-07-03 00:52:48 +00007095static UInt dis_SSE_E_to_G_lo64 ( UChar sorb, Int delta,
florian55085f82012-11-21 00:36:55 +00007096 const HChar* opname, IROp op )
sewardj636ad762004-12-07 11:16:04 +00007097{
7098 HChar dis_buf[50];
7099 Int alen;
7100 IRTemp addr;
7101 UChar rm = getIByte(delta);
7102 IRExpr* gpart = getXMMReg(gregOfRM(rm));
7103 if (epartIsReg(rm)) {
7104 putXMMReg( gregOfRM(rm),
7105 binop(op, gpart,
7106 getXMMReg(eregOfRM(rm))) );
7107 DIP("%s %s,%s\n", opname,
7108 nameXMMReg(eregOfRM(rm)),
7109 nameXMMReg(gregOfRM(rm)) );
7110 return delta+1;
7111 } else {
7112 /* We can only do a 64-bit memory read, so the upper half of the
7113 E operand needs to be made simply of zeroes. */
7114 IRTemp epart = newTemp(Ity_V128);
7115 addr = disAMode ( &alen, sorb, delta, dis_buf );
sewardjf0c1c582005-02-07 23:47:38 +00007116 assign( epart, unop( Iop_64UtoV128,
sewardj636ad762004-12-07 11:16:04 +00007117 loadLE(Ity_I64, mkexpr(addr))) );
7118 putXMMReg( gregOfRM(rm),
7119 binop(op, gpart, mkexpr(epart)) );
7120 DIP("%s %s,%s\n", opname,
7121 dis_buf,
7122 nameXMMReg(gregOfRM(rm)) );
7123 return delta+alen;
7124 }
7125}
7126
sewardj164f9272004-12-09 00:39:32 +00007127
sewardj129b3d92004-12-05 15:42:05 +00007128/* All lanes unary SSE operation, G = op(E). */
7129
7130static UInt dis_SSE_E_to_G_unary_all (
sewardj52d04912005-07-03 00:52:48 +00007131 UChar sorb, Int delta,
florian55085f82012-11-21 00:36:55 +00007132 const HChar* opname, IROp op
sewardj0bd7ce62004-12-05 02:47:40 +00007133 )
7134{
7135 HChar dis_buf[50];
7136 Int alen;
7137 IRTemp addr;
7138 UChar rm = getIByte(delta);
sewardj8bb1c9e2015-04-07 09:36:35 +00007139 // Sqrt32Fx4 and Sqrt64Fx2 take a rounding mode, which is faked
7140 // up in the usual way.
7141 Bool needsIRRM = op == Iop_Sqrt32Fx4 || op == Iop_Sqrt64Fx2;
sewardj0bd7ce62004-12-05 02:47:40 +00007142 if (epartIsReg(rm)) {
sewardj8bb1c9e2015-04-07 09:36:35 +00007143 IRExpr* src = getXMMReg(eregOfRM(rm));
7144 /* XXXROUNDINGFIXME */
7145 IRExpr* res = needsIRRM ? binop(op, get_FAKE_roundingmode(), src)
7146 : unop(op, src);
7147 putXMMReg( gregOfRM(rm), res );
sewardj0bd7ce62004-12-05 02:47:40 +00007148 DIP("%s %s,%s\n", opname,
7149 nameXMMReg(eregOfRM(rm)),
7150 nameXMMReg(gregOfRM(rm)) );
7151 return delta+1;
7152 } else {
7153 addr = disAMode ( &alen, sorb, delta, dis_buf );
sewardj8bb1c9e2015-04-07 09:36:35 +00007154 IRExpr* src = loadLE(Ity_V128, mkexpr(addr));
7155 /* XXXROUNDINGFIXME */
7156 IRExpr* res = needsIRRM ? binop(op, get_FAKE_roundingmode(), src)
7157 : unop(op, src);
7158 putXMMReg( gregOfRM(rm), res );
sewardj0bd7ce62004-12-05 02:47:40 +00007159 DIP("%s %s,%s\n", opname,
7160 dis_buf,
7161 nameXMMReg(gregOfRM(rm)) );
7162 return delta+alen;
7163 }
7164}
7165
sewardj164f9272004-12-09 00:39:32 +00007166
sewardj129b3d92004-12-05 15:42:05 +00007167/* Lowest 32-bit lane only unary SSE operation, G = op(E). */
sewardj0bd7ce62004-12-05 02:47:40 +00007168
sewardj129b3d92004-12-05 15:42:05 +00007169static UInt dis_SSE_E_to_G_unary_lo32 (
sewardj52d04912005-07-03 00:52:48 +00007170 UChar sorb, Int delta,
florian55085f82012-11-21 00:36:55 +00007171 const HChar* opname, IROp op
sewardj129b3d92004-12-05 15:42:05 +00007172 )
7173{
7174 /* First we need to get the old G value and patch the low 32 bits
7175 of the E operand into it. Then apply op and write back to G. */
7176 HChar dis_buf[50];
7177 Int alen;
7178 IRTemp addr;
7179 UChar rm = getIByte(delta);
7180 IRTemp oldG0 = newTemp(Ity_V128);
7181 IRTemp oldG1 = newTemp(Ity_V128);
7182
7183 assign( oldG0, getXMMReg(gregOfRM(rm)) );
7184
7185 if (epartIsReg(rm)) {
7186 assign( oldG1,
sewardjf0c1c582005-02-07 23:47:38 +00007187 binop( Iop_SetV128lo32,
sewardj129b3d92004-12-05 15:42:05 +00007188 mkexpr(oldG0),
sewardj35579be2004-12-06 00:36:25 +00007189 getXMMRegLane32(eregOfRM(rm), 0)) );
sewardj129b3d92004-12-05 15:42:05 +00007190 putXMMReg( gregOfRM(rm), unop(op, mkexpr(oldG1)) );
7191 DIP("%s %s,%s\n", opname,
7192 nameXMMReg(eregOfRM(rm)),
7193 nameXMMReg(gregOfRM(rm)) );
7194 return delta+1;
7195 } else {
7196 addr = disAMode ( &alen, sorb, delta, dis_buf );
7197 assign( oldG1,
sewardjf0c1c582005-02-07 23:47:38 +00007198 binop( Iop_SetV128lo32,
sewardj129b3d92004-12-05 15:42:05 +00007199 mkexpr(oldG0),
7200 loadLE(Ity_I32, mkexpr(addr)) ));
7201 putXMMReg( gregOfRM(rm), unop(op, mkexpr(oldG1)) );
7202 DIP("%s %s,%s\n", opname,
7203 dis_buf,
7204 nameXMMReg(gregOfRM(rm)) );
7205 return delta+alen;
7206 }
7207}
7208
sewardj164f9272004-12-09 00:39:32 +00007209
sewardj008754b2004-12-08 14:37:10 +00007210/* Lowest 64-bit lane only unary SSE operation, G = op(E). */
7211
7212static UInt dis_SSE_E_to_G_unary_lo64 (
sewardj52d04912005-07-03 00:52:48 +00007213 UChar sorb, Int delta,
florian55085f82012-11-21 00:36:55 +00007214 const HChar* opname, IROp op
sewardj008754b2004-12-08 14:37:10 +00007215 )
7216{
7217 /* First we need to get the old G value and patch the low 64 bits
7218 of the E operand into it. Then apply op and write back to G. */
7219 HChar dis_buf[50];
7220 Int alen;
7221 IRTemp addr;
7222 UChar rm = getIByte(delta);
7223 IRTemp oldG0 = newTemp(Ity_V128);
7224 IRTemp oldG1 = newTemp(Ity_V128);
7225
7226 assign( oldG0, getXMMReg(gregOfRM(rm)) );
7227
7228 if (epartIsReg(rm)) {
7229 assign( oldG1,
sewardjf0c1c582005-02-07 23:47:38 +00007230 binop( Iop_SetV128lo64,
sewardj008754b2004-12-08 14:37:10 +00007231 mkexpr(oldG0),
7232 getXMMRegLane64(eregOfRM(rm), 0)) );
7233 putXMMReg( gregOfRM(rm), unop(op, mkexpr(oldG1)) );
7234 DIP("%s %s,%s\n", opname,
7235 nameXMMReg(eregOfRM(rm)),
7236 nameXMMReg(gregOfRM(rm)) );
7237 return delta+1;
7238 } else {
7239 addr = disAMode ( &alen, sorb, delta, dis_buf );
7240 assign( oldG1,
sewardjf0c1c582005-02-07 23:47:38 +00007241 binop( Iop_SetV128lo64,
sewardj008754b2004-12-08 14:37:10 +00007242 mkexpr(oldG0),
7243 loadLE(Ity_I64, mkexpr(addr)) ));
7244 putXMMReg( gregOfRM(rm), unop(op, mkexpr(oldG1)) );
7245 DIP("%s %s,%s\n", opname,
7246 dis_buf,
7247 nameXMMReg(gregOfRM(rm)) );
7248 return delta+alen;
7249 }
7250}
7251
sewardj164f9272004-12-09 00:39:32 +00007252
7253/* SSE integer binary operation:
7254 G = G `op` E (eLeft == False)
7255 G = E `op` G (eLeft == True)
7256*/
7257static UInt dis_SSEint_E_to_G(
sewardj52d04912005-07-03 00:52:48 +00007258 UChar sorb, Int delta,
florian55085f82012-11-21 00:36:55 +00007259 const HChar* opname, IROp op,
sewardj164f9272004-12-09 00:39:32 +00007260 Bool eLeft
7261 )
7262{
7263 HChar dis_buf[50];
7264 Int alen;
7265 IRTemp addr;
7266 UChar rm = getIByte(delta);
7267 IRExpr* gpart = getXMMReg(gregOfRM(rm));
7268 IRExpr* epart = NULL;
7269 if (epartIsReg(rm)) {
7270 epart = getXMMReg(eregOfRM(rm));
7271 DIP("%s %s,%s\n", opname,
7272 nameXMMReg(eregOfRM(rm)),
7273 nameXMMReg(gregOfRM(rm)) );
7274 delta += 1;
7275 } else {
7276 addr = disAMode ( &alen, sorb, delta, dis_buf );
7277 epart = loadLE(Ity_V128, mkexpr(addr));
7278 DIP("%s %s,%s\n", opname,
7279 dis_buf,
7280 nameXMMReg(gregOfRM(rm)) );
7281 delta += alen;
7282 }
7283 putXMMReg( gregOfRM(rm),
7284 eLeft ? binop(op, epart, gpart)
7285 : binop(op, gpart, epart) );
7286 return delta;
7287}
7288
7289
sewardjfd226452004-12-07 19:02:18 +00007290/* Helper for doing SSE FP comparisons. */
sewardj0bd7ce62004-12-05 02:47:40 +00007291
sewardj1e6ad742004-12-02 16:16:11 +00007292static void findSSECmpOp ( Bool* needNot, IROp* op,
7293 Int imm8, Bool all_lanes, Int sz )
7294{
7295 imm8 &= 7;
7296 *needNot = False;
7297 *op = Iop_INVALID;
7298 if (imm8 >= 4) {
7299 *needNot = True;
7300 imm8 -= 4;
7301 }
7302
7303 if (sz == 4 && all_lanes) {
7304 switch (imm8) {
7305 case 0: *op = Iop_CmpEQ32Fx4; return;
7306 case 1: *op = Iop_CmpLT32Fx4; return;
7307 case 2: *op = Iop_CmpLE32Fx4; return;
7308 case 3: *op = Iop_CmpUN32Fx4; return;
7309 default: break;
7310 }
7311 }
7312 if (sz == 4 && !all_lanes) {
7313 switch (imm8) {
7314 case 0: *op = Iop_CmpEQ32F0x4; return;
7315 case 1: *op = Iop_CmpLT32F0x4; return;
7316 case 2: *op = Iop_CmpLE32F0x4; return;
7317 case 3: *op = Iop_CmpUN32F0x4; return;
7318 default: break;
7319 }
7320 }
sewardjfd226452004-12-07 19:02:18 +00007321 if (sz == 8 && all_lanes) {
7322 switch (imm8) {
7323 case 0: *op = Iop_CmpEQ64Fx2; return;
7324 case 1: *op = Iop_CmpLT64Fx2; return;
7325 case 2: *op = Iop_CmpLE64Fx2; return;
7326 case 3: *op = Iop_CmpUN64Fx2; return;
7327 default: break;
7328 }
7329 }
7330 if (sz == 8 && !all_lanes) {
7331 switch (imm8) {
7332 case 0: *op = Iop_CmpEQ64F0x2; return;
7333 case 1: *op = Iop_CmpLT64F0x2; return;
7334 case 2: *op = Iop_CmpLE64F0x2; return;
7335 case 3: *op = Iop_CmpUN64F0x2; return;
7336 default: break;
7337 }
sewardj1e6ad742004-12-02 16:16:11 +00007338 }
7339 vpanic("findSSECmpOp(x86,guest)");
7340}
7341
sewardj33c69e52006-01-01 17:15:19 +00007342/* Handles SSE 32F/64F comparisons. */
sewardj129b3d92004-12-05 15:42:05 +00007343
sewardj52d04912005-07-03 00:52:48 +00007344static UInt dis_SSEcmp_E_to_G ( UChar sorb, Int delta,
florian55085f82012-11-21 00:36:55 +00007345 const HChar* opname, Bool all_lanes, Int sz )
sewardj1e6ad742004-12-02 16:16:11 +00007346{
7347 HChar dis_buf[50];
7348 Int alen, imm8;
7349 IRTemp addr;
7350 Bool needNot = False;
7351 IROp op = Iop_INVALID;
7352 IRTemp plain = newTemp(Ity_V128);
7353 UChar rm = getIByte(delta);
7354 UShort mask = 0;
7355 vassert(sz == 4 || sz == 8);
7356 if (epartIsReg(rm)) {
7357 imm8 = getIByte(delta+1);
7358 findSSECmpOp(&needNot, &op, imm8, all_lanes, sz);
7359 assign( plain, binop(op, getXMMReg(gregOfRM(rm)),
7360 getXMMReg(eregOfRM(rm))) );
7361 delta += 2;
7362 DIP("%s $%d,%s,%s\n", opname,
florianb1737742015-08-03 16:03:13 +00007363 imm8,
sewardj1e6ad742004-12-02 16:16:11 +00007364 nameXMMReg(eregOfRM(rm)),
7365 nameXMMReg(gregOfRM(rm)) );
7366 } else {
7367 addr = disAMode ( &alen, sorb, delta, dis_buf );
7368 imm8 = getIByte(delta+alen);
7369 findSSECmpOp(&needNot, &op, imm8, all_lanes, sz);
sewardj33c69e52006-01-01 17:15:19 +00007370 assign( plain,
7371 binop(
7372 op,
7373 getXMMReg(gregOfRM(rm)),
7374 all_lanes ? loadLE(Ity_V128, mkexpr(addr))
7375 : sz == 8 ? unop( Iop_64UtoV128, loadLE(Ity_I64, mkexpr(addr)))
7376 : /*sz==4*/ unop( Iop_32UtoV128, loadLE(Ity_I32, mkexpr(addr)))
7377 )
7378 );
sewardj1e6ad742004-12-02 16:16:11 +00007379 delta += alen+1;
7380 DIP("%s $%d,%s,%s\n", opname,
florianb1737742015-08-03 16:03:13 +00007381 imm8,
sewardj1e6ad742004-12-02 16:16:11 +00007382 dis_buf,
7383 nameXMMReg(gregOfRM(rm)) );
7384 }
7385
sewardj2e383862004-12-12 16:46:47 +00007386 if (needNot && all_lanes) {
7387 putXMMReg( gregOfRM(rm),
sewardjf0c1c582005-02-07 23:47:38 +00007388 unop(Iop_NotV128, mkexpr(plain)) );
sewardj2e383862004-12-12 16:46:47 +00007389 }
7390 else
7391 if (needNot && !all_lanes) {
sewardj9b45b482005-02-07 01:42:18 +00007392 mask = toUShort( sz==4 ? 0x000F : 0x00FF );
sewardj2e383862004-12-12 16:46:47 +00007393 putXMMReg( gregOfRM(rm),
sewardjf0c1c582005-02-07 23:47:38 +00007394 binop(Iop_XorV128, mkexpr(plain), mkV128(mask)) );
sewardj2e383862004-12-12 16:46:47 +00007395 }
7396 else {
7397 putXMMReg( gregOfRM(rm), mkexpr(plain) );
7398 }
sewardj1e6ad742004-12-02 16:16:11 +00007399
sewardj1e6ad742004-12-02 16:16:11 +00007400 return delta;
7401}
7402
sewardjb9fa69b2004-12-09 23:25:14 +00007403
7404/* Vector by scalar shift of G by the amount specified at the bottom
7405 of E. */
7406
sewardj52d04912005-07-03 00:52:48 +00007407static UInt dis_SSE_shiftG_byE ( UChar sorb, Int delta,
florian55085f82012-11-21 00:36:55 +00007408 const HChar* opname, IROp op )
sewardjb9fa69b2004-12-09 23:25:14 +00007409{
7410 HChar dis_buf[50];
7411 Int alen, size;
7412 IRTemp addr;
7413 Bool shl, shr, sar;
7414 UChar rm = getIByte(delta);
7415 IRTemp g0 = newTemp(Ity_V128);
7416 IRTemp g1 = newTemp(Ity_V128);
7417 IRTemp amt = newTemp(Ity_I32);
7418 IRTemp amt8 = newTemp(Ity_I8);
7419 if (epartIsReg(rm)) {
7420 assign( amt, getXMMRegLane32(eregOfRM(rm), 0) );
7421 DIP("%s %s,%s\n", opname,
7422 nameXMMReg(eregOfRM(rm)),
7423 nameXMMReg(gregOfRM(rm)) );
7424 delta++;
7425 } else {
7426 addr = disAMode ( &alen, sorb, delta, dis_buf );
7427 assign( amt, loadLE(Ity_I32, mkexpr(addr)) );
7428 DIP("%s %s,%s\n", opname,
7429 dis_buf,
7430 nameXMMReg(gregOfRM(rm)) );
7431 delta += alen;
7432 }
7433 assign( g0, getXMMReg(gregOfRM(rm)) );
7434 assign( amt8, unop(Iop_32to8, mkexpr(amt)) );
7435
7436 shl = shr = sar = False;
7437 size = 0;
7438 switch (op) {
7439 case Iop_ShlN16x8: shl = True; size = 32; break;
7440 case Iop_ShlN32x4: shl = True; size = 32; break;
7441 case Iop_ShlN64x2: shl = True; size = 64; break;
7442 case Iop_SarN16x8: sar = True; size = 16; break;
7443 case Iop_SarN32x4: sar = True; size = 32; break;
7444 case Iop_ShrN16x8: shr = True; size = 16; break;
7445 case Iop_ShrN32x4: shr = True; size = 32; break;
7446 case Iop_ShrN64x2: shr = True; size = 64; break;
7447 default: vassert(0);
7448 }
7449
7450 if (shl || shr) {
7451 assign(
7452 g1,
florian99dd03e2013-01-29 03:56:06 +00007453 IRExpr_ITE(
sewardj009230b2013-01-26 11:47:55 +00007454 binop(Iop_CmpLT32U,mkexpr(amt),mkU32(size)),
florian99dd03e2013-01-29 03:56:06 +00007455 binop(op, mkexpr(g0), mkexpr(amt8)),
7456 mkV128(0x0000)
sewardjb9fa69b2004-12-09 23:25:14 +00007457 )
7458 );
7459 } else
7460 if (sar) {
7461 assign(
7462 g1,
florian99dd03e2013-01-29 03:56:06 +00007463 IRExpr_ITE(
sewardj009230b2013-01-26 11:47:55 +00007464 binop(Iop_CmpLT32U,mkexpr(amt),mkU32(size)),
florian99dd03e2013-01-29 03:56:06 +00007465 binop(op, mkexpr(g0), mkexpr(amt8)),
7466 binop(op, mkexpr(g0), mkU8(size-1))
sewardjb9fa69b2004-12-09 23:25:14 +00007467 )
7468 );
7469 } else {
sewardjba89f4c2005-04-07 17:31:27 +00007470 /*NOTREACHED*/
sewardjb9fa69b2004-12-09 23:25:14 +00007471 vassert(0);
7472 }
7473
7474 putXMMReg( gregOfRM(rm), mkexpr(g1) );
7475 return delta;
7476}
7477
7478
7479/* Vector by scalar shift of E by an immediate byte. */
7480
sewardj38a3f862005-01-13 15:06:51 +00007481static
florian55085f82012-11-21 00:36:55 +00007482UInt dis_SSE_shiftE_imm ( Int delta, const HChar* opname, IROp op )
sewardjb9fa69b2004-12-09 23:25:14 +00007483{
7484 Bool shl, shr, sar;
7485 UChar rm = getIByte(delta);
sewardj38a3f862005-01-13 15:06:51 +00007486 IRTemp e0 = newTemp(Ity_V128);
7487 IRTemp e1 = newTemp(Ity_V128);
sewardjb9fa69b2004-12-09 23:25:14 +00007488 UChar amt, size;
7489 vassert(epartIsReg(rm));
7490 vassert(gregOfRM(rm) == 2
7491 || gregOfRM(rm) == 4 || gregOfRM(rm) == 6);
sewardj2d49b432005-02-01 00:37:06 +00007492 amt = getIByte(delta+1);
sewardjb9fa69b2004-12-09 23:25:14 +00007493 delta += 2;
7494 DIP("%s $%d,%s\n", opname,
7495 (Int)amt,
7496 nameXMMReg(eregOfRM(rm)) );
sewardj38a3f862005-01-13 15:06:51 +00007497 assign( e0, getXMMReg(eregOfRM(rm)) );
sewardjb9fa69b2004-12-09 23:25:14 +00007498
7499 shl = shr = sar = False;
7500 size = 0;
7501 switch (op) {
7502 case Iop_ShlN16x8: shl = True; size = 16; break;
7503 case Iop_ShlN32x4: shl = True; size = 32; break;
7504 case Iop_ShlN64x2: shl = True; size = 64; break;
7505 case Iop_SarN16x8: sar = True; size = 16; break;
7506 case Iop_SarN32x4: sar = True; size = 32; break;
7507 case Iop_ShrN16x8: shr = True; size = 16; break;
7508 case Iop_ShrN32x4: shr = True; size = 32; break;
7509 case Iop_ShrN64x2: shr = True; size = 64; break;
7510 default: vassert(0);
7511 }
7512
7513 if (shl || shr) {
sewardjba89f4c2005-04-07 17:31:27 +00007514 assign( e1, amt >= size
7515 ? mkV128(0x0000)
7516 : binop(op, mkexpr(e0), mkU8(amt))
7517 );
sewardjb9fa69b2004-12-09 23:25:14 +00007518 } else
7519 if (sar) {
sewardjba89f4c2005-04-07 17:31:27 +00007520 assign( e1, amt >= size
7521 ? binop(op, mkexpr(e0), mkU8(size-1))
7522 : binop(op, mkexpr(e0), mkU8(amt))
7523 );
sewardjb9fa69b2004-12-09 23:25:14 +00007524 } else {
sewardjba89f4c2005-04-07 17:31:27 +00007525 /*NOTREACHED*/
sewardjb9fa69b2004-12-09 23:25:14 +00007526 vassert(0);
7527 }
7528
sewardj38a3f862005-01-13 15:06:51 +00007529 putXMMReg( eregOfRM(rm), mkexpr(e1) );
sewardjb9fa69b2004-12-09 23:25:14 +00007530 return delta;
7531}
7532
7533
sewardjc1e7dfc2004-12-05 19:29:45 +00007534/* Get the current SSE rounding mode. */
sewardjc9a65702004-07-07 16:32:57 +00007535
sewardj4cb918d2004-12-03 19:43:31 +00007536static IRExpr* /* :: Ity_I32 */ get_sse_roundingmode ( void )
7537{
7538 return binop( Iop_And32,
7539 IRExpr_Get( OFFB_SSEROUND, Ity_I32 ),
7540 mkU32(3) );
7541}
7542
sewardj636ad762004-12-07 11:16:04 +00007543static void put_sse_roundingmode ( IRExpr* sseround )
7544{
sewardjdd40fdf2006-12-24 02:20:24 +00007545 vassert(typeOfIRExpr(irsb->tyenv, sseround) == Ity_I32);
sewardj636ad762004-12-07 11:16:04 +00007546 stmt( IRStmt_Put( OFFB_SSEROUND, sseround ) );
7547}
7548
sewardjc1e7dfc2004-12-05 19:29:45 +00007549/* Break a 128-bit value up into four 32-bit ints. */
7550
7551static void breakup128to32s ( IRTemp t128,
7552 /*OUTs*/
7553 IRTemp* t3, IRTemp* t2,
7554 IRTemp* t1, IRTemp* t0 )
7555{
7556 IRTemp hi64 = newTemp(Ity_I64);
7557 IRTemp lo64 = newTemp(Ity_I64);
sewardjf0c1c582005-02-07 23:47:38 +00007558 assign( hi64, unop(Iop_V128HIto64, mkexpr(t128)) );
7559 assign( lo64, unop(Iop_V128to64, mkexpr(t128)) );
sewardjc1e7dfc2004-12-05 19:29:45 +00007560
7561 vassert(t0 && *t0 == IRTemp_INVALID);
7562 vassert(t1 && *t1 == IRTemp_INVALID);
7563 vassert(t2 && *t2 == IRTemp_INVALID);
7564 vassert(t3 && *t3 == IRTemp_INVALID);
7565
7566 *t0 = newTemp(Ity_I32);
7567 *t1 = newTemp(Ity_I32);
7568 *t2 = newTemp(Ity_I32);
7569 *t3 = newTemp(Ity_I32);
7570 assign( *t0, unop(Iop_64to32, mkexpr(lo64)) );
7571 assign( *t1, unop(Iop_64HIto32, mkexpr(lo64)) );
7572 assign( *t2, unop(Iop_64to32, mkexpr(hi64)) );
7573 assign( *t3, unop(Iop_64HIto32, mkexpr(hi64)) );
7574}
7575
7576/* Construct a 128-bit value from four 32-bit ints. */
7577
7578static IRExpr* mk128from32s ( IRTemp t3, IRTemp t2,
7579 IRTemp t1, IRTemp t0 )
7580{
7581 return
sewardjf0c1c582005-02-07 23:47:38 +00007582 binop( Iop_64HLtoV128,
sewardjc1e7dfc2004-12-05 19:29:45 +00007583 binop(Iop_32HLto64, mkexpr(t3), mkexpr(t2)),
7584 binop(Iop_32HLto64, mkexpr(t1), mkexpr(t0))
7585 );
7586}
7587
sewardjb9fa69b2004-12-09 23:25:14 +00007588/* Break a 64-bit value up into four 16-bit ints. */
7589
7590static void breakup64to16s ( IRTemp t64,
7591 /*OUTs*/
7592 IRTemp* t3, IRTemp* t2,
7593 IRTemp* t1, IRTemp* t0 )
7594{
7595 IRTemp hi32 = newTemp(Ity_I32);
7596 IRTemp lo32 = newTemp(Ity_I32);
7597 assign( hi32, unop(Iop_64HIto32, mkexpr(t64)) );
7598 assign( lo32, unop(Iop_64to32, mkexpr(t64)) );
7599
7600 vassert(t0 && *t0 == IRTemp_INVALID);
7601 vassert(t1 && *t1 == IRTemp_INVALID);
7602 vassert(t2 && *t2 == IRTemp_INVALID);
7603 vassert(t3 && *t3 == IRTemp_INVALID);
7604
7605 *t0 = newTemp(Ity_I16);
7606 *t1 = newTemp(Ity_I16);
7607 *t2 = newTemp(Ity_I16);
7608 *t3 = newTemp(Ity_I16);
7609 assign( *t0, unop(Iop_32to16, mkexpr(lo32)) );
7610 assign( *t1, unop(Iop_32HIto16, mkexpr(lo32)) );
7611 assign( *t2, unop(Iop_32to16, mkexpr(hi32)) );
7612 assign( *t3, unop(Iop_32HIto16, mkexpr(hi32)) );
7613}
7614
7615/* Construct a 64-bit value from four 16-bit ints. */
7616
7617static IRExpr* mk64from16s ( IRTemp t3, IRTemp t2,
7618 IRTemp t1, IRTemp t0 )
7619{
7620 return
7621 binop( Iop_32HLto64,
7622 binop(Iop_16HLto32, mkexpr(t3), mkexpr(t2)),
7623 binop(Iop_16HLto32, mkexpr(t1), mkexpr(t0))
7624 );
7625}
7626
sewardj0e9a0f52008-01-04 01:22:41 +00007627/* Generate IR to set the guest %EFLAGS from the pushfl-format image
7628 in the given 32-bit temporary. The flags that are set are: O S Z A
7629 C P D ID AC.
7630
7631 In all cases, code to set AC is generated. However, VEX actually
7632 ignores the AC value and so can optionally emit an emulation
7633 warning when it is enabled. In this routine, an emulation warning
7634 is only emitted if emit_AC_emwarn is True, in which case
7635 next_insn_EIP must be correct (this allows for correct code
7636 generation for popfl/popfw). If emit_AC_emwarn is False,
7637 next_insn_EIP is unimportant (this allows for easy if kludgey code
7638 generation for IRET.) */
7639
7640static
7641void set_EFLAGS_from_value ( IRTemp t1,
7642 Bool emit_AC_emwarn,
7643 Addr32 next_insn_EIP )
7644{
7645 vassert(typeOfIRTemp(irsb->tyenv,t1) == Ity_I32);
7646
7647 /* t1 is the flag word. Mask out everything except OSZACP and set
7648 the flags thunk to X86G_CC_OP_COPY. */
7649 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(X86G_CC_OP_COPY) ));
7650 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
7651 stmt( IRStmt_Put( OFFB_CC_DEP1,
7652 binop(Iop_And32,
7653 mkexpr(t1),
7654 mkU32( X86G_CC_MASK_C | X86G_CC_MASK_P
7655 | X86G_CC_MASK_A | X86G_CC_MASK_Z
7656 | X86G_CC_MASK_S| X86G_CC_MASK_O )
7657 )
7658 )
7659 );
7660 /* Set NDEP even though it isn't used. This makes redundant-PUT
7661 elimination of previous stores to this field work better. */
7662 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
7663
7664 /* Also need to set the D flag, which is held in bit 10 of t1.
7665 If zero, put 1 in OFFB_DFLAG, else -1 in OFFB_DFLAG. */
7666 stmt( IRStmt_Put(
7667 OFFB_DFLAG,
florian99dd03e2013-01-29 03:56:06 +00007668 IRExpr_ITE(
sewardj009230b2013-01-26 11:47:55 +00007669 unop(Iop_32to1,
sewardj0e9a0f52008-01-04 01:22:41 +00007670 binop(Iop_And32,
7671 binop(Iop_Shr32, mkexpr(t1), mkU8(10)),
7672 mkU32(1))),
florian99dd03e2013-01-29 03:56:06 +00007673 mkU32(0xFFFFFFFF),
7674 mkU32(1)))
sewardj0e9a0f52008-01-04 01:22:41 +00007675 );
7676
7677 /* Set the ID flag */
7678 stmt( IRStmt_Put(
7679 OFFB_IDFLAG,
florian99dd03e2013-01-29 03:56:06 +00007680 IRExpr_ITE(
sewardj009230b2013-01-26 11:47:55 +00007681 unop(Iop_32to1,
sewardj0e9a0f52008-01-04 01:22:41 +00007682 binop(Iop_And32,
7683 binop(Iop_Shr32, mkexpr(t1), mkU8(21)),
7684 mkU32(1))),
florian99dd03e2013-01-29 03:56:06 +00007685 mkU32(1),
7686 mkU32(0)))
sewardj0e9a0f52008-01-04 01:22:41 +00007687 );
7688
7689 /* And set the AC flag. If setting it 1 to, possibly emit an
7690 emulation warning. */
7691 stmt( IRStmt_Put(
7692 OFFB_ACFLAG,
florian99dd03e2013-01-29 03:56:06 +00007693 IRExpr_ITE(
sewardj009230b2013-01-26 11:47:55 +00007694 unop(Iop_32to1,
sewardj0e9a0f52008-01-04 01:22:41 +00007695 binop(Iop_And32,
7696 binop(Iop_Shr32, mkexpr(t1), mkU8(18)),
7697 mkU32(1))),
florian99dd03e2013-01-29 03:56:06 +00007698 mkU32(1),
7699 mkU32(0)))
sewardj0e9a0f52008-01-04 01:22:41 +00007700 );
7701
7702 if (emit_AC_emwarn) {
7703 put_emwarn( mkU32(EmWarn_X86_acFlag) );
7704 stmt(
7705 IRStmt_Exit(
7706 binop( Iop_CmpNE32,
7707 binop(Iop_And32, mkexpr(t1), mkU32(1<<18)),
7708 mkU32(0) ),
7709 Ijk_EmWarn,
sewardjc6f970f2012-04-02 21:54:49 +00007710 IRConst_U32( next_insn_EIP ),
7711 OFFB_EIP
sewardj0e9a0f52008-01-04 01:22:41 +00007712 )
7713 );
7714 }
7715}
7716
sewardj4cb918d2004-12-03 19:43:31 +00007717
sewardj150c9cd2008-02-09 01:16:02 +00007718/* Helper for the SSSE3 (not SSE3) PMULHRSW insns. Given two 64-bit
7719 values (aa,bb), computes, for each of the 4 16-bit lanes:
7720
7721 (((aa_lane *s32 bb_lane) >>u 14) + 1) >>u 1
7722*/
7723static IRExpr* dis_PMULHRSW_helper ( IRExpr* aax, IRExpr* bbx )
7724{
7725 IRTemp aa = newTemp(Ity_I64);
7726 IRTemp bb = newTemp(Ity_I64);
7727 IRTemp aahi32s = newTemp(Ity_I64);
7728 IRTemp aalo32s = newTemp(Ity_I64);
7729 IRTemp bbhi32s = newTemp(Ity_I64);
7730 IRTemp bblo32s = newTemp(Ity_I64);
7731 IRTemp rHi = newTemp(Ity_I64);
7732 IRTemp rLo = newTemp(Ity_I64);
7733 IRTemp one32x2 = newTemp(Ity_I64);
7734 assign(aa, aax);
7735 assign(bb, bbx);
7736 assign( aahi32s,
7737 binop(Iop_SarN32x2,
7738 binop(Iop_InterleaveHI16x4, mkexpr(aa), mkexpr(aa)),
7739 mkU8(16) ));
7740 assign( aalo32s,
7741 binop(Iop_SarN32x2,
7742 binop(Iop_InterleaveLO16x4, mkexpr(aa), mkexpr(aa)),
7743 mkU8(16) ));
7744 assign( bbhi32s,
7745 binop(Iop_SarN32x2,
7746 binop(Iop_InterleaveHI16x4, mkexpr(bb), mkexpr(bb)),
7747 mkU8(16) ));
7748 assign( bblo32s,
7749 binop(Iop_SarN32x2,
7750 binop(Iop_InterleaveLO16x4, mkexpr(bb), mkexpr(bb)),
7751 mkU8(16) ));
7752 assign(one32x2, mkU64( (1ULL << 32) + 1 ));
7753 assign(
7754 rHi,
7755 binop(
7756 Iop_ShrN32x2,
7757 binop(
7758 Iop_Add32x2,
7759 binop(
7760 Iop_ShrN32x2,
7761 binop(Iop_Mul32x2, mkexpr(aahi32s), mkexpr(bbhi32s)),
7762 mkU8(14)
7763 ),
7764 mkexpr(one32x2)
7765 ),
7766 mkU8(1)
7767 )
7768 );
7769 assign(
7770 rLo,
7771 binop(
7772 Iop_ShrN32x2,
7773 binop(
7774 Iop_Add32x2,
7775 binop(
7776 Iop_ShrN32x2,
7777 binop(Iop_Mul32x2, mkexpr(aalo32s), mkexpr(bblo32s)),
7778 mkU8(14)
7779 ),
7780 mkexpr(one32x2)
7781 ),
7782 mkU8(1)
7783 )
7784 );
7785 return
7786 binop(Iop_CatEvenLanes16x4, mkexpr(rHi), mkexpr(rLo));
7787}
7788
7789/* Helper for the SSSE3 (not SSE3) PSIGN{B,W,D} insns. Given two 64-bit
7790 values (aa,bb), computes, for each lane:
7791
7792 if aa_lane < 0 then - bb_lane
7793 else if aa_lane > 0 then bb_lane
7794 else 0
7795*/
7796static IRExpr* dis_PSIGN_helper ( IRExpr* aax, IRExpr* bbx, Int laneszB )
7797{
7798 IRTemp aa = newTemp(Ity_I64);
7799 IRTemp bb = newTemp(Ity_I64);
7800 IRTemp zero = newTemp(Ity_I64);
7801 IRTemp bbNeg = newTemp(Ity_I64);
7802 IRTemp negMask = newTemp(Ity_I64);
7803 IRTemp posMask = newTemp(Ity_I64);
7804 IROp opSub = Iop_INVALID;
7805 IROp opCmpGTS = Iop_INVALID;
7806
7807 switch (laneszB) {
7808 case 1: opSub = Iop_Sub8x8; opCmpGTS = Iop_CmpGT8Sx8; break;
7809 case 2: opSub = Iop_Sub16x4; opCmpGTS = Iop_CmpGT16Sx4; break;
7810 case 4: opSub = Iop_Sub32x2; opCmpGTS = Iop_CmpGT32Sx2; break;
7811 default: vassert(0);
7812 }
7813
7814 assign( aa, aax );
7815 assign( bb, bbx );
7816 assign( zero, mkU64(0) );
7817 assign( bbNeg, binop(opSub, mkexpr(zero), mkexpr(bb)) );
7818 assign( negMask, binop(opCmpGTS, mkexpr(zero), mkexpr(aa)) );
7819 assign( posMask, binop(opCmpGTS, mkexpr(aa), mkexpr(zero)) );
7820
7821 return
7822 binop(Iop_Or64,
7823 binop(Iop_And64, mkexpr(bb), mkexpr(posMask)),
7824 binop(Iop_And64, mkexpr(bbNeg), mkexpr(negMask)) );
7825
7826}
7827
7828/* Helper for the SSSE3 (not SSE3) PABS{B,W,D} insns. Given a 64-bit
7829 value aa, computes, for each lane
7830
7831 if aa < 0 then -aa else aa
7832
7833 Note that the result is interpreted as unsigned, so that the
7834 absolute value of the most negative signed input can be
7835 represented.
7836*/
7837static IRExpr* dis_PABS_helper ( IRExpr* aax, Int laneszB )
7838{
7839 IRTemp aa = newTemp(Ity_I64);
7840 IRTemp zero = newTemp(Ity_I64);
7841 IRTemp aaNeg = newTemp(Ity_I64);
7842 IRTemp negMask = newTemp(Ity_I64);
7843 IRTemp posMask = newTemp(Ity_I64);
7844 IROp opSub = Iop_INVALID;
7845 IROp opSarN = Iop_INVALID;
7846
7847 switch (laneszB) {
7848 case 1: opSub = Iop_Sub8x8; opSarN = Iop_SarN8x8; break;
7849 case 2: opSub = Iop_Sub16x4; opSarN = Iop_SarN16x4; break;
7850 case 4: opSub = Iop_Sub32x2; opSarN = Iop_SarN32x2; break;
7851 default: vassert(0);
7852 }
7853
7854 assign( aa, aax );
7855 assign( negMask, binop(opSarN, mkexpr(aa), mkU8(8*laneszB-1)) );
7856 assign( posMask, unop(Iop_Not64, mkexpr(negMask)) );
7857 assign( zero, mkU64(0) );
7858 assign( aaNeg, binop(opSub, mkexpr(zero), mkexpr(aa)) );
7859 return
7860 binop(Iop_Or64,
7861 binop(Iop_And64, mkexpr(aa), mkexpr(posMask)),
7862 binop(Iop_And64, mkexpr(aaNeg), mkexpr(negMask)) );
7863}
7864
7865static IRExpr* dis_PALIGNR_XMM_helper ( IRTemp hi64,
7866 IRTemp lo64, Int byteShift )
7867{
7868 vassert(byteShift >= 1 && byteShift <= 7);
7869 return
7870 binop(Iop_Or64,
7871 binop(Iop_Shl64, mkexpr(hi64), mkU8(8*(8-byteShift))),
7872 binop(Iop_Shr64, mkexpr(lo64), mkU8(8*byteShift))
7873 );
7874}
7875
7876/* Generate a SIGSEGV followed by a restart of the current instruction
7877 if effective_addr is not 16-aligned. This is required behaviour
7878 for some SSE3 instructions and all 128-bit SSSE3 instructions.
7879 This assumes that guest_RIP_curr_instr is set correctly! */
7880static void gen_SEGV_if_not_16_aligned ( IRTemp effective_addr )
7881{
7882 stmt(
7883 IRStmt_Exit(
7884 binop(Iop_CmpNE32,
7885 binop(Iop_And32,mkexpr(effective_addr),mkU32(0xF)),
7886 mkU32(0)),
7887 Ijk_SigSEGV,
sewardjc6f970f2012-04-02 21:54:49 +00007888 IRConst_U32(guest_EIP_curr_instr),
7889 OFFB_EIP
sewardj150c9cd2008-02-09 01:16:02 +00007890 )
7891 );
7892}
7893
7894
sewardjc4356f02007-11-09 21:15:04 +00007895/* Helper for deciding whether a given insn (starting at the opcode
7896 byte) may validly be used with a LOCK prefix. The following insns
7897 may be used with LOCK when their destination operand is in memory.
sewardje9d8a262009-07-01 08:06:34 +00007898 AFAICS this is exactly the same for both 32-bit and 64-bit mode.
sewardjc4356f02007-11-09 21:15:04 +00007899
sewardje9d8a262009-07-01 08:06:34 +00007900 ADD 80 /0, 81 /0, 82 /0, 83 /0, 00, 01
7901 OR 80 /1, 81 /1, 82 /x, 83 /1, 08, 09
7902 ADC 80 /2, 81 /2, 82 /2, 83 /2, 10, 11
7903 SBB 81 /3, 81 /3, 82 /x, 83 /3, 18, 19
7904 AND 80 /4, 81 /4, 82 /x, 83 /4, 20, 21
7905 SUB 80 /5, 81 /5, 82 /x, 83 /5, 28, 29
7906 XOR 80 /6, 81 /6, 82 /x, 83 /6, 30, 31
sewardjc4356f02007-11-09 21:15:04 +00007907
7908 DEC FE /1, FF /1
7909 INC FE /0, FF /0
7910
7911 NEG F6 /3, F7 /3
7912 NOT F6 /2, F7 /2
7913
sewardje9d8a262009-07-01 08:06:34 +00007914 XCHG 86, 87
sewardjc4356f02007-11-09 21:15:04 +00007915
7916 BTC 0F BB, 0F BA /7
7917 BTR 0F B3, 0F BA /6
7918 BTS 0F AB, 0F BA /5
7919
7920 CMPXCHG 0F B0, 0F B1
7921 CMPXCHG8B 0F C7 /1
7922
7923 XADD 0F C0, 0F C1
sewardje9d8a262009-07-01 08:06:34 +00007924
7925 ------------------------------
7926
7927 80 /0 = addb $imm8, rm8
7928 81 /0 = addl $imm32, rm32 and addw $imm16, rm16
7929 82 /0 = addb $imm8, rm8
7930 83 /0 = addl $simm8, rm32 and addw $simm8, rm16
7931
7932 00 = addb r8, rm8
7933 01 = addl r32, rm32 and addw r16, rm16
7934
7935 Same for ADD OR ADC SBB AND SUB XOR
7936
7937 FE /1 = dec rm8
7938 FF /1 = dec rm32 and dec rm16
7939
7940 FE /0 = inc rm8
7941 FF /0 = inc rm32 and inc rm16
7942
7943 F6 /3 = neg rm8
7944 F7 /3 = neg rm32 and neg rm16
7945
7946 F6 /2 = not rm8
7947 F7 /2 = not rm32 and not rm16
7948
7949 0F BB = btcw r16, rm16 and btcl r32, rm32
7950 OF BA /7 = btcw $imm8, rm16 and btcw $imm8, rm32
7951
7952 Same for BTS, BTR
sewardjc4356f02007-11-09 21:15:04 +00007953*/
florian8462d112014-09-24 15:18:09 +00007954static Bool can_be_used_with_LOCK_prefix ( const UChar* opc )
sewardjc4356f02007-11-09 21:15:04 +00007955{
7956 switch (opc[0]) {
sewardje9d8a262009-07-01 08:06:34 +00007957 case 0x00: case 0x01: case 0x08: case 0x09:
7958 case 0x10: case 0x11: case 0x18: case 0x19:
7959 case 0x20: case 0x21: case 0x28: case 0x29:
7960 case 0x30: case 0x31:
7961 if (!epartIsReg(opc[1]))
7962 return True;
7963 break;
sewardjc4356f02007-11-09 21:15:04 +00007964
sewardje9d8a262009-07-01 08:06:34 +00007965 case 0x80: case 0x81: case 0x82: case 0x83:
7966 if (gregOfRM(opc[1]) >= 0 && gregOfRM(opc[1]) <= 6
7967 && !epartIsReg(opc[1]))
sewardjc4356f02007-11-09 21:15:04 +00007968 return True;
7969 break;
7970
7971 case 0xFE: case 0xFF:
sewardje9d8a262009-07-01 08:06:34 +00007972 if (gregOfRM(opc[1]) >= 0 && gregOfRM(opc[1]) <= 1
7973 && !epartIsReg(opc[1]))
sewardjc4356f02007-11-09 21:15:04 +00007974 return True;
7975 break;
7976
7977 case 0xF6: case 0xF7:
sewardje9d8a262009-07-01 08:06:34 +00007978 if (gregOfRM(opc[1]) >= 2 && gregOfRM(opc[1]) <= 3
7979 && !epartIsReg(opc[1]))
sewardjc4356f02007-11-09 21:15:04 +00007980 return True;
7981 break;
7982
7983 case 0x86: case 0x87:
sewardje9d8a262009-07-01 08:06:34 +00007984 if (!epartIsReg(opc[1]))
7985 return True;
7986 break;
sewardjc4356f02007-11-09 21:15:04 +00007987
7988 case 0x0F: {
7989 switch (opc[1]) {
7990 case 0xBB: case 0xB3: case 0xAB:
sewardje9d8a262009-07-01 08:06:34 +00007991 if (!epartIsReg(opc[2]))
7992 return True;
7993 break;
sewardjc4356f02007-11-09 21:15:04 +00007994 case 0xBA:
sewardje9d8a262009-07-01 08:06:34 +00007995 if (gregOfRM(opc[2]) >= 5 && gregOfRM(opc[2]) <= 7
7996 && !epartIsReg(opc[2]))
sewardjc4356f02007-11-09 21:15:04 +00007997 return True;
7998 break;
7999 case 0xB0: case 0xB1:
sewardje9d8a262009-07-01 08:06:34 +00008000 if (!epartIsReg(opc[2]))
8001 return True;
8002 break;
sewardjc4356f02007-11-09 21:15:04 +00008003 case 0xC7:
sewardje9d8a262009-07-01 08:06:34 +00008004 if (gregOfRM(opc[2]) == 1 && !epartIsReg(opc[2]) )
sewardjc4356f02007-11-09 21:15:04 +00008005 return True;
8006 break;
8007 case 0xC0: case 0xC1:
sewardje9d8a262009-07-01 08:06:34 +00008008 if (!epartIsReg(opc[2]))
8009 return True;
8010 break;
sewardjc4356f02007-11-09 21:15:04 +00008011 default:
8012 break;
8013 } /* switch (opc[1]) */
8014 break;
8015 }
8016
8017 default:
8018 break;
8019 } /* switch (opc[0]) */
8020
8021 return False;
8022}
8023
sewardj021f6b42012-08-23 23:39:49 +00008024static IRTemp math_BSWAP ( IRTemp t1, IRType ty )
8025{
8026 IRTemp t2 = newTemp(ty);
8027 if (ty == Ity_I32) {
8028 assign( t2,
8029 binop(
8030 Iop_Or32,
8031 binop(Iop_Shl32, mkexpr(t1), mkU8(24)),
8032 binop(
8033 Iop_Or32,
8034 binop(Iop_And32, binop(Iop_Shl32, mkexpr(t1), mkU8(8)),
8035 mkU32(0x00FF0000)),
8036 binop(Iop_Or32,
8037 binop(Iop_And32, binop(Iop_Shr32, mkexpr(t1), mkU8(8)),
8038 mkU32(0x0000FF00)),
8039 binop(Iop_And32, binop(Iop_Shr32, mkexpr(t1), mkU8(24)),
8040 mkU32(0x000000FF) )
8041 )))
8042 );
8043 return t2;
8044 }
8045 if (ty == Ity_I16) {
8046 assign(t2,
8047 binop(Iop_Or16,
8048 binop(Iop_Shl16, mkexpr(t1), mkU8(8)),
8049 binop(Iop_Shr16, mkexpr(t1), mkU8(8)) ));
8050 return t2;
8051 }
8052 vassert(0);
8053 /*NOTREACHED*/
8054 return IRTemp_INVALID;
8055}
sewardjc4356f02007-11-09 21:15:04 +00008056
sewardjc9a65702004-07-07 16:32:57 +00008057/*------------------------------------------------------------*/
sewardjce70a5c2004-10-18 14:09:54 +00008058/*--- Disassemble a single instruction ---*/
sewardjc9a65702004-07-07 16:32:57 +00008059/*------------------------------------------------------------*/
8060
sewardje9d8a262009-07-01 08:06:34 +00008061/* Disassemble a single instruction into IR. The instruction is
8062 located in host memory at &guest_code[delta]. *expect_CAS is set
8063 to True if the resulting IR is expected to contain an IRCAS
8064 statement, and False if it's not expected to. This makes it
8065 possible for the caller of disInstr_X86_WRK to check that
8066 LOCK-prefixed instructions are at least plausibly translated, in
8067 that it becomes possible to check that a (validly) LOCK-prefixed
8068 instruction generates a translation containing an IRCAS, and
8069 instructions without LOCK prefixes don't generate translations
8070 containing an IRCAS.
8071*/
sewardj9e6491a2005-07-02 19:24:10 +00008072static
sewardje9d8a262009-07-01 08:06:34 +00008073DisResult disInstr_X86_WRK (
8074 /*OUT*/Bool* expect_CAS,
florianbeac5302014-12-31 12:09:38 +00008075 Bool (*resteerOkFn) ( /*opaque*/void*, Addr ),
sewardj984d9b12010-01-15 10:53:21 +00008076 Bool resteerCisOk,
sewardjc716aea2006-01-17 01:48:46 +00008077 void* callback_opaque,
sewardj9e6491a2005-07-02 19:24:10 +00008078 Long delta64,
floriancacba8e2014-12-15 18:58:07 +00008079 const VexArchInfo* archinfo,
8080 const VexAbiInfo* vbi,
sewardj442e51a2012-12-06 18:08:04 +00008081 Bool sigill_diag
sewardj9e6491a2005-07-02 19:24:10 +00008082 )
sewardjc9a65702004-07-07 16:32:57 +00008083{
sewardjce70a5c2004-10-18 14:09:54 +00008084 IRType ty;
sewardjb5452082004-12-04 20:33:02 +00008085 IRTemp addr, t0, t1, t2, t3, t4, t5, t6;
sewardjce70a5c2004-10-18 14:09:54 +00008086 Int alen;
sewardjc4356f02007-11-09 21:15:04 +00008087 UChar opc, modrm, abyte, pre;
sewardjce70a5c2004-10-18 14:09:54 +00008088 UInt d32;
sewardjc9a43662004-11-30 18:51:59 +00008089 HChar dis_buf[50];
sewardjc4356f02007-11-09 21:15:04 +00008090 Int am_sz, d_sz, n_prefixes;
sewardj9e6491a2005-07-02 19:24:10 +00008091 DisResult dres;
florian8462d112014-09-24 15:18:09 +00008092 const UChar* insn; /* used in SSE decoders */
sewardjce70a5c2004-10-18 14:09:54 +00008093
sewardj9e6491a2005-07-02 19:24:10 +00008094 /* The running delta */
8095 Int delta = (Int)delta64;
8096
sewardjc9a65702004-07-07 16:32:57 +00008097 /* Holds eip at the start of the insn, so that we can print
8098 consistent error messages for unimplemented insns. */
sewardj9e6491a2005-07-02 19:24:10 +00008099 Int delta_start = delta;
sewardjc9a65702004-07-07 16:32:57 +00008100
8101 /* sz denotes the nominal data-op size of the insn; we change it to
8102 2 if an 0x66 prefix is seen */
8103 Int sz = 4;
8104
8105 /* sorb holds the segment-override-prefix byte, if any. Zero if no
Elliott Hughesed398002017-06-21 14:41:24 -07008106 prefix has been seen, else one of {0x26, 0x36, 0x3E, 0x64, 0x65}
sewardjc9a65702004-07-07 16:32:57 +00008107 indicating the prefix. */
8108 UChar sorb = 0;
8109
sewardjc4356f02007-11-09 21:15:04 +00008110 /* Gets set to True if a LOCK prefix is seen. */
8111 Bool pfx_lock = False;
8112
sewardj9e6491a2005-07-02 19:24:10 +00008113 /* Set result defaults. */
sewardjc6f970f2012-04-02 21:54:49 +00008114 dres.whatNext = Dis_Continue;
8115 dres.len = 0;
8116 dres.continueAt = 0;
Elliott Hughesed398002017-06-21 14:41:24 -07008117 dres.hint = Dis_HintNone;
sewardjc6f970f2012-04-02 21:54:49 +00008118 dres.jk_StopHere = Ijk_INVALID;
sewardjce70a5c2004-10-18 14:09:54 +00008119
sewardje9d8a262009-07-01 08:06:34 +00008120 *expect_CAS = False;
8121
sewardjb5452082004-12-04 20:33:02 +00008122 addr = t0 = t1 = t2 = t3 = t4 = t5 = t6 = IRTemp_INVALID;
sewardjc9a65702004-07-07 16:32:57 +00008123
sewardje9d8a262009-07-01 08:06:34 +00008124 vassert(guest_EIP_bbstart + delta == guest_EIP_curr_instr);
sewardj9e6491a2005-07-02 19:24:10 +00008125 DIP("\t0x%x: ", guest_EIP_bbstart+delta);
8126
sewardjce02aa72006-01-12 12:27:58 +00008127 /* Spot "Special" instructions (see comment at top of file). */
sewardj750f4072004-07-26 22:39:11 +00008128 {
florian8462d112014-09-24 15:18:09 +00008129 const UChar* code = guest_code + delta;
sewardjce02aa72006-01-12 12:27:58 +00008130 /* Spot the 12-byte preamble:
8131 C1C703 roll $3, %edi
8132 C1C70D roll $13, %edi
8133 C1C71D roll $29, %edi
8134 C1C713 roll $19, %edi
sewardj750f4072004-07-26 22:39:11 +00008135 */
sewardjce02aa72006-01-12 12:27:58 +00008136 if (code[ 0] == 0xC1 && code[ 1] == 0xC7 && code[ 2] == 0x03 &&
8137 code[ 3] == 0xC1 && code[ 4] == 0xC7 && code[ 5] == 0x0D &&
8138 code[ 6] == 0xC1 && code[ 7] == 0xC7 && code[ 8] == 0x1D &&
8139 code[ 9] == 0xC1 && code[10] == 0xC7 && code[11] == 0x13) {
8140 /* Got a "Special" instruction preamble. Which one is it? */
8141 if (code[12] == 0x87 && code[13] == 0xDB /* xchgl %ebx,%ebx */) {
8142 /* %EDX = client_request ( %EAX ) */
8143 DIP("%%edx = client_request ( %%eax )\n");
8144 delta += 14;
sewardjc6f970f2012-04-02 21:54:49 +00008145 jmp_lit(&dres, Ijk_ClientReq, guest_EIP_bbstart+delta);
8146 vassert(dres.whatNext == Dis_StopHere);
sewardjce02aa72006-01-12 12:27:58 +00008147 goto decode_success;
8148 }
8149 else
8150 if (code[12] == 0x87 && code[13] == 0xC9 /* xchgl %ecx,%ecx */) {
8151 /* %EAX = guest_NRADDR */
8152 DIP("%%eax = guest_NRADDR\n");
8153 delta += 14;
8154 putIReg(4, R_EAX, IRExpr_Get( OFFB_NRADDR, Ity_I32 ));
8155 goto decode_success;
8156 }
8157 else
8158 if (code[12] == 0x87 && code[13] == 0xD2 /* xchgl %edx,%edx */) {
8159 /* call-noredir *%EAX */
8160 DIP("call-noredir *%%eax\n");
8161 delta += 14;
8162 t1 = newTemp(Ity_I32);
8163 assign(t1, getIReg(4,R_EAX));
8164 t2 = newTemp(Ity_I32);
8165 assign(t2, binop(Iop_Sub32, getIReg(4,R_ESP), mkU32(4)));
8166 putIReg(4, R_ESP, mkexpr(t2));
8167 storeLE( mkexpr(t2), mkU32(guest_EIP_bbstart+delta));
sewardjc6f970f2012-04-02 21:54:49 +00008168 jmp_treg(&dres, Ijk_NoRedir, t1);
8169 vassert(dres.whatNext == Dis_StopHere);
sewardjce02aa72006-01-12 12:27:58 +00008170 goto decode_success;
8171 }
florian2245ce92012-08-28 16:49:30 +00008172 else
8173 if (code[12] == 0x87 && code[13] == 0xFF /* xchgl %edi,%edi */) {
8174 /* IR injection */
8175 DIP("IR injection\n");
8176 vex_inject_ir(irsb, Iend_LE);
8177
8178 // Invalidate the current insn. The reason is that the IRop we're
8179 // injecting here can change. In which case the translation has to
8180 // be redone. For ease of handling, we simply invalidate all the
8181 // time.
sewardj05f5e012014-05-04 10:52:11 +00008182 stmt(IRStmt_Put(OFFB_CMSTART, mkU32(guest_EIP_curr_instr)));
8183 stmt(IRStmt_Put(OFFB_CMLEN, mkU32(14)));
florian2245ce92012-08-28 16:49:30 +00008184
8185 delta += 14;
8186
8187 stmt( IRStmt_Put( OFFB_EIP, mkU32(guest_EIP_bbstart + delta) ) );
8188 dres.whatNext = Dis_StopHere;
sewardj05f5e012014-05-04 10:52:11 +00008189 dres.jk_StopHere = Ijk_InvalICache;
florian2245ce92012-08-28 16:49:30 +00008190 goto decode_success;
8191 }
sewardjce02aa72006-01-12 12:27:58 +00008192 /* We don't know what it is. */
8193 goto decode_failure;
8194 /*NOTREACHED*/
sewardj750f4072004-07-26 22:39:11 +00008195 }
8196 }
sewardjc9a65702004-07-07 16:32:57 +00008197
sewardjc4356f02007-11-09 21:15:04 +00008198 /* Handle a couple of weird-ass NOPs that have been observed in the
8199 wild. */
8200 {
florian8462d112014-09-24 15:18:09 +00008201 const UChar* code = guest_code + delta;
sewardjc4356f02007-11-09 21:15:04 +00008202 /* Sun's JVM 1.5.0 uses the following as a NOP:
8203 26 2E 64 65 90 %es:%cs:%fs:%gs:nop */
8204 if (code[0] == 0x26 && code[1] == 0x2E && code[2] == 0x64
8205 && code[3] == 0x65 && code[4] == 0x90) {
8206 DIP("%%es:%%cs:%%fs:%%gs:nop\n");
8207 delta += 5;
8208 goto decode_success;
sewardjbb3f52d2005-01-07 14:14:50 +00008209 }
sewardjdeceef82010-05-03 21:58:22 +00008210 /* Don't barf on recent binutils padding,
8211 all variants of which are: nopw %cs:0x0(%eax,%eax,1)
8212 66 2e 0f 1f 84 00 00 00 00 00
8213 66 66 2e 0f 1f 84 00 00 00 00 00
8214 66 66 66 2e 0f 1f 84 00 00 00 00 00
8215 66 66 66 66 2e 0f 1f 84 00 00 00 00 00
8216 66 66 66 66 66 2e 0f 1f 84 00 00 00 00 00
8217 66 66 66 66 66 66 2e 0f 1f 84 00 00 00 00 00
8218 */
8219 if (code[0] == 0x66) {
8220 Int data16_cnt;
8221 for (data16_cnt = 1; data16_cnt < 6; data16_cnt++)
8222 if (code[data16_cnt] != 0x66)
8223 break;
8224 if (code[data16_cnt] == 0x2E && code[data16_cnt + 1] == 0x0F
8225 && code[data16_cnt + 2] == 0x1F && code[data16_cnt + 3] == 0x84
8226 && code[data16_cnt + 4] == 0x00 && code[data16_cnt + 5] == 0x00
8227 && code[data16_cnt + 6] == 0x00 && code[data16_cnt + 7] == 0x00
8228 && code[data16_cnt + 8] == 0x00 ) {
8229 DIP("nopw %%cs:0x0(%%eax,%%eax,1)\n");
8230 delta += 9 + data16_cnt;
8231 goto decode_success;
8232 }
sewardjce4a2822005-01-07 13:25:28 +00008233 }
sewardjbb3f52d2005-01-07 14:14:50 +00008234
Elliott Hughesed398002017-06-21 14:41:24 -07008235 // Intel CET requires the following opcodes to be treated as NOPs
8236 // with any prefix and ModRM, SIB and disp combination:
8237 // "0F 19", "0F 1C", "0F 1D", "0F 1E", "0F 1F"
8238 UInt opcode_index = 0;
8239 // Skip any prefix combination
8240 UInt addr_override = 0;
8241 UInt temp_sz = 4;
8242 Bool is_prefix = True;
8243 while (is_prefix) {
8244 switch (code[opcode_index]) {
8245 case 0x66:
8246 temp_sz = 2;
8247 opcode_index++;
8248 break;
8249 case 0x67:
8250 addr_override = 1;
8251 opcode_index++;
8252 break;
8253 case 0x26: case 0x3E: // if we set segment override here,
8254 case 0x64: case 0x65: // disAMode segfaults
8255 case 0x2E: case 0x36:
8256 case 0xF0: case 0xF2: case 0xF3:
8257 opcode_index++;
8258 break;
8259 default:
8260 is_prefix = False;
8261 }
8262 }
8263 // Check the opcode
8264 if (code[opcode_index] == 0x0F) {
8265 switch (code[opcode_index+1]) {
8266 case 0x19:
8267 case 0x1C: case 0x1D:
8268 case 0x1E: case 0x1F:
8269 delta += opcode_index+2;
8270 modrm = getUChar(delta);
8271 if (epartIsReg(modrm)) {
8272 delta += 1;
8273 DIP("nop%c\n", nameISize(temp_sz));
8274 }
8275 else {
8276 addr = disAMode(&alen, 0/*"no sorb"*/, delta, dis_buf);
8277 delta += alen - addr_override;
8278 DIP("nop%c %s\n", nameISize(temp_sz), dis_buf);
8279 }
8280 goto decode_success;
8281 default:
8282 break;
8283 }
8284 }
8285 }
sewardjc4356f02007-11-09 21:15:04 +00008286 /* Normal instruction handling starts here. */
sewardjc9a65702004-07-07 16:32:57 +00008287
sewardjc4356f02007-11-09 21:15:04 +00008288 /* Deal with some but not all prefixes:
8289 66(oso)
8290 F0(lock)
8291 2E(cs:) 3E(ds:) 26(es:) 64(fs:) 65(gs:) 36(ss:)
8292 Not dealt with (left in place):
8293 F2 F3
8294 */
8295 n_prefixes = 0;
8296 while (True) {
8297 if (n_prefixes > 7) goto decode_failure;
8298 pre = getUChar(delta);
8299 switch (pre) {
8300 case 0x66:
8301 sz = 2;
8302 break;
8303 case 0xF0:
8304 pfx_lock = True;
sewardje9d8a262009-07-01 08:06:34 +00008305 *expect_CAS = True;
sewardjc4356f02007-11-09 21:15:04 +00008306 break;
8307 case 0x3E: /* %DS: */
8308 case 0x26: /* %ES: */
8309 case 0x64: /* %FS: */
8310 case 0x65: /* %GS: */
Elliott Hughesed398002017-06-21 14:41:24 -07008311 case 0x36: /* %SS: */
sewardjc4356f02007-11-09 21:15:04 +00008312 if (sorb != 0)
8313 goto decode_failure; /* only one seg override allowed */
8314 sorb = pre;
8315 break;
8316 case 0x2E: { /* %CS: */
8317 /* 2E prefix on a conditional branch instruction is a
8318 branch-prediction hint, which can safely be ignored. */
sewardjc9a65702004-07-07 16:32:57 +00008319 UChar op1 = getIByte(delta+1);
8320 UChar op2 = getIByte(delta+2);
8321 if ((op1 >= 0x70 && op1 <= 0x7F)
8322 || (op1 == 0xE3)
8323 || (op1 == 0x0F && op2 >= 0x80 && op2 <= 0x8F)) {
sewardj4dfb1992005-03-13 18:56:28 +00008324 if (0) vex_printf("vex x86->IR: ignoring branch hint\n");
sewardjc4356f02007-11-09 21:15:04 +00008325 } else {
8326 /* All other CS override cases are not handled */
8327 goto decode_failure;
sewardjc9a65702004-07-07 16:32:57 +00008328 }
sewardjc4356f02007-11-09 21:15:04 +00008329 break;
sewardjc9a65702004-07-07 16:32:57 +00008330 }
sewardjc4356f02007-11-09 21:15:04 +00008331 default:
8332 goto not_a_prefix;
8333 }
8334 n_prefixes++;
8335 delta++;
sewardjc9a65702004-07-07 16:32:57 +00008336 }
8337
sewardjc4356f02007-11-09 21:15:04 +00008338 not_a_prefix:
8339
8340 /* Now we should be looking at the primary opcode byte or the
8341 leading F2 or F3. Check that any LOCK prefix is actually
8342 allowed. */
8343
sewardjc4356f02007-11-09 21:15:04 +00008344 if (pfx_lock) {
florian8462d112014-09-24 15:18:09 +00008345 if (can_be_used_with_LOCK_prefix( &guest_code[delta] )) {
sewardjc4356f02007-11-09 21:15:04 +00008346 DIP("lock ");
8347 } else {
sewardje9d8a262009-07-01 08:06:34 +00008348 *expect_CAS = False;
sewardjc4356f02007-11-09 21:15:04 +00008349 goto decode_failure;
8350 }
8351 }
8352
8353
sewardjc9a43662004-11-30 18:51:59 +00008354 /* ---------------------------------------------------- */
8355 /* --- The SSE decoder. --- */
8356 /* ---------------------------------------------------- */
8357
sewardj4cb918d2004-12-03 19:43:31 +00008358 /* What did I do to deserve SSE ? Perhaps I was really bad in a
8359 previous life? */
8360
sewardj9df271d2004-12-31 22:37:42 +00008361 /* Note, this doesn't handle SSE2 or SSE3. That is handled in a
8362 later section, further on. */
8363
florian8462d112014-09-24 15:18:09 +00008364 insn = &guest_code[delta];
sewardja0e83b02005-01-06 12:36:38 +00008365
8366 /* Treat fxsave specially. It should be doable even on an SSE0
8367 (Pentium-II class) CPU. Hence be prepared to handle it on
8368 any subarchitecture variant.
8369 */
8370
8371 /* 0F AE /0 = FXSAVE m512 -- write x87 and SSE state to memory */
8372 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xAE
8373 && !epartIsReg(insn[2]) && gregOfRM(insn[2]) == 0) {
sewardj9a036bf2005-03-14 18:19:08 +00008374 IRDirty* d;
sewardja0e83b02005-01-06 12:36:38 +00008375 modrm = getIByte(delta+2);
8376 vassert(sz == 4);
8377 vassert(!epartIsReg(modrm));
8378
8379 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8380 delta += 2+alen;
sewardjec993de2011-01-21 18:02:54 +00008381 gen_SEGV_if_not_16_aligned(addr);
sewardja0e83b02005-01-06 12:36:38 +00008382
sewardj33dd31b2005-01-08 18:17:32 +00008383 DIP("fxsave %s\n", dis_buf);
sewardja0e83b02005-01-06 12:36:38 +00008384
8385 /* Uses dirty helper:
8386 void x86g_do_FXSAVE ( VexGuestX86State*, UInt ) */
sewardj9a036bf2005-03-14 18:19:08 +00008387 d = unsafeIRDirty_0_N (
8388 0/*regparms*/,
8389 "x86g_dirtyhelper_FXSAVE",
8390 &x86g_dirtyhelper_FXSAVE,
Elliott Hughesed398002017-06-21 14:41:24 -07008391 mkIRExprVec_2( IRExpr_GSPTR(), mkexpr(addr) )
sewardj9a036bf2005-03-14 18:19:08 +00008392 );
sewardja0e83b02005-01-06 12:36:38 +00008393
8394 /* declare we're writing memory */
8395 d->mFx = Ifx_Write;
8396 d->mAddr = mkexpr(addr);
sewardjc9069f22012-06-01 16:09:50 +00008397 d->mSize = 464; /* according to recent Intel docs */
sewardja0e83b02005-01-06 12:36:38 +00008398
8399 /* declare we're reading guest state */
8400 d->nFxState = 7;
sewardjc9069f22012-06-01 16:09:50 +00008401 vex_bzero(&d->fxState, sizeof(d->fxState));
sewardja0e83b02005-01-06 12:36:38 +00008402
8403 d->fxState[0].fx = Ifx_Read;
8404 d->fxState[0].offset = OFFB_FTOP;
8405 d->fxState[0].size = sizeof(UInt);
8406
8407 d->fxState[1].fx = Ifx_Read;
8408 d->fxState[1].offset = OFFB_FPREGS;
8409 d->fxState[1].size = 8 * sizeof(ULong);
8410
8411 d->fxState[2].fx = Ifx_Read;
8412 d->fxState[2].offset = OFFB_FPTAGS;
8413 d->fxState[2].size = 8 * sizeof(UChar);
8414
8415 d->fxState[3].fx = Ifx_Read;
8416 d->fxState[3].offset = OFFB_FPROUND;
8417 d->fxState[3].size = sizeof(UInt);
8418
8419 d->fxState[4].fx = Ifx_Read;
8420 d->fxState[4].offset = OFFB_FC3210;
8421 d->fxState[4].size = sizeof(UInt);
8422
8423 d->fxState[5].fx = Ifx_Read;
8424 d->fxState[5].offset = OFFB_XMM0;
8425 d->fxState[5].size = 8 * sizeof(U128);
8426
8427 d->fxState[6].fx = Ifx_Read;
8428 d->fxState[6].offset = OFFB_SSEROUND;
8429 d->fxState[6].size = sizeof(UInt);
8430
8431 /* Be paranoid ... this assertion tries to ensure the 8 %xmm
8432 images are packed back-to-back. If not, the value of
8433 d->fxState[5].size is wrong. */
8434 vassert(16 == sizeof(U128));
8435 vassert(OFFB_XMM7 == (OFFB_XMM0 + 7 * 16));
8436
8437 stmt( IRStmt_Dirty(d) );
8438
8439 goto decode_success;
8440 }
8441
sewardj3800e2d2008-05-09 13:24:43 +00008442 /* 0F AE /1 = FXRSTOR m512 -- read x87 and SSE state from memory */
8443 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xAE
8444 && !epartIsReg(insn[2]) && gregOfRM(insn[2]) == 1) {
8445 IRDirty* d;
8446 modrm = getIByte(delta+2);
8447 vassert(sz == 4);
8448 vassert(!epartIsReg(modrm));
8449
8450 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8451 delta += 2+alen;
sewardjec993de2011-01-21 18:02:54 +00008452 gen_SEGV_if_not_16_aligned(addr);
sewardj3800e2d2008-05-09 13:24:43 +00008453
8454 DIP("fxrstor %s\n", dis_buf);
8455
8456 /* Uses dirty helper:
florian6ef84be2012-08-26 03:20:07 +00008457 VexEmNote x86g_do_FXRSTOR ( VexGuestX86State*, UInt )
sewardjec993de2011-01-21 18:02:54 +00008458 NOTE:
florian6ef84be2012-08-26 03:20:07 +00008459 the VexEmNote value is simply ignored (unlike for FRSTOR)
sewardjec993de2011-01-21 18:02:54 +00008460 */
sewardj3800e2d2008-05-09 13:24:43 +00008461 d = unsafeIRDirty_0_N (
8462 0/*regparms*/,
8463 "x86g_dirtyhelper_FXRSTOR",
8464 &x86g_dirtyhelper_FXRSTOR,
Elliott Hughesed398002017-06-21 14:41:24 -07008465 mkIRExprVec_2( IRExpr_GSPTR(), mkexpr(addr) )
sewardj3800e2d2008-05-09 13:24:43 +00008466 );
sewardj3800e2d2008-05-09 13:24:43 +00008467
8468 /* declare we're reading memory */
8469 d->mFx = Ifx_Read;
8470 d->mAddr = mkexpr(addr);
sewardjc9069f22012-06-01 16:09:50 +00008471 d->mSize = 464; /* according to recent Intel docs */
sewardj3800e2d2008-05-09 13:24:43 +00008472
8473 /* declare we're writing guest state */
8474 d->nFxState = 7;
sewardjc9069f22012-06-01 16:09:50 +00008475 vex_bzero(&d->fxState, sizeof(d->fxState));
sewardj3800e2d2008-05-09 13:24:43 +00008476
8477 d->fxState[0].fx = Ifx_Write;
8478 d->fxState[0].offset = OFFB_FTOP;
8479 d->fxState[0].size = sizeof(UInt);
8480
8481 d->fxState[1].fx = Ifx_Write;
8482 d->fxState[1].offset = OFFB_FPREGS;
8483 d->fxState[1].size = 8 * sizeof(ULong);
8484
8485 d->fxState[2].fx = Ifx_Write;
8486 d->fxState[2].offset = OFFB_FPTAGS;
8487 d->fxState[2].size = 8 * sizeof(UChar);
8488
8489 d->fxState[3].fx = Ifx_Write;
8490 d->fxState[3].offset = OFFB_FPROUND;
8491 d->fxState[3].size = sizeof(UInt);
8492
8493 d->fxState[4].fx = Ifx_Write;
8494 d->fxState[4].offset = OFFB_FC3210;
8495 d->fxState[4].size = sizeof(UInt);
8496
8497 d->fxState[5].fx = Ifx_Write;
8498 d->fxState[5].offset = OFFB_XMM0;
8499 d->fxState[5].size = 8 * sizeof(U128);
8500
8501 d->fxState[6].fx = Ifx_Write;
8502 d->fxState[6].offset = OFFB_SSEROUND;
8503 d->fxState[6].size = sizeof(UInt);
8504
8505 /* Be paranoid ... this assertion tries to ensure the 8 %xmm
8506 images are packed back-to-back. If not, the value of
8507 d->fxState[5].size is wrong. */
8508 vassert(16 == sizeof(U128));
8509 vassert(OFFB_XMM7 == (OFFB_XMM0 + 7 * 16));
8510
8511 stmt( IRStmt_Dirty(d) );
8512
8513 goto decode_success;
8514 }
8515
sewardja0e83b02005-01-06 12:36:38 +00008516 /* ------ SSE decoder main ------ */
8517
sewardj9df271d2004-12-31 22:37:42 +00008518 /* Skip parts of the decoder which don't apply given the stated
8519 guest subarchitecture. */
sewardj5117ce12006-01-27 21:20:15 +00008520 if (archinfo->hwcaps == 0/*baseline, no sse at all*/)
sewardj9df271d2004-12-31 22:37:42 +00008521 goto after_sse_decoders;
mjw6c65c122013-08-27 10:19:03 +00008522
8523 /* With mmxext only some extended MMX instructions are recognized.
8524 The mmxext instructions are MASKMOVQ MOVNTQ PAVGB PAVGW PMAXSW
8525 PMAXUB PMINSW PMINUB PMULHUW PSADBW PSHUFW PEXTRW PINSRW PMOVMSKB
8526 PREFETCHNTA PREFETCHT0 PREFETCHT1 PREFETCHT2 SFENCE
8527
8528 http://support.amd.com/us/Embedded_TechDocs/22466.pdf
8529 https://en.wikipedia.org/wiki/3DNow!#3DNow.21_extensions */
8530
8531 if (archinfo->hwcaps == VEX_HWCAPS_X86_MMXEXT/*integer only sse1 subset*/)
8532 goto mmxext;
8533
sewardj9df271d2004-12-31 22:37:42 +00008534 /* Otherwise we must be doing sse1 or sse2, so we can at least try
8535 for SSE1 here. */
sewardjc9a43662004-11-30 18:51:59 +00008536
sewardjc9a43662004-11-30 18:51:59 +00008537 /* 0F 58 = ADDPS -- add 32Fx4 from R/M to R */
sewardj636ad762004-12-07 11:16:04 +00008538 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x58) {
sewardj129b3d92004-12-05 15:42:05 +00008539 delta = dis_SSE_E_to_G_all( sorb, delta+2, "addps", Iop_Add32Fx4 );
sewardjc9a43662004-11-30 18:51:59 +00008540 goto decode_success;
8541 }
8542
sewardj1e6ad742004-12-02 16:16:11 +00008543 /* F3 0F 58 = ADDSS -- add 32F0x4 from R/M to R */
8544 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x58) {
8545 vassert(sz == 4);
sewardj129b3d92004-12-05 15:42:05 +00008546 delta = dis_SSE_E_to_G_lo32( sorb, delta+3, "addss", Iop_Add32F0x4 );
sewardj1e6ad742004-12-02 16:16:11 +00008547 goto decode_success;
8548 }
8549
8550 /* 0F 55 = ANDNPS -- G = (not G) and E */
sewardj636ad762004-12-07 11:16:04 +00008551 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x55) {
sewardjf0c1c582005-02-07 23:47:38 +00008552 delta = dis_SSE_E_to_G_all_invG( sorb, delta+2, "andnps", Iop_AndV128 );
sewardj1e6ad742004-12-02 16:16:11 +00008553 goto decode_success;
8554 }
8555
8556 /* 0F 54 = ANDPS -- G = G and E */
sewardj636ad762004-12-07 11:16:04 +00008557 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x54) {
sewardjf0c1c582005-02-07 23:47:38 +00008558 delta = dis_SSE_E_to_G_all( sorb, delta+2, "andps", Iop_AndV128 );
sewardj1e6ad742004-12-02 16:16:11 +00008559 goto decode_success;
8560 }
8561
8562 /* 0F C2 = CMPPS -- 32Fx4 comparison from R/M to R */
sewardj636ad762004-12-07 11:16:04 +00008563 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xC2) {
sewardj1e6ad742004-12-02 16:16:11 +00008564 delta = dis_SSEcmp_E_to_G( sorb, delta+2, "cmpps", True, 4 );
8565 goto decode_success;
8566 }
8567
8568 /* F3 0F C2 = CMPSS -- 32F0x4 comparison from R/M to R */
8569 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0xC2) {
8570 vassert(sz == 4);
8571 delta = dis_SSEcmp_E_to_G( sorb, delta+3, "cmpss", False, 4 );
8572 goto decode_success;
8573 }
sewardjc9a43662004-11-30 18:51:59 +00008574
sewardjfd226452004-12-07 19:02:18 +00008575 /* 0F 2F = COMISS -- 32F0x4 comparison G,E, and set ZCP */
sewardjc1e7dfc2004-12-05 19:29:45 +00008576 /* 0F 2E = UCOMISS -- 32F0x4 comparison G,E, and set ZCP */
sewardjfd226452004-12-07 19:02:18 +00008577 if (sz == 4 && insn[0] == 0x0F && (insn[1] == 0x2F || insn[1] == 0x2E)) {
sewardj67e002d2004-12-02 18:16:33 +00008578 IRTemp argL = newTemp(Ity_F32);
8579 IRTemp argR = newTemp(Ity_F32);
sewardj67e002d2004-12-02 18:16:33 +00008580 modrm = getIByte(delta+2);
8581 if (epartIsReg(modrm)) {
8582 assign( argR, getXMMRegLane32F( eregOfRM(modrm), 0/*lowest lane*/ ) );
8583 delta += 2+1;
sewardjc1e7dfc2004-12-05 19:29:45 +00008584 DIP("[u]comiss %s,%s\n", nameXMMReg(eregOfRM(modrm)),
8585 nameXMMReg(gregOfRM(modrm)) );
sewardj67e002d2004-12-02 18:16:33 +00008586 } else {
8587 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8588 assign( argR, loadLE(Ity_F32, mkexpr(addr)) );
8589 delta += 2+alen;
sewardjc1e7dfc2004-12-05 19:29:45 +00008590 DIP("[u]comiss %s,%s\n", dis_buf,
8591 nameXMMReg(gregOfRM(modrm)) );
sewardj67e002d2004-12-02 18:16:33 +00008592 }
8593 assign( argL, getXMMRegLane32F( gregOfRM(modrm), 0/*lowest lane*/ ) );
8594
8595 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(X86G_CC_OP_COPY) ));
8596 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
8597 stmt( IRStmt_Put(
8598 OFFB_CC_DEP1,
8599 binop( Iop_And32,
8600 binop(Iop_CmpF64,
8601 unop(Iop_F32toF64,mkexpr(argL)),
8602 unop(Iop_F32toF64,mkexpr(argR))),
8603 mkU32(0x45)
8604 )));
sewardja3b7e3a2005-04-05 01:54:19 +00008605 /* Set NDEP even though it isn't used. This makes redundant-PUT
8606 elimination of previous stores to this field work better. */
8607 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
sewardj67e002d2004-12-02 18:16:33 +00008608 goto decode_success;
8609 }
sewardjc9a43662004-11-30 18:51:59 +00008610
sewardj4cb918d2004-12-03 19:43:31 +00008611 /* 0F 2A = CVTPI2PS -- convert 2 x I32 in mem/mmx to 2 x F32 in low
8612 half xmm */
sewardjfd226452004-12-07 19:02:18 +00008613 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x2A) {
sewardj4cb918d2004-12-03 19:43:31 +00008614 IRTemp arg64 = newTemp(Ity_I64);
8615 IRTemp rmode = newTemp(Ity_I32);
8616 vassert(sz == 4);
8617
8618 modrm = getIByte(delta+2);
sewardj4cb918d2004-12-03 19:43:31 +00008619 if (epartIsReg(modrm)) {
Elliott Hughesa0664b92017-04-18 17:46:52 -07008620 /* Only switch to MMX mode if the source is a MMX register.
8621 See comments on CVTPI2PD for details. Fixes #357059. */
8622 do_MMX_preamble();
sewardj4cb918d2004-12-03 19:43:31 +00008623 assign( arg64, getMMXReg(eregOfRM(modrm)) );
8624 delta += 2+1;
8625 DIP("cvtpi2ps %s,%s\n", nameMMXReg(eregOfRM(modrm)),
8626 nameXMMReg(gregOfRM(modrm)));
8627 } else {
8628 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8629 assign( arg64, loadLE(Ity_I64, mkexpr(addr)) );
8630 delta += 2+alen;
8631 DIP("cvtpi2ps %s,%s\n", dis_buf,
8632 nameXMMReg(gregOfRM(modrm)) );
8633 }
8634
8635 assign( rmode, get_sse_roundingmode() );
8636
8637 putXMMRegLane32F(
sewardj3bca9062004-12-04 14:36:09 +00008638 gregOfRM(modrm), 0,
8639 binop(Iop_F64toF32,
sewardj4cb918d2004-12-03 19:43:31 +00008640 mkexpr(rmode),
sewardj6c299f32009-12-31 18:00:12 +00008641 unop(Iop_I32StoF64,
sewardj3bca9062004-12-04 14:36:09 +00008642 unop(Iop_64to32, mkexpr(arg64)) )) );
sewardj4cb918d2004-12-03 19:43:31 +00008643
8644 putXMMRegLane32F(
8645 gregOfRM(modrm), 1,
sewardj3bca9062004-12-04 14:36:09 +00008646 binop(Iop_F64toF32,
sewardj4cb918d2004-12-03 19:43:31 +00008647 mkexpr(rmode),
sewardj6c299f32009-12-31 18:00:12 +00008648 unop(Iop_I32StoF64,
sewardj3bca9062004-12-04 14:36:09 +00008649 unop(Iop_64HIto32, mkexpr(arg64)) )) );
sewardj4cb918d2004-12-03 19:43:31 +00008650
8651 goto decode_success;
8652 }
8653
8654 /* F3 0F 2A = CVTSI2SS -- convert I32 in mem/ireg to F32 in low
8655 quarter xmm */
8656 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x2A) {
8657 IRTemp arg32 = newTemp(Ity_I32);
8658 IRTemp rmode = newTemp(Ity_I32);
8659 vassert(sz == 4);
8660
8661 modrm = getIByte(delta+3);
sewardj4cb918d2004-12-03 19:43:31 +00008662 if (epartIsReg(modrm)) {
8663 assign( arg32, getIReg(4, eregOfRM(modrm)) );
8664 delta += 3+1;
8665 DIP("cvtsi2ss %s,%s\n", nameIReg(4, eregOfRM(modrm)),
8666 nameXMMReg(gregOfRM(modrm)));
8667 } else {
8668 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
8669 assign( arg32, loadLE(Ity_I32, mkexpr(addr)) );
8670 delta += 3+alen;
8671 DIP("cvtsi2ss %s,%s\n", dis_buf,
8672 nameXMMReg(gregOfRM(modrm)) );
8673 }
8674
8675 assign( rmode, get_sse_roundingmode() );
8676
8677 putXMMRegLane32F(
sewardj3bca9062004-12-04 14:36:09 +00008678 gregOfRM(modrm), 0,
8679 binop(Iop_F64toF32,
8680 mkexpr(rmode),
sewardj6c299f32009-12-31 18:00:12 +00008681 unop(Iop_I32StoF64, mkexpr(arg32)) ) );
sewardj4cb918d2004-12-03 19:43:31 +00008682
8683 goto decode_success;
8684 }
8685
8686 /* 0F 2D = CVTPS2PI -- convert 2 x F32 in mem/low half xmm to 2 x
8687 I32 in mmx, according to prevailing SSE rounding mode */
8688 /* 0F 2C = CVTTPS2PI -- convert 2 x F32 in mem/low half xmm to 2 x
8689 I32 in mmx, rounding towards zero */
sewardjfd226452004-12-07 19:02:18 +00008690 if (sz == 4 && insn[0] == 0x0F && (insn[1] == 0x2D || insn[1] == 0x2C)) {
sewardj4cb918d2004-12-03 19:43:31 +00008691 IRTemp dst64 = newTemp(Ity_I64);
8692 IRTemp rmode = newTemp(Ity_I32);
8693 IRTemp f32lo = newTemp(Ity_F32);
8694 IRTemp f32hi = newTemp(Ity_F32);
sewardj2d49b432005-02-01 00:37:06 +00008695 Bool r2zero = toBool(insn[1] == 0x2C);
sewardj4cb918d2004-12-03 19:43:31 +00008696
8697 do_MMX_preamble();
8698 modrm = getIByte(delta+2);
8699
8700 if (epartIsReg(modrm)) {
8701 delta += 2+1;
8702 assign(f32lo, getXMMRegLane32F(eregOfRM(modrm), 0));
8703 assign(f32hi, getXMMRegLane32F(eregOfRM(modrm), 1));
8704 DIP("cvt%sps2pi %s,%s\n", r2zero ? "t" : "",
8705 nameXMMReg(eregOfRM(modrm)),
8706 nameMMXReg(gregOfRM(modrm)));
8707 } else {
8708 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8709 assign(f32lo, loadLE(Ity_F32, mkexpr(addr)));
8710 assign(f32hi, loadLE(Ity_F32, binop( Iop_Add32,
8711 mkexpr(addr),
8712 mkU32(4) )));
8713 delta += 2+alen;
8714 DIP("cvt%sps2pi %s,%s\n", r2zero ? "t" : "",
8715 dis_buf,
8716 nameMMXReg(gregOfRM(modrm)));
8717 }
8718
8719 if (r2zero) {
8720 assign(rmode, mkU32((UInt)Irrm_ZERO) );
8721 } else {
8722 assign( rmode, get_sse_roundingmode() );
8723 }
8724
8725 assign(
8726 dst64,
8727 binop( Iop_32HLto64,
sewardj6c299f32009-12-31 18:00:12 +00008728 binop( Iop_F64toI32S,
sewardj4cb918d2004-12-03 19:43:31 +00008729 mkexpr(rmode),
8730 unop( Iop_F32toF64, mkexpr(f32hi) ) ),
sewardj6c299f32009-12-31 18:00:12 +00008731 binop( Iop_F64toI32S,
sewardj4cb918d2004-12-03 19:43:31 +00008732 mkexpr(rmode),
8733 unop( Iop_F32toF64, mkexpr(f32lo) ) )
8734 )
8735 );
8736
8737 putMMXReg(gregOfRM(modrm), mkexpr(dst64));
8738 goto decode_success;
8739 }
8740
8741 /* F3 0F 2D = CVTSS2SI -- convert F32 in mem/low quarter xmm to
8742 I32 in ireg, according to prevailing SSE rounding mode */
8743 /* F3 0F 2C = CVTTSS2SI -- convert F32 in mem/low quarter xmm to
sewardj0b210442005-02-23 13:28:27 +00008744 I32 in ireg, rounding towards zero */
sewardj4cb918d2004-12-03 19:43:31 +00008745 if (insn[0] == 0xF3 && insn[1] == 0x0F
8746 && (insn[2] == 0x2D || insn[2] == 0x2C)) {
8747 IRTemp rmode = newTemp(Ity_I32);
8748 IRTemp f32lo = newTemp(Ity_F32);
sewardj2d49b432005-02-01 00:37:06 +00008749 Bool r2zero = toBool(insn[2] == 0x2C);
sewardj4cb918d2004-12-03 19:43:31 +00008750 vassert(sz == 4);
8751
sewardj4cb918d2004-12-03 19:43:31 +00008752 modrm = getIByte(delta+3);
sewardj4cb918d2004-12-03 19:43:31 +00008753 if (epartIsReg(modrm)) {
8754 delta += 3+1;
8755 assign(f32lo, getXMMRegLane32F(eregOfRM(modrm), 0));
8756 DIP("cvt%sss2si %s,%s\n", r2zero ? "t" : "",
8757 nameXMMReg(eregOfRM(modrm)),
8758 nameIReg(4, gregOfRM(modrm)));
8759 } else {
8760 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
8761 assign(f32lo, loadLE(Ity_F32, mkexpr(addr)));
8762 delta += 3+alen;
8763 DIP("cvt%sss2si %s,%s\n", r2zero ? "t" : "",
8764 dis_buf,
8765 nameIReg(4, gregOfRM(modrm)));
8766 }
8767
8768 if (r2zero) {
sewardj7df596b2004-12-06 14:29:12 +00008769 assign( rmode, mkU32((UInt)Irrm_ZERO) );
sewardj4cb918d2004-12-03 19:43:31 +00008770 } else {
8771 assign( rmode, get_sse_roundingmode() );
8772 }
8773
8774 putIReg(4, gregOfRM(modrm),
sewardj6c299f32009-12-31 18:00:12 +00008775 binop( Iop_F64toI32S,
sewardj4cb918d2004-12-03 19:43:31 +00008776 mkexpr(rmode),
8777 unop( Iop_F32toF64, mkexpr(f32lo) ) )
8778 );
8779
8780 goto decode_success;
8781 }
8782
sewardj176a59c2004-12-03 20:08:31 +00008783 /* 0F 5E = DIVPS -- div 32Fx4 from R/M to R */
sewardjfd226452004-12-07 19:02:18 +00008784 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x5E) {
sewardj129b3d92004-12-05 15:42:05 +00008785 delta = dis_SSE_E_to_G_all( sorb, delta+2, "divps", Iop_Div32Fx4 );
sewardj176a59c2004-12-03 20:08:31 +00008786 goto decode_success;
8787 }
8788
8789 /* F3 0F 5E = DIVSS -- div 32F0x4 from R/M to R */
8790 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x5E) {
8791 vassert(sz == 4);
sewardj129b3d92004-12-05 15:42:05 +00008792 delta = dis_SSE_E_to_G_lo32( sorb, delta+3, "divss", Iop_Div32F0x4 );
sewardj176a59c2004-12-03 20:08:31 +00008793 goto decode_success;
8794 }
8795
sewardj7df596b2004-12-06 14:29:12 +00008796 /* 0F AE /2 = LDMXCSR m32 -- load %mxcsr */
8797 if (insn[0] == 0x0F && insn[1] == 0xAE
8798 && !epartIsReg(insn[2]) && gregOfRM(insn[2]) == 2) {
8799
8800 IRTemp t64 = newTemp(Ity_I64);
8801 IRTemp ew = newTemp(Ity_I32);
8802
8803 modrm = getIByte(delta+2);
8804 vassert(!epartIsReg(modrm));
8805 vassert(sz == 4);
8806
8807 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8808 delta += 2+alen;
sewardj33dd31b2005-01-08 18:17:32 +00008809 DIP("ldmxcsr %s\n", dis_buf);
sewardj7df596b2004-12-06 14:29:12 +00008810
8811 /* The only thing we observe in %mxcsr is the rounding mode.
8812 Therefore, pass the 32-bit value (SSE native-format control
8813 word) to a clean helper, getting back a 64-bit value, the
8814 lower half of which is the SSEROUND value to store, and the
8815 upper half of which is the emulation-warning token which may
8816 be generated.
8817 */
8818 /* ULong x86h_check_ldmxcsr ( UInt ); */
8819 assign( t64, mkIRExprCCall(
8820 Ity_I64, 0/*regparms*/,
sewardj3bd6f3e2004-12-13 10:48:19 +00008821 "x86g_check_ldmxcsr",
8822 &x86g_check_ldmxcsr,
sewardj7df596b2004-12-06 14:29:12 +00008823 mkIRExprVec_1( loadLE(Ity_I32, mkexpr(addr)) )
8824 )
8825 );
8826
sewardj636ad762004-12-07 11:16:04 +00008827 put_sse_roundingmode( unop(Iop_64to32, mkexpr(t64)) );
sewardj7df596b2004-12-06 14:29:12 +00008828 assign( ew, unop(Iop_64HIto32, mkexpr(t64) ) );
8829 put_emwarn( mkexpr(ew) );
8830 /* Finally, if an emulation warning was reported, side-exit to
8831 the next insn, reporting the warning, so that Valgrind's
8832 dispatcher sees the warning. */
8833 stmt(
8834 IRStmt_Exit(
8835 binop(Iop_CmpNE32, mkexpr(ew), mkU32(0)),
8836 Ijk_EmWarn,
sewardjc6f970f2012-04-02 21:54:49 +00008837 IRConst_U32( ((Addr32)guest_EIP_bbstart)+delta),
8838 OFFB_EIP
sewardj7df596b2004-12-06 14:29:12 +00008839 )
8840 );
8841 goto decode_success;
8842 }
8843
mjw6c65c122013-08-27 10:19:03 +00008844
8845 /* mmxext sse1 subset starts here. mmxext only arches will parse
8846 only this subset of the sse1 instructions. */
8847 mmxext:
8848
sewardjd71ba832006-12-27 01:15:29 +00008849 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
8850 /* 0F F7 = MASKMOVQ -- 8x8 masked store */
8851 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xF7) {
8852 Bool ok = False;
8853 delta = dis_MMX( &ok, sorb, sz, delta+1 );
8854 if (!ok)
8855 goto decode_failure;
8856 goto decode_success;
8857 }
8858
sewardjc2feffc2004-12-08 12:31:22 +00008859 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
sewardj9636b442004-12-04 01:38:37 +00008860 /* 0F E7 = MOVNTQ -- for us, just a plain MMX store. Note, the
8861 Intel manual does not say anything about the usual business of
8862 the FP reg tags getting trashed whenever an MMX insn happens.
8863 So we just leave them alone.
8864 */
8865 if (insn[0] == 0x0F && insn[1] == 0xE7) {
8866 modrm = getIByte(delta+2);
sewardjc2feffc2004-12-08 12:31:22 +00008867 if (sz == 4 && !epartIsReg(modrm)) {
sewardj519d66f2004-12-15 11:57:58 +00008868 /* do_MMX_preamble(); Intel docs don't specify this */
sewardj9636b442004-12-04 01:38:37 +00008869 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8870 storeLE( mkexpr(addr), getMMXReg(gregOfRM(modrm)) );
8871 DIP("movntq %s,%s\n", dis_buf,
8872 nameMMXReg(gregOfRM(modrm)));
8873 delta += 2+alen;
8874 goto decode_success;
8875 }
8876 /* else fall through */
8877 }
8878
sewardj3bca9062004-12-04 14:36:09 +00008879 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
8880 /* 0F E0 = PAVGB -- 8x8 unsigned Packed Average, with rounding */
sewardj164f9272004-12-09 00:39:32 +00008881 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xE0) {
sewardjb5452082004-12-04 20:33:02 +00008882 do_MMX_preamble();
8883 delta = dis_MMXop_regmem_to_reg (
8884 sorb, delta+2, insn[1], "pavgb", False );
8885 goto decode_success;
sewardj3bca9062004-12-04 14:36:09 +00008886 }
8887
sewardjb5452082004-12-04 20:33:02 +00008888 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
8889 /* 0F E3 = PAVGW -- 16x4 unsigned Packed Average, with rounding */
sewardj164f9272004-12-09 00:39:32 +00008890 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xE3) {
sewardjb5452082004-12-04 20:33:02 +00008891 do_MMX_preamble();
8892 delta = dis_MMXop_regmem_to_reg (
8893 sorb, delta+2, insn[1], "pavgw", False );
8894 goto decode_success;
8895 }
8896
8897 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
8898 /* 0F C5 = PEXTRW -- extract 16-bit field from mmx(E) and put
8899 zero-extend of it in ireg(G). */
8900 if (insn[0] == 0x0F && insn[1] == 0xC5) {
8901 modrm = insn[2];
8902 if (sz == 4 && epartIsReg(modrm)) {
sewardjb9fa69b2004-12-09 23:25:14 +00008903 IRTemp sV = newTemp(Ity_I64);
8904 t5 = newTemp(Ity_I16);
sewardjb5452082004-12-04 20:33:02 +00008905 do_MMX_preamble();
sewardjb9fa69b2004-12-09 23:25:14 +00008906 assign(sV, getMMXReg(eregOfRM(modrm)));
8907 breakup64to16s( sV, &t3, &t2, &t1, &t0 );
sewardjb5452082004-12-04 20:33:02 +00008908 switch (insn[3] & 3) {
sewardjb9fa69b2004-12-09 23:25:14 +00008909 case 0: assign(t5, mkexpr(t0)); break;
8910 case 1: assign(t5, mkexpr(t1)); break;
8911 case 2: assign(t5, mkexpr(t2)); break;
8912 case 3: assign(t5, mkexpr(t3)); break;
sewardjba89f4c2005-04-07 17:31:27 +00008913 default: vassert(0); /*NOTREACHED*/
sewardjb5452082004-12-04 20:33:02 +00008914 }
sewardjb9fa69b2004-12-09 23:25:14 +00008915 putIReg(4, gregOfRM(modrm), unop(Iop_16Uto32, mkexpr(t5)));
sewardjb5452082004-12-04 20:33:02 +00008916 DIP("pextrw $%d,%s,%s\n",
8917 (Int)insn[3], nameMMXReg(eregOfRM(modrm)),
8918 nameIReg(4,gregOfRM(modrm)));
8919 delta += 4;
8920 goto decode_success;
8921 }
8922 /* else fall through */
8923 }
8924
8925 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
8926 /* 0F C4 = PINSRW -- get 16 bits from E(mem or low half ireg) and
8927 put it into the specified lane of mmx(G). */
sewardje5854d62004-12-09 03:44:34 +00008928 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xC4) {
8929 /* Use t0 .. t3 to hold the 4 original 16-bit lanes of the
8930 mmx reg. t4 is the new lane value. t5 is the original
8931 mmx value. t6 is the new mmx value. */
8932 Int lane;
sewardje5854d62004-12-09 03:44:34 +00008933 t4 = newTemp(Ity_I16);
8934 t5 = newTemp(Ity_I64);
8935 t6 = newTemp(Ity_I64);
8936 modrm = insn[2];
8937 do_MMX_preamble();
sewardjb5452082004-12-04 20:33:02 +00008938
sewardje5854d62004-12-09 03:44:34 +00008939 assign(t5, getMMXReg(gregOfRM(modrm)));
sewardjb9fa69b2004-12-09 23:25:14 +00008940 breakup64to16s( t5, &t3, &t2, &t1, &t0 );
sewardjb5452082004-12-04 20:33:02 +00008941
sewardje5854d62004-12-09 03:44:34 +00008942 if (epartIsReg(modrm)) {
8943 assign(t4, getIReg(2, eregOfRM(modrm)));
sewardjaac7e082005-03-17 14:03:46 +00008944 delta += 3+1;
8945 lane = insn[3+1-1];
florianb1737742015-08-03 16:03:13 +00008946 DIP("pinsrw $%d,%s,%s\n", lane,
sewardje5854d62004-12-09 03:44:34 +00008947 nameIReg(2,eregOfRM(modrm)),
8948 nameMMXReg(gregOfRM(modrm)));
8949 } else {
sewardj7420b092005-03-13 20:19:19 +00008950 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8951 delta += 3+alen;
8952 lane = insn[3+alen-1];
8953 assign(t4, loadLE(Ity_I16, mkexpr(addr)));
florianb1737742015-08-03 16:03:13 +00008954 DIP("pinsrw $%d,%s,%s\n", lane,
sewardj7420b092005-03-13 20:19:19 +00008955 dis_buf,
8956 nameMMXReg(gregOfRM(modrm)));
sewardjb5452082004-12-04 20:33:02 +00008957 }
sewardje5854d62004-12-09 03:44:34 +00008958
8959 switch (lane & 3) {
sewardjb9fa69b2004-12-09 23:25:14 +00008960 case 0: assign(t6, mk64from16s(t3,t2,t1,t4)); break;
8961 case 1: assign(t6, mk64from16s(t3,t2,t4,t0)); break;
8962 case 2: assign(t6, mk64from16s(t3,t4,t1,t0)); break;
8963 case 3: assign(t6, mk64from16s(t4,t2,t1,t0)); break;
sewardjba89f4c2005-04-07 17:31:27 +00008964 default: vassert(0); /*NOTREACHED*/
sewardje5854d62004-12-09 03:44:34 +00008965 }
8966 putMMXReg(gregOfRM(modrm), mkexpr(t6));
8967 goto decode_success;
sewardjb5452082004-12-04 20:33:02 +00008968 }
8969
8970 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
8971 /* 0F EE = PMAXSW -- 16x4 signed max */
sewardje5854d62004-12-09 03:44:34 +00008972 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xEE) {
sewardjb5452082004-12-04 20:33:02 +00008973 do_MMX_preamble();
8974 delta = dis_MMXop_regmem_to_reg (
8975 sorb, delta+2, insn[1], "pmaxsw", False );
8976 goto decode_success;
8977 }
8978
8979 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
8980 /* 0F DE = PMAXUB -- 8x8 unsigned max */
sewardje5854d62004-12-09 03:44:34 +00008981 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xDE) {
sewardjb5452082004-12-04 20:33:02 +00008982 do_MMX_preamble();
8983 delta = dis_MMXop_regmem_to_reg (
8984 sorb, delta+2, insn[1], "pmaxub", False );
8985 goto decode_success;
8986 }
8987
8988 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
8989 /* 0F EA = PMINSW -- 16x4 signed min */
sewardje5854d62004-12-09 03:44:34 +00008990 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xEA) {
sewardjb5452082004-12-04 20:33:02 +00008991 do_MMX_preamble();
8992 delta = dis_MMXop_regmem_to_reg (
8993 sorb, delta+2, insn[1], "pminsw", False );
8994 goto decode_success;
8995 }
8996
8997 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
8998 /* 0F DA = PMINUB -- 8x8 unsigned min */
sewardje5854d62004-12-09 03:44:34 +00008999 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xDA) {
sewardjb5452082004-12-04 20:33:02 +00009000 do_MMX_preamble();
9001 delta = dis_MMXop_regmem_to_reg (
9002 sorb, delta+2, insn[1], "pminub", False );
9003 goto decode_success;
9004 }
9005
9006 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
9007 /* 0F D7 = PMOVMSKB -- extract sign bits from each of 8 lanes in
sewardje13074c2012-11-08 10:57:08 +00009008 mmx(E), turn them into a byte, and put zero-extend of it in
sewardjb5452082004-12-04 20:33:02 +00009009 ireg(G). */
sewardje5854d62004-12-09 03:44:34 +00009010 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xD7) {
sewardjb5452082004-12-04 20:33:02 +00009011 modrm = insn[2];
sewardje5854d62004-12-09 03:44:34 +00009012 if (epartIsReg(modrm)) {
sewardjb5452082004-12-04 20:33:02 +00009013 do_MMX_preamble();
9014 t0 = newTemp(Ity_I64);
9015 t1 = newTemp(Ity_I32);
9016 assign(t0, getMMXReg(eregOfRM(modrm)));
sewardje13074c2012-11-08 10:57:08 +00009017 assign(t1, unop(Iop_8Uto32, unop(Iop_GetMSBs8x8, mkexpr(t0))));
sewardjb5452082004-12-04 20:33:02 +00009018 putIReg(4, gregOfRM(modrm), mkexpr(t1));
9019 DIP("pmovmskb %s,%s\n", nameMMXReg(eregOfRM(modrm)),
9020 nameIReg(4,gregOfRM(modrm)));
9021 delta += 3;
9022 goto decode_success;
9023 }
9024 /* else fall through */
9025 }
9026
sewardj0bd7ce62004-12-05 02:47:40 +00009027 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
9028 /* 0F E4 = PMULUH -- 16x4 hi-half of unsigned widening multiply */
sewardje5854d62004-12-09 03:44:34 +00009029 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xE4) {
sewardj0bd7ce62004-12-05 02:47:40 +00009030 do_MMX_preamble();
9031 delta = dis_MMXop_regmem_to_reg (
9032 sorb, delta+2, insn[1], "pmuluh", False );
9033 goto decode_success;
9034 }
9035
sewardj7df596b2004-12-06 14:29:12 +00009036 /* 0F 18 /0 = PREFETCHNTA -- prefetch into caches, */
9037 /* 0F 18 /1 = PREFETCH0 -- with various different hints */
9038 /* 0F 18 /2 = PREFETCH1 */
9039 /* 0F 18 /3 = PREFETCH2 */
9040 if (insn[0] == 0x0F && insn[1] == 0x18
9041 && !epartIsReg(insn[2])
9042 && gregOfRM(insn[2]) >= 0 && gregOfRM(insn[2]) <= 3) {
florian55085f82012-11-21 00:36:55 +00009043 const HChar* hintstr = "??";
sewardj7df596b2004-12-06 14:29:12 +00009044
9045 modrm = getIByte(delta+2);
9046 vassert(!epartIsReg(modrm));
9047
9048 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9049 delta += 2+alen;
9050
9051 switch (gregOfRM(modrm)) {
9052 case 0: hintstr = "nta"; break;
9053 case 1: hintstr = "t0"; break;
9054 case 2: hintstr = "t1"; break;
9055 case 3: hintstr = "t2"; break;
sewardjba89f4c2005-04-07 17:31:27 +00009056 default: vassert(0); /*NOTREACHED*/
sewardj7df596b2004-12-06 14:29:12 +00009057 }
9058
9059 DIP("prefetch%s %s\n", hintstr, dis_buf);
9060 goto decode_success;
9061 }
9062
sewardj85317682006-03-06 14:07:58 +00009063 /* 0F 0D /0 = PREFETCH m8 -- 3DNow! prefetch */
9064 /* 0F 0D /1 = PREFETCHW m8 -- ditto, with some other hint */
9065 if (insn[0] == 0x0F && insn[1] == 0x0D
9066 && !epartIsReg(insn[2])
9067 && gregOfRM(insn[2]) >= 0 && gregOfRM(insn[2]) <= 1) {
florian55085f82012-11-21 00:36:55 +00009068 const HChar* hintstr = "??";
sewardj85317682006-03-06 14:07:58 +00009069
9070 modrm = getIByte(delta+2);
9071 vassert(!epartIsReg(modrm));
9072
9073 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9074 delta += 2+alen;
9075
9076 switch (gregOfRM(modrm)) {
9077 case 0: hintstr = ""; break;
9078 case 1: hintstr = "w"; break;
9079 default: vassert(0); /*NOTREACHED*/
9080 }
9081
9082 DIP("prefetch%s %s\n", hintstr, dis_buf);
9083 goto decode_success;
9084 }
9085
sewardj0bd7ce62004-12-05 02:47:40 +00009086 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
9087 /* 0F F6 = PSADBW -- sum of 8Ux8 absolute differences */
sewardj7b5b9982005-10-04 11:43:37 +00009088 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xF6) {
sewardj0bd7ce62004-12-05 02:47:40 +00009089 do_MMX_preamble();
9090 delta = dis_MMXop_regmem_to_reg (
9091 sorb, delta+2, insn[1], "psadbw", False );
9092 goto decode_success;
9093 }
9094
9095 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
9096 /* 0F 70 = PSHUFW -- rearrange 4x16 from E(mmx or mem) to G(mmx) */
sewardjb9fa69b2004-12-09 23:25:14 +00009097 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x70) {
sewardj0bd7ce62004-12-05 02:47:40 +00009098 Int order;
sewardjb9fa69b2004-12-09 23:25:14 +00009099 IRTemp sV, dV, s3, s2, s1, s0;
9100 s3 = s2 = s1 = s0 = IRTemp_INVALID;
9101 sV = newTemp(Ity_I64);
9102 dV = newTemp(Ity_I64);
sewardj0bd7ce62004-12-05 02:47:40 +00009103 do_MMX_preamble();
9104 modrm = insn[2];
9105 if (epartIsReg(modrm)) {
sewardjb9fa69b2004-12-09 23:25:14 +00009106 assign( sV, getMMXReg(eregOfRM(modrm)) );
sewardj0bd7ce62004-12-05 02:47:40 +00009107 order = (Int)insn[3];
9108 delta += 2+2;
9109 DIP("pshufw $%d,%s,%s\n", order,
9110 nameMMXReg(eregOfRM(modrm)),
9111 nameMMXReg(gregOfRM(modrm)));
9112 } else {
9113 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
sewardjb9fa69b2004-12-09 23:25:14 +00009114 assign( sV, loadLE(Ity_I64, mkexpr(addr)) );
sewardj0bd7ce62004-12-05 02:47:40 +00009115 order = (Int)insn[2+alen];
9116 delta += 3+alen;
9117 DIP("pshufw $%d,%s,%s\n", order,
9118 dis_buf,
9119 nameMMXReg(gregOfRM(modrm)));
9120 }
sewardjb9fa69b2004-12-09 23:25:14 +00009121 breakup64to16s( sV, &s3, &s2, &s1, &s0 );
sewardj0bd7ce62004-12-05 02:47:40 +00009122
sewardjb9fa69b2004-12-09 23:25:14 +00009123# define SEL(n) \
9124 ((n)==0 ? s0 : ((n)==1 ? s1 : ((n)==2 ? s2 : s3)))
9125 assign(dV,
9126 mk64from16s( SEL((order>>6)&3), SEL((order>>4)&3),
9127 SEL((order>>2)&3), SEL((order>>0)&3) )
sewardj0bd7ce62004-12-05 02:47:40 +00009128 );
sewardjb9fa69b2004-12-09 23:25:14 +00009129 putMMXReg(gregOfRM(modrm), mkexpr(dV));
sewardj0bd7ce62004-12-05 02:47:40 +00009130# undef SEL
sewardj0bd7ce62004-12-05 02:47:40 +00009131 goto decode_success;
9132 }
9133
mjw6c65c122013-08-27 10:19:03 +00009134 /* 0F AE /7 = SFENCE -- flush pending operations to memory */
9135 if (insn[0] == 0x0F && insn[1] == 0xAE
9136 && epartIsReg(insn[2]) && gregOfRM(insn[2]) == 7) {
9137 vassert(sz == 4);
9138 delta += 3;
9139 /* Insert a memory fence. It's sometimes important that these
9140 are carried through to the generated code. */
9141 stmt( IRStmt_MBE(Imbe_Fence) );
9142 DIP("sfence\n");
9143 goto decode_success;
9144 }
9145
9146 /* End of mmxext sse1 subset. No more sse parsing for mmxext only arches. */
9147 if (archinfo->hwcaps == VEX_HWCAPS_X86_MMXEXT/*integer only sse1 subset*/)
9148 goto after_sse_decoders;
9149
9150
9151 /* 0F 5F = MAXPS -- max 32Fx4 from R/M to R */
9152 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x5F) {
9153 delta = dis_SSE_E_to_G_all( sorb, delta+2, "maxps", Iop_Max32Fx4 );
9154 goto decode_success;
9155 }
9156
9157 /* F3 0F 5F = MAXSS -- max 32F0x4 from R/M to R */
9158 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x5F) {
9159 vassert(sz == 4);
9160 delta = dis_SSE_E_to_G_lo32( sorb, delta+3, "maxss", Iop_Max32F0x4 );
9161 goto decode_success;
9162 }
9163
9164 /* 0F 5D = MINPS -- min 32Fx4 from R/M to R */
9165 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x5D) {
9166 delta = dis_SSE_E_to_G_all( sorb, delta+2, "minps", Iop_Min32Fx4 );
9167 goto decode_success;
9168 }
9169
9170 /* F3 0F 5D = MINSS -- min 32F0x4 from R/M to R */
9171 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x5D) {
9172 vassert(sz == 4);
9173 delta = dis_SSE_E_to_G_lo32( sorb, delta+3, "minss", Iop_Min32F0x4 );
9174 goto decode_success;
9175 }
9176
9177 /* 0F 28 = MOVAPS -- move from E (mem or xmm) to G (xmm). */
9178 /* 0F 10 = MOVUPS -- move from E (mem or xmm) to G (xmm). */
9179 if (sz == 4 && insn[0] == 0x0F && (insn[1] == 0x28 || insn[1] == 0x10)) {
9180 modrm = getIByte(delta+2);
9181 if (epartIsReg(modrm)) {
9182 putXMMReg( gregOfRM(modrm),
9183 getXMMReg( eregOfRM(modrm) ));
9184 DIP("mov[ua]ps %s,%s\n", nameXMMReg(eregOfRM(modrm)),
9185 nameXMMReg(gregOfRM(modrm)));
9186 delta += 2+1;
9187 } else {
9188 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9189 if (insn[1] == 0x28/*movaps*/)
9190 gen_SEGV_if_not_16_aligned( addr );
9191 putXMMReg( gregOfRM(modrm),
9192 loadLE(Ity_V128, mkexpr(addr)) );
9193 DIP("mov[ua]ps %s,%s\n", dis_buf,
9194 nameXMMReg(gregOfRM(modrm)));
9195 delta += 2+alen;
9196 }
9197 goto decode_success;
9198 }
9199
9200 /* 0F 29 = MOVAPS -- move from G (xmm) to E (mem or xmm). */
9201 /* 0F 11 = MOVUPS -- move from G (xmm) to E (mem or xmm). */
9202 if (sz == 4 && insn[0] == 0x0F
9203 && (insn[1] == 0x29 || insn[1] == 0x11)) {
9204 modrm = getIByte(delta+2);
9205 if (epartIsReg(modrm)) {
9206 /* fall through; awaiting test case */
9207 } else {
9208 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9209 if (insn[1] == 0x29/*movaps*/)
9210 gen_SEGV_if_not_16_aligned( addr );
9211 storeLE( mkexpr(addr), getXMMReg(gregOfRM(modrm)) );
9212 DIP("mov[ua]ps %s,%s\n", nameXMMReg(gregOfRM(modrm)),
9213 dis_buf );
9214 delta += 2+alen;
9215 goto decode_success;
9216 }
9217 }
9218
9219 /* 0F 16 = MOVHPS -- move from mem to high half of XMM. */
9220 /* 0F 16 = MOVLHPS -- move from lo half to hi half of XMM. */
9221 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x16) {
9222 modrm = getIByte(delta+2);
9223 if (epartIsReg(modrm)) {
9224 delta += 2+1;
9225 putXMMRegLane64( gregOfRM(modrm), 1/*upper lane*/,
9226 getXMMRegLane64( eregOfRM(modrm), 0 ) );
9227 DIP("movhps %s,%s\n", nameXMMReg(eregOfRM(modrm)),
9228 nameXMMReg(gregOfRM(modrm)));
9229 } else {
9230 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9231 delta += 2+alen;
9232 putXMMRegLane64( gregOfRM(modrm), 1/*upper lane*/,
9233 loadLE(Ity_I64, mkexpr(addr)) );
9234 DIP("movhps %s,%s\n", dis_buf,
9235 nameXMMReg( gregOfRM(modrm) ));
9236 }
9237 goto decode_success;
9238 }
9239
9240 /* 0F 17 = MOVHPS -- move from high half of XMM to mem. */
9241 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x17) {
9242 if (!epartIsReg(insn[2])) {
9243 delta += 2;
9244 addr = disAMode ( &alen, sorb, delta, dis_buf );
9245 delta += alen;
9246 storeLE( mkexpr(addr),
9247 getXMMRegLane64( gregOfRM(insn[2]),
9248 1/*upper lane*/ ) );
9249 DIP("movhps %s,%s\n", nameXMMReg( gregOfRM(insn[2]) ),
9250 dis_buf);
9251 goto decode_success;
9252 }
9253 /* else fall through */
9254 }
9255
9256 /* 0F 12 = MOVLPS -- move from mem to low half of XMM. */
9257 /* OF 12 = MOVHLPS -- from from hi half to lo half of XMM. */
9258 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x12) {
9259 modrm = getIByte(delta+2);
9260 if (epartIsReg(modrm)) {
9261 delta += 2+1;
9262 putXMMRegLane64( gregOfRM(modrm),
9263 0/*lower lane*/,
9264 getXMMRegLane64( eregOfRM(modrm), 1 ));
9265 DIP("movhlps %s, %s\n", nameXMMReg(eregOfRM(modrm)),
9266 nameXMMReg(gregOfRM(modrm)));
9267 } else {
9268 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9269 delta += 2+alen;
9270 putXMMRegLane64( gregOfRM(modrm), 0/*lower lane*/,
9271 loadLE(Ity_I64, mkexpr(addr)) );
9272 DIP("movlps %s, %s\n",
9273 dis_buf, nameXMMReg( gregOfRM(modrm) ));
9274 }
9275 goto decode_success;
9276 }
9277
9278 /* 0F 13 = MOVLPS -- move from low half of XMM to mem. */
9279 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x13) {
9280 if (!epartIsReg(insn[2])) {
9281 delta += 2;
9282 addr = disAMode ( &alen, sorb, delta, dis_buf );
9283 delta += alen;
9284 storeLE( mkexpr(addr),
9285 getXMMRegLane64( gregOfRM(insn[2]),
9286 0/*lower lane*/ ) );
9287 DIP("movlps %s, %s\n", nameXMMReg( gregOfRM(insn[2]) ),
9288 dis_buf);
9289 goto decode_success;
9290 }
9291 /* else fall through */
9292 }
9293
9294 /* 0F 50 = MOVMSKPS - move 4 sign bits from 4 x F32 in xmm(E)
9295 to 4 lowest bits of ireg(G) */
9296 if (insn[0] == 0x0F && insn[1] == 0x50) {
9297 modrm = getIByte(delta+2);
9298 if (sz == 4 && epartIsReg(modrm)) {
9299 Int src;
9300 t0 = newTemp(Ity_I32);
9301 t1 = newTemp(Ity_I32);
9302 t2 = newTemp(Ity_I32);
9303 t3 = newTemp(Ity_I32);
9304 delta += 2+1;
9305 src = eregOfRM(modrm);
9306 assign( t0, binop( Iop_And32,
9307 binop(Iop_Shr32, getXMMRegLane32(src,0), mkU8(31)),
9308 mkU32(1) ));
9309 assign( t1, binop( Iop_And32,
9310 binop(Iop_Shr32, getXMMRegLane32(src,1), mkU8(30)),
9311 mkU32(2) ));
9312 assign( t2, binop( Iop_And32,
9313 binop(Iop_Shr32, getXMMRegLane32(src,2), mkU8(29)),
9314 mkU32(4) ));
9315 assign( t3, binop( Iop_And32,
9316 binop(Iop_Shr32, getXMMRegLane32(src,3), mkU8(28)),
9317 mkU32(8) ));
9318 putIReg(4, gregOfRM(modrm),
9319 binop(Iop_Or32,
9320 binop(Iop_Or32, mkexpr(t0), mkexpr(t1)),
9321 binop(Iop_Or32, mkexpr(t2), mkexpr(t3))
9322 )
9323 );
9324 DIP("movmskps %s,%s\n", nameXMMReg(src),
9325 nameIReg(4, gregOfRM(modrm)));
9326 goto decode_success;
9327 }
9328 /* else fall through */
9329 }
9330
9331 /* 0F 2B = MOVNTPS -- for us, just a plain SSE store. */
9332 /* 66 0F 2B = MOVNTPD -- for us, just a plain SSE store. */
9333 if (insn[0] == 0x0F && insn[1] == 0x2B) {
9334 modrm = getIByte(delta+2);
9335 if (!epartIsReg(modrm)) {
9336 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9337 gen_SEGV_if_not_16_aligned( addr );
9338 storeLE( mkexpr(addr), getXMMReg(gregOfRM(modrm)) );
9339 DIP("movntp%s %s,%s\n", sz==2 ? "d" : "s",
9340 dis_buf,
9341 nameXMMReg(gregOfRM(modrm)));
9342 delta += 2+alen;
9343 goto decode_success;
9344 }
9345 /* else fall through */
9346 }
9347
9348 /* F3 0F 10 = MOVSS -- move 32 bits from E (mem or lo 1/4 xmm) to G
9349 (lo 1/4 xmm). If E is mem, upper 3/4 of G is zeroed out. */
9350 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x10) {
9351 vassert(sz == 4);
9352 modrm = getIByte(delta+3);
9353 if (epartIsReg(modrm)) {
9354 putXMMRegLane32( gregOfRM(modrm), 0,
9355 getXMMRegLane32( eregOfRM(modrm), 0 ));
9356 DIP("movss %s,%s\n", nameXMMReg(eregOfRM(modrm)),
9357 nameXMMReg(gregOfRM(modrm)));
9358 delta += 3+1;
9359 } else {
9360 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
9361 /* zero bits 127:64 */
9362 putXMMRegLane64( gregOfRM(modrm), 1, mkU64(0) );
9363 /* zero bits 63:32 */
9364 putXMMRegLane32( gregOfRM(modrm), 1, mkU32(0) );
9365 /* write bits 31:0 */
9366 putXMMRegLane32( gregOfRM(modrm), 0,
9367 loadLE(Ity_I32, mkexpr(addr)) );
9368 DIP("movss %s,%s\n", dis_buf,
9369 nameXMMReg(gregOfRM(modrm)));
9370 delta += 3+alen;
9371 }
9372 goto decode_success;
9373 }
9374
9375 /* F3 0F 11 = MOVSS -- move 32 bits from G (lo 1/4 xmm) to E (mem
9376 or lo 1/4 xmm). */
9377 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x11) {
9378 vassert(sz == 4);
9379 modrm = getIByte(delta+3);
9380 if (epartIsReg(modrm)) {
9381 /* fall through, we don't yet have a test case */
9382 } else {
9383 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
9384 storeLE( mkexpr(addr),
9385 getXMMRegLane32(gregOfRM(modrm), 0) );
9386 DIP("movss %s,%s\n", nameXMMReg(gregOfRM(modrm)),
9387 dis_buf);
9388 delta += 3+alen;
9389 goto decode_success;
9390 }
9391 }
9392
9393 /* 0F 59 = MULPS -- mul 32Fx4 from R/M to R */
9394 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x59) {
9395 delta = dis_SSE_E_to_G_all( sorb, delta+2, "mulps", Iop_Mul32Fx4 );
9396 goto decode_success;
9397 }
9398
9399 /* F3 0F 59 = MULSS -- mul 32F0x4 from R/M to R */
9400 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x59) {
9401 vassert(sz == 4);
9402 delta = dis_SSE_E_to_G_lo32( sorb, delta+3, "mulss", Iop_Mul32F0x4 );
9403 goto decode_success;
9404 }
9405
9406 /* 0F 56 = ORPS -- G = G and E */
9407 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x56) {
9408 delta = dis_SSE_E_to_G_all( sorb, delta+2, "orps", Iop_OrV128 );
9409 goto decode_success;
9410 }
9411
sewardj0bd7ce62004-12-05 02:47:40 +00009412 /* 0F 53 = RCPPS -- approx reciprocal 32Fx4 from R/M to R */
9413 if (insn[0] == 0x0F && insn[1] == 0x53) {
9414 vassert(sz == 4);
sewardj129b3d92004-12-05 15:42:05 +00009415 delta = dis_SSE_E_to_G_unary_all( sorb, delta+2,
sewardj1ddee212014-08-24 14:00:19 +00009416 "rcpps", Iop_RecipEst32Fx4 );
sewardj0bd7ce62004-12-05 02:47:40 +00009417 goto decode_success;
9418 }
9419
9420 /* F3 0F 53 = RCPSS -- approx reciprocal 32F0x4 from R/M to R */
9421 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x53) {
9422 vassert(sz == 4);
sewardj129b3d92004-12-05 15:42:05 +00009423 delta = dis_SSE_E_to_G_unary_lo32( sorb, delta+3,
sewardj1ddee212014-08-24 14:00:19 +00009424 "rcpss", Iop_RecipEst32F0x4 );
sewardj0bd7ce62004-12-05 02:47:40 +00009425 goto decode_success;
9426 }
sewardjb5452082004-12-04 20:33:02 +00009427
sewardjc1e7dfc2004-12-05 19:29:45 +00009428 /* 0F 52 = RSQRTPS -- approx reciprocal sqrt 32Fx4 from R/M to R */
9429 if (insn[0] == 0x0F && insn[1] == 0x52) {
9430 vassert(sz == 4);
9431 delta = dis_SSE_E_to_G_unary_all( sorb, delta+2,
sewardj1ddee212014-08-24 14:00:19 +00009432 "rsqrtps", Iop_RSqrtEst32Fx4 );
sewardjc1e7dfc2004-12-05 19:29:45 +00009433 goto decode_success;
9434 }
9435
9436 /* F3 0F 52 = RSQRTSS -- approx reciprocal sqrt 32F0x4 from R/M to R */
9437 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x52) {
9438 vassert(sz == 4);
9439 delta = dis_SSE_E_to_G_unary_lo32( sorb, delta+3,
sewardj1ddee212014-08-24 14:00:19 +00009440 "rsqrtss", Iop_RSqrtEst32F0x4 );
sewardjc1e7dfc2004-12-05 19:29:45 +00009441 goto decode_success;
9442 }
9443
sewardjc1e7dfc2004-12-05 19:29:45 +00009444 /* 0F C6 /r ib = SHUFPS -- shuffle packed F32s */
sewardj008754b2004-12-08 14:37:10 +00009445 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xC6) {
sewardjc1e7dfc2004-12-05 19:29:45 +00009446 Int select;
9447 IRTemp sV, dV;
9448 IRTemp s3, s2, s1, s0, d3, d2, d1, d0;
9449 sV = newTemp(Ity_V128);
9450 dV = newTemp(Ity_V128);
9451 s3 = s2 = s1 = s0 = d3 = d2 = d1 = d0 = IRTemp_INVALID;
sewardjc1e7dfc2004-12-05 19:29:45 +00009452 modrm = insn[2];
9453 assign( dV, getXMMReg(gregOfRM(modrm)) );
9454
9455 if (epartIsReg(modrm)) {
9456 assign( sV, getXMMReg(eregOfRM(modrm)) );
9457 select = (Int)insn[3];
9458 delta += 2+2;
9459 DIP("shufps $%d,%s,%s\n", select,
9460 nameXMMReg(eregOfRM(modrm)),
9461 nameXMMReg(gregOfRM(modrm)));
9462 } else {
9463 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9464 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
9465 select = (Int)insn[2+alen];
9466 delta += 3+alen;
9467 DIP("shufps $%d,%s,%s\n", select,
9468 dis_buf,
9469 nameXMMReg(gregOfRM(modrm)));
9470 }
9471
9472 breakup128to32s( dV, &d3, &d2, &d1, &d0 );
9473 breakup128to32s( sV, &s3, &s2, &s1, &s0 );
9474
9475# define SELD(n) ((n)==0 ? d0 : ((n)==1 ? d1 : ((n)==2 ? d2 : d3)))
9476# define SELS(n) ((n)==0 ? s0 : ((n)==1 ? s1 : ((n)==2 ? s2 : s3)))
9477
9478 putXMMReg(
9479 gregOfRM(modrm),
9480 mk128from32s( SELS((select>>6)&3), SELS((select>>4)&3),
9481 SELD((select>>2)&3), SELD((select>>0)&3) )
9482 );
9483
9484# undef SELD
9485# undef SELS
9486
9487 goto decode_success;
9488 }
9489
9490 /* 0F 51 = SQRTPS -- approx sqrt 32Fx4 from R/M to R */
sewardj008754b2004-12-08 14:37:10 +00009491 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x51) {
sewardjc1e7dfc2004-12-05 19:29:45 +00009492 delta = dis_SSE_E_to_G_unary_all( sorb, delta+2,
9493 "sqrtps", Iop_Sqrt32Fx4 );
9494 goto decode_success;
9495 }
9496
9497 /* F3 0F 51 = SQRTSS -- approx sqrt 32F0x4 from R/M to R */
9498 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x51) {
9499 vassert(sz == 4);
9500 delta = dis_SSE_E_to_G_unary_lo32( sorb, delta+3,
9501 "sqrtss", Iop_Sqrt32F0x4 );
9502 goto decode_success;
9503 }
9504
sewardja0e83b02005-01-06 12:36:38 +00009505 /* 0F AE /3 = STMXCSR m32 -- store %mxcsr */
sewardj7df596b2004-12-06 14:29:12 +00009506 if (insn[0] == 0x0F && insn[1] == 0xAE
9507 && !epartIsReg(insn[2]) && gregOfRM(insn[2]) == 3) {
9508 modrm = getIByte(delta+2);
9509 vassert(sz == 4);
9510 vassert(!epartIsReg(modrm));
9511
9512 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9513 delta += 2+alen;
9514
9515 /* Fake up a native SSE mxcsr word. The only thing it depends
9516 on is SSEROUND[1:0], so call a clean helper to cook it up.
9517 */
9518 /* UInt x86h_create_mxcsr ( UInt sseround ) */
sewardj33dd31b2005-01-08 18:17:32 +00009519 DIP("stmxcsr %s\n", dis_buf);
sewardj7df596b2004-12-06 14:29:12 +00009520 storeLE( mkexpr(addr),
9521 mkIRExprCCall(
9522 Ity_I32, 0/*regp*/,
sewardj3bd6f3e2004-12-13 10:48:19 +00009523 "x86g_create_mxcsr", &x86g_create_mxcsr,
sewardja0e83b02005-01-06 12:36:38 +00009524 mkIRExprVec_1( get_sse_roundingmode() )
sewardj7df596b2004-12-06 14:29:12 +00009525 )
9526 );
9527 goto decode_success;
9528 }
9529
sewardjc1e7dfc2004-12-05 19:29:45 +00009530 /* 0F 5C = SUBPS -- sub 32Fx4 from R/M to R */
sewardj008754b2004-12-08 14:37:10 +00009531 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x5C) {
sewardjc1e7dfc2004-12-05 19:29:45 +00009532 delta = dis_SSE_E_to_G_all( sorb, delta+2, "subps", Iop_Sub32Fx4 );
9533 goto decode_success;
9534 }
9535
sewardj008754b2004-12-08 14:37:10 +00009536 /* F3 0F 5C = SUBSS -- sub 32F0x4 from R/M to R */
sewardjc1e7dfc2004-12-05 19:29:45 +00009537 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x5C) {
9538 vassert(sz == 4);
9539 delta = dis_SSE_E_to_G_lo32( sorb, delta+3, "subss", Iop_Sub32F0x4 );
9540 goto decode_success;
9541 }
9542
9543 /* 0F 15 = UNPCKHPS -- unpack and interleave high part F32s */
9544 /* 0F 14 = UNPCKLPS -- unpack and interleave low part F32s */
9545 /* These just appear to be special cases of SHUFPS */
sewardj008754b2004-12-08 14:37:10 +00009546 if (sz == 4 && insn[0] == 0x0F && (insn[1] == 0x15 || insn[1] == 0x14)) {
sewardjc1e7dfc2004-12-05 19:29:45 +00009547 IRTemp sV, dV;
9548 IRTemp s3, s2, s1, s0, d3, d2, d1, d0;
sewardj2d49b432005-02-01 00:37:06 +00009549 Bool hi = toBool(insn[1] == 0x15);
sewardjc1e7dfc2004-12-05 19:29:45 +00009550 sV = newTemp(Ity_V128);
9551 dV = newTemp(Ity_V128);
9552 s3 = s2 = s1 = s0 = d3 = d2 = d1 = d0 = IRTemp_INVALID;
sewardjc1e7dfc2004-12-05 19:29:45 +00009553 modrm = insn[2];
9554 assign( dV, getXMMReg(gregOfRM(modrm)) );
9555
9556 if (epartIsReg(modrm)) {
9557 assign( sV, getXMMReg(eregOfRM(modrm)) );
9558 delta += 2+1;
9559 DIP("unpck%sps %s,%s\n", hi ? "h" : "l",
9560 nameXMMReg(eregOfRM(modrm)),
9561 nameXMMReg(gregOfRM(modrm)));
9562 } else {
9563 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9564 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
9565 delta += 2+alen;
9566 DIP("unpck%sps %s,%s\n", hi ? "h" : "l",
9567 dis_buf,
9568 nameXMMReg(gregOfRM(modrm)));
9569 }
9570
9571 breakup128to32s( dV, &d3, &d2, &d1, &d0 );
9572 breakup128to32s( sV, &s3, &s2, &s1, &s0 );
9573
9574 if (hi) {
9575 putXMMReg( gregOfRM(modrm), mk128from32s( s3, d3, s2, d2 ) );
9576 } else {
9577 putXMMReg( gregOfRM(modrm), mk128from32s( s1, d1, s0, d0 ) );
9578 }
9579
9580 goto decode_success;
9581 }
9582
9583 /* 0F 57 = XORPS -- G = G and E */
sewardj008754b2004-12-08 14:37:10 +00009584 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x57) {
sewardjf0c1c582005-02-07 23:47:38 +00009585 delta = dis_SSE_E_to_G_all( sorb, delta+2, "xorps", Iop_XorV128 );
sewardjc1e7dfc2004-12-05 19:29:45 +00009586 goto decode_success;
9587 }
9588
sewardj636ad762004-12-07 11:16:04 +00009589 /* ---------------------------------------------------- */
9590 /* --- end of the SSE decoder. --- */
9591 /* ---------------------------------------------------- */
9592
9593 /* ---------------------------------------------------- */
9594 /* --- start of the SSE2 decoder. --- */
9595 /* ---------------------------------------------------- */
9596
sewardj9df271d2004-12-31 22:37:42 +00009597 /* Skip parts of the decoder which don't apply given the stated
9598 guest subarchitecture. */
sewardj5117ce12006-01-27 21:20:15 +00009599 if (0 == (archinfo->hwcaps & VEX_HWCAPS_X86_SSE2))
9600 goto after_sse_decoders; /* no SSE2 capabilities */
sewardj9df271d2004-12-31 22:37:42 +00009601
florian8462d112014-09-24 15:18:09 +00009602 insn = &guest_code[delta];
sewardj636ad762004-12-07 11:16:04 +00009603
9604 /* 66 0F 58 = ADDPD -- add 32Fx4 from R/M to R */
9605 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x58) {
9606 delta = dis_SSE_E_to_G_all( sorb, delta+2, "addpd", Iop_Add64Fx2 );
9607 goto decode_success;
9608 }
9609
9610 /* F2 0F 58 = ADDSD -- add 64F0x2 from R/M to R */
9611 if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x58) {
9612 vassert(sz == 4);
9613 delta = dis_SSE_E_to_G_lo64( sorb, delta+3, "addsd", Iop_Add64F0x2 );
9614 goto decode_success;
9615 }
9616
9617 /* 66 0F 55 = ANDNPD -- G = (not G) and E */
9618 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x55) {
sewardjf0c1c582005-02-07 23:47:38 +00009619 delta = dis_SSE_E_to_G_all_invG( sorb, delta+2, "andnpd", Iop_AndV128 );
sewardj636ad762004-12-07 11:16:04 +00009620 goto decode_success;
9621 }
9622
9623 /* 66 0F 54 = ANDPD -- G = G and E */
9624 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x54) {
sewardjf0c1c582005-02-07 23:47:38 +00009625 delta = dis_SSE_E_to_G_all( sorb, delta+2, "andpd", Iop_AndV128 );
sewardj636ad762004-12-07 11:16:04 +00009626 goto decode_success;
9627 }
9628
sewardjfd226452004-12-07 19:02:18 +00009629 /* 66 0F C2 = CMPPD -- 64Fx2 comparison from R/M to R */
9630 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xC2) {
9631 delta = dis_SSEcmp_E_to_G( sorb, delta+2, "cmppd", True, 8 );
9632 goto decode_success;
9633 }
9634
9635 /* F2 0F C2 = CMPSD -- 64F0x2 comparison from R/M to R */
9636 if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0xC2) {
9637 vassert(sz == 4);
9638 delta = dis_SSEcmp_E_to_G( sorb, delta+3, "cmpsd", False, 8 );
9639 goto decode_success;
9640 }
9641
9642 /* 66 0F 2F = COMISD -- 64F0x2 comparison G,E, and set ZCP */
9643 /* 66 0F 2E = UCOMISD -- 64F0x2 comparison G,E, and set ZCP */
9644 if (sz == 2 && insn[0] == 0x0F && (insn[1] == 0x2F || insn[1] == 0x2E)) {
9645 IRTemp argL = newTemp(Ity_F64);
9646 IRTemp argR = newTemp(Ity_F64);
9647 modrm = getIByte(delta+2);
9648 if (epartIsReg(modrm)) {
9649 assign( argR, getXMMRegLane64F( eregOfRM(modrm), 0/*lowest lane*/ ) );
9650 delta += 2+1;
9651 DIP("[u]comisd %s,%s\n", nameXMMReg(eregOfRM(modrm)),
9652 nameXMMReg(gregOfRM(modrm)) );
9653 } else {
9654 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9655 assign( argR, loadLE(Ity_F64, mkexpr(addr)) );
9656 delta += 2+alen;
9657 DIP("[u]comisd %s,%s\n", dis_buf,
9658 nameXMMReg(gregOfRM(modrm)) );
9659 }
9660 assign( argL, getXMMRegLane64F( gregOfRM(modrm), 0/*lowest lane*/ ) );
9661
9662 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(X86G_CC_OP_COPY) ));
9663 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
9664 stmt( IRStmt_Put(
9665 OFFB_CC_DEP1,
9666 binop( Iop_And32,
9667 binop(Iop_CmpF64, mkexpr(argL), mkexpr(argR)),
9668 mkU32(0x45)
9669 )));
sewardja3b7e3a2005-04-05 01:54:19 +00009670 /* Set NDEP even though it isn't used. This makes redundant-PUT
9671 elimination of previous stores to this field work better. */
9672 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
sewardjfd226452004-12-07 19:02:18 +00009673 goto decode_success;
9674 }
9675
9676 /* F3 0F E6 = CVTDQ2PD -- convert 2 x I32 in mem/lo half xmm to 2 x
9677 F64 in xmm(G) */
9678 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0xE6) {
9679 IRTemp arg64 = newTemp(Ity_I64);
9680 vassert(sz == 4);
9681
9682 modrm = getIByte(delta+3);
9683 if (epartIsReg(modrm)) {
9684 assign( arg64, getXMMRegLane64(eregOfRM(modrm), 0) );
9685 delta += 3+1;
9686 DIP("cvtdq2pd %s,%s\n", nameXMMReg(eregOfRM(modrm)),
9687 nameXMMReg(gregOfRM(modrm)));
9688 } else {
9689 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
9690 assign( arg64, loadLE(Ity_I64, mkexpr(addr)) );
9691 delta += 3+alen;
9692 DIP("cvtdq2pd %s,%s\n", dis_buf,
9693 nameXMMReg(gregOfRM(modrm)) );
9694 }
9695
9696 putXMMRegLane64F(
9697 gregOfRM(modrm), 0,
sewardj6c299f32009-12-31 18:00:12 +00009698 unop(Iop_I32StoF64, unop(Iop_64to32, mkexpr(arg64)))
sewardjfd226452004-12-07 19:02:18 +00009699 );
9700
9701 putXMMRegLane64F(
9702 gregOfRM(modrm), 1,
sewardj6c299f32009-12-31 18:00:12 +00009703 unop(Iop_I32StoF64, unop(Iop_64HIto32, mkexpr(arg64)))
sewardjfd226452004-12-07 19:02:18 +00009704 );
9705
9706 goto decode_success;
9707 }
9708
9709 /* 0F 5B = CVTDQ2PS -- convert 4 x I32 in mem/xmm to 4 x F32 in
9710 xmm(G) */
9711 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x5B) {
9712 IRTemp argV = newTemp(Ity_V128);
9713 IRTemp rmode = newTemp(Ity_I32);
9714
9715 modrm = getIByte(delta+2);
9716 if (epartIsReg(modrm)) {
9717 assign( argV, getXMMReg(eregOfRM(modrm)) );
9718 delta += 2+1;
9719 DIP("cvtdq2ps %s,%s\n", nameXMMReg(eregOfRM(modrm)),
9720 nameXMMReg(gregOfRM(modrm)));
9721 } else {
9722 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9723 assign( argV, loadLE(Ity_V128, mkexpr(addr)) );
9724 delta += 2+alen;
9725 DIP("cvtdq2ps %s,%s\n", dis_buf,
9726 nameXMMReg(gregOfRM(modrm)) );
9727 }
9728
9729 assign( rmode, get_sse_roundingmode() );
9730 breakup128to32s( argV, &t3, &t2, &t1, &t0 );
9731
9732# define CVT(_t) binop( Iop_F64toF32, \
9733 mkexpr(rmode), \
sewardj6c299f32009-12-31 18:00:12 +00009734 unop(Iop_I32StoF64,mkexpr(_t)))
sewardjfd226452004-12-07 19:02:18 +00009735
9736 putXMMRegLane32F( gregOfRM(modrm), 3, CVT(t3) );
9737 putXMMRegLane32F( gregOfRM(modrm), 2, CVT(t2) );
9738 putXMMRegLane32F( gregOfRM(modrm), 1, CVT(t1) );
9739 putXMMRegLane32F( gregOfRM(modrm), 0, CVT(t0) );
9740
9741# undef CVT
9742
9743 goto decode_success;
9744 }
9745
9746 /* F2 0F E6 = CVTPD2DQ -- convert 2 x F64 in mem/xmm to 2 x I32 in
9747 lo half xmm(G), and zero upper half */
9748 if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0xE6) {
9749 IRTemp argV = newTemp(Ity_V128);
9750 IRTemp rmode = newTemp(Ity_I32);
9751 vassert(sz == 4);
9752
9753 modrm = getIByte(delta+3);
9754 if (epartIsReg(modrm)) {
9755 assign( argV, getXMMReg(eregOfRM(modrm)) );
9756 delta += 3+1;
9757 DIP("cvtpd2dq %s,%s\n", nameXMMReg(eregOfRM(modrm)),
9758 nameXMMReg(gregOfRM(modrm)));
9759 } else {
9760 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
9761 assign( argV, loadLE(Ity_V128, mkexpr(addr)) );
9762 delta += 3+alen;
9763 DIP("cvtpd2dq %s,%s\n", dis_buf,
9764 nameXMMReg(gregOfRM(modrm)) );
9765 }
9766
9767 assign( rmode, get_sse_roundingmode() );
9768 t0 = newTemp(Ity_F64);
9769 t1 = newTemp(Ity_F64);
9770 assign( t0, unop(Iop_ReinterpI64asF64,
sewardjf0c1c582005-02-07 23:47:38 +00009771 unop(Iop_V128to64, mkexpr(argV))) );
sewardjfd226452004-12-07 19:02:18 +00009772 assign( t1, unop(Iop_ReinterpI64asF64,
sewardjf0c1c582005-02-07 23:47:38 +00009773 unop(Iop_V128HIto64, mkexpr(argV))) );
sewardjfd226452004-12-07 19:02:18 +00009774
sewardj6c299f32009-12-31 18:00:12 +00009775# define CVT(_t) binop( Iop_F64toI32S, \
sewardjfd226452004-12-07 19:02:18 +00009776 mkexpr(rmode), \
9777 mkexpr(_t) )
9778
9779 putXMMRegLane32( gregOfRM(modrm), 3, mkU32(0) );
9780 putXMMRegLane32( gregOfRM(modrm), 2, mkU32(0) );
9781 putXMMRegLane32( gregOfRM(modrm), 1, CVT(t1) );
9782 putXMMRegLane32( gregOfRM(modrm), 0, CVT(t0) );
9783
9784# undef CVT
9785
9786 goto decode_success;
9787 }
9788
9789 /* 66 0F 2D = CVTPD2PI -- convert 2 x F64 in mem/xmm to 2 x
9790 I32 in mmx, according to prevailing SSE rounding mode */
9791 /* 66 0F 2C = CVTTPD2PI -- convert 2 x F64 in mem/xmm to 2 x
9792 I32 in mmx, rounding towards zero */
9793 if (sz == 2 && insn[0] == 0x0F && (insn[1] == 0x2D || insn[1] == 0x2C)) {
9794 IRTemp dst64 = newTemp(Ity_I64);
9795 IRTemp rmode = newTemp(Ity_I32);
9796 IRTemp f64lo = newTemp(Ity_F64);
9797 IRTemp f64hi = newTemp(Ity_F64);
sewardj2d49b432005-02-01 00:37:06 +00009798 Bool r2zero = toBool(insn[1] == 0x2C);
sewardjfd226452004-12-07 19:02:18 +00009799
9800 do_MMX_preamble();
9801 modrm = getIByte(delta+2);
9802
9803 if (epartIsReg(modrm)) {
9804 delta += 2+1;
9805 assign(f64lo, getXMMRegLane64F(eregOfRM(modrm), 0));
9806 assign(f64hi, getXMMRegLane64F(eregOfRM(modrm), 1));
9807 DIP("cvt%spd2pi %s,%s\n", r2zero ? "t" : "",
9808 nameXMMReg(eregOfRM(modrm)),
9809 nameMMXReg(gregOfRM(modrm)));
9810 } else {
9811 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9812 assign(f64lo, loadLE(Ity_F64, mkexpr(addr)));
9813 assign(f64hi, loadLE(Ity_F64, binop( Iop_Add32,
9814 mkexpr(addr),
9815 mkU32(8) )));
9816 delta += 2+alen;
9817 DIP("cvt%spf2pi %s,%s\n", r2zero ? "t" : "",
9818 dis_buf,
9819 nameMMXReg(gregOfRM(modrm)));
9820 }
9821
9822 if (r2zero) {
9823 assign(rmode, mkU32((UInt)Irrm_ZERO) );
9824 } else {
9825 assign( rmode, get_sse_roundingmode() );
9826 }
9827
9828 assign(
9829 dst64,
9830 binop( Iop_32HLto64,
sewardj6c299f32009-12-31 18:00:12 +00009831 binop( Iop_F64toI32S, mkexpr(rmode), mkexpr(f64hi) ),
9832 binop( Iop_F64toI32S, mkexpr(rmode), mkexpr(f64lo) )
sewardjfd226452004-12-07 19:02:18 +00009833 )
9834 );
9835
9836 putMMXReg(gregOfRM(modrm), mkexpr(dst64));
9837 goto decode_success;
9838 }
9839
9840 /* 66 0F 5A = CVTPD2PS -- convert 2 x F64 in mem/xmm to 2 x F32 in
9841 lo half xmm(G), and zero upper half */
9842 /* Note, this is practically identical to CVTPD2DQ. It would have
9843 been nicer to merge them together, but the insn[] offsets differ
9844 by one. */
9845 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x5A) {
9846 IRTemp argV = newTemp(Ity_V128);
9847 IRTemp rmode = newTemp(Ity_I32);
9848
9849 modrm = getIByte(delta+2);
9850 if (epartIsReg(modrm)) {
9851 assign( argV, getXMMReg(eregOfRM(modrm)) );
9852 delta += 2+1;
9853 DIP("cvtpd2ps %s,%s\n", nameXMMReg(eregOfRM(modrm)),
9854 nameXMMReg(gregOfRM(modrm)));
9855 } else {
9856 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9857 assign( argV, loadLE(Ity_V128, mkexpr(addr)) );
9858 delta += 2+alen;
9859 DIP("cvtpd2ps %s,%s\n", dis_buf,
9860 nameXMMReg(gregOfRM(modrm)) );
9861 }
9862
9863 assign( rmode, get_sse_roundingmode() );
9864 t0 = newTemp(Ity_F64);
9865 t1 = newTemp(Ity_F64);
9866 assign( t0, unop(Iop_ReinterpI64asF64,
sewardjf0c1c582005-02-07 23:47:38 +00009867 unop(Iop_V128to64, mkexpr(argV))) );
sewardjfd226452004-12-07 19:02:18 +00009868 assign( t1, unop(Iop_ReinterpI64asF64,
sewardjf0c1c582005-02-07 23:47:38 +00009869 unop(Iop_V128HIto64, mkexpr(argV))) );
sewardjfd226452004-12-07 19:02:18 +00009870
9871# define CVT(_t) binop( Iop_F64toF32, \
9872 mkexpr(rmode), \
9873 mkexpr(_t) )
9874
9875 putXMMRegLane32( gregOfRM(modrm), 3, mkU32(0) );
9876 putXMMRegLane32( gregOfRM(modrm), 2, mkU32(0) );
9877 putXMMRegLane32F( gregOfRM(modrm), 1, CVT(t1) );
9878 putXMMRegLane32F( gregOfRM(modrm), 0, CVT(t0) );
9879
9880# undef CVT
9881
9882 goto decode_success;
9883 }
9884
9885 /* 66 0F 2A = CVTPI2PD -- convert 2 x I32 in mem/mmx to 2 x F64 in
9886 xmm(G) */
9887 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x2A) {
9888 IRTemp arg64 = newTemp(Ity_I64);
9889
9890 modrm = getIByte(delta+2);
sewardjfd226452004-12-07 19:02:18 +00009891 if (epartIsReg(modrm)) {
sewardj30a20e92010-02-21 20:40:53 +00009892 /* Only switch to MMX mode if the source is a MMX register.
9893 This is inconsistent with all other instructions which
9894 convert between XMM and (M64 or MMX), which always switch
9895 to MMX mode even if 64-bit operand is M64 and not MMX. At
9896 least, that's what the Intel docs seem to me to say.
9897 Fixes #210264. */
9898 do_MMX_preamble();
sewardjfd226452004-12-07 19:02:18 +00009899 assign( arg64, getMMXReg(eregOfRM(modrm)) );
9900 delta += 2+1;
9901 DIP("cvtpi2pd %s,%s\n", nameMMXReg(eregOfRM(modrm)),
9902 nameXMMReg(gregOfRM(modrm)));
9903 } else {
9904 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9905 assign( arg64, loadLE(Ity_I64, mkexpr(addr)) );
9906 delta += 2+alen;
9907 DIP("cvtpi2pd %s,%s\n", dis_buf,
9908 nameXMMReg(gregOfRM(modrm)) );
9909 }
9910
9911 putXMMRegLane64F(
9912 gregOfRM(modrm), 0,
sewardj6c299f32009-12-31 18:00:12 +00009913 unop(Iop_I32StoF64, unop(Iop_64to32, mkexpr(arg64)) )
sewardjfd226452004-12-07 19:02:18 +00009914 );
9915
9916 putXMMRegLane64F(
9917 gregOfRM(modrm), 1,
sewardj6c299f32009-12-31 18:00:12 +00009918 unop(Iop_I32StoF64, unop(Iop_64HIto32, mkexpr(arg64)) )
sewardjfd226452004-12-07 19:02:18 +00009919 );
9920
9921 goto decode_success;
9922 }
9923
9924 /* 66 0F 5B = CVTPS2DQ -- convert 4 x F32 in mem/xmm to 4 x I32 in
9925 xmm(G) */
9926 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x5B) {
9927 IRTemp argV = newTemp(Ity_V128);
9928 IRTemp rmode = newTemp(Ity_I32);
9929
9930 modrm = getIByte(delta+2);
9931 if (epartIsReg(modrm)) {
9932 assign( argV, getXMMReg(eregOfRM(modrm)) );
9933 delta += 2+1;
9934 DIP("cvtps2dq %s,%s\n", nameXMMReg(eregOfRM(modrm)),
9935 nameXMMReg(gregOfRM(modrm)));
9936 } else {
9937 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9938 assign( argV, loadLE(Ity_V128, mkexpr(addr)) );
9939 delta += 2+alen;
9940 DIP("cvtps2dq %s,%s\n", dis_buf,
9941 nameXMMReg(gregOfRM(modrm)) );
9942 }
9943
9944 assign( rmode, get_sse_roundingmode() );
9945 breakup128to32s( argV, &t3, &t2, &t1, &t0 );
9946
9947 /* This is less than ideal. If it turns out to be a performance
9948 bottleneck it can be improved. */
9949# define CVT(_t) \
sewardj6c299f32009-12-31 18:00:12 +00009950 binop( Iop_F64toI32S, \
sewardjfd226452004-12-07 19:02:18 +00009951 mkexpr(rmode), \
9952 unop( Iop_F32toF64, \
9953 unop( Iop_ReinterpI32asF32, mkexpr(_t))) )
9954
9955 putXMMRegLane32( gregOfRM(modrm), 3, CVT(t3) );
9956 putXMMRegLane32( gregOfRM(modrm), 2, CVT(t2) );
9957 putXMMRegLane32( gregOfRM(modrm), 1, CVT(t1) );
9958 putXMMRegLane32( gregOfRM(modrm), 0, CVT(t0) );
9959
9960# undef CVT
9961
9962 goto decode_success;
9963 }
9964
9965 /* 0F 5A = CVTPS2PD -- convert 2 x F32 in low half mem/xmm to 2 x
9966 F64 in xmm(G). */
9967 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x5A) {
9968 IRTemp f32lo = newTemp(Ity_F32);
9969 IRTemp f32hi = newTemp(Ity_F32);
9970
9971 modrm = getIByte(delta+2);
9972 if (epartIsReg(modrm)) {
9973 assign( f32lo, getXMMRegLane32F(eregOfRM(modrm), 0) );
9974 assign( f32hi, getXMMRegLane32F(eregOfRM(modrm), 1) );
9975 delta += 2+1;
9976 DIP("cvtps2pd %s,%s\n", nameXMMReg(eregOfRM(modrm)),
9977 nameXMMReg(gregOfRM(modrm)));
9978 } else {
9979 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9980 assign( f32lo, loadLE(Ity_F32, mkexpr(addr)) );
9981 assign( f32hi, loadLE(Ity_F32,
9982 binop(Iop_Add32,mkexpr(addr),mkU32(4))) );
9983 delta += 2+alen;
9984 DIP("cvtps2pd %s,%s\n", dis_buf,
9985 nameXMMReg(gregOfRM(modrm)) );
9986 }
9987
9988 putXMMRegLane64F( gregOfRM(modrm), 1,
9989 unop(Iop_F32toF64, mkexpr(f32hi)) );
9990 putXMMRegLane64F( gregOfRM(modrm), 0,
9991 unop(Iop_F32toF64, mkexpr(f32lo)) );
9992
9993 goto decode_success;
9994 }
9995
9996 /* F2 0F 2D = CVTSD2SI -- convert F64 in mem/low half xmm to
9997 I32 in ireg, according to prevailing SSE rounding mode */
9998 /* F2 0F 2C = CVTTSD2SI -- convert F64 in mem/low half xmm to
sewardj0b210442005-02-23 13:28:27 +00009999 I32 in ireg, rounding towards zero */
sewardjfd226452004-12-07 19:02:18 +000010000 if (insn[0] == 0xF2 && insn[1] == 0x0F
10001 && (insn[2] == 0x2D || insn[2] == 0x2C)) {
10002 IRTemp rmode = newTemp(Ity_I32);
10003 IRTemp f64lo = newTemp(Ity_F64);
sewardj2d49b432005-02-01 00:37:06 +000010004 Bool r2zero = toBool(insn[2] == 0x2C);
sewardjfd226452004-12-07 19:02:18 +000010005 vassert(sz == 4);
10006
10007 modrm = getIByte(delta+3);
10008 if (epartIsReg(modrm)) {
10009 delta += 3+1;
10010 assign(f64lo, getXMMRegLane64F(eregOfRM(modrm), 0));
10011 DIP("cvt%ssd2si %s,%s\n", r2zero ? "t" : "",
10012 nameXMMReg(eregOfRM(modrm)),
10013 nameIReg(4, gregOfRM(modrm)));
10014 } else {
10015 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
10016 assign(f64lo, loadLE(Ity_F64, mkexpr(addr)));
10017 delta += 3+alen;
10018 DIP("cvt%ssd2si %s,%s\n", r2zero ? "t" : "",
10019 dis_buf,
10020 nameIReg(4, gregOfRM(modrm)));
10021 }
10022
10023 if (r2zero) {
10024 assign( rmode, mkU32((UInt)Irrm_ZERO) );
10025 } else {
10026 assign( rmode, get_sse_roundingmode() );
10027 }
10028
10029 putIReg(4, gregOfRM(modrm),
sewardj6c299f32009-12-31 18:00:12 +000010030 binop( Iop_F64toI32S, mkexpr(rmode), mkexpr(f64lo)) );
sewardjfd226452004-12-07 19:02:18 +000010031
10032 goto decode_success;
10033 }
10034
10035 /* F2 0F 5A = CVTSD2SS -- convert F64 in mem/low half xmm to F32 in
10036 low 1/4 xmm(G), according to prevailing SSE rounding mode */
10037 if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x5A) {
10038 IRTemp rmode = newTemp(Ity_I32);
10039 IRTemp f64lo = newTemp(Ity_F64);
10040 vassert(sz == 4);
10041
10042 modrm = getIByte(delta+3);
10043 if (epartIsReg(modrm)) {
10044 delta += 3+1;
10045 assign(f64lo, getXMMRegLane64F(eregOfRM(modrm), 0));
10046 DIP("cvtsd2ss %s,%s\n", nameXMMReg(eregOfRM(modrm)),
10047 nameXMMReg(gregOfRM(modrm)));
10048 } else {
10049 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
10050 assign(f64lo, loadLE(Ity_F64, mkexpr(addr)));
10051 delta += 3+alen;
10052 DIP("cvtsd2ss %s,%s\n", dis_buf,
10053 nameXMMReg(gregOfRM(modrm)));
10054 }
10055
10056 assign( rmode, get_sse_roundingmode() );
10057 putXMMRegLane32F(
10058 gregOfRM(modrm), 0,
10059 binop( Iop_F64toF32, mkexpr(rmode), mkexpr(f64lo) )
10060 );
10061
10062 goto decode_success;
10063 }
10064
10065 /* F2 0F 2A = CVTSI2SD -- convert I32 in mem/ireg to F64 in low
10066 half xmm */
10067 if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x2A) {
10068 IRTemp arg32 = newTemp(Ity_I32);
10069 vassert(sz == 4);
10070
10071 modrm = getIByte(delta+3);
sewardjfd226452004-12-07 19:02:18 +000010072 if (epartIsReg(modrm)) {
10073 assign( arg32, getIReg(4, eregOfRM(modrm)) );
10074 delta += 3+1;
10075 DIP("cvtsi2sd %s,%s\n", nameIReg(4, eregOfRM(modrm)),
10076 nameXMMReg(gregOfRM(modrm)));
10077 } else {
10078 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
10079 assign( arg32, loadLE(Ity_I32, mkexpr(addr)) );
10080 delta += 3+alen;
10081 DIP("cvtsi2sd %s,%s\n", dis_buf,
10082 nameXMMReg(gregOfRM(modrm)) );
10083 }
10084
10085 putXMMRegLane64F(
10086 gregOfRM(modrm), 0,
sewardj6c299f32009-12-31 18:00:12 +000010087 unop(Iop_I32StoF64, mkexpr(arg32)) );
sewardjfd226452004-12-07 19:02:18 +000010088
10089 goto decode_success;
10090 }
10091
10092 /* F3 0F 5A = CVTSS2SD -- convert F32 in mem/low 1/4 xmm to F64 in
10093 low half xmm(G) */
10094 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x5A) {
10095 IRTemp f32lo = newTemp(Ity_F32);
10096 vassert(sz == 4);
10097
10098 modrm = getIByte(delta+3);
10099 if (epartIsReg(modrm)) {
10100 delta += 3+1;
10101 assign(f32lo, getXMMRegLane32F(eregOfRM(modrm), 0));
10102 DIP("cvtss2sd %s,%s\n", nameXMMReg(eregOfRM(modrm)),
10103 nameXMMReg(gregOfRM(modrm)));
10104 } else {
10105 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
10106 assign(f32lo, loadLE(Ity_F32, mkexpr(addr)));
10107 delta += 3+alen;
10108 DIP("cvtss2sd %s,%s\n", dis_buf,
10109 nameXMMReg(gregOfRM(modrm)));
10110 }
10111
10112 putXMMRegLane64F( gregOfRM(modrm), 0,
10113 unop( Iop_F32toF64, mkexpr(f32lo) ) );
10114
10115 goto decode_success;
10116 }
10117
10118 /* 66 0F E6 = CVTTPD2DQ -- convert 2 x F64 in mem/xmm to 2 x I32 in
10119 lo half xmm(G), and zero upper half, rounding towards zero */
10120 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xE6) {
10121 IRTemp argV = newTemp(Ity_V128);
10122 IRTemp rmode = newTemp(Ity_I32);
10123
10124 modrm = getIByte(delta+2);
10125 if (epartIsReg(modrm)) {
10126 assign( argV, getXMMReg(eregOfRM(modrm)) );
10127 delta += 2+1;
10128 DIP("cvttpd2dq %s,%s\n", nameXMMReg(eregOfRM(modrm)),
10129 nameXMMReg(gregOfRM(modrm)));
10130 } else {
10131 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
10132 assign( argV, loadLE(Ity_V128, mkexpr(addr)) );
10133 delta += 2+alen;
10134 DIP("cvttpd2dq %s,%s\n", dis_buf,
10135 nameXMMReg(gregOfRM(modrm)) );
10136 }
10137
10138 assign( rmode, mkU32((UInt)Irrm_ZERO) );
10139
10140 t0 = newTemp(Ity_F64);
10141 t1 = newTemp(Ity_F64);
10142 assign( t0, unop(Iop_ReinterpI64asF64,
sewardjf0c1c582005-02-07 23:47:38 +000010143 unop(Iop_V128to64, mkexpr(argV))) );
sewardjfd226452004-12-07 19:02:18 +000010144 assign( t1, unop(Iop_ReinterpI64asF64,
sewardjf0c1c582005-02-07 23:47:38 +000010145 unop(Iop_V128HIto64, mkexpr(argV))) );
sewardjfd226452004-12-07 19:02:18 +000010146
sewardj6c299f32009-12-31 18:00:12 +000010147# define CVT(_t) binop( Iop_F64toI32S, \
sewardjfd226452004-12-07 19:02:18 +000010148 mkexpr(rmode), \
10149 mkexpr(_t) )
10150
10151 putXMMRegLane32( gregOfRM(modrm), 3, mkU32(0) );
10152 putXMMRegLane32( gregOfRM(modrm), 2, mkU32(0) );
10153 putXMMRegLane32( gregOfRM(modrm), 1, CVT(t1) );
10154 putXMMRegLane32( gregOfRM(modrm), 0, CVT(t0) );
10155
10156# undef CVT
10157
10158 goto decode_success;
10159 }
10160
10161 /* F3 0F 5B = CVTTPS2DQ -- convert 4 x F32 in mem/xmm to 4 x I32 in
10162 xmm(G), rounding towards zero */
10163 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x5B) {
10164 IRTemp argV = newTemp(Ity_V128);
10165 IRTemp rmode = newTemp(Ity_I32);
10166 vassert(sz == 4);
10167
10168 modrm = getIByte(delta+3);
10169 if (epartIsReg(modrm)) {
10170 assign( argV, getXMMReg(eregOfRM(modrm)) );
10171 delta += 3+1;
10172 DIP("cvttps2dq %s,%s\n", nameXMMReg(eregOfRM(modrm)),
10173 nameXMMReg(gregOfRM(modrm)));
10174 } else {
10175 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
10176 assign( argV, loadLE(Ity_V128, mkexpr(addr)) );
10177 delta += 3+alen;
10178 DIP("cvttps2dq %s,%s\n", dis_buf,
10179 nameXMMReg(gregOfRM(modrm)) );
10180 }
10181
10182 assign( rmode, mkU32((UInt)Irrm_ZERO) );
10183 breakup128to32s( argV, &t3, &t2, &t1, &t0 );
10184
10185 /* This is less than ideal. If it turns out to be a performance
10186 bottleneck it can be improved. */
10187# define CVT(_t) \
sewardj6c299f32009-12-31 18:00:12 +000010188 binop( Iop_F64toI32S, \
sewardjfd226452004-12-07 19:02:18 +000010189 mkexpr(rmode), \
10190 unop( Iop_F32toF64, \
10191 unop( Iop_ReinterpI32asF32, mkexpr(_t))) )
10192
10193 putXMMRegLane32( gregOfRM(modrm), 3, CVT(t3) );
10194 putXMMRegLane32( gregOfRM(modrm), 2, CVT(t2) );
10195 putXMMRegLane32( gregOfRM(modrm), 1, CVT(t1) );
10196 putXMMRegLane32( gregOfRM(modrm), 0, CVT(t0) );
10197
10198# undef CVT
10199
10200 goto decode_success;
10201 }
10202
10203 /* 66 0F 5E = DIVPD -- div 64Fx2 from R/M to R */
10204 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x5E) {
10205 delta = dis_SSE_E_to_G_all( sorb, delta+2, "divpd", Iop_Div64Fx2 );
10206 goto decode_success;
10207 }
10208
sewardjc2feffc2004-12-08 12:31:22 +000010209 /* F2 0F 5E = DIVSD -- div 64F0x2 from R/M to R */
10210 if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x5E) {
10211 vassert(sz == 4);
10212 delta = dis_SSE_E_to_G_lo64( sorb, delta+3, "divsd", Iop_Div64F0x2 );
10213 goto decode_success;
10214 }
10215
10216 /* 0F AE /5 = LFENCE -- flush pending operations to memory */
10217 /* 0F AE /6 = MFENCE -- flush pending operations to memory */
10218 if (insn[0] == 0x0F && insn[1] == 0xAE
10219 && epartIsReg(insn[2])
10220 && (gregOfRM(insn[2]) == 5 || gregOfRM(insn[2]) == 6)) {
10221 vassert(sz == 4);
10222 delta += 3;
sewardj3e838932005-01-07 12:09:15 +000010223 /* Insert a memory fence. It's sometimes important that these
10224 are carried through to the generated code. */
sewardjc4356f02007-11-09 21:15:04 +000010225 stmt( IRStmt_MBE(Imbe_Fence) );
sewardjc2feffc2004-12-08 12:31:22 +000010226 DIP("%sfence\n", gregOfRM(insn[2])==5 ? "l" : "m");
10227 goto decode_success;
10228 }
10229
10230 /* 66 0F 5F = MAXPD -- max 64Fx2 from R/M to R */
10231 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x5F) {
10232 delta = dis_SSE_E_to_G_all( sorb, delta+2, "maxpd", Iop_Max64Fx2 );
10233 goto decode_success;
10234 }
10235
10236 /* F2 0F 5F = MAXSD -- max 64F0x2 from R/M to R */
10237 if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x5F) {
10238 vassert(sz == 4);
10239 delta = dis_SSE_E_to_G_lo64( sorb, delta+3, "maxsd", Iop_Max64F0x2 );
10240 goto decode_success;
10241 }
10242
10243 /* 66 0F 5D = MINPD -- min 64Fx2 from R/M to R */
10244 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x5D) {
10245 delta = dis_SSE_E_to_G_all( sorb, delta+2, "minpd", Iop_Min64Fx2 );
10246 goto decode_success;
10247 }
10248
10249 /* F2 0F 5D = MINSD -- min 64F0x2 from R/M to R */
10250 if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x5D) {
10251 vassert(sz == 4);
10252 delta = dis_SSE_E_to_G_lo64( sorb, delta+3, "minsd", Iop_Min64F0x2 );
10253 goto decode_success;
10254 }
10255
10256 /* 66 0F 28 = MOVAPD -- move from E (mem or xmm) to G (xmm). */
10257 /* 66 0F 10 = MOVUPD -- move from E (mem or xmm) to G (xmm). */
10258 /* 66 0F 6F = MOVDQA -- move from E (mem or xmm) to G (xmm). */
10259 if (sz == 2 && insn[0] == 0x0F
10260 && (insn[1] == 0x28 || insn[1] == 0x10 || insn[1] == 0x6F)) {
florian55085f82012-11-21 00:36:55 +000010261 const HChar* wot = insn[1]==0x28 ? "apd" :
10262 insn[1]==0x10 ? "upd" : "dqa";
sewardjc2feffc2004-12-08 12:31:22 +000010263 modrm = getIByte(delta+2);
10264 if (epartIsReg(modrm)) {
10265 putXMMReg( gregOfRM(modrm),
10266 getXMMReg( eregOfRM(modrm) ));
10267 DIP("mov%s %s,%s\n", wot, nameXMMReg(eregOfRM(modrm)),
10268 nameXMMReg(gregOfRM(modrm)));
10269 delta += 2+1;
10270 } else {
10271 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
sewardj45ca0b92010-09-30 14:51:51 +000010272 if (insn[1] == 0x28/*movapd*/ || insn[1] == 0x6F/*movdqa*/)
10273 gen_SEGV_if_not_16_aligned( addr );
sewardjc2feffc2004-12-08 12:31:22 +000010274 putXMMReg( gregOfRM(modrm),
10275 loadLE(Ity_V128, mkexpr(addr)) );
10276 DIP("mov%s %s,%s\n", wot, dis_buf,
10277 nameXMMReg(gregOfRM(modrm)));
10278 delta += 2+alen;
10279 }
10280 goto decode_success;
10281 }
10282
sewardj95535fe2004-12-15 17:42:58 +000010283 /* 66 0F 29 = MOVAPD -- move from G (xmm) to E (mem or xmm). */
sewardj1c318772005-03-19 14:27:04 +000010284 /* 66 0F 11 = MOVUPD -- move from G (xmm) to E (mem or xmm). */
10285 if (sz == 2 && insn[0] == 0x0F
10286 && (insn[1] == 0x29 || insn[1] == 0x11)) {
florian55085f82012-11-21 00:36:55 +000010287 const HChar* wot = insn[1]==0x29 ? "apd" : "upd";
sewardj95535fe2004-12-15 17:42:58 +000010288 modrm = getIByte(delta+2);
10289 if (epartIsReg(modrm)) {
10290 /* fall through; awaiting test case */
10291 } else {
10292 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
sewardj45ca0b92010-09-30 14:51:51 +000010293 if (insn[1] == 0x29/*movapd*/)
10294 gen_SEGV_if_not_16_aligned( addr );
sewardj95535fe2004-12-15 17:42:58 +000010295 storeLE( mkexpr(addr), getXMMReg(gregOfRM(modrm)) );
sewardj1c318772005-03-19 14:27:04 +000010296 DIP("mov%s %s,%s\n", wot, nameXMMReg(gregOfRM(modrm)),
10297 dis_buf );
sewardj95535fe2004-12-15 17:42:58 +000010298 delta += 2+alen;
10299 goto decode_success;
10300 }
10301 }
10302
sewardjc2feffc2004-12-08 12:31:22 +000010303 /* 66 0F 6E = MOVD from r/m32 to xmm, zeroing high 3/4 of xmm. */
10304 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x6E) {
10305 modrm = getIByte(delta+2);
10306 if (epartIsReg(modrm)) {
10307 delta += 2+1;
10308 putXMMReg(
10309 gregOfRM(modrm),
sewardjf0c1c582005-02-07 23:47:38 +000010310 unop( Iop_32UtoV128, getIReg(4, eregOfRM(modrm)) )
sewardjc2feffc2004-12-08 12:31:22 +000010311 );
10312 DIP("movd %s, %s\n",
10313 nameIReg(4,eregOfRM(modrm)), nameXMMReg(gregOfRM(modrm)));
10314 } else {
10315 addr = disAMode( &alen, sorb, delta+2, dis_buf );
10316 delta += 2+alen;
10317 putXMMReg(
10318 gregOfRM(modrm),
sewardjf0c1c582005-02-07 23:47:38 +000010319 unop( Iop_32UtoV128,loadLE(Ity_I32, mkexpr(addr)) )
sewardjc2feffc2004-12-08 12:31:22 +000010320 );
10321 DIP("movd %s, %s\n", dis_buf, nameXMMReg(gregOfRM(modrm)));
10322 }
10323 goto decode_success;
10324 }
10325
10326 /* 66 0F 7E = MOVD from xmm low 1/4 to r/m32. */
10327 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x7E) {
10328 modrm = getIByte(delta+2);
10329 if (epartIsReg(modrm)) {
10330 delta += 2+1;
10331 putIReg( 4, eregOfRM(modrm),
10332 getXMMRegLane32(gregOfRM(modrm), 0) );
10333 DIP("movd %s, %s\n",
10334 nameXMMReg(gregOfRM(modrm)), nameIReg(4,eregOfRM(modrm)));
10335 } else {
10336 addr = disAMode( &alen, sorb, delta+2, dis_buf );
10337 delta += 2+alen;
10338 storeLE( mkexpr(addr),
10339 getXMMRegLane32(gregOfRM(modrm), 0) );
10340 DIP("movd %s, %s\n", nameXMMReg(gregOfRM(modrm)), dis_buf);
10341 }
10342 goto decode_success;
10343 }
10344
10345 /* 66 0F 7F = MOVDQA -- move from G (xmm) to E (mem or xmm). */
10346 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x7F) {
10347 modrm = getIByte(delta+2);
10348 if (epartIsReg(modrm)) {
10349 delta += 2+1;
10350 putXMMReg( eregOfRM(modrm),
10351 getXMMReg(gregOfRM(modrm)) );
10352 DIP("movdqa %s, %s\n", nameXMMReg(gregOfRM(modrm)),
10353 nameXMMReg(eregOfRM(modrm)));
10354 } else {
10355 addr = disAMode( &alen, sorb, delta+2, dis_buf );
10356 delta += 2+alen;
sewardj45ca0b92010-09-30 14:51:51 +000010357 gen_SEGV_if_not_16_aligned( addr );
sewardjc2feffc2004-12-08 12:31:22 +000010358 storeLE( mkexpr(addr), getXMMReg(gregOfRM(modrm)) );
10359 DIP("movdqa %s, %s\n", nameXMMReg(gregOfRM(modrm)), dis_buf);
10360 }
10361 goto decode_success;
10362 }
10363
10364 /* F3 0F 6F = MOVDQU -- move from E (mem or xmm) to G (xmm). */
10365 /* Unfortunately can't simply use the MOVDQA case since the
10366 prefix lengths are different (66 vs F3) */
10367 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x6F) {
10368 vassert(sz == 4);
10369 modrm = getIByte(delta+3);
10370 if (epartIsReg(modrm)) {
10371 putXMMReg( gregOfRM(modrm),
10372 getXMMReg( eregOfRM(modrm) ));
10373 DIP("movdqu %s,%s\n", nameXMMReg(eregOfRM(modrm)),
10374 nameXMMReg(gregOfRM(modrm)));
10375 delta += 3+1;
10376 } else {
10377 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
10378 putXMMReg( gregOfRM(modrm),
10379 loadLE(Ity_V128, mkexpr(addr)) );
10380 DIP("movdqu %s,%s\n", dis_buf,
10381 nameXMMReg(gregOfRM(modrm)));
10382 delta += 3+alen;
10383 }
10384 goto decode_success;
10385 }
10386
10387 /* F3 0F 7F = MOVDQU -- move from G (xmm) to E (mem or xmm). */
10388 /* Unfortunately can't simply use the MOVDQA case since the
10389 prefix lengths are different (66 vs F3) */
10390 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x7F) {
10391 vassert(sz == 4);
10392 modrm = getIByte(delta+3);
10393 if (epartIsReg(modrm)) {
10394 delta += 3+1;
10395 putXMMReg( eregOfRM(modrm),
10396 getXMMReg(gregOfRM(modrm)) );
10397 DIP("movdqu %s, %s\n", nameXMMReg(gregOfRM(modrm)),
10398 nameXMMReg(eregOfRM(modrm)));
10399 } else {
10400 addr = disAMode( &alen, sorb, delta+3, dis_buf );
10401 delta += 3+alen;
10402 storeLE( mkexpr(addr), getXMMReg(gregOfRM(modrm)) );
10403 DIP("movdqu %s, %s\n", nameXMMReg(gregOfRM(modrm)), dis_buf);
10404 }
10405 goto decode_success;
10406 }
10407
10408 /* F2 0F D6 = MOVDQ2Q -- move from E (lo half xmm, not mem) to G (mmx). */
10409 if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0xD6) {
10410 vassert(sz == 4);
10411 modrm = getIByte(delta+3);
10412 if (epartIsReg(modrm)) {
10413 do_MMX_preamble();
10414 putMMXReg( gregOfRM(modrm),
10415 getXMMRegLane64( eregOfRM(modrm), 0 ));
10416 DIP("movdq2q %s,%s\n", nameXMMReg(eregOfRM(modrm)),
10417 nameMMXReg(gregOfRM(modrm)));
10418 delta += 3+1;
10419 goto decode_success;
10420 } else {
10421 /* fall through, apparently no mem case for this insn */
10422 }
10423 }
10424
10425 /* 66 0F 16 = MOVHPD -- move from mem to high half of XMM. */
10426 /* These seems identical to MOVHPS. This instruction encoding is
10427 completely crazy. */
10428 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x16) {
10429 modrm = getIByte(delta+2);
10430 if (epartIsReg(modrm)) {
10431 /* fall through; apparently reg-reg is not possible */
10432 } else {
10433 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
10434 delta += 2+alen;
10435 putXMMRegLane64( gregOfRM(modrm), 1/*upper lane*/,
10436 loadLE(Ity_I64, mkexpr(addr)) );
10437 DIP("movhpd %s,%s\n", dis_buf,
10438 nameXMMReg( gregOfRM(modrm) ));
10439 goto decode_success;
10440 }
10441 }
10442
10443 /* 66 0F 17 = MOVHPD -- move from high half of XMM to mem. */
10444 /* Again, this seems identical to MOVHPS. */
10445 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x17) {
10446 if (!epartIsReg(insn[2])) {
10447 delta += 2;
10448 addr = disAMode ( &alen, sorb, delta, dis_buf );
10449 delta += alen;
10450 storeLE( mkexpr(addr),
10451 getXMMRegLane64( gregOfRM(insn[2]),
10452 1/*upper lane*/ ) );
10453 DIP("movhpd %s,%s\n", nameXMMReg( gregOfRM(insn[2]) ),
10454 dis_buf);
10455 goto decode_success;
10456 }
10457 /* else fall through */
10458 }
10459
10460 /* 66 0F 12 = MOVLPD -- move from mem to low half of XMM. */
10461 /* Identical to MOVLPS ? */
10462 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x12) {
10463 modrm = getIByte(delta+2);
10464 if (epartIsReg(modrm)) {
10465 /* fall through; apparently reg-reg is not possible */
10466 } else {
10467 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
10468 delta += 2+alen;
10469 putXMMRegLane64( gregOfRM(modrm), 0/*lower lane*/,
10470 loadLE(Ity_I64, mkexpr(addr)) );
10471 DIP("movlpd %s, %s\n",
10472 dis_buf, nameXMMReg( gregOfRM(modrm) ));
10473 goto decode_success;
10474 }
10475 }
10476
10477 /* 66 0F 13 = MOVLPD -- move from low half of XMM to mem. */
10478 /* Identical to MOVLPS ? */
10479 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x13) {
10480 if (!epartIsReg(insn[2])) {
10481 delta += 2;
10482 addr = disAMode ( &alen, sorb, delta, dis_buf );
10483 delta += alen;
10484 storeLE( mkexpr(addr),
10485 getXMMRegLane64( gregOfRM(insn[2]),
10486 0/*lower lane*/ ) );
10487 DIP("movlpd %s, %s\n", nameXMMReg( gregOfRM(insn[2]) ),
10488 dis_buf);
10489 goto decode_success;
10490 }
10491 /* else fall through */
10492 }
10493
10494 /* 66 0F 50 = MOVMSKPD - move 2 sign bits from 2 x F64 in xmm(E) to
10495 2 lowest bits of ireg(G) */
10496 if (insn[0] == 0x0F && insn[1] == 0x50) {
10497 modrm = getIByte(delta+2);
10498 if (sz == 2 && epartIsReg(modrm)) {
10499 Int src;
10500 t0 = newTemp(Ity_I32);
10501 t1 = newTemp(Ity_I32);
10502 delta += 2+1;
10503 src = eregOfRM(modrm);
10504 assign( t0, binop( Iop_And32,
10505 binop(Iop_Shr32, getXMMRegLane32(src,1), mkU8(31)),
10506 mkU32(1) ));
10507 assign( t1, binop( Iop_And32,
10508 binop(Iop_Shr32, getXMMRegLane32(src,3), mkU8(30)),
10509 mkU32(2) ));
10510 putIReg(4, gregOfRM(modrm),
10511 binop(Iop_Or32, mkexpr(t0), mkexpr(t1))
10512 );
10513 DIP("movmskpd %s,%s\n", nameXMMReg(src),
10514 nameIReg(4, gregOfRM(modrm)));
10515 goto decode_success;
10516 }
10517 /* else fall through */
10518 }
10519
sewardjd71ba832006-12-27 01:15:29 +000010520 /* 66 0F F7 = MASKMOVDQU -- store selected bytes of double quadword */
10521 if (insn[0] == 0x0F && insn[1] == 0xF7) {
10522 modrm = getIByte(delta+2);
10523 if (sz == 2 && epartIsReg(modrm)) {
10524 IRTemp regD = newTemp(Ity_V128);
10525 IRTemp mask = newTemp(Ity_V128);
10526 IRTemp olddata = newTemp(Ity_V128);
10527 IRTemp newdata = newTemp(Ity_V128);
10528 addr = newTemp(Ity_I32);
10529
10530 assign( addr, handleSegOverride( sorb, getIReg(4, R_EDI) ));
10531 assign( regD, getXMMReg( gregOfRM(modrm) ));
10532
10533 /* Unfortunately can't do the obvious thing with SarN8x16
10534 here since that can't be re-emitted as SSE2 code - no such
10535 insn. */
10536 assign(
10537 mask,
10538 binop(Iop_64HLtoV128,
10539 binop(Iop_SarN8x8,
10540 getXMMRegLane64( eregOfRM(modrm), 1 ),
10541 mkU8(7) ),
10542 binop(Iop_SarN8x8,
10543 getXMMRegLane64( eregOfRM(modrm), 0 ),
10544 mkU8(7) ) ));
10545 assign( olddata, loadLE( Ity_V128, mkexpr(addr) ));
10546 assign( newdata,
10547 binop(Iop_OrV128,
10548 binop(Iop_AndV128,
10549 mkexpr(regD),
10550 mkexpr(mask) ),
10551 binop(Iop_AndV128,
10552 mkexpr(olddata),
10553 unop(Iop_NotV128, mkexpr(mask)))) );
10554 storeLE( mkexpr(addr), mkexpr(newdata) );
10555
10556 delta += 2+1;
10557 DIP("maskmovdqu %s,%s\n", nameXMMReg( eregOfRM(modrm) ),
10558 nameXMMReg( gregOfRM(modrm) ) );
10559 goto decode_success;
10560 }
10561 /* else fall through */
10562 }
10563
sewardjc2feffc2004-12-08 12:31:22 +000010564 /* 66 0F E7 = MOVNTDQ -- for us, just a plain SSE store. */
10565 if (insn[0] == 0x0F && insn[1] == 0xE7) {
10566 modrm = getIByte(delta+2);
10567 if (sz == 2 && !epartIsReg(modrm)) {
10568 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
sewardj45ca0b92010-09-30 14:51:51 +000010569 gen_SEGV_if_not_16_aligned( addr );
sewardjc2feffc2004-12-08 12:31:22 +000010570 storeLE( mkexpr(addr), getXMMReg(gregOfRM(modrm)) );
10571 DIP("movntdq %s,%s\n", dis_buf,
10572 nameXMMReg(gregOfRM(modrm)));
10573 delta += 2+alen;
10574 goto decode_success;
10575 }
10576 /* else fall through */
10577 }
10578
10579 /* 0F C3 = MOVNTI -- for us, just a plain ireg store. */
10580 if (insn[0] == 0x0F && insn[1] == 0xC3) {
10581 vassert(sz == 4);
10582 modrm = getIByte(delta+2);
10583 if (!epartIsReg(modrm)) {
10584 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
10585 storeLE( mkexpr(addr), getIReg(4, gregOfRM(modrm)) );
10586 DIP("movnti %s,%s\n", dis_buf,
10587 nameIReg(4, gregOfRM(modrm)));
10588 delta += 2+alen;
10589 goto decode_success;
10590 }
10591 /* else fall through */
10592 }
10593
sewardj95535fe2004-12-15 17:42:58 +000010594 /* 66 0F D6 = MOVQ -- move 64 bits from G (lo half xmm) to E (mem
10595 or lo half xmm). */
sewardj9ee82862004-12-14 01:16:59 +000010596 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD6) {
10597 modrm = getIByte(delta+2);
10598 if (epartIsReg(modrm)) {
10599 /* fall through, awaiting test case */
sewardj6d7ccd52005-05-14 02:04:12 +000010600 /* dst: lo half copied, hi half zeroed */
sewardj9ee82862004-12-14 01:16:59 +000010601 } else {
10602 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
10603 storeLE( mkexpr(addr),
10604 getXMMRegLane64( gregOfRM(modrm), 0 ));
10605 DIP("movq %s,%s\n", nameXMMReg(gregOfRM(modrm)), dis_buf );
10606 delta += 2+alen;
10607 goto decode_success;
10608 }
10609 }
10610
sewardjc2feffc2004-12-08 12:31:22 +000010611 /* F3 0F D6 = MOVQ2DQ -- move from E (mmx) to G (lo half xmm, zero
10612 hi half). */
10613 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0xD6) {
10614 vassert(sz == 4);
10615 modrm = getIByte(delta+3);
10616 if (epartIsReg(modrm)) {
10617 do_MMX_preamble();
10618 putXMMReg( gregOfRM(modrm),
sewardjf0c1c582005-02-07 23:47:38 +000010619 unop(Iop_64UtoV128, getMMXReg( eregOfRM(modrm) )) );
sewardjc2feffc2004-12-08 12:31:22 +000010620 DIP("movq2dq %s,%s\n", nameMMXReg(eregOfRM(modrm)),
10621 nameXMMReg(gregOfRM(modrm)));
10622 delta += 3+1;
10623 goto decode_success;
10624 } else {
10625 /* fall through, apparently no mem case for this insn */
10626 }
10627 }
10628
sewardj95535fe2004-12-15 17:42:58 +000010629 /* F3 0F 7E = MOVQ -- move 64 bits from E (mem or lo half xmm) to
sewardj6d7ccd52005-05-14 02:04:12 +000010630 G (lo half xmm). Upper half of G is zeroed out. */
sewardj95535fe2004-12-15 17:42:58 +000010631 /* F2 0F 10 = MOVSD -- move 64 bits from E (mem or lo half xmm) to
10632 G (lo half xmm). If E is mem, upper half of G is zeroed out.
sewardj6d7ccd52005-05-14 02:04:12 +000010633 If E is reg, upper half of G is unchanged. */
sewardj95535fe2004-12-15 17:42:58 +000010634 if ((insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x10)
10635 || (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x7E)) {
sewardjc2feffc2004-12-08 12:31:22 +000010636 vassert(sz == 4);
10637 modrm = getIByte(delta+3);
10638 if (epartIsReg(modrm)) {
10639 putXMMRegLane64( gregOfRM(modrm), 0,
10640 getXMMRegLane64( eregOfRM(modrm), 0 ));
sewardj6d7ccd52005-05-14 02:04:12 +000010641 if (insn[0] == 0xF3/*MOVQ*/) {
10642 /* zero bits 127:64 */
10643 putXMMRegLane64( gregOfRM(modrm), 1, mkU64(0) );
10644 }
sewardjc2feffc2004-12-08 12:31:22 +000010645 DIP("movsd %s,%s\n", nameXMMReg(eregOfRM(modrm)),
10646 nameXMMReg(gregOfRM(modrm)));
10647 delta += 3+1;
10648 } else {
10649 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
sewardjad50db02005-04-06 01:45:44 +000010650 /* zero bits 127:64 */
sewardj5bf1fd42005-04-06 01:11:08 +000010651 putXMMRegLane64( gregOfRM(modrm), 1, mkU64(0) );
sewardjad50db02005-04-06 01:45:44 +000010652 /* write bits 63:0 */
sewardjc2feffc2004-12-08 12:31:22 +000010653 putXMMRegLane64( gregOfRM(modrm), 0,
10654 loadLE(Ity_I64, mkexpr(addr)) );
10655 DIP("movsd %s,%s\n", dis_buf,
10656 nameXMMReg(gregOfRM(modrm)));
10657 delta += 3+alen;
10658 }
10659 goto decode_success;
10660 }
10661
10662 /* F2 0F 11 = MOVSD -- move 64 bits from G (lo half xmm) to E (mem
10663 or lo half xmm). */
10664 if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x11) {
10665 vassert(sz == 4);
10666 modrm = getIByte(delta+3);
10667 if (epartIsReg(modrm)) {
sewardjb7ba04f2008-11-17 20:25:37 +000010668 putXMMRegLane64( eregOfRM(modrm), 0,
10669 getXMMRegLane64( gregOfRM(modrm), 0 ));
10670 DIP("movsd %s,%s\n", nameXMMReg(gregOfRM(modrm)),
10671 nameXMMReg(eregOfRM(modrm)));
10672 delta += 3+1;
sewardjc2feffc2004-12-08 12:31:22 +000010673 } else {
10674 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
10675 storeLE( mkexpr(addr),
sewardj519d66f2004-12-15 11:57:58 +000010676 getXMMRegLane64(gregOfRM(modrm), 0) );
10677 DIP("movsd %s,%s\n", nameXMMReg(gregOfRM(modrm)),
sewardjc2feffc2004-12-08 12:31:22 +000010678 dis_buf);
10679 delta += 3+alen;
sewardjc2feffc2004-12-08 12:31:22 +000010680 }
sewardjb7ba04f2008-11-17 20:25:37 +000010681 goto decode_success;
sewardjc2feffc2004-12-08 12:31:22 +000010682 }
sewardjfd226452004-12-07 19:02:18 +000010683
sewardj008754b2004-12-08 14:37:10 +000010684 /* 66 0F 59 = MULPD -- mul 64Fx2 from R/M to R */
10685 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x59) {
10686 delta = dis_SSE_E_to_G_all( sorb, delta+2, "mulpd", Iop_Mul64Fx2 );
10687 goto decode_success;
10688 }
10689
10690 /* F2 0F 59 = MULSD -- mul 64F0x2 from R/M to R */
10691 if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x59) {
10692 vassert(sz == 4);
10693 delta = dis_SSE_E_to_G_lo64( sorb, delta+3, "mulsd", Iop_Mul64F0x2 );
10694 goto decode_success;
10695 }
10696
10697 /* 66 0F 56 = ORPD -- G = G and E */
10698 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x56) {
sewardjf0c1c582005-02-07 23:47:38 +000010699 delta = dis_SSE_E_to_G_all( sorb, delta+2, "orpd", Iop_OrV128 );
sewardj008754b2004-12-08 14:37:10 +000010700 goto decode_success;
10701 }
10702
10703 /* 66 0F C6 /r ib = SHUFPD -- shuffle packed F64s */
10704 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xC6) {
10705 Int select;
10706 IRTemp sV = newTemp(Ity_V128);
10707 IRTemp dV = newTemp(Ity_V128);
10708 IRTemp s1 = newTemp(Ity_I64);
10709 IRTemp s0 = newTemp(Ity_I64);
10710 IRTemp d1 = newTemp(Ity_I64);
10711 IRTemp d0 = newTemp(Ity_I64);
10712
10713 modrm = insn[2];
10714 assign( dV, getXMMReg(gregOfRM(modrm)) );
10715
10716 if (epartIsReg(modrm)) {
10717 assign( sV, getXMMReg(eregOfRM(modrm)) );
10718 select = (Int)insn[3];
10719 delta += 2+2;
10720 DIP("shufpd $%d,%s,%s\n", select,
10721 nameXMMReg(eregOfRM(modrm)),
10722 nameXMMReg(gregOfRM(modrm)));
10723 } else {
10724 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
10725 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
10726 select = (Int)insn[2+alen];
10727 delta += 3+alen;
10728 DIP("shufpd $%d,%s,%s\n", select,
10729 dis_buf,
10730 nameXMMReg(gregOfRM(modrm)));
10731 }
10732
sewardjf0c1c582005-02-07 23:47:38 +000010733 assign( d1, unop(Iop_V128HIto64, mkexpr(dV)) );
10734 assign( d0, unop(Iop_V128to64, mkexpr(dV)) );
10735 assign( s1, unop(Iop_V128HIto64, mkexpr(sV)) );
10736 assign( s0, unop(Iop_V128to64, mkexpr(sV)) );
sewardj008754b2004-12-08 14:37:10 +000010737
10738# define SELD(n) mkexpr((n)==0 ? d0 : d1)
10739# define SELS(n) mkexpr((n)==0 ? s0 : s1)
10740
10741 putXMMReg(
10742 gregOfRM(modrm),
sewardjf0c1c582005-02-07 23:47:38 +000010743 binop(Iop_64HLtoV128, SELS((select>>1)&1), SELD((select>>0)&1) )
sewardj008754b2004-12-08 14:37:10 +000010744 );
10745
10746# undef SELD
10747# undef SELS
10748
10749 goto decode_success;
10750 }
10751
10752 /* 66 0F 51 = SQRTPD -- approx sqrt 64Fx2 from R/M to R */
10753 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x51) {
10754 delta = dis_SSE_E_to_G_unary_all( sorb, delta+2,
10755 "sqrtpd", Iop_Sqrt64Fx2 );
10756 goto decode_success;
10757 }
10758
10759 /* F2 0F 51 = SQRTSD -- approx sqrt 64F0x2 from R/M to R */
10760 if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x51) {
10761 vassert(sz == 4);
10762 delta = dis_SSE_E_to_G_unary_lo64( sorb, delta+3,
10763 "sqrtsd", Iop_Sqrt64F0x2 );
10764 goto decode_success;
10765 }
10766
10767 /* 66 0F 5C = SUBPD -- sub 64Fx2 from R/M to R */
10768 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x5C) {
10769 delta = dis_SSE_E_to_G_all( sorb, delta+2, "subpd", Iop_Sub64Fx2 );
10770 goto decode_success;
10771 }
10772
10773 /* F2 0F 5C = SUBSD -- sub 64F0x2 from R/M to R */
10774 if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x5C) {
10775 vassert(sz == 4);
10776 delta = dis_SSE_E_to_G_lo64( sorb, delta+3, "subsd", Iop_Sub64F0x2 );
10777 goto decode_success;
10778 }
10779
10780 /* 66 0F 15 = UNPCKHPD -- unpack and interleave high part F64s */
10781 /* 66 0F 14 = UNPCKLPD -- unpack and interleave low part F64s */
10782 /* These just appear to be special cases of SHUFPS */
10783 if (sz == 2 && insn[0] == 0x0F && (insn[1] == 0x15 || insn[1] == 0x14)) {
10784 IRTemp s1 = newTemp(Ity_I64);
10785 IRTemp s0 = newTemp(Ity_I64);
10786 IRTemp d1 = newTemp(Ity_I64);
10787 IRTemp d0 = newTemp(Ity_I64);
10788 IRTemp sV = newTemp(Ity_V128);
10789 IRTemp dV = newTemp(Ity_V128);
sewardj2d49b432005-02-01 00:37:06 +000010790 Bool hi = toBool(insn[1] == 0x15);
sewardj008754b2004-12-08 14:37:10 +000010791
10792 modrm = insn[2];
10793 assign( dV, getXMMReg(gregOfRM(modrm)) );
10794
10795 if (epartIsReg(modrm)) {
10796 assign( sV, getXMMReg(eregOfRM(modrm)) );
10797 delta += 2+1;
10798 DIP("unpck%sps %s,%s\n", hi ? "h" : "l",
10799 nameXMMReg(eregOfRM(modrm)),
10800 nameXMMReg(gregOfRM(modrm)));
10801 } else {
10802 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
10803 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
10804 delta += 2+alen;
10805 DIP("unpck%sps %s,%s\n", hi ? "h" : "l",
10806 dis_buf,
10807 nameXMMReg(gregOfRM(modrm)));
10808 }
10809
sewardjf0c1c582005-02-07 23:47:38 +000010810 assign( d1, unop(Iop_V128HIto64, mkexpr(dV)) );
10811 assign( d0, unop(Iop_V128to64, mkexpr(dV)) );
10812 assign( s1, unop(Iop_V128HIto64, mkexpr(sV)) );
10813 assign( s0, unop(Iop_V128to64, mkexpr(sV)) );
sewardj008754b2004-12-08 14:37:10 +000010814
10815 if (hi) {
10816 putXMMReg( gregOfRM(modrm),
sewardjf0c1c582005-02-07 23:47:38 +000010817 binop(Iop_64HLtoV128, mkexpr(s1), mkexpr(d1)) );
sewardj008754b2004-12-08 14:37:10 +000010818 } else {
10819 putXMMReg( gregOfRM(modrm),
sewardjf0c1c582005-02-07 23:47:38 +000010820 binop(Iop_64HLtoV128, mkexpr(s0), mkexpr(d0)) );
sewardj008754b2004-12-08 14:37:10 +000010821 }
10822
10823 goto decode_success;
10824 }
10825
10826 /* 66 0F 57 = XORPD -- G = G and E */
10827 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x57) {
sewardjf0c1c582005-02-07 23:47:38 +000010828 delta = dis_SSE_E_to_G_all( sorb, delta+2, "xorpd", Iop_XorV128 );
sewardj008754b2004-12-08 14:37:10 +000010829 goto decode_success;
10830 }
sewardj636ad762004-12-07 11:16:04 +000010831
sewardj164f9272004-12-09 00:39:32 +000010832 /* 66 0F 6B = PACKSSDW */
10833 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x6B) {
10834 delta = dis_SSEint_E_to_G( sorb, delta+2,
sewardjc9bff7d2011-06-15 15:09:37 +000010835 "packssdw",
sewardj5f438dd2011-06-16 11:36:23 +000010836 Iop_QNarrowBin32Sto16Sx8, True );
sewardj164f9272004-12-09 00:39:32 +000010837 goto decode_success;
10838 }
10839
10840 /* 66 0F 63 = PACKSSWB */
10841 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x63) {
10842 delta = dis_SSEint_E_to_G( sorb, delta+2,
sewardjc9bff7d2011-06-15 15:09:37 +000010843 "packsswb",
sewardj5f438dd2011-06-16 11:36:23 +000010844 Iop_QNarrowBin16Sto8Sx16, True );
sewardj164f9272004-12-09 00:39:32 +000010845 goto decode_success;
10846 }
10847
10848 /* 66 0F 67 = PACKUSWB */
10849 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x67) {
10850 delta = dis_SSEint_E_to_G( sorb, delta+2,
sewardjc9bff7d2011-06-15 15:09:37 +000010851 "packuswb",
sewardj5f438dd2011-06-16 11:36:23 +000010852 Iop_QNarrowBin16Sto8Ux16, True );
sewardj164f9272004-12-09 00:39:32 +000010853 goto decode_success;
10854 }
10855
10856 /* 66 0F FC = PADDB */
10857 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xFC) {
10858 delta = dis_SSEint_E_to_G( sorb, delta+2,
10859 "paddb", Iop_Add8x16, False );
10860 goto decode_success;
10861 }
10862
10863 /* 66 0F FE = PADDD */
10864 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xFE) {
10865 delta = dis_SSEint_E_to_G( sorb, delta+2,
10866 "paddd", Iop_Add32x4, False );
10867 goto decode_success;
10868 }
10869
10870 /* ***--- this is an MMX class insn introduced in SSE2 ---*** */
10871 /* 0F D4 = PADDQ -- add 64x1 */
10872 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xD4) {
10873 do_MMX_preamble();
10874 delta = dis_MMXop_regmem_to_reg (
10875 sorb, delta+2, insn[1], "paddq", False );
10876 goto decode_success;
10877 }
10878
10879 /* 66 0F D4 = PADDQ */
10880 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD4) {
10881 delta = dis_SSEint_E_to_G( sorb, delta+2,
10882 "paddq", Iop_Add64x2, False );
10883 goto decode_success;
10884 }
10885
10886 /* 66 0F FD = PADDW */
10887 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xFD) {
10888 delta = dis_SSEint_E_to_G( sorb, delta+2,
10889 "paddw", Iop_Add16x8, False );
10890 goto decode_success;
10891 }
10892
10893 /* 66 0F EC = PADDSB */
10894 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xEC) {
10895 delta = dis_SSEint_E_to_G( sorb, delta+2,
10896 "paddsb", Iop_QAdd8Sx16, False );
10897 goto decode_success;
10898 }
10899
10900 /* 66 0F ED = PADDSW */
10901 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xED) {
10902 delta = dis_SSEint_E_to_G( sorb, delta+2,
10903 "paddsw", Iop_QAdd16Sx8, False );
10904 goto decode_success;
10905 }
10906
10907 /* 66 0F DC = PADDUSB */
10908 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xDC) {
10909 delta = dis_SSEint_E_to_G( sorb, delta+2,
10910 "paddusb", Iop_QAdd8Ux16, False );
10911 goto decode_success;
10912 }
10913
10914 /* 66 0F DD = PADDUSW */
10915 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xDD) {
10916 delta = dis_SSEint_E_to_G( sorb, delta+2,
10917 "paddusw", Iop_QAdd16Ux8, False );
10918 goto decode_success;
10919 }
10920
10921 /* 66 0F DB = PAND */
10922 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xDB) {
sewardjf0c1c582005-02-07 23:47:38 +000010923 delta = dis_SSE_E_to_G_all( sorb, delta+2, "pand", Iop_AndV128 );
sewardj164f9272004-12-09 00:39:32 +000010924 goto decode_success;
10925 }
10926
10927 /* 66 0F DF = PANDN */
10928 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xDF) {
sewardjf0c1c582005-02-07 23:47:38 +000010929 delta = dis_SSE_E_to_G_all_invG( sorb, delta+2, "pandn", Iop_AndV128 );
sewardj164f9272004-12-09 00:39:32 +000010930 goto decode_success;
10931 }
10932
10933 /* 66 0F E0 = PAVGB */
10934 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xE0) {
10935 delta = dis_SSEint_E_to_G( sorb, delta+2,
10936 "pavgb", Iop_Avg8Ux16, False );
10937 goto decode_success;
10938 }
10939
10940 /* 66 0F E3 = PAVGW */
10941 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xE3) {
10942 delta = dis_SSEint_E_to_G( sorb, delta+2,
10943 "pavgw", Iop_Avg16Ux8, False );
10944 goto decode_success;
10945 }
10946
sewardje5854d62004-12-09 03:44:34 +000010947 /* 66 0F 74 = PCMPEQB */
10948 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x74) {
10949 delta = dis_SSEint_E_to_G( sorb, delta+2,
10950 "pcmpeqb", Iop_CmpEQ8x16, False );
10951 goto decode_success;
10952 }
10953
10954 /* 66 0F 76 = PCMPEQD */
10955 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x76) {
10956 delta = dis_SSEint_E_to_G( sorb, delta+2,
10957 "pcmpeqd", Iop_CmpEQ32x4, False );
10958 goto decode_success;
10959 }
10960
10961 /* 66 0F 75 = PCMPEQW */
10962 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x75) {
10963 delta = dis_SSEint_E_to_G( sorb, delta+2,
10964 "pcmpeqw", Iop_CmpEQ16x8, False );
10965 goto decode_success;
10966 }
10967
10968 /* 66 0F 64 = PCMPGTB */
10969 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x64) {
10970 delta = dis_SSEint_E_to_G( sorb, delta+2,
10971 "pcmpgtb", Iop_CmpGT8Sx16, False );
10972 goto decode_success;
10973 }
10974
10975 /* 66 0F 66 = PCMPGTD */
10976 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x66) {
10977 delta = dis_SSEint_E_to_G( sorb, delta+2,
10978 "pcmpgtd", Iop_CmpGT32Sx4, False );
10979 goto decode_success;
10980 }
10981
10982 /* 66 0F 65 = PCMPGTW */
10983 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x65) {
10984 delta = dis_SSEint_E_to_G( sorb, delta+2,
10985 "pcmpgtw", Iop_CmpGT16Sx8, False );
10986 goto decode_success;
10987 }
10988
10989 /* 66 0F C5 = PEXTRW -- extract 16-bit field from xmm(E) and put
10990 zero-extend of it in ireg(G). */
10991 if (insn[0] == 0x0F && insn[1] == 0xC5) {
10992 modrm = insn[2];
10993 if (sz == 2 && epartIsReg(modrm)) {
10994 t5 = newTemp(Ity_V128);
10995 t4 = newTemp(Ity_I16);
10996 assign(t5, getXMMReg(eregOfRM(modrm)));
10997 breakup128to32s( t5, &t3, &t2, &t1, &t0 );
10998 switch (insn[3] & 7) {
10999 case 0: assign(t4, unop(Iop_32to16, mkexpr(t0))); break;
11000 case 1: assign(t4, unop(Iop_32HIto16, mkexpr(t0))); break;
11001 case 2: assign(t4, unop(Iop_32to16, mkexpr(t1))); break;
11002 case 3: assign(t4, unop(Iop_32HIto16, mkexpr(t1))); break;
11003 case 4: assign(t4, unop(Iop_32to16, mkexpr(t2))); break;
11004 case 5: assign(t4, unop(Iop_32HIto16, mkexpr(t2))); break;
11005 case 6: assign(t4, unop(Iop_32to16, mkexpr(t3))); break;
11006 case 7: assign(t4, unop(Iop_32HIto16, mkexpr(t3))); break;
sewardjba89f4c2005-04-07 17:31:27 +000011007 default: vassert(0); /*NOTREACHED*/
sewardje5854d62004-12-09 03:44:34 +000011008 }
11009 putIReg(4, gregOfRM(modrm), unop(Iop_16Uto32, mkexpr(t4)));
11010 DIP("pextrw $%d,%s,%s\n",
11011 (Int)insn[3], nameXMMReg(eregOfRM(modrm)),
11012 nameIReg(4,gregOfRM(modrm)));
11013 delta += 4;
11014 goto decode_success;
11015 }
11016 /* else fall through */
11017 }
11018
11019 /* 66 0F C4 = PINSRW -- get 16 bits from E(mem or low half ireg) and
11020 put it into the specified lane of xmm(G). */
11021 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xC4) {
11022 Int lane;
11023 t4 = newTemp(Ity_I16);
11024 modrm = insn[2];
11025
11026 if (epartIsReg(modrm)) {
11027 assign(t4, getIReg(2, eregOfRM(modrm)));
sewardjaac7e082005-03-17 14:03:46 +000011028 delta += 3+1;
11029 lane = insn[3+1-1];
florianb1737742015-08-03 16:03:13 +000011030 DIP("pinsrw $%d,%s,%s\n", lane,
sewardje5854d62004-12-09 03:44:34 +000011031 nameIReg(2,eregOfRM(modrm)),
11032 nameXMMReg(gregOfRM(modrm)));
11033 } else {
sewardjaac7e082005-03-17 14:03:46 +000011034 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
11035 delta += 3+alen;
11036 lane = insn[3+alen-1];
11037 assign(t4, loadLE(Ity_I16, mkexpr(addr)));
florianb1737742015-08-03 16:03:13 +000011038 DIP("pinsrw $%d,%s,%s\n", lane,
sewardjaac7e082005-03-17 14:03:46 +000011039 dis_buf,
11040 nameXMMReg(gregOfRM(modrm)));
sewardje5854d62004-12-09 03:44:34 +000011041 }
11042
11043 putXMMRegLane16( gregOfRM(modrm), lane & 7, mkexpr(t4) );
11044 goto decode_success;
11045 }
11046
sewardjb8a3dea2005-10-04 20:00:49 +000011047 /* 66 0F F5 = PMADDWD -- Multiply and add packed integers from
11048 E(xmm or mem) to G(xmm) */
11049 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xF5) {
11050 IRTemp s1V = newTemp(Ity_V128);
11051 IRTemp s2V = newTemp(Ity_V128);
11052 IRTemp dV = newTemp(Ity_V128);
11053 IRTemp s1Hi = newTemp(Ity_I64);
11054 IRTemp s1Lo = newTemp(Ity_I64);
11055 IRTemp s2Hi = newTemp(Ity_I64);
11056 IRTemp s2Lo = newTemp(Ity_I64);
11057 IRTemp dHi = newTemp(Ity_I64);
11058 IRTemp dLo = newTemp(Ity_I64);
11059 modrm = insn[2];
11060 if (epartIsReg(modrm)) {
11061 assign( s1V, getXMMReg(eregOfRM(modrm)) );
11062 delta += 2+1;
11063 DIP("pmaddwd %s,%s\n", nameXMMReg(eregOfRM(modrm)),
11064 nameXMMReg(gregOfRM(modrm)));
11065 } else {
11066 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
11067 assign( s1V, loadLE(Ity_V128, mkexpr(addr)) );
11068 delta += 2+alen;
11069 DIP("pmaddwd %s,%s\n", dis_buf,
11070 nameXMMReg(gregOfRM(modrm)));
11071 }
11072 assign( s2V, getXMMReg(gregOfRM(modrm)) );
11073 assign( s1Hi, unop(Iop_V128HIto64, mkexpr(s1V)) );
11074 assign( s1Lo, unop(Iop_V128to64, mkexpr(s1V)) );
11075 assign( s2Hi, unop(Iop_V128HIto64, mkexpr(s2V)) );
11076 assign( s2Lo, unop(Iop_V128to64, mkexpr(s2V)) );
11077 assign( dHi, mkIRExprCCall(
11078 Ity_I64, 0/*regparms*/,
11079 "x86g_calculate_mmx_pmaddwd",
11080 &x86g_calculate_mmx_pmaddwd,
11081 mkIRExprVec_2( mkexpr(s1Hi), mkexpr(s2Hi))
11082 ));
11083 assign( dLo, mkIRExprCCall(
11084 Ity_I64, 0/*regparms*/,
11085 "x86g_calculate_mmx_pmaddwd",
11086 &x86g_calculate_mmx_pmaddwd,
11087 mkIRExprVec_2( mkexpr(s1Lo), mkexpr(s2Lo))
11088 ));
11089 assign( dV, binop(Iop_64HLtoV128, mkexpr(dHi), mkexpr(dLo))) ;
11090 putXMMReg(gregOfRM(modrm), mkexpr(dV));
11091 goto decode_success;
11092 }
11093
sewardje5854d62004-12-09 03:44:34 +000011094 /* 66 0F EE = PMAXSW -- 16x8 signed max */
11095 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xEE) {
11096 delta = dis_SSEint_E_to_G( sorb, delta+2,
11097 "pmaxsw", Iop_Max16Sx8, False );
11098 goto decode_success;
11099 }
11100
11101 /* 66 0F DE = PMAXUB -- 8x16 unsigned max */
11102 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xDE) {
11103 delta = dis_SSEint_E_to_G( sorb, delta+2,
11104 "pmaxub", Iop_Max8Ux16, False );
11105 goto decode_success;
11106 }
11107
11108 /* 66 0F EA = PMINSW -- 16x8 signed min */
11109 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xEA) {
11110 delta = dis_SSEint_E_to_G( sorb, delta+2,
11111 "pminsw", Iop_Min16Sx8, False );
11112 goto decode_success;
11113 }
11114
11115 /* 66 0F DA = PMINUB -- 8x16 unsigned min */
11116 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xDA) {
11117 delta = dis_SSEint_E_to_G( sorb, delta+2,
11118 "pminub", Iop_Min8Ux16, False );
11119 goto decode_success;
11120 }
11121
sewardje13074c2012-11-08 10:57:08 +000011122 /* 66 0F D7 = PMOVMSKB -- extract sign bits from each of 16 lanes
11123 in xmm(E), turn them into a byte, and put zero-extend of it in
11124 ireg(G). */
sewardje5854d62004-12-09 03:44:34 +000011125 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD7) {
11126 modrm = insn[2];
11127 if (epartIsReg(modrm)) {
11128 t0 = newTemp(Ity_I64);
11129 t1 = newTemp(Ity_I64);
11130 assign(t0, getXMMRegLane64(eregOfRM(modrm), 0));
11131 assign(t1, getXMMRegLane64(eregOfRM(modrm), 1));
11132 t5 = newTemp(Ity_I32);
sewardje13074c2012-11-08 10:57:08 +000011133 assign(t5,
11134 unop(Iop_16Uto32,
11135 binop(Iop_8HLto16,
11136 unop(Iop_GetMSBs8x8, mkexpr(t1)),
11137 unop(Iop_GetMSBs8x8, mkexpr(t0)))));
sewardje5854d62004-12-09 03:44:34 +000011138 putIReg(4, gregOfRM(modrm), mkexpr(t5));
11139 DIP("pmovmskb %s,%s\n", nameXMMReg(eregOfRM(modrm)),
11140 nameIReg(4,gregOfRM(modrm)));
11141 delta += 3;
11142 goto decode_success;
11143 }
11144 /* else fall through */
11145 }
11146
11147 /* 66 0F E4 = PMULHUW -- 16x8 hi-half of unsigned widening multiply */
11148 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xE4) {
11149 delta = dis_SSEint_E_to_G( sorb, delta+2,
11150 "pmulhuw", Iop_MulHi16Ux8, False );
11151 goto decode_success;
11152 }
11153
11154 /* 66 0F E5 = PMULHW -- 16x8 hi-half of signed widening multiply */
11155 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xE5) {
11156 delta = dis_SSEint_E_to_G( sorb, delta+2,
11157 "pmulhw", Iop_MulHi16Sx8, False );
11158 goto decode_success;
11159 }
11160
11161 /* 66 0F D5 = PMULHL -- 16x8 multiply */
11162 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD5) {
11163 delta = dis_SSEint_E_to_G( sorb, delta+2,
11164 "pmullw", Iop_Mul16x8, False );
11165 goto decode_success;
11166 }
11167
11168 /* ***--- this is an MMX class insn introduced in SSE2 ---*** */
11169 /* 0F F4 = PMULUDQ -- unsigned widening multiply of 32-lanes 0 x
11170 0 to form 64-bit result */
11171 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xF4) {
11172 IRTemp sV = newTemp(Ity_I64);
11173 IRTemp dV = newTemp(Ity_I64);
11174 t1 = newTemp(Ity_I32);
11175 t0 = newTemp(Ity_I32);
11176 modrm = insn[2];
11177
11178 do_MMX_preamble();
11179 assign( dV, getMMXReg(gregOfRM(modrm)) );
11180
11181 if (epartIsReg(modrm)) {
11182 assign( sV, getMMXReg(eregOfRM(modrm)) );
11183 delta += 2+1;
11184 DIP("pmuludq %s,%s\n", nameMMXReg(eregOfRM(modrm)),
11185 nameMMXReg(gregOfRM(modrm)));
11186 } else {
11187 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
11188 assign( sV, loadLE(Ity_I64, mkexpr(addr)) );
11189 delta += 2+alen;
11190 DIP("pmuludq %s,%s\n", dis_buf,
11191 nameMMXReg(gregOfRM(modrm)));
11192 }
11193
11194 assign( t0, unop(Iop_64to32, mkexpr(dV)) );
11195 assign( t1, unop(Iop_64to32, mkexpr(sV)) );
11196 putMMXReg( gregOfRM(modrm),
11197 binop( Iop_MullU32, mkexpr(t0), mkexpr(t1) ) );
11198 goto decode_success;
11199 }
11200
11201 /* 66 0F F4 = PMULUDQ -- unsigned widening multiply of 32-lanes 0 x
11202 0 to form lower 64-bit half and lanes 2 x 2 to form upper 64-bit
11203 half */
11204 /* This is a really poor translation -- could be improved if
11205 performance critical */
11206 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xF4) {
11207 IRTemp sV, dV;
11208 IRTemp s3, s2, s1, s0, d3, d2, d1, d0;
11209 sV = newTemp(Ity_V128);
11210 dV = newTemp(Ity_V128);
11211 s3 = s2 = s1 = s0 = d3 = d2 = d1 = d0 = IRTemp_INVALID;
11212 t1 = newTemp(Ity_I64);
11213 t0 = newTemp(Ity_I64);
11214 modrm = insn[2];
11215 assign( dV, getXMMReg(gregOfRM(modrm)) );
11216
11217 if (epartIsReg(modrm)) {
11218 assign( sV, getXMMReg(eregOfRM(modrm)) );
11219 delta += 2+1;
11220 DIP("pmuludq %s,%s\n", nameXMMReg(eregOfRM(modrm)),
11221 nameXMMReg(gregOfRM(modrm)));
11222 } else {
11223 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
11224 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
11225 delta += 2+alen;
11226 DIP("pmuludq %s,%s\n", dis_buf,
11227 nameXMMReg(gregOfRM(modrm)));
11228 }
11229
11230 breakup128to32s( dV, &d3, &d2, &d1, &d0 );
11231 breakup128to32s( sV, &s3, &s2, &s1, &s0 );
11232
11233 assign( t0, binop( Iop_MullU32, mkexpr(d0), mkexpr(s0)) );
11234 putXMMRegLane64( gregOfRM(modrm), 0, mkexpr(t0) );
11235 assign( t1, binop( Iop_MullU32, mkexpr(d2), mkexpr(s2)) );
11236 putXMMRegLane64( gregOfRM(modrm), 1, mkexpr(t1) );
11237 goto decode_success;
11238 }
11239
11240 /* 66 0F EB = POR */
11241 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xEB) {
sewardjf0c1c582005-02-07 23:47:38 +000011242 delta = dis_SSE_E_to_G_all( sorb, delta+2, "por", Iop_OrV128 );
sewardje5854d62004-12-09 03:44:34 +000011243 goto decode_success;
11244 }
11245
sewardj7b5b9982005-10-04 11:43:37 +000011246 /* 66 0F F6 = PSADBW -- 2 x (8x8 -> 48 zeroes ++ u16) Sum Abs Diffs
11247 from E(xmm or mem) to G(xmm) */
11248 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xF6) {
11249 IRTemp s1V = newTemp(Ity_V128);
11250 IRTemp s2V = newTemp(Ity_V128);
11251 IRTemp dV = newTemp(Ity_V128);
11252 IRTemp s1Hi = newTemp(Ity_I64);
11253 IRTemp s1Lo = newTemp(Ity_I64);
11254 IRTemp s2Hi = newTemp(Ity_I64);
11255 IRTemp s2Lo = newTemp(Ity_I64);
11256 IRTemp dHi = newTemp(Ity_I64);
11257 IRTemp dLo = newTemp(Ity_I64);
11258 modrm = insn[2];
11259 if (epartIsReg(modrm)) {
11260 assign( s1V, getXMMReg(eregOfRM(modrm)) );
11261 delta += 2+1;
11262 DIP("psadbw %s,%s\n", nameXMMReg(eregOfRM(modrm)),
11263 nameXMMReg(gregOfRM(modrm)));
11264 } else {
11265 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
11266 assign( s1V, loadLE(Ity_V128, mkexpr(addr)) );
11267 delta += 2+alen;
11268 DIP("psadbw %s,%s\n", dis_buf,
11269 nameXMMReg(gregOfRM(modrm)));
11270 }
11271 assign( s2V, getXMMReg(gregOfRM(modrm)) );
11272 assign( s1Hi, unop(Iop_V128HIto64, mkexpr(s1V)) );
11273 assign( s1Lo, unop(Iop_V128to64, mkexpr(s1V)) );
11274 assign( s2Hi, unop(Iop_V128HIto64, mkexpr(s2V)) );
11275 assign( s2Lo, unop(Iop_V128to64, mkexpr(s2V)) );
11276 assign( dHi, mkIRExprCCall(
11277 Ity_I64, 0/*regparms*/,
11278 "x86g_calculate_mmx_psadbw",
11279 &x86g_calculate_mmx_psadbw,
11280 mkIRExprVec_2( mkexpr(s1Hi), mkexpr(s2Hi))
11281 ));
11282 assign( dLo, mkIRExprCCall(
11283 Ity_I64, 0/*regparms*/,
11284 "x86g_calculate_mmx_psadbw",
11285 &x86g_calculate_mmx_psadbw,
11286 mkIRExprVec_2( mkexpr(s1Lo), mkexpr(s2Lo))
11287 ));
11288 assign( dV, binop(Iop_64HLtoV128, mkexpr(dHi), mkexpr(dLo))) ;
11289 putXMMReg(gregOfRM(modrm), mkexpr(dV));
11290 goto decode_success;
11291 }
11292
sewardjb9fa69b2004-12-09 23:25:14 +000011293 /* 66 0F 70 = PSHUFD -- rearrange 4x32 from E(xmm or mem) to G(xmm) */
11294 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x70) {
11295 Int order;
11296 IRTemp sV, dV, s3, s2, s1, s0;
11297 s3 = s2 = s1 = s0 = IRTemp_INVALID;
11298 sV = newTemp(Ity_V128);
11299 dV = newTemp(Ity_V128);
11300 modrm = insn[2];
11301 if (epartIsReg(modrm)) {
11302 assign( sV, getXMMReg(eregOfRM(modrm)) );
11303 order = (Int)insn[3];
11304 delta += 2+2;
11305 DIP("pshufd $%d,%s,%s\n", order,
11306 nameXMMReg(eregOfRM(modrm)),
11307 nameXMMReg(gregOfRM(modrm)));
11308 } else {
11309 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
11310 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
11311 order = (Int)insn[2+alen];
11312 delta += 3+alen;
11313 DIP("pshufd $%d,%s,%s\n", order,
11314 dis_buf,
11315 nameXMMReg(gregOfRM(modrm)));
11316 }
11317 breakup128to32s( sV, &s3, &s2, &s1, &s0 );
11318
11319# define SEL(n) \
11320 ((n)==0 ? s0 : ((n)==1 ? s1 : ((n)==2 ? s2 : s3)))
11321 assign(dV,
11322 mk128from32s( SEL((order>>6)&3), SEL((order>>4)&3),
11323 SEL((order>>2)&3), SEL((order>>0)&3) )
11324 );
11325 putXMMReg(gregOfRM(modrm), mkexpr(dV));
11326# undef SEL
11327 goto decode_success;
11328 }
11329
11330 /* F3 0F 70 = PSHUFHW -- rearrange upper half 4x16 from E(xmm or
11331 mem) to G(xmm), and copy lower half */
11332 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x70) {
11333 Int order;
11334 IRTemp sVhi, dVhi, sV, dV, s3, s2, s1, s0;
11335 s3 = s2 = s1 = s0 = IRTemp_INVALID;
11336 sV = newTemp(Ity_V128);
11337 dV = newTemp(Ity_V128);
11338 sVhi = newTemp(Ity_I64);
11339 dVhi = newTemp(Ity_I64);
11340 modrm = insn[3];
11341 if (epartIsReg(modrm)) {
11342 assign( sV, getXMMReg(eregOfRM(modrm)) );
11343 order = (Int)insn[4];
11344 delta += 4+1;
11345 DIP("pshufhw $%d,%s,%s\n", order,
11346 nameXMMReg(eregOfRM(modrm)),
11347 nameXMMReg(gregOfRM(modrm)));
11348 } else {
11349 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
11350 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
11351 order = (Int)insn[3+alen];
11352 delta += 4+alen;
11353 DIP("pshufhw $%d,%s,%s\n", order,
11354 dis_buf,
11355 nameXMMReg(gregOfRM(modrm)));
11356 }
sewardjf0c1c582005-02-07 23:47:38 +000011357 assign( sVhi, unop(Iop_V128HIto64, mkexpr(sV)) );
sewardjb9fa69b2004-12-09 23:25:14 +000011358 breakup64to16s( sVhi, &s3, &s2, &s1, &s0 );
11359
11360# define SEL(n) \
11361 ((n)==0 ? s0 : ((n)==1 ? s1 : ((n)==2 ? s2 : s3)))
11362 assign(dVhi,
11363 mk64from16s( SEL((order>>6)&3), SEL((order>>4)&3),
11364 SEL((order>>2)&3), SEL((order>>0)&3) )
11365 );
sewardjf0c1c582005-02-07 23:47:38 +000011366 assign(dV, binop( Iop_64HLtoV128,
sewardjb9fa69b2004-12-09 23:25:14 +000011367 mkexpr(dVhi),
sewardjf0c1c582005-02-07 23:47:38 +000011368 unop(Iop_V128to64, mkexpr(sV))) );
sewardjb9fa69b2004-12-09 23:25:14 +000011369 putXMMReg(gregOfRM(modrm), mkexpr(dV));
11370# undef SEL
11371 goto decode_success;
11372 }
11373
11374 /* F2 0F 70 = PSHUFLW -- rearrange lower half 4x16 from E(xmm or
11375 mem) to G(xmm), and copy upper half */
11376 if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x70) {
11377 Int order;
11378 IRTemp sVlo, dVlo, sV, dV, s3, s2, s1, s0;
11379 s3 = s2 = s1 = s0 = IRTemp_INVALID;
11380 sV = newTemp(Ity_V128);
11381 dV = newTemp(Ity_V128);
11382 sVlo = newTemp(Ity_I64);
11383 dVlo = newTemp(Ity_I64);
11384 modrm = insn[3];
11385 if (epartIsReg(modrm)) {
11386 assign( sV, getXMMReg(eregOfRM(modrm)) );
11387 order = (Int)insn[4];
11388 delta += 4+1;
11389 DIP("pshuflw $%d,%s,%s\n", order,
11390 nameXMMReg(eregOfRM(modrm)),
11391 nameXMMReg(gregOfRM(modrm)));
11392 } else {
11393 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
11394 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
11395 order = (Int)insn[3+alen];
11396 delta += 4+alen;
11397 DIP("pshuflw $%d,%s,%s\n", order,
11398 dis_buf,
11399 nameXMMReg(gregOfRM(modrm)));
11400 }
sewardjf0c1c582005-02-07 23:47:38 +000011401 assign( sVlo, unop(Iop_V128to64, mkexpr(sV)) );
sewardjb9fa69b2004-12-09 23:25:14 +000011402 breakup64to16s( sVlo, &s3, &s2, &s1, &s0 );
11403
11404# define SEL(n) \
11405 ((n)==0 ? s0 : ((n)==1 ? s1 : ((n)==2 ? s2 : s3)))
11406 assign(dVlo,
11407 mk64from16s( SEL((order>>6)&3), SEL((order>>4)&3),
11408 SEL((order>>2)&3), SEL((order>>0)&3) )
11409 );
sewardjf0c1c582005-02-07 23:47:38 +000011410 assign(dV, binop( Iop_64HLtoV128,
11411 unop(Iop_V128HIto64, mkexpr(sV)),
sewardjb9fa69b2004-12-09 23:25:14 +000011412 mkexpr(dVlo) ) );
11413 putXMMReg(gregOfRM(modrm), mkexpr(dV));
11414# undef SEL
11415 goto decode_success;
11416 }
11417
11418 /* 66 0F 72 /6 ib = PSLLD by immediate */
11419 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x72
11420 && epartIsReg(insn[2])
11421 && gregOfRM(insn[2]) == 6) {
sewardj38a3f862005-01-13 15:06:51 +000011422 delta = dis_SSE_shiftE_imm( delta+2, "pslld", Iop_ShlN32x4 );
sewardjb9fa69b2004-12-09 23:25:14 +000011423 goto decode_success;
11424 }
11425
11426 /* 66 0F F2 = PSLLD by E */
11427 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xF2) {
11428 delta = dis_SSE_shiftG_byE( sorb, delta+2, "pslld", Iop_ShlN32x4 );
11429 goto decode_success;
11430 }
11431
sewardjb9fa69b2004-12-09 23:25:14 +000011432 /* 66 0F 73 /7 ib = PSLLDQ by immediate */
11433 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x73
11434 && epartIsReg(insn[2])
11435 && gregOfRM(insn[2]) == 7) {
sewardj0c9907c2005-01-10 20:37:31 +000011436 IRTemp sV, dV, hi64, lo64, hi64r, lo64r;
11437 Int imm = (Int)insn[3];
11438 Int reg = eregOfRM(insn[2]);
11439 DIP("pslldq $%d,%s\n", imm, nameXMMReg(reg));
11440 vassert(imm >= 0 && imm <= 255);
11441 delta += 4;
11442
11443 sV = newTemp(Ity_V128);
11444 dV = newTemp(Ity_V128);
11445 hi64 = newTemp(Ity_I64);
11446 lo64 = newTemp(Ity_I64);
11447 hi64r = newTemp(Ity_I64);
11448 lo64r = newTemp(Ity_I64);
11449
11450 if (imm >= 16) {
sewardj0c9907c2005-01-10 20:37:31 +000011451 putXMMReg(reg, mkV128(0x0000));
11452 goto decode_success;
11453 }
11454
11455 assign( sV, getXMMReg(reg) );
sewardjf0c1c582005-02-07 23:47:38 +000011456 assign( hi64, unop(Iop_V128HIto64, mkexpr(sV)) );
11457 assign( lo64, unop(Iop_V128to64, mkexpr(sV)) );
sewardj0c9907c2005-01-10 20:37:31 +000011458
sewardjba89f4c2005-04-07 17:31:27 +000011459 if (imm == 0) {
11460 assign( lo64r, mkexpr(lo64) );
11461 assign( hi64r, mkexpr(hi64) );
11462 }
11463 else
sewardj0c9907c2005-01-10 20:37:31 +000011464 if (imm == 8) {
11465 assign( lo64r, mkU64(0) );
11466 assign( hi64r, mkexpr(lo64) );
11467 }
sewardjc02043c2005-01-11 15:03:53 +000011468 else
sewardj0c9907c2005-01-10 20:37:31 +000011469 if (imm > 8) {
sewardj0c9907c2005-01-10 20:37:31 +000011470 assign( lo64r, mkU64(0) );
11471 assign( hi64r, binop( Iop_Shl64,
11472 mkexpr(lo64),
11473 mkU8( 8*(imm-8) ) ));
11474 } else {
11475 assign( lo64r, binop( Iop_Shl64,
11476 mkexpr(lo64),
11477 mkU8(8 * imm) ));
11478 assign( hi64r,
11479 binop( Iop_Or64,
11480 binop(Iop_Shl64, mkexpr(hi64),
11481 mkU8(8 * imm)),
11482 binop(Iop_Shr64, mkexpr(lo64),
11483 mkU8(8 * (8 - imm)) )
11484 )
11485 );
11486 }
sewardjf0c1c582005-02-07 23:47:38 +000011487 assign( dV, binop(Iop_64HLtoV128, mkexpr(hi64r), mkexpr(lo64r)) );
sewardj0c9907c2005-01-10 20:37:31 +000011488 putXMMReg(reg, mkexpr(dV));
sewardjb9fa69b2004-12-09 23:25:14 +000011489 goto decode_success;
11490 }
sewardjb9fa69b2004-12-09 23:25:14 +000011491
11492 /* 66 0F 73 /6 ib = PSLLQ by immediate */
11493 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x73
11494 && epartIsReg(insn[2])
11495 && gregOfRM(insn[2]) == 6) {
sewardj38a3f862005-01-13 15:06:51 +000011496 delta = dis_SSE_shiftE_imm( delta+2, "psllq", Iop_ShlN64x2 );
sewardjb9fa69b2004-12-09 23:25:14 +000011497 goto decode_success;
11498 }
11499
11500 /* 66 0F F3 = PSLLQ by E */
11501 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xF3) {
11502 delta = dis_SSE_shiftG_byE( sorb, delta+2, "psllq", Iop_ShlN64x2 );
11503 goto decode_success;
11504 }
11505
11506 /* 66 0F 71 /6 ib = PSLLW by immediate */
11507 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x71
11508 && epartIsReg(insn[2])
11509 && gregOfRM(insn[2]) == 6) {
sewardj38a3f862005-01-13 15:06:51 +000011510 delta = dis_SSE_shiftE_imm( delta+2, "psllw", Iop_ShlN16x8 );
sewardjb9fa69b2004-12-09 23:25:14 +000011511 goto decode_success;
11512 }
11513
11514 /* 66 0F F1 = PSLLW by E */
11515 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xF1) {
11516 delta = dis_SSE_shiftG_byE( sorb, delta+2, "psllw", Iop_ShlN16x8 );
11517 goto decode_success;
11518 }
11519
11520 /* 66 0F 72 /4 ib = PSRAD by immediate */
11521 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x72
11522 && epartIsReg(insn[2])
11523 && gregOfRM(insn[2]) == 4) {
sewardj38a3f862005-01-13 15:06:51 +000011524 delta = dis_SSE_shiftE_imm( delta+2, "psrad", Iop_SarN32x4 );
sewardjb9fa69b2004-12-09 23:25:14 +000011525 goto decode_success;
11526 }
11527
11528 /* 66 0F E2 = PSRAD by E */
11529 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xE2) {
11530 delta = dis_SSE_shiftG_byE( sorb, delta+2, "psrad", Iop_SarN32x4 );
11531 goto decode_success;
11532 }
11533
11534 /* 66 0F 71 /4 ib = PSRAW by immediate */
11535 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x71
11536 && epartIsReg(insn[2])
11537 && gregOfRM(insn[2]) == 4) {
sewardj38a3f862005-01-13 15:06:51 +000011538 delta = dis_SSE_shiftE_imm( delta+2, "psraw", Iop_SarN16x8 );
sewardjb9fa69b2004-12-09 23:25:14 +000011539 goto decode_success;
11540 }
11541
11542 /* 66 0F E1 = PSRAW by E */
11543 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xE1) {
11544 delta = dis_SSE_shiftG_byE( sorb, delta+2, "psraw", Iop_SarN16x8 );
11545 goto decode_success;
11546 }
11547
11548 /* 66 0F 72 /2 ib = PSRLD by immediate */
11549 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x72
11550 && epartIsReg(insn[2])
11551 && gregOfRM(insn[2]) == 2) {
sewardj38a3f862005-01-13 15:06:51 +000011552 delta = dis_SSE_shiftE_imm( delta+2, "psrld", Iop_ShrN32x4 );
sewardjb9fa69b2004-12-09 23:25:14 +000011553 goto decode_success;
11554 }
11555
11556 /* 66 0F D2 = PSRLD by E */
11557 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD2) {
11558 delta = dis_SSE_shiftG_byE( sorb, delta+2, "psrld", Iop_ShrN32x4 );
11559 goto decode_success;
11560 }
11561
sewardj9ee82862004-12-14 01:16:59 +000011562 /* 66 0F 73 /3 ib = PSRLDQ by immediate */
11563 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x73
11564 && epartIsReg(insn[2])
sewardj95535fe2004-12-15 17:42:58 +000011565 && gregOfRM(insn[2]) == 3) {
11566 IRTemp sV, dV, hi64, lo64, hi64r, lo64r;
sewardj9ee82862004-12-14 01:16:59 +000011567 Int imm = (Int)insn[3];
11568 Int reg = eregOfRM(insn[2]);
sewardj9ee82862004-12-14 01:16:59 +000011569 DIP("psrldq $%d,%s\n", imm, nameXMMReg(reg));
sewardj95535fe2004-12-15 17:42:58 +000011570 vassert(imm >= 0 && imm <= 255);
11571 delta += 4;
11572
11573 sV = newTemp(Ity_V128);
11574 dV = newTemp(Ity_V128);
11575 hi64 = newTemp(Ity_I64);
11576 lo64 = newTemp(Ity_I64);
11577 hi64r = newTemp(Ity_I64);
11578 lo64r = newTemp(Ity_I64);
11579
11580 if (imm >= 16) {
sewardj95535fe2004-12-15 17:42:58 +000011581 putXMMReg(reg, mkV128(0x0000));
11582 goto decode_success;
11583 }
11584
11585 assign( sV, getXMMReg(reg) );
sewardjf0c1c582005-02-07 23:47:38 +000011586 assign( hi64, unop(Iop_V128HIto64, mkexpr(sV)) );
11587 assign( lo64, unop(Iop_V128to64, mkexpr(sV)) );
sewardj95535fe2004-12-15 17:42:58 +000011588
sewardjba89f4c2005-04-07 17:31:27 +000011589 if (imm == 0) {
11590 assign( lo64r, mkexpr(lo64) );
11591 assign( hi64r, mkexpr(hi64) );
11592 }
11593 else
sewardj95535fe2004-12-15 17:42:58 +000011594 if (imm == 8) {
11595 assign( hi64r, mkU64(0) );
11596 assign( lo64r, mkexpr(hi64) );
11597 }
11598 else
11599 if (imm > 8) {
sewardj95535fe2004-12-15 17:42:58 +000011600 assign( hi64r, mkU64(0) );
11601 assign( lo64r, binop( Iop_Shr64,
11602 mkexpr(hi64),
11603 mkU8( 8*(imm-8) ) ));
11604 } else {
11605 assign( hi64r, binop( Iop_Shr64,
11606 mkexpr(hi64),
11607 mkU8(8 * imm) ));
11608 assign( lo64r,
11609 binop( Iop_Or64,
11610 binop(Iop_Shr64, mkexpr(lo64),
11611 mkU8(8 * imm)),
11612 binop(Iop_Shl64, mkexpr(hi64),
11613 mkU8(8 * (8 - imm)) )
11614 )
11615 );
11616 }
11617
sewardjf0c1c582005-02-07 23:47:38 +000011618 assign( dV, binop(Iop_64HLtoV128, mkexpr(hi64r), mkexpr(lo64r)) );
sewardj95535fe2004-12-15 17:42:58 +000011619 putXMMReg(reg, mkexpr(dV));
sewardj9ee82862004-12-14 01:16:59 +000011620 goto decode_success;
11621 }
11622
sewardjb9fa69b2004-12-09 23:25:14 +000011623 /* 66 0F 73 /2 ib = PSRLQ by immediate */
11624 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x73
11625 && epartIsReg(insn[2])
11626 && gregOfRM(insn[2]) == 2) {
sewardj38a3f862005-01-13 15:06:51 +000011627 delta = dis_SSE_shiftE_imm( delta+2, "psrlq", Iop_ShrN64x2 );
sewardjb9fa69b2004-12-09 23:25:14 +000011628 goto decode_success;
11629 }
11630
11631 /* 66 0F D3 = PSRLQ by E */
11632 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD3) {
11633 delta = dis_SSE_shiftG_byE( sorb, delta+2, "psrlq", Iop_ShrN64x2 );
11634 goto decode_success;
11635 }
11636
11637 /* 66 0F 71 /2 ib = PSRLW by immediate */
11638 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x71
11639 && epartIsReg(insn[2])
11640 && gregOfRM(insn[2]) == 2) {
sewardj38a3f862005-01-13 15:06:51 +000011641 delta = dis_SSE_shiftE_imm( delta+2, "psrlw", Iop_ShrN16x8 );
sewardjb9fa69b2004-12-09 23:25:14 +000011642 goto decode_success;
11643 }
11644
11645 /* 66 0F D1 = PSRLW by E */
11646 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD1) {
11647 delta = dis_SSE_shiftG_byE( sorb, delta+2, "psrlw", Iop_ShrN16x8 );
11648 goto decode_success;
11649 }
11650
11651 /* 66 0F F8 = PSUBB */
11652 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xF8) {
11653 delta = dis_SSEint_E_to_G( sorb, delta+2,
11654 "psubb", Iop_Sub8x16, False );
11655 goto decode_success;
11656 }
11657
11658 /* 66 0F FA = PSUBD */
11659 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xFA) {
11660 delta = dis_SSEint_E_to_G( sorb, delta+2,
11661 "psubd", Iop_Sub32x4, False );
11662 goto decode_success;
11663 }
11664
11665 /* ***--- this is an MMX class insn introduced in SSE2 ---*** */
11666 /* 0F FB = PSUBQ -- sub 64x1 */
11667 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xFB) {
11668 do_MMX_preamble();
11669 delta = dis_MMXop_regmem_to_reg (
11670 sorb, delta+2, insn[1], "psubq", False );
11671 goto decode_success;
11672 }
11673
11674 /* 66 0F FB = PSUBQ */
11675 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xFB) {
11676 delta = dis_SSEint_E_to_G( sorb, delta+2,
11677 "psubq", Iop_Sub64x2, False );
11678 goto decode_success;
11679 }
11680
11681 /* 66 0F F9 = PSUBW */
11682 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xF9) {
11683 delta = dis_SSEint_E_to_G( sorb, delta+2,
11684 "psubw", Iop_Sub16x8, False );
11685 goto decode_success;
11686 }
11687
11688 /* 66 0F E8 = PSUBSB */
11689 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xE8) {
11690 delta = dis_SSEint_E_to_G( sorb, delta+2,
11691 "psubsb", Iop_QSub8Sx16, False );
11692 goto decode_success;
11693 }
11694
11695 /* 66 0F E9 = PSUBSW */
11696 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xE9) {
11697 delta = dis_SSEint_E_to_G( sorb, delta+2,
11698 "psubsw", Iop_QSub16Sx8, False );
11699 goto decode_success;
11700 }
11701
11702 /* 66 0F D8 = PSUBSB */
11703 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD8) {
11704 delta = dis_SSEint_E_to_G( sorb, delta+2,
11705 "psubusb", Iop_QSub8Ux16, False );
11706 goto decode_success;
11707 }
11708
11709 /* 66 0F D9 = PSUBSW */
11710 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD9) {
11711 delta = dis_SSEint_E_to_G( sorb, delta+2,
11712 "psubusw", Iop_QSub16Ux8, False );
11713 goto decode_success;
11714 }
11715
sewardj9e203592004-12-10 01:48:18 +000011716 /* 66 0F 68 = PUNPCKHBW */
11717 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x68) {
11718 delta = dis_SSEint_E_to_G( sorb, delta+2,
11719 "punpckhbw",
11720 Iop_InterleaveHI8x16, True );
11721 goto decode_success;
11722 }
11723
11724 /* 66 0F 6A = PUNPCKHDQ */
11725 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x6A) {
11726 delta = dis_SSEint_E_to_G( sorb, delta+2,
11727 "punpckhdq",
11728 Iop_InterleaveHI32x4, True );
11729 goto decode_success;
11730 }
11731
11732 /* 66 0F 6D = PUNPCKHQDQ */
11733 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x6D) {
11734 delta = dis_SSEint_E_to_G( sorb, delta+2,
11735 "punpckhqdq",
11736 Iop_InterleaveHI64x2, True );
11737 goto decode_success;
11738 }
11739
11740 /* 66 0F 69 = PUNPCKHWD */
11741 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x69) {
11742 delta = dis_SSEint_E_to_G( sorb, delta+2,
11743 "punpckhwd",
11744 Iop_InterleaveHI16x8, True );
11745 goto decode_success;
11746 }
11747
11748 /* 66 0F 60 = PUNPCKLBW */
11749 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x60) {
11750 delta = dis_SSEint_E_to_G( sorb, delta+2,
11751 "punpcklbw",
11752 Iop_InterleaveLO8x16, True );
11753 goto decode_success;
11754 }
11755
11756 /* 66 0F 62 = PUNPCKLDQ */
11757 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x62) {
11758 delta = dis_SSEint_E_to_G( sorb, delta+2,
11759 "punpckldq",
11760 Iop_InterleaveLO32x4, True );
11761 goto decode_success;
11762 }
11763
11764 /* 66 0F 6C = PUNPCKLQDQ */
11765 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x6C) {
11766 delta = dis_SSEint_E_to_G( sorb, delta+2,
11767 "punpcklqdq",
11768 Iop_InterleaveLO64x2, True );
11769 goto decode_success;
11770 }
11771
11772 /* 66 0F 61 = PUNPCKLWD */
11773 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x61) {
11774 delta = dis_SSEint_E_to_G( sorb, delta+2,
11775 "punpcklwd",
11776 Iop_InterleaveLO16x8, True );
11777 goto decode_success;
11778 }
11779
11780 /* 66 0F EF = PXOR */
11781 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xEF) {
sewardjf0c1c582005-02-07 23:47:38 +000011782 delta = dis_SSE_E_to_G_all( sorb, delta+2, "pxor", Iop_XorV128 );
sewardj9e203592004-12-10 01:48:18 +000011783 goto decode_success;
11784 }
11785
sewardjc9a65702004-07-07 16:32:57 +000011786//-- /* FXSAVE/FXRSTOR m32 -- load/store the FPU/MMX/SSE state. */
11787//-- if (insn[0] == 0x0F && insn[1] == 0xAE
11788//-- && (!epartIsReg(insn[2]))
11789//-- && (gregOfRM(insn[2]) == 1 || gregOfRM(insn[2]) == 0) ) {
11790//-- Bool store = gregOfRM(insn[2]) == 0;
11791//-- vg_assert(sz == 4);
11792//-- pair = disAMode ( cb, sorb, eip+2, dis_buf );
11793//-- t1 = LOW24(pair);
11794//-- eip += 2+HI8(pair);
11795//-- uInstr3(cb, store ? SSE2a_MemWr : SSE2a_MemRd, 512,
11796//-- Lit16, (((UShort)insn[0]) << 8) | (UShort)insn[1],
11797//-- Lit16, (UShort)insn[2],
11798//-- TempReg, t1 );
11799//-- DIP("fx%s %s\n", store ? "save" : "rstor", dis_buf );
11800//-- goto decode_success;
11801//-- }
sewardjc9a65702004-07-07 16:32:57 +000011802
sewardjbfceb082005-11-15 11:16:30 +000011803 /* 0F AE /7 = CLFLUSH -- flush cache line */
11804 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xAE
11805 && !epartIsReg(insn[2]) && gregOfRM(insn[2]) == 7) {
11806
11807 /* This is something of a hack. We need to know the size of the
11808 cache line containing addr. Since we don't (easily), assume
11809 256 on the basis that no real cache would have a line that
11810 big. It's safe to invalidate more stuff than we need, just
11811 inefficient. */
11812 UInt lineszB = 256;
11813
11814 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
11815 delta += 2+alen;
11816
11817 /* Round addr down to the start of the containing block. */
11818 stmt( IRStmt_Put(
sewardj05f5e012014-05-04 10:52:11 +000011819 OFFB_CMSTART,
sewardjbfceb082005-11-15 11:16:30 +000011820 binop( Iop_And32,
11821 mkexpr(addr),
11822 mkU32( ~(lineszB-1) ))) );
11823
sewardj05f5e012014-05-04 10:52:11 +000011824 stmt( IRStmt_Put(OFFB_CMLEN, mkU32(lineszB) ) );
sewardjbfceb082005-11-15 11:16:30 +000011825
sewardj05f5e012014-05-04 10:52:11 +000011826 jmp_lit(&dres, Ijk_InvalICache, (Addr32)(guest_EIP_bbstart+delta));
sewardjbfceb082005-11-15 11:16:30 +000011827
11828 DIP("clflush %s\n", dis_buf);
11829 goto decode_success;
11830 }
sewardjc9a65702004-07-07 16:32:57 +000011831
11832 /* ---------------------------------------------------- */
sewardj90e91ee2005-11-07 14:23:52 +000011833 /* --- end of the SSE2 decoder. --- */
11834 /* ---------------------------------------------------- */
11835
11836 /* ---------------------------------------------------- */
11837 /* --- start of the SSE3 decoder. --- */
11838 /* ---------------------------------------------------- */
11839
11840 /* Skip parts of the decoder which don't apply given the stated
11841 guest subarchitecture. */
florian9f07e862014-12-09 20:09:42 +000011842 if (0 == (archinfo->hwcaps & VEX_HWCAPS_X86_SSE3))
sewardj5117ce12006-01-27 21:20:15 +000011843 goto after_sse_decoders; /* no SSE3 capabilities */
sewardj90e91ee2005-11-07 14:23:52 +000011844
florian8462d112014-09-24 15:18:09 +000011845 insn = &guest_code[delta];
sewardj90e91ee2005-11-07 14:23:52 +000011846
11847 /* F3 0F 12 = MOVSLDUP -- move from E (mem or xmm) to G (xmm),
11848 duplicating some lanes (2:2:0:0). */
11849 /* F3 0F 16 = MOVSHDUP -- move from E (mem or xmm) to G (xmm),
11850 duplicating some lanes (3:3:1:1). */
11851 if (sz == 4 && insn[0] == 0xF3 && insn[1] == 0x0F
11852 && (insn[2] == 0x12 || insn[2] == 0x16)) {
11853 IRTemp s3, s2, s1, s0;
11854 IRTemp sV = newTemp(Ity_V128);
11855 Bool isH = insn[2] == 0x16;
11856 s3 = s2 = s1 = s0 = IRTemp_INVALID;
11857
11858 modrm = insn[3];
11859 if (epartIsReg(modrm)) {
11860 assign( sV, getXMMReg( eregOfRM(modrm)) );
11861 DIP("movs%cdup %s,%s\n", isH ? 'h' : 'l',
11862 nameXMMReg(eregOfRM(modrm)),
11863 nameXMMReg(gregOfRM(modrm)));
11864 delta += 3+1;
11865 } else {
11866 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
sewardj45ca0b92010-09-30 14:51:51 +000011867 gen_SEGV_if_not_16_aligned( addr );
sewardj90e91ee2005-11-07 14:23:52 +000011868 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
11869 DIP("movs%cdup %s,%s\n", isH ? 'h' : 'l',
11870 dis_buf,
11871 nameXMMReg(gregOfRM(modrm)));
11872 delta += 3+alen;
11873 }
11874
11875 breakup128to32s( sV, &s3, &s2, &s1, &s0 );
11876 putXMMReg( gregOfRM(modrm),
11877 isH ? mk128from32s( s3, s3, s1, s1 )
11878 : mk128from32s( s2, s2, s0, s0 ) );
11879 goto decode_success;
11880 }
11881
sewardjdd5d2042006-08-03 15:03:19 +000011882 /* F2 0F 12 = MOVDDUP -- move from E (mem or xmm) to G (xmm),
11883 duplicating some lanes (0:1:0:1). */
11884 if (sz == 4 && insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x12) {
11885 IRTemp sV = newTemp(Ity_V128);
11886 IRTemp d0 = newTemp(Ity_I64);
11887
11888 modrm = insn[3];
11889 if (epartIsReg(modrm)) {
11890 assign( sV, getXMMReg( eregOfRM(modrm)) );
11891 DIP("movddup %s,%s\n", nameXMMReg(eregOfRM(modrm)),
11892 nameXMMReg(gregOfRM(modrm)));
11893 delta += 3+1;
11894 assign ( d0, unop(Iop_V128to64, mkexpr(sV)) );
11895 } else {
11896 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
11897 assign( d0, loadLE(Ity_I64, mkexpr(addr)) );
11898 DIP("movddup %s,%s\n", dis_buf,
11899 nameXMMReg(gregOfRM(modrm)));
11900 delta += 3+alen;
11901 }
11902
11903 putXMMReg( gregOfRM(modrm), binop(Iop_64HLtoV128,mkexpr(d0),mkexpr(d0)) );
11904 goto decode_success;
11905 }
11906
sewardj90e91ee2005-11-07 14:23:52 +000011907 /* F2 0F D0 = ADDSUBPS -- 32x4 +/-/+/- from E (mem or xmm) to G (xmm). */
11908 if (sz == 4 && insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0xD0) {
11909 IRTemp a3, a2, a1, a0, s3, s2, s1, s0;
11910 IRTemp eV = newTemp(Ity_V128);
11911 IRTemp gV = newTemp(Ity_V128);
11912 IRTemp addV = newTemp(Ity_V128);
11913 IRTemp subV = newTemp(Ity_V128);
sewardj9571dc02014-01-26 18:34:23 +000011914 IRTemp rm = newTemp(Ity_I32);
sewardj90e91ee2005-11-07 14:23:52 +000011915 a3 = a2 = a1 = a0 = s3 = s2 = s1 = s0 = IRTemp_INVALID;
11916
11917 modrm = insn[3];
11918 if (epartIsReg(modrm)) {
11919 assign( eV, getXMMReg( eregOfRM(modrm)) );
11920 DIP("addsubps %s,%s\n", nameXMMReg(eregOfRM(modrm)),
11921 nameXMMReg(gregOfRM(modrm)));
11922 delta += 3+1;
11923 } else {
11924 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
11925 assign( eV, loadLE(Ity_V128, mkexpr(addr)) );
11926 DIP("addsubps %s,%s\n", dis_buf,
11927 nameXMMReg(gregOfRM(modrm)));
11928 delta += 3+alen;
11929 }
11930
11931 assign( gV, getXMMReg(gregOfRM(modrm)) );
11932
sewardj9571dc02014-01-26 18:34:23 +000011933 assign( rm, get_FAKE_roundingmode() ); /* XXXROUNDINGFIXME */
11934 assign( addV, triop(Iop_Add32Fx4, mkexpr(rm), mkexpr(gV), mkexpr(eV)) );
11935 assign( subV, triop(Iop_Sub32Fx4, mkexpr(rm), mkexpr(gV), mkexpr(eV)) );
sewardj90e91ee2005-11-07 14:23:52 +000011936
11937 breakup128to32s( addV, &a3, &a2, &a1, &a0 );
11938 breakup128to32s( subV, &s3, &s2, &s1, &s0 );
11939
11940 putXMMReg( gregOfRM(modrm), mk128from32s( a3, s2, a1, s0 ));
11941 goto decode_success;
11942 }
11943
sewardjdd5d2042006-08-03 15:03:19 +000011944 /* 66 0F D0 = ADDSUBPD -- 64x4 +/- from E (mem or xmm) to G (xmm). */
11945 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD0) {
11946 IRTemp eV = newTemp(Ity_V128);
11947 IRTemp gV = newTemp(Ity_V128);
11948 IRTemp addV = newTemp(Ity_V128);
11949 IRTemp subV = newTemp(Ity_V128);
11950 IRTemp a1 = newTemp(Ity_I64);
11951 IRTemp s0 = newTemp(Ity_I64);
sewardj9571dc02014-01-26 18:34:23 +000011952 IRTemp rm = newTemp(Ity_I32);
sewardjdd5d2042006-08-03 15:03:19 +000011953
11954 modrm = insn[2];
11955 if (epartIsReg(modrm)) {
11956 assign( eV, getXMMReg( eregOfRM(modrm)) );
11957 DIP("addsubpd %s,%s\n", nameXMMReg(eregOfRM(modrm)),
11958 nameXMMReg(gregOfRM(modrm)));
11959 delta += 2+1;
11960 } else {
11961 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
11962 assign( eV, loadLE(Ity_V128, mkexpr(addr)) );
11963 DIP("addsubpd %s,%s\n", dis_buf,
11964 nameXMMReg(gregOfRM(modrm)));
11965 delta += 2+alen;
11966 }
11967
11968 assign( gV, getXMMReg(gregOfRM(modrm)) );
11969
sewardj9571dc02014-01-26 18:34:23 +000011970 assign( rm, get_FAKE_roundingmode() ); /* XXXROUNDINGFIXME */
11971 assign( addV, triop(Iop_Add64Fx2, mkexpr(rm), mkexpr(gV), mkexpr(eV)) );
11972 assign( subV, triop(Iop_Sub64Fx2, mkexpr(rm), mkexpr(gV), mkexpr(eV)) );
sewardjdd5d2042006-08-03 15:03:19 +000011973
11974 assign( a1, unop(Iop_V128HIto64, mkexpr(addV) ));
11975 assign( s0, unop(Iop_V128to64, mkexpr(subV) ));
11976
11977 putXMMReg( gregOfRM(modrm),
11978 binop(Iop_64HLtoV128, mkexpr(a1), mkexpr(s0)) );
11979 goto decode_success;
11980 }
11981
11982 /* F2 0F 7D = HSUBPS -- 32x4 sub across from E (mem or xmm) to G (xmm). */
11983 /* F2 0F 7C = HADDPS -- 32x4 add across from E (mem or xmm) to G (xmm). */
11984 if (sz == 4 && insn[0] == 0xF2 && insn[1] == 0x0F
11985 && (insn[2] == 0x7C || insn[2] == 0x7D)) {
11986 IRTemp e3, e2, e1, e0, g3, g2, g1, g0;
11987 IRTemp eV = newTemp(Ity_V128);
11988 IRTemp gV = newTemp(Ity_V128);
11989 IRTemp leftV = newTemp(Ity_V128);
11990 IRTemp rightV = newTemp(Ity_V128);
sewardj9571dc02014-01-26 18:34:23 +000011991 IRTemp rm = newTemp(Ity_I32);
sewardjdd5d2042006-08-03 15:03:19 +000011992 Bool isAdd = insn[2] == 0x7C;
florian55085f82012-11-21 00:36:55 +000011993 const HChar* str = isAdd ? "add" : "sub";
sewardjdd5d2042006-08-03 15:03:19 +000011994 e3 = e2 = e1 = e0 = g3 = g2 = g1 = g0 = IRTemp_INVALID;
11995
11996 modrm = insn[3];
11997 if (epartIsReg(modrm)) {
11998 assign( eV, getXMMReg( eregOfRM(modrm)) );
11999 DIP("h%sps %s,%s\n", str, nameXMMReg(eregOfRM(modrm)),
12000 nameXMMReg(gregOfRM(modrm)));
12001 delta += 3+1;
12002 } else {
12003 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
12004 assign( eV, loadLE(Ity_V128, mkexpr(addr)) );
12005 DIP("h%sps %s,%s\n", str, dis_buf,
12006 nameXMMReg(gregOfRM(modrm)));
12007 delta += 3+alen;
12008 }
12009
12010 assign( gV, getXMMReg(gregOfRM(modrm)) );
12011
12012 breakup128to32s( eV, &e3, &e2, &e1, &e0 );
12013 breakup128to32s( gV, &g3, &g2, &g1, &g0 );
12014
12015 assign( leftV, mk128from32s( e2, e0, g2, g0 ) );
12016 assign( rightV, mk128from32s( e3, e1, g3, g1 ) );
12017
sewardj9571dc02014-01-26 18:34:23 +000012018 assign( rm, get_FAKE_roundingmode() ); /* XXXROUNDINGFIXME */
sewardjdd5d2042006-08-03 15:03:19 +000012019 putXMMReg( gregOfRM(modrm),
sewardj9571dc02014-01-26 18:34:23 +000012020 triop(isAdd ? Iop_Add32Fx4 : Iop_Sub32Fx4,
12021 mkexpr(rm), mkexpr(leftV), mkexpr(rightV) ) );
sewardjdd5d2042006-08-03 15:03:19 +000012022 goto decode_success;
12023 }
12024
12025 /* 66 0F 7D = HSUBPD -- 64x2 sub across from E (mem or xmm) to G (xmm). */
12026 /* 66 0F 7C = HADDPD -- 64x2 add across from E (mem or xmm) to G (xmm). */
12027 if (sz == 2 && insn[0] == 0x0F && (insn[1] == 0x7C || insn[1] == 0x7D)) {
12028 IRTemp e1 = newTemp(Ity_I64);
12029 IRTemp e0 = newTemp(Ity_I64);
12030 IRTemp g1 = newTemp(Ity_I64);
12031 IRTemp g0 = newTemp(Ity_I64);
12032 IRTemp eV = newTemp(Ity_V128);
12033 IRTemp gV = newTemp(Ity_V128);
12034 IRTemp leftV = newTemp(Ity_V128);
12035 IRTemp rightV = newTemp(Ity_V128);
sewardj9571dc02014-01-26 18:34:23 +000012036 IRTemp rm = newTemp(Ity_I32);
sewardjdd5d2042006-08-03 15:03:19 +000012037 Bool isAdd = insn[1] == 0x7C;
florian55085f82012-11-21 00:36:55 +000012038 const HChar* str = isAdd ? "add" : "sub";
sewardjdd5d2042006-08-03 15:03:19 +000012039
12040 modrm = insn[2];
12041 if (epartIsReg(modrm)) {
12042 assign( eV, getXMMReg( eregOfRM(modrm)) );
12043 DIP("h%spd %s,%s\n", str, nameXMMReg(eregOfRM(modrm)),
12044 nameXMMReg(gregOfRM(modrm)));
12045 delta += 2+1;
12046 } else {
12047 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
12048 assign( eV, loadLE(Ity_V128, mkexpr(addr)) );
12049 DIP("h%spd %s,%s\n", str, dis_buf,
12050 nameXMMReg(gregOfRM(modrm)));
12051 delta += 2+alen;
12052 }
12053
12054 assign( gV, getXMMReg(gregOfRM(modrm)) );
12055
12056 assign( e1, unop(Iop_V128HIto64, mkexpr(eV) ));
12057 assign( e0, unop(Iop_V128to64, mkexpr(eV) ));
12058 assign( g1, unop(Iop_V128HIto64, mkexpr(gV) ));
12059 assign( g0, unop(Iop_V128to64, mkexpr(gV) ));
12060
12061 assign( leftV, binop(Iop_64HLtoV128, mkexpr(e0),mkexpr(g0)) );
12062 assign( rightV, binop(Iop_64HLtoV128, mkexpr(e1),mkexpr(g1)) );
12063
sewardj9571dc02014-01-26 18:34:23 +000012064 assign( rm, get_FAKE_roundingmode() ); /* XXXROUNDINGFIXME */
sewardjdd5d2042006-08-03 15:03:19 +000012065 putXMMReg( gregOfRM(modrm),
sewardj9571dc02014-01-26 18:34:23 +000012066 triop(isAdd ? Iop_Add64Fx2 : Iop_Sub64Fx2,
12067 mkexpr(rm), mkexpr(leftV), mkexpr(rightV) ) );
sewardjdd5d2042006-08-03 15:03:19 +000012068 goto decode_success;
12069 }
12070
12071 /* F2 0F F0 = LDDQU -- move from E (mem or xmm) to G (xmm). */
12072 if (sz == 4 && insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0xF0) {
12073 modrm = getIByte(delta+3);
12074 if (epartIsReg(modrm)) {
12075 goto decode_failure;
12076 } else {
12077 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
12078 putXMMReg( gregOfRM(modrm),
12079 loadLE(Ity_V128, mkexpr(addr)) );
12080 DIP("lddqu %s,%s\n", dis_buf,
12081 nameXMMReg(gregOfRM(modrm)));
12082 delta += 3+alen;
12083 }
12084 goto decode_success;
12085 }
12086
sewardj90e91ee2005-11-07 14:23:52 +000012087 /* ---------------------------------------------------- */
12088 /* --- end of the SSE3 decoder. --- */
sewardjc9a65702004-07-07 16:32:57 +000012089 /* ---------------------------------------------------- */
12090
sewardj150c9cd2008-02-09 01:16:02 +000012091 /* ---------------------------------------------------- */
12092 /* --- start of the SSSE3 decoder. --- */
12093 /* ---------------------------------------------------- */
12094
12095 /* 0F 38 04 = PMADDUBSW -- Multiply and Add Packed Signed and
12096 Unsigned Bytes (MMX) */
12097 if (sz == 4
12098 && insn[0] == 0x0F && insn[1] == 0x38 && insn[2] == 0x04) {
12099 IRTemp sV = newTemp(Ity_I64);
12100 IRTemp dV = newTemp(Ity_I64);
12101 IRTemp sVoddsSX = newTemp(Ity_I64);
12102 IRTemp sVevensSX = newTemp(Ity_I64);
12103 IRTemp dVoddsZX = newTemp(Ity_I64);
12104 IRTemp dVevensZX = newTemp(Ity_I64);
12105
12106 modrm = insn[3];
12107 do_MMX_preamble();
12108 assign( dV, getMMXReg(gregOfRM(modrm)) );
12109
12110 if (epartIsReg(modrm)) {
12111 assign( sV, getMMXReg(eregOfRM(modrm)) );
12112 delta += 3+1;
12113 DIP("pmaddubsw %s,%s\n", nameMMXReg(eregOfRM(modrm)),
12114 nameMMXReg(gregOfRM(modrm)));
12115 } else {
12116 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
12117 assign( sV, loadLE(Ity_I64, mkexpr(addr)) );
12118 delta += 3+alen;
12119 DIP("pmaddubsw %s,%s\n", dis_buf,
12120 nameMMXReg(gregOfRM(modrm)));
12121 }
12122
12123 /* compute dV unsigned x sV signed */
12124 assign( sVoddsSX,
12125 binop(Iop_SarN16x4, mkexpr(sV), mkU8(8)) );
12126 assign( sVevensSX,
12127 binop(Iop_SarN16x4,
12128 binop(Iop_ShlN16x4, mkexpr(sV), mkU8(8)),
12129 mkU8(8)) );
12130 assign( dVoddsZX,
12131 binop(Iop_ShrN16x4, mkexpr(dV), mkU8(8)) );
12132 assign( dVevensZX,
12133 binop(Iop_ShrN16x4,
12134 binop(Iop_ShlN16x4, mkexpr(dV), mkU8(8)),
12135 mkU8(8)) );
12136
12137 putMMXReg(
12138 gregOfRM(modrm),
12139 binop(Iop_QAdd16Sx4,
12140 binop(Iop_Mul16x4, mkexpr(sVoddsSX), mkexpr(dVoddsZX)),
12141 binop(Iop_Mul16x4, mkexpr(sVevensSX), mkexpr(dVevensZX))
12142 )
12143 );
12144 goto decode_success;
12145 }
12146
12147 /* 66 0F 38 04 = PMADDUBSW -- Multiply and Add Packed Signed and
12148 Unsigned Bytes (XMM) */
12149 if (sz == 2
12150 && insn[0] == 0x0F && insn[1] == 0x38 && insn[2] == 0x04) {
12151 IRTemp sV = newTemp(Ity_V128);
12152 IRTemp dV = newTemp(Ity_V128);
12153 IRTemp sVoddsSX = newTemp(Ity_V128);
12154 IRTemp sVevensSX = newTemp(Ity_V128);
12155 IRTemp dVoddsZX = newTemp(Ity_V128);
12156 IRTemp dVevensZX = newTemp(Ity_V128);
12157
12158 modrm = insn[3];
12159 assign( dV, getXMMReg(gregOfRM(modrm)) );
12160
12161 if (epartIsReg(modrm)) {
12162 assign( sV, getXMMReg(eregOfRM(modrm)) );
12163 delta += 3+1;
12164 DIP("pmaddubsw %s,%s\n", nameXMMReg(eregOfRM(modrm)),
12165 nameXMMReg(gregOfRM(modrm)));
12166 } else {
12167 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
12168 gen_SEGV_if_not_16_aligned( addr );
12169 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
12170 delta += 3+alen;
12171 DIP("pmaddubsw %s,%s\n", dis_buf,
12172 nameXMMReg(gregOfRM(modrm)));
12173 }
12174
12175 /* compute dV unsigned x sV signed */
12176 assign( sVoddsSX,
12177 binop(Iop_SarN16x8, mkexpr(sV), mkU8(8)) );
12178 assign( sVevensSX,
12179 binop(Iop_SarN16x8,
12180 binop(Iop_ShlN16x8, mkexpr(sV), mkU8(8)),
12181 mkU8(8)) );
12182 assign( dVoddsZX,
12183 binop(Iop_ShrN16x8, mkexpr(dV), mkU8(8)) );
12184 assign( dVevensZX,
12185 binop(Iop_ShrN16x8,
12186 binop(Iop_ShlN16x8, mkexpr(dV), mkU8(8)),
12187 mkU8(8)) );
12188
12189 putXMMReg(
12190 gregOfRM(modrm),
12191 binop(Iop_QAdd16Sx8,
12192 binop(Iop_Mul16x8, mkexpr(sVoddsSX), mkexpr(dVoddsZX)),
12193 binop(Iop_Mul16x8, mkexpr(sVevensSX), mkexpr(dVevensZX))
12194 )
12195 );
12196 goto decode_success;
12197 }
12198
12199 /* ***--- these are MMX class insns introduced in SSSE3 ---*** */
12200 /* 0F 38 03 = PHADDSW -- 16x4 signed qadd across from E (mem or
12201 mmx) and G to G (mmx). */
12202 /* 0F 38 07 = PHSUBSW -- 16x4 signed qsub across from E (mem or
12203 mmx) and G to G (mmx). */
12204 /* 0F 38 01 = PHADDW -- 16x4 add across from E (mem or mmx) and G
12205 to G (mmx). */
12206 /* 0F 38 05 = PHSUBW -- 16x4 sub across from E (mem or mmx) and G
12207 to G (mmx). */
12208 /* 0F 38 02 = PHADDD -- 32x2 add across from E (mem or mmx) and G
12209 to G (mmx). */
12210 /* 0F 38 06 = PHSUBD -- 32x2 sub across from E (mem or mmx) and G
12211 to G (mmx). */
12212
12213 if (sz == 4
12214 && insn[0] == 0x0F && insn[1] == 0x38
12215 && (insn[2] == 0x03 || insn[2] == 0x07 || insn[2] == 0x01
12216 || insn[2] == 0x05 || insn[2] == 0x02 || insn[2] == 0x06)) {
florian55085f82012-11-21 00:36:55 +000012217 const HChar* str = "???";
sewardj150c9cd2008-02-09 01:16:02 +000012218 IROp opV64 = Iop_INVALID;
12219 IROp opCatO = Iop_CatOddLanes16x4;
12220 IROp opCatE = Iop_CatEvenLanes16x4;
12221 IRTemp sV = newTemp(Ity_I64);
12222 IRTemp dV = newTemp(Ity_I64);
12223
12224 modrm = insn[3];
12225
12226 switch (insn[2]) {
12227 case 0x03: opV64 = Iop_QAdd16Sx4; str = "addsw"; break;
12228 case 0x07: opV64 = Iop_QSub16Sx4; str = "subsw"; break;
12229 case 0x01: opV64 = Iop_Add16x4; str = "addw"; break;
12230 case 0x05: opV64 = Iop_Sub16x4; str = "subw"; break;
12231 case 0x02: opV64 = Iop_Add32x2; str = "addd"; break;
12232 case 0x06: opV64 = Iop_Sub32x2; str = "subd"; break;
12233 default: vassert(0);
12234 }
12235 if (insn[2] == 0x02 || insn[2] == 0x06) {
12236 opCatO = Iop_InterleaveHI32x2;
12237 opCatE = Iop_InterleaveLO32x2;
12238 }
12239
12240 do_MMX_preamble();
12241 assign( dV, getMMXReg(gregOfRM(modrm)) );
12242
12243 if (epartIsReg(modrm)) {
12244 assign( sV, getMMXReg(eregOfRM(modrm)) );
12245 delta += 3+1;
12246 DIP("ph%s %s,%s\n", str, nameMMXReg(eregOfRM(modrm)),
12247 nameMMXReg(gregOfRM(modrm)));
12248 } else {
12249 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
12250 assign( sV, loadLE(Ity_I64, mkexpr(addr)) );
12251 delta += 3+alen;
12252 DIP("ph%s %s,%s\n", str, dis_buf,
12253 nameMMXReg(gregOfRM(modrm)));
12254 }
12255
12256 putMMXReg(
12257 gregOfRM(modrm),
12258 binop(opV64,
12259 binop(opCatE,mkexpr(sV),mkexpr(dV)),
12260 binop(opCatO,mkexpr(sV),mkexpr(dV))
12261 )
12262 );
12263 goto decode_success;
12264 }
12265
12266 /* 66 0F 38 03 = PHADDSW -- 16x8 signed qadd across from E (mem or
12267 xmm) and G to G (xmm). */
12268 /* 66 0F 38 07 = PHSUBSW -- 16x8 signed qsub across from E (mem or
12269 xmm) and G to G (xmm). */
12270 /* 66 0F 38 01 = PHADDW -- 16x8 add across from E (mem or xmm) and
12271 G to G (xmm). */
12272 /* 66 0F 38 05 = PHSUBW -- 16x8 sub across from E (mem or xmm) and
12273 G to G (xmm). */
12274 /* 66 0F 38 02 = PHADDD -- 32x4 add across from E (mem or xmm) and
12275 G to G (xmm). */
12276 /* 66 0F 38 06 = PHSUBD -- 32x4 sub across from E (mem or xmm) and
12277 G to G (xmm). */
12278
12279 if (sz == 2
12280 && insn[0] == 0x0F && insn[1] == 0x38
12281 && (insn[2] == 0x03 || insn[2] == 0x07 || insn[2] == 0x01
12282 || insn[2] == 0x05 || insn[2] == 0x02 || insn[2] == 0x06)) {
florian55085f82012-11-21 00:36:55 +000012283 const HChar* str = "???";
sewardj150c9cd2008-02-09 01:16:02 +000012284 IROp opV64 = Iop_INVALID;
12285 IROp opCatO = Iop_CatOddLanes16x4;
12286 IROp opCatE = Iop_CatEvenLanes16x4;
12287 IRTemp sV = newTemp(Ity_V128);
12288 IRTemp dV = newTemp(Ity_V128);
12289 IRTemp sHi = newTemp(Ity_I64);
12290 IRTemp sLo = newTemp(Ity_I64);
12291 IRTemp dHi = newTemp(Ity_I64);
12292 IRTemp dLo = newTemp(Ity_I64);
12293
12294 modrm = insn[3];
12295
12296 switch (insn[2]) {
12297 case 0x03: opV64 = Iop_QAdd16Sx4; str = "addsw"; break;
12298 case 0x07: opV64 = Iop_QSub16Sx4; str = "subsw"; break;
12299 case 0x01: opV64 = Iop_Add16x4; str = "addw"; break;
12300 case 0x05: opV64 = Iop_Sub16x4; str = "subw"; break;
12301 case 0x02: opV64 = Iop_Add32x2; str = "addd"; break;
12302 case 0x06: opV64 = Iop_Sub32x2; str = "subd"; break;
12303 default: vassert(0);
12304 }
12305 if (insn[2] == 0x02 || insn[2] == 0x06) {
12306 opCatO = Iop_InterleaveHI32x2;
12307 opCatE = Iop_InterleaveLO32x2;
12308 }
12309
12310 assign( dV, getXMMReg(gregOfRM(modrm)) );
12311
12312 if (epartIsReg(modrm)) {
12313 assign( sV, getXMMReg( eregOfRM(modrm)) );
12314 DIP("ph%s %s,%s\n", str, nameXMMReg(eregOfRM(modrm)),
12315 nameXMMReg(gregOfRM(modrm)));
12316 delta += 3+1;
12317 } else {
12318 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
12319 gen_SEGV_if_not_16_aligned( addr );
12320 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
12321 DIP("ph%s %s,%s\n", str, dis_buf,
12322 nameXMMReg(gregOfRM(modrm)));
12323 delta += 3+alen;
12324 }
12325
12326 assign( dHi, unop(Iop_V128HIto64, mkexpr(dV)) );
12327 assign( dLo, unop(Iop_V128to64, mkexpr(dV)) );
12328 assign( sHi, unop(Iop_V128HIto64, mkexpr(sV)) );
12329 assign( sLo, unop(Iop_V128to64, mkexpr(sV)) );
12330
12331 /* This isn't a particularly efficient way to compute the
12332 result, but at least it avoids a proliferation of IROps,
12333 hence avoids complication all the backends. */
12334 putXMMReg(
12335 gregOfRM(modrm),
12336 binop(Iop_64HLtoV128,
12337 binop(opV64,
12338 binop(opCatE,mkexpr(sHi),mkexpr(sLo)),
12339 binop(opCatO,mkexpr(sHi),mkexpr(sLo))
12340 ),
12341 binop(opV64,
12342 binop(opCatE,mkexpr(dHi),mkexpr(dLo)),
12343 binop(opCatO,mkexpr(dHi),mkexpr(dLo))
12344 )
12345 )
12346 );
12347 goto decode_success;
12348 }
12349
12350 /* 0F 38 0B = PMULHRSW -- Packed Multiply High with Round and Scale
12351 (MMX) */
12352 if (sz == 4
12353 && insn[0] == 0x0F && insn[1] == 0x38 && insn[2] == 0x0B) {
12354 IRTemp sV = newTemp(Ity_I64);
12355 IRTemp dV = newTemp(Ity_I64);
12356
12357 modrm = insn[3];
12358 do_MMX_preamble();
12359 assign( dV, getMMXReg(gregOfRM(modrm)) );
12360
12361 if (epartIsReg(modrm)) {
12362 assign( sV, getMMXReg(eregOfRM(modrm)) );
12363 delta += 3+1;
12364 DIP("pmulhrsw %s,%s\n", nameMMXReg(eregOfRM(modrm)),
12365 nameMMXReg(gregOfRM(modrm)));
12366 } else {
12367 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
12368 assign( sV, loadLE(Ity_I64, mkexpr(addr)) );
12369 delta += 3+alen;
12370 DIP("pmulhrsw %s,%s\n", dis_buf,
12371 nameMMXReg(gregOfRM(modrm)));
12372 }
12373
12374 putMMXReg(
12375 gregOfRM(modrm),
12376 dis_PMULHRSW_helper( mkexpr(sV), mkexpr(dV) )
12377 );
12378 goto decode_success;
12379 }
12380
12381 /* 66 0F 38 0B = PMULHRSW -- Packed Multiply High with Round and
12382 Scale (XMM) */
12383 if (sz == 2
12384 && insn[0] == 0x0F && insn[1] == 0x38 && insn[2] == 0x0B) {
12385 IRTemp sV = newTemp(Ity_V128);
12386 IRTemp dV = newTemp(Ity_V128);
12387 IRTemp sHi = newTemp(Ity_I64);
12388 IRTemp sLo = newTemp(Ity_I64);
12389 IRTemp dHi = newTemp(Ity_I64);
12390 IRTemp dLo = newTemp(Ity_I64);
12391
12392 modrm = insn[3];
12393 assign( dV, getXMMReg(gregOfRM(modrm)) );
12394
12395 if (epartIsReg(modrm)) {
12396 assign( sV, getXMMReg(eregOfRM(modrm)) );
12397 delta += 3+1;
12398 DIP("pmulhrsw %s,%s\n", nameXMMReg(eregOfRM(modrm)),
12399 nameXMMReg(gregOfRM(modrm)));
12400 } else {
12401 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
12402 gen_SEGV_if_not_16_aligned( addr );
12403 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
12404 delta += 3+alen;
12405 DIP("pmulhrsw %s,%s\n", dis_buf,
12406 nameXMMReg(gregOfRM(modrm)));
12407 }
12408
12409 assign( dHi, unop(Iop_V128HIto64, mkexpr(dV)) );
12410 assign( dLo, unop(Iop_V128to64, mkexpr(dV)) );
12411 assign( sHi, unop(Iop_V128HIto64, mkexpr(sV)) );
12412 assign( sLo, unop(Iop_V128to64, mkexpr(sV)) );
12413
12414 putXMMReg(
12415 gregOfRM(modrm),
12416 binop(Iop_64HLtoV128,
12417 dis_PMULHRSW_helper( mkexpr(sHi), mkexpr(dHi) ),
12418 dis_PMULHRSW_helper( mkexpr(sLo), mkexpr(dLo) )
12419 )
12420 );
12421 goto decode_success;
12422 }
12423
12424 /* 0F 38 08 = PSIGNB -- Packed Sign 8x8 (MMX) */
12425 /* 0F 38 09 = PSIGNW -- Packed Sign 16x4 (MMX) */
12426 /* 0F 38 09 = PSIGND -- Packed Sign 32x2 (MMX) */
12427 if (sz == 4
12428 && insn[0] == 0x0F && insn[1] == 0x38
12429 && (insn[2] == 0x08 || insn[2] == 0x09 || insn[2] == 0x0A)) {
12430 IRTemp sV = newTemp(Ity_I64);
12431 IRTemp dV = newTemp(Ity_I64);
florian55085f82012-11-21 00:36:55 +000012432 const HChar* str = "???";
sewardj150c9cd2008-02-09 01:16:02 +000012433 Int laneszB = 0;
12434
12435 switch (insn[2]) {
12436 case 0x08: laneszB = 1; str = "b"; break;
12437 case 0x09: laneszB = 2; str = "w"; break;
12438 case 0x0A: laneszB = 4; str = "d"; break;
12439 default: vassert(0);
12440 }
12441
12442 modrm = insn[3];
12443 do_MMX_preamble();
12444 assign( dV, getMMXReg(gregOfRM(modrm)) );
12445
12446 if (epartIsReg(modrm)) {
12447 assign( sV, getMMXReg(eregOfRM(modrm)) );
12448 delta += 3+1;
12449 DIP("psign%s %s,%s\n", str, nameMMXReg(eregOfRM(modrm)),
12450 nameMMXReg(gregOfRM(modrm)));
12451 } else {
12452 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
12453 assign( sV, loadLE(Ity_I64, mkexpr(addr)) );
12454 delta += 3+alen;
12455 DIP("psign%s %s,%s\n", str, dis_buf,
12456 nameMMXReg(gregOfRM(modrm)));
12457 }
12458
12459 putMMXReg(
12460 gregOfRM(modrm),
12461 dis_PSIGN_helper( mkexpr(sV), mkexpr(dV), laneszB )
12462 );
12463 goto decode_success;
12464 }
12465
12466 /* 66 0F 38 08 = PSIGNB -- Packed Sign 8x16 (XMM) */
12467 /* 66 0F 38 09 = PSIGNW -- Packed Sign 16x8 (XMM) */
12468 /* 66 0F 38 09 = PSIGND -- Packed Sign 32x4 (XMM) */
12469 if (sz == 2
12470 && insn[0] == 0x0F && insn[1] == 0x38
12471 && (insn[2] == 0x08 || insn[2] == 0x09 || insn[2] == 0x0A)) {
12472 IRTemp sV = newTemp(Ity_V128);
12473 IRTemp dV = newTemp(Ity_V128);
12474 IRTemp sHi = newTemp(Ity_I64);
12475 IRTemp sLo = newTemp(Ity_I64);
12476 IRTemp dHi = newTemp(Ity_I64);
12477 IRTemp dLo = newTemp(Ity_I64);
florian55085f82012-11-21 00:36:55 +000012478 const HChar* str = "???";
sewardj150c9cd2008-02-09 01:16:02 +000012479 Int laneszB = 0;
12480
12481 switch (insn[2]) {
12482 case 0x08: laneszB = 1; str = "b"; break;
12483 case 0x09: laneszB = 2; str = "w"; break;
12484 case 0x0A: laneszB = 4; str = "d"; break;
12485 default: vassert(0);
12486 }
12487
12488 modrm = insn[3];
12489 assign( dV, getXMMReg(gregOfRM(modrm)) );
12490
12491 if (epartIsReg(modrm)) {
12492 assign( sV, getXMMReg(eregOfRM(modrm)) );
12493 delta += 3+1;
12494 DIP("psign%s %s,%s\n", str, nameXMMReg(eregOfRM(modrm)),
12495 nameXMMReg(gregOfRM(modrm)));
12496 } else {
12497 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
12498 gen_SEGV_if_not_16_aligned( addr );
12499 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
12500 delta += 3+alen;
12501 DIP("psign%s %s,%s\n", str, dis_buf,
12502 nameXMMReg(gregOfRM(modrm)));
12503 }
12504
12505 assign( dHi, unop(Iop_V128HIto64, mkexpr(dV)) );
12506 assign( dLo, unop(Iop_V128to64, mkexpr(dV)) );
12507 assign( sHi, unop(Iop_V128HIto64, mkexpr(sV)) );
12508 assign( sLo, unop(Iop_V128to64, mkexpr(sV)) );
12509
12510 putXMMReg(
12511 gregOfRM(modrm),
12512 binop(Iop_64HLtoV128,
12513 dis_PSIGN_helper( mkexpr(sHi), mkexpr(dHi), laneszB ),
12514 dis_PSIGN_helper( mkexpr(sLo), mkexpr(dLo), laneszB )
12515 )
12516 );
12517 goto decode_success;
12518 }
12519
12520 /* 0F 38 1C = PABSB -- Packed Absolute Value 8x8 (MMX) */
12521 /* 0F 38 1D = PABSW -- Packed Absolute Value 16x4 (MMX) */
12522 /* 0F 38 1E = PABSD -- Packed Absolute Value 32x2 (MMX) */
12523 if (sz == 4
12524 && insn[0] == 0x0F && insn[1] == 0x38
12525 && (insn[2] == 0x1C || insn[2] == 0x1D || insn[2] == 0x1E)) {
12526 IRTemp sV = newTemp(Ity_I64);
florian55085f82012-11-21 00:36:55 +000012527 const HChar* str = "???";
sewardj150c9cd2008-02-09 01:16:02 +000012528 Int laneszB = 0;
12529
12530 switch (insn[2]) {
12531 case 0x1C: laneszB = 1; str = "b"; break;
12532 case 0x1D: laneszB = 2; str = "w"; break;
12533 case 0x1E: laneszB = 4; str = "d"; break;
12534 default: vassert(0);
12535 }
12536
12537 modrm = insn[3];
12538 do_MMX_preamble();
12539
12540 if (epartIsReg(modrm)) {
12541 assign( sV, getMMXReg(eregOfRM(modrm)) );
12542 delta += 3+1;
12543 DIP("pabs%s %s,%s\n", str, nameMMXReg(eregOfRM(modrm)),
12544 nameMMXReg(gregOfRM(modrm)));
12545 } else {
12546 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
12547 assign( sV, loadLE(Ity_I64, mkexpr(addr)) );
12548 delta += 3+alen;
12549 DIP("pabs%s %s,%s\n", str, dis_buf,
12550 nameMMXReg(gregOfRM(modrm)));
12551 }
12552
12553 putMMXReg(
12554 gregOfRM(modrm),
12555 dis_PABS_helper( mkexpr(sV), laneszB )
12556 );
12557 goto decode_success;
12558 }
12559
12560 /* 66 0F 38 1C = PABSB -- Packed Absolute Value 8x16 (XMM) */
12561 /* 66 0F 38 1D = PABSW -- Packed Absolute Value 16x8 (XMM) */
12562 /* 66 0F 38 1E = PABSD -- Packed Absolute Value 32x4 (XMM) */
12563 if (sz == 2
12564 && insn[0] == 0x0F && insn[1] == 0x38
12565 && (insn[2] == 0x1C || insn[2] == 0x1D || insn[2] == 0x1E)) {
12566 IRTemp sV = newTemp(Ity_V128);
12567 IRTemp sHi = newTemp(Ity_I64);
12568 IRTemp sLo = newTemp(Ity_I64);
florian55085f82012-11-21 00:36:55 +000012569 const HChar* str = "???";
sewardj150c9cd2008-02-09 01:16:02 +000012570 Int laneszB = 0;
12571
12572 switch (insn[2]) {
12573 case 0x1C: laneszB = 1; str = "b"; break;
12574 case 0x1D: laneszB = 2; str = "w"; break;
12575 case 0x1E: laneszB = 4; str = "d"; break;
12576 default: vassert(0);
12577 }
12578
12579 modrm = insn[3];
12580
12581 if (epartIsReg(modrm)) {
12582 assign( sV, getXMMReg(eregOfRM(modrm)) );
12583 delta += 3+1;
12584 DIP("pabs%s %s,%s\n", str, nameXMMReg(eregOfRM(modrm)),
12585 nameXMMReg(gregOfRM(modrm)));
12586 } else {
12587 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
12588 gen_SEGV_if_not_16_aligned( addr );
12589 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
12590 delta += 3+alen;
12591 DIP("pabs%s %s,%s\n", str, dis_buf,
12592 nameXMMReg(gregOfRM(modrm)));
12593 }
12594
12595 assign( sHi, unop(Iop_V128HIto64, mkexpr(sV)) );
12596 assign( sLo, unop(Iop_V128to64, mkexpr(sV)) );
12597
12598 putXMMReg(
12599 gregOfRM(modrm),
12600 binop(Iop_64HLtoV128,
12601 dis_PABS_helper( mkexpr(sHi), laneszB ),
12602 dis_PABS_helper( mkexpr(sLo), laneszB )
12603 )
12604 );
12605 goto decode_success;
12606 }
12607
12608 /* 0F 3A 0F = PALIGNR -- Packed Align Right (MMX) */
12609 if (sz == 4
12610 && insn[0] == 0x0F && insn[1] == 0x3A && insn[2] == 0x0F) {
12611 IRTemp sV = newTemp(Ity_I64);
12612 IRTemp dV = newTemp(Ity_I64);
12613 IRTemp res = newTemp(Ity_I64);
12614
12615 modrm = insn[3];
12616 do_MMX_preamble();
12617 assign( dV, getMMXReg(gregOfRM(modrm)) );
12618
12619 if (epartIsReg(modrm)) {
12620 assign( sV, getMMXReg(eregOfRM(modrm)) );
12621 d32 = (UInt)insn[3+1];
12622 delta += 3+1+1;
florianb1737742015-08-03 16:03:13 +000012623 DIP("palignr $%u,%s,%s\n", d32,
sewardj150c9cd2008-02-09 01:16:02 +000012624 nameMMXReg(eregOfRM(modrm)),
12625 nameMMXReg(gregOfRM(modrm)));
12626 } else {
12627 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
12628 assign( sV, loadLE(Ity_I64, mkexpr(addr)) );
12629 d32 = (UInt)insn[3+alen];
12630 delta += 3+alen+1;
florianb1737742015-08-03 16:03:13 +000012631 DIP("palignr $%u%s,%s\n", d32,
sewardj150c9cd2008-02-09 01:16:02 +000012632 dis_buf,
12633 nameMMXReg(gregOfRM(modrm)));
12634 }
12635
12636 if (d32 == 0) {
12637 assign( res, mkexpr(sV) );
12638 }
12639 else if (d32 >= 1 && d32 <= 7) {
12640 assign(res,
12641 binop(Iop_Or64,
12642 binop(Iop_Shr64, mkexpr(sV), mkU8(8*d32)),
12643 binop(Iop_Shl64, mkexpr(dV), mkU8(8*(8-d32))
12644 )));
12645 }
12646 else if (d32 == 8) {
12647 assign( res, mkexpr(dV) );
12648 }
12649 else if (d32 >= 9 && d32 <= 15) {
12650 assign( res, binop(Iop_Shr64, mkexpr(dV), mkU8(8*(d32-8))) );
12651 }
12652 else if (d32 >= 16 && d32 <= 255) {
12653 assign( res, mkU64(0) );
12654 }
12655 else
12656 vassert(0);
12657
12658 putMMXReg( gregOfRM(modrm), mkexpr(res) );
12659 goto decode_success;
12660 }
12661
12662 /* 66 0F 3A 0F = PALIGNR -- Packed Align Right (XMM) */
12663 if (sz == 2
12664 && insn[0] == 0x0F && insn[1] == 0x3A && insn[2] == 0x0F) {
12665 IRTemp sV = newTemp(Ity_V128);
12666 IRTemp dV = newTemp(Ity_V128);
12667 IRTemp sHi = newTemp(Ity_I64);
12668 IRTemp sLo = newTemp(Ity_I64);
12669 IRTemp dHi = newTemp(Ity_I64);
12670 IRTemp dLo = newTemp(Ity_I64);
12671 IRTemp rHi = newTemp(Ity_I64);
12672 IRTemp rLo = newTemp(Ity_I64);
12673
12674 modrm = insn[3];
12675 assign( dV, getXMMReg(gregOfRM(modrm)) );
12676
12677 if (epartIsReg(modrm)) {
12678 assign( sV, getXMMReg(eregOfRM(modrm)) );
12679 d32 = (UInt)insn[3+1];
12680 delta += 3+1+1;
florianb1737742015-08-03 16:03:13 +000012681 DIP("palignr $%u,%s,%s\n", d32,
sewardj150c9cd2008-02-09 01:16:02 +000012682 nameXMMReg(eregOfRM(modrm)),
12683 nameXMMReg(gregOfRM(modrm)));
12684 } else {
12685 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
12686 gen_SEGV_if_not_16_aligned( addr );
12687 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
12688 d32 = (UInt)insn[3+alen];
12689 delta += 3+alen+1;
florianb1737742015-08-03 16:03:13 +000012690 DIP("palignr $%u,%s,%s\n", d32,
sewardj150c9cd2008-02-09 01:16:02 +000012691 dis_buf,
12692 nameXMMReg(gregOfRM(modrm)));
12693 }
12694
12695 assign( dHi, unop(Iop_V128HIto64, mkexpr(dV)) );
12696 assign( dLo, unop(Iop_V128to64, mkexpr(dV)) );
12697 assign( sHi, unop(Iop_V128HIto64, mkexpr(sV)) );
12698 assign( sLo, unop(Iop_V128to64, mkexpr(sV)) );
12699
12700 if (d32 == 0) {
12701 assign( rHi, mkexpr(sHi) );
12702 assign( rLo, mkexpr(sLo) );
12703 }
12704 else if (d32 >= 1 && d32 <= 7) {
12705 assign( rHi, dis_PALIGNR_XMM_helper(dLo, sHi, d32) );
12706 assign( rLo, dis_PALIGNR_XMM_helper(sHi, sLo, d32) );
12707 }
12708 else if (d32 == 8) {
12709 assign( rHi, mkexpr(dLo) );
12710 assign( rLo, mkexpr(sHi) );
12711 }
12712 else if (d32 >= 9 && d32 <= 15) {
12713 assign( rHi, dis_PALIGNR_XMM_helper(dHi, dLo, d32-8) );
12714 assign( rLo, dis_PALIGNR_XMM_helper(dLo, sHi, d32-8) );
12715 }
12716 else if (d32 == 16) {
12717 assign( rHi, mkexpr(dHi) );
12718 assign( rLo, mkexpr(dLo) );
12719 }
12720 else if (d32 >= 17 && d32 <= 23) {
12721 assign( rHi, binop(Iop_Shr64, mkexpr(dHi), mkU8(8*(d32-16))) );
12722 assign( rLo, dis_PALIGNR_XMM_helper(dHi, dLo, d32-16) );
12723 }
12724 else if (d32 == 24) {
12725 assign( rHi, mkU64(0) );
12726 assign( rLo, mkexpr(dHi) );
12727 }
12728 else if (d32 >= 25 && d32 <= 31) {
12729 assign( rHi, mkU64(0) );
12730 assign( rLo, binop(Iop_Shr64, mkexpr(dHi), mkU8(8*(d32-24))) );
12731 }
12732 else if (d32 >= 32 && d32 <= 255) {
12733 assign( rHi, mkU64(0) );
12734 assign( rLo, mkU64(0) );
12735 }
12736 else
12737 vassert(0);
12738
12739 putXMMReg(
12740 gregOfRM(modrm),
12741 binop(Iop_64HLtoV128, mkexpr(rHi), mkexpr(rLo))
12742 );
12743 goto decode_success;
12744 }
12745
12746 /* 0F 38 00 = PSHUFB -- Packed Shuffle Bytes 8x8 (MMX) */
12747 if (sz == 4
12748 && insn[0] == 0x0F && insn[1] == 0x38 && insn[2] == 0x00) {
12749 IRTemp sV = newTemp(Ity_I64);
12750 IRTemp dV = newTemp(Ity_I64);
12751
12752 modrm = insn[3];
12753 do_MMX_preamble();
12754 assign( dV, getMMXReg(gregOfRM(modrm)) );
12755
12756 if (epartIsReg(modrm)) {
12757 assign( sV, getMMXReg(eregOfRM(modrm)) );
12758 delta += 3+1;
12759 DIP("pshufb %s,%s\n", nameMMXReg(eregOfRM(modrm)),
12760 nameMMXReg(gregOfRM(modrm)));
12761 } else {
12762 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
12763 assign( sV, loadLE(Ity_I64, mkexpr(addr)) );
12764 delta += 3+alen;
12765 DIP("pshufb %s,%s\n", dis_buf,
12766 nameMMXReg(gregOfRM(modrm)));
12767 }
12768
12769 putMMXReg(
12770 gregOfRM(modrm),
12771 binop(
12772 Iop_And64,
12773 /* permute the lanes */
12774 binop(
12775 Iop_Perm8x8,
12776 mkexpr(dV),
12777 binop(Iop_And64, mkexpr(sV), mkU64(0x0707070707070707ULL))
12778 ),
12779 /* mask off lanes which have (index & 0x80) == 0x80 */
12780 unop(Iop_Not64, binop(Iop_SarN8x8, mkexpr(sV), mkU8(7)))
12781 )
12782 );
12783 goto decode_success;
12784 }
12785
12786 /* 66 0F 38 00 = PSHUFB -- Packed Shuffle Bytes 8x16 (XMM) */
12787 if (sz == 2
12788 && insn[0] == 0x0F && insn[1] == 0x38 && insn[2] == 0x00) {
12789 IRTemp sV = newTemp(Ity_V128);
12790 IRTemp dV = newTemp(Ity_V128);
12791 IRTemp sHi = newTemp(Ity_I64);
12792 IRTemp sLo = newTemp(Ity_I64);
12793 IRTemp dHi = newTemp(Ity_I64);
12794 IRTemp dLo = newTemp(Ity_I64);
12795 IRTemp rHi = newTemp(Ity_I64);
12796 IRTemp rLo = newTemp(Ity_I64);
12797 IRTemp sevens = newTemp(Ity_I64);
12798 IRTemp mask0x80hi = newTemp(Ity_I64);
12799 IRTemp mask0x80lo = newTemp(Ity_I64);
12800 IRTemp maskBit3hi = newTemp(Ity_I64);
12801 IRTemp maskBit3lo = newTemp(Ity_I64);
12802 IRTemp sAnd7hi = newTemp(Ity_I64);
12803 IRTemp sAnd7lo = newTemp(Ity_I64);
12804 IRTemp permdHi = newTemp(Ity_I64);
12805 IRTemp permdLo = newTemp(Ity_I64);
12806
12807 modrm = insn[3];
12808 assign( dV, getXMMReg(gregOfRM(modrm)) );
12809
12810 if (epartIsReg(modrm)) {
12811 assign( sV, getXMMReg(eregOfRM(modrm)) );
12812 delta += 3+1;
12813 DIP("pshufb %s,%s\n", nameXMMReg(eregOfRM(modrm)),
12814 nameXMMReg(gregOfRM(modrm)));
12815 } else {
12816 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
12817 gen_SEGV_if_not_16_aligned( addr );
12818 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
12819 delta += 3+alen;
12820 DIP("pshufb %s,%s\n", dis_buf,
12821 nameXMMReg(gregOfRM(modrm)));
12822 }
12823
12824 assign( dHi, unop(Iop_V128HIto64, mkexpr(dV)) );
12825 assign( dLo, unop(Iop_V128to64, mkexpr(dV)) );
12826 assign( sHi, unop(Iop_V128HIto64, mkexpr(sV)) );
12827 assign( sLo, unop(Iop_V128to64, mkexpr(sV)) );
12828
12829 assign( sevens, mkU64(0x0707070707070707ULL) );
12830
12831 /*
12832 mask0x80hi = Not(SarN8x8(sHi,7))
12833 maskBit3hi = SarN8x8(ShlN8x8(sHi,4),7)
12834 sAnd7hi = And(sHi,sevens)
12835 permdHi = Or( And(Perm8x8(dHi,sAnd7hi),maskBit3hi),
12836 And(Perm8x8(dLo,sAnd7hi),Not(maskBit3hi)) )
12837 rHi = And(permdHi,mask0x80hi)
12838 */
12839 assign(
12840 mask0x80hi,
12841 unop(Iop_Not64, binop(Iop_SarN8x8,mkexpr(sHi),mkU8(7))));
12842
12843 assign(
12844 maskBit3hi,
12845 binop(Iop_SarN8x8,
12846 binop(Iop_ShlN8x8,mkexpr(sHi),mkU8(4)),
12847 mkU8(7)));
12848
12849 assign(sAnd7hi, binop(Iop_And64,mkexpr(sHi),mkexpr(sevens)));
12850
12851 assign(
12852 permdHi,
12853 binop(
12854 Iop_Or64,
12855 binop(Iop_And64,
12856 binop(Iop_Perm8x8,mkexpr(dHi),mkexpr(sAnd7hi)),
12857 mkexpr(maskBit3hi)),
12858 binop(Iop_And64,
12859 binop(Iop_Perm8x8,mkexpr(dLo),mkexpr(sAnd7hi)),
12860 unop(Iop_Not64,mkexpr(maskBit3hi))) ));
12861
12862 assign(rHi, binop(Iop_And64,mkexpr(permdHi),mkexpr(mask0x80hi)) );
12863
12864 /* And the same for the lower half of the result. What fun. */
12865
12866 assign(
12867 mask0x80lo,
12868 unop(Iop_Not64, binop(Iop_SarN8x8,mkexpr(sLo),mkU8(7))));
12869
12870 assign(
12871 maskBit3lo,
12872 binop(Iop_SarN8x8,
12873 binop(Iop_ShlN8x8,mkexpr(sLo),mkU8(4)),
12874 mkU8(7)));
12875
12876 assign(sAnd7lo, binop(Iop_And64,mkexpr(sLo),mkexpr(sevens)));
12877
12878 assign(
12879 permdLo,
12880 binop(
12881 Iop_Or64,
12882 binop(Iop_And64,
12883 binop(Iop_Perm8x8,mkexpr(dHi),mkexpr(sAnd7lo)),
12884 mkexpr(maskBit3lo)),
12885 binop(Iop_And64,
12886 binop(Iop_Perm8x8,mkexpr(dLo),mkexpr(sAnd7lo)),
12887 unop(Iop_Not64,mkexpr(maskBit3lo))) ));
12888
12889 assign(rLo, binop(Iop_And64,mkexpr(permdLo),mkexpr(mask0x80lo)) );
12890
12891 putXMMReg(
12892 gregOfRM(modrm),
12893 binop(Iop_64HLtoV128, mkexpr(rHi), mkexpr(rLo))
12894 );
12895 goto decode_success;
12896 }
sewardj021f6b42012-08-23 23:39:49 +000012897
12898 /* 0F 38 F0 = MOVBE m16/32(E), r16/32(G) */
12899 /* 0F 38 F1 = MOVBE r16/32(G), m16/32(E) */
12900 if ((sz == 2 || sz == 4)
12901 && insn[0] == 0x0F && insn[1] == 0x38
12902 && (insn[2] == 0xF0 || insn[2] == 0xF1)
12903 && !epartIsReg(insn[3])) {
12904
12905 modrm = insn[3];
12906 addr = disAMode(&alen, sorb, delta + 3, dis_buf);
12907 delta += 3 + alen;
12908 ty = szToITy(sz);
12909 IRTemp src = newTemp(ty);
12910
12911 if (insn[2] == 0xF0) { /* LOAD */
12912 assign(src, loadLE(ty, mkexpr(addr)));
12913 IRTemp dst = math_BSWAP(src, ty);
12914 putIReg(sz, gregOfRM(modrm), mkexpr(dst));
12915 DIP("movbe %s,%s\n", dis_buf, nameIReg(sz, gregOfRM(modrm)));
12916 } else { /* STORE */
12917 assign(src, getIReg(sz, gregOfRM(modrm)));
12918 IRTemp dst = math_BSWAP(src, ty);
12919 storeLE(mkexpr(addr), mkexpr(dst));
12920 DIP("movbe %s,%s\n", nameIReg(sz, gregOfRM(modrm)), dis_buf);
12921 }
12922 goto decode_success;
12923 }
sewardj150c9cd2008-02-09 01:16:02 +000012924
12925 /* ---------------------------------------------------- */
12926 /* --- end of the SSSE3 decoder. --- */
12927 /* ---------------------------------------------------- */
12928
sewardjb7271612010-07-23 21:23:25 +000012929 /* ---------------------------------------------------- */
12930 /* --- start of the SSE4 decoder --- */
12931 /* ---------------------------------------------------- */
12932
12933 /* 66 0F 3A 0B /r ib = ROUNDSD imm8, xmm2/m64, xmm1
12934 (Partial implementation only -- only deal with cases where
12935 the rounding mode is specified directly by the immediate byte.)
12936 66 0F 3A 0A /r ib = ROUNDSS imm8, xmm2/m32, xmm1
12937 (Limitations ditto)
12938 */
12939 if (sz == 2
12940 && insn[0] == 0x0F && insn[1] == 0x3A
rhyskidde66a2472015-08-15 07:39:27 +000012941 && (insn[2] == 0x0B || insn[2] == 0x0A)) {
sewardjb7271612010-07-23 21:23:25 +000012942
12943 Bool isD = insn[2] == 0x0B;
12944 IRTemp src = newTemp(isD ? Ity_F64 : Ity_F32);
12945 IRTemp res = newTemp(isD ? Ity_F64 : Ity_F32);
12946 Int imm = 0;
12947
12948 modrm = insn[3];
12949
12950 if (epartIsReg(modrm)) {
12951 assign( src,
12952 isD ? getXMMRegLane64F( eregOfRM(modrm), 0 )
12953 : getXMMRegLane32F( eregOfRM(modrm), 0 ) );
12954 imm = insn[3+1];
12955 if (imm & ~3) goto decode_failure;
12956 delta += 3+1+1;
12957 DIP( "rounds%c $%d,%s,%s\n",
12958 isD ? 'd' : 's',
12959 imm, nameXMMReg( eregOfRM(modrm) ),
12960 nameXMMReg( gregOfRM(modrm) ) );
12961 } else {
12962 addr = disAMode( &alen, sorb, delta+3, dis_buf );
12963 assign( src, loadLE( isD ? Ity_F64 : Ity_F32, mkexpr(addr) ));
12964 imm = insn[3+alen];
12965 if (imm & ~3) goto decode_failure;
12966 delta += 3+alen+1;
12967 DIP( "roundsd $%d,%s,%s\n",
12968 imm, dis_buf, nameXMMReg( gregOfRM(modrm) ) );
12969 }
12970
12971 /* (imm & 3) contains an Intel-encoded rounding mode. Because
12972 that encoding is the same as the encoding for IRRoundingMode,
12973 we can use that value directly in the IR as a rounding
12974 mode. */
12975 assign(res, binop(isD ? Iop_RoundF64toInt : Iop_RoundF32toInt,
12976 mkU32(imm & 3), mkexpr(src)) );
12977
12978 if (isD)
12979 putXMMRegLane64F( gregOfRM(modrm), 0, mkexpr(res) );
12980 else
12981 putXMMRegLane32F( gregOfRM(modrm), 0, mkexpr(res) );
12982
12983 goto decode_success;
12984 }
12985
sewardj536fbab2010-07-29 15:39:05 +000012986 /* F3 0F BD -- LZCNT (count leading zeroes. An AMD extension,
12987 which we can only decode if we're sure this is an AMD cpu that
12988 supports LZCNT, since otherwise it's BSR, which behaves
12989 differently. */
12990 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0xBD
12991 && 0 != (archinfo->hwcaps & VEX_HWCAPS_X86_LZCNT)) {
sewardj9a660ea2010-07-29 11:34:38 +000012992 vassert(sz == 2 || sz == 4);
12993 /*IRType*/ ty = szToITy(sz);
12994 IRTemp src = newTemp(ty);
12995 modrm = insn[3];
12996 if (epartIsReg(modrm)) {
12997 assign(src, getIReg(sz, eregOfRM(modrm)));
12998 delta += 3+1;
12999 DIP("lzcnt%c %s, %s\n", nameISize(sz),
13000 nameIReg(sz, eregOfRM(modrm)),
13001 nameIReg(sz, gregOfRM(modrm)));
13002 } else {
13003 addr = disAMode( &alen, sorb, delta+3, dis_buf );
13004 assign(src, loadLE(ty, mkexpr(addr)));
13005 delta += 3+alen;
13006 DIP("lzcnt%c %s, %s\n", nameISize(sz), dis_buf,
13007 nameIReg(sz, gregOfRM(modrm)));
13008 }
13009
13010 IRTemp res = gen_LZCNT(ty, src);
13011 putIReg(sz, gregOfRM(modrm), mkexpr(res));
13012
13013 // Update flags. This is pretty lame .. perhaps can do better
13014 // if this turns out to be performance critical.
13015 // O S A P are cleared. Z is set if RESULT == 0.
13016 // C is set if SRC is zero.
13017 IRTemp src32 = newTemp(Ity_I32);
13018 IRTemp res32 = newTemp(Ity_I32);
13019 assign(src32, widenUto32(mkexpr(src)));
13020 assign(res32, widenUto32(mkexpr(res)));
13021
13022 IRTemp oszacp = newTemp(Ity_I32);
13023 assign(
13024 oszacp,
13025 binop(Iop_Or32,
13026 binop(Iop_Shl32,
13027 unop(Iop_1Uto32,
13028 binop(Iop_CmpEQ32, mkexpr(res32), mkU32(0))),
13029 mkU8(X86G_CC_SHIFT_Z)),
13030 binop(Iop_Shl32,
13031 unop(Iop_1Uto32,
13032 binop(Iop_CmpEQ32, mkexpr(src32), mkU32(0))),
13033 mkU8(X86G_CC_SHIFT_C))
13034 )
13035 );
13036
13037 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(X86G_CC_OP_COPY) ));
13038 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
13039 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
13040 stmt( IRStmt_Put( OFFB_CC_DEP1, mkexpr(oszacp) ));
13041
13042 goto decode_success;
13043 }
13044
sewardjb7271612010-07-23 21:23:25 +000013045 /* ---------------------------------------------------- */
13046 /* --- end of the SSE4 decoder --- */
13047 /* ---------------------------------------------------- */
13048
sewardj9df271d2004-12-31 22:37:42 +000013049 after_sse_decoders:
13050
sewardjdc5d0842006-11-16 10:42:02 +000013051 /* ---------------------------------------------------- */
13052 /* --- deal with misc 0x67 pfxs (addr size override) -- */
13053 /* ---------------------------------------------------- */
13054
13055 /* 67 E3 = JCXZ (for JECXZ see below) */
13056 if (insn[0] == 0x67 && insn[1] == 0xE3 && sz == 4) {
13057 delta += 2;
13058 d32 = (((Addr32)guest_EIP_bbstart)+delta+1) + getSDisp8(delta);
13059 delta ++;
13060 stmt( IRStmt_Exit(
13061 binop(Iop_CmpEQ16, getIReg(2,R_ECX), mkU16(0)),
13062 Ijk_Boring,
sewardjc6f970f2012-04-02 21:54:49 +000013063 IRConst_U32(d32),
13064 OFFB_EIP
sewardjdc5d0842006-11-16 10:42:02 +000013065 ));
13066 DIP("jcxz 0x%x\n", d32);
13067 goto decode_success;
13068 }
13069
13070 /* ---------------------------------------------------- */
13071 /* --- start of the baseline insn decoder -- */
13072 /* ---------------------------------------------------- */
13073
sewardjc9a65702004-07-07 16:32:57 +000013074 /* Get the primary opcode. */
13075 opc = getIByte(delta); delta++;
13076
13077 /* We get here if the current insn isn't SSE, or this CPU doesn't
13078 support SSE. */
13079
13080 switch (opc) {
13081
13082 /* ------------------------ Control flow --------------- */
sewardj940e8c92004-07-11 16:53:24 +000013083
13084 case 0xC2: /* RET imm16 */
13085 d32 = getUDisp16(delta);
13086 delta += 2;
sewardjc6f970f2012-04-02 21:54:49 +000013087 dis_ret(&dres, d32);
florianb1737742015-08-03 16:03:13 +000013088 DIP("ret %u\n", d32);
sewardj940e8c92004-07-11 16:53:24 +000013089 break;
sewardje05c42c2004-07-08 20:25:10 +000013090 case 0xC3: /* RET */
sewardjc6f970f2012-04-02 21:54:49 +000013091 dis_ret(&dres, 0);
sewardje05c42c2004-07-08 20:25:10 +000013092 DIP("ret\n");
13093 break;
sewardj0e9a0f52008-01-04 01:22:41 +000013094
13095 case 0xCF: /* IRET */
13096 /* Note, this is an extremely kludgey and limited implementation
13097 of iret. All it really does is:
13098 popl %EIP; popl %CS; popl %EFLAGS.
13099 %CS is set but ignored (as it is in (eg) popw %cs)". */
13100 t1 = newTemp(Ity_I32); /* ESP */
13101 t2 = newTemp(Ity_I32); /* new EIP */
13102 t3 = newTemp(Ity_I32); /* new CS */
13103 t4 = newTemp(Ity_I32); /* new EFLAGS */
13104 assign(t1, getIReg(4,R_ESP));
13105 assign(t2, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t1),mkU32(0) )));
13106 assign(t3, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t1),mkU32(4) )));
13107 assign(t4, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t1),mkU32(8) )));
13108 /* Get stuff off stack */
13109 putIReg(4, R_ESP,binop(Iop_Add32, mkexpr(t1), mkU32(12)));
13110 /* set %CS (which is ignored anyway) */
13111 putSReg( R_CS, unop(Iop_32to16, mkexpr(t3)) );
13112 /* set %EFLAGS */
13113 set_EFLAGS_from_value( t4, False/*!emit_AC_emwarn*/, 0/*unused*/ );
13114 /* goto new EIP value */
sewardjc6f970f2012-04-02 21:54:49 +000013115 jmp_treg(&dres, Ijk_Ret, t2);
13116 vassert(dres.whatNext == Dis_StopHere);
sewardj0e9a0f52008-01-04 01:22:41 +000013117 DIP("iret (very kludgey)\n");
13118 break;
13119
sewardjd1061ab2004-07-08 01:45:30 +000013120 case 0xE8: /* CALL J4 */
13121 d32 = getUDisp32(delta); delta += 4;
sewardj9e6491a2005-07-02 19:24:10 +000013122 d32 += (guest_EIP_bbstart+delta);
sewardjce70a5c2004-10-18 14:09:54 +000013123 /* (guest_eip_bbstart+delta) == return-to addr, d32 == call-to addr */
sewardj9e6491a2005-07-02 19:24:10 +000013124 if (d32 == guest_EIP_bbstart+delta && getIByte(delta) >= 0x58
sewardjce70a5c2004-10-18 14:09:54 +000013125 && getIByte(delta) <= 0x5F) {
sewardjd1061ab2004-07-08 01:45:30 +000013126 /* Specially treat the position-independent-code idiom
13127 call X
13128 X: popl %reg
13129 as
13130 movl %eip, %reg.
13131 since this generates better code, but for no other reason. */
13132 Int archReg = getIByte(delta) - 0x58;
sewardjc2ac51e2004-07-12 01:03:26 +000013133 /* vex_printf("-- fPIC thingy\n"); */
sewardj9e6491a2005-07-02 19:24:10 +000013134 putIReg(4, archReg, mkU32(guest_EIP_bbstart+delta));
sewardjd1061ab2004-07-08 01:45:30 +000013135 delta++; /* Step over the POP */
13136 DIP("call 0x%x ; popl %s\n",d32,nameIReg(4,archReg));
sewardjc2ac51e2004-07-12 01:03:26 +000013137 } else {
sewardjd1061ab2004-07-08 01:45:30 +000013138 /* The normal sequence for a call. */
13139 t1 = newTemp(Ity_I32);
sewardj41f43bc2004-07-08 14:23:22 +000013140 assign(t1, binop(Iop_Sub32, getIReg(4,R_ESP), mkU32(4)));
13141 putIReg(4, R_ESP, mkexpr(t1));
sewardj9e6491a2005-07-02 19:24:10 +000013142 storeLE( mkexpr(t1), mkU32(guest_EIP_bbstart+delta));
florianbeac5302014-12-31 12:09:38 +000013143 if (resteerOkFn( callback_opaque, (Addr32)d32 )) {
sewardjce70a5c2004-10-18 14:09:54 +000013144 /* follow into the call target. */
sewardj984d9b12010-01-15 10:53:21 +000013145 dres.whatNext = Dis_ResteerU;
florian0eaa35f2015-01-02 13:34:15 +000013146 dres.continueAt = (Addr32)d32;
sewardjce70a5c2004-10-18 14:09:54 +000013147 } else {
sewardjc6f970f2012-04-02 21:54:49 +000013148 jmp_lit(&dres, Ijk_Call, d32);
13149 vassert(dres.whatNext == Dis_StopHere);
sewardjce70a5c2004-10-18 14:09:54 +000013150 }
sewardjd1061ab2004-07-08 01:45:30 +000013151 DIP("call 0x%x\n",d32);
13152 }
13153 break;
13154
sewardjc9a65702004-07-07 16:32:57 +000013155//-- case 0xC8: /* ENTER */
13156//-- d32 = getUDisp16(eip); eip += 2;
13157//-- abyte = getIByte(delta); delta++;
13158//--
13159//-- vg_assert(sz == 4);
13160//-- vg_assert(abyte == 0);
13161//--
13162//-- t1 = newTemp(cb); t2 = newTemp(cb);
13163//-- uInstr2(cb, GET, sz, ArchReg, R_EBP, TempReg, t1);
13164//-- uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t2);
13165//-- uInstr2(cb, SUB, 4, Literal, 0, TempReg, t2);
13166//-- uLiteral(cb, sz);
13167//-- uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_ESP);
13168//-- uInstr2(cb, STORE, 4, TempReg, t1, TempReg, t2);
13169//-- uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_EBP);
13170//-- if (d32) {
13171//-- uInstr2(cb, SUB, 4, Literal, 0, TempReg, t2);
sewardj5bd4d162004-11-10 13:02:48 +000013172//-- uLiteral(cb, d32);
13173//-- uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_ESP);
sewardjc9a65702004-07-07 16:32:57 +000013174//-- }
13175//-- DIP("enter 0x%x, 0x%x", d32, abyte);
13176//-- break;
sewardjc2ac51e2004-07-12 01:03:26 +000013177
13178 case 0xC9: /* LEAVE */
13179 vassert(sz == 4);
13180 t1 = newTemp(Ity_I32); t2 = newTemp(Ity_I32);
13181 assign(t1, getIReg(4,R_EBP));
13182 /* First PUT ESP looks redundant, but need it because ESP must
13183 always be up-to-date for Memcheck to work... */
13184 putIReg(4, R_ESP, mkexpr(t1));
13185 assign(t2, loadLE(Ity_I32,mkexpr(t1)));
13186 putIReg(4, R_EBP, mkexpr(t2));
13187 putIReg(4, R_ESP, binop(Iop_Add32, mkexpr(t1), mkU32(4)) );
13188 DIP("leave\n");
13189 break;
13190
sewardj8edc36b2007-11-23 02:46:29 +000013191 /* ---------------- Misc weird-ass insns --------------- */
13192
13193 case 0x27: /* DAA */
13194 case 0x2F: /* DAS */
13195 case 0x37: /* AAA */
13196 case 0x3F: /* AAS */
13197 /* An ugly implementation for some ugly instructions. Oh
13198 well. */
13199 if (sz != 4) 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 4 instructions it
13214 is doing the computation for. */
13215 vassert(opc == 0x27 || opc == 0x2F || opc == 0x37 || opc == 0x3F);
13216 assign(t2,
13217 mkIRExprCCall(
13218 Ity_I32, 0/*regparm*/, "x86g_calculate_daa_das_aaa_aas",
13219 &x86g_calculate_daa_das_aaa_aas,
13220 mkIRExprVec_2( mkexpr(t1), mkU32( opc & 0xFF) )
13221 ));
13222 putIReg(2, R_EAX, unop(Iop_32to16, mkexpr(t2) ));
13223
13224 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(X86G_CC_OP_COPY) ));
13225 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
13226 stmt( IRStmt_Put( OFFB_CC_DEP1,
13227 binop(Iop_And32,
13228 binop(Iop_Shr32, mkexpr(t2), mkU8(16)),
13229 mkU32( X86G_CC_MASK_C | X86G_CC_MASK_P
13230 | X86G_CC_MASK_A | X86G_CC_MASK_Z
13231 | X86G_CC_MASK_S| X86G_CC_MASK_O )
13232 )
13233 )
13234 );
13235 /* Set NDEP even though it isn't used. This makes redundant-PUT
13236 elimination of previous stores to this field work better. */
13237 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
13238 switch (opc) {
13239 case 0x27: DIP("daa\n"); break;
13240 case 0x2F: DIP("das\n"); break;
13241 case 0x37: DIP("aaa\n"); break;
13242 case 0x3F: DIP("aas\n"); break;
13243 default: vassert(0);
13244 }
13245 break;
13246
sewardj321bbbf2011-01-17 12:32:25 +000013247 case 0xD4: /* AAM */
13248 case 0xD5: /* AAD */
13249 d32 = getIByte(delta); delta++;
13250 if (sz != 4 || d32 != 10) goto decode_failure;
13251 t1 = newTemp(Ity_I32);
13252 t2 = newTemp(Ity_I32);
13253 /* Make up a 32-bit value (t1), with the old value of AX in the
13254 bottom 16 bits, and the old OSZACP bitmask in the upper 16
13255 bits. */
13256 assign(t1,
13257 binop(Iop_16HLto32,
13258 unop(Iop_32to16,
13259 mk_x86g_calculate_eflags_all()),
13260 getIReg(2, R_EAX)
13261 ));
13262 /* Call the helper fn, to get a new AX and OSZACP value, and
13263 poke both back into the guest state. Also pass the helper
13264 the actual opcode so it knows which of the 2 instructions it
13265 is doing the computation for. */
13266 assign(t2,
13267 mkIRExprCCall(
13268 Ity_I32, 0/*regparm*/, "x86g_calculate_aad_aam",
13269 &x86g_calculate_aad_aam,
13270 mkIRExprVec_2( mkexpr(t1), mkU32( opc & 0xFF) )
13271 ));
13272 putIReg(2, R_EAX, unop(Iop_32to16, mkexpr(t2) ));
13273
13274 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(X86G_CC_OP_COPY) ));
13275 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
13276 stmt( IRStmt_Put( OFFB_CC_DEP1,
13277 binop(Iop_And32,
13278 binop(Iop_Shr32, mkexpr(t2), mkU8(16)),
13279 mkU32( X86G_CC_MASK_C | X86G_CC_MASK_P
13280 | X86G_CC_MASK_A | X86G_CC_MASK_Z
13281 | X86G_CC_MASK_S| X86G_CC_MASK_O )
13282 )
13283 )
13284 );
13285 /* Set NDEP even though it isn't used. This makes
13286 redundant-PUT elimination of previous stores to this field
13287 work better. */
13288 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
13289
13290 DIP(opc == 0xD4 ? "aam\n" : "aad\n");
13291 break;
sewardj1c6f9912004-09-07 10:15:24 +000013292
13293 /* ------------------------ CWD/CDQ -------------------- */
13294
13295 case 0x98: /* CBW */
13296 if (sz == 4) {
13297 putIReg(4, R_EAX, unop(Iop_16Sto32, getIReg(2, R_EAX)));
13298 DIP("cwde\n");
13299 } else {
sewardj47341042004-09-19 11:55:46 +000013300 vassert(sz == 2);
13301 putIReg(2, R_EAX, unop(Iop_8Sto16, getIReg(1, R_EAX)));
13302 DIP("cbw\n");
sewardj1c6f9912004-09-07 10:15:24 +000013303 }
13304 break;
sewardj64e1d652004-07-12 14:00:46 +000013305
13306 case 0x99: /* CWD/CDQ */
13307 ty = szToITy(sz);
13308 putIReg(sz, R_EDX,
13309 binop(mkSizedOp(ty,Iop_Sar8),
13310 getIReg(sz, R_EAX),
sewardj9ee82862004-12-14 01:16:59 +000013311 mkU8(sz == 2 ? 15 : 31)) );
sewardj64e1d652004-07-12 14:00:46 +000013312 DIP(sz == 2 ? "cwdq\n" : "cdqq\n");
13313 break;
13314
sewardjbdc7d212004-09-09 02:46:40 +000013315 /* ------------------------ FPU ops -------------------- */
13316
13317 case 0x9E: /* SAHF */
13318 codegen_SAHF();
13319 DIP("sahf\n");
13320 break;
13321
sewardj8dfdc8a2005-10-03 11:39:02 +000013322 case 0x9F: /* LAHF */
13323 codegen_LAHF();
13324 DIP("lahf\n");
13325 break;
13326
sewardjbdc7d212004-09-09 02:46:40 +000013327 case 0x9B: /* FWAIT */
13328 /* ignore? */
13329 DIP("fwait\n");
13330 break;
13331
sewardjd1725d12004-08-12 20:46:53 +000013332 case 0xD8:
13333 case 0xD9:
13334 case 0xDA:
13335 case 0xDB:
13336 case 0xDC:
13337 case 0xDD:
13338 case 0xDE:
13339 case 0xDF: {
sewardj52d04912005-07-03 00:52:48 +000013340 Int delta0 = delta;
sewardjd1725d12004-08-12 20:46:53 +000013341 Bool decode_OK = False;
13342 delta = dis_FPU ( &decode_OK, sorb, delta );
13343 if (!decode_OK) {
13344 delta = delta0;
13345 goto decode_failure;
13346 }
13347 break;
13348 }
sewardj0611d802004-07-11 02:37:54 +000013349
13350 /* ------------------------ INC & DEC ------------------ */
13351
13352 case 0x40: /* INC eAX */
13353 case 0x41: /* INC eCX */
13354 case 0x42: /* INC eDX */
13355 case 0x43: /* INC eBX */
13356 case 0x44: /* INC eSP */
13357 case 0x45: /* INC eBP */
13358 case 0x46: /* INC eSI */
13359 case 0x47: /* INC eDI */
13360 vassert(sz == 2 || sz == 4);
13361 ty = szToITy(sz);
13362 t1 = newTemp(ty);
13363 assign( t1, binop(mkSizedOp(ty,Iop_Add8),
13364 getIReg(sz, (UInt)(opc - 0x40)),
13365 mkU(ty,1)) );
13366 setFlags_INC_DEC( True, t1, ty );
13367 putIReg(sz, (UInt)(opc - 0x40), mkexpr(t1));
13368 DIP("inc%c %s\n", nameISize(sz), nameIReg(sz,opc-0x40));
13369 break;
13370
13371 case 0x48: /* DEC eAX */
13372 case 0x49: /* DEC eCX */
13373 case 0x4A: /* DEC eDX */
13374 case 0x4B: /* DEC eBX */
13375 case 0x4C: /* DEC eSP */
13376 case 0x4D: /* DEC eBP */
13377 case 0x4E: /* DEC eSI */
13378 case 0x4F: /* DEC eDI */
13379 vassert(sz == 2 || sz == 4);
13380 ty = szToITy(sz);
13381 t1 = newTemp(ty);
13382 assign( t1, binop(mkSizedOp(ty,Iop_Sub8),
13383 getIReg(sz, (UInt)(opc - 0x48)),
13384 mkU(ty,1)) );
13385 setFlags_INC_DEC( False, t1, ty );
13386 putIReg(sz, (UInt)(opc - 0x48), mkexpr(t1));
13387 DIP("dec%c %s\n", nameISize(sz), nameIReg(sz,opc-0x48));
13388 break;
13389
13390 /* ------------------------ INT ------------------------ */
13391
sewardj322bfa02007-02-28 23:31:42 +000013392 case 0xCC: /* INT 3 */
sewardjc6f970f2012-04-02 21:54:49 +000013393 jmp_lit(&dres, Ijk_SigTRAP, ((Addr32)guest_EIP_bbstart)+delta);
13394 vassert(dres.whatNext == Dis_StopHere);
sewardj322bfa02007-02-28 23:31:42 +000013395 DIP("int $0x3\n");
13396 break;
13397
sewardj0611d802004-07-11 02:37:54 +000013398 case 0xCD: /* INT imm8 */
13399 d32 = getIByte(delta); delta++;
sewardj0f500042007-08-29 09:09:17 +000013400
sewardjd660d412008-12-03 21:29:59 +000013401 /* For any of the cases where we emit a jump (that is, for all
13402 currently handled cases), it's important that all ArchRegs
13403 carry their up-to-date value at this point. So we declare an
13404 end-of-block here, which forces any TempRegs caching ArchRegs
13405 to be flushed. */
13406
sewardj84af6762012-02-16 12:36:47 +000013407 /* Handle int $0x3F .. $0x4F by synthesising a segfault and a
sewardj0f500042007-08-29 09:09:17 +000013408 restart of this instruction (hence the "-2" two lines below,
13409 to get the restart EIP to be this instruction. This is
13410 probably Linux-specific and it would be more correct to only
sewardj84af6762012-02-16 12:36:47 +000013411 do this if the VexAbiInfo says that is what we should do.
13412 This used to handle just 0x40-0x43; Jikes RVM uses a larger
13413 range (0x3F-0x49), and this allows some slack as well. */
13414 if (d32 >= 0x3F && d32 <= 0x4F) {
sewardjc6f970f2012-04-02 21:54:49 +000013415 jmp_lit(&dres, Ijk_SigSEGV, ((Addr32)guest_EIP_bbstart)+delta-2);
13416 vassert(dres.whatNext == Dis_StopHere);
florianb1737742015-08-03 16:03:13 +000013417 DIP("int $0x%x\n", d32);
sewardj0f500042007-08-29 09:09:17 +000013418 break;
13419 }
13420
sewardjd660d412008-12-03 21:29:59 +000013421 /* Handle int $0x80 (linux syscalls), int $0x81 and $0x82
sewardj3e5d82d2015-07-21 14:43:23 +000013422 (darwin syscalls), int $0x91 (Solaris syscalls) and int $0xD2
13423 (Solaris fasttrap syscalls). As part of this, note where we are, so we
sewardje86310f2009-03-19 22:21:40 +000013424 can back up the guest to this point if the syscall needs to
13425 be restarted. */
sewardj3e5d82d2015-07-21 14:43:23 +000013426 IRJumpKind jump_kind;
13427 switch (d32) {
13428 case 0x80:
13429 jump_kind = Ijk_Sys_int128;
sewardjd660d412008-12-03 21:29:59 +000013430 break;
sewardj3e5d82d2015-07-21 14:43:23 +000013431 case 0x81:
13432 jump_kind = Ijk_Sys_int129;
sewardjd660d412008-12-03 21:29:59 +000013433 break;
sewardj3e5d82d2015-07-21 14:43:23 +000013434 case 0x82:
13435 jump_kind = Ijk_Sys_int130;
sewardjd660d412008-12-03 21:29:59 +000013436 break;
sewardj3e5d82d2015-07-21 14:43:23 +000013437 case 0x91:
13438 jump_kind = Ijk_Sys_int145;
13439 break;
13440 case 0xD2:
13441 jump_kind = Ijk_Sys_int210;
13442 break;
13443 default:
13444 /* none of the above */
13445 goto decode_failure;
sewardjd660d412008-12-03 21:29:59 +000013446 }
13447
sewardj3e5d82d2015-07-21 14:43:23 +000013448 stmt( IRStmt_Put( OFFB_IP_AT_SYSCALL,
13449 mkU32(guest_EIP_curr_instr) ) );
13450 jmp_lit(&dres, jump_kind, ((Addr32)guest_EIP_bbstart)+delta);
13451 vassert(dres.whatNext == Dis_StopHere);
florianb1737742015-08-03 16:03:13 +000013452 DIP("int $0x%x\n", d32);
sewardj3e5d82d2015-07-21 14:43:23 +000013453 break;
sewardj0611d802004-07-11 02:37:54 +000013454
sewardj77b86be2004-07-11 13:28:24 +000013455 /* ------------------------ Jcond, byte offset --------- */
13456
13457 case 0xEB: /* Jb (jump, byte offset) */
sewardj9e6491a2005-07-02 19:24:10 +000013458 d32 = (((Addr32)guest_EIP_bbstart)+delta+1) + getSDisp8(delta);
sewardj77b86be2004-07-11 13:28:24 +000013459 delta++;
florianbeac5302014-12-31 12:09:38 +000013460 if (resteerOkFn( callback_opaque, (Addr32)d32) ) {
sewardj984d9b12010-01-15 10:53:21 +000013461 dres.whatNext = Dis_ResteerU;
florian0eaa35f2015-01-02 13:34:15 +000013462 dres.continueAt = (Addr32)d32;
sewardjce70a5c2004-10-18 14:09:54 +000013463 } else {
sewardjc6f970f2012-04-02 21:54:49 +000013464 jmp_lit(&dres, Ijk_Boring, d32);
13465 vassert(dres.whatNext == Dis_StopHere);
sewardjce70a5c2004-10-18 14:09:54 +000013466 }
sewardj77b86be2004-07-11 13:28:24 +000013467 DIP("jmp-8 0x%x\n", d32);
13468 break;
sewardj0611d802004-07-11 02:37:54 +000013469
13470 case 0xE9: /* Jv (jump, 16/32 offset) */
13471 vassert(sz == 4); /* JRS added 2004 July 11 */
sewardj9e6491a2005-07-02 19:24:10 +000013472 d32 = (((Addr32)guest_EIP_bbstart)+delta+sz) + getSDisp(sz,delta);
sewardj0611d802004-07-11 02:37:54 +000013473 delta += sz;
florianbeac5302014-12-31 12:09:38 +000013474 if (resteerOkFn( callback_opaque, (Addr32)d32) ) {
sewardj984d9b12010-01-15 10:53:21 +000013475 dres.whatNext = Dis_ResteerU;
florian0eaa35f2015-01-02 13:34:15 +000013476 dres.continueAt = (Addr32)d32;
sewardjce70a5c2004-10-18 14:09:54 +000013477 } else {
sewardjc6f970f2012-04-02 21:54:49 +000013478 jmp_lit(&dres, Ijk_Boring, d32);
13479 vassert(dres.whatNext == Dis_StopHere);
sewardjce70a5c2004-10-18 14:09:54 +000013480 }
sewardj0611d802004-07-11 02:37:54 +000013481 DIP("jmp 0x%x\n", d32);
13482 break;
sewardje87b4842004-07-10 12:23:30 +000013483
13484 case 0x70:
13485 case 0x71:
13486 case 0x72: /* JBb/JNAEb (jump below) */
13487 case 0x73: /* JNBb/JAEb (jump not below) */
13488 case 0x74: /* JZb/JEb (jump zero) */
13489 case 0x75: /* JNZb/JNEb (jump not zero) */
13490 case 0x76: /* JBEb/JNAb (jump below or equal) */
13491 case 0x77: /* JNBEb/JAb (jump not below or equal) */
13492 case 0x78: /* JSb (jump negative) */
13493 case 0x79: /* JSb (jump not negative) */
13494 case 0x7A: /* JP (jump parity even) */
13495 case 0x7B: /* JNP/JPO (jump parity odd) */
13496 case 0x7C: /* JLb/JNGEb (jump less) */
13497 case 0x7D: /* JGEb/JNLb (jump greater or equal) */
13498 case 0x7E: /* JLEb/JNGb (jump less or equal) */
13499 case 0x7F: /* JGb/JNLEb (jump greater) */
sewardj984d9b12010-01-15 10:53:21 +000013500 { Int jmpDelta;
florian55085f82012-11-21 00:36:55 +000013501 const HChar* comment = "";
sewardj984d9b12010-01-15 10:53:21 +000013502 jmpDelta = (Int)getSDisp8(delta);
13503 vassert(-128 <= jmpDelta && jmpDelta < 128);
13504 d32 = (((Addr32)guest_EIP_bbstart)+delta+1) + jmpDelta;
sewardje87b4842004-07-10 12:23:30 +000013505 delta++;
sewardj984d9b12010-01-15 10:53:21 +000013506 if (resteerCisOk
13507 && vex_control.guest_chase_cond
sewardj0d925b12010-01-17 15:47:01 +000013508 && (Addr32)d32 != (Addr32)guest_EIP_bbstart
sewardj984d9b12010-01-15 10:53:21 +000013509 && jmpDelta < 0
florianbeac5302014-12-31 12:09:38 +000013510 && resteerOkFn( callback_opaque, (Addr32)d32) ) {
sewardj984d9b12010-01-15 10:53:21 +000013511 /* Speculation: assume this backward branch is taken. So we
13512 need to emit a side-exit to the insn following this one,
13513 on the negation of the condition, and continue at the
sewardj0d925b12010-01-17 15:47:01 +000013514 branch target address (d32). If we wind up back at the
13515 first instruction of the trace, just stop; it's better to
13516 let the IR loop unroller handle that case. */
sewardjdbf550c2005-01-24 11:54:11 +000013517 stmt( IRStmt_Exit(
13518 mk_x86g_calculate_condition((X86Condcode)(1 ^ (opc - 0x70))),
13519 Ijk_Boring,
sewardjc6f970f2012-04-02 21:54:49 +000013520 IRConst_U32(guest_EIP_bbstart+delta),
13521 OFFB_EIP ) );
sewardj984d9b12010-01-15 10:53:21 +000013522 dres.whatNext = Dis_ResteerC;
florian0eaa35f2015-01-02 13:34:15 +000013523 dres.continueAt = (Addr32)d32;
sewardj984d9b12010-01-15 10:53:21 +000013524 comment = "(assumed taken)";
13525 }
13526 else
13527 if (resteerCisOk
13528 && vex_control.guest_chase_cond
sewardj0d925b12010-01-17 15:47:01 +000013529 && (Addr32)d32 != (Addr32)guest_EIP_bbstart
sewardj984d9b12010-01-15 10:53:21 +000013530 && jmpDelta >= 0
13531 && resteerOkFn( callback_opaque,
florianbeac5302014-12-31 12:09:38 +000013532 (Addr32)(guest_EIP_bbstart+delta)) ) {
sewardj984d9b12010-01-15 10:53:21 +000013533 /* Speculation: assume this forward branch is not taken. So
13534 we need to emit a side-exit to d32 (the dest) and continue
13535 disassembling at the insn immediately following this
13536 one. */
13537 stmt( IRStmt_Exit(
13538 mk_x86g_calculate_condition((X86Condcode)(opc - 0x70)),
13539 Ijk_Boring,
sewardjc6f970f2012-04-02 21:54:49 +000013540 IRConst_U32(d32),
13541 OFFB_EIP ) );
sewardj984d9b12010-01-15 10:53:21 +000013542 dres.whatNext = Dis_ResteerC;
florian0eaa35f2015-01-02 13:34:15 +000013543 dres.continueAt = guest_EIP_bbstart + delta;
sewardj984d9b12010-01-15 10:53:21 +000013544 comment = "(assumed not taken)";
13545 }
13546 else {
13547 /* Conservative default translation - end the block at this
13548 point. */
sewardjc6f970f2012-04-02 21:54:49 +000013549 jcc_01( &dres, (X86Condcode)(opc - 0x70),
sewardj984d9b12010-01-15 10:53:21 +000013550 (Addr32)(guest_EIP_bbstart+delta), d32);
sewardjc6f970f2012-04-02 21:54:49 +000013551 vassert(dres.whatNext == Dis_StopHere);
sewardjdbf550c2005-01-24 11:54:11 +000013552 }
sewardj984d9b12010-01-15 10:53:21 +000013553 DIP("j%s-8 0x%x %s\n", name_X86Condcode(opc - 0x70), d32, comment);
sewardje87b4842004-07-10 12:23:30 +000013554 break;
sewardj984d9b12010-01-15 10:53:21 +000013555 }
sewardje87b4842004-07-10 12:23:30 +000013556
sewardjdc5d0842006-11-16 10:42:02 +000013557 case 0xE3: /* JECXZ (for JCXZ see above) */
sewardjbaa66082005-08-23 17:29:27 +000013558 if (sz != 4) goto decode_failure;
sewardj9e6491a2005-07-02 19:24:10 +000013559 d32 = (((Addr32)guest_EIP_bbstart)+delta+1) + getSDisp8(delta);
sewardjdc5d0842006-11-16 10:42:02 +000013560 delta ++;
sewardj458a6f82004-08-25 12:46:02 +000013561 stmt( IRStmt_Exit(
sewardjdc5d0842006-11-16 10:42:02 +000013562 binop(Iop_CmpEQ32, getIReg(4,R_ECX), mkU32(0)),
sewardj893aada2004-11-29 19:57:54 +000013563 Ijk_Boring,
sewardjc6f970f2012-04-02 21:54:49 +000013564 IRConst_U32(d32),
13565 OFFB_EIP
sewardjdc5d0842006-11-16 10:42:02 +000013566 ));
13567 DIP("jecxz 0x%x\n", d32);
sewardj458a6f82004-08-25 12:46:02 +000013568 break;
13569
sewardjbaa66082005-08-23 17:29:27 +000013570 case 0xE0: /* LOOPNE disp8: decrement count, jump if count != 0 && ZF==0 */
13571 case 0xE1: /* LOOPE disp8: decrement count, jump if count != 0 && ZF==1 */
13572 case 0xE2: /* LOOP disp8: decrement count, jump if count != 0 */
13573 { /* Again, the docs say this uses ECX/CX as a count depending on
13574 the address size override, not the operand one. Since we
13575 don't handle address size overrides, I guess that means
13576 ECX. */
13577 IRExpr* zbit = NULL;
13578 IRExpr* count = NULL;
13579 IRExpr* cond = NULL;
florian55085f82012-11-21 00:36:55 +000013580 const HChar* xtra = NULL;
sewardjbaa66082005-08-23 17:29:27 +000013581
13582 if (sz != 4) goto decode_failure;
13583 d32 = (((Addr32)guest_EIP_bbstart)+delta+1) + getSDisp8(delta);
13584 delta++;
13585 putIReg(4, R_ECX, binop(Iop_Sub32, getIReg(4,R_ECX), mkU32(1)));
13586
13587 count = getIReg(4,R_ECX);
13588 cond = binop(Iop_CmpNE32, count, mkU32(0));
13589 switch (opc) {
13590 case 0xE2:
13591 xtra = "";
13592 break;
13593 case 0xE1:
13594 xtra = "e";
13595 zbit = mk_x86g_calculate_condition( X86CondZ );
13596 cond = mkAnd1(cond, zbit);
13597 break;
13598 case 0xE0:
13599 xtra = "ne";
13600 zbit = mk_x86g_calculate_condition( X86CondNZ );
13601 cond = mkAnd1(cond, zbit);
13602 break;
13603 default:
13604 vassert(0);
13605 }
sewardjc6f970f2012-04-02 21:54:49 +000013606 stmt( IRStmt_Exit(cond, Ijk_Boring, IRConst_U32(d32), OFFB_EIP) );
sewardjbaa66082005-08-23 17:29:27 +000013607
13608 DIP("loop%s 0x%x\n", xtra, d32);
13609 break;
13610 }
sewardj1813dbe2004-07-28 17:09:04 +000013611
13612 /* ------------------------ IMUL ----------------------- */
13613
13614 case 0x69: /* IMUL Iv, Ev, Gv */
13615 delta = dis_imul_I_E_G ( sorb, sz, delta, sz );
13616 break;
13617 case 0x6B: /* IMUL Ib, Ev, Gv */
13618 delta = dis_imul_I_E_G ( sorb, sz, delta, 1 );
13619 break;
sewardj0611d802004-07-11 02:37:54 +000013620
13621 /* ------------------------ MOV ------------------------ */
13622
13623 case 0x88: /* MOV Gb,Eb */
13624 delta = dis_mov_G_E(sorb, 1, delta);
13625 break;
sewardjc9a65702004-07-07 16:32:57 +000013626
13627 case 0x89: /* MOV Gv,Ev */
13628 delta = dis_mov_G_E(sorb, sz, delta);
13629 break;
13630
sewardjc2ac51e2004-07-12 01:03:26 +000013631 case 0x8A: /* MOV Eb,Gb */
13632 delta = dis_mov_E_G(sorb, 1, delta);
13633 break;
sewardje05c42c2004-07-08 20:25:10 +000013634
13635 case 0x8B: /* MOV Ev,Gv */
13636 delta = dis_mov_E_G(sorb, sz, delta);
13637 break;
13638
sewardje87b4842004-07-10 12:23:30 +000013639 case 0x8D: /* LEA M,Gv */
sewardje9460bd2005-01-28 13:45:42 +000013640 if (sz != 4)
13641 goto decode_failure;
sewardje05c42c2004-07-08 20:25:10 +000013642 modrm = getIByte(delta);
13643 if (epartIsReg(modrm))
sewardje9460bd2005-01-28 13:45:42 +000013644 goto decode_failure;
sewardje05c42c2004-07-08 20:25:10 +000013645 /* NOTE! this is the one place where a segment override prefix
13646 has no effect on the address calculation. Therefore we pass
13647 zero instead of sorb here. */
sewardje87b4842004-07-10 12:23:30 +000013648 addr = disAMode ( &alen, /*sorb*/ 0, delta, dis_buf );
13649 delta += alen;
sewardj940e8c92004-07-11 16:53:24 +000013650 putIReg(sz, gregOfRM(modrm), mkexpr(addr));
sewardje05c42c2004-07-08 20:25:10 +000013651 DIP("lea%c %s, %s\n", nameISize(sz), dis_buf,
13652 nameIReg(sz,gregOfRM(modrm)));
13653 break;
sewardje05c42c2004-07-08 20:25:10 +000013654
sewardj063f02f2004-10-20 12:36:12 +000013655 case 0x8C: /* MOV Sw,Ew -- MOV from a SEGMENT REGISTER */
13656 delta = dis_mov_Sw_Ew(sorb, sz, delta);
13657 break;
13658
sewardj7df596b2004-12-06 14:29:12 +000013659 case 0x8E: /* MOV Ew,Sw -- MOV to a SEGMENT REGISTER */
13660 delta = dis_mov_Ew_Sw(sorb, delta);
13661 break;
13662
sewardj43852812004-10-16 23:10:08 +000013663 case 0xA0: /* MOV Ob,AL */
13664 sz = 1;
13665 /* Fall through ... */
sewardj0c12ea82004-07-12 08:18:16 +000013666 case 0xA1: /* MOV Ov,eAX */
13667 d32 = getUDisp32(delta); delta += 4;
13668 ty = szToITy(sz);
13669 addr = newTemp(Ity_I32);
13670 assign( addr, handleSegOverride(sorb, mkU32(d32)) );
13671 putIReg(sz, R_EAX, loadLE(ty, mkexpr(addr)));
13672 DIP("mov%c %s0x%x, %s\n", nameISize(sz), sorbTxt(sorb),
13673 d32, nameIReg(sz,R_EAX));
13674 break;
13675
sewardj180e8b32004-07-29 01:40:11 +000013676 case 0xA2: /* MOV Ob,AL */
13677 sz = 1;
13678 /* Fall through ... */
sewardj750f4072004-07-26 22:39:11 +000013679 case 0xA3: /* MOV eAX,Ov */
13680 d32 = getUDisp32(delta); delta += 4;
13681 ty = szToITy(sz);
13682 addr = newTemp(Ity_I32);
13683 assign( addr, handleSegOverride(sorb, mkU32(d32)) );
13684 storeLE( mkexpr(addr), getIReg(sz,R_EAX) );
13685 DIP("mov%c %s, %s0x%x\n", nameISize(sz), nameIReg(sz,R_EAX),
13686 sorbTxt(sorb), d32);
13687 break;
sewardje87b4842004-07-10 12:23:30 +000013688
sewardjc2ac51e2004-07-12 01:03:26 +000013689 case 0xB0: /* MOV imm,AL */
13690 case 0xB1: /* MOV imm,CL */
13691 case 0xB2: /* MOV imm,DL */
13692 case 0xB3: /* MOV imm,BL */
13693 case 0xB4: /* MOV imm,AH */
13694 case 0xB5: /* MOV imm,CH */
13695 case 0xB6: /* MOV imm,DH */
13696 case 0xB7: /* MOV imm,BH */
13697 d32 = getIByte(delta); delta += 1;
13698 putIReg(1, opc-0xB0, mkU8(d32));
13699 DIP("movb $0x%x,%s\n", d32, nameIReg(1,opc-0xB0));
13700 break;
sewardj7ed22952004-07-29 00:09:58 +000013701
sewardje87b4842004-07-10 12:23:30 +000013702 case 0xB8: /* MOV imm,eAX */
13703 case 0xB9: /* MOV imm,eCX */
13704 case 0xBA: /* MOV imm,eDX */
13705 case 0xBB: /* MOV imm,eBX */
13706 case 0xBC: /* MOV imm,eSP */
13707 case 0xBD: /* MOV imm,eBP */
13708 case 0xBE: /* MOV imm,eSI */
13709 case 0xBF: /* MOV imm,eDI */
13710 d32 = getUDisp(sz,delta); delta += sz;
13711 putIReg(sz, opc-0xB8, mkU(szToITy(sz), d32));
13712 DIP("mov%c $0x%x,%s\n", nameISize(sz), d32, nameIReg(sz,opc-0xB8));
13713 break;
13714
sewardj1bf44e32013-09-18 18:27:55 +000013715 case 0xC6: /* C6 /0 = MOV Ib,Eb */
sewardj77b86be2004-07-11 13:28:24 +000013716 sz = 1;
sewardj1bf44e32013-09-18 18:27:55 +000013717 goto maybe_do_Mov_I_E;
13718 case 0xC7: /* C7 /0 = MOV Iv,Ev */
13719 goto maybe_do_Mov_I_E;
sewardje87b4842004-07-10 12:23:30 +000013720
sewardj1bf44e32013-09-18 18:27:55 +000013721 maybe_do_Mov_I_E:
sewardje87b4842004-07-10 12:23:30 +000013722 modrm = getIByte(delta);
sewardj1bf44e32013-09-18 18:27:55 +000013723 if (gregOfRM(modrm) == 0) {
13724 if (epartIsReg(modrm)) {
13725 delta++; /* mod/rm byte */
13726 d32 = getUDisp(sz,delta); delta += sz;
13727 putIReg(sz, eregOfRM(modrm), mkU(szToITy(sz), d32));
13728 DIP("mov%c $0x%x, %s\n", nameISize(sz), d32,
13729 nameIReg(sz,eregOfRM(modrm)));
13730 } else {
13731 addr = disAMode ( &alen, sorb, delta, dis_buf );
13732 delta += alen;
13733 d32 = getUDisp(sz,delta); delta += sz;
13734 storeLE(mkexpr(addr), mkU(szToITy(sz), d32));
13735 DIP("mov%c $0x%x, %s\n", nameISize(sz), d32, dis_buf);
13736 }
13737 break;
sewardje87b4842004-07-10 12:23:30 +000013738 }
sewardj1bf44e32013-09-18 18:27:55 +000013739 goto decode_failure;
sewardje87b4842004-07-10 12:23:30 +000013740
sewardj1813dbe2004-07-28 17:09:04 +000013741 /* ------------------------ opl imm, A ----------------- */
13742
13743 case 0x04: /* ADD Ib, AL */
sewardja718d5d2005-04-03 14:59:54 +000013744 delta = dis_op_imm_A( 1, False, Iop_Add8, True, delta, "add" );
sewardj1813dbe2004-07-28 17:09:04 +000013745 break;
sewardj77b86be2004-07-11 13:28:24 +000013746 case 0x05: /* ADD Iv, eAX */
sewardja718d5d2005-04-03 14:59:54 +000013747 delta = dis_op_imm_A( sz, False, Iop_Add8, True, delta, "add" );
sewardj77b86be2004-07-11 13:28:24 +000013748 break;
13749
sewardj940e8c92004-07-11 16:53:24 +000013750 case 0x0C: /* OR Ib, AL */
sewardja718d5d2005-04-03 14:59:54 +000013751 delta = dis_op_imm_A( 1, False, Iop_Or8, True, delta, "or" );
sewardj940e8c92004-07-11 16:53:24 +000013752 break;
sewardj82292882004-07-27 00:15:59 +000013753 case 0x0D: /* OR Iv, eAX */
sewardja718d5d2005-04-03 14:59:54 +000013754 delta = dis_op_imm_A( sz, False, Iop_Or8, True, delta, "or" );
sewardj82292882004-07-27 00:15:59 +000013755 break;
13756
sewardjeca20362005-08-24 09:22:39 +000013757 case 0x14: /* ADC Ib, AL */
13758 delta = dis_op_imm_A( 1, True, Iop_Add8, True, delta, "adc" );
13759 break;
sewardja718d5d2005-04-03 14:59:54 +000013760 case 0x15: /* ADC Iv, eAX */
sewardjeca20362005-08-24 09:22:39 +000013761 delta = dis_op_imm_A( sz, True, Iop_Add8, True, delta, "adc" );
sewardja718d5d2005-04-03 14:59:54 +000013762 break;
13763
sewardj2fbae082005-10-03 02:07:08 +000013764 case 0x1C: /* SBB Ib, AL */
13765 delta = dis_op_imm_A( 1, True, Iop_Sub8, True, delta, "sbb" );
13766 break;
13767 case 0x1D: /* SBB Iv, eAX */
13768 delta = dis_op_imm_A( sz, True, Iop_Sub8, True, delta, "sbb" );
13769 break;
13770
sewardj940e8c92004-07-11 16:53:24 +000013771 case 0x24: /* AND Ib, AL */
sewardja718d5d2005-04-03 14:59:54 +000013772 delta = dis_op_imm_A( 1, False, Iop_And8, True, delta, "and" );
sewardj940e8c92004-07-11 16:53:24 +000013773 break;
sewardjc2ac51e2004-07-12 01:03:26 +000013774 case 0x25: /* AND Iv, eAX */
sewardja718d5d2005-04-03 14:59:54 +000013775 delta = dis_op_imm_A( sz, False, Iop_And8, True, delta, "and" );
sewardjc2ac51e2004-07-12 01:03:26 +000013776 break;
sewardj0611d802004-07-11 02:37:54 +000013777
13778 case 0x2C: /* SUB Ib, AL */
sewardja718d5d2005-04-03 14:59:54 +000013779 delta = dis_op_imm_A( 1, False, Iop_Sub8, True, delta, "sub" );
sewardj0611d802004-07-11 02:37:54 +000013780 break;
sewardj68511542004-07-28 00:15:44 +000013781 case 0x2D: /* SUB Iv, eAX */
sewardja718d5d2005-04-03 14:59:54 +000013782 delta = dis_op_imm_A( sz, False, Iop_Sub8, True, delta, "sub" );
sewardj68511542004-07-28 00:15:44 +000013783 break;
13784
sewardj1c6f9912004-09-07 10:15:24 +000013785 case 0x34: /* XOR Ib, AL */
sewardja718d5d2005-04-03 14:59:54 +000013786 delta = dis_op_imm_A( 1, False, Iop_Xor8, True, delta, "xor" );
sewardj1c6f9912004-09-07 10:15:24 +000013787 break;
sewardjcaca9d02004-07-28 07:11:32 +000013788 case 0x35: /* XOR Iv, eAX */
sewardja718d5d2005-04-03 14:59:54 +000013789 delta = dis_op_imm_A( sz, False, Iop_Xor8, True, delta, "xor" );
sewardjcaca9d02004-07-28 07:11:32 +000013790 break;
13791
sewardj0611d802004-07-11 02:37:54 +000013792 case 0x3C: /* CMP Ib, AL */
sewardja718d5d2005-04-03 14:59:54 +000013793 delta = dis_op_imm_A( 1, False, Iop_Sub8, False, delta, "cmp" );
sewardj0611d802004-07-11 02:37:54 +000013794 break;
13795 case 0x3D: /* CMP Iv, eAX */
sewardja718d5d2005-04-03 14:59:54 +000013796 delta = dis_op_imm_A( sz, False, Iop_Sub8, False, delta, "cmp" );
sewardj0611d802004-07-11 02:37:54 +000013797 break;
13798
sewardj77b86be2004-07-11 13:28:24 +000013799 case 0xA8: /* TEST Ib, AL */
sewardja718d5d2005-04-03 14:59:54 +000013800 delta = dis_op_imm_A( 1, False, Iop_And8, False, delta, "test" );
sewardj77b86be2004-07-11 13:28:24 +000013801 break;
sewardjc2ac51e2004-07-12 01:03:26 +000013802 case 0xA9: /* TEST Iv, eAX */
sewardja718d5d2005-04-03 14:59:54 +000013803 delta = dis_op_imm_A( sz, False, Iop_And8, False, delta, "test" );
sewardjc2ac51e2004-07-12 01:03:26 +000013804 break;
13805
sewardj1c6f9912004-09-07 10:15:24 +000013806 /* ------------------------ opl Ev, Gv ----------------- */
13807
sewardj89cd0932004-09-08 18:23:25 +000013808 case 0x02: /* ADD Eb,Gb */
13809 delta = dis_op2_E_G ( sorb, False, Iop_Add8, True, 1, delta, "add" );
13810 break;
sewardj9334b0f2004-07-10 22:43:54 +000013811 case 0x03: /* ADD Ev,Gv */
sewardj180e8b32004-07-29 01:40:11 +000013812 delta = dis_op2_E_G ( sorb, False, Iop_Add8, True, sz, delta, "add" );
sewardj9334b0f2004-07-10 22:43:54 +000013813 break;
13814
sewardj7ed22952004-07-29 00:09:58 +000013815 case 0x0A: /* OR Eb,Gb */
sewardj180e8b32004-07-29 01:40:11 +000013816 delta = dis_op2_E_G ( sorb, False, Iop_Or8, True, 1, delta, "or" );
sewardj7ed22952004-07-29 00:09:58 +000013817 break;
sewardjc2ac51e2004-07-12 01:03:26 +000013818 case 0x0B: /* OR Ev,Gv */
sewardj180e8b32004-07-29 01:40:11 +000013819 delta = dis_op2_E_G ( sorb, False, Iop_Or8, True, sz, delta, "or" );
sewardjc2ac51e2004-07-12 01:03:26 +000013820 break;
sewardj2fbae082005-10-03 02:07:08 +000013821
13822 case 0x12: /* ADC Eb,Gb */
13823 delta = dis_op2_E_G ( sorb, True, Iop_Add8, True, 1, delta, "adc" );
13824 break;
sewardjc4eaff32004-09-10 20:25:11 +000013825 case 0x13: /* ADC Ev,Gv */
13826 delta = dis_op2_E_G ( sorb, True, Iop_Add8, True, sz, delta, "adc" );
13827 break;
13828
sewardj2fbae082005-10-03 02:07:08 +000013829 case 0x1A: /* SBB Eb,Gb */
13830 delta = dis_op2_E_G ( sorb, True, Iop_Sub8, True, 1, delta, "sbb" );
13831 break;
sewardj180e8b32004-07-29 01:40:11 +000013832 case 0x1B: /* SBB Ev,Gv */
13833 delta = dis_op2_E_G ( sorb, True, Iop_Sub8, True, sz, delta, "sbb" );
sewardj940e8c92004-07-11 16:53:24 +000013834 break;
13835
sewardj1c6f9912004-09-07 10:15:24 +000013836 case 0x22: /* AND Eb,Gb */
13837 delta = dis_op2_E_G ( sorb, False, Iop_And8, True, 1, delta, "and" );
13838 break;
sewardj180e8b32004-07-29 01:40:11 +000013839 case 0x23: /* AND Ev,Gv */
13840 delta = dis_op2_E_G ( sorb, False, Iop_And8, True, sz, delta, "and" );
13841 break;
13842
13843 case 0x2A: /* SUB Eb,Gb */
13844 delta = dis_op2_E_G ( sorb, False, Iop_Sub8, True, 1, delta, "sub" );
13845 break;
sewardj0611d802004-07-11 02:37:54 +000013846 case 0x2B: /* SUB Ev,Gv */
sewardj180e8b32004-07-29 01:40:11 +000013847 delta = dis_op2_E_G ( sorb, False, Iop_Sub8, True, sz, delta, "sub" );
sewardj0611d802004-07-11 02:37:54 +000013848 break;
sewardjc2ac51e2004-07-12 01:03:26 +000013849
13850 case 0x32: /* XOR Eb,Gb */
sewardj180e8b32004-07-29 01:40:11 +000013851 delta = dis_op2_E_G ( sorb, False, Iop_Xor8, True, 1, delta, "xor" );
sewardjc2ac51e2004-07-12 01:03:26 +000013852 break;
sewardj1813dbe2004-07-28 17:09:04 +000013853 case 0x33: /* XOR Ev,Gv */
sewardj180e8b32004-07-29 01:40:11 +000013854 delta = dis_op2_E_G ( sorb, False, Iop_Xor8, True, sz, delta, "xor" );
sewardj1813dbe2004-07-28 17:09:04 +000013855 break;
13856
sewardjc2ac51e2004-07-12 01:03:26 +000013857 case 0x3A: /* CMP Eb,Gb */
sewardj180e8b32004-07-29 01:40:11 +000013858 delta = dis_op2_E_G ( sorb, False, Iop_Sub8, False, 1, delta, "cmp" );
sewardjc2ac51e2004-07-12 01:03:26 +000013859 break;
sewardje90ad6a2004-07-10 19:02:10 +000013860 case 0x3B: /* CMP Ev,Gv */
sewardj180e8b32004-07-29 01:40:11 +000013861 delta = dis_op2_E_G ( sorb, False, Iop_Sub8, False, sz, delta, "cmp" );
sewardje90ad6a2004-07-10 19:02:10 +000013862 break;
13863
sewardj0611d802004-07-11 02:37:54 +000013864 case 0x84: /* TEST Eb,Gb */
sewardj180e8b32004-07-29 01:40:11 +000013865 delta = dis_op2_E_G ( sorb, False, Iop_And8, False, 1, delta, "test" );
sewardj0611d802004-07-11 02:37:54 +000013866 break;
sewardje05c42c2004-07-08 20:25:10 +000013867 case 0x85: /* TEST Ev,Gv */
sewardj180e8b32004-07-29 01:40:11 +000013868 delta = dis_op2_E_G ( sorb, False, Iop_And8, False, sz, delta, "test" );
sewardje05c42c2004-07-08 20:25:10 +000013869 break;
13870
sewardj180e8b32004-07-29 01:40:11 +000013871 /* ------------------------ opl Gv, Ev ----------------- */
13872
13873 case 0x00: /* ADD Gb,Eb */
sewardje9d8a262009-07-01 08:06:34 +000013874 delta = dis_op2_G_E ( sorb, pfx_lock, False,
13875 Iop_Add8, True, 1, delta, "add" );
sewardj180e8b32004-07-29 01:40:11 +000013876 break;
sewardje05c42c2004-07-08 20:25:10 +000013877 case 0x01: /* ADD Gv,Ev */
sewardje9d8a262009-07-01 08:06:34 +000013878 delta = dis_op2_G_E ( sorb, pfx_lock, False,
13879 Iop_Add8, True, sz, delta, "add" );
sewardje05c42c2004-07-08 20:25:10 +000013880 break;
13881
sewardj940e8c92004-07-11 16:53:24 +000013882 case 0x08: /* OR Gb,Eb */
sewardje9d8a262009-07-01 08:06:34 +000013883 delta = dis_op2_G_E ( sorb, pfx_lock, False,
13884 Iop_Or8, True, 1, delta, "or" );
sewardj940e8c92004-07-11 16:53:24 +000013885 break;
sewardj9334b0f2004-07-10 22:43:54 +000013886 case 0x09: /* OR Gv,Ev */
sewardje9d8a262009-07-01 08:06:34 +000013887 delta = dis_op2_G_E ( sorb, pfx_lock, False,
13888 Iop_Or8, True, sz, delta, "or" );
sewardj9334b0f2004-07-10 22:43:54 +000013889 break;
13890
sewardja2384712004-07-29 14:36:40 +000013891 case 0x10: /* ADC Gb,Eb */
sewardje9d8a262009-07-01 08:06:34 +000013892 delta = dis_op2_G_E ( sorb, pfx_lock, True,
13893 Iop_Add8, True, 1, delta, "adc" );
sewardja2384712004-07-29 14:36:40 +000013894 break;
sewardjcaca9d02004-07-28 07:11:32 +000013895 case 0x11: /* ADC Gv,Ev */
sewardje9d8a262009-07-01 08:06:34 +000013896 delta = dis_op2_G_E ( sorb, pfx_lock, True,
13897 Iop_Add8, True, sz, delta, "adc" );
sewardjcaca9d02004-07-28 07:11:32 +000013898 break;
13899
sewardja2384712004-07-29 14:36:40 +000013900 case 0x18: /* SBB Gb,Eb */
sewardje9d8a262009-07-01 08:06:34 +000013901 delta = dis_op2_G_E ( sorb, pfx_lock, True,
13902 Iop_Sub8, True, 1, delta, "sbb" );
sewardja2384712004-07-29 14:36:40 +000013903 break;
sewardjcaca9d02004-07-28 07:11:32 +000013904 case 0x19: /* SBB Gv,Ev */
sewardje9d8a262009-07-01 08:06:34 +000013905 delta = dis_op2_G_E ( sorb, pfx_lock, True,
13906 Iop_Sub8, True, sz, delta, "sbb" );
sewardjcaca9d02004-07-28 07:11:32 +000013907 break;
13908
sewardja2384712004-07-29 14:36:40 +000013909 case 0x20: /* AND Gb,Eb */
sewardje9d8a262009-07-01 08:06:34 +000013910 delta = dis_op2_G_E ( sorb, pfx_lock, False,
13911 Iop_And8, True, 1, delta, "and" );
sewardja2384712004-07-29 14:36:40 +000013912 break;
sewardj0611d802004-07-11 02:37:54 +000013913 case 0x21: /* AND Gv,Ev */
sewardje9d8a262009-07-01 08:06:34 +000013914 delta = dis_op2_G_E ( sorb, pfx_lock, False,
13915 Iop_And8, True, sz, delta, "and" );
sewardj0611d802004-07-11 02:37:54 +000013916 break;
13917
sewardj180e8b32004-07-29 01:40:11 +000013918 case 0x28: /* SUB Gb,Eb */
sewardje9d8a262009-07-01 08:06:34 +000013919 delta = dis_op2_G_E ( sorb, pfx_lock, False,
13920 Iop_Sub8, True, 1, delta, "sub" );
sewardj180e8b32004-07-29 01:40:11 +000013921 break;
sewardje05c42c2004-07-08 20:25:10 +000013922 case 0x29: /* SUB Gv,Ev */
sewardje9d8a262009-07-01 08:06:34 +000013923 delta = dis_op2_G_E ( sorb, pfx_lock, False,
13924 Iop_Sub8, True, sz, delta, "sub" );
sewardje05c42c2004-07-08 20:25:10 +000013925 break;
13926
sewardjc2ac51e2004-07-12 01:03:26 +000013927 case 0x30: /* XOR Gb,Eb */
sewardje9d8a262009-07-01 08:06:34 +000013928 delta = dis_op2_G_E ( sorb, pfx_lock, False,
13929 Iop_Xor8, True, 1, delta, "xor" );
sewardjc2ac51e2004-07-12 01:03:26 +000013930 break;
sewardje87b4842004-07-10 12:23:30 +000013931 case 0x31: /* XOR Gv,Ev */
sewardje9d8a262009-07-01 08:06:34 +000013932 delta = dis_op2_G_E ( sorb, pfx_lock, False,
13933 Iop_Xor8, True, sz, delta, "xor" );
sewardje87b4842004-07-10 12:23:30 +000013934 break;
13935
sewardj0611d802004-07-11 02:37:54 +000013936 case 0x38: /* CMP Gb,Eb */
sewardje9d8a262009-07-01 08:06:34 +000013937 delta = dis_op2_G_E ( sorb, pfx_lock, False,
13938 Iop_Sub8, False, 1, delta, "cmp" );
sewardj0611d802004-07-11 02:37:54 +000013939 break;
sewardje90ad6a2004-07-10 19:02:10 +000013940 case 0x39: /* CMP Gv,Ev */
sewardje9d8a262009-07-01 08:06:34 +000013941 delta = dis_op2_G_E ( sorb, pfx_lock, False,
13942 Iop_Sub8, False, sz, delta, "cmp" );
sewardje90ad6a2004-07-10 19:02:10 +000013943 break;
13944
sewardj9334b0f2004-07-10 22:43:54 +000013945 /* ------------------------ POP ------------------------ */
13946
13947 case 0x58: /* POP eAX */
13948 case 0x59: /* POP eCX */
13949 case 0x5A: /* POP eDX */
13950 case 0x5B: /* POP eBX */
13951 case 0x5D: /* POP eBP */
13952 case 0x5E: /* POP eSI */
13953 case 0x5F: /* POP eDI */
13954 case 0x5C: /* POP eSP */
13955 vassert(sz == 2 || sz == 4);
13956 t1 = newTemp(szToITy(sz)); t2 = newTemp(Ity_I32);
13957 assign(t2, getIReg(4, R_ESP));
13958 assign(t1, loadLE(szToITy(sz),mkexpr(t2)));
13959 putIReg(4, R_ESP, binop(Iop_Add32, mkexpr(t2), mkU32(sz)));
13960 putIReg(sz, opc-0x58, mkexpr(t1));
13961 DIP("pop%c %s\n", nameISize(sz), nameIReg(sz,opc-0x58));
13962 break;
13963
sewardja2384712004-07-29 14:36:40 +000013964 case 0x9D: /* POPF */
13965 vassert(sz == 2 || sz == 4);
sewardja2384712004-07-29 14:36:40 +000013966 t1 = newTemp(Ity_I32); t2 = newTemp(Ity_I32);
13967 assign(t2, getIReg(4, R_ESP));
sewardjc22a6fd2004-07-29 23:41:47 +000013968 assign(t1, widenUto32(loadLE(szToITy(sz),mkexpr(t2))));
sewardja2384712004-07-29 14:36:40 +000013969 putIReg(4, R_ESP, binop(Iop_Add32, mkexpr(t2), mkU32(sz)));
sewardja2384712004-07-29 14:36:40 +000013970
sewardj0e9a0f52008-01-04 01:22:41 +000013971 /* Generate IR to set %EFLAGS{O,S,Z,A,C,P,D,ID,AC} from the
13972 value in t1. */
13973 set_EFLAGS_from_value( t1, True/*emit_AC_emwarn*/,
13974 ((Addr32)guest_EIP_bbstart)+delta );
sewardj6d269842005-08-06 11:45:02 +000013975
sewardja2384712004-07-29 14:36:40 +000013976 DIP("popf%c\n", nameISize(sz));
13977 break;
13978
sewardjbbdc6222004-12-15 18:43:39 +000013979 case 0x61: /* POPA */
13980 /* This is almost certainly wrong for sz==2. So ... */
13981 if (sz != 4) goto decode_failure;
13982
13983 /* t5 is the old %ESP value. */
13984 t5 = newTemp(Ity_I32);
13985 assign( t5, getIReg(4, R_ESP) );
13986
13987 /* Reload all the registers, except %esp. */
13988 putIReg(4,R_EAX, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32(28)) ));
13989 putIReg(4,R_ECX, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32(24)) ));
13990 putIReg(4,R_EDX, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32(20)) ));
13991 putIReg(4,R_EBX, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32(16)) ));
13992 /* ignore saved %ESP */
13993 putIReg(4,R_EBP, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32( 8)) ));
13994 putIReg(4,R_ESI, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32( 4)) ));
13995 putIReg(4,R_EDI, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32( 0)) ));
13996
13997 /* and move %ESP back up */
13998 putIReg( 4, R_ESP, binop(Iop_Add32, mkexpr(t5), mkU32(8*4)) );
13999
sewardja3d1a662005-03-29 21:33:11 +000014000 DIP("popa%c\n", nameISize(sz));
sewardjbbdc6222004-12-15 18:43:39 +000014001 break;
sewardjfeeb8a82004-11-30 12:30:11 +000014002
14003 case 0x8F: /* POPL/POPW m32 */
sewardjfcff1782006-05-12 14:04:48 +000014004 { Int len;
14005 UChar rm = getIByte(delta);
sewardjfeeb8a82004-11-30 12:30:11 +000014006
14007 /* make sure this instruction is correct POP */
sewardjfcff1782006-05-12 14:04:48 +000014008 if (epartIsReg(rm) || gregOfRM(rm) != 0)
14009 goto decode_failure;
sewardjfeeb8a82004-11-30 12:30:11 +000014010 /* and has correct size */
sewardjfcff1782006-05-12 14:04:48 +000014011 if (sz != 4 && sz != 2)
14012 goto decode_failure;
14013 ty = szToITy(sz);
14014
14015 t1 = newTemp(Ity_I32); /* stack address */
14016 t3 = newTemp(ty); /* data */
sewardjfeeb8a82004-11-30 12:30:11 +000014017 /* set t1 to ESP: t1 = ESP */
14018 assign( t1, getIReg(4, R_ESP) );
14019 /* load M[ESP] to virtual register t3: t3 = M[t1] */
sewardjfcff1782006-05-12 14:04:48 +000014020 assign( t3, loadLE(ty, mkexpr(t1)) );
sewardjfeeb8a82004-11-30 12:30:11 +000014021
14022 /* increase ESP; must be done before the STORE. Intel manual says:
14023 If the ESP register is used as a base register for addressing
14024 a destination operand in memory, the POP instruction computes
14025 the effective address of the operand after it increments the
14026 ESP register.
14027 */
14028 putIReg(4, R_ESP, binop(Iop_Add32, mkexpr(t1), mkU32(sz)) );
14029
14030 /* resolve MODR/M */
14031 addr = disAMode ( &len, sorb, delta, dis_buf);
14032 storeLE( mkexpr(addr), mkexpr(t3) );
14033
sewardjfcff1782006-05-12 14:04:48 +000014034 DIP("pop%c %s\n", sz==2 ? 'w' : 'l', dis_buf);
sewardjfeeb8a82004-11-30 12:30:11 +000014035
14036 delta += len;
14037 break;
14038 }
14039
sewardj5c5f72c2006-03-18 11:29:25 +000014040 case 0x1F: /* POP %DS */
14041 dis_pop_segreg( R_DS, sz ); break;
14042 case 0x07: /* POP %ES */
14043 dis_pop_segreg( R_ES, sz ); break;
14044 case 0x17: /* POP %SS */
14045 dis_pop_segreg( R_SS, sz ); break;
sewardjd1061ab2004-07-08 01:45:30 +000014046
14047 /* ------------------------ PUSH ----------------------- */
14048
14049 case 0x50: /* PUSH eAX */
14050 case 0x51: /* PUSH eCX */
14051 case 0x52: /* PUSH eDX */
14052 case 0x53: /* PUSH eBX */
14053 case 0x55: /* PUSH eBP */
14054 case 0x56: /* PUSH eSI */
14055 case 0x57: /* PUSH eDI */
14056 case 0x54: /* PUSH eSP */
14057 /* This is the Right Way, in that the value to be pushed is
14058 established before %esp is changed, so that pushl %esp
14059 correctly pushes the old value. */
14060 vassert(sz == 2 || sz == 4);
14061 ty = sz==2 ? Ity_I16 : Ity_I32;
sewardj883b00b2004-09-11 09:30:24 +000014062 t1 = newTemp(ty); t2 = newTemp(Ity_I32);
sewardj41f43bc2004-07-08 14:23:22 +000014063 assign(t1, getIReg(sz, opc-0x50));
14064 assign(t2, binop(Iop_Sub32, getIReg(4, R_ESP), mkU32(sz)));
14065 putIReg(4, R_ESP, mkexpr(t2) );
14066 storeLE(mkexpr(t2),mkexpr(t1));
sewardjd1061ab2004-07-08 01:45:30 +000014067 DIP("push%c %s\n", nameISize(sz), nameIReg(sz,opc-0x50));
14068 break;
14069
14070
sewardj0c12ea82004-07-12 08:18:16 +000014071 case 0x68: /* PUSH Iv */
14072 d32 = getUDisp(sz,delta); delta += sz;
14073 goto do_push_I;
sewardj741153c2004-07-25 23:39:13 +000014074 case 0x6A: /* PUSH Ib, sign-extended to sz */
14075 d32 = getSDisp8(delta); delta += 1;
14076 goto do_push_I;
sewardj0c12ea82004-07-12 08:18:16 +000014077 do_push_I:
14078 ty = szToITy(sz);
14079 t1 = newTemp(Ity_I32); t2 = newTemp(ty);
14080 assign( t1, binop(Iop_Sub32,getIReg(4,R_ESP),mkU32(sz)) );
14081 putIReg(4, R_ESP, mkexpr(t1) );
sewardjc4255a02006-08-28 18:04:33 +000014082 /* stop mkU16 asserting if d32 is a negative 16-bit number
14083 (bug #132813) */
14084 if (ty == Ity_I16)
14085 d32 &= 0xFFFF;
sewardj0c12ea82004-07-12 08:18:16 +000014086 storeLE( mkexpr(t1), mkU(ty,d32) );
14087 DIP("push%c $0x%x\n", nameISize(sz), d32);
14088 break;
14089
sewardja2384712004-07-29 14:36:40 +000014090 case 0x9C: /* PUSHF */ {
sewardja2384712004-07-29 14:36:40 +000014091 vassert(sz == 2 || sz == 4);
sewardja2384712004-07-29 14:36:40 +000014092
14093 t1 = newTemp(Ity_I32);
14094 assign( t1, binop(Iop_Sub32,getIReg(4,R_ESP),mkU32(sz)) );
14095 putIReg(4, R_ESP, mkexpr(t1) );
14096
sewardjbc210942005-07-21 10:07:13 +000014097 /* Calculate OSZACP, and patch in fixed fields as per
14098 Intel docs.
14099 - bit 1 is always 1
14100 - bit 9 is Interrupt Enable (should always be 1 in user mode?)
14101 */
sewardja2384712004-07-29 14:36:40 +000014102 t2 = newTemp(Ity_I32);
sewardjbc210942005-07-21 10:07:13 +000014103 assign( t2, binop(Iop_Or32,
14104 mk_x86g_calculate_eflags_all(),
14105 mkU32( (1<<1)|(1<<9) ) ));
sewardja2384712004-07-29 14:36:40 +000014106
sewardjf9c74fe2004-12-16 02:54:54 +000014107 /* Patch in the D flag. This can simply be a copy of bit 10 of
14108 baseBlock[OFFB_DFLAG]. */
sewardja2384712004-07-29 14:36:40 +000014109 t3 = newTemp(Ity_I32);
14110 assign( t3, binop(Iop_Or32,
14111 mkexpr(t2),
14112 binop(Iop_And32,
sewardjf9c74fe2004-12-16 02:54:54 +000014113 IRExpr_Get(OFFB_DFLAG,Ity_I32),
sewardj5bd4d162004-11-10 13:02:48 +000014114 mkU32(1<<10)))
sewardja2384712004-07-29 14:36:40 +000014115 );
sewardj006a6a22004-10-26 00:50:52 +000014116
14117 /* And patch in the ID flag. */
14118 t4 = newTemp(Ity_I32);
14119 assign( t4, binop(Iop_Or32,
14120 mkexpr(t3),
14121 binop(Iop_And32,
sewardj5bd4d162004-11-10 13:02:48 +000014122 binop(Iop_Shl32, IRExpr_Get(OFFB_IDFLAG,Ity_I32),
sewardj006a6a22004-10-26 00:50:52 +000014123 mkU8(21)),
sewardj5bd4d162004-11-10 13:02:48 +000014124 mkU32(1<<21)))
sewardj006a6a22004-10-26 00:50:52 +000014125 );
14126
sewardj6d269842005-08-06 11:45:02 +000014127 /* And patch in the AC flag. */
14128 t5 = newTemp(Ity_I32);
14129 assign( t5, binop(Iop_Or32,
14130 mkexpr(t4),
14131 binop(Iop_And32,
14132 binop(Iop_Shl32, IRExpr_Get(OFFB_ACFLAG,Ity_I32),
14133 mkU8(18)),
14134 mkU32(1<<18)))
14135 );
14136
sewardja2384712004-07-29 14:36:40 +000014137 /* if sz==2, the stored value needs to be narrowed. */
14138 if (sz == 2)
sewardj6d269842005-08-06 11:45:02 +000014139 storeLE( mkexpr(t1), unop(Iop_32to16,mkexpr(t5)) );
sewardja2384712004-07-29 14:36:40 +000014140 else
sewardj6d269842005-08-06 11:45:02 +000014141 storeLE( mkexpr(t1), mkexpr(t5) );
sewardja2384712004-07-29 14:36:40 +000014142
14143 DIP("pushf%c\n", nameISize(sz));
14144 break;
14145 }
14146
sewardjbbdc6222004-12-15 18:43:39 +000014147 case 0x60: /* PUSHA */
14148 /* This is almost certainly wrong for sz==2. So ... */
14149 if (sz != 4) goto decode_failure;
14150
14151 /* This is the Right Way, in that the value to be pushed is
14152 established before %esp is changed, so that pusha
14153 correctly pushes the old %esp value. New value of %esp is
14154 pushed at start. */
14155 /* t0 is the %ESP value we're going to push. */
14156 t0 = newTemp(Ity_I32);
14157 assign( t0, getIReg(4, R_ESP) );
14158
14159 /* t5 will be the new %ESP value. */
14160 t5 = newTemp(Ity_I32);
14161 assign( t5, binop(Iop_Sub32, mkexpr(t0), mkU32(8*4)) );
14162
14163 /* Update guest state before prodding memory. */
14164 putIReg(4, R_ESP, mkexpr(t5));
14165
14166 /* Dump all the registers. */
14167 storeLE( binop(Iop_Add32,mkexpr(t5),mkU32(28)), getIReg(4,R_EAX) );
14168 storeLE( binop(Iop_Add32,mkexpr(t5),mkU32(24)), getIReg(4,R_ECX) );
14169 storeLE( binop(Iop_Add32,mkexpr(t5),mkU32(20)), getIReg(4,R_EDX) );
14170 storeLE( binop(Iop_Add32,mkexpr(t5),mkU32(16)), getIReg(4,R_EBX) );
14171 storeLE( binop(Iop_Add32,mkexpr(t5),mkU32(12)), mkexpr(t0) /*esp*/);
14172 storeLE( binop(Iop_Add32,mkexpr(t5),mkU32( 8)), getIReg(4,R_EBP) );
14173 storeLE( binop(Iop_Add32,mkexpr(t5),mkU32( 4)), getIReg(4,R_ESI) );
14174 storeLE( binop(Iop_Add32,mkexpr(t5),mkU32( 0)), getIReg(4,R_EDI) );
14175
14176 DIP("pusha%c\n", nameISize(sz));
14177 break;
14178
sewardj5c5f72c2006-03-18 11:29:25 +000014179 case 0x0E: /* PUSH %CS */
14180 dis_push_segreg( R_CS, sz ); break;
14181 case 0x1E: /* PUSH %DS */
14182 dis_push_segreg( R_DS, sz ); break;
14183 case 0x06: /* PUSH %ES */
14184 dis_push_segreg( R_ES, sz ); break;
14185 case 0x16: /* PUSH %SS */
14186 dis_push_segreg( R_SS, sz ); break;
sewardj458a6f82004-08-25 12:46:02 +000014187
14188 /* ------------------------ SCAS et al ----------------- */
14189
14190 case 0xA4: /* MOVS, no REP prefix */
14191 case 0xA5:
sewardj9c3b25a2007-04-05 15:06:56 +000014192 if (sorb != 0)
14193 goto decode_failure; /* else dis_string_op asserts */
sewardj458a6f82004-08-25 12:46:02 +000014194 dis_string_op( dis_MOVS, ( opc == 0xA4 ? 1 : sz ), "movs", sorb );
14195 break;
14196
sewardj8d4d2232005-01-20 10:47:46 +000014197 case 0xA6: /* CMPSb, no REP prefix */
sewardj33b53542005-03-11 14:00:27 +000014198 case 0xA7:
sewardj9c3b25a2007-04-05 15:06:56 +000014199 if (sorb != 0)
14200 goto decode_failure; /* else dis_string_op asserts */
14201 dis_string_op( dis_CMPS, ( opc == 0xA6 ? 1 : sz ), "cmps", sorb );
14202 break;
sewardj33b53542005-03-11 14:00:27 +000014203
sewardj883b00b2004-09-11 09:30:24 +000014204 case 0xAA: /* STOS, no REP prefix */
sewardj47341042004-09-19 11:55:46 +000014205 case 0xAB:
sewardj9c3b25a2007-04-05 15:06:56 +000014206 if (sorb != 0)
14207 goto decode_failure; /* else dis_string_op asserts */
sewardj883b00b2004-09-11 09:30:24 +000014208 dis_string_op( dis_STOS, ( opc == 0xAA ? 1 : sz ), "stos", sorb );
14209 break;
sewardj33b53542005-03-11 14:00:27 +000014210
sewardj10ca4eb2005-05-30 11:19:54 +000014211 case 0xAC: /* LODS, no REP prefix */
14212 case 0xAD:
sewardj9c3b25a2007-04-05 15:06:56 +000014213 if (sorb != 0)
14214 goto decode_failure; /* else dis_string_op asserts */
sewardj10ca4eb2005-05-30 11:19:54 +000014215 dis_string_op( dis_LODS, ( opc == 0xAC ? 1 : sz ), "lods", sorb );
14216 break;
sewardj2d4c3a02004-10-15 00:03:23 +000014217
14218 case 0xAE: /* SCAS, no REP prefix */
14219 case 0xAF:
sewardj9c3b25a2007-04-05 15:06:56 +000014220 if (sorb != 0)
14221 goto decode_failure; /* else dis_string_op asserts */
sewardj2d4c3a02004-10-15 00:03:23 +000014222 dis_string_op( dis_SCAS, ( opc == 0xAE ? 1 : sz ), "scas", sorb );
14223 break;
sewardj64e1d652004-07-12 14:00:46 +000014224
14225
14226 case 0xFC: /* CLD */
sewardjeeb9ef82004-07-15 12:39:03 +000014227 stmt( IRStmt_Put( OFFB_DFLAG, mkU32(1)) );
sewardj64e1d652004-07-12 14:00:46 +000014228 DIP("cld\n");
14229 break;
14230
sewardj1813dbe2004-07-28 17:09:04 +000014231 case 0xFD: /* STD */
14232 stmt( IRStmt_Put( OFFB_DFLAG, mkU32(0xFFFFFFFF)) );
14233 DIP("std\n");
14234 break;
14235
sewardjbc210942005-07-21 10:07:13 +000014236 case 0xF8: /* CLC */
14237 case 0xF9: /* STC */
14238 case 0xF5: /* CMC */
14239 t0 = newTemp(Ity_I32);
14240 t1 = newTemp(Ity_I32);
14241 assign( t0, mk_x86g_calculate_eflags_all() );
14242 switch (opc) {
14243 case 0xF8:
14244 assign( t1, binop(Iop_And32, mkexpr(t0),
14245 mkU32(~X86G_CC_MASK_C)));
14246 DIP("clc\n");
14247 break;
14248 case 0xF9:
14249 assign( t1, binop(Iop_Or32, mkexpr(t0),
14250 mkU32(X86G_CC_MASK_C)));
14251 DIP("stc\n");
14252 break;
14253 case 0xF5:
14254 assign( t1, binop(Iop_Xor32, mkexpr(t0),
14255 mkU32(X86G_CC_MASK_C)));
14256 DIP("cmc\n");
14257 break;
14258 default:
14259 vpanic("disInstr(x86)(clc/stc/cmc)");
14260 }
14261 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(X86G_CC_OP_COPY) ));
14262 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
14263 stmt( IRStmt_Put( OFFB_CC_DEP1, mkexpr(t1) ));
14264 /* Set NDEP even though it isn't used. This makes redundant-PUT
14265 elimination of previous stores to this field work better. */
14266 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
14267 break;
sewardj82292882004-07-27 00:15:59 +000014268
sewardja384eb92007-11-16 02:30:38 +000014269 case 0xD6: /* SALC */
14270 t0 = newTemp(Ity_I32);
14271 t1 = newTemp(Ity_I32);
14272 assign( t0, binop(Iop_And32,
14273 mk_x86g_calculate_eflags_c(),
14274 mkU32(1)) );
14275 assign( t1, binop(Iop_Sar32,
14276 binop(Iop_Shl32, mkexpr(t0), mkU8(31)),
14277 mkU8(31)) );
14278 putIReg(1, R_EAX, unop(Iop_32to8, mkexpr(t1)) );
14279 DIP("salc\n");
14280 break;
14281
sewardj82292882004-07-27 00:15:59 +000014282 /* REPNE prefix insn */
14283 case 0xF2: {
sewardj068baa22008-05-11 10:11:58 +000014284 Addr32 eip_orig = guest_EIP_bbstart + delta_start;
sewardj9c3b25a2007-04-05 15:06:56 +000014285 if (sorb != 0) goto decode_failure;
sewardj82292882004-07-27 00:15:59 +000014286 abyte = getIByte(delta); delta++;
14287
14288 if (abyte == 0x66) { sz = 2; abyte = getIByte(delta); delta++; }
sewardj82292882004-07-27 00:15:59 +000014289
14290 switch (abyte) {
14291 /* According to the Intel manual, "repne movs" should never occur, but
14292 * in practice it has happened, so allow for it here... */
sewardj180e8b32004-07-29 01:40:11 +000014293 case 0xA4: sz = 1; /* REPNE MOVS<sz> */
sewardjcea96622006-11-14 15:33:05 +000014294 case 0xA5:
sewardjc6f970f2012-04-02 21:54:49 +000014295 dis_REP_op ( &dres, X86CondNZ, dis_MOVS, sz, eip_orig,
14296 guest_EIP_bbstart+delta, "repne movs" );
sewardjcea96622006-11-14 15:33:05 +000014297 break;
sewardj842dfb42008-05-09 08:53:50 +000014298
14299 case 0xA6: sz = 1; /* REPNE CMP<sz> */
14300 case 0xA7:
sewardjc6f970f2012-04-02 21:54:49 +000014301 dis_REP_op ( &dres, X86CondNZ, dis_CMPS, sz, eip_orig,
14302 guest_EIP_bbstart+delta, "repne cmps" );
sewardj842dfb42008-05-09 08:53:50 +000014303 break;
14304
sewardjb69a6fa2006-11-14 15:13:55 +000014305 case 0xAA: sz = 1; /* REPNE STOS<sz> */
14306 case 0xAB:
sewardjc6f970f2012-04-02 21:54:49 +000014307 dis_REP_op ( &dres, X86CondNZ, dis_STOS, sz, eip_orig,
14308 guest_EIP_bbstart+delta, "repne stos" );
sewardjb69a6fa2006-11-14 15:13:55 +000014309 break;
14310
sewardj82292882004-07-27 00:15:59 +000014311 case 0xAE: sz = 1; /* REPNE SCAS<sz> */
sewardj2d4c3a02004-10-15 00:03:23 +000014312 case 0xAF:
sewardjc6f970f2012-04-02 21:54:49 +000014313 dis_REP_op ( &dres, X86CondNZ, dis_SCAS, sz, eip_orig,
14314 guest_EIP_bbstart+delta, "repne scas" );
sewardj82292882004-07-27 00:15:59 +000014315 break;
14316
14317 default:
14318 goto decode_failure;
14319 }
14320 break;
14321 }
sewardj64e1d652004-07-12 14:00:46 +000014322
14323 /* REP/REPE prefix insn (for SCAS and CMPS, 0xF3 means REPE,
14324 for the rest, it means REP) */
14325 case 0xF3: {
sewardj068baa22008-05-11 10:11:58 +000014326 Addr32 eip_orig = guest_EIP_bbstart + delta_start;
sewardj64e1d652004-07-12 14:00:46 +000014327 abyte = getIByte(delta); delta++;
14328
14329 if (abyte == 0x66) { sz = 2; abyte = getIByte(delta); delta++; }
sewardj64e1d652004-07-12 14:00:46 +000014330
sewardjc8851af2012-08-23 20:14:51 +000014331 if (sorb != 0 && abyte != 0x0F) goto decode_failure;
14332
sewardj64e1d652004-07-12 14:00:46 +000014333 switch (abyte) {
sewardjc8851af2012-08-23 20:14:51 +000014334 case 0x0F:
14335 switch (getIByte(delta)) {
14336 /* On older CPUs, TZCNT behaves the same as BSF. */
14337 case 0xBC: /* REP BSF Gv,Ev */
14338 delta = dis_bs_E_G ( sorb, sz, delta + 1, True );
14339 break;
14340 /* On older CPUs, LZCNT behaves the same as BSR. */
14341 case 0xBD: /* REP BSR Gv,Ev */
14342 delta = dis_bs_E_G ( sorb, sz, delta + 1, False );
14343 break;
14344 default:
14345 goto decode_failure;
14346 }
14347 break;
14348
sewardj64e1d652004-07-12 14:00:46 +000014349 case 0xA4: sz = 1; /* REP MOVS<sz> */
14350 case 0xA5:
sewardjc6f970f2012-04-02 21:54:49 +000014351 dis_REP_op ( &dres, X86CondAlways, dis_MOVS, sz, eip_orig,
14352 guest_EIP_bbstart+delta, "rep movs" );
sewardj64e1d652004-07-12 14:00:46 +000014353 break;
14354
14355 case 0xA6: sz = 1; /* REPE CMP<sz> */
sewardj2d4c3a02004-10-15 00:03:23 +000014356 case 0xA7:
sewardjc6f970f2012-04-02 21:54:49 +000014357 dis_REP_op ( &dres, X86CondZ, dis_CMPS, sz, eip_orig,
14358 guest_EIP_bbstart+delta, "repe cmps" );
sewardj64e1d652004-07-12 14:00:46 +000014359 break;
14360
14361 case 0xAA: sz = 1; /* REP STOS<sz> */
14362 case 0xAB:
sewardjc6f970f2012-04-02 21:54:49 +000014363 dis_REP_op ( &dres, X86CondAlways, dis_STOS, sz, eip_orig,
14364 guest_EIP_bbstart+delta, "rep stos" );
sewardj64e1d652004-07-12 14:00:46 +000014365 break;
sewardj576f3232006-04-12 17:30:46 +000014366
sewardjdfb038d2007-11-25 01:34:03 +000014367 case 0xAC: sz = 1; /* REP LODS<sz> */
14368 case 0xAD:
sewardjc6f970f2012-04-02 21:54:49 +000014369 dis_REP_op ( &dres, X86CondAlways, dis_LODS, sz, eip_orig,
14370 guest_EIP_bbstart+delta, "rep lods" );
sewardjdfb038d2007-11-25 01:34:03 +000014371 break;
14372
sewardj576f3232006-04-12 17:30:46 +000014373 case 0xAE: sz = 1; /* REPE SCAS<sz> */
14374 case 0xAF:
sewardjc6f970f2012-04-02 21:54:49 +000014375 dis_REP_op ( &dres, X86CondZ, dis_SCAS, sz, eip_orig,
14376 guest_EIP_bbstart+delta, "repe scas" );
sewardj576f3232006-04-12 17:30:46 +000014377 break;
sewardj43b8df12004-11-26 12:18:51 +000014378
14379 case 0x90: /* REP NOP (PAUSE) */
14380 /* a hint to the P4 re spin-wait loop */
14381 DIP("rep nop (P4 pause)\n");
sewardj7ec59f62005-03-12 16:47:18 +000014382 /* "observe" the hint. The Vex client needs to be careful not
14383 to cause very long delays as a result, though. */
sewardjc6f970f2012-04-02 21:54:49 +000014384 jmp_lit(&dres, Ijk_Yield, ((Addr32)guest_EIP_bbstart)+delta);
14385 vassert(dres.whatNext == Dis_StopHere);
sewardj43b8df12004-11-26 12:18:51 +000014386 break;
14387
sewardj7d3d3472005-08-12 23:51:31 +000014388 case 0xC3: /* REP RET -- same as normal ret? */
sewardjc6f970f2012-04-02 21:54:49 +000014389 dis_ret(&dres, 0);
sewardj7d3d3472005-08-12 23:51:31 +000014390 DIP("rep ret\n");
14391 break;
sewardj64e1d652004-07-12 14:00:46 +000014392
14393 default:
14394 goto decode_failure;
14395 }
14396 break;
14397 }
sewardj0611d802004-07-11 02:37:54 +000014398
14399 /* ------------------------ XCHG ----------------------- */
14400
sewardjc4356f02007-11-09 21:15:04 +000014401 /* XCHG reg,mem automatically asserts LOCK# even without a LOCK
sewardj1fb8c922009-07-12 12:56:53 +000014402 prefix; hence it must be translated with an IRCAS (at least, the
14403 memory variant). */
sewardj0611d802004-07-11 02:37:54 +000014404 case 0x86: /* XCHG Gb,Eb */
14405 sz = 1;
14406 /* Fall through ... */
14407 case 0x87: /* XCHG Gv,Ev */
14408 modrm = getIByte(delta);
14409 ty = szToITy(sz);
14410 t1 = newTemp(ty); t2 = newTemp(ty);
14411 if (epartIsReg(modrm)) {
sewardj5bd4d162004-11-10 13:02:48 +000014412 assign(t1, getIReg(sz, eregOfRM(modrm)));
14413 assign(t2, getIReg(sz, gregOfRM(modrm)));
14414 putIReg(sz, gregOfRM(modrm), mkexpr(t1));
14415 putIReg(sz, eregOfRM(modrm), mkexpr(t2));
sewardj0611d802004-07-11 02:37:54 +000014416 delta++;
14417 DIP("xchg%c %s, %s\n",
14418 nameISize(sz), nameIReg(sz,gregOfRM(modrm)),
14419 nameIReg(sz,eregOfRM(modrm)));
14420 } else {
sewardje9d8a262009-07-01 08:06:34 +000014421 *expect_CAS = True;
sewardj0c12ea82004-07-12 08:18:16 +000014422 addr = disAMode ( &alen, sorb, delta, dis_buf );
sewardj5bd4d162004-11-10 13:02:48 +000014423 assign( t1, loadLE(ty,mkexpr(addr)) );
14424 assign( t2, getIReg(sz,gregOfRM(modrm)) );
sewardje9d8a262009-07-01 08:06:34 +000014425 casLE( mkexpr(addr),
14426 mkexpr(t1), mkexpr(t2), guest_EIP_curr_instr );
sewardj5bd4d162004-11-10 13:02:48 +000014427 putIReg( sz, gregOfRM(modrm), mkexpr(t1) );
14428 delta += alen;
sewardj0611d802004-07-11 02:37:54 +000014429 DIP("xchg%c %s, %s\n", nameISize(sz),
14430 nameIReg(sz,gregOfRM(modrm)), dis_buf);
sewardj0611d802004-07-11 02:37:54 +000014431 }
14432 break;
sewardje87b4842004-07-10 12:23:30 +000014433
14434 case 0x90: /* XCHG eAX,eAX */
14435 DIP("nop\n");
14436 break;
sewardj64e1d652004-07-12 14:00:46 +000014437 case 0x91: /* XCHG eAX,eCX */
14438 case 0x92: /* XCHG eAX,eDX */
14439 case 0x93: /* XCHG eAX,eBX */
14440 case 0x94: /* XCHG eAX,eSP */
14441 case 0x95: /* XCHG eAX,eBP */
14442 case 0x96: /* XCHG eAX,eSI */
14443 case 0x97: /* XCHG eAX,eDI */
14444 codegen_xchg_eAX_Reg ( sz, opc - 0x90 );
14445 break;
14446
sewardj048de4d2006-11-12 22:25:21 +000014447 /* ------------------------ XLAT ----------------------- */
14448
14449 case 0xD7: /* XLAT */
14450 if (sz != 4) goto decode_failure; /* sz == 2 is also allowed (0x66) */
14451 putIReg(
14452 1,
14453 R_EAX/*AL*/,
14454 loadLE(Ity_I8,
14455 handleSegOverride(
14456 sorb,
14457 binop(Iop_Add32,
14458 getIReg(4, R_EBX),
14459 unop(Iop_8Uto32, getIReg(1, R_EAX/*AL*/))))));
14460
14461 DIP("xlat%c [ebx]\n", nameISize(sz));
14462 break;
sewardjd14c5702005-10-29 19:19:51 +000014463
14464 /* ------------------------ IN / OUT ----------------------- */
14465
14466 case 0xE4: /* IN imm8, AL */
14467 sz = 1;
14468 t1 = newTemp(Ity_I32);
14469 abyte = getIByte(delta); delta++;
14470 assign(t1, mkU32( abyte & 0xFF ));
florianb1737742015-08-03 16:03:13 +000014471 DIP("in%c $%d,%s\n", nameISize(sz), abyte, nameIReg(sz,R_EAX));
sewardjd14c5702005-10-29 19:19:51 +000014472 goto do_IN;
14473 case 0xE5: /* IN imm8, eAX */
14474 vassert(sz == 2 || sz == 4);
14475 t1 = newTemp(Ity_I32);
14476 abyte = getIByte(delta); delta++;
14477 assign(t1, mkU32( abyte & 0xFF ));
florianb1737742015-08-03 16:03:13 +000014478 DIP("in%c $%d,%s\n", nameISize(sz), abyte, nameIReg(sz,R_EAX));
sewardjd14c5702005-10-29 19:19:51 +000014479 goto do_IN;
14480 case 0xEC: /* IN %DX, AL */
14481 sz = 1;
14482 t1 = newTemp(Ity_I32);
14483 assign(t1, unop(Iop_16Uto32, getIReg(2, R_EDX)));
14484 DIP("in%c %s,%s\n", nameISize(sz), nameIReg(2,R_EDX),
14485 nameIReg(sz,R_EAX));
14486 goto do_IN;
14487 case 0xED: /* IN %DX, eAX */
14488 vassert(sz == 2 || sz == 4);
14489 t1 = newTemp(Ity_I32);
14490 assign(t1, unop(Iop_16Uto32, getIReg(2, R_EDX)));
14491 DIP("in%c %s,%s\n", nameISize(sz), nameIReg(2,R_EDX),
14492 nameIReg(sz,R_EAX));
14493 goto do_IN;
14494 do_IN: {
14495 /* At this point, sz indicates the width, and t1 is a 32-bit
14496 value giving port number. */
14497 IRDirty* d;
14498 vassert(sz == 1 || sz == 2 || sz == 4);
14499 ty = szToITy(sz);
14500 t2 = newTemp(Ity_I32);
14501 d = unsafeIRDirty_1_N(
14502 t2,
14503 0/*regparms*/,
14504 "x86g_dirtyhelper_IN",
14505 &x86g_dirtyhelper_IN,
14506 mkIRExprVec_2( mkexpr(t1), mkU32(sz) )
14507 );
14508 /* do the call, dumping the result in t2. */
14509 stmt( IRStmt_Dirty(d) );
14510 putIReg(sz, R_EAX, narrowTo( ty, mkexpr(t2) ) );
14511 break;
14512 }
14513
14514 case 0xE6: /* OUT AL, imm8 */
14515 sz = 1;
14516 t1 = newTemp(Ity_I32);
14517 abyte = getIByte(delta); delta++;
14518 assign( t1, mkU32( abyte & 0xFF ) );
florianb1737742015-08-03 16:03:13 +000014519 DIP("out%c %s,$%d\n", nameISize(sz), nameIReg(sz,R_EAX), abyte);
sewardjd14c5702005-10-29 19:19:51 +000014520 goto do_OUT;
14521 case 0xE7: /* OUT eAX, imm8 */
14522 vassert(sz == 2 || sz == 4);
14523 t1 = newTemp(Ity_I32);
14524 abyte = getIByte(delta); delta++;
14525 assign( t1, mkU32( abyte & 0xFF ) );
florianb1737742015-08-03 16:03:13 +000014526 DIP("out%c %s,$%d\n", nameISize(sz), nameIReg(sz,R_EAX), abyte);
sewardjd14c5702005-10-29 19:19:51 +000014527 goto do_OUT;
14528 case 0xEE: /* OUT AL, %DX */
14529 sz = 1;
14530 t1 = newTemp(Ity_I32);
14531 assign( t1, unop(Iop_16Uto32, getIReg(2, R_EDX)) );
14532 DIP("out%c %s,%s\n", nameISize(sz), nameIReg(sz,R_EAX),
14533 nameIReg(2,R_EDX));
14534 goto do_OUT;
14535 case 0xEF: /* OUT eAX, %DX */
14536 vassert(sz == 2 || sz == 4);
14537 t1 = newTemp(Ity_I32);
14538 assign( t1, unop(Iop_16Uto32, getIReg(2, R_EDX)) );
14539 DIP("out%c %s,%s\n", nameISize(sz), nameIReg(sz,R_EAX),
14540 nameIReg(2,R_EDX));
14541 goto do_OUT;
14542 do_OUT: {
14543 /* At this point, sz indicates the width, and t1 is a 32-bit
14544 value giving port number. */
14545 IRDirty* d;
14546 vassert(sz == 1 || sz == 2 || sz == 4);
14547 ty = szToITy(sz);
14548 d = unsafeIRDirty_0_N(
14549 0/*regparms*/,
14550 "x86g_dirtyhelper_OUT",
14551 &x86g_dirtyhelper_OUT,
14552 mkIRExprVec_3( mkexpr(t1),
14553 widenUto32( getIReg(sz, R_EAX) ),
14554 mkU32(sz) )
14555 );
14556 stmt( IRStmt_Dirty(d) );
14557 break;
14558 }
sewardj0611d802004-07-11 02:37:54 +000014559
14560 /* ------------------------ (Grp1 extensions) ---------- */
14561
sewardj792d7712008-10-31 21:27:38 +000014562 case 0x82: /* Grp1 Ib,Eb too. Apparently this is the same as
14563 case 0x80, but only in 32-bit mode. */
14564 /* fallthru */
sewardj0611d802004-07-11 02:37:54 +000014565 case 0x80: /* Grp1 Ib,Eb */
14566 modrm = getIByte(delta);
14567 am_sz = lengthAMode(delta);
14568 sz = 1;
14569 d_sz = 1;
sewardjc2ac51e2004-07-12 01:03:26 +000014570 d32 = getUChar(delta + am_sz);
sewardje9d8a262009-07-01 08:06:34 +000014571 delta = dis_Grp1 ( sorb, pfx_lock, delta, modrm, am_sz, d_sz, sz, d32 );
sewardj0611d802004-07-11 02:37:54 +000014572 break;
sewardje05c42c2004-07-08 20:25:10 +000014573
14574 case 0x81: /* Grp1 Iv,Ev */
14575 modrm = getIByte(delta);
14576 am_sz = lengthAMode(delta);
14577 d_sz = sz;
14578 d32 = getUDisp(d_sz, delta + am_sz);
sewardje9d8a262009-07-01 08:06:34 +000014579 delta = dis_Grp1 ( sorb, pfx_lock, delta, modrm, am_sz, d_sz, sz, d32 );
sewardje05c42c2004-07-08 20:25:10 +000014580 break;
sewardjd1061ab2004-07-08 01:45:30 +000014581
14582 case 0x83: /* Grp1 Ib,Ev */
14583 modrm = getIByte(delta);
14584 am_sz = lengthAMode(delta);
14585 d_sz = 1;
14586 d32 = getSDisp8(delta + am_sz);
sewardje9d8a262009-07-01 08:06:34 +000014587 delta = dis_Grp1 ( sorb, pfx_lock, delta, modrm, am_sz, d_sz, sz, d32 );
sewardjd1061ab2004-07-08 01:45:30 +000014588 break;
14589
sewardjc2ac51e2004-07-12 01:03:26 +000014590 /* ------------------------ (Grp2 extensions) ---------- */
14591
sewardjd51dc812007-03-20 14:18:45 +000014592 case 0xC0: { /* Grp2 Ib,Eb */
14593 Bool decode_OK = True;
sewardjc2ac51e2004-07-12 01:03:26 +000014594 modrm = getIByte(delta);
14595 am_sz = lengthAMode(delta);
14596 d_sz = 1;
sewardj180e8b32004-07-29 01:40:11 +000014597 d32 = getUChar(delta + am_sz);
sewardjc2ac51e2004-07-12 01:03:26 +000014598 sz = 1;
sewardj6d2638e2004-07-15 09:38:27 +000014599 delta = dis_Grp2 ( sorb, delta, modrm, am_sz, d_sz, sz,
sewardjd51dc812007-03-20 14:18:45 +000014600 mkU8(d32 & 0xFF), NULL, &decode_OK );
14601 if (!decode_OK)
14602 goto decode_failure;
sewardjc2ac51e2004-07-12 01:03:26 +000014603 break;
sewardjd51dc812007-03-20 14:18:45 +000014604 }
14605 case 0xC1: { /* Grp2 Ib,Ev */
14606 Bool decode_OK = True;
sewardjc2ac51e2004-07-12 01:03:26 +000014607 modrm = getIByte(delta);
sewardje90ad6a2004-07-10 19:02:10 +000014608 am_sz = lengthAMode(delta);
14609 d_sz = 1;
sewardj180e8b32004-07-29 01:40:11 +000014610 d32 = getUChar(delta + am_sz);
sewardj6d2638e2004-07-15 09:38:27 +000014611 delta = dis_Grp2 ( sorb, delta, modrm, am_sz, d_sz, sz,
sewardjd51dc812007-03-20 14:18:45 +000014612 mkU8(d32 & 0xFF), NULL, &decode_OK );
14613 if (!decode_OK)
14614 goto decode_failure;
sewardje90ad6a2004-07-10 19:02:10 +000014615 break;
sewardjd51dc812007-03-20 14:18:45 +000014616 }
14617 case 0xD0: { /* Grp2 1,Eb */
14618 Bool decode_OK = True;
sewardj180e8b32004-07-29 01:40:11 +000014619 modrm = getIByte(delta);
14620 am_sz = lengthAMode(delta);
14621 d_sz = 0;
14622 d32 = 1;
14623 sz = 1;
14624 delta = dis_Grp2 ( sorb, delta, modrm, am_sz, d_sz, sz,
sewardjd51dc812007-03-20 14:18:45 +000014625 mkU8(d32), NULL, &decode_OK );
14626 if (!decode_OK)
14627 goto decode_failure;
sewardj180e8b32004-07-29 01:40:11 +000014628 break;
sewardjd51dc812007-03-20 14:18:45 +000014629 }
14630 case 0xD1: { /* Grp2 1,Ev */
14631 Bool decode_OK = True;
sewardjc2ac51e2004-07-12 01:03:26 +000014632 modrm = getUChar(delta);
14633 am_sz = lengthAMode(delta);
14634 d_sz = 0;
14635 d32 = 1;
sewardj6d2638e2004-07-15 09:38:27 +000014636 delta = dis_Grp2 ( sorb, delta, modrm, am_sz, d_sz, sz,
sewardjd51dc812007-03-20 14:18:45 +000014637 mkU8(d32), NULL, &decode_OK );
14638 if (!decode_OK)
14639 goto decode_failure;
sewardjc2ac51e2004-07-12 01:03:26 +000014640 break;
sewardjd51dc812007-03-20 14:18:45 +000014641 }
14642 case 0xD2: { /* Grp2 CL,Eb */
14643 Bool decode_OK = True;
sewardj8c7f1ab2004-07-29 20:31:09 +000014644 modrm = getUChar(delta);
14645 am_sz = lengthAMode(delta);
14646 d_sz = 0;
14647 sz = 1;
14648 delta = dis_Grp2 ( sorb, delta, modrm, am_sz, d_sz, sz,
sewardjd51dc812007-03-20 14:18:45 +000014649 getIReg(1,R_ECX), "%cl", &decode_OK );
14650 if (!decode_OK)
14651 goto decode_failure;
sewardj8c7f1ab2004-07-29 20:31:09 +000014652 break;
sewardjd51dc812007-03-20 14:18:45 +000014653 }
14654 case 0xD3: { /* Grp2 CL,Ev */
14655 Bool decode_OK = True;
sewardj9334b0f2004-07-10 22:43:54 +000014656 modrm = getIByte(delta);
14657 am_sz = lengthAMode(delta);
14658 d_sz = 0;
14659 delta = dis_Grp2 ( sorb, delta, modrm, am_sz, d_sz, sz,
sewardjd51dc812007-03-20 14:18:45 +000014660 getIReg(1,R_ECX), "%cl", &decode_OK );
14661 if (!decode_OK)
14662 goto decode_failure;
sewardj9334b0f2004-07-10 22:43:54 +000014663 break;
sewardjd51dc812007-03-20 14:18:45 +000014664 }
sewardj9334b0f2004-07-10 22:43:54 +000014665
sewardj940e8c92004-07-11 16:53:24 +000014666 /* ------------------------ (Grp3 extensions) ---------- */
14667
sewardjd51dc812007-03-20 14:18:45 +000014668 case 0xF6: { /* Grp3 Eb */
14669 Bool decode_OK = True;
sewardje9d8a262009-07-01 08:06:34 +000014670 delta = dis_Grp3 ( sorb, pfx_lock, 1, delta, &decode_OK );
sewardjd51dc812007-03-20 14:18:45 +000014671 if (!decode_OK)
14672 goto decode_failure;
sewardj940e8c92004-07-11 16:53:24 +000014673 break;
sewardjd51dc812007-03-20 14:18:45 +000014674 }
14675 case 0xF7: { /* Grp3 Ev */
14676 Bool decode_OK = True;
sewardje9d8a262009-07-01 08:06:34 +000014677 delta = dis_Grp3 ( sorb, pfx_lock, sz, delta, &decode_OK );
sewardjd51dc812007-03-20 14:18:45 +000014678 if (!decode_OK)
14679 goto decode_failure;
sewardj940e8c92004-07-11 16:53:24 +000014680 break;
sewardjd51dc812007-03-20 14:18:45 +000014681 }
sewardj940e8c92004-07-11 16:53:24 +000014682
sewardjc2ac51e2004-07-12 01:03:26 +000014683 /* ------------------------ (Grp4 extensions) ---------- */
14684
sewardjd51dc812007-03-20 14:18:45 +000014685 case 0xFE: { /* Grp4 Eb */
14686 Bool decode_OK = True;
sewardje9d8a262009-07-01 08:06:34 +000014687 delta = dis_Grp4 ( sorb, pfx_lock, delta, &decode_OK );
sewardjd51dc812007-03-20 14:18:45 +000014688 if (!decode_OK)
14689 goto decode_failure;
sewardjc2ac51e2004-07-12 01:03:26 +000014690 break;
sewardjd51dc812007-03-20 14:18:45 +000014691 }
sewardj0611d802004-07-11 02:37:54 +000014692
14693 /* ------------------------ (Grp5 extensions) ---------- */
14694
sewardjd51dc812007-03-20 14:18:45 +000014695 case 0xFF: { /* Grp5 Ev */
14696 Bool decode_OK = True;
sewardje9d8a262009-07-01 08:06:34 +000014697 delta = dis_Grp5 ( sorb, pfx_lock, sz, delta, &dres, &decode_OK );
sewardjd51dc812007-03-20 14:18:45 +000014698 if (!decode_OK)
14699 goto decode_failure;
sewardj0611d802004-07-11 02:37:54 +000014700 break;
sewardjd51dc812007-03-20 14:18:45 +000014701 }
sewardje87b4842004-07-10 12:23:30 +000014702
14703 /* ------------------------ Escapes to 2-byte opcodes -- */
14704
14705 case 0x0F: {
14706 opc = getIByte(delta); delta++;
14707 switch (opc) {
14708
sewardj490ad382005-03-13 17:25:53 +000014709 /* =-=-=-=-=-=-=-=-=- Grp8 =-=-=-=-=-=-=-=-=-=-=-= */
14710
14711 case 0xBA: { /* Grp8 Ib,Ev */
14712 Bool decode_OK = False;
14713 modrm = getUChar(delta);
14714 am_sz = lengthAMode(delta);
14715 d32 = getSDisp8(delta + am_sz);
sewardje9d8a262009-07-01 08:06:34 +000014716 delta = dis_Grp8_Imm ( sorb, pfx_lock, delta, modrm,
14717 am_sz, sz, d32, &decode_OK );
sewardj490ad382005-03-13 17:25:53 +000014718 if (!decode_OK)
14719 goto decode_failure;
14720 break;
14721 }
sewardjce646f22004-08-31 23:55:54 +000014722
14723 /* =-=-=-=-=-=-=-=-=- BSF/BSR -=-=-=-=-=-=-=-=-=-= */
14724
14725 case 0xBC: /* BSF Gv,Ev */
14726 delta = dis_bs_E_G ( sorb, sz, delta, True );
14727 break;
14728 case 0xBD: /* BSR Gv,Ev */
14729 delta = dis_bs_E_G ( sorb, sz, delta, False );
14730 break;
sewardj1c4208f2004-08-25 13:25:29 +000014731
14732 /* =-=-=-=-=-=-=-=-=- BSWAP -=-=-=-=-=-=-=-=-=-=-= */
14733
14734 case 0xC8: /* BSWAP %eax */
14735 case 0xC9:
14736 case 0xCA:
sewardjb4666cf2004-10-23 00:21:50 +000014737 case 0xCB:
14738 case 0xCC:
14739 case 0xCD:
sewardj1c4208f2004-08-25 13:25:29 +000014740 case 0xCE:
sewardj1c6f9912004-09-07 10:15:24 +000014741 case 0xCF: /* BSWAP %edi */
sewardj1c4208f2004-08-25 13:25:29 +000014742 /* AFAICS from the Intel docs, this only exists at size 4. */
sewardj021f6b42012-08-23 23:39:49 +000014743 if (sz != 4) goto decode_failure;
14744
sewardj1c4208f2004-08-25 13:25:29 +000014745 t1 = newTemp(Ity_I32);
sewardj1c4208f2004-08-25 13:25:29 +000014746 assign( t1, getIReg(4, opc-0xC8) );
sewardj021f6b42012-08-23 23:39:49 +000014747 t2 = math_BSWAP(t1, Ity_I32);
sewardj1c4208f2004-08-25 13:25:29 +000014748
14749 putIReg(4, opc-0xC8, mkexpr(t2));
sewardj1c4208f2004-08-25 13:25:29 +000014750 DIP("bswapl %s\n", nameIReg(4, opc-0xC8));
14751 break;
14752
sewardj1c6f9912004-09-07 10:15:24 +000014753 /* =-=-=-=-=-=-=-=-=- BT/BTS/BTR/BTC =-=-=-=-=-=-= */
14754
14755 case 0xA3: /* BT Gv,Ev */
sewardj02834302010-07-29 18:10:51 +000014756 delta = dis_bt_G_E ( vbi, sorb, pfx_lock, sz, delta, BtOpNone );
sewardj1c6f9912004-09-07 10:15:24 +000014757 break;
sewardje6709112004-09-10 18:37:18 +000014758 case 0xB3: /* BTR Gv,Ev */
sewardj02834302010-07-29 18:10:51 +000014759 delta = dis_bt_G_E ( vbi, sorb, pfx_lock, sz, delta, BtOpReset );
sewardje6709112004-09-10 18:37:18 +000014760 break;
sewardj1c6f9912004-09-07 10:15:24 +000014761 case 0xAB: /* BTS Gv,Ev */
sewardj02834302010-07-29 18:10:51 +000014762 delta = dis_bt_G_E ( vbi, sorb, pfx_lock, sz, delta, BtOpSet );
sewardj1c6f9912004-09-07 10:15:24 +000014763 break;
sewardj4963a422004-10-14 23:34:03 +000014764 case 0xBB: /* BTC Gv,Ev */
sewardj02834302010-07-29 18:10:51 +000014765 delta = dis_bt_G_E ( vbi, sorb, pfx_lock, sz, delta, BtOpComp );
sewardj4963a422004-10-14 23:34:03 +000014766 break;
sewardj458a6f82004-08-25 12:46:02 +000014767
14768 /* =-=-=-=-=-=-=-=-=- CMOV =-=-=-=-=-=-=-=-=-=-=-= */
14769
sewardj2d4c3a02004-10-15 00:03:23 +000014770 case 0x40:
14771 case 0x41:
sewardj458a6f82004-08-25 12:46:02 +000014772 case 0x42: /* CMOVBb/CMOVNAEb (cmov below) */
14773 case 0x43: /* CMOVNBb/CMOVAEb (cmov not below) */
14774 case 0x44: /* CMOVZb/CMOVEb (cmov zero) */
14775 case 0x45: /* CMOVNZb/CMOVNEb (cmov not zero) */
14776 case 0x46: /* CMOVBEb/CMOVNAb (cmov below or equal) */
14777 case 0x47: /* CMOVNBEb/CMOVAb (cmov not below or equal) */
sewardjce646f22004-08-31 23:55:54 +000014778 case 0x48: /* CMOVSb (cmov negative) */
sewardj458a6f82004-08-25 12:46:02 +000014779 case 0x49: /* CMOVSb (cmov not negative) */
sewardj2d4c3a02004-10-15 00:03:23 +000014780 case 0x4A: /* CMOVP (cmov parity even) */
14781 case 0x4B: /* CMOVNP (cmov parity odd) */
sewardj458a6f82004-08-25 12:46:02 +000014782 case 0x4C: /* CMOVLb/CMOVNGEb (cmov less) */
14783 case 0x4D: /* CMOVGEb/CMOVNLb (cmov greater or equal) */
14784 case 0x4E: /* CMOVLEb/CMOVNGb (cmov less or equal) */
14785 case 0x4F: /* CMOVGb/CMOVNLEb (cmov greater) */
sewardj2a9ad022004-11-25 02:46:58 +000014786 delta = dis_cmov_E_G(sorb, sz, (X86Condcode)(opc - 0x40), delta);
sewardj458a6f82004-08-25 12:46:02 +000014787 break;
14788
14789 /* =-=-=-=-=-=-=-=-=- CMPXCHG -=-=-=-=-=-=-=-=-=-= */
14790
sewardjc744e872004-08-26 11:24:39 +000014791 case 0xB0: /* CMPXCHG Gb,Eb */
sewardje9d8a262009-07-01 08:06:34 +000014792 delta = dis_cmpxchg_G_E ( sorb, pfx_lock, 1, delta );
sewardjc744e872004-08-26 11:24:39 +000014793 break;
sewardj458a6f82004-08-25 12:46:02 +000014794 case 0xB1: /* CMPXCHG Gv,Ev */
sewardje9d8a262009-07-01 08:06:34 +000014795 delta = dis_cmpxchg_G_E ( sorb, pfx_lock, sz, delta );
sewardj458a6f82004-08-25 12:46:02 +000014796 break;
sewardj300bb872005-08-12 23:04:48 +000014797
14798 case 0xC7: { /* CMPXCHG8B Gv (0F C7 /1) */
sewardje9d8a262009-07-01 08:06:34 +000014799 IRTemp expdHi = newTemp(Ity_I32);
14800 IRTemp expdLo = newTemp(Ity_I32);
14801 IRTemp dataHi = newTemp(Ity_I32);
14802 IRTemp dataLo = newTemp(Ity_I32);
14803 IRTemp oldHi = newTemp(Ity_I32);
14804 IRTemp oldLo = newTemp(Ity_I32);
sewardj300bb872005-08-12 23:04:48 +000014805 IRTemp flags_old = newTemp(Ity_I32);
14806 IRTemp flags_new = newTemp(Ity_I32);
sewardje9d8a262009-07-01 08:06:34 +000014807 IRTemp success = newTemp(Ity_I1);
14808
14809 /* Translate this using a DCAS, even if there is no LOCK
14810 prefix. Life is too short to bother with generating two
14811 different translations for the with/without-LOCK-prefix
14812 cases. */
14813 *expect_CAS = True;
sewardj300bb872005-08-12 23:04:48 +000014814
14815 /* Decode, and generate address. */
sewardje9d8a262009-07-01 08:06:34 +000014816 if (sz != 4) goto decode_failure;
sewardj300bb872005-08-12 23:04:48 +000014817 modrm = getIByte(delta);
14818 if (epartIsReg(modrm)) goto decode_failure;
14819 if (gregOfRM(modrm) != 1) goto decode_failure;
14820 addr = disAMode ( &alen, sorb, delta, dis_buf );
14821 delta += alen;
14822
sewardje9d8a262009-07-01 08:06:34 +000014823 /* Get the expected and new values. */
14824 assign( expdHi, getIReg(4,R_EDX) );
14825 assign( expdLo, getIReg(4,R_EAX) );
14826 assign( dataHi, getIReg(4,R_ECX) );
14827 assign( dataLo, getIReg(4,R_EBX) );
sewardj300bb872005-08-12 23:04:48 +000014828
sewardje9d8a262009-07-01 08:06:34 +000014829 /* Do the DCAS */
14830 stmt( IRStmt_CAS(
14831 mkIRCAS( oldHi, oldLo,
14832 Iend_LE, mkexpr(addr),
14833 mkexpr(expdHi), mkexpr(expdLo),
14834 mkexpr(dataHi), mkexpr(dataLo)
14835 )));
sewardj300bb872005-08-12 23:04:48 +000014836
sewardje9d8a262009-07-01 08:06:34 +000014837 /* success when oldHi:oldLo == expdHi:expdLo */
14838 assign( success,
sewardj1fb8c922009-07-12 12:56:53 +000014839 binop(Iop_CasCmpEQ32,
sewardje9d8a262009-07-01 08:06:34 +000014840 binop(Iop_Or32,
14841 binop(Iop_Xor32, mkexpr(oldHi), mkexpr(expdHi)),
14842 binop(Iop_Xor32, mkexpr(oldLo), mkexpr(expdLo))
14843 ),
14844 mkU32(0)
14845 ));
sewardj300bb872005-08-12 23:04:48 +000014846
sewardje9d8a262009-07-01 08:06:34 +000014847 /* If the DCAS is successful, that is to say oldHi:oldLo ==
14848 expdHi:expdLo, then put expdHi:expdLo back in EDX:EAX,
14849 which is where they came from originally. Both the actual
14850 contents of these two regs, and any shadow values, are
14851 unchanged. If the DCAS fails then we're putting into
14852 EDX:EAX the value seen in memory. */
14853 putIReg(4, R_EDX,
florian99dd03e2013-01-29 03:56:06 +000014854 IRExpr_ITE( mkexpr(success),
14855 mkexpr(expdHi), mkexpr(oldHi)
sewardje9d8a262009-07-01 08:06:34 +000014856 ));
14857 putIReg(4, R_EAX,
florian99dd03e2013-01-29 03:56:06 +000014858 IRExpr_ITE( mkexpr(success),
14859 mkexpr(expdLo), mkexpr(oldLo)
sewardje9d8a262009-07-01 08:06:34 +000014860 ));
sewardj300bb872005-08-12 23:04:48 +000014861
sewardje9d8a262009-07-01 08:06:34 +000014862 /* Copy the success bit into the Z flag and leave the others
14863 unchanged */
sewardj300bb872005-08-12 23:04:48 +000014864 assign( flags_old, widenUto32(mk_x86g_calculate_eflags_all()));
14865 assign(
14866 flags_new,
14867 binop(Iop_Or32,
14868 binop(Iop_And32, mkexpr(flags_old),
14869 mkU32(~X86G_CC_MASK_Z)),
14870 binop(Iop_Shl32,
14871 binop(Iop_And32,
sewardje9d8a262009-07-01 08:06:34 +000014872 unop(Iop_1Uto32, mkexpr(success)), mkU32(1)),
sewardj300bb872005-08-12 23:04:48 +000014873 mkU8(X86G_CC_SHIFT_Z)) ));
14874
14875 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(X86G_CC_OP_COPY) ));
14876 stmt( IRStmt_Put( OFFB_CC_DEP1, mkexpr(flags_new) ));
14877 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
14878 /* Set NDEP even though it isn't used. This makes
14879 redundant-PUT elimination of previous stores to this field
14880 work better. */
14881 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
14882
14883 /* Sheesh. Aren't you glad it was me and not you that had to
14884 write and validate all this grunge? */
14885
14886 DIP("cmpxchg8b %s\n", dis_buf);
14887 break;
14888 }
14889
sewardj588ea762004-09-10 18:56:32 +000014890 /* =-=-=-=-=-=-=-=-=- CPUID -=-=-=-=-=-=-=-=-=-=-= */
14891
sewardj7cb49d72004-10-24 22:31:25 +000014892 case 0xA2: { /* CPUID */
14893 /* Uses dirty helper:
sewardj9df271d2004-12-31 22:37:42 +000014894 void dirtyhelper_CPUID_sse[012] ( VexGuestX86State* )
sewardj7cb49d72004-10-24 22:31:25 +000014895 declared to mod eax, wr ebx, ecx, edx
14896 */
sewardj9df271d2004-12-31 22:37:42 +000014897 IRDirty* d = NULL;
sewardj9df271d2004-12-31 22:37:42 +000014898 void* fAddr = NULL;
florian55085f82012-11-21 00:36:55 +000014899 const HChar* fName = NULL;
philippe6d7c8e42015-06-17 21:33:19 +000014900 if (archinfo->hwcaps & VEX_HWCAPS_X86_SSE3) {
14901 fName = "x86g_dirtyhelper_CPUID_sse3";
14902 fAddr = &x86g_dirtyhelper_CPUID_sse3;
sewardj5117ce12006-01-27 21:20:15 +000014903 }
14904 else
philippe7ffce012015-06-18 21:31:32 +000014905 if (archinfo->hwcaps & VEX_HWCAPS_X86_SSE2) {
14906 fName = "x86g_dirtyhelper_CPUID_sse2";
14907 fAddr = &x86g_dirtyhelper_CPUID_sse2;
14908 }
14909 else
sewardj5117ce12006-01-27 21:20:15 +000014910 if (archinfo->hwcaps & VEX_HWCAPS_X86_SSE1) {
14911 fName = "x86g_dirtyhelper_CPUID_sse1";
14912 fAddr = &x86g_dirtyhelper_CPUID_sse1;
14913 }
14914 else
mjw6c65c122013-08-27 10:19:03 +000014915 if (archinfo->hwcaps & VEX_HWCAPS_X86_MMXEXT) {
14916 fName = "x86g_dirtyhelper_CPUID_mmxext";
14917 fAddr = &x86g_dirtyhelper_CPUID_mmxext;
14918 }
14919 else
sewardj5117ce12006-01-27 21:20:15 +000014920 if (archinfo->hwcaps == 0/*no SSE*/) {
14921 fName = "x86g_dirtyhelper_CPUID_sse0";
14922 fAddr = &x86g_dirtyhelper_CPUID_sse0;
14923 } else
14924 vpanic("disInstr(x86)(cpuid)");
14925
sewardj9df271d2004-12-31 22:37:42 +000014926 vassert(fName); vassert(fAddr);
14927 d = unsafeIRDirty_0_N ( 0/*regparms*/,
Elliott Hughesed398002017-06-21 14:41:24 -070014928 fName, fAddr, mkIRExprVec_1(IRExpr_GSPTR()) );
sewardj7cb49d72004-10-24 22:31:25 +000014929 /* declare guest state effects */
14930 d->nFxState = 4;
sewardjc9069f22012-06-01 16:09:50 +000014931 vex_bzero(&d->fxState, sizeof(d->fxState));
sewardj7cb49d72004-10-24 22:31:25 +000014932 d->fxState[0].fx = Ifx_Modify;
14933 d->fxState[0].offset = OFFB_EAX;
14934 d->fxState[0].size = 4;
14935 d->fxState[1].fx = Ifx_Write;
14936 d->fxState[1].offset = OFFB_EBX;
14937 d->fxState[1].size = 4;
sewardj32bfd3e2008-02-10 13:29:19 +000014938 d->fxState[2].fx = Ifx_Modify;
sewardj7cb49d72004-10-24 22:31:25 +000014939 d->fxState[2].offset = OFFB_ECX;
14940 d->fxState[2].size = 4;
14941 d->fxState[3].fx = Ifx_Write;
14942 d->fxState[3].offset = OFFB_EDX;
14943 d->fxState[3].size = 4;
14944 /* execute the dirty call, side-effecting guest state */
14945 stmt( IRStmt_Dirty(d) );
sewardj55860d82005-01-08 18:25:05 +000014946 /* CPUID is a serialising insn. So, just in case someone is
14947 using it as a memory fence ... */
sewardjc4356f02007-11-09 21:15:04 +000014948 stmt( IRStmt_MBE(Imbe_Fence) );
sewardj517a7d62004-10-25 09:52:18 +000014949 DIP("cpuid\n");
sewardj588ea762004-09-10 18:56:32 +000014950 break;
sewardj7cb49d72004-10-24 22:31:25 +000014951 }
14952
sewardj5bd4d162004-11-10 13:02:48 +000014953//-- if (!VG_(cpu_has_feature)(VG_X86_FEAT_CPUID))
14954//-- goto decode_failure;
sewardjc9a65702004-07-07 16:32:57 +000014955//--
14956//-- t1 = newTemp(cb);
14957//-- t2 = newTemp(cb);
14958//-- t3 = newTemp(cb);
14959//-- t4 = newTemp(cb);
14960//-- uInstr0(cb, CALLM_S, 0);
14961//--
14962//-- uInstr2(cb, GET, 4, ArchReg, R_EAX, TempReg, t1);
14963//-- uInstr1(cb, PUSH, 4, TempReg, t1);
14964//--
14965//-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t2);
14966//-- uLiteral(cb, 0);
14967//-- uInstr1(cb, PUSH, 4, TempReg, t2);
14968//--
14969//-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t3);
14970//-- uLiteral(cb, 0);
14971//-- uInstr1(cb, PUSH, 4, TempReg, t3);
14972//--
14973//-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t4);
14974//-- uLiteral(cb, 0);
14975//-- uInstr1(cb, PUSH, 4, TempReg, t4);
14976//--
14977//-- uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_CPUID));
14978//-- uFlagsRWU(cb, FlagsEmpty, FlagsEmpty, FlagsEmpty);
14979//--
14980//-- uInstr1(cb, POP, 4, TempReg, t4);
14981//-- uInstr2(cb, PUT, 4, TempReg, t4, ArchReg, R_EDX);
14982//--
14983//-- uInstr1(cb, POP, 4, TempReg, t3);
14984//-- uInstr2(cb, PUT, 4, TempReg, t3, ArchReg, R_ECX);
14985//--
14986//-- uInstr1(cb, POP, 4, TempReg, t2);
14987//-- uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_EBX);
14988//--
14989//-- uInstr1(cb, POP, 4, TempReg, t1);
14990//-- uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, R_EAX);
14991//--
14992//-- uInstr0(cb, CALLM_E, 0);
14993//-- DIP("cpuid\n");
14994//-- break;
14995//--
sewardj9334b0f2004-07-10 22:43:54 +000014996 /* =-=-=-=-=-=-=-=-=- MOVZX, MOVSX =-=-=-=-=-=-=-= */
14997
14998 case 0xB6: /* MOVZXb Eb,Gv */
sewardj6ba982f2006-05-03 17:57:15 +000014999 if (sz != 2 && sz != 4)
15000 goto decode_failure;
15001 delta = dis_movx_E_G ( sorb, delta, 1, sz, False );
sewardj9334b0f2004-07-10 22:43:54 +000015002 break;
sewardj6ba982f2006-05-03 17:57:15 +000015003
sewardj940e8c92004-07-11 16:53:24 +000015004 case 0xB7: /* MOVZXw Ew,Gv */
sewardj6ba982f2006-05-03 17:57:15 +000015005 if (sz != 4)
15006 goto decode_failure;
sewardj940e8c92004-07-11 16:53:24 +000015007 delta = dis_movx_E_G ( sorb, delta, 2, 4, False );
15008 break;
15009
sewardj0611d802004-07-11 02:37:54 +000015010 case 0xBE: /* MOVSXb Eb,Gv */
sewardj6ba982f2006-05-03 17:57:15 +000015011 if (sz != 2 && sz != 4)
15012 goto decode_failure;
15013 delta = dis_movx_E_G ( sorb, delta, 1, sz, True );
sewardj0611d802004-07-11 02:37:54 +000015014 break;
sewardj6ba982f2006-05-03 17:57:15 +000015015
sewardj7ed22952004-07-29 00:09:58 +000015016 case 0xBF: /* MOVSXw Ew,Gv */
sewardj33ca4ac2010-09-30 13:37:31 +000015017 if (sz != 4 && /* accept movsww, sigh, see #250799 */sz != 2)
sewardj6ba982f2006-05-03 17:57:15 +000015018 goto decode_failure;
sewardj33ca4ac2010-09-30 13:37:31 +000015019 delta = dis_movx_E_G ( sorb, delta, 2, sz, True );
sewardj7ed22952004-07-29 00:09:58 +000015020 break;
15021
sewardjc9a65702004-07-07 16:32:57 +000015022//-- /* =-=-=-=-=-=-=-=-=-=-= MOVNTI -=-=-=-=-=-=-=-=-= */
15023//--
15024//-- case 0xC3: /* MOVNTI Gv,Ev */
15025//-- vg_assert(sz == 4);
15026//-- modrm = getUChar(eip);
15027//-- vg_assert(!epartIsReg(modrm));
15028//-- t1 = newTemp(cb);
15029//-- uInstr2(cb, GET, 4, ArchReg, gregOfRM(modrm), TempReg, t1);
15030//-- pair = disAMode ( cb, sorb, eip, dis_buf );
15031//-- t2 = LOW24(pair);
15032//-- eip += HI8(pair);
15033//-- uInstr2(cb, STORE, 4, TempReg, t1, TempReg, t2);
15034//-- DIP("movnti %s,%s\n", nameIReg(4,gregOfRM(modrm)), dis_buf);
15035//-- break;
sewardjcf780b42004-07-13 18:42:17 +000015036
15037 /* =-=-=-=-=-=-=-=-=- MUL/IMUL =-=-=-=-=-=-=-=-=-= */
15038
15039 case 0xAF: /* IMUL Ev, Gv */
sewardj2a2ba8b2004-11-08 13:14:06 +000015040 delta = dis_mul_E_G ( sorb, sz, delta );
sewardjcf780b42004-07-13 18:42:17 +000015041 break;
sewardje87b4842004-07-10 12:23:30 +000015042
sewardjec387ca2006-08-01 18:36:25 +000015043 /* =-=-=-=-=-=-=-=-=- NOPs =-=-=-=-=-=-=-=-=-=-=-= */
15044
15045 case 0x1F:
15046 modrm = getUChar(delta);
15047 if (epartIsReg(modrm)) goto decode_failure;
15048 addr = disAMode ( &alen, sorb, delta, dis_buf );
15049 delta += alen;
15050 DIP("nop%c %s\n", nameISize(sz), dis_buf);
15051 break;
15052
sewardje87b4842004-07-10 12:23:30 +000015053 /* =-=-=-=-=-=-=-=-=- Jcond d32 -=-=-=-=-=-=-=-=-= */
15054 case 0x80:
15055 case 0x81:
15056 case 0x82: /* JBb/JNAEb (jump below) */
15057 case 0x83: /* JNBb/JAEb (jump not below) */
15058 case 0x84: /* JZb/JEb (jump zero) */
15059 case 0x85: /* JNZb/JNEb (jump not zero) */
15060 case 0x86: /* JBEb/JNAb (jump below or equal) */
15061 case 0x87: /* JNBEb/JAb (jump not below or equal) */
15062 case 0x88: /* JSb (jump negative) */
15063 case 0x89: /* JSb (jump not negative) */
15064 case 0x8A: /* JP (jump parity even) */
15065 case 0x8B: /* JNP/JPO (jump parity odd) */
15066 case 0x8C: /* JLb/JNGEb (jump less) */
15067 case 0x8D: /* JGEb/JNLb (jump greater or equal) */
15068 case 0x8E: /* JLEb/JNGb (jump less or equal) */
15069 case 0x8F: /* JGb/JNLEb (jump greater) */
sewardj984d9b12010-01-15 10:53:21 +000015070 { Int jmpDelta;
florian55085f82012-11-21 00:36:55 +000015071 const HChar* comment = "";
sewardj984d9b12010-01-15 10:53:21 +000015072 jmpDelta = (Int)getUDisp32(delta);
15073 d32 = (((Addr32)guest_EIP_bbstart)+delta+4) + jmpDelta;
sewardje87b4842004-07-10 12:23:30 +000015074 delta += 4;
sewardj984d9b12010-01-15 10:53:21 +000015075 if (resteerCisOk
15076 && vex_control.guest_chase_cond
sewardj0d925b12010-01-17 15:47:01 +000015077 && (Addr32)d32 != (Addr32)guest_EIP_bbstart
sewardj984d9b12010-01-15 10:53:21 +000015078 && jmpDelta < 0
florianbeac5302014-12-31 12:09:38 +000015079 && resteerOkFn( callback_opaque, (Addr32)d32) ) {
sewardj984d9b12010-01-15 10:53:21 +000015080 /* Speculation: assume this backward branch is taken. So
15081 we need to emit a side-exit to the insn following this
15082 one, on the negation of the condition, and continue at
sewardj0d925b12010-01-17 15:47:01 +000015083 the branch target address (d32). If we wind up back at
15084 the first instruction of the trace, just stop; it's
15085 better to let the IR loop unroller handle that case.*/
sewardj984d9b12010-01-15 10:53:21 +000015086 stmt( IRStmt_Exit(
sewardj0d925b12010-01-17 15:47:01 +000015087 mk_x86g_calculate_condition((X86Condcode)
15088 (1 ^ (opc - 0x80))),
sewardj984d9b12010-01-15 10:53:21 +000015089 Ijk_Boring,
sewardjc6f970f2012-04-02 21:54:49 +000015090 IRConst_U32(guest_EIP_bbstart+delta),
15091 OFFB_EIP ) );
sewardj984d9b12010-01-15 10:53:21 +000015092 dres.whatNext = Dis_ResteerC;
florian0eaa35f2015-01-02 13:34:15 +000015093 dres.continueAt = (Addr32)d32;
sewardj984d9b12010-01-15 10:53:21 +000015094 comment = "(assumed taken)";
15095 }
15096 else
15097 if (resteerCisOk
15098 && vex_control.guest_chase_cond
sewardj0d925b12010-01-17 15:47:01 +000015099 && (Addr32)d32 != (Addr32)guest_EIP_bbstart
sewardj984d9b12010-01-15 10:53:21 +000015100 && jmpDelta >= 0
15101 && resteerOkFn( callback_opaque,
florianbeac5302014-12-31 12:09:38 +000015102 (Addr32)(guest_EIP_bbstart+delta)) ) {
sewardj984d9b12010-01-15 10:53:21 +000015103 /* Speculation: assume this forward branch is not taken.
15104 So we need to emit a side-exit to d32 (the dest) and
15105 continue disassembling at the insn immediately
15106 following this one. */
15107 stmt( IRStmt_Exit(
15108 mk_x86g_calculate_condition((X86Condcode)(opc - 0x80)),
15109 Ijk_Boring,
sewardjc6f970f2012-04-02 21:54:49 +000015110 IRConst_U32(d32),
15111 OFFB_EIP ) );
sewardj984d9b12010-01-15 10:53:21 +000015112 dres.whatNext = Dis_ResteerC;
florian0eaa35f2015-01-02 13:34:15 +000015113 dres.continueAt = guest_EIP_bbstart + delta;
sewardj984d9b12010-01-15 10:53:21 +000015114 comment = "(assumed not taken)";
15115 }
15116 else {
15117 /* Conservative default translation - end the block at
15118 this point. */
sewardjc6f970f2012-04-02 21:54:49 +000015119 jcc_01( &dres, (X86Condcode)(opc - 0x80),
sewardj984d9b12010-01-15 10:53:21 +000015120 (Addr32)(guest_EIP_bbstart+delta), d32);
sewardjc6f970f2012-04-02 21:54:49 +000015121 vassert(dres.whatNext == Dis_StopHere);
sewardj984d9b12010-01-15 10:53:21 +000015122 }
15123 DIP("j%s-32 0x%x %s\n", name_X86Condcode(opc - 0x80), d32, comment);
sewardje87b4842004-07-10 12:23:30 +000015124 break;
sewardj984d9b12010-01-15 10:53:21 +000015125 }
sewardje87b4842004-07-10 12:23:30 +000015126
sewardj89cd0932004-09-08 18:23:25 +000015127 /* =-=-=-=-=-=-=-=-=- RDTSC -=-=-=-=-=-=-=-=-=-=-= */
sewardj4ed64292005-08-23 19:24:29 +000015128 case 0x31: { /* RDTSC */
15129 IRTemp val = newTemp(Ity_I64);
15130 IRExpr** args = mkIRExprVec_0();
15131 IRDirty* d = unsafeIRDirty_1_N (
15132 val,
15133 0/*regparms*/,
15134 "x86g_dirtyhelper_RDTSC",
15135 &x86g_dirtyhelper_RDTSC,
15136 args
15137 );
sewardja5cbbdc2005-08-23 23:17:38 +000015138 /* execute the dirty call, dumping the result in val. */
15139 stmt( IRStmt_Dirty(d) );
15140 putIReg(4, R_EDX, unop(Iop_64HIto32, mkexpr(val)));
15141 putIReg(4, R_EAX, unop(Iop_64to32, mkexpr(val)));
15142 DIP("rdtsc\n");
15143 break;
sewardj4ed64292005-08-23 19:24:29 +000015144 }
sewardj77b86be2004-07-11 13:28:24 +000015145
sewardjb64821b2004-12-14 10:00:16 +000015146 /* =-=-=-=-=-=-=-=-=- PUSH/POP Sreg =-=-=-=-=-=-=-=-=-= */
15147
15148 case 0xA1: /* POP %FS */
15149 dis_pop_segreg( R_FS, sz ); break;
15150 case 0xA9: /* POP %GS */
15151 dis_pop_segreg( R_GS, sz ); break;
15152
15153 case 0xA0: /* PUSH %FS */
15154 dis_push_segreg( R_FS, sz ); break;
15155 case 0xA8: /* PUSH %GS */
15156 dis_push_segreg( R_GS, sz ); break;
15157
sewardj77b86be2004-07-11 13:28:24 +000015158 /* =-=-=-=-=-=-=-=-=- SETcc Eb =-=-=-=-=-=-=-=-=-= */
15159 case 0x90:
15160 case 0x91:
15161 case 0x92: /* set-Bb/set-NAEb (jump below) */
15162 case 0x93: /* set-NBb/set-AEb (jump not below) */
15163 case 0x94: /* set-Zb/set-Eb (jump zero) */
15164 case 0x95: /* set-NZb/set-NEb (jump not zero) */
15165 case 0x96: /* set-BEb/set-NAb (jump below or equal) */
15166 case 0x97: /* set-NBEb/set-Ab (jump not below or equal) */
15167 case 0x98: /* set-Sb (jump negative) */
15168 case 0x99: /* set-Sb (jump not negative) */
15169 case 0x9A: /* set-P (jump parity even) */
15170 case 0x9B: /* set-NP (jump parity odd) */
15171 case 0x9C: /* set-Lb/set-NGEb (jump less) */
15172 case 0x9D: /* set-GEb/set-NLb (jump greater or equal) */
15173 case 0x9E: /* set-LEb/set-NGb (jump less or equal) */
15174 case 0x9F: /* set-Gb/set-NLEb (jump greater) */
sewardj5bd4d162004-11-10 13:02:48 +000015175 t1 = newTemp(Ity_I8);
sewardj2a9ad022004-11-25 02:46:58 +000015176 assign( t1, unop(Iop_1Uto8,mk_x86g_calculate_condition(opc-0x90)) );
sewardj77b86be2004-07-11 13:28:24 +000015177 modrm = getIByte(delta);
15178 if (epartIsReg(modrm)) {
15179 delta++;
sewardj5bd4d162004-11-10 13:02:48 +000015180 putIReg(1, eregOfRM(modrm), mkexpr(t1));
sewardj2a9ad022004-11-25 02:46:58 +000015181 DIP("set%s %s\n", name_X86Condcode(opc-0x90),
sewardj77b86be2004-07-11 13:28:24 +000015182 nameIReg(1,eregOfRM(modrm)));
15183 } else {
sewardj750f4072004-07-26 22:39:11 +000015184 addr = disAMode ( &alen, sorb, delta, dis_buf );
15185 delta += alen;
15186 storeLE( mkexpr(addr), mkexpr(t1) );
sewardj2a9ad022004-11-25 02:46:58 +000015187 DIP("set%s %s\n", name_X86Condcode(opc-0x90), dis_buf);
sewardj77b86be2004-07-11 13:28:24 +000015188 }
15189 break;
15190
sewardj180e8b32004-07-29 01:40:11 +000015191 /* =-=-=-=-=-=-=-=-=- SHLD/SHRD -=-=-=-=-=-=-=-=-= */
15192
15193 case 0xA4: /* SHLDv imm8,Gv,Ev */
15194 modrm = getIByte(delta);
15195 d32 = delta + lengthAMode(delta);
sewardj2d49b432005-02-01 00:37:06 +000015196 vex_sprintf(dis_buf, "$%d", getIByte(d32));
sewardj180e8b32004-07-29 01:40:11 +000015197 delta = dis_SHLRD_Gv_Ev (
15198 sorb, delta, modrm, sz,
15199 mkU8(getIByte(d32)), True, /* literal */
15200 dis_buf, True );
15201 break;
sewardja06e5562004-07-14 13:18:05 +000015202 case 0xA5: /* SHLDv %cl,Gv,Ev */
15203 modrm = getIByte(delta);
15204 delta = dis_SHLRD_Gv_Ev (
15205 sorb, delta, modrm, sz,
15206 getIReg(1,R_ECX), False, /* not literal */
15207 "%cl", True );
15208 break;
15209
sewardj68511542004-07-28 00:15:44 +000015210 case 0xAC: /* SHRDv imm8,Gv,Ev */
15211 modrm = getIByte(delta);
15212 d32 = delta + lengthAMode(delta);
sewardj2d49b432005-02-01 00:37:06 +000015213 vex_sprintf(dis_buf, "$%d", getIByte(d32));
sewardj68511542004-07-28 00:15:44 +000015214 delta = dis_SHLRD_Gv_Ev (
15215 sorb, delta, modrm, sz,
15216 mkU8(getIByte(d32)), True, /* literal */
15217 dis_buf, False );
15218 break;
sewardja511afc2004-07-29 22:26:03 +000015219 case 0xAD: /* SHRDv %cl,Gv,Ev */
15220 modrm = getIByte(delta);
15221 delta = dis_SHLRD_Gv_Ev (
15222 sorb, delta, modrm, sz,
15223 getIReg(1,R_ECX), False, /* not literal */
15224 "%cl", False );
15225 break;
15226
sewardjf07ed032005-08-07 14:48:03 +000015227 /* =-=-=-=-=-=-=-=-=- SYSENTER -=-=-=-=-=-=-=-=-=-= */
15228
15229 case 0x34:
15230 /* Simple implementation needing a long explaination.
15231
15232 sysenter is a kind of syscall entry. The key thing here
15233 is that the return address is not known -- that is
15234 something that is beyond Vex's knowledge. So this IR
15235 forces a return to the scheduler, which can do what it
sewardj4fa325a2005-11-03 13:27:24 +000015236 likes to simulate the systenter, but it MUST set this
sewardjf07ed032005-08-07 14:48:03 +000015237 thread's guest_EIP field with the continuation address
15238 before resuming execution. If that doesn't happen, the
15239 thread will jump to address zero, which is probably
15240 fatal.
sewardje86310f2009-03-19 22:21:40 +000015241 */
15242
15243 /* Note where we are, so we can back up the guest to this
15244 point if the syscall needs to be restarted. */
15245 stmt( IRStmt_Put( OFFB_IP_AT_SYSCALL,
15246 mkU32(guest_EIP_curr_instr) ) );
sewardjc6f970f2012-04-02 21:54:49 +000015247 jmp_lit(&dres, Ijk_Sys_sysenter, 0/*bogus next EIP value*/);
15248 vassert(dres.whatNext == Dis_StopHere);
sewardjf07ed032005-08-07 14:48:03 +000015249 DIP("sysenter");
15250 break;
15251
sewardj464efa42004-11-19 22:17:29 +000015252 /* =-=-=-=-=-=-=-=-=- XADD -=-=-=-=-=-=-=-=-=-= */
15253
sewardj0092e0d2006-03-06 13:35:42 +000015254 case 0xC0: { /* XADD Gb,Eb */
15255 Bool decodeOK;
sewardje9d8a262009-07-01 08:06:34 +000015256 delta = dis_xadd_G_E ( sorb, pfx_lock, 1, delta, &decodeOK );
sewardj0092e0d2006-03-06 13:35:42 +000015257 if (!decodeOK) goto decode_failure;
sewardj883b00b2004-09-11 09:30:24 +000015258 break;
sewardj0092e0d2006-03-06 13:35:42 +000015259 }
15260 case 0xC1: { /* XADD Gv,Ev */
15261 Bool decodeOK;
sewardje9d8a262009-07-01 08:06:34 +000015262 delta = dis_xadd_G_E ( sorb, pfx_lock, sz, delta, &decodeOK );
sewardj0092e0d2006-03-06 13:35:42 +000015263 if (!decodeOK) goto decode_failure;
15264 break;
15265 }
sewardj883b00b2004-09-11 09:30:24 +000015266
sewardjf13f37b2004-12-08 17:01:23 +000015267 /* =-=-=-=-=-=-=-=-=- MMXery =-=-=-=-=-=-=-=-=-=-= */
sewardj464efa42004-11-19 22:17:29 +000015268
sewardj2b7a9202004-11-26 19:15:38 +000015269 case 0x71:
15270 case 0x72:
sewardj38a3f862005-01-13 15:06:51 +000015271 case 0x73: /* PSLLgg/PSRAgg/PSRLgg mmxreg by imm8 */
sewardj2b7a9202004-11-26 19:15:38 +000015272
15273 case 0x6E: /* MOVD (src)ireg-or-mem, (dst)mmxreg */
15274 case 0x7E: /* MOVD (src)mmxreg, (dst)ireg-or-mem */
sewardj464efa42004-11-19 22:17:29 +000015275 case 0x7F: /* MOVQ (src)mmxreg, (dst)mmxreg-or-mem */
sewardj2b7a9202004-11-26 19:15:38 +000015276 case 0x6F: /* MOVQ (src)mmxreg-or-mem, (dst)mmxreg */
sewardj464efa42004-11-19 22:17:29 +000015277
15278 case 0xFC:
15279 case 0xFD:
15280 case 0xFE: /* PADDgg (src)mmxreg-or-mem, (dst)mmxreg */
15281
15282 case 0xEC:
15283 case 0xED: /* PADDSgg (src)mmxreg-or-mem, (dst)mmxreg */
15284
15285 case 0xDC:
15286 case 0xDD: /* PADDUSgg (src)mmxreg-or-mem, (dst)mmxreg */
15287
15288 case 0xF8:
15289 case 0xF9:
15290 case 0xFA: /* PSUBgg (src)mmxreg-or-mem, (dst)mmxreg */
15291
15292 case 0xE8:
15293 case 0xE9: /* PSUBSgg (src)mmxreg-or-mem, (dst)mmxreg */
15294
15295 case 0xD8:
15296 case 0xD9: /* PSUBUSgg (src)mmxreg-or-mem, (dst)mmxreg */
15297
15298 case 0xE5: /* PMULHW (src)mmxreg-or-mem, (dst)mmxreg */
15299 case 0xD5: /* PMULLW (src)mmxreg-or-mem, (dst)mmxreg */
15300
sewardj4340dac2004-11-20 13:17:04 +000015301 case 0xF5: /* PMADDWD (src)mmxreg-or-mem, (dst)mmxreg */
15302
15303 case 0x74:
15304 case 0x75:
15305 case 0x76: /* PCMPEQgg (src)mmxreg-or-mem, (dst)mmxreg */
15306
15307 case 0x64:
15308 case 0x65:
15309 case 0x66: /* PCMPGTgg (src)mmxreg-or-mem, (dst)mmxreg */
15310
sewardj63ba4092004-11-21 12:30:18 +000015311 case 0x6B: /* PACKSSDW (src)mmxreg-or-mem, (dst)mmxreg */
15312 case 0x63: /* PACKSSWB (src)mmxreg-or-mem, (dst)mmxreg */
15313 case 0x67: /* PACKUSWB (src)mmxreg-or-mem, (dst)mmxreg */
15314
15315 case 0x68:
15316 case 0x69:
15317 case 0x6A: /* PUNPCKHgg (src)mmxreg-or-mem, (dst)mmxreg */
15318
15319 case 0x60:
15320 case 0x61:
15321 case 0x62: /* PUNPCKLgg (src)mmxreg-or-mem, (dst)mmxreg */
15322
15323 case 0xDB: /* PAND (src)mmxreg-or-mem, (dst)mmxreg */
15324 case 0xDF: /* PANDN (src)mmxreg-or-mem, (dst)mmxreg */
15325 case 0xEB: /* POR (src)mmxreg-or-mem, (dst)mmxreg */
15326 case 0xEF: /* PXOR (src)mmxreg-or-mem, (dst)mmxreg */
15327
sewardj38a3f862005-01-13 15:06:51 +000015328 case 0xF1: /* PSLLgg (src)mmxreg-or-mem, (dst)mmxreg */
sewardj8d14a592004-11-21 17:04:50 +000015329 case 0xF2:
sewardj38a3f862005-01-13 15:06:51 +000015330 case 0xF3:
sewardj8d14a592004-11-21 17:04:50 +000015331
sewardj38a3f862005-01-13 15:06:51 +000015332 case 0xD1: /* PSRLgg (src)mmxreg-or-mem, (dst)mmxreg */
sewardj8d14a592004-11-21 17:04:50 +000015333 case 0xD2:
sewardj38a3f862005-01-13 15:06:51 +000015334 case 0xD3:
sewardj8d14a592004-11-21 17:04:50 +000015335
sewardj38a3f862005-01-13 15:06:51 +000015336 case 0xE1: /* PSRAgg (src)mmxreg-or-mem, (dst)mmxreg */
15337 case 0xE2:
sewardj464efa42004-11-19 22:17:29 +000015338 {
sewardj52d04912005-07-03 00:52:48 +000015339 Int delta0 = delta-1;
sewardj464efa42004-11-19 22:17:29 +000015340 Bool decode_OK = False;
sewardj38a3f862005-01-13 15:06:51 +000015341
15342 /* If sz==2 this is SSE, and we assume sse idec has
15343 already spotted those cases by now. */
15344 if (sz != 4)
15345 goto decode_failure;
15346
sewardj464efa42004-11-19 22:17:29 +000015347 delta = dis_MMX ( &decode_OK, sorb, sz, delta-1 );
15348 if (!decode_OK) {
15349 delta = delta0;
15350 goto decode_failure;
15351 }
15352 break;
15353 }
15354
tome3aa0162011-08-11 14:43:12 +000015355 case 0x0E: /* FEMMS */
sewardj8d14a592004-11-21 17:04:50 +000015356 case 0x77: /* EMMS */
sewardj38a3f862005-01-13 15:06:51 +000015357 if (sz != 4)
15358 goto decode_failure;
sewardj4cb918d2004-12-03 19:43:31 +000015359 do_EMMS_preamble();
tome3aa0162011-08-11 14:43:12 +000015360 DIP("{f}emms\n");
sewardj8d14a592004-11-21 17:04:50 +000015361 break;
15362
sewardjb9dc2432010-06-07 16:22:22 +000015363 /* =-=-=-=-=-=-=-=-=- SGDT and SIDT =-=-=-=-=-=-=-=-=-=-= */
15364 case 0x01: /* 0F 01 /0 -- SGDT */
15365 /* 0F 01 /1 -- SIDT */
15366 {
15367 /* This is really revolting, but ... since each processor
15368 (core) only has one IDT and one GDT, just let the guest
15369 see it (pass-through semantics). I can't see any way to
15370 construct a faked-up value, so don't bother to try. */
15371 modrm = getUChar(delta);
sewardjb9dc2432010-06-07 16:22:22 +000015372 if (epartIsReg(modrm)) goto decode_failure;
15373 if (gregOfRM(modrm) != 0 && gregOfRM(modrm) != 1)
15374 goto decode_failure;
Elliott Hughesed398002017-06-21 14:41:24 -070015375 addr = disAMode ( &alen, sorb, delta, dis_buf );
15376 delta += alen;
sewardjb9dc2432010-06-07 16:22:22 +000015377 switch (gregOfRM(modrm)) {
15378 case 0: DIP("sgdt %s\n", dis_buf); break;
15379 case 1: DIP("sidt %s\n", dis_buf); break;
15380 default: vassert(0); /*NOTREACHED*/
15381 }
15382
15383 IRDirty* d = unsafeIRDirty_0_N (
15384 0/*regparms*/,
15385 "x86g_dirtyhelper_SxDT",
15386 &x86g_dirtyhelper_SxDT,
15387 mkIRExprVec_2( mkexpr(addr),
15388 mkU32(gregOfRM(modrm)) )
15389 );
15390 /* declare we're writing memory */
15391 d->mFx = Ifx_Write;
15392 d->mAddr = mkexpr(addr);
15393 d->mSize = 6;
15394 stmt( IRStmt_Dirty(d) );
15395 break;
15396 }
15397
tomf0bb6792014-02-09 11:40:20 +000015398 case 0x05: /* AMD's syscall */
15399 stmt( IRStmt_Put( OFFB_IP_AT_SYSCALL,
sewardj3e5d82d2015-07-21 14:43:23 +000015400 mkU32(guest_EIP_curr_instr) ) );
tomf0bb6792014-02-09 11:40:20 +000015401 jmp_lit(&dres, Ijk_Sys_syscall, ((Addr32)guest_EIP_bbstart)+delta);
15402 vassert(dres.whatNext == Dis_StopHere);
15403 DIP("syscall\n");
15404 break;
15405
sewardje87b4842004-07-10 12:23:30 +000015406 /* =-=-=-=-=-=-=-=-=- unimp2 =-=-=-=-=-=-=-=-=-=-= */
15407
15408 default:
15409 goto decode_failure;
15410 } /* switch (opc) for the 2-byte opcodes */
15411 goto decode_success;
15412 } /* case 0x0F: of primary opcode */
sewardjc9a65702004-07-07 16:32:57 +000015413
15414 /* ------------------------ ??? ------------------------ */
15415
15416 default:
sewardje87b4842004-07-10 12:23:30 +000015417 decode_failure:
sewardjc9a65702004-07-07 16:32:57 +000015418 /* All decode failures end up here. */
sewardj442e51a2012-12-06 18:08:04 +000015419 if (sigill_diag) {
15420 vex_printf("vex x86->IR: unhandled instruction bytes: "
15421 "0x%x 0x%x 0x%x 0x%x\n",
florianb1737742015-08-03 16:03:13 +000015422 getIByte(delta_start+0),
15423 getIByte(delta_start+1),
15424 getIByte(delta_start+2),
15425 getIByte(delta_start+3));
sewardj442e51a2012-12-06 18:08:04 +000015426 }
sewardj52444cb2004-12-13 14:09:01 +000015427
sewardjb64821b2004-12-14 10:00:16 +000015428 /* Tell the dispatcher that this insn cannot be decoded, and so has
15429 not been executed, and (is currently) the next to be executed.
15430 EIP should be up-to-date since it made so at the start of each
15431 insn, but nevertheless be paranoid and update it again right
15432 now. */
sewardj9e6491a2005-07-02 19:24:10 +000015433 stmt( IRStmt_Put( OFFB_EIP, mkU32(guest_EIP_curr_instr) ) );
sewardjc6f970f2012-04-02 21:54:49 +000015434 jmp_lit(&dres, Ijk_NoDecode, guest_EIP_curr_instr);
15435 vassert(dres.whatNext == Dis_StopHere);
sewardj9e6491a2005-07-02 19:24:10 +000015436 dres.len = 0;
sewardje9d8a262009-07-01 08:06:34 +000015437 /* We also need to say that a CAS is not expected now, regardless
15438 of what it might have been set to at the start of the function,
15439 since the IR that we've emitted just above (to synthesis a
15440 SIGILL) does not involve any CAS, and presumably no other IR has
15441 been emitted for this (non-decoded) insn. */
15442 *expect_CAS = False;
sewardj9e6491a2005-07-02 19:24:10 +000015443 return dres;
sewardj52444cb2004-12-13 14:09:01 +000015444
sewardjc9a65702004-07-07 16:32:57 +000015445 } /* switch (opc) for the main (primary) opcode switch. */
15446
sewardje87b4842004-07-10 12:23:30 +000015447 decode_success:
sewardjc9a65702004-07-07 16:32:57 +000015448 /* All decode successes end up here. */
sewardjc6f970f2012-04-02 21:54:49 +000015449 switch (dres.whatNext) {
15450 case Dis_Continue:
15451 stmt( IRStmt_Put( OFFB_EIP, mkU32(guest_EIP_bbstart + delta) ) );
15452 break;
15453 case Dis_ResteerU:
15454 case Dis_ResteerC:
15455 stmt( IRStmt_Put( OFFB_EIP, mkU32(dres.continueAt) ) );
15456 break;
15457 case Dis_StopHere:
15458 break;
15459 default:
15460 vassert(0);
15461 }
15462
sewardjc9a65702004-07-07 16:32:57 +000015463 DIP("\n");
sewardj9e6491a2005-07-02 19:24:10 +000015464 dres.len = delta - delta_start;
15465 return dres;
sewardjc9a65702004-07-07 16:32:57 +000015466}
15467
15468#undef DIP
15469#undef DIS
15470
sewardj9e6491a2005-07-02 19:24:10 +000015471
15472/*------------------------------------------------------------*/
15473/*--- Top-level fn ---*/
15474/*------------------------------------------------------------*/
15475
15476/* Disassemble a single instruction into IR. The instruction
15477 is located in host memory at &guest_code[delta]. */
15478
sewardjdd40fdf2006-12-24 02:20:24 +000015479DisResult disInstr_X86 ( IRSB* irsb_IN,
florianbeac5302014-12-31 12:09:38 +000015480 Bool (*resteerOkFn) ( void*, Addr ),
sewardj984d9b12010-01-15 10:53:21 +000015481 Bool resteerCisOk,
sewardjc716aea2006-01-17 01:48:46 +000015482 void* callback_opaque,
florian8462d112014-09-24 15:18:09 +000015483 const UChar* guest_code_IN,
sewardj9e6491a2005-07-02 19:24:10 +000015484 Long delta,
floriand4cc0de2015-01-02 11:44:12 +000015485 Addr guest_IP,
sewardja5f55da2006-04-30 23:37:32 +000015486 VexArch guest_arch,
floriancacba8e2014-12-15 18:58:07 +000015487 const VexArchInfo* archinfo,
15488 const VexAbiInfo* abiinfo,
sewardj9b769162014-07-24 12:42:03 +000015489 VexEndness host_endness_IN,
sewardj442e51a2012-12-06 18:08:04 +000015490 Bool sigill_diag_IN )
sewardj9e6491a2005-07-02 19:24:10 +000015491{
sewardje9d8a262009-07-01 08:06:34 +000015492 Int i, x1, x2;
15493 Bool expect_CAS, has_CAS;
sewardj9e6491a2005-07-02 19:24:10 +000015494 DisResult dres;
15495
15496 /* Set globals (see top of this file) */
sewardja5f55da2006-04-30 23:37:32 +000015497 vassert(guest_arch == VexArchX86);
sewardj9e6491a2005-07-02 19:24:10 +000015498 guest_code = guest_code_IN;
sewardjdd40fdf2006-12-24 02:20:24 +000015499 irsb = irsb_IN;
sewardj9b769162014-07-24 12:42:03 +000015500 host_endness = host_endness_IN;
sewardj9e6491a2005-07-02 19:24:10 +000015501 guest_EIP_curr_instr = (Addr32)guest_IP;
15502 guest_EIP_bbstart = (Addr32)toUInt(guest_IP - delta);
15503
sewardje9d8a262009-07-01 08:06:34 +000015504 x1 = irsb_IN->stmts_used;
15505 expect_CAS = False;
sewardjc6f970f2012-04-02 21:54:49 +000015506 dres = disInstr_X86_WRK ( &expect_CAS, resteerOkFn,
sewardj984d9b12010-01-15 10:53:21 +000015507 resteerCisOk,
sewardj02834302010-07-29 18:10:51 +000015508 callback_opaque,
sewardj442e51a2012-12-06 18:08:04 +000015509 delta, archinfo, abiinfo, sigill_diag_IN );
sewardje9d8a262009-07-01 08:06:34 +000015510 x2 = irsb_IN->stmts_used;
15511 vassert(x2 >= x1);
15512
15513 /* See comment at the top of disInstr_X86_WRK for meaning of
15514 expect_CAS. Here, we (sanity-)check for the presence/absence of
15515 IRCAS as directed by the returned expect_CAS value. */
15516 has_CAS = False;
15517 for (i = x1; i < x2; i++) {
15518 if (irsb_IN->stmts[i]->tag == Ist_CAS)
15519 has_CAS = True;
15520 }
15521
15522 if (expect_CAS != has_CAS) {
15523 /* inconsistency detected. re-disassemble the instruction so as
15524 to generate a useful error message; then assert. */
15525 vex_traceflags |= VEX_TRACE_FE;
sewardjc6f970f2012-04-02 21:54:49 +000015526 dres = disInstr_X86_WRK ( &expect_CAS, resteerOkFn,
sewardj984d9b12010-01-15 10:53:21 +000015527 resteerCisOk,
sewardj02834302010-07-29 18:10:51 +000015528 callback_opaque,
sewardj442e51a2012-12-06 18:08:04 +000015529 delta, archinfo, abiinfo, sigill_diag_IN );
sewardje9d8a262009-07-01 08:06:34 +000015530 for (i = x1; i < x2; i++) {
15531 vex_printf("\t\t");
15532 ppIRStmt(irsb_IN->stmts[i]);
15533 vex_printf("\n");
15534 }
15535 /* Failure of this assertion is serious and denotes a bug in
15536 disInstr. */
15537 vpanic("disInstr_X86: inconsistency in LOCK prefix handling");
15538 }
sewardj9e6491a2005-07-02 19:24:10 +000015539
15540 return dres;
15541}
15542
15543
sewardjc9a65702004-07-07 16:32:57 +000015544/*--------------------------------------------------------------------*/
sewardjcef7d3e2009-07-02 12:21:59 +000015545/*--- end guest_x86_toIR.c ---*/
sewardjc9a65702004-07-07 16:32:57 +000015546/*--------------------------------------------------------------------*/