blob: 0426b40e172ca4909011619af46f3dd0b8790864 [file] [log] [blame]
sewardjc2c87162004-11-25 13:07:02 +00001
2/*--------------------------------------------------------------------*/
sewardj752f9062010-05-03 21:38:49 +00003/*--- begin guest_arm_toIR.c ---*/
sewardjc2c87162004-11-25 13:07:02 +00004/*--------------------------------------------------------------------*/
5
6/*
sewardj752f9062010-05-03 21:38:49 +00007 This file is part of Valgrind, a dynamic binary instrumentation
8 framework.
sewardjc2c87162004-11-25 13:07:02 +00009
sewardje6c53e02011-10-23 07:33:43 +000010 Copyright (C) 2004-2011 OpenWorks LLP
sewardj752f9062010-05-03 21:38:49 +000011 info@open-works.net
sewardj64733c42010-10-12 10:10:46 +000012
13 NEON support is
sewardje6c53e02011-10-23 07:33:43 +000014 Copyright (C) 2010-2011 Samsung Electronics
sewardj64733c42010-10-12 10:10:46 +000015 contributed by Dmitry Zhurikhin <zhur@ispras.ru>
16 and Kirill Batuzov <batuzovk@ispras.ru>
sewardjc2c87162004-11-25 13:07:02 +000017
sewardj752f9062010-05-03 21:38:49 +000018 This program is free software; you can redistribute it and/or
19 modify it under the terms of the GNU General Public License as
20 published by the Free Software Foundation; either version 2 of the
21 License, or (at your option) any later version.
sewardjc2c87162004-11-25 13:07:02 +000022
sewardj752f9062010-05-03 21:38:49 +000023 This program is distributed in the hope that it will be useful, but
24 WITHOUT ANY WARRANTY; without even the implied warranty of
25 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
26 General Public License for more details.
27
28 You should have received a copy of the GNU General Public License
29 along with this program; if not, write to the Free Software
30 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
sewardj7bd6ffe2005-08-03 16:07:36 +000031 02110-1301, USA.
32
sewardj752f9062010-05-03 21:38:49 +000033 The GNU General Public License is contained in the file COPYING.
sewardjc2c87162004-11-25 13:07:02 +000034*/
35
sewardjd2664472010-08-22 12:44:20 +000036/* XXXX thumb to check:
37 that all cases where putIRegT writes r15, we generate a jump.
38
39 All uses of newTemp assign to an IRTemp and not a UInt
40
41 For all thumb loads and stores, including VFP ones, new-ITSTATE is
42 backed out before the memory op, and restored afterwards. This
43 needs to happen even after we go uncond. (and for sure it doesn't
44 happen for VFP loads/stores right now).
45
46 VFP on thumb: check that we exclude all r13/r15 cases that we
47 should.
48
49 XXXX thumb to do: improve the ITSTATE-zeroing optimisation by
50 taking into account the number of insns guarded by an IT.
51
52 remove the nasty hack, in the spechelper, of looking for Or32(...,
53 0xE0) in as the first arg to armg_calculate_condition, and instead
54 use Slice44 as specified in comments in the spechelper.
55
56 add specialisations for armg_calculate_flag_c and _v, as they
57 are moderately often needed in Thumb code.
58
59 Correctness: ITSTATE handling in Thumb SVCs is wrong.
60
61 Correctness (obscure): in m_transtab, when invalidating code
62 address ranges, invalidate up to 18 bytes after the end of the
63 range. This is because the ITSTATE optimisation at the top of
64 _THUMB_WRK below analyses up to 18 bytes before the start of any
65 given instruction, and so might depend on the invalidated area.
66*/
67
sewardj6c299f32009-12-31 18:00:12 +000068/* Limitations, etc
69
70 - pretty dodgy exception semantics for {LD,ST}Mxx, no doubt
71
72 - SWP: the restart jump back is Ijk_Boring; it should be
73 Ijk_NoRedir but that's expensive. See comments on casLE() in
74 guest_x86_toIR.c.
sewardj6c299f32009-12-31 18:00:12 +000075*/
76
77/* "Special" instructions.
78
79 This instruction decoder can decode four special instructions
80 which mean nothing natively (are no-ops as far as regs/mem are
81 concerned) but have meaning for supporting Valgrind. A special
82 instruction is flagged by a 16-byte preamble:
83
84 E1A0C1EC E1A0C6EC E1A0CEEC E1A0C9EC
85 (mov r12, r12, ROR #3; mov r12, r12, ROR #13;
86 mov r12, r12, ROR #29; mov r12, r12, ROR #19)
87
88 Following that, one of the following 3 are allowed
89 (standard interpretation in parentheses):
90
91 E18AA00A (orr r10,r10,r10) R3 = client_request ( R4 )
92 E18BB00B (orr r11,r11,r11) R3 = guest_NRADDR
93 E18CC00C (orr r12,r12,r12) branch-and-link-to-noredir R4
94
95 Any other bytes following the 16-byte preamble are illegal and
96 constitute a failure in instruction decoding. This all assumes
97 that the preamble will never occur except in specific code
98 fragments designed for Valgrind to catch.
99*/
100
101/* Translates ARM(v5) code to IR. */
sewardjc2c87162004-11-25 13:07:02 +0000102
103#include "libvex_basictypes.h"
104#include "libvex_ir.h"
105#include "libvex.h"
106#include "libvex_guest_arm.h"
107
sewardjcef7d3e2009-07-02 12:21:59 +0000108#include "main_util.h"
109#include "main_globals.h"
sewardj6c299f32009-12-31 18:00:12 +0000110#include "guest_generic_bb_to_IR.h"
sewardjcef7d3e2009-07-02 12:21:59 +0000111#include "guest_arm_defs.h"
sewardjc2c87162004-11-25 13:07:02 +0000112
113
114/*------------------------------------------------------------*/
115/*--- Globals ---*/
116/*------------------------------------------------------------*/
117
sewardj6c299f32009-12-31 18:00:12 +0000118/* These are set at the start of the translation of a instruction, so
119 that we don't have to pass them around endlessly. CONST means does
120 not change during translation of the instruction.
sewardjc2c87162004-11-25 13:07:02 +0000121*/
122
sewardj6c299f32009-12-31 18:00:12 +0000123/* CONST: is the host bigendian? This has to do with float vs double
124 register accesses on VFP, but it's complex and not properly thought
125 out. */
sewardjc2c87162004-11-25 13:07:02 +0000126static Bool host_is_bigendian;
127
sewardj6c299f32009-12-31 18:00:12 +0000128/* CONST: The guest address for the instruction currently being
sewardjd2664472010-08-22 12:44:20 +0000129 translated. This is the real, "decoded" address (not subject
130 to the CPSR.T kludge). */
131static Addr32 guest_R15_curr_instr_notENC;
132
133/* CONST, FOR ASSERTIONS ONLY. Indicates whether currently processed
134 insn is Thumb (True) or ARM (False). */
135static Bool __curr_is_Thumb;
sewardjc2c87162004-11-25 13:07:02 +0000136
sewardj6c299f32009-12-31 18:00:12 +0000137/* MOD: The IRSB* into which we're generating code. */
sewardjdd40fdf2006-12-24 02:20:24 +0000138static IRSB* irsb;
sewardjc2c87162004-11-25 13:07:02 +0000139
sewardj6c299f32009-12-31 18:00:12 +0000140/* These are to do with handling writes to r15. They are initially
141 set at the start of disInstr_ARM_WRK to indicate no update,
142 possibly updated during the routine, and examined again at the end.
143 If they have been set to indicate a r15 update then a jump is
144 generated. Note, "explicit" jumps (b, bx, etc) are generated
145 directly, not using this mechanism -- this is intended to handle
146 the implicit-style jumps resulting from (eg) assigning to r15 as
147 the result of insns we wouldn't normally consider branchy. */
148
149/* MOD. Initially False; set to True iff abovementioned handling is
150 required. */
151static Bool r15written;
152
153/* MOD. Initially IRTemp_INVALID. If the r15 branch to be generated
154 is conditional, this holds the gating IRTemp :: Ity_I32. If the
155 branch to be generated is unconditional, this remains
156 IRTemp_INVALID. */
157static IRTemp r15guard; /* :: Ity_I32, 0 or 1 */
158
159/* MOD. Initially Ijk_Boring. If an r15 branch is to be generated,
160 this holds the jump kind. */
161static IRTemp r15kind;
162
sewardjc2c87162004-11-25 13:07:02 +0000163
164/*------------------------------------------------------------*/
165/*--- Debugging output ---*/
166/*------------------------------------------------------------*/
167
168#define DIP(format, args...) \
169 if (vex_traceflags & VEX_TRACE_FE) \
170 vex_printf(format, ## args)
171
172#define DIS(buf, format, args...) \
173 if (vex_traceflags & VEX_TRACE_FE) \
174 vex_sprintf(buf, format, ## args)
175
sewardjd2664472010-08-22 12:44:20 +0000176#define ASSERT_IS_THUMB \
177 do { vassert(__curr_is_Thumb); } while (0)
178
179#define ASSERT_IS_ARM \
180 do { vassert(! __curr_is_Thumb); } while (0)
181
sewardjc2c87162004-11-25 13:07:02 +0000182
sewardj6c299f32009-12-31 18:00:12 +0000183/*------------------------------------------------------------*/
184/*--- Helper bits and pieces for deconstructing the ---*/
185/*--- arm insn stream. ---*/
186/*------------------------------------------------------------*/
187
188/* Do a little-endian load of a 32-bit word, regardless of the
189 endianness of the underlying host. */
sewardj80bea7b2010-01-09 11:43:21 +0000190static inline UInt getUIntLittleEndianly ( UChar* p )
sewardj6c299f32009-12-31 18:00:12 +0000191{
192 UInt w = 0;
193 w = (w << 8) | p[3];
194 w = (w << 8) | p[2];
195 w = (w << 8) | p[1];
196 w = (w << 8) | p[0];
197 return w;
198}
199
sewardjd2664472010-08-22 12:44:20 +0000200/* Do a little-endian load of a 16-bit word, regardless of the
201 endianness of the underlying host. */
202static inline UShort getUShortLittleEndianly ( UChar* p )
203{
204 UShort w = 0;
205 w = (w << 8) | p[1];
206 w = (w << 8) | p[0];
207 return w;
208}
209
sewardj6c299f32009-12-31 18:00:12 +0000210static UInt ROR32 ( UInt x, UInt sh ) {
211 vassert(sh >= 0 && sh < 32);
212 if (sh == 0)
213 return x;
214 else
215 return (x << (32-sh)) | (x >> sh);
216}
217
sewardjd2664472010-08-22 12:44:20 +0000218static Int popcount32 ( UInt x )
219{
220 Int res = 0, i;
221 for (i = 0; i < 32; i++) {
222 res += (x & 1);
223 x >>= 1;
224 }
225 return res;
226}
227
228static UInt setbit32 ( UInt x, Int ix, UInt b )
229{
230 UInt mask = 1 << ix;
231 x &= ~mask;
232 x |= ((b << ix) & mask);
233 return x;
234}
235
sewardj6c299f32009-12-31 18:00:12 +0000236#define BITS2(_b1,_b0) \
237 (((_b1) << 1) | (_b0))
238
239#define BITS3(_b2,_b1,_b0) \
240 (((_b2) << 2) | ((_b1) << 1) | (_b0))
241
242#define BITS4(_b3,_b2,_b1,_b0) \
243 (((_b3) << 3) | ((_b2) << 2) | ((_b1) << 1) | (_b0))
244
245#define BITS8(_b7,_b6,_b5,_b4,_b3,_b2,_b1,_b0) \
246 ((BITS4((_b7),(_b6),(_b5),(_b4)) << 4) \
247 | BITS4((_b3),(_b2),(_b1),(_b0)))
ceriona70a37b2004-12-03 18:54:08 +0000248
sewardjd2664472010-08-22 12:44:20 +0000249#define BITS5(_b4,_b3,_b2,_b1,_b0) \
250 (BITS8(0,0,0,(_b4),(_b3),(_b2),(_b1),(_b0)))
251#define BITS6(_b5,_b4,_b3,_b2,_b1,_b0) \
252 (BITS8(0,0,(_b5),(_b4),(_b3),(_b2),(_b1),(_b0)))
253#define BITS7(_b6,_b5,_b4,_b3,_b2,_b1,_b0) \
254 (BITS8(0,(_b6),(_b5),(_b4),(_b3),(_b2),(_b1),(_b0)))
255
256#define BITS9(_b8,_b7,_b6,_b5,_b4,_b3,_b2,_b1,_b0) \
257 (((_b8) << 8) \
258 | BITS8((_b7),(_b6),(_b5),(_b4),(_b3),(_b2),(_b1),(_b0)))
259
sewardj1f139f52010-08-29 12:33:02 +0000260#define BITS10(_b9,_b8,_b7,_b6,_b5,_b4,_b3,_b2,_b1,_b0) \
261 (((_b9) << 9) | ((_b8) << 8) \
262 | BITS8((_b7),(_b6),(_b5),(_b4),(_b3),(_b2),(_b1),(_b0)))
263
sewardj80bea7b2010-01-09 11:43:21 +0000264/* produces _uint[_bMax:_bMin] */
265#define SLICE_UInt(_uint,_bMax,_bMin) \
266 (( ((UInt)(_uint)) >> (_bMin)) \
sewardjd2664472010-08-22 12:44:20 +0000267 & (UInt)((1ULL << ((_bMax) - (_bMin) + 1)) - 1ULL))
sewardj80bea7b2010-01-09 11:43:21 +0000268
ceriona70a37b2004-12-03 18:54:08 +0000269
sewardjc2c87162004-11-25 13:07:02 +0000270/*------------------------------------------------------------*/
sewardj6c299f32009-12-31 18:00:12 +0000271/*--- Helper bits and pieces for creating IR fragments. ---*/
272/*------------------------------------------------------------*/
273
sewardjd2664472010-08-22 12:44:20 +0000274static IRExpr* mkU64 ( ULong i )
275{
276 return IRExpr_Const(IRConst_U64(i));
277}
278
sewardj6c299f32009-12-31 18:00:12 +0000279static IRExpr* mkU32 ( UInt i )
280{
281 return IRExpr_Const(IRConst_U32(i));
282}
283
284static IRExpr* mkU8 ( UInt i )
285{
286 vassert(i < 256);
287 return IRExpr_Const(IRConst_U8( (UChar)i ));
288}
289
290static IRExpr* mkexpr ( IRTemp tmp )
291{
292 return IRExpr_RdTmp(tmp);
293}
294
295static IRExpr* unop ( IROp op, IRExpr* a )
296{
297 return IRExpr_Unop(op, a);
298}
299
300static IRExpr* binop ( IROp op, IRExpr* a1, IRExpr* a2 )
301{
302 return IRExpr_Binop(op, a1, a2);
303}
304
305static IRExpr* triop ( IROp op, IRExpr* a1, IRExpr* a2, IRExpr* a3 )
306{
307 return IRExpr_Triop(op, a1, a2, a3);
308}
309
310static IRExpr* loadLE ( IRType ty, IRExpr* addr )
311{
312 return IRExpr_Load(Iend_LE, ty, addr);
313}
314
315/* Add a statement to the list held by "irbb". */
316static void stmt ( IRStmt* st )
317{
318 addStmtToIRSB( irsb, st );
319}
320
321static void assign ( IRTemp dst, IRExpr* e )
322{
323 stmt( IRStmt_WrTmp(dst, e) );
324}
325
326static void storeLE ( IRExpr* addr, IRExpr* data )
327{
328 stmt( IRStmt_Store(Iend_LE, addr, data) );
329}
330
331/* Generate a new temporary of the given type. */
332static IRTemp newTemp ( IRType ty )
333{
334 vassert(isPlausibleIRType(ty));
335 return newIRTemp( irsb->tyenv, ty );
336}
337
338/* Produces a value in 0 .. 3, which is encoded as per the type
339 IRRoundingMode. */
340static IRExpr* /* :: Ity_I32 */ get_FAKE_roundingmode ( void )
341{
342 return mkU32(Irrm_NEAREST);
343}
344
345/* Generate an expression for SRC rotated right by ROT. */
346static IRExpr* genROR32( IRTemp src, Int rot )
347{
348 vassert(rot >= 0 && rot < 32);
349 if (rot == 0)
350 return mkexpr(src);
351 return
352 binop(Iop_Or32,
353 binop(Iop_Shl32, mkexpr(src), mkU8(32 - rot)),
354 binop(Iop_Shr32, mkexpr(src), mkU8(rot)));
355}
356
sewardjd2664472010-08-22 12:44:20 +0000357static IRExpr* mkU128 ( ULong i )
358{
359 return binop(Iop_64HLtoV128, mkU64(i), mkU64(i));
360}
361
362/* Generate a 4-aligned version of the given expression if
363 the given condition is true. Else return it unchanged. */
364static IRExpr* align4if ( IRExpr* e, Bool b )
365{
366 if (b)
367 return binop(Iop_And32, e, mkU32(~3));
368 else
369 return e;
370}
371
sewardj6c299f32009-12-31 18:00:12 +0000372
373/*------------------------------------------------------------*/
374/*--- Helpers for accessing guest registers. ---*/
sewardjc2c87162004-11-25 13:07:02 +0000375/*------------------------------------------------------------*/
376
377#define OFFB_R0 offsetof(VexGuestARMState,guest_R0)
cerionc60c01e2004-12-02 20:19:22 +0000378#define OFFB_R1 offsetof(VexGuestARMState,guest_R1)
379#define OFFB_R2 offsetof(VexGuestARMState,guest_R2)
380#define OFFB_R3 offsetof(VexGuestARMState,guest_R3)
381#define OFFB_R4 offsetof(VexGuestARMState,guest_R4)
382#define OFFB_R5 offsetof(VexGuestARMState,guest_R5)
383#define OFFB_R6 offsetof(VexGuestARMState,guest_R6)
384#define OFFB_R7 offsetof(VexGuestARMState,guest_R7)
385#define OFFB_R8 offsetof(VexGuestARMState,guest_R8)
386#define OFFB_R9 offsetof(VexGuestARMState,guest_R9)
387#define OFFB_R10 offsetof(VexGuestARMState,guest_R10)
388#define OFFB_R11 offsetof(VexGuestARMState,guest_R11)
389#define OFFB_R12 offsetof(VexGuestARMState,guest_R12)
390#define OFFB_R13 offsetof(VexGuestARMState,guest_R13)
391#define OFFB_R14 offsetof(VexGuestARMState,guest_R14)
sewardjd2664472010-08-22 12:44:20 +0000392#define OFFB_R15T offsetof(VexGuestARMState,guest_R15T)
sewardjc2c87162004-11-25 13:07:02 +0000393
cerionc60c01e2004-12-02 20:19:22 +0000394#define OFFB_CC_OP offsetof(VexGuestARMState,guest_CC_OP)
395#define OFFB_CC_DEP1 offsetof(VexGuestARMState,guest_CC_DEP1)
396#define OFFB_CC_DEP2 offsetof(VexGuestARMState,guest_CC_DEP2)
sewardj6c299f32009-12-31 18:00:12 +0000397#define OFFB_CC_NDEP offsetof(VexGuestARMState,guest_CC_NDEP)
398#define OFFB_NRADDR offsetof(VexGuestARMState,guest_NRADDR)
cerionc60c01e2004-12-02 20:19:22 +0000399
sewardj6c299f32009-12-31 18:00:12 +0000400#define OFFB_D0 offsetof(VexGuestARMState,guest_D0)
401#define OFFB_D1 offsetof(VexGuestARMState,guest_D1)
402#define OFFB_D2 offsetof(VexGuestARMState,guest_D2)
403#define OFFB_D3 offsetof(VexGuestARMState,guest_D3)
404#define OFFB_D4 offsetof(VexGuestARMState,guest_D4)
405#define OFFB_D5 offsetof(VexGuestARMState,guest_D5)
406#define OFFB_D6 offsetof(VexGuestARMState,guest_D6)
407#define OFFB_D7 offsetof(VexGuestARMState,guest_D7)
408#define OFFB_D8 offsetof(VexGuestARMState,guest_D8)
409#define OFFB_D9 offsetof(VexGuestARMState,guest_D9)
410#define OFFB_D10 offsetof(VexGuestARMState,guest_D10)
411#define OFFB_D11 offsetof(VexGuestARMState,guest_D11)
412#define OFFB_D12 offsetof(VexGuestARMState,guest_D12)
413#define OFFB_D13 offsetof(VexGuestARMState,guest_D13)
414#define OFFB_D14 offsetof(VexGuestARMState,guest_D14)
415#define OFFB_D15 offsetof(VexGuestARMState,guest_D15)
sewardjd2664472010-08-22 12:44:20 +0000416#define OFFB_D16 offsetof(VexGuestARMState,guest_D16)
417#define OFFB_D17 offsetof(VexGuestARMState,guest_D17)
418#define OFFB_D18 offsetof(VexGuestARMState,guest_D18)
419#define OFFB_D19 offsetof(VexGuestARMState,guest_D19)
420#define OFFB_D20 offsetof(VexGuestARMState,guest_D20)
421#define OFFB_D21 offsetof(VexGuestARMState,guest_D21)
422#define OFFB_D22 offsetof(VexGuestARMState,guest_D22)
423#define OFFB_D23 offsetof(VexGuestARMState,guest_D23)
424#define OFFB_D24 offsetof(VexGuestARMState,guest_D24)
425#define OFFB_D25 offsetof(VexGuestARMState,guest_D25)
426#define OFFB_D26 offsetof(VexGuestARMState,guest_D26)
427#define OFFB_D27 offsetof(VexGuestARMState,guest_D27)
428#define OFFB_D28 offsetof(VexGuestARMState,guest_D28)
429#define OFFB_D29 offsetof(VexGuestARMState,guest_D29)
430#define OFFB_D30 offsetof(VexGuestARMState,guest_D30)
431#define OFFB_D31 offsetof(VexGuestARMState,guest_D31)
sewardj6c299f32009-12-31 18:00:12 +0000432
433#define OFFB_FPSCR offsetof(VexGuestARMState,guest_FPSCR)
434#define OFFB_TPIDRURO offsetof(VexGuestARMState,guest_TPIDRURO)
sewardjd2664472010-08-22 12:44:20 +0000435#define OFFB_ITSTATE offsetof(VexGuestARMState,guest_ITSTATE)
436#define OFFB_QFLAG32 offsetof(VexGuestARMState,guest_QFLAG32)
sewardj1f139f52010-08-29 12:33:02 +0000437#define OFFB_GEFLAG0 offsetof(VexGuestARMState,guest_GEFLAG0)
438#define OFFB_GEFLAG1 offsetof(VexGuestARMState,guest_GEFLAG1)
439#define OFFB_GEFLAG2 offsetof(VexGuestARMState,guest_GEFLAG2)
440#define OFFB_GEFLAG3 offsetof(VexGuestARMState,guest_GEFLAG3)
cerionc60c01e2004-12-02 20:19:22 +0000441
sewardjc2c87162004-11-25 13:07:02 +0000442
sewardj6c299f32009-12-31 18:00:12 +0000443/* ---------------- Integer registers ---------------- */
sewardjc2c87162004-11-25 13:07:02 +0000444
sewardj6c299f32009-12-31 18:00:12 +0000445static Int integerGuestRegOffset ( UInt iregNo )
sewardjc2c87162004-11-25 13:07:02 +0000446{
sewardj6c299f32009-12-31 18:00:12 +0000447 /* Do we care about endianness here? We do if sub-parts of integer
448 registers are accessed, but I don't think that ever happens on
449 ARM. */
450 switch (iregNo) {
451 case 0: return OFFB_R0;
452 case 1: return OFFB_R1;
453 case 2: return OFFB_R2;
454 case 3: return OFFB_R3;
455 case 4: return OFFB_R4;
456 case 5: return OFFB_R5;
457 case 6: return OFFB_R6;
458 case 7: return OFFB_R7;
459 case 8: return OFFB_R8;
460 case 9: return OFFB_R9;
461 case 10: return OFFB_R10;
462 case 11: return OFFB_R11;
463 case 12: return OFFB_R12;
464 case 13: return OFFB_R13;
465 case 14: return OFFB_R14;
sewardjd2664472010-08-22 12:44:20 +0000466 case 15: return OFFB_R15T;
sewardj6c299f32009-12-31 18:00:12 +0000467 default: vassert(0);
sewardjc2c87162004-11-25 13:07:02 +0000468 }
469}
470
sewardj6c299f32009-12-31 18:00:12 +0000471/* Plain ("low level") read from a reg; no +8 offset magic for r15. */
472static IRExpr* llGetIReg ( UInt iregNo )
473{
474 vassert(iregNo < 16);
475 return IRExpr_Get( integerGuestRegOffset(iregNo), Ity_I32 );
476}
477
sewardjd2664472010-08-22 12:44:20 +0000478/* Architected read from a reg in ARM mode. This automagically adds 8
479 to all reads of r15. */
480static IRExpr* getIRegA ( UInt iregNo )
sewardj6c299f32009-12-31 18:00:12 +0000481{
482 IRExpr* e;
sewardjd2664472010-08-22 12:44:20 +0000483 ASSERT_IS_ARM;
sewardj6c299f32009-12-31 18:00:12 +0000484 vassert(iregNo < 16);
485 if (iregNo == 15) {
486 /* If asked for r15, don't read the guest state value, as that
487 may not be up to date in the case where loop unrolling has
488 happened, because the first insn's write to the block is
489 omitted; hence in the 2nd and subsequent unrollings we don't
490 have a correct value in guest r15. Instead produce the
491 constant that we know would be produced at this point. */
sewardjd2664472010-08-22 12:44:20 +0000492 vassert(0 == (guest_R15_curr_instr_notENC & 3));
493 e = mkU32(guest_R15_curr_instr_notENC + 8);
494 } else {
495 e = IRExpr_Get( integerGuestRegOffset(iregNo), Ity_I32 );
496 }
497 return e;
498}
499
500/* Architected read from a reg in Thumb mode. This automagically adds
501 4 to all reads of r15. */
502static IRExpr* getIRegT ( UInt iregNo )
503{
504 IRExpr* e;
505 ASSERT_IS_THUMB;
506 vassert(iregNo < 16);
507 if (iregNo == 15) {
508 /* Ditto comment in getIReg. */
509 vassert(0 == (guest_R15_curr_instr_notENC & 1));
510 e = mkU32(guest_R15_curr_instr_notENC + 4);
sewardj6c299f32009-12-31 18:00:12 +0000511 } else {
512 e = IRExpr_Get( integerGuestRegOffset(iregNo), Ity_I32 );
513 }
514 return e;
515}
516
517/* Plain ("low level") write to a reg; no jump or alignment magic for
518 r15. */
519static void llPutIReg ( UInt iregNo, IRExpr* e )
520{
521 vassert(iregNo < 16);
522 vassert(typeOfIRExpr(irsb->tyenv, e) == Ity_I32);
523 stmt( IRStmt_Put(integerGuestRegOffset(iregNo), e) );
524}
525
sewardjd2664472010-08-22 12:44:20 +0000526/* Architected write to an integer register in ARM mode. If it is to
527 r15, record info so at the end of this insn's translation, a branch
528 to it can be made. Also handles conditional writes to the
529 register: if guardT == IRTemp_INVALID then the write is
530 unconditional. If writing r15, also 4-align it. */
531static void putIRegA ( UInt iregNo,
532 IRExpr* e,
533 IRTemp guardT /* :: Ity_I32, 0 or 1 */,
534 IRJumpKind jk /* if a jump is generated */ )
sewardj6c299f32009-12-31 18:00:12 +0000535{
536 /* if writing r15, force e to be 4-aligned. */
sewardjd2664472010-08-22 12:44:20 +0000537 // INTERWORKING FIXME. this needs to be relaxed so that
538 // puts caused by LDMxx which load r15 interwork right.
539 // but is no aligned too relaxed?
540 //if (iregNo == 15)
541 // e = binop(Iop_And32, e, mkU32(~3));
542 ASSERT_IS_ARM;
sewardj6c299f32009-12-31 18:00:12 +0000543 /* So, generate either an unconditional or a conditional write to
544 the reg. */
545 if (guardT == IRTemp_INVALID) {
546 /* unconditional write */
547 llPutIReg( iregNo, e );
548 } else {
549 llPutIReg( iregNo,
550 IRExpr_Mux0X( unop(Iop_32to8, mkexpr(guardT)),
551 llGetIReg(iregNo),
552 e ));
553 }
554 if (iregNo == 15) {
555 // assert against competing r15 updates. Shouldn't
556 // happen; should be ruled out by the instr matching
557 // logic.
558 vassert(r15written == False);
559 vassert(r15guard == IRTemp_INVALID);
560 vassert(r15kind == Ijk_Boring);
561 r15written = True;
562 r15guard = guardT;
563 r15kind = jk;
564 }
565}
566
567
sewardjd2664472010-08-22 12:44:20 +0000568/* Architected write to an integer register in Thumb mode. Writes to
569 r15 are not allowed. Handles conditional writes to the register:
570 if guardT == IRTemp_INVALID then the write is unconditional. */
571static void putIRegT ( UInt iregNo,
572 IRExpr* e,
573 IRTemp guardT /* :: Ity_I32, 0 or 1 */ )
574{
575 /* So, generate either an unconditional or a conditional write to
576 the reg. */
577 ASSERT_IS_THUMB;
578 vassert(iregNo >= 0 && iregNo <= 14);
579 if (guardT == IRTemp_INVALID) {
580 /* unconditional write */
581 llPutIReg( iregNo, e );
582 } else {
583 llPutIReg( iregNo,
584 IRExpr_Mux0X( unop(Iop_32to8, mkexpr(guardT)),
585 llGetIReg(iregNo),
586 e ));
587 }
588}
589
590
591/* Thumb16 and Thumb32 only.
592 Returns true if reg is 13 or 15. Implements the BadReg
593 predicate in the ARM ARM. */
594static Bool isBadRegT ( UInt r )
595{
596 vassert(r <= 15);
597 ASSERT_IS_THUMB;
598 return r == 13 || r == 15;
599}
600
601
sewardj6c299f32009-12-31 18:00:12 +0000602/* ---------------- Double registers ---------------- */
603
604static Int doubleGuestRegOffset ( UInt dregNo )
605{
606 /* Do we care about endianness here? Probably do if we ever get
607 into the situation of dealing with the single-precision VFP
608 registers. */
609 switch (dregNo) {
610 case 0: return OFFB_D0;
611 case 1: return OFFB_D1;
612 case 2: return OFFB_D2;
613 case 3: return OFFB_D3;
614 case 4: return OFFB_D4;
615 case 5: return OFFB_D5;
616 case 6: return OFFB_D6;
617 case 7: return OFFB_D7;
618 case 8: return OFFB_D8;
619 case 9: return OFFB_D9;
620 case 10: return OFFB_D10;
621 case 11: return OFFB_D11;
622 case 12: return OFFB_D12;
623 case 13: return OFFB_D13;
624 case 14: return OFFB_D14;
625 case 15: return OFFB_D15;
sewardjd2664472010-08-22 12:44:20 +0000626 case 16: return OFFB_D16;
627 case 17: return OFFB_D17;
628 case 18: return OFFB_D18;
629 case 19: return OFFB_D19;
630 case 20: return OFFB_D20;
631 case 21: return OFFB_D21;
632 case 22: return OFFB_D22;
633 case 23: return OFFB_D23;
634 case 24: return OFFB_D24;
635 case 25: return OFFB_D25;
636 case 26: return OFFB_D26;
637 case 27: return OFFB_D27;
638 case 28: return OFFB_D28;
639 case 29: return OFFB_D29;
640 case 30: return OFFB_D30;
641 case 31: return OFFB_D31;
sewardj6c299f32009-12-31 18:00:12 +0000642 default: vassert(0);
643 }
644}
645
646/* Plain ("low level") read from a VFP Dreg. */
647static IRExpr* llGetDReg ( UInt dregNo )
648{
sewardjd2664472010-08-22 12:44:20 +0000649 vassert(dregNo < 32);
sewardj6c299f32009-12-31 18:00:12 +0000650 return IRExpr_Get( doubleGuestRegOffset(dregNo), Ity_F64 );
651}
652
653/* Architected read from a VFP Dreg. */
654static IRExpr* getDReg ( UInt dregNo ) {
655 return llGetDReg( dregNo );
656}
657
658/* Plain ("low level") write to a VFP Dreg. */
659static void llPutDReg ( UInt dregNo, IRExpr* e )
660{
sewardjd2664472010-08-22 12:44:20 +0000661 vassert(dregNo < 32);
sewardj6c299f32009-12-31 18:00:12 +0000662 vassert(typeOfIRExpr(irsb->tyenv, e) == Ity_F64);
663 stmt( IRStmt_Put(doubleGuestRegOffset(dregNo), e) );
664}
665
666/* Architected write to a VFP Dreg. Handles conditional writes to the
667 register: if guardT == IRTemp_INVALID then the write is
668 unconditional. */
669static void putDReg ( UInt dregNo,
670 IRExpr* e,
671 IRTemp guardT /* :: Ity_I32, 0 or 1 */)
672{
673 /* So, generate either an unconditional or a conditional write to
674 the reg. */
675 if (guardT == IRTemp_INVALID) {
676 /* unconditional write */
677 llPutDReg( dregNo, e );
678 } else {
679 llPutDReg( dregNo,
680 IRExpr_Mux0X( unop(Iop_32to8, mkexpr(guardT)),
681 llGetDReg(dregNo),
682 e ));
683 }
684}
685
sewardjd2664472010-08-22 12:44:20 +0000686/* And now exactly the same stuff all over again, but this time
687 taking/returning I64 rather than F64, to support 64-bit Neon
688 ops. */
689
690/* Plain ("low level") read from a Neon Integer Dreg. */
691static IRExpr* llGetDRegI64 ( UInt dregNo )
692{
693 vassert(dregNo < 32);
694 return IRExpr_Get( doubleGuestRegOffset(dregNo), Ity_I64 );
695}
696
697/* Architected read from a Neon Integer Dreg. */
698static IRExpr* getDRegI64 ( UInt dregNo ) {
699 return llGetDRegI64( dregNo );
700}
701
702/* Plain ("low level") write to a Neon Integer Dreg. */
703static void llPutDRegI64 ( UInt dregNo, IRExpr* e )
704{
705 vassert(dregNo < 32);
706 vassert(typeOfIRExpr(irsb->tyenv, e) == Ity_I64);
707 stmt( IRStmt_Put(doubleGuestRegOffset(dregNo), e) );
708}
709
710/* Architected write to a Neon Integer Dreg. Handles conditional
711 writes to the register: if guardT == IRTemp_INVALID then the write
712 is unconditional. */
713static void putDRegI64 ( UInt dregNo,
714 IRExpr* e,
715 IRTemp guardT /* :: Ity_I32, 0 or 1 */)
716{
717 /* So, generate either an unconditional or a conditional write to
718 the reg. */
719 if (guardT == IRTemp_INVALID) {
720 /* unconditional write */
721 llPutDRegI64( dregNo, e );
722 } else {
723 llPutDRegI64( dregNo,
724 IRExpr_Mux0X( unop(Iop_32to8, mkexpr(guardT)),
725 llGetDRegI64(dregNo),
726 e ));
727 }
728}
729
730/* ---------------- Quad registers ---------------- */
731
732static Int quadGuestRegOffset ( UInt qregNo )
733{
734 /* Do we care about endianness here? Probably do if we ever get
735 into the situation of dealing with the 64 bit Neon registers. */
736 switch (qregNo) {
737 case 0: return OFFB_D0;
738 case 1: return OFFB_D2;
739 case 2: return OFFB_D4;
740 case 3: return OFFB_D6;
741 case 4: return OFFB_D8;
742 case 5: return OFFB_D10;
743 case 6: return OFFB_D12;
744 case 7: return OFFB_D14;
745 case 8: return OFFB_D16;
746 case 9: return OFFB_D18;
747 case 10: return OFFB_D20;
748 case 11: return OFFB_D22;
749 case 12: return OFFB_D24;
750 case 13: return OFFB_D26;
751 case 14: return OFFB_D28;
752 case 15: return OFFB_D30;
753 default: vassert(0);
754 }
755}
756
757/* Plain ("low level") read from a Neon Qreg. */
758static IRExpr* llGetQReg ( UInt qregNo )
759{
760 vassert(qregNo < 16);
761 return IRExpr_Get( quadGuestRegOffset(qregNo), Ity_V128 );
762}
763
764/* Architected read from a Neon Qreg. */
765static IRExpr* getQReg ( UInt qregNo ) {
766 return llGetQReg( qregNo );
767}
768
769/* Plain ("low level") write to a Neon Qreg. */
770static void llPutQReg ( UInt qregNo, IRExpr* e )
771{
772 vassert(qregNo < 16);
773 vassert(typeOfIRExpr(irsb->tyenv, e) == Ity_V128);
774 stmt( IRStmt_Put(quadGuestRegOffset(qregNo), e) );
775}
776
777/* Architected write to a Neon Qreg. Handles conditional writes to the
778 register: if guardT == IRTemp_INVALID then the write is
779 unconditional. */
780static void putQReg ( UInt qregNo,
781 IRExpr* e,
782 IRTemp guardT /* :: Ity_I32, 0 or 1 */)
783{
784 /* So, generate either an unconditional or a conditional write to
785 the reg. */
786 if (guardT == IRTemp_INVALID) {
787 /* unconditional write */
788 llPutQReg( qregNo, e );
789 } else {
790 llPutQReg( qregNo,
791 IRExpr_Mux0X( unop(Iop_32to8, mkexpr(guardT)),
792 llGetQReg(qregNo),
793 e ));
794 }
795}
796
sewardj6c299f32009-12-31 18:00:12 +0000797
798/* ---------------- Float registers ---------------- */
799
800static Int floatGuestRegOffset ( UInt fregNo )
801{
sewardjd2664472010-08-22 12:44:20 +0000802 /* Start with the offset of the containing double, and then correct
sewardj6c299f32009-12-31 18:00:12 +0000803 for endianness. Actually this is completely bogus and needs
804 careful thought. */
805 Int off;
806 vassert(fregNo < 32);
807 off = doubleGuestRegOffset(fregNo >> 1);
808 if (host_is_bigendian) {
809 vassert(0);
810 } else {
811 if (fregNo & 1)
812 off += 4;
813 }
814 return off;
815}
816
817/* Plain ("low level") read from a VFP Freg. */
818static IRExpr* llGetFReg ( UInt fregNo )
819{
820 vassert(fregNo < 32);
821 return IRExpr_Get( floatGuestRegOffset(fregNo), Ity_F32 );
822}
823
824/* Architected read from a VFP Freg. */
825static IRExpr* getFReg ( UInt fregNo ) {
826 return llGetFReg( fregNo );
827}
828
829/* Plain ("low level") write to a VFP Freg. */
830static void llPutFReg ( UInt fregNo, IRExpr* e )
831{
832 vassert(fregNo < 32);
833 vassert(typeOfIRExpr(irsb->tyenv, e) == Ity_F32);
834 stmt( IRStmt_Put(floatGuestRegOffset(fregNo), e) );
835}
836
837/* Architected write to a VFP Freg. Handles conditional writes to the
838 register: if guardT == IRTemp_INVALID then the write is
839 unconditional. */
840static void putFReg ( UInt fregNo,
841 IRExpr* e,
842 IRTemp guardT /* :: Ity_I32, 0 or 1 */)
843{
844 /* So, generate either an unconditional or a conditional write to
845 the reg. */
846 if (guardT == IRTemp_INVALID) {
847 /* unconditional write */
848 llPutFReg( fregNo, e );
849 } else {
850 llPutFReg( fregNo,
851 IRExpr_Mux0X( unop(Iop_32to8, mkexpr(guardT)),
852 llGetFReg(fregNo),
853 e ));
854 }
855}
856
857
858/* ---------------- Misc registers ---------------- */
859
860static void putMiscReg32 ( UInt gsoffset,
861 IRExpr* e, /* :: Ity_I32 */
862 IRTemp guardT /* :: Ity_I32, 0 or 1 */)
863{
864 switch (gsoffset) {
sewardjd2664472010-08-22 12:44:20 +0000865 case OFFB_FPSCR: break;
866 case OFFB_QFLAG32: break;
sewardj1f139f52010-08-29 12:33:02 +0000867 case OFFB_GEFLAG0: break;
868 case OFFB_GEFLAG1: break;
869 case OFFB_GEFLAG2: break;
870 case OFFB_GEFLAG3: break;
sewardj6c299f32009-12-31 18:00:12 +0000871 default: vassert(0); /* awaiting more cases */
872 }
873 vassert(typeOfIRExpr(irsb->tyenv, e) == Ity_I32);
874
875 if (guardT == IRTemp_INVALID) {
876 /* unconditional write */
877 stmt(IRStmt_Put(gsoffset, e));
878 } else {
sewardjd2664472010-08-22 12:44:20 +0000879 stmt(IRStmt_Put(
880 gsoffset,
881 IRExpr_Mux0X( unop(Iop_32to8, mkexpr(guardT)),
882 IRExpr_Get(gsoffset, Ity_I32),
883 e
884 )
885 ));
sewardj6c299f32009-12-31 18:00:12 +0000886 }
887}
888
sewardjd2664472010-08-22 12:44:20 +0000889static IRTemp get_ITSTATE ( void )
890{
891 ASSERT_IS_THUMB;
892 IRTemp t = newTemp(Ity_I32);
893 assign(t, IRExpr_Get( OFFB_ITSTATE, Ity_I32));
894 return t;
895}
896
897static void put_ITSTATE ( IRTemp t )
898{
899 ASSERT_IS_THUMB;
900 stmt( IRStmt_Put( OFFB_ITSTATE, mkexpr(t)) );
901}
902
903static IRTemp get_QFLAG32 ( void )
904{
905 IRTemp t = newTemp(Ity_I32);
906 assign(t, IRExpr_Get( OFFB_QFLAG32, Ity_I32));
907 return t;
908}
909
910static void put_QFLAG32 ( IRTemp t, IRTemp condT )
911{
912 putMiscReg32( OFFB_QFLAG32, mkexpr(t), condT );
913}
914
sewardj1f139f52010-08-29 12:33:02 +0000915/* Stickily set the 'Q' flag (APSR bit 27) of the APSR (Application Program
916 Status Register) to indicate that overflow or saturation occurred.
917 Nb: t must be zero to denote no saturation, and any nonzero
918 value to indicate saturation. */
919static void or_into_QFLAG32 ( IRExpr* e, IRTemp condT )
sewardjd2664472010-08-22 12:44:20 +0000920{
921 IRTemp old = get_QFLAG32();
922 IRTemp nyu = newTemp(Ity_I32);
sewardj1f139f52010-08-29 12:33:02 +0000923 assign(nyu, binop(Iop_Or32, mkexpr(old), e) );
sewardjd2664472010-08-22 12:44:20 +0000924 put_QFLAG32(nyu, condT);
925}
926
sewardj1f139f52010-08-29 12:33:02 +0000927/* Generate code to set APSR.GE[flagNo]. Each fn call sets 1 bit.
928 flagNo: which flag bit to set [3...0]
929 lowbits_to_ignore: 0 = look at all 32 bits
930 8 = look at top 24 bits only
931 16 = look at top 16 bits only
932 31 = look at the top bit only
933 e: input value to be evaluated.
934 The new value is taken from 'e' with the lowest 'lowbits_to_ignore'
935 masked out. If the resulting value is zero then the GE flag is
936 set to 0; any other value sets the flag to 1. */
937static void put_GEFLAG32 ( Int flagNo, /* 0, 1, 2 or 3 */
938 Int lowbits_to_ignore, /* 0, 8, 16 or 31 */
939 IRExpr* e, /* Ity_I32 */
940 IRTemp condT )
941{
942 vassert( flagNo >= 0 && flagNo <= 3 );
943 vassert( lowbits_to_ignore == 0 ||
944 lowbits_to_ignore == 8 ||
945 lowbits_to_ignore == 16 ||
946 lowbits_to_ignore == 31 );
947 IRTemp masked = newTemp(Ity_I32);
948 assign(masked, binop(Iop_Shr32, e, mkU8(lowbits_to_ignore)));
949
950 switch (flagNo) {
951 case 0: putMiscReg32(OFFB_GEFLAG0, mkexpr(masked), condT); break;
952 case 1: putMiscReg32(OFFB_GEFLAG1, mkexpr(masked), condT); break;
953 case 2: putMiscReg32(OFFB_GEFLAG2, mkexpr(masked), condT); break;
954 case 3: putMiscReg32(OFFB_GEFLAG3, mkexpr(masked), condT); break;
955 default: vassert(0);
956 }
957}
958
959/* Return the (32-bit, zero-or-nonzero representation scheme) of
960 the specified GE flag. */
961static IRExpr* get_GEFLAG32( Int flagNo /* 0, 1, 2, 3 */ )
962{
963 switch (flagNo) {
964 case 0: return IRExpr_Get( OFFB_GEFLAG0, Ity_I32 );
965 case 1: return IRExpr_Get( OFFB_GEFLAG1, Ity_I32 );
966 case 2: return IRExpr_Get( OFFB_GEFLAG2, Ity_I32 );
967 case 3: return IRExpr_Get( OFFB_GEFLAG3, Ity_I32 );
968 default: vassert(0);
969 }
970}
971
sewardje2ea1762010-09-22 00:56:37 +0000972/* Set all 4 GE flags from the given 32-bit value as follows: GE 3 and
973 2 are set from bit 31 of the value, and GE 1 and 0 are set from bit
974 15 of the value. All other bits are ignored. */
975static void set_GE_32_10_from_bits_31_15 ( IRTemp t32, IRTemp condT )
976{
977 IRTemp ge10 = newTemp(Ity_I32);
978 IRTemp ge32 = newTemp(Ity_I32);
979 assign(ge10, binop(Iop_And32, mkexpr(t32), mkU32(0x00008000)));
980 assign(ge32, binop(Iop_And32, mkexpr(t32), mkU32(0x80000000)));
981 put_GEFLAG32( 0, 0, mkexpr(ge10), condT );
982 put_GEFLAG32( 1, 0, mkexpr(ge10), condT );
983 put_GEFLAG32( 2, 0, mkexpr(ge32), condT );
984 put_GEFLAG32( 3, 0, mkexpr(ge32), condT );
985}
986
987
988/* Set all 4 GE flags from the given 32-bit value as follows: GE 3
989 from bit 31, GE 2 from bit 23, GE 1 from bit 15, and GE0 from
990 bit 7. All other bits are ignored. */
991static void set_GE_3_2_1_0_from_bits_31_23_15_7 ( IRTemp t32, IRTemp condT )
992{
993 IRTemp ge0 = newTemp(Ity_I32);
994 IRTemp ge1 = newTemp(Ity_I32);
995 IRTemp ge2 = newTemp(Ity_I32);
996 IRTemp ge3 = newTemp(Ity_I32);
997 assign(ge0, binop(Iop_And32, mkexpr(t32), mkU32(0x00000080)));
998 assign(ge1, binop(Iop_And32, mkexpr(t32), mkU32(0x00008000)));
999 assign(ge2, binop(Iop_And32, mkexpr(t32), mkU32(0x00800000)));
1000 assign(ge3, binop(Iop_And32, mkexpr(t32), mkU32(0x80000000)));
1001 put_GEFLAG32( 0, 0, mkexpr(ge0), condT );
1002 put_GEFLAG32( 1, 0, mkexpr(ge1), condT );
1003 put_GEFLAG32( 2, 0, mkexpr(ge2), condT );
1004 put_GEFLAG32( 3, 0, mkexpr(ge3), condT );
1005}
1006
sewardj6c299f32009-12-31 18:00:12 +00001007
1008/* ---------------- FPSCR stuff ---------------- */
1009
1010/* Generate IR to get hold of the rounding mode bits in FPSCR, and
1011 convert them to IR format. Bind the final result to the
1012 returned temp. */
1013static IRTemp /* :: Ity_I32 */ mk_get_IR_rounding_mode ( void )
1014{
1015 /* The ARMvfp encoding for rounding mode bits is:
1016 00 to nearest
1017 01 to +infinity
1018 10 to -infinity
1019 11 to zero
1020 We need to convert that to the IR encoding:
1021 00 to nearest (the default)
1022 10 to +infinity
1023 01 to -infinity
1024 11 to zero
1025 Which can be done by swapping bits 0 and 1.
1026 The rmode bits are at 23:22 in FPSCR.
1027 */
1028 IRTemp armEncd = newTemp(Ity_I32);
1029 IRTemp swapped = newTemp(Ity_I32);
1030 /* Fish FPSCR[23:22] out, and slide to bottom. Doesn't matter that
1031 we don't zero out bits 24 and above, since the assignment to
1032 'swapped' will mask them out anyway. */
1033 assign(armEncd,
1034 binop(Iop_Shr32, IRExpr_Get(OFFB_FPSCR, Ity_I32), mkU8(22)));
1035 /* Now swap them. */
1036 assign(swapped,
1037 binop(Iop_Or32,
1038 binop(Iop_And32,
1039 binop(Iop_Shl32, mkexpr(armEncd), mkU8(1)),
1040 mkU32(2)),
1041 binop(Iop_And32,
1042 binop(Iop_Shr32, mkexpr(armEncd), mkU8(1)),
1043 mkU32(1))
1044 ));
1045 return swapped;
1046}
1047
sewardjc2c87162004-11-25 13:07:02 +00001048
1049/*------------------------------------------------------------*/
sewardj6c299f32009-12-31 18:00:12 +00001050/*--- Helpers for flag handling and conditional insns ---*/
sewardjc2c87162004-11-25 13:07:02 +00001051/*------------------------------------------------------------*/
1052
sewardj6c299f32009-12-31 18:00:12 +00001053static HChar* name_ARMCondcode ( ARMCondcode cond )
sewardjc2c87162004-11-25 13:07:02 +00001054{
sewardj6c299f32009-12-31 18:00:12 +00001055 switch (cond) {
1056 case ARMCondEQ: return "{eq}";
1057 case ARMCondNE: return "{ne}";
1058 case ARMCondHS: return "{hs}"; // or 'cs'
1059 case ARMCondLO: return "{lo}"; // or 'cc'
1060 case ARMCondMI: return "{mi}";
1061 case ARMCondPL: return "{pl}";
1062 case ARMCondVS: return "{vs}";
1063 case ARMCondVC: return "{vc}";
1064 case ARMCondHI: return "{hi}";
1065 case ARMCondLS: return "{ls}";
1066 case ARMCondGE: return "{ge}";
1067 case ARMCondLT: return "{lt}";
1068 case ARMCondGT: return "{gt}";
1069 case ARMCondLE: return "{le}";
1070 case ARMCondAL: return ""; // {al}: is the default
1071 case ARMCondNV: return "{nv}";
1072 default: vpanic("name_ARMCondcode");
sewardjc2c87162004-11-25 13:07:02 +00001073 }
1074}
sewardj6c299f32009-12-31 18:00:12 +00001075/* and a handy shorthand for it */
1076static HChar* nCC ( ARMCondcode cond ) {
1077 return name_ARMCondcode(cond);
cerionf7da63d2004-12-09 19:04:57 +00001078}
1079
cerionc60c01e2004-12-02 20:19:22 +00001080
sewardjc2c87162004-11-25 13:07:02 +00001081/* Build IR to calculate some particular condition from stored
sewardj6c299f32009-12-31 18:00:12 +00001082 CC_OP/CC_DEP1/CC_DEP2/CC_NDEP. Returns an expression of type
1083 Ity_I32, suitable for narrowing. Although the return type is
sewardjd2664472010-08-22 12:44:20 +00001084 Ity_I32, the returned value is either 0 or 1. 'cond' must be
1085 :: Ity_I32 and must denote the condition to compute in
1086 bits 7:4, and be zero everywhere else.
cerionc60c01e2004-12-02 20:19:22 +00001087*/
sewardjd2664472010-08-22 12:44:20 +00001088static IRExpr* mk_armg_calculate_condition_dyn ( IRExpr* cond )
sewardjc2c87162004-11-25 13:07:02 +00001089{
sewardjd2664472010-08-22 12:44:20 +00001090 vassert(typeOfIRExpr(irsb->tyenv, cond) == Ity_I32);
sewardjbb8b3942011-05-01 18:47:10 +00001091 /* And 'cond' had better produce a value in which only bits 7:4 are
1092 nonzero. However, obviously we can't assert for that. */
sewardjd2664472010-08-22 12:44:20 +00001093
1094 /* So what we're constructing for the first argument is
sewardjbb8b3942011-05-01 18:47:10 +00001095 "(cond << 4) | stored-operation".
1096 However, as per comments above, 'cond' must be supplied
1097 pre-shifted to this function.
sewardjd2664472010-08-22 12:44:20 +00001098
1099 This pairing scheme requires that the ARM_CC_OP_ values all fit
1100 in 4 bits. Hence we are passing a (COND, OP) pair in the lowest
1101 8 bits of the first argument. */
sewardjc2c87162004-11-25 13:07:02 +00001102 IRExpr** args
sewardj6c299f32009-12-31 18:00:12 +00001103 = mkIRExprVec_4(
sewardjd2664472010-08-22 12:44:20 +00001104 binop(Iop_Or32, IRExpr_Get(OFFB_CC_OP, Ity_I32), cond),
sewardj6c299f32009-12-31 18:00:12 +00001105 IRExpr_Get(OFFB_CC_DEP1, Ity_I32),
1106 IRExpr_Get(OFFB_CC_DEP2, Ity_I32),
1107 IRExpr_Get(OFFB_CC_NDEP, Ity_I32)
1108 );
sewardjc2c87162004-11-25 13:07:02 +00001109 IRExpr* call
1110 = mkIRExprCCall(
1111 Ity_I32,
1112 0/*regparm*/,
cerionc60c01e2004-12-02 20:19:22 +00001113 "armg_calculate_condition", &armg_calculate_condition,
sewardjc2c87162004-11-25 13:07:02 +00001114 args
1115 );
cerionc60c01e2004-12-02 20:19:22 +00001116
sewardj6c299f32009-12-31 18:00:12 +00001117 /* Exclude the requested condition, OP and NDEP from definedness
sewardjc2c87162004-11-25 13:07:02 +00001118 checking. We're only interested in DEP1 and DEP2. */
sewardj6c299f32009-12-31 18:00:12 +00001119 call->Iex.CCall.cee->mcx_mask = (1<<0) | (1<<3);
1120 return call;
sewardjc2c87162004-11-25 13:07:02 +00001121}
1122
cerionc60c01e2004-12-02 20:19:22 +00001123
sewardjd2664472010-08-22 12:44:20 +00001124/* Build IR to calculate some particular condition from stored
1125 CC_OP/CC_DEP1/CC_DEP2/CC_NDEP. Returns an expression of type
1126 Ity_I32, suitable for narrowing. Although the return type is
1127 Ity_I32, the returned value is either 0 or 1.
1128*/
1129static IRExpr* mk_armg_calculate_condition ( ARMCondcode cond )
1130{
1131 /* First arg is "(cond << 4) | condition". This requires that the
1132 ARM_CC_OP_ values all fit in 4 bits. Hence we are passing a
1133 (COND, OP) pair in the lowest 8 bits of the first argument. */
1134 vassert(cond >= 0 && cond <= 15);
1135 return mk_armg_calculate_condition_dyn( mkU32(cond << 4) );
1136}
1137
1138
sewardj6c299f32009-12-31 18:00:12 +00001139/* Build IR to calculate just the carry flag from stored
1140 CC_OP/CC_DEP1/CC_DEP2/CC_NDEP. Returns an expression ::
1141 Ity_I32. */
1142static IRExpr* mk_armg_calculate_flag_c ( void )
sewardjc2c87162004-11-25 13:07:02 +00001143{
sewardj6c299f32009-12-31 18:00:12 +00001144 IRExpr** args
1145 = mkIRExprVec_4( IRExpr_Get(OFFB_CC_OP, Ity_I32),
1146 IRExpr_Get(OFFB_CC_DEP1, Ity_I32),
1147 IRExpr_Get(OFFB_CC_DEP2, Ity_I32),
1148 IRExpr_Get(OFFB_CC_NDEP, Ity_I32) );
1149 IRExpr* call
1150 = mkIRExprCCall(
1151 Ity_I32,
1152 0/*regparm*/,
1153 "armg_calculate_flag_c", &armg_calculate_flag_c,
1154 args
1155 );
1156 /* Exclude OP and NDEP from definedness checking. We're only
1157 interested in DEP1 and DEP2. */
1158 call->Iex.CCall.cee->mcx_mask = (1<<0) | (1<<3);
1159 return call;
sewardjc2c87162004-11-25 13:07:02 +00001160}
1161
sewardj6c299f32009-12-31 18:00:12 +00001162
1163/* Build IR to calculate just the overflow flag from stored
1164 CC_OP/CC_DEP1/CC_DEP2/CC_NDEP. Returns an expression ::
1165 Ity_I32. */
1166static IRExpr* mk_armg_calculate_flag_v ( void )
sewardjc2c87162004-11-25 13:07:02 +00001167{
sewardj6c299f32009-12-31 18:00:12 +00001168 IRExpr** args
1169 = mkIRExprVec_4( IRExpr_Get(OFFB_CC_OP, Ity_I32),
1170 IRExpr_Get(OFFB_CC_DEP1, Ity_I32),
1171 IRExpr_Get(OFFB_CC_DEP2, Ity_I32),
1172 IRExpr_Get(OFFB_CC_NDEP, Ity_I32) );
1173 IRExpr* call
1174 = mkIRExprCCall(
1175 Ity_I32,
1176 0/*regparm*/,
1177 "armg_calculate_flag_v", &armg_calculate_flag_v,
1178 args
1179 );
1180 /* Exclude OP and NDEP from definedness checking. We're only
1181 interested in DEP1 and DEP2. */
1182 call->Iex.CCall.cee->mcx_mask = (1<<0) | (1<<3);
1183 return call;
sewardjc2c87162004-11-25 13:07:02 +00001184}
1185
sewardj6c299f32009-12-31 18:00:12 +00001186
1187/* Build IR to calculate N Z C V in bits 31:28 of the
1188 returned word. */
1189static IRExpr* mk_armg_calculate_flags_nzcv ( void )
sewardjc2c87162004-11-25 13:07:02 +00001190{
sewardj6c299f32009-12-31 18:00:12 +00001191 IRExpr** args
1192 = mkIRExprVec_4( IRExpr_Get(OFFB_CC_OP, Ity_I32),
1193 IRExpr_Get(OFFB_CC_DEP1, Ity_I32),
1194 IRExpr_Get(OFFB_CC_DEP2, Ity_I32),
1195 IRExpr_Get(OFFB_CC_NDEP, Ity_I32) );
1196 IRExpr* call
1197 = mkIRExprCCall(
1198 Ity_I32,
1199 0/*regparm*/,
1200 "armg_calculate_flags_nzcv", &armg_calculate_flags_nzcv,
1201 args
1202 );
1203 /* Exclude OP and NDEP from definedness checking. We're only
1204 interested in DEP1 and DEP2. */
1205 call->Iex.CCall.cee->mcx_mask = (1<<0) | (1<<3);
1206 return call;
sewardjc2c87162004-11-25 13:07:02 +00001207}
1208
sewardjd2664472010-08-22 12:44:20 +00001209static IRExpr* mk_armg_calculate_flag_qc ( IRExpr* resL, IRExpr* resR, Bool Q )
1210{
1211 IRExpr** args1;
1212 IRExpr** args2;
1213 IRExpr *call1, *call2, *res;
1214
1215 if (Q) {
1216 args1 = mkIRExprVec_4 ( binop(Iop_GetElem32x4, resL, mkU8(0)),
1217 binop(Iop_GetElem32x4, resL, mkU8(1)),
1218 binop(Iop_GetElem32x4, resR, mkU8(0)),
1219 binop(Iop_GetElem32x4, resR, mkU8(1)) );
1220 args2 = mkIRExprVec_4 ( binop(Iop_GetElem32x4, resL, mkU8(2)),
1221 binop(Iop_GetElem32x4, resL, mkU8(3)),
1222 binop(Iop_GetElem32x4, resR, mkU8(2)),
1223 binop(Iop_GetElem32x4, resR, mkU8(3)) );
1224 } else {
1225 args1 = mkIRExprVec_4 ( binop(Iop_GetElem32x2, resL, mkU8(0)),
1226 binop(Iop_GetElem32x2, resL, mkU8(1)),
1227 binop(Iop_GetElem32x2, resR, mkU8(0)),
1228 binop(Iop_GetElem32x2, resR, mkU8(1)) );
1229 }
1230
1231#if 1
1232 call1 = mkIRExprCCall(
1233 Ity_I32,
1234 0/*regparm*/,
1235 "armg_calculate_flag_qc", &armg_calculate_flag_qc,
1236 args1
1237 );
1238 if (Q) {
1239 call2 = mkIRExprCCall(
1240 Ity_I32,
1241 0/*regparm*/,
1242 "armg_calculate_flag_qc", &armg_calculate_flag_qc,
1243 args2
1244 );
1245 }
1246 if (Q) {
1247 res = binop(Iop_Or32, call1, call2);
1248 } else {
1249 res = call1;
1250 }
1251#else
1252 if (Q) {
1253 res = unop(Iop_1Uto32,
1254 binop(Iop_CmpNE32,
1255 binop(Iop_Or32,
1256 binop(Iop_Or32,
1257 binop(Iop_Xor32,
1258 args1[0],
1259 args1[2]),
1260 binop(Iop_Xor32,
1261 args1[1],
1262 args1[3])),
1263 binop(Iop_Or32,
1264 binop(Iop_Xor32,
1265 args2[0],
1266 args2[2]),
1267 binop(Iop_Xor32,
1268 args2[1],
1269 args2[3]))),
1270 mkU32(0)));
1271 } else {
1272 res = unop(Iop_1Uto32,
1273 binop(Iop_CmpNE32,
1274 binop(Iop_Or32,
1275 binop(Iop_Xor32,
1276 args1[0],
1277 args1[2]),
1278 binop(Iop_Xor32,
1279 args1[1],
1280 args1[3])),
1281 mkU32(0)));
1282 }
1283#endif
1284 return res;
1285}
1286
sewardj9dbbd7b2010-08-22 18:24:51 +00001287// FIXME: this is named wrongly .. looks like a sticky set of
1288// QC, not a write to it.
sewardjd2664472010-08-22 12:44:20 +00001289static void setFlag_QC ( IRExpr* resL, IRExpr* resR, Bool Q,
1290 IRTemp condT )
1291{
1292 putMiscReg32 (OFFB_FPSCR,
1293 binop(Iop_Or32,
1294 IRExpr_Get(OFFB_FPSCR, Ity_I32),
1295 binop(Iop_Shl32,
1296 mk_armg_calculate_flag_qc(resL, resR, Q),
1297 mkU8(27))),
1298 condT);
1299}
sewardjc2c87162004-11-25 13:07:02 +00001300
sewardj6c299f32009-12-31 18:00:12 +00001301/* Build IR to conditionally set the flags thunk. As with putIReg, if
1302 guard is IRTemp_INVALID then it's unconditional, else it holds a
1303 condition :: Ity_I32. */
sewardjc2c87162004-11-25 13:07:02 +00001304static
sewardj6c299f32009-12-31 18:00:12 +00001305void setFlags_D1_D2_ND ( UInt cc_op, IRTemp t_dep1,
1306 IRTemp t_dep2, IRTemp t_ndep,
1307 IRTemp guardT /* :: Ity_I32, 0 or 1 */ )
sewardjc2c87162004-11-25 13:07:02 +00001308{
sewardj6c299f32009-12-31 18:00:12 +00001309 IRTemp c8;
1310 vassert(typeOfIRTemp(irsb->tyenv, t_dep1 == Ity_I32));
1311 vassert(typeOfIRTemp(irsb->tyenv, t_dep2 == Ity_I32));
1312 vassert(typeOfIRTemp(irsb->tyenv, t_ndep == Ity_I32));
1313 vassert(cc_op >= ARMG_CC_OP_COPY && cc_op < ARMG_CC_OP_NUMBER);
1314 if (guardT == IRTemp_INVALID) {
1315 /* unconditional */
1316 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(cc_op) ));
1317 stmt( IRStmt_Put( OFFB_CC_DEP1, mkexpr(t_dep1) ));
1318 stmt( IRStmt_Put( OFFB_CC_DEP2, mkexpr(t_dep2) ));
1319 stmt( IRStmt_Put( OFFB_CC_NDEP, mkexpr(t_ndep) ));
sewardjc2c87162004-11-25 13:07:02 +00001320 } else {
sewardj6c299f32009-12-31 18:00:12 +00001321 /* conditional */
1322 c8 = newTemp(Ity_I8);
1323 assign( c8, unop(Iop_32to8, mkexpr(guardT)) );
1324 stmt( IRStmt_Put(
1325 OFFB_CC_OP,
1326 IRExpr_Mux0X( mkexpr(c8),
1327 IRExpr_Get(OFFB_CC_OP, Ity_I32),
1328 mkU32(cc_op) )));
1329 stmt( IRStmt_Put(
1330 OFFB_CC_DEP1,
1331 IRExpr_Mux0X( mkexpr(c8),
1332 IRExpr_Get(OFFB_CC_DEP1, Ity_I32),
1333 mkexpr(t_dep1) )));
1334 stmt( IRStmt_Put(
1335 OFFB_CC_DEP2,
1336 IRExpr_Mux0X( mkexpr(c8),
1337 IRExpr_Get(OFFB_CC_DEP2, Ity_I32),
1338 mkexpr(t_dep2) )));
1339 stmt( IRStmt_Put(
1340 OFFB_CC_NDEP,
1341 IRExpr_Mux0X( mkexpr(c8),
1342 IRExpr_Get(OFFB_CC_NDEP, Ity_I32),
1343 mkexpr(t_ndep) )));
sewardjc2c87162004-11-25 13:07:02 +00001344 }
1345}
cerionc60c01e2004-12-02 20:19:22 +00001346
1347
sewardj6c299f32009-12-31 18:00:12 +00001348/* Minor variant of the above that sets NDEP to zero (if it
1349 sets it at all) */
1350static void setFlags_D1_D2 ( UInt cc_op, IRTemp t_dep1,
1351 IRTemp t_dep2,
1352 IRTemp guardT /* :: Ity_I32, 0 or 1 */ )
cerion397f9e52004-12-15 13:04:06 +00001353{
sewardj6c299f32009-12-31 18:00:12 +00001354 IRTemp z32 = newTemp(Ity_I32);
1355 assign( z32, mkU32(0) );
1356 setFlags_D1_D2_ND( cc_op, t_dep1, t_dep2, z32, guardT );
cerion397f9e52004-12-15 13:04:06 +00001357}
1358
1359
sewardj6c299f32009-12-31 18:00:12 +00001360/* Minor variant of the above that sets DEP2 to zero (if it
1361 sets it at all) */
1362static void setFlags_D1_ND ( UInt cc_op, IRTemp t_dep1,
1363 IRTemp t_ndep,
1364 IRTemp guardT /* :: Ity_I32, 0 or 1 */ )
cerion397f9e52004-12-15 13:04:06 +00001365{
sewardj6c299f32009-12-31 18:00:12 +00001366 IRTemp z32 = newTemp(Ity_I32);
1367 assign( z32, mkU32(0) );
1368 setFlags_D1_D2_ND( cc_op, t_dep1, z32, t_ndep, guardT );
cerion397f9e52004-12-15 13:04:06 +00001369}
1370
sewardj6c299f32009-12-31 18:00:12 +00001371
1372/* Minor variant of the above that sets DEP2 and NDEP to zero (if it
1373 sets them at all) */
1374static void setFlags_D1 ( UInt cc_op, IRTemp t_dep1,
1375 IRTemp guardT /* :: Ity_I32, 0 or 1 */ )
cerion397f9e52004-12-15 13:04:06 +00001376{
sewardj6c299f32009-12-31 18:00:12 +00001377 IRTemp z32 = newTemp(Ity_I32);
1378 assign( z32, mkU32(0) );
1379 setFlags_D1_D2_ND( cc_op, t_dep1, z32, z32, guardT );
cerion397f9e52004-12-15 13:04:06 +00001380}
cerionc60c01e2004-12-02 20:19:22 +00001381
1382
sewardjd2664472010-08-22 12:44:20 +00001383/* ARM only */
sewardj6c299f32009-12-31 18:00:12 +00001384/* Generate a side-exit to the next instruction, if the given guard
1385 expression :: Ity_I32 is 0 (note! the side exit is taken if the
1386 condition is false!) This is used to skip over conditional
1387 instructions which we can't generate straight-line code for, either
1388 because they are too complex or (more likely) they potentially
1389 generate exceptions.
cerionf7da63d2004-12-09 19:04:57 +00001390*/
sewardjd2664472010-08-22 12:44:20 +00001391static void mk_skip_over_A32_if_cond_is_false (
sewardj6c299f32009-12-31 18:00:12 +00001392 IRTemp guardT /* :: Ity_I32, 0 or 1 */
1393 )
cerionf7da63d2004-12-09 19:04:57 +00001394{
sewardjd2664472010-08-22 12:44:20 +00001395 ASSERT_IS_ARM;
sewardj6c299f32009-12-31 18:00:12 +00001396 vassert(guardT != IRTemp_INVALID);
sewardjd2664472010-08-22 12:44:20 +00001397 vassert(0 == (guest_R15_curr_instr_notENC & 3));
sewardj6c299f32009-12-31 18:00:12 +00001398 stmt( IRStmt_Exit(
1399 unop(Iop_Not1, unop(Iop_32to1, mkexpr(guardT))),
1400 Ijk_Boring,
sewardjc6f970f2012-04-02 21:54:49 +00001401 IRConst_U32(toUInt(guest_R15_curr_instr_notENC + 4)),
1402 OFFB_R15T
sewardj6c299f32009-12-31 18:00:12 +00001403 ));
1404}
1405
sewardjd2664472010-08-22 12:44:20 +00001406/* Thumb16 only */
1407/* ditto, but jump over a 16-bit thumb insn */
1408static void mk_skip_over_T16_if_cond_is_false (
1409 IRTemp guardT /* :: Ity_I32, 0 or 1 */
1410 )
1411{
1412 ASSERT_IS_THUMB;
1413 vassert(guardT != IRTemp_INVALID);
1414 vassert(0 == (guest_R15_curr_instr_notENC & 1));
1415 stmt( IRStmt_Exit(
1416 unop(Iop_Not1, unop(Iop_32to1, mkexpr(guardT))),
1417 Ijk_Boring,
sewardjc6f970f2012-04-02 21:54:49 +00001418 IRConst_U32(toUInt((guest_R15_curr_instr_notENC + 2) | 1)),
1419 OFFB_R15T
sewardjd2664472010-08-22 12:44:20 +00001420 ));
1421}
1422
1423
1424/* Thumb32 only */
1425/* ditto, but jump over a 32-bit thumb insn */
1426static void mk_skip_over_T32_if_cond_is_false (
1427 IRTemp guardT /* :: Ity_I32, 0 or 1 */
1428 )
1429{
1430 ASSERT_IS_THUMB;
1431 vassert(guardT != IRTemp_INVALID);
1432 vassert(0 == (guest_R15_curr_instr_notENC & 1));
1433 stmt( IRStmt_Exit(
1434 unop(Iop_Not1, unop(Iop_32to1, mkexpr(guardT))),
1435 Ijk_Boring,
sewardjc6f970f2012-04-02 21:54:49 +00001436 IRConst_U32(toUInt((guest_R15_curr_instr_notENC + 4) | 1)),
1437 OFFB_R15T
sewardjd2664472010-08-22 12:44:20 +00001438 ));
1439}
1440
1441
1442/* Thumb16 and Thumb32 only
1443 Generate a SIGILL followed by a restart of the current instruction
1444 if the given temp is nonzero. */
1445static void gen_SIGILL_T_if_nonzero ( IRTemp t /* :: Ity_I32 */ )
1446{
1447 ASSERT_IS_THUMB;
1448 vassert(t != IRTemp_INVALID);
1449 vassert(0 == (guest_R15_curr_instr_notENC & 1));
1450 stmt(
1451 IRStmt_Exit(
1452 binop(Iop_CmpNE32, mkexpr(t), mkU32(0)),
1453 Ijk_NoDecode,
sewardjc6f970f2012-04-02 21:54:49 +00001454 IRConst_U32(toUInt(guest_R15_curr_instr_notENC | 1)),
1455 OFFB_R15T
sewardjd2664472010-08-22 12:44:20 +00001456 )
1457 );
1458}
1459
1460
1461/* Inspect the old_itstate, and generate a SIGILL if it indicates that
1462 we are currently in an IT block and are not the last in the block.
1463 This also rolls back guest_ITSTATE to its old value before the exit
1464 and restores it to its new value afterwards. This is so that if
1465 the exit is taken, we have an up to date version of ITSTATE
1466 available. Without doing that, we have no hope of making precise
1467 exceptions work. */
1468static void gen_SIGILL_T_if_in_but_NLI_ITBlock (
1469 IRTemp old_itstate /* :: Ity_I32 */,
1470 IRTemp new_itstate /* :: Ity_I32 */
1471 )
1472{
1473 ASSERT_IS_THUMB;
1474 put_ITSTATE(old_itstate); // backout
1475 IRTemp guards_for_next3 = newTemp(Ity_I32);
1476 assign(guards_for_next3,
1477 binop(Iop_Shr32, mkexpr(old_itstate), mkU8(8)));
1478 gen_SIGILL_T_if_nonzero(guards_for_next3);
1479 put_ITSTATE(new_itstate); //restore
1480}
1481
1482
1483/* Simpler version of the above, which generates a SIGILL if
1484 we're anywhere within an IT block. */
1485static void gen_SIGILL_T_if_in_ITBlock (
1486 IRTemp old_itstate /* :: Ity_I32 */,
1487 IRTemp new_itstate /* :: Ity_I32 */
1488 )
1489{
1490 put_ITSTATE(old_itstate); // backout
1491 gen_SIGILL_T_if_nonzero(old_itstate);
1492 put_ITSTATE(new_itstate); //restore
1493}
1494
1495
sewardj1f139f52010-08-29 12:33:02 +00001496/* Generate an APSR value, from the NZCV thunk, and
1497 from QFLAG32 and GEFLAG0 .. GEFLAG3. */
1498static IRTemp synthesise_APSR ( void )
1499{
1500 IRTemp res1 = newTemp(Ity_I32);
1501 // Get NZCV
1502 assign( res1, mk_armg_calculate_flags_nzcv() );
1503 // OR in the Q value
1504 IRTemp res2 = newTemp(Ity_I32);
1505 assign(
1506 res2,
1507 binop(Iop_Or32,
1508 mkexpr(res1),
1509 binop(Iop_Shl32,
1510 unop(Iop_1Uto32,
1511 binop(Iop_CmpNE32,
1512 mkexpr(get_QFLAG32()),
1513 mkU32(0))),
1514 mkU8(ARMG_CC_SHIFT_Q)))
1515 );
1516 // OR in GE0 .. GE3
1517 IRExpr* ge0
1518 = unop(Iop_1Uto32, binop(Iop_CmpNE32, get_GEFLAG32(0), mkU32(0)));
1519 IRExpr* ge1
1520 = unop(Iop_1Uto32, binop(Iop_CmpNE32, get_GEFLAG32(1), mkU32(0)));
1521 IRExpr* ge2
1522 = unop(Iop_1Uto32, binop(Iop_CmpNE32, get_GEFLAG32(2), mkU32(0)));
1523 IRExpr* ge3
1524 = unop(Iop_1Uto32, binop(Iop_CmpNE32, get_GEFLAG32(3), mkU32(0)));
1525 IRTemp res3 = newTemp(Ity_I32);
1526 assign(res3,
1527 binop(Iop_Or32,
1528 mkexpr(res2),
1529 binop(Iop_Or32,
1530 binop(Iop_Or32,
1531 binop(Iop_Shl32, ge0, mkU8(16)),
1532 binop(Iop_Shl32, ge1, mkU8(17))),
1533 binop(Iop_Or32,
1534 binop(Iop_Shl32, ge2, mkU8(18)),
1535 binop(Iop_Shl32, ge3, mkU8(19))) )));
1536 return res3;
1537}
1538
1539
1540/* and the inverse transformation: given an APSR value,
1541 set the NZCV thunk, the Q flag, and the GE flags. */
1542static void desynthesise_APSR ( Bool write_nzcvq, Bool write_ge,
1543 IRTemp apsrT, IRTemp condT )
1544{
1545 vassert(write_nzcvq || write_ge);
1546 if (write_nzcvq) {
1547 // Do NZCV
1548 IRTemp immT = newTemp(Ity_I32);
1549 assign(immT, binop(Iop_And32, mkexpr(apsrT), mkU32(0xF0000000)) );
1550 setFlags_D1(ARMG_CC_OP_COPY, immT, condT);
1551 // Do Q
1552 IRTemp qnewT = newTemp(Ity_I32);
1553 assign(qnewT, binop(Iop_And32, mkexpr(apsrT), mkU32(ARMG_CC_MASK_Q)));
1554 put_QFLAG32(qnewT, condT);
1555 }
1556 if (write_ge) {
1557 // Do GE3..0
1558 put_GEFLAG32(0, 0, binop(Iop_And32, mkexpr(apsrT), mkU32(1<<16)),
1559 condT);
1560 put_GEFLAG32(1, 0, binop(Iop_And32, mkexpr(apsrT), mkU32(1<<17)),
1561 condT);
1562 put_GEFLAG32(2, 0, binop(Iop_And32, mkexpr(apsrT), mkU32(1<<18)),
1563 condT);
1564 put_GEFLAG32(3, 0, binop(Iop_And32, mkexpr(apsrT), mkU32(1<<19)),
1565 condT);
1566 }
1567}
1568
1569
1570/*------------------------------------------------------------*/
1571/*--- Helpers for saturation ---*/
1572/*------------------------------------------------------------*/
1573
1574/* FIXME: absolutely the only diff. between (a) armUnsignedSatQ and
1575 (b) armSignedSatQ is that in (a) the floor is set to 0, whereas in
1576 (b) the floor is computed from the value of imm5. these two fnsn
1577 should be commoned up. */
1578
1579/* UnsignedSatQ(): 'clamp' each value so it lies between 0 <= x <= (2^N)-1
1580 Optionally return flag resQ saying whether saturation occurred.
1581 See definition in manual, section A2.2.1, page 41
1582 (bits(N), boolean) UnsignedSatQ( integer i, integer N )
1583 {
1584 if ( i > (2^N)-1 ) { result = (2^N)-1; saturated = TRUE; }
1585 elsif ( i < 0 ) { result = 0; saturated = TRUE; }
1586 else { result = i; saturated = FALSE; }
1587 return ( result<N-1:0>, saturated );
1588 }
1589*/
1590static void armUnsignedSatQ( IRTemp* res, /* OUT - Ity_I32 */
1591 IRTemp* resQ, /* OUT - Ity_I32 */
1592 IRTemp regT, /* value to clamp - Ity_I32 */
1593 UInt imm5 ) /* saturation ceiling */
1594{
1595 UInt ceil = (1 << imm5) - 1; // (2^imm5)-1
1596 UInt floor = 0;
1597
1598 IRTemp node0 = newTemp(Ity_I32);
1599 IRTemp node1 = newTemp(Ity_I32);
1600 IRTemp node2 = newTemp(Ity_I1);
1601 IRTemp node3 = newTemp(Ity_I32);
1602 IRTemp node4 = newTemp(Ity_I32);
1603 IRTemp node5 = newTemp(Ity_I1);
1604 IRTemp node6 = newTemp(Ity_I32);
1605
1606 assign( node0, mkexpr(regT) );
1607 assign( node1, mkU32(ceil) );
1608 assign( node2, binop( Iop_CmpLT32S, mkexpr(node1), mkexpr(node0) ) );
1609 assign( node3, IRExpr_Mux0X( unop(Iop_1Uto8, mkexpr(node2)),
1610 mkexpr(node0),
1611 mkexpr(node1) ) );
1612 assign( node4, mkU32(floor) );
1613 assign( node5, binop( Iop_CmpLT32S, mkexpr(node3), mkexpr(node4) ) );
1614 assign( node6, IRExpr_Mux0X( unop(Iop_1Uto8, mkexpr(node5)),
1615 mkexpr(node3),
1616 mkexpr(node4) ) );
1617 assign( *res, mkexpr(node6) );
1618
1619 /* if saturation occurred, then resQ is set to some nonzero value
1620 if sat did not occur, resQ is guaranteed to be zero. */
1621 if (resQ) {
1622 assign( *resQ, binop(Iop_Xor32, mkexpr(*res), mkexpr(regT)) );
1623 }
1624}
1625
1626
1627/* SignedSatQ(): 'clamp' each value so it lies between -2^N <= x <= (2^N) - 1
1628 Optionally return flag resQ saying whether saturation occurred.
1629 - see definition in manual, section A2.2.1, page 41
1630 (bits(N), boolean ) SignedSatQ( integer i, integer N )
1631 {
1632 if ( i > 2^(N-1) - 1 ) { result = 2^(N-1) - 1; saturated = TRUE; }
1633 elsif ( i < -(2^(N-1)) ) { result = -(2^(N-1)); saturated = FALSE; }
1634 else { result = i; saturated = FALSE; }
1635 return ( result[N-1:0], saturated );
1636 }
1637*/
1638static void armSignedSatQ( IRTemp regT, /* value to clamp - Ity_I32 */
1639 UInt imm5, /* saturation ceiling */
1640 IRTemp* res, /* OUT - Ity_I32 */
1641 IRTemp* resQ ) /* OUT - Ity_I32 */
1642{
1643 Int ceil = (1 << (imm5-1)) - 1; // (2^(imm5-1))-1
1644 Int floor = -(1 << (imm5-1)); // -(2^(imm5-1))
1645
1646 IRTemp node0 = newTemp(Ity_I32);
1647 IRTemp node1 = newTemp(Ity_I32);
1648 IRTemp node2 = newTemp(Ity_I1);
1649 IRTemp node3 = newTemp(Ity_I32);
1650 IRTemp node4 = newTemp(Ity_I32);
1651 IRTemp node5 = newTemp(Ity_I1);
1652 IRTemp node6 = newTemp(Ity_I32);
1653
1654 assign( node0, mkexpr(regT) );
1655 assign( node1, mkU32(ceil) );
1656 assign( node2, binop( Iop_CmpLT32S, mkexpr(node1), mkexpr(node0) ) );
1657 assign( node3, IRExpr_Mux0X( unop(Iop_1Uto8, mkexpr(node2)),
1658 mkexpr(node0), mkexpr(node1) ) );
1659 assign( node4, mkU32(floor) );
1660 assign( node5, binop( Iop_CmpLT32S, mkexpr(node3), mkexpr(node4) ) );
1661 assign( node6, IRExpr_Mux0X( unop(Iop_1Uto8, mkexpr(node5)),
1662 mkexpr(node3), mkexpr(node4) ) );
1663 assign( *res, mkexpr(node6) );
1664
1665 /* if saturation occurred, then resQ is set to some nonzero value
1666 if sat did not occur, resQ is guaranteed to be zero. */
1667 if (resQ) {
1668 assign( *resQ, binop(Iop_Xor32, mkexpr(*res), mkexpr(regT)) );
1669 }
1670}
1671
sewardj6c299f32009-12-31 18:00:12 +00001672
sewardj310d6b22010-10-18 16:29:40 +00001673/* Compute a value 0 :: I32 or 1 :: I32, indicating whether signed
1674 overflow occurred for 32-bit addition. Needs both args and the
1675 result. HD p27. */
1676static
1677IRExpr* signed_overflow_after_Add32 ( IRExpr* resE,
1678 IRTemp argL, IRTemp argR )
1679{
1680 IRTemp res = newTemp(Ity_I32);
1681 assign(res, resE);
1682 return
1683 binop( Iop_Shr32,
1684 binop( Iop_And32,
1685 binop( Iop_Xor32, mkexpr(res), mkexpr(argL) ),
1686 binop( Iop_Xor32, mkexpr(res), mkexpr(argR) )),
1687 mkU8(31) );
1688}
1689
sewardj44ce46d2012-07-11 13:19:10 +00001690/* Similarly .. also from HD p27 .. */
1691static
1692IRExpr* signed_overflow_after_Sub32 ( IRExpr* resE,
1693 IRTemp argL, IRTemp argR )
1694{
1695 IRTemp res = newTemp(Ity_I32);
1696 assign(res, resE);
1697 return
1698 binop( Iop_Shr32,
1699 binop( Iop_And32,
1700 binop( Iop_Xor32, mkexpr(argL), mkexpr(argR) ),
1701 binop( Iop_Xor32, mkexpr(res), mkexpr(argL) )),
1702 mkU8(31) );
1703}
1704
sewardj310d6b22010-10-18 16:29:40 +00001705
sewardj6c299f32009-12-31 18:00:12 +00001706/*------------------------------------------------------------*/
1707/*--- Larger helpers ---*/
1708/*------------------------------------------------------------*/
1709
sewardjd2664472010-08-22 12:44:20 +00001710/* Compute both the result and new C flag value for a LSL by an imm5
1711 or by a register operand. May generate reads of the old C value
1712 (hence only safe to use before any writes to guest state happen).
1713 Are factored out so can be used by both ARM and Thumb.
1714
1715 Note that in compute_result_and_C_after_{LSL,LSR,ASR}_by{imm5,reg},
1716 "res" (the result) is a.k.a. "shop", shifter operand
1717 "newC" (the new C) is a.k.a. "shco", shifter carry out
1718
1719 The calling convention for res and newC is a bit funny. They could
1720 be passed by value, but instead are passed by ref.
sewardjbb8b3942011-05-01 18:47:10 +00001721
1722 The C (shco) value computed must be zero in bits 31:1, as the IR
1723 optimisations for flag handling (guest_arm_spechelper) rely on
1724 that, and the slow-path handlers (armg_calculate_flags_nzcv) assert
1725 for it. Same applies to all these functions that compute shco
1726 after a shift or rotate, not just this one.
sewardjd2664472010-08-22 12:44:20 +00001727*/
1728
1729static void compute_result_and_C_after_LSL_by_imm5 (
1730 /*OUT*/HChar* buf,
1731 IRTemp* res,
1732 IRTemp* newC,
1733 IRTemp rMt, UInt shift_amt, /* operands */
1734 UInt rM /* only for debug printing */
1735 )
1736{
1737 if (shift_amt == 0) {
1738 if (newC) {
1739 assign( *newC, mk_armg_calculate_flag_c() );
1740 }
1741 assign( *res, mkexpr(rMt) );
1742 DIS(buf, "r%u", rM);
1743 } else {
1744 vassert(shift_amt >= 1 && shift_amt <= 31);
1745 if (newC) {
1746 assign( *newC,
1747 binop(Iop_And32,
1748 binop(Iop_Shr32, mkexpr(rMt),
1749 mkU8(32 - shift_amt)),
1750 mkU32(1)));
1751 }
1752 assign( *res,
1753 binop(Iop_Shl32, mkexpr(rMt), mkU8(shift_amt)) );
1754 DIS(buf, "r%u, LSL #%u", rM, shift_amt);
1755 }
1756}
1757
1758
1759static void compute_result_and_C_after_LSL_by_reg (
1760 /*OUT*/HChar* buf,
1761 IRTemp* res,
1762 IRTemp* newC,
1763 IRTemp rMt, IRTemp rSt, /* operands */
1764 UInt rM, UInt rS /* only for debug printing */
1765 )
1766{
1767 // shift left in range 0 .. 255
1768 // amt = rS & 255
1769 // res = amt < 32 ? Rm << amt : 0
1770 // newC = amt == 0 ? oldC :
1771 // amt in 1..32 ? Rm[32-amt] : 0
1772 IRTemp amtT = newTemp(Ity_I32);
1773 assign( amtT, binop(Iop_And32, mkexpr(rSt), mkU32(255)) );
1774 if (newC) {
1775 /* mux0X(amt == 0,
1776 mux0X(amt < 32,
1777 0,
sewardjbb8b3942011-05-01 18:47:10 +00001778 Rm[(32-amt) & 31]),
sewardjd2664472010-08-22 12:44:20 +00001779 oldC)
1780 */
1781 /* About the best you can do is pray that iropt is able
1782 to nuke most or all of the following junk. */
1783 IRTemp oldC = newTemp(Ity_I32);
1784 assign(oldC, mk_armg_calculate_flag_c() );
1785 assign(
1786 *newC,
1787 IRExpr_Mux0X(
1788 unop(Iop_1Uto8,
1789 binop(Iop_CmpEQ32, mkexpr(amtT), mkU32(0))),
1790 IRExpr_Mux0X(
1791 unop(Iop_1Uto8,
1792 binop(Iop_CmpLE32U, mkexpr(amtT), mkU32(32))),
1793 mkU32(0),
sewardjbb8b3942011-05-01 18:47:10 +00001794 binop(Iop_And32,
1795 binop(Iop_Shr32,
1796 mkexpr(rMt),
1797 unop(Iop_32to8,
1798 binop(Iop_And32,
1799 binop(Iop_Sub32,
1800 mkU32(32),
1801 mkexpr(amtT)),
1802 mkU32(31)
1803 )
1804 )
1805 ),
1806 mkU32(1)
sewardjd2664472010-08-22 12:44:20 +00001807 )
1808 ),
1809 mkexpr(oldC)
1810 )
1811 );
1812 }
1813 // (Rm << (Rs & 31)) & (((Rs & 255) - 32) >>s 31)
1814 // Lhs of the & limits the shift to 31 bits, so as to
1815 // give known IR semantics. Rhs of the & is all 1s for
1816 // Rs <= 31 and all 0s for Rs >= 32.
1817 assign(
1818 *res,
1819 binop(
1820 Iop_And32,
1821 binop(Iop_Shl32,
1822 mkexpr(rMt),
1823 unop(Iop_32to8,
1824 binop(Iop_And32, mkexpr(rSt), mkU32(31)))),
1825 binop(Iop_Sar32,
1826 binop(Iop_Sub32,
1827 mkexpr(amtT),
1828 mkU32(32)),
1829 mkU8(31))));
1830 DIS(buf, "r%u, LSL r%u", rM, rS);
1831}
1832
1833
1834static void compute_result_and_C_after_LSR_by_imm5 (
1835 /*OUT*/HChar* buf,
1836 IRTemp* res,
1837 IRTemp* newC,
1838 IRTemp rMt, UInt shift_amt, /* operands */
1839 UInt rM /* only for debug printing */
1840 )
1841{
1842 if (shift_amt == 0) {
1843 // conceptually a 32-bit shift, however:
1844 // res = 0
1845 // newC = Rm[31]
1846 if (newC) {
1847 assign( *newC,
1848 binop(Iop_And32,
1849 binop(Iop_Shr32, mkexpr(rMt), mkU8(31)),
1850 mkU32(1)));
1851 }
1852 assign( *res, mkU32(0) );
1853 DIS(buf, "r%u, LSR #0(a.k.a. 32)", rM);
1854 } else {
1855 // shift in range 1..31
1856 // res = Rm >>u shift_amt
1857 // newC = Rm[shift_amt - 1]
1858 vassert(shift_amt >= 1 && shift_amt <= 31);
1859 if (newC) {
1860 assign( *newC,
1861 binop(Iop_And32,
1862 binop(Iop_Shr32, mkexpr(rMt),
1863 mkU8(shift_amt - 1)),
1864 mkU32(1)));
1865 }
1866 assign( *res,
1867 binop(Iop_Shr32, mkexpr(rMt), mkU8(shift_amt)) );
1868 DIS(buf, "r%u, LSR #%u", rM, shift_amt);
1869 }
1870}
1871
1872
1873static void compute_result_and_C_after_LSR_by_reg (
1874 /*OUT*/HChar* buf,
1875 IRTemp* res,
1876 IRTemp* newC,
1877 IRTemp rMt, IRTemp rSt, /* operands */
1878 UInt rM, UInt rS /* only for debug printing */
1879 )
1880{
1881 // shift right in range 0 .. 255
1882 // amt = rS & 255
1883 // res = amt < 32 ? Rm >>u amt : 0
1884 // newC = amt == 0 ? oldC :
1885 // amt in 1..32 ? Rm[amt-1] : 0
1886 IRTemp amtT = newTemp(Ity_I32);
1887 assign( amtT, binop(Iop_And32, mkexpr(rSt), mkU32(255)) );
1888 if (newC) {
1889 /* mux0X(amt == 0,
1890 mux0X(amt < 32,
1891 0,
sewardjbb8b3942011-05-01 18:47:10 +00001892 Rm[(amt-1) & 31]),
sewardjd2664472010-08-22 12:44:20 +00001893 oldC)
1894 */
1895 IRTemp oldC = newTemp(Ity_I32);
1896 assign(oldC, mk_armg_calculate_flag_c() );
1897 assign(
1898 *newC,
1899 IRExpr_Mux0X(
1900 unop(Iop_1Uto8,
1901 binop(Iop_CmpEQ32, mkexpr(amtT), mkU32(0))),
1902 IRExpr_Mux0X(
1903 unop(Iop_1Uto8,
1904 binop(Iop_CmpLE32U, mkexpr(amtT), mkU32(32))),
1905 mkU32(0),
sewardjbb8b3942011-05-01 18:47:10 +00001906 binop(Iop_And32,
1907 binop(Iop_Shr32,
1908 mkexpr(rMt),
1909 unop(Iop_32to8,
1910 binop(Iop_And32,
1911 binop(Iop_Sub32,
1912 mkexpr(amtT),
1913 mkU32(1)),
1914 mkU32(31)
1915 )
1916 )
1917 ),
1918 mkU32(1)
sewardjd2664472010-08-22 12:44:20 +00001919 )
1920 ),
1921 mkexpr(oldC)
1922 )
1923 );
1924 }
1925 // (Rm >>u (Rs & 31)) & (((Rs & 255) - 32) >>s 31)
1926 // Lhs of the & limits the shift to 31 bits, so as to
1927 // give known IR semantics. Rhs of the & is all 1s for
1928 // Rs <= 31 and all 0s for Rs >= 32.
1929 assign(
1930 *res,
1931 binop(
1932 Iop_And32,
1933 binop(Iop_Shr32,
1934 mkexpr(rMt),
1935 unop(Iop_32to8,
1936 binop(Iop_And32, mkexpr(rSt), mkU32(31)))),
1937 binop(Iop_Sar32,
1938 binop(Iop_Sub32,
1939 mkexpr(amtT),
1940 mkU32(32)),
1941 mkU8(31))));
1942 DIS(buf, "r%u, LSR r%u", rM, rS);
1943}
1944
1945
1946static void compute_result_and_C_after_ASR_by_imm5 (
1947 /*OUT*/HChar* buf,
1948 IRTemp* res,
1949 IRTemp* newC,
1950 IRTemp rMt, UInt shift_amt, /* operands */
1951 UInt rM /* only for debug printing */
1952 )
1953{
1954 if (shift_amt == 0) {
1955 // conceptually a 32-bit shift, however:
1956 // res = Rm >>s 31
1957 // newC = Rm[31]
1958 if (newC) {
1959 assign( *newC,
1960 binop(Iop_And32,
1961 binop(Iop_Shr32, mkexpr(rMt), mkU8(31)),
1962 mkU32(1)));
1963 }
1964 assign( *res, binop(Iop_Sar32, mkexpr(rMt), mkU8(31)) );
1965 DIS(buf, "r%u, ASR #0(a.k.a. 32)", rM);
1966 } else {
1967 // shift in range 1..31
1968 // res = Rm >>s shift_amt
1969 // newC = Rm[shift_amt - 1]
1970 vassert(shift_amt >= 1 && shift_amt <= 31);
1971 if (newC) {
1972 assign( *newC,
1973 binop(Iop_And32,
1974 binop(Iop_Shr32, mkexpr(rMt),
1975 mkU8(shift_amt - 1)),
1976 mkU32(1)));
1977 }
1978 assign( *res,
1979 binop(Iop_Sar32, mkexpr(rMt), mkU8(shift_amt)) );
1980 DIS(buf, "r%u, ASR #%u", rM, shift_amt);
1981 }
1982}
1983
1984
1985static void compute_result_and_C_after_ASR_by_reg (
1986 /*OUT*/HChar* buf,
1987 IRTemp* res,
1988 IRTemp* newC,
1989 IRTemp rMt, IRTemp rSt, /* operands */
1990 UInt rM, UInt rS /* only for debug printing */
1991 )
1992{
1993 // arithmetic shift right in range 0 .. 255
1994 // amt = rS & 255
1995 // res = amt < 32 ? Rm >>s amt : Rm >>s 31
1996 // newC = amt == 0 ? oldC :
1997 // amt in 1..32 ? Rm[amt-1] : Rm[31]
1998 IRTemp amtT = newTemp(Ity_I32);
1999 assign( amtT, binop(Iop_And32, mkexpr(rSt), mkU32(255)) );
2000 if (newC) {
2001 /* mux0X(amt == 0,
2002 mux0X(amt < 32,
2003 Rm[31],
2004 Rm[(amt-1) & 31])
2005 oldC)
2006 */
2007 IRTemp oldC = newTemp(Ity_I32);
2008 assign(oldC, mk_armg_calculate_flag_c() );
2009 assign(
2010 *newC,
2011 IRExpr_Mux0X(
2012 unop(Iop_1Uto8,
2013 binop(Iop_CmpEQ32, mkexpr(amtT), mkU32(0))),
2014 IRExpr_Mux0X(
2015 unop(Iop_1Uto8,
2016 binop(Iop_CmpLE32U, mkexpr(amtT), mkU32(32))),
sewardjbb8b3942011-05-01 18:47:10 +00002017 binop(Iop_And32,
2018 binop(Iop_Shr32,
2019 mkexpr(rMt),
2020 mkU8(31)
2021 ),
2022 mkU32(1)
sewardjd2664472010-08-22 12:44:20 +00002023 ),
sewardjbb8b3942011-05-01 18:47:10 +00002024 binop(Iop_And32,
2025 binop(Iop_Shr32,
2026 mkexpr(rMt),
2027 unop(Iop_32to8,
2028 binop(Iop_And32,
2029 binop(Iop_Sub32,
2030 mkexpr(amtT),
2031 mkU32(1)),
2032 mkU32(31)
2033 )
2034 )
2035 ),
2036 mkU32(1)
sewardjd2664472010-08-22 12:44:20 +00002037 )
2038 ),
2039 mkexpr(oldC)
2040 )
2041 );
2042 }
2043 // (Rm >>s (amt <u 32 ? amt : 31))
2044 assign(
2045 *res,
2046 binop(
2047 Iop_Sar32,
2048 mkexpr(rMt),
2049 unop(
2050 Iop_32to8,
2051 IRExpr_Mux0X(
2052 unop(
2053 Iop_1Uto8,
2054 binop(Iop_CmpLT32U, mkexpr(amtT), mkU32(32))),
2055 mkU32(31),
2056 mkexpr(amtT)))));
2057 DIS(buf, "r%u, ASR r%u", rM, rS);
2058}
2059
2060
2061static void compute_result_and_C_after_ROR_by_reg (
2062 /*OUT*/HChar* buf,
2063 IRTemp* res,
2064 IRTemp* newC,
2065 IRTemp rMt, IRTemp rSt, /* operands */
2066 UInt rM, UInt rS /* only for debug printing */
2067 )
2068{
2069 // rotate right in range 0 .. 255
2070 // amt = rS & 255
2071 // shop = Rm `ror` (amt & 31)
2072 // shco = amt == 0 ? oldC : Rm[(amt-1) & 31]
2073 IRTemp amtT = newTemp(Ity_I32);
2074 assign( amtT, binop(Iop_And32, mkexpr(rSt), mkU32(255)) );
2075 IRTemp amt5T = newTemp(Ity_I32);
2076 assign( amt5T, binop(Iop_And32, mkexpr(rSt), mkU32(31)) );
2077 IRTemp oldC = newTemp(Ity_I32);
2078 assign(oldC, mk_armg_calculate_flag_c() );
2079 if (newC) {
2080 assign(
2081 *newC,
2082 IRExpr_Mux0X(
2083 unop(Iop_32to8, mkexpr(amtT)),
2084 mkexpr(oldC),
2085 binop(Iop_And32,
2086 binop(Iop_Shr32,
2087 mkexpr(rMt),
2088 unop(Iop_32to8,
2089 binop(Iop_And32,
2090 binop(Iop_Sub32,
2091 mkexpr(amtT),
2092 mkU32(1)
2093 ),
2094 mkU32(31)
2095 )
2096 )
2097 ),
2098 mkU32(1)
2099 )
2100 )
2101 );
2102 }
2103 assign(
2104 *res,
2105 IRExpr_Mux0X(
2106 unop(Iop_32to8, mkexpr(amt5T)), mkexpr(rMt),
2107 binop(Iop_Or32,
2108 binop(Iop_Shr32,
2109 mkexpr(rMt),
2110 unop(Iop_32to8, mkexpr(amt5T))
2111 ),
2112 binop(Iop_Shl32,
2113 mkexpr(rMt),
2114 unop(Iop_32to8,
2115 binop(Iop_Sub32, mkU32(32), mkexpr(amt5T))
2116 )
2117 )
2118 )
2119 )
2120 );
2121 DIS(buf, "r%u, ROR r#%u", rM, rS);
2122}
2123
2124
2125/* Generate an expression corresponding to the immediate-shift case of
2126 a shifter operand. This is used both for ARM and Thumb2.
2127
2128 Bind it to a temporary, and return that via *res. If newC is
2129 non-NULL, also compute a value for the shifter's carry out (in the
2130 LSB of a word), bind it to a temporary, and return that via *shco.
2131
2132 Generates GETs from the guest state and is therefore not safe to
2133 use once we start doing PUTs to it, for any given instruction.
2134
2135 'how' is encoded thusly:
2136 00b LSL, 01b LSR, 10b ASR, 11b ROR
2137 Most but not all ARM and Thumb integer insns use this encoding.
2138 Be careful to ensure the right value is passed here.
2139*/
2140static void compute_result_and_C_after_shift_by_imm5 (
2141 /*OUT*/HChar* buf,
2142 /*OUT*/IRTemp* res,
2143 /*OUT*/IRTemp* newC,
2144 IRTemp rMt, /* reg to shift */
2145 UInt how, /* what kind of shift */
2146 UInt shift_amt, /* shift amount (0..31) */
2147 UInt rM /* only for debug printing */
2148 )
2149{
2150 vassert(shift_amt < 32);
2151 vassert(how < 4);
2152
2153 switch (how) {
2154
2155 case 0:
2156 compute_result_and_C_after_LSL_by_imm5(
2157 buf, res, newC, rMt, shift_amt, rM
2158 );
2159 break;
2160
2161 case 1:
2162 compute_result_and_C_after_LSR_by_imm5(
2163 buf, res, newC, rMt, shift_amt, rM
2164 );
2165 break;
2166
2167 case 2:
2168 compute_result_and_C_after_ASR_by_imm5(
2169 buf, res, newC, rMt, shift_amt, rM
2170 );
2171 break;
2172
2173 case 3:
2174 if (shift_amt == 0) {
2175 IRTemp oldcT = newTemp(Ity_I32);
2176 // rotate right 1 bit through carry (?)
2177 // RRX -- described at ARM ARM A5-17
2178 // res = (oldC << 31) | (Rm >>u 1)
2179 // newC = Rm[0]
2180 if (newC) {
2181 assign( *newC,
2182 binop(Iop_And32, mkexpr(rMt), mkU32(1)));
2183 }
2184 assign( oldcT, mk_armg_calculate_flag_c() );
2185 assign( *res,
2186 binop(Iop_Or32,
2187 binop(Iop_Shl32, mkexpr(oldcT), mkU8(31)),
2188 binop(Iop_Shr32, mkexpr(rMt), mkU8(1))) );
2189 DIS(buf, "r%u, RRX", rM);
2190 } else {
2191 // rotate right in range 1..31
2192 // res = Rm `ror` shift_amt
2193 // newC = Rm[shift_amt - 1]
2194 vassert(shift_amt >= 1 && shift_amt <= 31);
2195 if (newC) {
2196 assign( *newC,
2197 binop(Iop_And32,
2198 binop(Iop_Shr32, mkexpr(rMt),
2199 mkU8(shift_amt - 1)),
2200 mkU32(1)));
2201 }
2202 assign( *res,
2203 binop(Iop_Or32,
2204 binop(Iop_Shr32, mkexpr(rMt), mkU8(shift_amt)),
2205 binop(Iop_Shl32, mkexpr(rMt),
2206 mkU8(32-shift_amt))));
2207 DIS(buf, "r%u, ROR #%u", rM, shift_amt);
2208 }
2209 break;
2210
2211 default:
2212 /*NOTREACHED*/
2213 vassert(0);
2214 }
2215}
2216
2217
2218/* Generate an expression corresponding to the register-shift case of
2219 a shifter operand. This is used both for ARM and Thumb2.
2220
2221 Bind it to a temporary, and return that via *res. If newC is
2222 non-NULL, also compute a value for the shifter's carry out (in the
2223 LSB of a word), bind it to a temporary, and return that via *shco.
2224
2225 Generates GETs from the guest state and is therefore not safe to
2226 use once we start doing PUTs to it, for any given instruction.
2227
2228 'how' is encoded thusly:
2229 00b LSL, 01b LSR, 10b ASR, 11b ROR
2230 Most but not all ARM and Thumb integer insns use this encoding.
2231 Be careful to ensure the right value is passed here.
2232*/
2233static void compute_result_and_C_after_shift_by_reg (
2234 /*OUT*/HChar* buf,
2235 /*OUT*/IRTemp* res,
2236 /*OUT*/IRTemp* newC,
2237 IRTemp rMt, /* reg to shift */
2238 UInt how, /* what kind of shift */
2239 IRTemp rSt, /* shift amount */
2240 UInt rM, /* only for debug printing */
2241 UInt rS /* only for debug printing */
2242 )
2243{
2244 vassert(how < 4);
2245 switch (how) {
2246 case 0: { /* LSL */
2247 compute_result_and_C_after_LSL_by_reg(
2248 buf, res, newC, rMt, rSt, rM, rS
2249 );
2250 break;
2251 }
2252 case 1: { /* LSR */
2253 compute_result_and_C_after_LSR_by_reg(
2254 buf, res, newC, rMt, rSt, rM, rS
2255 );
2256 break;
2257 }
2258 case 2: { /* ASR */
2259 compute_result_and_C_after_ASR_by_reg(
2260 buf, res, newC, rMt, rSt, rM, rS
2261 );
2262 break;
2263 }
2264 case 3: { /* ROR */
2265 compute_result_and_C_after_ROR_by_reg(
2266 buf, res, newC, rMt, rSt, rM, rS
2267 );
2268 break;
2269 }
2270 default:
2271 /*NOTREACHED*/
2272 vassert(0);
2273 }
2274}
2275
2276
sewardj6c299f32009-12-31 18:00:12 +00002277/* Generate an expression corresponding to a shifter_operand, bind it
2278 to a temporary, and return that via *shop. If shco is non-NULL,
2279 also compute a value for the shifter's carry out (in the LSB of a
2280 word), bind it to a temporary, and return that via *shco.
2281
2282 If for some reason we can't come up with a shifter operand (missing
2283 case? not really a shifter operand?) return False.
sewardjd2664472010-08-22 12:44:20 +00002284
2285 Generates GETs from the guest state and is therefore not safe to
2286 use once we start doing PUTs to it, for any given instruction.
2287
2288 For ARM insns only; not for Thumb.
sewardj6c299f32009-12-31 18:00:12 +00002289*/
2290static Bool mk_shifter_operand ( UInt insn_25, UInt insn_11_0,
2291 /*OUT*/IRTemp* shop,
2292 /*OUT*/IRTemp* shco,
2293 /*OUT*/HChar* buf )
2294{
2295 UInt insn_4 = (insn_11_0 >> 4) & 1;
2296 UInt insn_7 = (insn_11_0 >> 7) & 1;
2297 vassert(insn_25 <= 0x1);
2298 vassert(insn_11_0 <= 0xFFF);
2299
2300 vassert(shop && *shop == IRTemp_INVALID);
2301 *shop = newTemp(Ity_I32);
2302
2303 if (shco) {
2304 vassert(*shco == IRTemp_INVALID);
2305 *shco = newTemp(Ity_I32);
cerionb85e8bb2005-02-16 08:54:33 +00002306 }
cerion060c5422004-12-10 15:28:43 +00002307
sewardj6c299f32009-12-31 18:00:12 +00002308 /* 32-bit immediate */
2309
2310 if (insn_25 == 1) {
2311 /* immediate: (7:0) rotated right by 2 * (11:8) */
2312 UInt imm = (insn_11_0 >> 0) & 0xFF;
2313 UInt rot = 2 * ((insn_11_0 >> 8) & 0xF);
2314 vassert(rot <= 30);
2315 imm = ROR32(imm, rot);
2316 if (shco) {
2317 if (rot == 0) {
2318 assign( *shco, mk_armg_calculate_flag_c() );
2319 } else {
2320 assign( *shco, mkU32( (imm >> 31) & 1 ) );
2321 }
cerionb85e8bb2005-02-16 08:54:33 +00002322 }
sewardj6c299f32009-12-31 18:00:12 +00002323 DIS(buf, "#0x%x", imm);
2324 assign( *shop, mkU32(imm) );
2325 return True;
cerionb85e8bb2005-02-16 08:54:33 +00002326 }
sewardj6c299f32009-12-31 18:00:12 +00002327
2328 /* Shift/rotate by immediate */
2329
2330 if (insn_25 == 0 && insn_4 == 0) {
2331 /* Rm (3:0) shifted (6:5) by immediate (11:7) */
2332 UInt shift_amt = (insn_11_0 >> 7) & 0x1F;
2333 UInt rM = (insn_11_0 >> 0) & 0xF;
2334 UInt how = (insn_11_0 >> 5) & 3;
2335 /* how: 00 = Shl, 01 = Shr, 10 = Sar, 11 = Ror */
2336 IRTemp rMt = newTemp(Ity_I32);
sewardjd2664472010-08-22 12:44:20 +00002337 assign(rMt, getIRegA(rM));
sewardj6c299f32009-12-31 18:00:12 +00002338
2339 vassert(shift_amt <= 31);
2340
sewardjd2664472010-08-22 12:44:20 +00002341 compute_result_and_C_after_shift_by_imm5(
2342 buf, shop, shco, rMt, how, shift_amt, rM
2343 );
2344 return True;
cerionb85e8bb2005-02-16 08:54:33 +00002345 }
sewardj6c299f32009-12-31 18:00:12 +00002346
2347 /* Shift/rotate by register */
2348 if (insn_25 == 0 && insn_4 == 1) {
2349 /* Rm (3:0) shifted (6:5) by Rs (11:8) */
2350 UInt rM = (insn_11_0 >> 0) & 0xF;
2351 UInt rS = (insn_11_0 >> 8) & 0xF;
2352 UInt how = (insn_11_0 >> 5) & 3;
2353 /* how: 00 = Shl, 01 = Shr, 10 = Sar, 11 = Ror */
2354 IRTemp rMt = newTemp(Ity_I32);
2355 IRTemp rSt = newTemp(Ity_I32);
2356
2357 if (insn_7 == 1)
2358 return False; /* not really a shifter operand */
2359
sewardjd2664472010-08-22 12:44:20 +00002360 assign(rMt, getIRegA(rM));
2361 assign(rSt, getIRegA(rS));
sewardj6c299f32009-12-31 18:00:12 +00002362
sewardjd2664472010-08-22 12:44:20 +00002363 compute_result_and_C_after_shift_by_reg(
2364 buf, shop, shco, rMt, how, rSt, rM, rS
2365 );
2366 return True;
sewardj6c299f32009-12-31 18:00:12 +00002367 }
2368
2369 vex_printf("mk_shifter_operand(0x%x,0x%x)\n", insn_25, insn_11_0 );
2370 return False;
cerion060c5422004-12-10 15:28:43 +00002371}
cerionf7da63d2004-12-09 19:04:57 +00002372
2373
sewardjd2664472010-08-22 12:44:20 +00002374/* ARM only */
sewardj6c299f32009-12-31 18:00:12 +00002375static
2376IRExpr* mk_EA_reg_plusminus_imm12 ( UInt rN, UInt bU, UInt imm12,
2377 /*OUT*/HChar* buf )
cerion060c5422004-12-10 15:28:43 +00002378{
sewardj6c299f32009-12-31 18:00:12 +00002379 vassert(rN < 16);
2380 vassert(bU < 2);
2381 vassert(imm12 < 0x1000);
2382 UChar opChar = bU == 1 ? '+' : '-';
2383 DIS(buf, "[r%u, #%c%u]", rN, opChar, imm12);
2384 return
2385 binop( (bU == 1 ? Iop_Add32 : Iop_Sub32),
sewardjd2664472010-08-22 12:44:20 +00002386 getIRegA(rN),
sewardj6c299f32009-12-31 18:00:12 +00002387 mkU32(imm12) );
cerionf7da63d2004-12-09 19:04:57 +00002388}
cerionc60c01e2004-12-02 20:19:22 +00002389
cerionc60c01e2004-12-02 20:19:22 +00002390
sewardjd2664472010-08-22 12:44:20 +00002391/* ARM only.
2392 NB: This is "DecodeImmShift" in newer versions of the the ARM ARM.
sewardj80bea7b2010-01-09 11:43:21 +00002393*/
ceriona70a37b2004-12-03 18:54:08 +00002394static
sewardj6c299f32009-12-31 18:00:12 +00002395IRExpr* mk_EA_reg_plusminus_shifted_reg ( UInt rN, UInt bU, UInt rM,
2396 UInt sh2, UInt imm5,
2397 /*OUT*/HChar* buf )
ceriona70a37b2004-12-03 18:54:08 +00002398{
sewardj6c299f32009-12-31 18:00:12 +00002399 vassert(rN < 16);
2400 vassert(bU < 2);
2401 vassert(rM < 16);
2402 vassert(sh2 < 4);
2403 vassert(imm5 < 32);
2404 UChar opChar = bU == 1 ? '+' : '-';
2405 IRExpr* index = NULL;
2406 switch (sh2) {
2407 case 0: /* LSL */
2408 /* imm5 can be in the range 0 .. 31 inclusive. */
sewardjd2664472010-08-22 12:44:20 +00002409 index = binop(Iop_Shl32, getIRegA(rM), mkU8(imm5));
sewardj6c299f32009-12-31 18:00:12 +00002410 DIS(buf, "[r%u, %c r%u LSL #%u]", rN, opChar, rM, imm5);
cerionb85e8bb2005-02-16 08:54:33 +00002411 break;
sewardj6c299f32009-12-31 18:00:12 +00002412 case 1: /* LSR */
2413 if (imm5 == 0) {
2414 index = mkU32(0);
2415 vassert(0); // ATC
2416 } else {
sewardjd2664472010-08-22 12:44:20 +00002417 index = binop(Iop_Shr32, getIRegA(rM), mkU8(imm5));
sewardj6c299f32009-12-31 18:00:12 +00002418 }
2419 DIS(buf, "[r%u, %cr%u, LSR #%u]",
2420 rN, opChar, rM, imm5 == 0 ? 32 : imm5);
cerionb85e8bb2005-02-16 08:54:33 +00002421 break;
sewardj6c299f32009-12-31 18:00:12 +00002422 case 2: /* ASR */
2423 /* Doesn't this just mean that the behaviour with imm5 == 0
2424 is the same as if it had been 31 ? */
2425 if (imm5 == 0) {
sewardjd2664472010-08-22 12:44:20 +00002426 index = binop(Iop_Sar32, getIRegA(rM), mkU8(31));
sewardj6c299f32009-12-31 18:00:12 +00002427 vassert(0); // ATC
2428 } else {
sewardjd2664472010-08-22 12:44:20 +00002429 index = binop(Iop_Sar32, getIRegA(rM), mkU8(imm5));
sewardj6c299f32009-12-31 18:00:12 +00002430 }
2431 DIS(buf, "[r%u, %cr%u, ASR #%u]",
2432 rN, opChar, rM, imm5 == 0 ? 32 : imm5);
cerionb85e8bb2005-02-16 08:54:33 +00002433 break;
sewardj6c299f32009-12-31 18:00:12 +00002434 case 3: /* ROR or RRX */
2435 if (imm5 == 0) {
2436 IRTemp rmT = newTemp(Ity_I32);
2437 IRTemp cflagT = newTemp(Ity_I32);
sewardjd2664472010-08-22 12:44:20 +00002438 assign(rmT, getIRegA(rM));
sewardj80bea7b2010-01-09 11:43:21 +00002439 assign(cflagT, mk_armg_calculate_flag_c());
sewardj6c299f32009-12-31 18:00:12 +00002440 index = binop(Iop_Or32,
2441 binop(Iop_Shl32, mkexpr(cflagT), mkU8(31)),
2442 binop(Iop_Shr32, mkexpr(rmT), mkU8(1)));
sewardj6c299f32009-12-31 18:00:12 +00002443 DIS(buf, "[r%u, %cr%u, RRX]", rN, opChar, rM);
2444 } else {
2445 IRTemp rmT = newTemp(Ity_I32);
sewardjd2664472010-08-22 12:44:20 +00002446 assign(rmT, getIRegA(rM));
sewardj6c299f32009-12-31 18:00:12 +00002447 vassert(imm5 >= 1 && imm5 <= 31);
2448 index = binop(Iop_Or32,
2449 binop(Iop_Shl32, mkexpr(rmT), mkU8(32-imm5)),
2450 binop(Iop_Shr32, mkexpr(rmT), mkU8(imm5)));
sewardj6c299f32009-12-31 18:00:12 +00002451 DIS(buf, "[r%u, %cr%u, ROR #%u]", rN, opChar, rM, imm5);
2452 }
2453 break;
cerionb85e8bb2005-02-16 08:54:33 +00002454 default:
sewardj6c299f32009-12-31 18:00:12 +00002455 vassert(0);
cerionb85e8bb2005-02-16 08:54:33 +00002456 }
sewardj6c299f32009-12-31 18:00:12 +00002457 vassert(index);
2458 return binop(bU == 1 ? Iop_Add32 : Iop_Sub32,
sewardjd2664472010-08-22 12:44:20 +00002459 getIRegA(rN), index);
cerionc60c01e2004-12-02 20:19:22 +00002460}
2461
2462
sewardjd2664472010-08-22 12:44:20 +00002463/* ARM only */
sewardj6c299f32009-12-31 18:00:12 +00002464static
2465IRExpr* mk_EA_reg_plusminus_imm8 ( UInt rN, UInt bU, UInt imm8,
2466 /*OUT*/HChar* buf )
cerionf7da63d2004-12-09 19:04:57 +00002467{
sewardj6c299f32009-12-31 18:00:12 +00002468 vassert(rN < 16);
2469 vassert(bU < 2);
2470 vassert(imm8 < 0x100);
2471 UChar opChar = bU == 1 ? '+' : '-';
2472 DIS(buf, "[r%u, #%c%u]", rN, opChar, imm8);
2473 return
2474 binop( (bU == 1 ? Iop_Add32 : Iop_Sub32),
sewardjd2664472010-08-22 12:44:20 +00002475 getIRegA(rN),
sewardj6c299f32009-12-31 18:00:12 +00002476 mkU32(imm8) );
cerionc60c01e2004-12-02 20:19:22 +00002477}
2478
2479
sewardjd2664472010-08-22 12:44:20 +00002480/* ARM only */
cerionc60c01e2004-12-02 20:19:22 +00002481static
sewardj6c299f32009-12-31 18:00:12 +00002482IRExpr* mk_EA_reg_plusminus_reg ( UInt rN, UInt bU, UInt rM,
2483 /*OUT*/HChar* buf )
cerionc60c01e2004-12-02 20:19:22 +00002484{
sewardj6c299f32009-12-31 18:00:12 +00002485 vassert(rN < 16);
2486 vassert(bU < 2);
2487 vassert(rM < 16);
2488 UChar opChar = bU == 1 ? '+' : '-';
sewardjd2664472010-08-22 12:44:20 +00002489 IRExpr* index = getIRegA(rM);
sewardj6c299f32009-12-31 18:00:12 +00002490 DIS(buf, "[r%u, %c r%u]", rN, opChar, rM);
2491 return binop(bU == 1 ? Iop_Add32 : Iop_Sub32,
sewardjd2664472010-08-22 12:44:20 +00002492 getIRegA(rN), index);
cerionc60c01e2004-12-02 20:19:22 +00002493}
2494
2495
sewardj6c299f32009-12-31 18:00:12 +00002496/* irRes :: Ity_I32 holds a floating point comparison result encoded
2497 as an IRCmpF64Result. Generate code to convert it to an
2498 ARM-encoded (N,Z,C,V) group in the lowest 4 bits of an I32 value.
2499 Assign a new temp to hold that value, and return the temp. */
ceriona70a37b2004-12-03 18:54:08 +00002500static
sewardj6c299f32009-12-31 18:00:12 +00002501IRTemp mk_convert_IRCmpF64Result_to_NZCV ( IRTemp irRes )
ceriona70a37b2004-12-03 18:54:08 +00002502{
sewardj6c299f32009-12-31 18:00:12 +00002503 IRTemp ix = newTemp(Ity_I32);
2504 IRTemp termL = newTemp(Ity_I32);
2505 IRTemp termR = newTemp(Ity_I32);
2506 IRTemp nzcv = newTemp(Ity_I32);
ceriona70a37b2004-12-03 18:54:08 +00002507
sewardj6c299f32009-12-31 18:00:12 +00002508 /* This is where the fun starts. We have to convert 'irRes' from
2509 an IR-convention return result (IRCmpF64Result) to an
2510 ARM-encoded (N,Z,C,V) group. The final result is in the bottom
2511 4 bits of 'nzcv'. */
2512 /* Map compare result from IR to ARM(nzcv) */
2513 /*
2514 FP cmp result | IR | ARM(nzcv)
2515 --------------------------------
2516 UN 0x45 0011
2517 LT 0x01 1000
2518 GT 0x00 0010
2519 EQ 0x40 0110
2520 */
2521 /* Now since you're probably wondering WTF ..
cerion397f9e52004-12-15 13:04:06 +00002522
sewardj6c299f32009-12-31 18:00:12 +00002523 ix fishes the useful bits out of the IR value, bits 6 and 0, and
2524 places them side by side, giving a number which is 0, 1, 2 or 3.
cerion397f9e52004-12-15 13:04:06 +00002525
sewardj6c299f32009-12-31 18:00:12 +00002526 termL is a sequence cooked up by GNU superopt. It converts ix
2527 into an almost correct value NZCV value (incredibly), except
2528 for the case of UN, where it produces 0100 instead of the
2529 required 0011.
cerion397f9e52004-12-15 13:04:06 +00002530
sewardj6c299f32009-12-31 18:00:12 +00002531 termR is therefore a correction term, also computed from ix. It
2532 is 1 in the UN case and 0 for LT, GT and UN. Hence, to get
2533 the final correct value, we subtract termR from termL.
ceriona70a37b2004-12-03 18:54:08 +00002534
sewardj6c299f32009-12-31 18:00:12 +00002535 Don't take my word for it. There's a test program at the bottom
2536 of this file, to try this out with.
2537 */
2538 assign(
2539 ix,
2540 binop(Iop_Or32,
2541 binop(Iop_And32,
2542 binop(Iop_Shr32, mkexpr(irRes), mkU8(5)),
2543 mkU32(3)),
2544 binop(Iop_And32, mkexpr(irRes), mkU32(1))));
ceriona70a37b2004-12-03 18:54:08 +00002545
sewardj6c299f32009-12-31 18:00:12 +00002546 assign(
2547 termL,
2548 binop(Iop_Add32,
2549 binop(Iop_Shr32,
2550 binop(Iop_Sub32,
2551 binop(Iop_Shl32,
2552 binop(Iop_Xor32, mkexpr(ix), mkU32(1)),
2553 mkU8(30)),
2554 mkU32(1)),
2555 mkU8(29)),
2556 mkU32(1)));
ceriona70a37b2004-12-03 18:54:08 +00002557
sewardj6c299f32009-12-31 18:00:12 +00002558 assign(
2559 termR,
2560 binop(Iop_And32,
2561 binop(Iop_And32,
2562 mkexpr(ix),
2563 binop(Iop_Shr32, mkexpr(ix), mkU8(1))),
2564 mkU32(1)));
cerionf7da63d2004-12-09 19:04:57 +00002565
sewardj6c299f32009-12-31 18:00:12 +00002566 assign(nzcv, binop(Iop_Sub32, mkexpr(termL), mkexpr(termR)));
2567 return nzcv;
ceriona70a37b2004-12-03 18:54:08 +00002568}
2569
2570
sewardjd2664472010-08-22 12:44:20 +00002571/* Thumb32 only. This is "ThumbExpandImm" in the ARM ARM. If
2572 updatesC is non-NULL, a boolean is written to it indicating whether
2573 or not the C flag is updated, as per ARM ARM "ThumbExpandImm_C".
2574*/
2575static UInt thumbExpandImm ( Bool* updatesC,
2576 UInt imm1, UInt imm3, UInt imm8 )
2577{
2578 vassert(imm1 < (1<<1));
2579 vassert(imm3 < (1<<3));
2580 vassert(imm8 < (1<<8));
2581 UInt i_imm3_a = (imm1 << 4) | (imm3 << 1) | ((imm8 >> 7) & 1);
2582 UInt abcdefgh = imm8;
2583 UInt lbcdefgh = imm8 | 0x80;
2584 if (updatesC) {
2585 *updatesC = i_imm3_a >= 8;
2586 }
2587 switch (i_imm3_a) {
2588 case 0: case 1:
2589 return abcdefgh;
2590 case 2: case 3:
2591 return (abcdefgh << 16) | abcdefgh;
2592 case 4: case 5:
2593 return (abcdefgh << 24) | (abcdefgh << 8);
2594 case 6: case 7:
2595 return (abcdefgh << 24) | (abcdefgh << 16)
2596 | (abcdefgh << 8) | abcdefgh;
2597 case 8 ... 31:
2598 return lbcdefgh << (32 - i_imm3_a);
2599 default:
2600 break;
2601 }
2602 /*NOTREACHED*/vassert(0);
2603}
2604
2605
2606/* Version of thumbExpandImm where we simply feed it the
2607 instruction halfwords (the lowest addressed one is I0). */
2608static UInt thumbExpandImm_from_I0_I1 ( Bool* updatesC,
2609 UShort i0s, UShort i1s )
2610{
2611 UInt i0 = (UInt)i0s;
2612 UInt i1 = (UInt)i1s;
2613 UInt imm1 = SLICE_UInt(i0,10,10);
2614 UInt imm3 = SLICE_UInt(i1,14,12);
2615 UInt imm8 = SLICE_UInt(i1,7,0);
2616 return thumbExpandImm(updatesC, imm1, imm3, imm8);
2617}
2618
2619
2620/* Thumb16 only. Given the firstcond and mask fields from an IT
2621 instruction, compute the 32-bit ITSTATE value implied, as described
2622 in libvex_guest_arm.h. This is not the ARM ARM representation.
2623 Also produce the t/e chars for the 2nd, 3rd, 4th insns, for
2624 disassembly printing. Returns False if firstcond or mask
2625 denote something invalid.
2626
2627 The number and conditions for the instructions to be
2628 conditionalised depend on firstcond and mask:
2629
2630 mask cond 1 cond 2 cond 3 cond 4
2631
2632 1000 fc[3:0]
2633 x100 fc[3:0] fc[3:1]:x
2634 xy10 fc[3:0] fc[3:1]:x fc[3:1]:y
2635 xyz1 fc[3:0] fc[3:1]:x fc[3:1]:y fc[3:1]:z
2636
2637 The condition fields are assembled in *itstate backwards (cond 4 at
2638 the top, cond 1 at the bottom). Conditions are << 4'd and then
2639 ^0xE'd, and those fields that correspond to instructions in the IT
2640 block are tagged with a 1 bit.
2641*/
2642static Bool compute_ITSTATE ( /*OUT*/UInt* itstate,
2643 /*OUT*/UChar* ch1,
2644 /*OUT*/UChar* ch2,
2645 /*OUT*/UChar* ch3,
2646 UInt firstcond, UInt mask )
2647{
2648 vassert(firstcond <= 0xF);
2649 vassert(mask <= 0xF);
2650 *itstate = 0;
2651 *ch1 = *ch2 = *ch3 = '.';
2652 if (mask == 0)
2653 return False; /* the logic below actually ensures this anyway,
2654 but clearer to make it explicit. */
2655 if (firstcond == 0xF)
2656 return False; /* NV is not allowed */
2657 if (firstcond == 0xE && popcount32(mask) != 1)
2658 return False; /* if firstcond is AL then all the rest must be too */
2659
2660 UInt m3 = (mask >> 3) & 1;
2661 UInt m2 = (mask >> 2) & 1;
2662 UInt m1 = (mask >> 1) & 1;
2663 UInt m0 = (mask >> 0) & 1;
2664
2665 UInt fc = (firstcond << 4) | 1/*in-IT-block*/;
2666 UInt ni = (0xE/*AL*/ << 4) | 0/*not-in-IT-block*/;
2667
2668 if (m3 == 1 && (m2|m1|m0) == 0) {
2669 *itstate = (ni << 24) | (ni << 16) | (ni << 8) | fc;
2670 *itstate ^= 0xE0E0E0E0;
2671 return True;
2672 }
2673
2674 if (m2 == 1 && (m1|m0) == 0) {
2675 *itstate = (ni << 24) | (ni << 16) | (setbit32(fc, 4, m3) << 8) | fc;
2676 *itstate ^= 0xE0E0E0E0;
2677 *ch1 = m3 == (firstcond & 1) ? 't' : 'e';
2678 return True;
2679 }
2680
2681 if (m1 == 1 && m0 == 0) {
2682 *itstate = (ni << 24)
2683 | (setbit32(fc, 4, m2) << 16)
2684 | (setbit32(fc, 4, m3) << 8) | fc;
2685 *itstate ^= 0xE0E0E0E0;
2686 *ch1 = m3 == (firstcond & 1) ? 't' : 'e';
2687 *ch2 = m2 == (firstcond & 1) ? 't' : 'e';
2688 return True;
2689 }
2690
2691 if (m0 == 1) {
2692 *itstate = (setbit32(fc, 4, m1) << 24)
2693 | (setbit32(fc, 4, m2) << 16)
2694 | (setbit32(fc, 4, m3) << 8) | fc;
2695 *itstate ^= 0xE0E0E0E0;
2696 *ch1 = m3 == (firstcond & 1) ? 't' : 'e';
2697 *ch2 = m2 == (firstcond & 1) ? 't' : 'e';
2698 *ch3 = m1 == (firstcond & 1) ? 't' : 'e';
2699 return True;
2700 }
2701
2702 return False;
2703}
2704
sewardj677e5af2010-09-02 21:02:47 +00002705
2706/* Generate IR to do 32-bit bit reversal, a la Hacker's Delight
2707 Chapter 7 Section 1. */
2708static IRTemp gen_BITREV ( IRTemp x0 )
2709{
2710 IRTemp x1 = newTemp(Ity_I32);
2711 IRTemp x2 = newTemp(Ity_I32);
2712 IRTemp x3 = newTemp(Ity_I32);
2713 IRTemp x4 = newTemp(Ity_I32);
2714 IRTemp x5 = newTemp(Ity_I32);
2715 UInt c1 = 0x55555555;
2716 UInt c2 = 0x33333333;
2717 UInt c3 = 0x0F0F0F0F;
2718 UInt c4 = 0x00FF00FF;
2719 UInt c5 = 0x0000FFFF;
2720 assign(x1,
2721 binop(Iop_Or32,
2722 binop(Iop_Shl32,
2723 binop(Iop_And32, mkexpr(x0), mkU32(c1)),
2724 mkU8(1)),
2725 binop(Iop_Shr32,
2726 binop(Iop_And32, mkexpr(x0), mkU32(~c1)),
2727 mkU8(1))
2728 ));
2729 assign(x2,
2730 binop(Iop_Or32,
2731 binop(Iop_Shl32,
2732 binop(Iop_And32, mkexpr(x1), mkU32(c2)),
2733 mkU8(2)),
2734 binop(Iop_Shr32,
2735 binop(Iop_And32, mkexpr(x1), mkU32(~c2)),
2736 mkU8(2))
2737 ));
2738 assign(x3,
2739 binop(Iop_Or32,
2740 binop(Iop_Shl32,
2741 binop(Iop_And32, mkexpr(x2), mkU32(c3)),
2742 mkU8(4)),
2743 binop(Iop_Shr32,
2744 binop(Iop_And32, mkexpr(x2), mkU32(~c3)),
2745 mkU8(4))
2746 ));
2747 assign(x4,
2748 binop(Iop_Or32,
2749 binop(Iop_Shl32,
2750 binop(Iop_And32, mkexpr(x3), mkU32(c4)),
2751 mkU8(8)),
2752 binop(Iop_Shr32,
2753 binop(Iop_And32, mkexpr(x3), mkU32(~c4)),
2754 mkU8(8))
2755 ));
2756 assign(x5,
2757 binop(Iop_Or32,
2758 binop(Iop_Shl32,
2759 binop(Iop_And32, mkexpr(x4), mkU32(c5)),
2760 mkU8(16)),
2761 binop(Iop_Shr32,
2762 binop(Iop_And32, mkexpr(x4), mkU32(~c5)),
2763 mkU8(16))
2764 ));
2765 return x5;
2766}
2767
2768
sewardj27312d32010-09-26 00:48:41 +00002769/* Generate IR to do rearrange bytes 3:2:1:0 in a word in to the order
2770 0:1:2:3 (aka byte-swap). */
2771static IRTemp gen_REV ( IRTemp arg )
2772{
2773 IRTemp res = newTemp(Ity_I32);
2774 assign(res,
2775 binop(Iop_Or32,
2776 binop(Iop_Shl32, mkexpr(arg), mkU8(24)),
2777 binop(Iop_Or32,
2778 binop(Iop_And32, binop(Iop_Shl32, mkexpr(arg), mkU8(8)),
2779 mkU32(0x00FF0000)),
2780 binop(Iop_Or32,
2781 binop(Iop_And32, binop(Iop_Shr32, mkexpr(arg), mkU8(8)),
2782 mkU32(0x0000FF00)),
2783 binop(Iop_And32, binop(Iop_Shr32, mkexpr(arg), mkU8(24)),
2784 mkU32(0x000000FF) )
2785 ))));
2786 return res;
2787}
2788
2789
2790/* Generate IR to do rearrange bytes 3:2:1:0 in a word in to the order
2791 2:3:0:1 (swap within lo and hi halves). */
2792static IRTemp gen_REV16 ( IRTemp arg )
2793{
2794 IRTemp res = newTemp(Ity_I32);
2795 assign(res,
2796 binop(Iop_Or32,
2797 binop(Iop_And32,
2798 binop(Iop_Shl32, mkexpr(arg), mkU8(8)),
2799 mkU32(0xFF00FF00)),
2800 binop(Iop_And32,
2801 binop(Iop_Shr32, mkexpr(arg), mkU8(8)),
2802 mkU32(0x00FF00FF))));
2803 return res;
2804}
2805
2806
sewardjd2664472010-08-22 12:44:20 +00002807/*------------------------------------------------------------*/
2808/*--- Advanced SIMD (NEON) instructions ---*/
2809/*------------------------------------------------------------*/
2810
2811/*------------------------------------------------------------*/
2812/*--- NEON data processing ---*/
2813/*------------------------------------------------------------*/
2814
2815/* For all NEON DP ops, we use the normal scheme to handle conditional
2816 writes to registers -- pass in condT and hand that on to the
2817 put*Reg functions. In ARM mode condT is always IRTemp_INVALID
2818 since NEON is unconditional for ARM. In Thumb mode condT is
2819 derived from the ITSTATE shift register in the normal way. */
2820
2821static
2822UInt get_neon_d_regno(UInt theInstr)
2823{
2824 UInt x = ((theInstr >> 18) & 0x10) | ((theInstr >> 12) & 0xF);
2825 if (theInstr & 0x40) {
2826 if (x & 1) {
2827 x = x + 0x100;
2828 } else {
2829 x = x >> 1;
2830 }
2831 }
2832 return x;
2833}
2834
2835static
2836UInt get_neon_n_regno(UInt theInstr)
2837{
2838 UInt x = ((theInstr >> 3) & 0x10) | ((theInstr >> 16) & 0xF);
2839 if (theInstr & 0x40) {
2840 if (x & 1) {
2841 x = x + 0x100;
2842 } else {
2843 x = x >> 1;
2844 }
2845 }
2846 return x;
2847}
2848
2849static
2850UInt get_neon_m_regno(UInt theInstr)
2851{
2852 UInt x = ((theInstr >> 1) & 0x10) | (theInstr & 0xF);
2853 if (theInstr & 0x40) {
2854 if (x & 1) {
2855 x = x + 0x100;
2856 } else {
2857 x = x >> 1;
2858 }
2859 }
2860 return x;
2861}
2862
2863static
2864Bool dis_neon_vext ( UInt theInstr, IRTemp condT )
2865{
2866 UInt dreg = get_neon_d_regno(theInstr);
2867 UInt mreg = get_neon_m_regno(theInstr);
2868 UInt nreg = get_neon_n_regno(theInstr);
2869 UInt imm4 = (theInstr >> 8) & 0xf;
2870 UInt Q = (theInstr >> 6) & 1;
2871 HChar reg_t = Q ? 'q' : 'd';
2872
2873 if (Q) {
2874 putQReg(dreg, triop(Iop_ExtractV128, getQReg(nreg),
2875 getQReg(mreg), mkU8(imm4)), condT);
2876 } else {
2877 putDRegI64(dreg, triop(Iop_Extract64, getDRegI64(nreg),
2878 getDRegI64(mreg), mkU8(imm4)), condT);
2879 }
2880 DIP("vext.8 %c%d, %c%d, %c%d, #%d\n", reg_t, dreg, reg_t, nreg,
2881 reg_t, mreg, imm4);
2882 return True;
2883}
2884
2885/* VTBL, VTBX */
2886static
2887Bool dis_neon_vtb ( UInt theInstr, IRTemp condT )
2888{
2889 UInt op = (theInstr >> 6) & 1;
2890 UInt dreg = get_neon_d_regno(theInstr & ~(1 << 6));
2891 UInt nreg = get_neon_n_regno(theInstr & ~(1 << 6));
2892 UInt mreg = get_neon_m_regno(theInstr & ~(1 << 6));
2893 UInt len = (theInstr >> 8) & 3;
2894 Int i;
2895 IROp cmp;
2896 ULong imm;
2897 IRTemp arg_l;
2898 IRTemp old_mask, new_mask, cur_mask;
2899 IRTemp old_res, new_res;
2900 IRTemp old_arg, new_arg;
2901
2902 if (dreg >= 0x100 || mreg >= 0x100 || nreg >= 0x100)
2903 return False;
2904 if (nreg + len > 31)
2905 return False;
2906
2907 cmp = Iop_CmpGT8Ux8;
2908
2909 old_mask = newTemp(Ity_I64);
2910 old_res = newTemp(Ity_I64);
2911 old_arg = newTemp(Ity_I64);
2912 assign(old_mask, mkU64(0));
2913 assign(old_res, mkU64(0));
2914 assign(old_arg, getDRegI64(mreg));
2915 imm = 8;
2916 imm = (imm << 8) | imm;
2917 imm = (imm << 16) | imm;
2918 imm = (imm << 32) | imm;
2919
2920 for (i = 0; i <= len; i++) {
2921 arg_l = newTemp(Ity_I64);
2922 new_mask = newTemp(Ity_I64);
2923 cur_mask = newTemp(Ity_I64);
2924 new_res = newTemp(Ity_I64);
2925 new_arg = newTemp(Ity_I64);
2926 assign(arg_l, getDRegI64(nreg+i));
2927 assign(new_arg, binop(Iop_Sub8x8, mkexpr(old_arg), mkU64(imm)));
2928 assign(cur_mask, binop(cmp, mkU64(imm), mkexpr(old_arg)));
2929 assign(new_mask, binop(Iop_Or64, mkexpr(old_mask), mkexpr(cur_mask)));
2930 assign(new_res, binop(Iop_Or64,
2931 mkexpr(old_res),
2932 binop(Iop_And64,
2933 binop(Iop_Perm8x8,
2934 mkexpr(arg_l),
2935 binop(Iop_And64,
2936 mkexpr(old_arg),
2937 mkexpr(cur_mask))),
2938 mkexpr(cur_mask))));
2939
2940 old_arg = new_arg;
2941 old_mask = new_mask;
2942 old_res = new_res;
2943 }
2944 if (op) {
2945 new_res = newTemp(Ity_I64);
2946 assign(new_res, binop(Iop_Or64,
2947 binop(Iop_And64,
2948 getDRegI64(dreg),
2949 unop(Iop_Not64, mkexpr(old_mask))),
2950 mkexpr(old_res)));
2951 old_res = new_res;
2952 }
2953
2954 putDRegI64(dreg, mkexpr(old_res), condT);
2955 DIP("vtb%c.8 d%u, {", op ? 'x' : 'l', dreg);
2956 if (len > 0) {
2957 DIP("d%u-d%u", nreg, nreg + len);
2958 } else {
2959 DIP("d%u", nreg);
2960 }
2961 DIP("}, d%u\n", mreg);
2962 return True;
2963}
2964
2965/* VDUP (scalar) */
2966static
2967Bool dis_neon_vdup ( UInt theInstr, IRTemp condT )
2968{
2969 UInt Q = (theInstr >> 6) & 1;
2970 UInt dreg = ((theInstr >> 18) & 0x10) | ((theInstr >> 12) & 0xF);
2971 UInt mreg = ((theInstr >> 1) & 0x10) | (theInstr & 0xF);
2972 UInt imm4 = (theInstr >> 16) & 0xF;
2973 UInt index;
2974 UInt size;
2975 IRTemp arg_m;
2976 IRTemp res;
2977 IROp op, op2;
2978
2979 if ((imm4 == 0) || (imm4 == 8))
2980 return False;
2981 if ((Q == 1) && ((dreg & 1) == 1))
2982 return False;
2983 if (Q)
2984 dreg >>= 1;
2985 arg_m = newTemp(Ity_I64);
2986 assign(arg_m, getDRegI64(mreg));
2987 if (Q)
2988 res = newTemp(Ity_V128);
2989 else
2990 res = newTemp(Ity_I64);
2991 if ((imm4 & 1) == 1) {
2992 op = Q ? Iop_Dup8x16 : Iop_Dup8x8;
2993 op2 = Iop_GetElem8x8;
2994 index = imm4 >> 1;
2995 size = 8;
2996 } else if ((imm4 & 3) == 2) {
2997 op = Q ? Iop_Dup16x8 : Iop_Dup16x4;
2998 op2 = Iop_GetElem16x4;
2999 index = imm4 >> 2;
3000 size = 16;
3001 } else if ((imm4 & 7) == 4) {
3002 op = Q ? Iop_Dup32x4 : Iop_Dup32x2;
3003 op2 = Iop_GetElem32x2;
3004 index = imm4 >> 3;
3005 size = 32;
sewardj9dbbd7b2010-08-22 18:24:51 +00003006 } else {
3007 return False; // can this ever happen?
sewardjd2664472010-08-22 12:44:20 +00003008 }
3009 assign(res, unop(op, binop(op2, mkexpr(arg_m), mkU8(index))));
3010 if (Q) {
3011 putQReg(dreg, mkexpr(res), condT);
3012 } else {
3013 putDRegI64(dreg, mkexpr(res), condT);
3014 }
3015 DIP("vdup.%d %c%d, d%d[%d]\n", size, Q ? 'q' : 'd', dreg, mreg, index);
3016 return True;
3017}
3018
3019/* A7.4.1 Three registers of the same length */
3020static
3021Bool dis_neon_data_3same ( UInt theInstr, IRTemp condT )
3022{
3023 UInt Q = (theInstr >> 6) & 1;
3024 UInt dreg = get_neon_d_regno(theInstr);
3025 UInt nreg = get_neon_n_regno(theInstr);
3026 UInt mreg = get_neon_m_regno(theInstr);
3027 UInt A = (theInstr >> 8) & 0xF;
3028 UInt B = (theInstr >> 4) & 1;
3029 UInt C = (theInstr >> 20) & 0x3;
3030 UInt U = (theInstr >> 24) & 1;
3031 UInt size = C;
3032
3033 IRTemp arg_n;
3034 IRTemp arg_m;
3035 IRTemp res;
3036
3037 if (Q) {
3038 arg_n = newTemp(Ity_V128);
3039 arg_m = newTemp(Ity_V128);
3040 res = newTemp(Ity_V128);
3041 assign(arg_n, getQReg(nreg));
3042 assign(arg_m, getQReg(mreg));
3043 } else {
3044 arg_n = newTemp(Ity_I64);
3045 arg_m = newTemp(Ity_I64);
3046 res = newTemp(Ity_I64);
3047 assign(arg_n, getDRegI64(nreg));
3048 assign(arg_m, getDRegI64(mreg));
3049 }
3050
3051 switch(A) {
3052 case 0:
3053 if (B == 0) {
3054 /* VHADD */
3055 ULong imm = 0;
3056 IRExpr *imm_val;
3057 IROp addOp;
3058 IROp andOp;
3059 IROp shOp;
3060 char regType = Q ? 'q' : 'd';
3061
3062 if (size == 3)
3063 return False;
3064 switch(size) {
3065 case 0: imm = 0x101010101010101LL; break;
3066 case 1: imm = 0x1000100010001LL; break;
3067 case 2: imm = 0x100000001LL; break;
3068 default: vassert(0);
3069 }
3070 if (Q) {
3071 imm_val = binop(Iop_64HLtoV128, mkU64(imm), mkU64(imm));
3072 andOp = Iop_AndV128;
3073 } else {
3074 imm_val = mkU64(imm);
3075 andOp = Iop_And64;
3076 }
3077 if (U) {
3078 switch(size) {
3079 case 0:
3080 addOp = Q ? Iop_Add8x16 : Iop_Add8x8;
3081 shOp = Q ? Iop_ShrN8x16 : Iop_ShrN8x8;
3082 break;
3083 case 1:
3084 addOp = Q ? Iop_Add16x8 : Iop_Add16x4;
3085 shOp = Q ? Iop_ShrN16x8 : Iop_ShrN16x4;
3086 break;
3087 case 2:
3088 addOp = Q ? Iop_Add32x4 : Iop_Add32x2;
3089 shOp = Q ? Iop_ShrN32x4 : Iop_ShrN32x2;
3090 break;
3091 default:
3092 vassert(0);
3093 }
3094 } else {
3095 switch(size) {
3096 case 0:
3097 addOp = Q ? Iop_Add8x16 : Iop_Add8x8;
3098 shOp = Q ? Iop_SarN8x16 : Iop_SarN8x8;
3099 break;
3100 case 1:
3101 addOp = Q ? Iop_Add16x8 : Iop_Add16x4;
3102 shOp = Q ? Iop_SarN16x8 : Iop_SarN16x4;
3103 break;
3104 case 2:
3105 addOp = Q ? Iop_Add32x4 : Iop_Add32x2;
3106 shOp = Q ? Iop_SarN32x4 : Iop_SarN32x2;
3107 break;
3108 default:
3109 vassert(0);
3110 }
3111 }
3112 assign(res,
3113 binop(addOp,
3114 binop(addOp,
3115 binop(shOp, mkexpr(arg_m), mkU8(1)),
3116 binop(shOp, mkexpr(arg_n), mkU8(1))),
3117 binop(shOp,
3118 binop(addOp,
3119 binop(andOp, mkexpr(arg_m), imm_val),
3120 binop(andOp, mkexpr(arg_n), imm_val)),
3121 mkU8(1))));
3122 DIP("vhadd.%c%d %c%d, %c%d, %c%d\n",
3123 U ? 'u' : 's', 8 << size, regType,
3124 dreg, regType, nreg, regType, mreg);
3125 } else {
3126 /* VQADD */
3127 IROp op, op2;
3128 IRTemp tmp;
3129 char reg_t = Q ? 'q' : 'd';
3130 if (Q) {
3131 switch (size) {
3132 case 0:
3133 op = U ? Iop_QAdd8Ux16 : Iop_QAdd8Sx16;
3134 op2 = Iop_Add8x16;
3135 break;
3136 case 1:
3137 op = U ? Iop_QAdd16Ux8 : Iop_QAdd16Sx8;
3138 op2 = Iop_Add16x8;
3139 break;
3140 case 2:
3141 op = U ? Iop_QAdd32Ux4 : Iop_QAdd32Sx4;
3142 op2 = Iop_Add32x4;
3143 break;
3144 case 3:
3145 op = U ? Iop_QAdd64Ux2 : Iop_QAdd64Sx2;
3146 op2 = Iop_Add64x2;
3147 break;
3148 default:
3149 vassert(0);
3150 }
3151 } else {
3152 switch (size) {
3153 case 0:
3154 op = U ? Iop_QAdd8Ux8 : Iop_QAdd8Sx8;
3155 op2 = Iop_Add8x8;
3156 break;
3157 case 1:
3158 op = U ? Iop_QAdd16Ux4 : Iop_QAdd16Sx4;
3159 op2 = Iop_Add16x4;
3160 break;
3161 case 2:
3162 op = U ? Iop_QAdd32Ux2 : Iop_QAdd32Sx2;
3163 op2 = Iop_Add32x2;
3164 break;
3165 case 3:
3166 op = U ? Iop_QAdd64Ux1 : Iop_QAdd64Sx1;
3167 op2 = Iop_Add64;
3168 break;
3169 default:
3170 vassert(0);
3171 }
3172 }
3173 if (Q) {
3174 tmp = newTemp(Ity_V128);
3175 } else {
3176 tmp = newTemp(Ity_I64);
3177 }
3178 assign(res, binop(op, mkexpr(arg_n), mkexpr(arg_m)));
3179#ifndef DISABLE_QC_FLAG
3180 assign(tmp, binop(op2, mkexpr(arg_n), mkexpr(arg_m)));
3181 setFlag_QC(mkexpr(res), mkexpr(tmp), Q, condT);
3182#endif
3183 DIP("vqadd.%c%d %c%d, %c%d, %c%d\n",
3184 U ? 'u' : 's',
3185 8 << size, reg_t, dreg, reg_t, nreg, reg_t, mreg);
3186 }
3187 break;
3188 case 1:
3189 if (B == 0) {
3190 /* VRHADD */
3191 /* VRHADD C, A, B ::=
3192 C = (A >> 1) + (B >> 1) + (((A & 1) + (B & 1) + 1) >> 1) */
3193 IROp shift_op, add_op;
3194 IRTemp cc;
3195 ULong one = 1;
3196 HChar reg_t = Q ? 'q' : 'd';
3197 switch (size) {
3198 case 0: one = (one << 8) | one; /* fall through */
3199 case 1: one = (one << 16) | one; /* fall through */
3200 case 2: one = (one << 32) | one; break;
3201 case 3: return False;
3202 default: vassert(0);
3203 }
3204 if (Q) {
3205 switch (size) {
3206 case 0:
3207 shift_op = U ? Iop_ShrN8x16 : Iop_SarN8x16;
3208 add_op = Iop_Add8x16;
3209 break;
3210 case 1:
3211 shift_op = U ? Iop_ShrN16x8 : Iop_SarN16x8;
3212 add_op = Iop_Add16x8;
3213 break;
3214 case 2:
3215 shift_op = U ? Iop_ShrN32x4 : Iop_SarN32x4;
3216 add_op = Iop_Add32x4;
3217 break;
3218 case 3:
3219 return False;
3220 default:
3221 vassert(0);
3222 }
3223 } else {
3224 switch (size) {
3225 case 0:
3226 shift_op = U ? Iop_ShrN8x8 : Iop_SarN8x8;
3227 add_op = Iop_Add8x8;
3228 break;
3229 case 1:
3230 shift_op = U ? Iop_ShrN16x4 : Iop_SarN16x4;
3231 add_op = Iop_Add16x4;
3232 break;
3233 case 2:
3234 shift_op = U ? Iop_ShrN32x2 : Iop_SarN32x2;
3235 add_op = Iop_Add32x2;
3236 break;
3237 case 3:
3238 return False;
3239 default:
3240 vassert(0);
3241 }
3242 }
3243 if (Q) {
3244 cc = newTemp(Ity_V128);
3245 assign(cc, binop(shift_op,
3246 binop(add_op,
3247 binop(add_op,
3248 binop(Iop_AndV128,
3249 mkexpr(arg_n),
3250 binop(Iop_64HLtoV128,
3251 mkU64(one),
3252 mkU64(one))),
3253 binop(Iop_AndV128,
3254 mkexpr(arg_m),
3255 binop(Iop_64HLtoV128,
3256 mkU64(one),
3257 mkU64(one)))),
3258 binop(Iop_64HLtoV128,
3259 mkU64(one),
3260 mkU64(one))),
3261 mkU8(1)));
3262 assign(res, binop(add_op,
3263 binop(add_op,
3264 binop(shift_op,
3265 mkexpr(arg_n),
3266 mkU8(1)),
3267 binop(shift_op,
3268 mkexpr(arg_m),
3269 mkU8(1))),
3270 mkexpr(cc)));
3271 } else {
3272 cc = newTemp(Ity_I64);
3273 assign(cc, binop(shift_op,
3274 binop(add_op,
3275 binop(add_op,
3276 binop(Iop_And64,
3277 mkexpr(arg_n),
3278 mkU64(one)),
3279 binop(Iop_And64,
3280 mkexpr(arg_m),
3281 mkU64(one))),
3282 mkU64(one)),
3283 mkU8(1)));
3284 assign(res, binop(add_op,
3285 binop(add_op,
3286 binop(shift_op,
3287 mkexpr(arg_n),
3288 mkU8(1)),
3289 binop(shift_op,
3290 mkexpr(arg_m),
3291 mkU8(1))),
3292 mkexpr(cc)));
3293 }
3294 DIP("vrhadd.%c%d %c%d, %c%d, %c%d\n",
3295 U ? 'u' : 's',
3296 8 << size, reg_t, dreg, reg_t, nreg, reg_t, mreg);
3297 } else {
3298 if (U == 0) {
3299 switch(C) {
3300 case 0: {
3301 /* VAND */
3302 HChar reg_t = Q ? 'q' : 'd';
3303 if (Q) {
3304 assign(res, binop(Iop_AndV128, mkexpr(arg_n),
3305 mkexpr(arg_m)));
3306 } else {
3307 assign(res, binop(Iop_And64, mkexpr(arg_n),
3308 mkexpr(arg_m)));
3309 }
3310 DIP("vand %c%d, %c%d, %c%d\n",
3311 reg_t, dreg, reg_t, nreg, reg_t, mreg);
3312 break;
3313 }
3314 case 1: {
3315 /* VBIC */
3316 HChar reg_t = Q ? 'q' : 'd';
3317 if (Q) {
3318 assign(res, binop(Iop_AndV128,mkexpr(arg_n),
3319 unop(Iop_NotV128, mkexpr(arg_m))));
3320 } else {
3321 assign(res, binop(Iop_And64, mkexpr(arg_n),
3322 unop(Iop_Not64, mkexpr(arg_m))));
3323 }
3324 DIP("vbic %c%d, %c%d, %c%d\n",
3325 reg_t, dreg, reg_t, nreg, reg_t, mreg);
3326 break;
3327 }
3328 case 2:
3329 if ( nreg != mreg) {
3330 /* VORR */
3331 HChar reg_t = Q ? 'q' : 'd';
3332 if (Q) {
3333 assign(res, binop(Iop_OrV128, mkexpr(arg_n),
3334 mkexpr(arg_m)));
3335 } else {
3336 assign(res, binop(Iop_Or64, mkexpr(arg_n),
3337 mkexpr(arg_m)));
3338 }
3339 DIP("vorr %c%d, %c%d, %c%d\n",
3340 reg_t, dreg, reg_t, nreg, reg_t, mreg);
3341 } else {
3342 /* VMOV */
3343 HChar reg_t = Q ? 'q' : 'd';
3344 assign(res, mkexpr(arg_m));
3345 DIP("vmov %c%d, %c%d\n", reg_t, dreg, reg_t, mreg);
3346 }
3347 break;
3348 case 3:{
3349 /* VORN */
3350 HChar reg_t = Q ? 'q' : 'd';
3351 if (Q) {
3352 assign(res, binop(Iop_OrV128,mkexpr(arg_n),
3353 unop(Iop_NotV128, mkexpr(arg_m))));
3354 } else {
3355 assign(res, binop(Iop_Or64, mkexpr(arg_n),
3356 unop(Iop_Not64, mkexpr(arg_m))));
3357 }
3358 DIP("vorn %c%d, %c%d, %c%d\n",
3359 reg_t, dreg, reg_t, nreg, reg_t, mreg);
3360 break;
3361 }
3362 }
3363 } else {
3364 switch(C) {
3365 case 0:
3366 /* VEOR (XOR) */
3367 if (Q) {
3368 assign(res, binop(Iop_XorV128, mkexpr(arg_n),
3369 mkexpr(arg_m)));
3370 } else {
3371 assign(res, binop(Iop_Xor64, mkexpr(arg_n),
3372 mkexpr(arg_m)));
3373 }
3374 DIP("veor %c%u, %c%u, %c%u\n", Q ? 'q' : 'd', dreg,
3375 Q ? 'q' : 'd', nreg, Q ? 'q' : 'd', mreg);
3376 break;
3377 case 1:
3378 /* VBSL */
3379 if (Q) {
3380 IRTemp reg_d = newTemp(Ity_V128);
3381 assign(reg_d, getQReg(dreg));
3382 assign(res,
3383 binop(Iop_OrV128,
3384 binop(Iop_AndV128, mkexpr(arg_n),
3385 mkexpr(reg_d)),
3386 binop(Iop_AndV128,
3387 mkexpr(arg_m),
3388 unop(Iop_NotV128,
3389 mkexpr(reg_d)) ) ) );
3390 } else {
3391 IRTemp reg_d = newTemp(Ity_I64);
3392 assign(reg_d, getDRegI64(dreg));
3393 assign(res,
3394 binop(Iop_Or64,
3395 binop(Iop_And64, mkexpr(arg_n),
3396 mkexpr(reg_d)),
3397 binop(Iop_And64,
3398 mkexpr(arg_m),
3399 unop(Iop_Not64, mkexpr(reg_d)))));
3400 }
3401 DIP("vbsl %c%u, %c%u, %c%u\n",
3402 Q ? 'q' : 'd', dreg,
3403 Q ? 'q' : 'd', nreg, Q ? 'q' : 'd', mreg);
3404 break;
3405 case 2:
3406 /* VBIT */
3407 if (Q) {
3408 IRTemp reg_d = newTemp(Ity_V128);
3409 assign(reg_d, getQReg(dreg));
3410 assign(res,
3411 binop(Iop_OrV128,
3412 binop(Iop_AndV128, mkexpr(arg_n),
3413 mkexpr(arg_m)),
3414 binop(Iop_AndV128,
3415 mkexpr(reg_d),
3416 unop(Iop_NotV128, mkexpr(arg_m)))));
3417 } else {
3418 IRTemp reg_d = newTemp(Ity_I64);
3419 assign(reg_d, getDRegI64(dreg));
3420 assign(res,
3421 binop(Iop_Or64,
3422 binop(Iop_And64, mkexpr(arg_n),
3423 mkexpr(arg_m)),
3424 binop(Iop_And64,
3425 mkexpr(reg_d),
3426 unop(Iop_Not64, mkexpr(arg_m)))));
3427 }
3428 DIP("vbit %c%u, %c%u, %c%u\n",
3429 Q ? 'q' : 'd', dreg,
3430 Q ? 'q' : 'd', nreg, Q ? 'q' : 'd', mreg);
3431 break;
3432 case 3:
3433 /* VBIF */
3434 if (Q) {
3435 IRTemp reg_d = newTemp(Ity_V128);
3436 assign(reg_d, getQReg(dreg));
3437 assign(res,
3438 binop(Iop_OrV128,
3439 binop(Iop_AndV128, mkexpr(reg_d),
3440 mkexpr(arg_m)),
3441 binop(Iop_AndV128,
3442 mkexpr(arg_n),
3443 unop(Iop_NotV128, mkexpr(arg_m)))));
3444 } else {
3445 IRTemp reg_d = newTemp(Ity_I64);
3446 assign(reg_d, getDRegI64(dreg));
3447 assign(res,
3448 binop(Iop_Or64,
3449 binop(Iop_And64, mkexpr(reg_d),
3450 mkexpr(arg_m)),
3451 binop(Iop_And64,
3452 mkexpr(arg_n),
3453 unop(Iop_Not64, mkexpr(arg_m)))));
3454 }
3455 DIP("vbif %c%u, %c%u, %c%u\n",
3456 Q ? 'q' : 'd', dreg,
3457 Q ? 'q' : 'd', nreg, Q ? 'q' : 'd', mreg);
3458 break;
3459 }
3460 }
3461 }
3462 break;
3463 case 2:
3464 if (B == 0) {
3465 /* VHSUB */
3466 /* (A >> 1) - (B >> 1) - (NOT (A) & B & 1) */
3467 ULong imm = 0;
3468 IRExpr *imm_val;
3469 IROp subOp;
3470 IROp notOp;
3471 IROp andOp;
3472 IROp shOp;
3473 if (size == 3)
3474 return False;
3475 switch(size) {
3476 case 0: imm = 0x101010101010101LL; break;
3477 case 1: imm = 0x1000100010001LL; break;
3478 case 2: imm = 0x100000001LL; break;
3479 default: vassert(0);
3480 }
3481 if (Q) {
3482 imm_val = binop(Iop_64HLtoV128, mkU64(imm), mkU64(imm));
3483 andOp = Iop_AndV128;
3484 notOp = Iop_NotV128;
3485 } else {
3486 imm_val = mkU64(imm);
3487 andOp = Iop_And64;
3488 notOp = Iop_Not64;
3489 }
3490 if (U) {
3491 switch(size) {
3492 case 0:
3493 subOp = Q ? Iop_Sub8x16 : Iop_Sub8x8;
3494 shOp = Q ? Iop_ShrN8x16 : Iop_ShrN8x8;
3495 break;
3496 case 1:
3497 subOp = Q ? Iop_Sub16x8 : Iop_Sub16x4;
3498 shOp = Q ? Iop_ShrN16x8 : Iop_ShrN16x4;
3499 break;
3500 case 2:
3501 subOp = Q ? Iop_Sub32x4 : Iop_Sub32x2;
3502 shOp = Q ? Iop_ShrN32x4 : Iop_ShrN32x2;
3503 break;
3504 default:
3505 vassert(0);
3506 }
3507 } else {
3508 switch(size) {
3509 case 0:
3510 subOp = Q ? Iop_Sub8x16 : Iop_Sub8x8;
3511 shOp = Q ? Iop_SarN8x16 : Iop_SarN8x8;
3512 break;
3513 case 1:
3514 subOp = Q ? Iop_Sub16x8 : Iop_Sub16x4;
3515 shOp = Q ? Iop_SarN16x8 : Iop_SarN16x4;
3516 break;
3517 case 2:
3518 subOp = Q ? Iop_Sub32x4 : Iop_Sub32x2;
3519 shOp = Q ? Iop_SarN32x4 : Iop_SarN32x2;
3520 break;
3521 default:
3522 vassert(0);
3523 }
3524 }
3525 assign(res,
3526 binop(subOp,
3527 binop(subOp,
3528 binop(shOp, mkexpr(arg_n), mkU8(1)),
3529 binop(shOp, mkexpr(arg_m), mkU8(1))),
3530 binop(andOp,
3531 binop(andOp,
3532 unop(notOp, mkexpr(arg_n)),
3533 mkexpr(arg_m)),
3534 imm_val)));
3535 DIP("vhsub.%c%u %c%u, %c%u, %c%u\n",
3536 U ? 'u' : 's', 8 << size,
3537 Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', nreg, Q ? 'q' : 'd',
3538 mreg);
3539 } else {
3540 /* VQSUB */
3541 IROp op, op2;
3542 IRTemp tmp;
3543 if (Q) {
3544 switch (size) {
3545 case 0:
3546 op = U ? Iop_QSub8Ux16 : Iop_QSub8Sx16;
3547 op2 = Iop_Sub8x16;
3548 break;
3549 case 1:
3550 op = U ? Iop_QSub16Ux8 : Iop_QSub16Sx8;
3551 op2 = Iop_Sub16x8;
3552 break;
3553 case 2:
3554 op = U ? Iop_QSub32Ux4 : Iop_QSub32Sx4;
3555 op2 = Iop_Sub32x4;
3556 break;
3557 case 3:
3558 op = U ? Iop_QSub64Ux2 : Iop_QSub64Sx2;
3559 op2 = Iop_Sub64x2;
3560 break;
3561 default:
3562 vassert(0);
3563 }
3564 } else {
3565 switch (size) {
3566 case 0:
3567 op = U ? Iop_QSub8Ux8 : Iop_QSub8Sx8;
3568 op2 = Iop_Sub8x8;
3569 break;
3570 case 1:
3571 op = U ? Iop_QSub16Ux4 : Iop_QSub16Sx4;
3572 op2 = Iop_Sub16x4;
3573 break;
3574 case 2:
3575 op = U ? Iop_QSub32Ux2 : Iop_QSub32Sx2;
3576 op2 = Iop_Sub32x2;
3577 break;
3578 case 3:
3579 op = U ? Iop_QSub64Ux1 : Iop_QSub64Sx1;
3580 op2 = Iop_Sub64;
3581 break;
3582 default:
3583 vassert(0);
3584 }
3585 }
3586 if (Q)
3587 tmp = newTemp(Ity_V128);
3588 else
3589 tmp = newTemp(Ity_I64);
3590 assign(res, binop(op, mkexpr(arg_n), mkexpr(arg_m)));
3591#ifndef DISABLE_QC_FLAG
3592 assign(tmp, binop(op2, mkexpr(arg_n), mkexpr(arg_m)));
3593 setFlag_QC(mkexpr(res), mkexpr(tmp), Q, condT);
3594#endif
3595 DIP("vqsub.%c%u %c%u, %c%u, %c%u\n",
3596 U ? 'u' : 's', 8 << size,
3597 Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', nreg, Q ? 'q' : 'd',
3598 mreg);
3599 }
3600 break;
3601 case 3: {
3602 IROp op;
3603 if (Q) {
3604 switch (size) {
3605 case 0: op = U ? Iop_CmpGT8Ux16 : Iop_CmpGT8Sx16; break;
3606 case 1: op = U ? Iop_CmpGT16Ux8 : Iop_CmpGT16Sx8; break;
3607 case 2: op = U ? Iop_CmpGT32Ux4 : Iop_CmpGT32Sx4; break;
3608 case 3: return False;
3609 default: vassert(0);
3610 }
3611 } else {
3612 switch (size) {
3613 case 0: op = U ? Iop_CmpGT8Ux8 : Iop_CmpGT8Sx8; break;
3614 case 1: op = U ? Iop_CmpGT16Ux4 : Iop_CmpGT16Sx4; break;
3615 case 2: op = U ? Iop_CmpGT32Ux2: Iop_CmpGT32Sx2; break;
3616 case 3: return False;
3617 default: vassert(0);
3618 }
3619 }
3620 if (B == 0) {
3621 /* VCGT */
3622 assign(res, binop(op, mkexpr(arg_n), mkexpr(arg_m)));
3623 DIP("vcgt.%c%u %c%u, %c%u, %c%u\n",
3624 U ? 'u' : 's', 8 << size,
3625 Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', nreg, Q ? 'q' : 'd',
3626 mreg);
3627 } else {
3628 /* VCGE */
3629 /* VCGE res, argn, argm
3630 is equal to
3631 VCGT tmp, argm, argn
3632 VNOT res, tmp */
3633 assign(res,
3634 unop(Q ? Iop_NotV128 : Iop_Not64,
3635 binop(op, mkexpr(arg_m), mkexpr(arg_n))));
3636 DIP("vcge.%c%u %c%u, %c%u, %c%u\n",
3637 U ? 'u' : 's', 8 << size,
3638 Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', nreg, Q ? 'q' : 'd',
3639 mreg);
3640 }
3641 }
3642 break;
3643 case 4:
3644 if (B == 0) {
3645 /* VSHL */
3646 IROp op, sub_op;
3647 IRTemp tmp;
3648 if (U) {
3649 switch (size) {
3650 case 0: op = Q ? Iop_Shl8x16 : Iop_Shl8x8; break;
3651 case 1: op = Q ? Iop_Shl16x8 : Iop_Shl16x4; break;
3652 case 2: op = Q ? Iop_Shl32x4 : Iop_Shl32x2; break;
3653 case 3: op = Q ? Iop_Shl64x2 : Iop_Shl64; break;
3654 default: vassert(0);
3655 }
3656 } else {
3657 tmp = newTemp(Q ? Ity_V128 : Ity_I64);
3658 switch (size) {
3659 case 0:
3660 op = Q ? Iop_Sar8x16 : Iop_Sar8x8;
3661 sub_op = Q ? Iop_Sub8x16 : Iop_Sub8x8;
3662 break;
3663 case 1:
3664 op = Q ? Iop_Sar16x8 : Iop_Sar16x4;
3665 sub_op = Q ? Iop_Sub16x8 : Iop_Sub16x4;
3666 break;
3667 case 2:
3668 op = Q ? Iop_Sar32x4 : Iop_Sar32x2;
3669 sub_op = Q ? Iop_Sub32x4 : Iop_Sub32x2;
3670 break;
3671 case 3:
3672 op = Q ? Iop_Sar64x2 : Iop_Sar64;
3673 sub_op = Q ? Iop_Sub64x2 : Iop_Sub64;
3674 break;
3675 default:
3676 vassert(0);
3677 }
3678 }
3679 if (U) {
3680 if (!Q && (size == 3))
3681 assign(res, binop(op, mkexpr(arg_m),
3682 unop(Iop_64to8, mkexpr(arg_n))));
3683 else
3684 assign(res, binop(op, mkexpr(arg_m), mkexpr(arg_n)));
3685 } else {
3686 if (Q)
3687 assign(tmp, binop(sub_op,
3688 binop(Iop_64HLtoV128, mkU64(0), mkU64(0)),
3689 mkexpr(arg_n)));
3690 else
3691 assign(tmp, binop(sub_op, mkU64(0), mkexpr(arg_n)));
3692 if (!Q && (size == 3))
3693 assign(res, binop(op, mkexpr(arg_m),
3694 unop(Iop_64to8, mkexpr(tmp))));
3695 else
3696 assign(res, binop(op, mkexpr(arg_m), mkexpr(tmp)));
3697 }
3698 DIP("vshl.%c%u %c%u, %c%u, %c%u\n",
3699 U ? 'u' : 's', 8 << size,
3700 Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', mreg, Q ? 'q' : 'd',
3701 nreg);
3702 } else {
3703 /* VQSHL */
3704 IROp op, op_rev, op_shrn, op_shln, cmp_neq, cmp_gt;
3705 IRTemp tmp, shval, mask, old_shval;
3706 UInt i;
3707 ULong esize;
3708 cmp_neq = Q ? Iop_CmpNEZ8x16 : Iop_CmpNEZ8x8;
3709 cmp_gt = Q ? Iop_CmpGT8Sx16 : Iop_CmpGT8Sx8;
3710 if (U) {
3711 switch (size) {
3712 case 0:
3713 op = Q ? Iop_QShl8x16 : Iop_QShl8x8;
3714 op_rev = Q ? Iop_Shr8x16 : Iop_Shr8x8;
3715 op_shrn = Q ? Iop_ShrN8x16 : Iop_ShrN8x8;
3716 op_shln = Q ? Iop_ShlN8x16 : Iop_ShlN8x8;
3717 break;
3718 case 1:
3719 op = Q ? Iop_QShl16x8 : Iop_QShl16x4;
3720 op_rev = Q ? Iop_Shr16x8 : Iop_Shr16x4;
3721 op_shrn = Q ? Iop_ShrN16x8 : Iop_ShrN16x4;
3722 op_shln = Q ? Iop_ShlN16x8 : Iop_ShlN16x4;
3723 break;
3724 case 2:
3725 op = Q ? Iop_QShl32x4 : Iop_QShl32x2;
3726 op_rev = Q ? Iop_Shr32x4 : Iop_Shr32x2;
3727 op_shrn = Q ? Iop_ShrN32x4 : Iop_ShrN32x2;
3728 op_shln = Q ? Iop_ShlN32x4 : Iop_ShlN32x2;
3729 break;
3730 case 3:
3731 op = Q ? Iop_QShl64x2 : Iop_QShl64x1;
3732 op_rev = Q ? Iop_Shr64x2 : Iop_Shr64;
3733 op_shrn = Q ? Iop_ShrN64x2 : Iop_Shr64;
3734 op_shln = Q ? Iop_ShlN64x2 : Iop_Shl64;
3735 break;
3736 default:
3737 vassert(0);
3738 }
3739 } else {
3740 switch (size) {
3741 case 0:
3742 op = Q ? Iop_QSal8x16 : Iop_QSal8x8;
3743 op_rev = Q ? Iop_Sar8x16 : Iop_Sar8x8;
3744 op_shrn = Q ? Iop_ShrN8x16 : Iop_ShrN8x8;
3745 op_shln = Q ? Iop_ShlN8x16 : Iop_ShlN8x8;
3746 break;
3747 case 1:
3748 op = Q ? Iop_QSal16x8 : Iop_QSal16x4;
3749 op_rev = Q ? Iop_Sar16x8 : Iop_Sar16x4;
3750 op_shrn = Q ? Iop_ShrN16x8 : Iop_ShrN16x4;
3751 op_shln = Q ? Iop_ShlN16x8 : Iop_ShlN16x4;
3752 break;
3753 case 2:
3754 op = Q ? Iop_QSal32x4 : Iop_QSal32x2;
3755 op_rev = Q ? Iop_Sar32x4 : Iop_Sar32x2;
3756 op_shrn = Q ? Iop_ShrN32x4 : Iop_ShrN32x2;
3757 op_shln = Q ? Iop_ShlN32x4 : Iop_ShlN32x2;
3758 break;
3759 case 3:
3760 op = Q ? Iop_QSal64x2 : Iop_QSal64x1;
3761 op_rev = Q ? Iop_Sar64x2 : Iop_Sar64;
3762 op_shrn = Q ? Iop_ShrN64x2 : Iop_Shr64;
3763 op_shln = Q ? Iop_ShlN64x2 : Iop_Shl64;
3764 break;
3765 default:
3766 vassert(0);
3767 }
3768 }
3769 if (Q) {
3770 tmp = newTemp(Ity_V128);
3771 shval = newTemp(Ity_V128);
3772 mask = newTemp(Ity_V128);
3773 } else {
3774 tmp = newTemp(Ity_I64);
3775 shval = newTemp(Ity_I64);
3776 mask = newTemp(Ity_I64);
3777 }
3778 assign(res, binop(op, mkexpr(arg_m), mkexpr(arg_n)));
3779#ifndef DISABLE_QC_FLAG
3780 /* Only least significant byte from second argument is used.
3781 Copy this byte to the whole vector element. */
3782 assign(shval, binop(op_shrn,
3783 binop(op_shln,
3784 mkexpr(arg_n),
3785 mkU8((8 << size) - 8)),
3786 mkU8((8 << size) - 8)));
3787 for(i = 0; i < size; i++) {
3788 old_shval = shval;
3789 shval = newTemp(Q ? Ity_V128 : Ity_I64);
3790 assign(shval, binop(Q ? Iop_OrV128 : Iop_Or64,
3791 mkexpr(old_shval),
3792 binop(op_shln,
3793 mkexpr(old_shval),
3794 mkU8(8 << i))));
3795 }
3796 /* If shift is greater or equal to the element size and
3797 element is non-zero, then QC flag should be set. */
3798 esize = (8 << size) - 1;
3799 esize = (esize << 8) | esize;
3800 esize = (esize << 16) | esize;
3801 esize = (esize << 32) | esize;
3802 setFlag_QC(binop(Q ? Iop_AndV128 : Iop_And64,
3803 binop(cmp_gt, mkexpr(shval),
3804 Q ? mkU128(esize) : mkU64(esize)),
3805 unop(cmp_neq, mkexpr(arg_m))),
3806 Q ? mkU128(0) : mkU64(0),
3807 Q, condT);
3808 /* Othervise QC flag should be set if shift value is positive and
3809 result beign rightshifted the same value is not equal to left
3810 argument. */
3811 assign(mask, binop(cmp_gt, mkexpr(shval),
3812 Q ? mkU128(0) : mkU64(0)));
3813 if (!Q && size == 3)
3814 assign(tmp, binop(op_rev, mkexpr(res),
3815 unop(Iop_64to8, mkexpr(arg_n))));
3816 else
3817 assign(tmp, binop(op_rev, mkexpr(res), mkexpr(arg_n)));
3818 setFlag_QC(binop(Q ? Iop_AndV128 : Iop_And64,
3819 mkexpr(tmp), mkexpr(mask)),
3820 binop(Q ? Iop_AndV128 : Iop_And64,
3821 mkexpr(arg_m), mkexpr(mask)),
3822 Q, condT);
3823#endif
3824 DIP("vqshl.%c%u %c%u, %c%u, %c%u\n",
3825 U ? 'u' : 's', 8 << size,
3826 Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', mreg, Q ? 'q' : 'd',
3827 nreg);
3828 }
3829 break;
3830 case 5:
3831 if (B == 0) {
3832 /* VRSHL */
sewardj06122e72011-03-28 12:14:48 +00003833 IROp op, op_shrn, op_shln, cmp_gt, op_add;
sewardjd2664472010-08-22 12:44:20 +00003834 IRTemp shval, old_shval, imm_val, round;
3835 UInt i;
3836 ULong imm;
3837 cmp_gt = Q ? Iop_CmpGT8Sx16 : Iop_CmpGT8Sx8;
3838 imm = 1L;
3839 switch (size) {
3840 case 0: imm = (imm << 8) | imm; /* fall through */
3841 case 1: imm = (imm << 16) | imm; /* fall through */
3842 case 2: imm = (imm << 32) | imm; /* fall through */
3843 case 3: break;
3844 default: vassert(0);
3845 }
3846 imm_val = newTemp(Q ? Ity_V128 : Ity_I64);
3847 round = newTemp(Q ? Ity_V128 : Ity_I64);
3848 assign(imm_val, Q ? mkU128(imm) : mkU64(imm));
3849 if (U) {
3850 switch (size) {
3851 case 0:
3852 op = Q ? Iop_Shl8x16 : Iop_Shl8x8;
sewardjd2664472010-08-22 12:44:20 +00003853 op_add = Q ? Iop_Add8x16 : Iop_Add8x8;
3854 op_shrn = Q ? Iop_ShrN8x16 : Iop_ShrN8x8;
3855 op_shln = Q ? Iop_ShlN8x16 : Iop_ShlN8x8;
3856 break;
3857 case 1:
3858 op = Q ? Iop_Shl16x8 : Iop_Shl16x4;
sewardjd2664472010-08-22 12:44:20 +00003859 op_add = Q ? Iop_Add16x8 : Iop_Add16x4;
3860 op_shrn = Q ? Iop_ShrN16x8 : Iop_ShrN16x4;
3861 op_shln = Q ? Iop_ShlN16x8 : Iop_ShlN16x4;
3862 break;
3863 case 2:
3864 op = Q ? Iop_Shl32x4 : Iop_Shl32x2;
sewardjd2664472010-08-22 12:44:20 +00003865 op_add = Q ? Iop_Add32x4 : Iop_Add32x2;
3866 op_shrn = Q ? Iop_ShrN32x4 : Iop_ShrN32x2;
3867 op_shln = Q ? Iop_ShlN32x4 : Iop_ShlN32x2;
3868 break;
3869 case 3:
3870 op = Q ? Iop_Shl64x2 : Iop_Shl64;
sewardjd2664472010-08-22 12:44:20 +00003871 op_add = Q ? Iop_Add64x2 : Iop_Add64;
3872 op_shrn = Q ? Iop_ShrN64x2 : Iop_Shr64;
3873 op_shln = Q ? Iop_ShlN64x2 : Iop_Shl64;
3874 break;
3875 default:
3876 vassert(0);
3877 }
3878 } else {
3879 switch (size) {
3880 case 0:
3881 op = Q ? Iop_Sal8x16 : Iop_Sal8x8;
sewardjd2664472010-08-22 12:44:20 +00003882 op_add = Q ? Iop_Add8x16 : Iop_Add8x8;
3883 op_shrn = Q ? Iop_ShrN8x16 : Iop_ShrN8x8;
3884 op_shln = Q ? Iop_ShlN8x16 : Iop_ShlN8x8;
3885 break;
3886 case 1:
3887 op = Q ? Iop_Sal16x8 : Iop_Sal16x4;
sewardjd2664472010-08-22 12:44:20 +00003888 op_add = Q ? Iop_Add16x8 : Iop_Add16x4;
3889 op_shrn = Q ? Iop_ShrN16x8 : Iop_ShrN16x4;
3890 op_shln = Q ? Iop_ShlN16x8 : Iop_ShlN16x4;
3891 break;
3892 case 2:
3893 op = Q ? Iop_Sal32x4 : Iop_Sal32x2;
sewardjd2664472010-08-22 12:44:20 +00003894 op_add = Q ? Iop_Add32x4 : Iop_Add32x2;
3895 op_shrn = Q ? Iop_ShrN32x4 : Iop_ShrN32x2;
3896 op_shln = Q ? Iop_ShlN32x4 : Iop_ShlN32x2;
3897 break;
3898 case 3:
3899 op = Q ? Iop_Sal64x2 : Iop_Sal64x1;
sewardjd2664472010-08-22 12:44:20 +00003900 op_add = Q ? Iop_Add64x2 : Iop_Add64;
3901 op_shrn = Q ? Iop_ShrN64x2 : Iop_Shr64;
3902 op_shln = Q ? Iop_ShlN64x2 : Iop_Shl64;
3903 break;
3904 default:
3905 vassert(0);
3906 }
3907 }
3908 if (Q) {
3909 shval = newTemp(Ity_V128);
3910 } else {
3911 shval = newTemp(Ity_I64);
3912 }
3913 /* Only least significant byte from second argument is used.
3914 Copy this byte to the whole vector element. */
3915 assign(shval, binop(op_shrn,
3916 binop(op_shln,
3917 mkexpr(arg_n),
3918 mkU8((8 << size) - 8)),
3919 mkU8((8 << size) - 8)));
3920 for (i = 0; i < size; i++) {
3921 old_shval = shval;
3922 shval = newTemp(Q ? Ity_V128 : Ity_I64);
3923 assign(shval, binop(Q ? Iop_OrV128 : Iop_Or64,
3924 mkexpr(old_shval),
3925 binop(op_shln,
3926 mkexpr(old_shval),
3927 mkU8(8 << i))));
3928 }
3929 /* Compute the result */
3930 if (!Q && size == 3 && U) {
3931 assign(round, binop(Q ? Iop_AndV128 : Iop_And64,
3932 binop(op,
3933 mkexpr(arg_m),
3934 unop(Iop_64to8,
sewardjb0d80ea2010-10-06 20:47:22 +00003935 binop(op_add,
sewardjd2664472010-08-22 12:44:20 +00003936 mkexpr(arg_n),
3937 mkexpr(imm_val)))),
3938 binop(Q ? Iop_AndV128 : Iop_And64,
3939 mkexpr(imm_val),
3940 binop(cmp_gt,
3941 Q ? mkU128(0) : mkU64(0),
3942 mkexpr(arg_n)))));
3943 assign(res, binop(op_add,
3944 binop(op,
3945 mkexpr(arg_m),
3946 unop(Iop_64to8, mkexpr(arg_n))),
3947 mkexpr(round)));
3948 } else {
3949 assign(round, binop(Q ? Iop_AndV128 : Iop_And64,
3950 binop(op,
3951 mkexpr(arg_m),
3952 binop(op_add,
3953 mkexpr(arg_n),
3954 mkexpr(imm_val))),
3955 binop(Q ? Iop_AndV128 : Iop_And64,
3956 mkexpr(imm_val),
3957 binop(cmp_gt,
3958 Q ? mkU128(0) : mkU64(0),
3959 mkexpr(arg_n)))));
3960 assign(res, binop(op_add,
3961 binop(op, mkexpr(arg_m), mkexpr(arg_n)),
3962 mkexpr(round)));
3963 }
3964 DIP("vrshl.%c%u %c%u, %c%u, %c%u\n",
3965 U ? 'u' : 's', 8 << size,
3966 Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', mreg, Q ? 'q' : 'd',
3967 nreg);
3968 } else {
3969 /* VQRSHL */
sewardj06122e72011-03-28 12:14:48 +00003970 IROp op, op_rev, op_shrn, op_shln, cmp_neq, cmp_gt, op_add;
sewardjd2664472010-08-22 12:44:20 +00003971 IRTemp tmp, shval, mask, old_shval, imm_val, round;
3972 UInt i;
3973 ULong esize, imm;
3974 cmp_neq = Q ? Iop_CmpNEZ8x16 : Iop_CmpNEZ8x8;
3975 cmp_gt = Q ? Iop_CmpGT8Sx16 : Iop_CmpGT8Sx8;
3976 imm = 1L;
3977 switch (size) {
3978 case 0: imm = (imm << 8) | imm; /* fall through */
3979 case 1: imm = (imm << 16) | imm; /* fall through */
3980 case 2: imm = (imm << 32) | imm; /* fall through */
3981 case 3: break;
3982 default: vassert(0);
3983 }
3984 imm_val = newTemp(Q ? Ity_V128 : Ity_I64);
3985 round = newTemp(Q ? Ity_V128 : Ity_I64);
3986 assign(imm_val, Q ? mkU128(imm) : mkU64(imm));
3987 if (U) {
3988 switch (size) {
3989 case 0:
3990 op = Q ? Iop_QShl8x16 : Iop_QShl8x8;
sewardjd2664472010-08-22 12:44:20 +00003991 op_add = Q ? Iop_Add8x16 : Iop_Add8x8;
3992 op_rev = Q ? Iop_Shr8x16 : Iop_Shr8x8;
3993 op_shrn = Q ? Iop_ShrN8x16 : Iop_ShrN8x8;
3994 op_shln = Q ? Iop_ShlN8x16 : Iop_ShlN8x8;
3995 break;
3996 case 1:
3997 op = Q ? Iop_QShl16x8 : Iop_QShl16x4;
sewardjd2664472010-08-22 12:44:20 +00003998 op_add = Q ? Iop_Add16x8 : Iop_Add16x4;
3999 op_rev = Q ? Iop_Shr16x8 : Iop_Shr16x4;
4000 op_shrn = Q ? Iop_ShrN16x8 : Iop_ShrN16x4;
4001 op_shln = Q ? Iop_ShlN16x8 : Iop_ShlN16x4;
4002 break;
4003 case 2:
4004 op = Q ? Iop_QShl32x4 : Iop_QShl32x2;
sewardjd2664472010-08-22 12:44:20 +00004005 op_add = Q ? Iop_Add32x4 : Iop_Add32x2;
4006 op_rev = Q ? Iop_Shr32x4 : Iop_Shr32x2;
4007 op_shrn = Q ? Iop_ShrN32x4 : Iop_ShrN32x2;
4008 op_shln = Q ? Iop_ShlN32x4 : Iop_ShlN32x2;
4009 break;
4010 case 3:
4011 op = Q ? Iop_QShl64x2 : Iop_QShl64x1;
sewardjd2664472010-08-22 12:44:20 +00004012 op_add = Q ? Iop_Add64x2 : Iop_Add64;
4013 op_rev = Q ? Iop_Shr64x2 : Iop_Shr64;
4014 op_shrn = Q ? Iop_ShrN64x2 : Iop_Shr64;
4015 op_shln = Q ? Iop_ShlN64x2 : Iop_Shl64;
4016 break;
4017 default:
4018 vassert(0);
4019 }
4020 } else {
4021 switch (size) {
4022 case 0:
4023 op = Q ? Iop_QSal8x16 : Iop_QSal8x8;
sewardjd2664472010-08-22 12:44:20 +00004024 op_add = Q ? Iop_Add8x16 : Iop_Add8x8;
4025 op_rev = Q ? Iop_Sar8x16 : Iop_Sar8x8;
4026 op_shrn = Q ? Iop_ShrN8x16 : Iop_ShrN8x8;
4027 op_shln = Q ? Iop_ShlN8x16 : Iop_ShlN8x8;
4028 break;
4029 case 1:
4030 op = Q ? Iop_QSal16x8 : Iop_QSal16x4;
sewardjd2664472010-08-22 12:44:20 +00004031 op_add = Q ? Iop_Add16x8 : Iop_Add16x4;
4032 op_rev = Q ? Iop_Sar16x8 : Iop_Sar16x4;
4033 op_shrn = Q ? Iop_ShrN16x8 : Iop_ShrN16x4;
4034 op_shln = Q ? Iop_ShlN16x8 : Iop_ShlN16x4;
4035 break;
4036 case 2:
4037 op = Q ? Iop_QSal32x4 : Iop_QSal32x2;
sewardjd2664472010-08-22 12:44:20 +00004038 op_add = Q ? Iop_Add32x4 : Iop_Add32x2;
4039 op_rev = Q ? Iop_Sar32x4 : Iop_Sar32x2;
4040 op_shrn = Q ? Iop_ShrN32x4 : Iop_ShrN32x2;
4041 op_shln = Q ? Iop_ShlN32x4 : Iop_ShlN32x2;
4042 break;
4043 case 3:
4044 op = Q ? Iop_QSal64x2 : Iop_QSal64x1;
sewardjd2664472010-08-22 12:44:20 +00004045 op_add = Q ? Iop_Add64x2 : Iop_Add64;
4046 op_rev = Q ? Iop_Sar64x2 : Iop_Sar64;
4047 op_shrn = Q ? Iop_ShrN64x2 : Iop_Shr64;
4048 op_shln = Q ? Iop_ShlN64x2 : Iop_Shl64;
4049 break;
4050 default:
4051 vassert(0);
4052 }
4053 }
4054 if (Q) {
4055 tmp = newTemp(Ity_V128);
4056 shval = newTemp(Ity_V128);
4057 mask = newTemp(Ity_V128);
4058 } else {
4059 tmp = newTemp(Ity_I64);
4060 shval = newTemp(Ity_I64);
4061 mask = newTemp(Ity_I64);
4062 }
4063 /* Only least significant byte from second argument is used.
4064 Copy this byte to the whole vector element. */
4065 assign(shval, binop(op_shrn,
4066 binop(op_shln,
4067 mkexpr(arg_n),
4068 mkU8((8 << size) - 8)),
4069 mkU8((8 << size) - 8)));
4070 for (i = 0; i < size; i++) {
4071 old_shval = shval;
4072 shval = newTemp(Q ? Ity_V128 : Ity_I64);
4073 assign(shval, binop(Q ? Iop_OrV128 : Iop_Or64,
4074 mkexpr(old_shval),
4075 binop(op_shln,
4076 mkexpr(old_shval),
4077 mkU8(8 << i))));
4078 }
4079 /* Compute the result */
4080 assign(round, binop(Q ? Iop_AndV128 : Iop_And64,
4081 binop(op,
4082 mkexpr(arg_m),
4083 binop(op_add,
4084 mkexpr(arg_n),
4085 mkexpr(imm_val))),
4086 binop(Q ? Iop_AndV128 : Iop_And64,
4087 mkexpr(imm_val),
4088 binop(cmp_gt,
4089 Q ? mkU128(0) : mkU64(0),
4090 mkexpr(arg_n)))));
4091 assign(res, binop(op_add,
4092 binop(op, mkexpr(arg_m), mkexpr(arg_n)),
4093 mkexpr(round)));
4094#ifndef DISABLE_QC_FLAG
4095 /* If shift is greater or equal to the element size and element is
4096 non-zero, then QC flag should be set. */
4097 esize = (8 << size) - 1;
4098 esize = (esize << 8) | esize;
4099 esize = (esize << 16) | esize;
4100 esize = (esize << 32) | esize;
4101 setFlag_QC(binop(Q ? Iop_AndV128 : Iop_And64,
4102 binop(cmp_gt, mkexpr(shval),
4103 Q ? mkU128(esize) : mkU64(esize)),
4104 unop(cmp_neq, mkexpr(arg_m))),
4105 Q ? mkU128(0) : mkU64(0),
4106 Q, condT);
4107 /* Othervise QC flag should be set if shift value is positive and
4108 result beign rightshifted the same value is not equal to left
4109 argument. */
4110 assign(mask, binop(cmp_gt, mkexpr(shval),
4111 Q ? mkU128(0) : mkU64(0)));
4112 if (!Q && size == 3)
4113 assign(tmp, binop(op_rev, mkexpr(res),
4114 unop(Iop_64to8, mkexpr(arg_n))));
4115 else
4116 assign(tmp, binop(op_rev, mkexpr(res), mkexpr(arg_n)));
4117 setFlag_QC(binop(Q ? Iop_AndV128 : Iop_And64,
4118 mkexpr(tmp), mkexpr(mask)),
4119 binop(Q ? Iop_AndV128 : Iop_And64,
4120 mkexpr(arg_m), mkexpr(mask)),
4121 Q, condT);
4122#endif
4123 DIP("vqrshl.%c%u %c%u, %c%u, %c%u\n",
4124 U ? 'u' : 's', 8 << size,
4125 Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', mreg, Q ? 'q' : 'd',
4126 nreg);
4127 }
4128 break;
4129 case 6:
4130 /* VMAX, VMIN */
4131 if (B == 0) {
4132 /* VMAX */
4133 IROp op;
4134 if (U == 0) {
4135 switch (size) {
4136 case 0: op = Q ? Iop_Max8Sx16 : Iop_Max8Sx8; break;
4137 case 1: op = Q ? Iop_Max16Sx8 : Iop_Max16Sx4; break;
4138 case 2: op = Q ? Iop_Max32Sx4 : Iop_Max32Sx2; break;
4139 case 3: return False;
4140 default: vassert(0);
4141 }
4142 } else {
4143 switch (size) {
4144 case 0: op = Q ? Iop_Max8Ux16 : Iop_Max8Ux8; break;
4145 case 1: op = Q ? Iop_Max16Ux8 : Iop_Max16Ux4; break;
4146 case 2: op = Q ? Iop_Max32Ux4 : Iop_Max32Ux2; break;
4147 case 3: return False;
4148 default: vassert(0);
4149 }
4150 }
4151 assign(res, binop(op, mkexpr(arg_n), mkexpr(arg_m)));
4152 DIP("vmax.%c%u %c%u, %c%u, %c%u\n",
4153 U ? 'u' : 's', 8 << size,
4154 Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', nreg, Q ? 'q' : 'd',
4155 mreg);
4156 } else {
4157 /* VMIN */
4158 IROp op;
4159 if (U == 0) {
4160 switch (size) {
4161 case 0: op = Q ? Iop_Min8Sx16 : Iop_Min8Sx8; break;
4162 case 1: op = Q ? Iop_Min16Sx8 : Iop_Min16Sx4; break;
4163 case 2: op = Q ? Iop_Min32Sx4 : Iop_Min32Sx2; break;
4164 case 3: return False;
4165 default: vassert(0);
4166 }
4167 } else {
4168 switch (size) {
sewardjb0d80ea2010-10-06 20:47:22 +00004169 case 0: op = Q ? Iop_Min8Ux16 : Iop_Min8Ux8; break;
4170 case 1: op = Q ? Iop_Min16Ux8 : Iop_Min16Ux4; break;
4171 case 2: op = Q ? Iop_Min32Ux4 : Iop_Min32Ux2; break;
sewardjd2664472010-08-22 12:44:20 +00004172 case 3: return False;
4173 default: vassert(0);
4174 }
4175 }
4176 assign(res, binop(op, mkexpr(arg_n), mkexpr(arg_m)));
4177 DIP("vmin.%c%u %c%u, %c%u, %c%u\n",
4178 U ? 'u' : 's', 8 << size,
4179 Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', nreg, Q ? 'q' : 'd',
4180 mreg);
4181 }
4182 break;
4183 case 7:
4184 if (B == 0) {
4185 /* VABD */
4186 IROp op_cmp, op_sub;
4187 IRTemp cond;
4188 if ((theInstr >> 23) & 1) {
4189 vpanic("VABDL should not be in dis_neon_data_3same\n");
4190 }
4191 if (Q) {
4192 switch (size) {
4193 case 0:
4194 op_cmp = U ? Iop_CmpGT8Ux16 : Iop_CmpGT8Sx16;
4195 op_sub = Iop_Sub8x16;
4196 break;
4197 case 1:
4198 op_cmp = U ? Iop_CmpGT16Ux8 : Iop_CmpGT16Sx8;
4199 op_sub = Iop_Sub16x8;
4200 break;
4201 case 2:
4202 op_cmp = U ? Iop_CmpGT32Ux4 : Iop_CmpGT32Sx4;
4203 op_sub = Iop_Sub32x4;
4204 break;
4205 case 3:
4206 return False;
4207 default:
4208 vassert(0);
4209 }
4210 } else {
4211 switch (size) {
4212 case 0:
4213 op_cmp = U ? Iop_CmpGT8Ux8 : Iop_CmpGT8Sx8;
4214 op_sub = Iop_Sub8x8;
4215 break;
4216 case 1:
4217 op_cmp = U ? Iop_CmpGT16Ux4 : Iop_CmpGT16Sx4;
4218 op_sub = Iop_Sub16x4;
4219 break;
4220 case 2:
4221 op_cmp = U ? Iop_CmpGT32Ux2 : Iop_CmpGT32Sx2;
4222 op_sub = Iop_Sub32x2;
4223 break;
4224 case 3:
4225 return False;
4226 default:
4227 vassert(0);
4228 }
4229 }
4230 if (Q) {
4231 cond = newTemp(Ity_V128);
4232 } else {
4233 cond = newTemp(Ity_I64);
4234 }
4235 assign(cond, binop(op_cmp, mkexpr(arg_n), mkexpr(arg_m)));
4236 assign(res, binop(Q ? Iop_OrV128 : Iop_Or64,
4237 binop(Q ? Iop_AndV128 : Iop_And64,
4238 binop(op_sub, mkexpr(arg_n),
4239 mkexpr(arg_m)),
4240 mkexpr(cond)),
4241 binop(Q ? Iop_AndV128 : Iop_And64,
4242 binop(op_sub, mkexpr(arg_m),
4243 mkexpr(arg_n)),
4244 unop(Q ? Iop_NotV128 : Iop_Not64,
4245 mkexpr(cond)))));
4246 DIP("vabd.%c%u %c%u, %c%u, %c%u\n",
4247 U ? 'u' : 's', 8 << size,
4248 Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', nreg, Q ? 'q' : 'd',
4249 mreg);
4250 } else {
4251 /* VABA */
4252 IROp op_cmp, op_sub, op_add;
4253 IRTemp cond, acc, tmp;
4254 if ((theInstr >> 23) & 1) {
4255 vpanic("VABAL should not be in dis_neon_data_3same");
4256 }
4257 if (Q) {
4258 switch (size) {
4259 case 0:
4260 op_cmp = U ? Iop_CmpGT8Ux16 : Iop_CmpGT8Sx16;
4261 op_sub = Iop_Sub8x16;
4262 op_add = Iop_Add8x16;
4263 break;
4264 case 1:
4265 op_cmp = U ? Iop_CmpGT16Ux8 : Iop_CmpGT16Sx8;
4266 op_sub = Iop_Sub16x8;
4267 op_add = Iop_Add16x8;
4268 break;
4269 case 2:
4270 op_cmp = U ? Iop_CmpGT32Ux4 : Iop_CmpGT32Sx4;
4271 op_sub = Iop_Sub32x4;
4272 op_add = Iop_Add32x4;
4273 break;
4274 case 3:
4275 return False;
4276 default:
4277 vassert(0);
4278 }
4279 } else {
4280 switch (size) {
4281 case 0:
4282 op_cmp = U ? Iop_CmpGT8Ux8 : Iop_CmpGT8Sx8;
4283 op_sub = Iop_Sub8x8;
4284 op_add = Iop_Add8x8;
4285 break;
4286 case 1:
4287 op_cmp = U ? Iop_CmpGT16Ux4 : Iop_CmpGT16Sx4;
4288 op_sub = Iop_Sub16x4;
4289 op_add = Iop_Add16x4;
4290 break;
4291 case 2:
4292 op_cmp = U ? Iop_CmpGT32Ux2 : Iop_CmpGT32Sx2;
4293 op_sub = Iop_Sub32x2;
4294 op_add = Iop_Add32x2;
4295 break;
4296 case 3:
4297 return False;
4298 default:
4299 vassert(0);
4300 }
4301 }
4302 if (Q) {
4303 cond = newTemp(Ity_V128);
4304 acc = newTemp(Ity_V128);
4305 tmp = newTemp(Ity_V128);
4306 assign(acc, getQReg(dreg));
4307 } else {
4308 cond = newTemp(Ity_I64);
4309 acc = newTemp(Ity_I64);
4310 tmp = newTemp(Ity_I64);
4311 assign(acc, getDRegI64(dreg));
4312 }
4313 assign(cond, binop(op_cmp, mkexpr(arg_n), mkexpr(arg_m)));
4314 assign(tmp, binop(Q ? Iop_OrV128 : Iop_Or64,
4315 binop(Q ? Iop_AndV128 : Iop_And64,
4316 binop(op_sub, mkexpr(arg_n),
4317 mkexpr(arg_m)),
4318 mkexpr(cond)),
4319 binop(Q ? Iop_AndV128 : Iop_And64,
4320 binop(op_sub, mkexpr(arg_m),
4321 mkexpr(arg_n)),
4322 unop(Q ? Iop_NotV128 : Iop_Not64,
4323 mkexpr(cond)))));
4324 assign(res, binop(op_add, mkexpr(acc), mkexpr(tmp)));
4325 DIP("vaba.%c%u %c%u, %c%u, %c%u\n",
4326 U ? 'u' : 's', 8 << size,
4327 Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', nreg, Q ? 'q' : 'd',
4328 mreg);
4329 }
4330 break;
4331 case 8:
4332 if (B == 0) {
4333 IROp op;
4334 if (U == 0) {
4335 /* VADD */
4336 switch (size) {
4337 case 0: op = Q ? Iop_Add8x16 : Iop_Add8x8; break;
4338 case 1: op = Q ? Iop_Add16x8 : Iop_Add16x4; break;
4339 case 2: op = Q ? Iop_Add32x4 : Iop_Add32x2; break;
4340 case 3: op = Q ? Iop_Add64x2 : Iop_Add64; break;
4341 default: vassert(0);
4342 }
4343 DIP("vadd.i%u %c%u, %c%u, %c%u\n",
4344 8 << size, Q ? 'q' : 'd',
4345 dreg, Q ? 'q' : 'd', nreg, Q ? 'q' : 'd', mreg);
4346 } else {
4347 /* VSUB */
4348 switch (size) {
4349 case 0: op = Q ? Iop_Sub8x16 : Iop_Sub8x8; break;
4350 case 1: op = Q ? Iop_Sub16x8 : Iop_Sub16x4; break;
4351 case 2: op = Q ? Iop_Sub32x4 : Iop_Sub32x2; break;
4352 case 3: op = Q ? Iop_Sub64x2 : Iop_Sub64; break;
4353 default: vassert(0);
4354 }
4355 DIP("vsub.i%u %c%u, %c%u, %c%u\n",
4356 8 << size, Q ? 'q' : 'd',
4357 dreg, Q ? 'q' : 'd', nreg, Q ? 'q' : 'd', mreg);
4358 }
4359 assign(res, binop(op, mkexpr(arg_n), mkexpr(arg_m)));
4360 } else {
4361 IROp op;
4362 switch (size) {
4363 case 0: op = Q ? Iop_CmpNEZ8x16 : Iop_CmpNEZ8x8; break;
4364 case 1: op = Q ? Iop_CmpNEZ16x8 : Iop_CmpNEZ16x4; break;
4365 case 2: op = Q ? Iop_CmpNEZ32x4 : Iop_CmpNEZ32x2; break;
4366 case 3: op = Q ? Iop_CmpNEZ64x2 : Iop_CmpwNEZ64; break;
4367 default: vassert(0);
4368 }
4369 if (U == 0) {
4370 /* VTST */
4371 assign(res, unop(op, binop(Q ? Iop_AndV128 : Iop_And64,
4372 mkexpr(arg_n),
4373 mkexpr(arg_m))));
4374 DIP("vtst.%u %c%u, %c%u, %c%u\n",
4375 8 << size, Q ? 'q' : 'd',
4376 dreg, Q ? 'q' : 'd', nreg, Q ? 'q' : 'd', mreg);
4377 } else {
4378 /* VCEQ */
4379 assign(res, unop(Q ? Iop_NotV128 : Iop_Not64,
4380 unop(op,
4381 binop(Q ? Iop_XorV128 : Iop_Xor64,
4382 mkexpr(arg_n),
4383 mkexpr(arg_m)))));
4384 DIP("vceq.i%u %c%u, %c%u, %c%u\n",
4385 8 << size, Q ? 'q' : 'd',
4386 dreg, Q ? 'q' : 'd', nreg, Q ? 'q' : 'd', mreg);
4387 }
4388 }
4389 break;
4390 case 9:
4391 if (B == 0) {
4392 /* VMLA, VMLS (integer) */
4393 IROp op, op2;
4394 UInt P = (theInstr >> 24) & 1;
4395 if (P) {
4396 switch (size) {
4397 case 0:
4398 op = Q ? Iop_Mul8x16 : Iop_Mul8x8;
4399 op2 = Q ? Iop_Sub8x16 : Iop_Sub8x8;
4400 break;
4401 case 1:
4402 op = Q ? Iop_Mul16x8 : Iop_Mul16x4;
4403 op2 = Q ? Iop_Sub16x8 : Iop_Sub16x4;
4404 break;
4405 case 2:
4406 op = Q ? Iop_Mul32x4 : Iop_Mul32x2;
4407 op2 = Q ? Iop_Sub32x4 : Iop_Sub32x2;
4408 break;
4409 case 3:
4410 return False;
4411 default:
4412 vassert(0);
4413 }
4414 } else {
4415 switch (size) {
4416 case 0:
4417 op = Q ? Iop_Mul8x16 : Iop_Mul8x8;
4418 op2 = Q ? Iop_Add8x16 : Iop_Add8x8;
4419 break;
4420 case 1:
4421 op = Q ? Iop_Mul16x8 : Iop_Mul16x4;
4422 op2 = Q ? Iop_Add16x8 : Iop_Add16x4;
4423 break;
4424 case 2:
4425 op = Q ? Iop_Mul32x4 : Iop_Mul32x2;
4426 op2 = Q ? Iop_Add32x4 : Iop_Add32x2;
4427 break;
4428 case 3:
4429 return False;
4430 default:
4431 vassert(0);
4432 }
4433 }
4434 assign(res, binop(op2,
4435 Q ? getQReg(dreg) : getDRegI64(dreg),
4436 binop(op, mkexpr(arg_n), mkexpr(arg_m))));
4437 DIP("vml%c.i%u %c%u, %c%u, %c%u\n",
4438 P ? 's' : 'a', 8 << size,
4439 Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', nreg, Q ? 'q' : 'd',
4440 mreg);
4441 } else {
4442 /* VMUL */
4443 IROp op;
4444 UInt P = (theInstr >> 24) & 1;
4445 if (P) {
4446 switch (size) {
4447 case 0:
4448 op = Q ? Iop_PolynomialMul8x16 : Iop_PolynomialMul8x8;
4449 break;
4450 case 1: case 2: case 3: return False;
4451 default: vassert(0);
4452 }
4453 } else {
4454 switch (size) {
4455 case 0: op = Q ? Iop_Mul8x16 : Iop_Mul8x8; break;
4456 case 1: op = Q ? Iop_Mul16x8 : Iop_Mul16x4; break;
4457 case 2: op = Q ? Iop_Mul32x4 : Iop_Mul32x2; break;
4458 case 3: return False;
4459 default: vassert(0);
4460 }
4461 }
4462 assign(res, binop(op, mkexpr(arg_n), mkexpr(arg_m)));
4463 DIP("vmul.%c%u %c%u, %c%u, %c%u\n",
4464 P ? 'p' : 'i', 8 << size,
4465 Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', nreg, Q ? 'q' : 'd',
4466 mreg);
4467 }
4468 break;
4469 case 10: {
4470 /* VPMAX, VPMIN */
4471 UInt P = (theInstr >> 4) & 1;
4472 IROp op;
4473 if (Q)
4474 return False;
4475 if (P) {
4476 switch (size) {
4477 case 0: op = U ? Iop_PwMin8Ux8 : Iop_PwMin8Sx8; break;
4478 case 1: op = U ? Iop_PwMin16Ux4 : Iop_PwMin16Sx4; break;
4479 case 2: op = U ? Iop_PwMin32Ux2 : Iop_PwMin32Sx2; break;
4480 case 3: return False;
4481 default: vassert(0);
4482 }
4483 } else {
4484 switch (size) {
4485 case 0: op = U ? Iop_PwMax8Ux8 : Iop_PwMax8Sx8; break;
4486 case 1: op = U ? Iop_PwMax16Ux4 : Iop_PwMax16Sx4; break;
4487 case 2: op = U ? Iop_PwMax32Ux2 : Iop_PwMax32Sx2; break;
4488 case 3: return False;
4489 default: vassert(0);
4490 }
4491 }
4492 assign(res, binop(op, mkexpr(arg_n), mkexpr(arg_m)));
4493 DIP("vp%s.%c%u %c%u, %c%u, %c%u\n",
4494 P ? "min" : "max", U ? 'u' : 's',
4495 8 << size, Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', nreg,
4496 Q ? 'q' : 'd', mreg);
4497 break;
4498 }
4499 case 11:
4500 if (B == 0) {
4501 if (U == 0) {
4502 /* VQDMULH */
4503 IROp op ,op2;
4504 ULong imm;
4505 switch (size) {
4506 case 0: case 3:
4507 return False;
4508 case 1:
4509 op = Q ? Iop_QDMulHi16Sx8 : Iop_QDMulHi16Sx4;
4510 op2 = Q ? Iop_CmpEQ16x8 : Iop_CmpEQ16x4;
4511 imm = 1LL << 15;
4512 imm = (imm << 16) | imm;
4513 imm = (imm << 32) | imm;
4514 break;
4515 case 2:
4516 op = Q ? Iop_QDMulHi32Sx4 : Iop_QDMulHi32Sx2;
4517 op2 = Q ? Iop_CmpEQ32x4 : Iop_CmpEQ32x2;
4518 imm = 1LL << 31;
4519 imm = (imm << 32) | imm;
4520 break;
4521 default:
4522 vassert(0);
4523 }
4524 assign(res, binop(op, mkexpr(arg_n), mkexpr(arg_m)));
4525#ifndef DISABLE_QC_FLAG
4526 setFlag_QC(binop(Q ? Iop_AndV128 : Iop_And64,
4527 binop(op2, mkexpr(arg_n),
4528 Q ? mkU128(imm) : mkU64(imm)),
4529 binop(op2, mkexpr(arg_m),
4530 Q ? mkU128(imm) : mkU64(imm))),
4531 Q ? mkU128(0) : mkU64(0),
4532 Q, condT);
4533#endif
4534 DIP("vqdmulh.s%u %c%u, %c%u, %c%u\n",
4535 8 << size, Q ? 'q' : 'd',
4536 dreg, Q ? 'q' : 'd', nreg, Q ? 'q' : 'd', mreg);
4537 } else {
4538 /* VQRDMULH */
4539 IROp op ,op2;
4540 ULong imm;
4541 switch(size) {
4542 case 0: case 3:
4543 return False;
4544 case 1:
4545 imm = 1LL << 15;
4546 imm = (imm << 16) | imm;
4547 imm = (imm << 32) | imm;
4548 op = Q ? Iop_QRDMulHi16Sx8 : Iop_QRDMulHi16Sx4;
4549 op2 = Q ? Iop_CmpEQ16x8 : Iop_CmpEQ16x4;
4550 break;
4551 case 2:
4552 imm = 1LL << 31;
4553 imm = (imm << 32) | imm;
4554 op = Q ? Iop_QRDMulHi32Sx4 : Iop_QRDMulHi32Sx2;
4555 op2 = Q ? Iop_CmpEQ32x4 : Iop_CmpEQ32x2;
4556 break;
4557 default:
4558 vassert(0);
4559 }
4560 assign(res, binop(op, mkexpr(arg_n), mkexpr(arg_m)));
4561#ifndef DISABLE_QC_FLAG
4562 setFlag_QC(binop(Q ? Iop_AndV128 : Iop_And64,
4563 binop(op2, mkexpr(arg_n),
4564 Q ? mkU128(imm) : mkU64(imm)),
4565 binop(op2, mkexpr(arg_m),
4566 Q ? mkU128(imm) : mkU64(imm))),
4567 Q ? mkU128(0) : mkU64(0),
4568 Q, condT);
4569#endif
4570 DIP("vqrdmulh.s%u %c%u, %c%u, %c%u\n",
4571 8 << size, Q ? 'q' : 'd',
4572 dreg, Q ? 'q' : 'd', nreg, Q ? 'q' : 'd', mreg);
4573 }
4574 } else {
4575 if (U == 0) {
4576 /* VPADD */
4577 IROp op;
4578 if (Q)
4579 return False;
4580 switch (size) {
4581 case 0: op = Q ? Iop_PwAdd8x16 : Iop_PwAdd8x8; break;
4582 case 1: op = Q ? Iop_PwAdd16x8 : Iop_PwAdd16x4; break;
4583 case 2: op = Q ? Iop_PwAdd32x4 : Iop_PwAdd32x2; break;
4584 case 3: return False;
4585 default: vassert(0);
4586 }
4587 assign(res, binop(op, mkexpr(arg_n), mkexpr(arg_m)));
4588 DIP("vpadd.i%d %c%u, %c%u, %c%u\n",
4589 8 << size, Q ? 'q' : 'd',
4590 dreg, Q ? 'q' : 'd', nreg, Q ? 'q' : 'd', mreg);
4591 }
4592 }
4593 break;
4594 /* Starting from here these are FP SIMD cases */
4595 case 13:
4596 if (B == 0) {
4597 IROp op;
4598 if (U == 0) {
4599 if ((C >> 1) == 0) {
4600 /* VADD */
4601 op = Q ? Iop_Add32Fx4 : Iop_Add32Fx2 ;
4602 DIP("vadd.f32 %c%u, %c%u, %c%u\n",
4603 Q ? 'q' : 'd', dreg,
4604 Q ? 'q' : 'd', nreg, Q ? 'q' : 'd', mreg);
4605 } else {
4606 /* VSUB */
4607 op = Q ? Iop_Sub32Fx4 : Iop_Sub32Fx2 ;
4608 DIP("vsub.f32 %c%u, %c%u, %c%u\n",
4609 Q ? 'q' : 'd', dreg,
4610 Q ? 'q' : 'd', nreg, Q ? 'q' : 'd', mreg);
4611 }
4612 } else {
4613 if ((C >> 1) == 0) {
4614 /* VPADD */
4615 if (Q)
4616 return False;
4617 op = Iop_PwAdd32Fx2;
4618 DIP("vpadd.f32 d%u, d%u, d%u\n", dreg, nreg, mreg);
4619 } else {
4620 /* VABD */
4621 if (Q) {
4622 assign(res, unop(Iop_Abs32Fx4,
4623 binop(Iop_Sub32Fx4,
4624 mkexpr(arg_n),
4625 mkexpr(arg_m))));
4626 } else {
4627 assign(res, unop(Iop_Abs32Fx2,
4628 binop(Iop_Sub32Fx2,
4629 mkexpr(arg_n),
4630 mkexpr(arg_m))));
4631 }
4632 DIP("vabd.f32 %c%u, %c%u, %c%u\n",
4633 Q ? 'q' : 'd', dreg,
4634 Q ? 'q' : 'd', nreg, Q ? 'q' : 'd', mreg);
4635 break;
4636 }
4637 }
4638 assign(res, binop(op, mkexpr(arg_n), mkexpr(arg_m)));
4639 } else {
4640 if (U == 0) {
4641 /* VMLA, VMLS */
4642 IROp op, op2;
4643 UInt P = (theInstr >> 21) & 1;
4644 if (P) {
4645 switch (size & 1) {
4646 case 0:
4647 op = Q ? Iop_Mul32Fx4 : Iop_Mul32Fx2;
4648 op2 = Q ? Iop_Sub32Fx4 : Iop_Sub32Fx2;
4649 break;
4650 case 1: return False;
4651 default: vassert(0);
4652 }
4653 } else {
4654 switch (size & 1) {
4655 case 0:
4656 op = Q ? Iop_Mul32Fx4 : Iop_Mul32Fx2;
4657 op2 = Q ? Iop_Add32Fx4 : Iop_Add32Fx2;
4658 break;
4659 case 1: return False;
4660 default: vassert(0);
4661 }
4662 }
4663 assign(res, binop(op2,
4664 Q ? getQReg(dreg) : getDRegI64(dreg),
4665 binop(op, mkexpr(arg_n), mkexpr(arg_m))));
4666
4667 DIP("vml%c.f32 %c%u, %c%u, %c%u\n",
4668 P ? 's' : 'a', Q ? 'q' : 'd',
4669 dreg, Q ? 'q' : 'd', nreg, Q ? 'q' : 'd', mreg);
4670 } else {
4671 /* VMUL */
4672 IROp op;
4673 if ((C >> 1) != 0)
4674 return False;
4675 op = Q ? Iop_Mul32Fx4 : Iop_Mul32Fx2 ;
4676 assign(res, binop(op, mkexpr(arg_n), mkexpr(arg_m)));
4677 DIP("vmul.f32 %c%u, %c%u, %c%u\n",
4678 Q ? 'q' : 'd', dreg,
4679 Q ? 'q' : 'd', nreg, Q ? 'q' : 'd', mreg);
4680 }
4681 }
4682 break;
4683 case 14:
4684 if (B == 0) {
4685 if (U == 0) {
4686 if ((C >> 1) == 0) {
4687 /* VCEQ */
4688 IROp op;
4689 if ((theInstr >> 20) & 1)
4690 return False;
4691 op = Q ? Iop_CmpEQ32Fx4 : Iop_CmpEQ32Fx2;
4692 assign(res, binop(op, mkexpr(arg_n), mkexpr(arg_m)));
4693 DIP("vceq.f32 %c%u, %c%u, %c%u\n",
4694 Q ? 'q' : 'd', dreg,
4695 Q ? 'q' : 'd', nreg, Q ? 'q' : 'd', mreg);
4696 } else {
4697 return False;
4698 }
4699 } else {
4700 if ((C >> 1) == 0) {
4701 /* VCGE */
4702 IROp op;
4703 if ((theInstr >> 20) & 1)
4704 return False;
4705 op = Q ? Iop_CmpGE32Fx4 : Iop_CmpGE32Fx2;
4706 assign(res, binop(op, mkexpr(arg_n), mkexpr(arg_m)));
4707 DIP("vcge.f32 %c%u, %c%u, %c%u\n",
4708 Q ? 'q' : 'd', dreg,
4709 Q ? 'q' : 'd', nreg, Q ? 'q' : 'd', mreg);
4710 } else {
4711 /* VCGT */
4712 IROp op;
4713 if ((theInstr >> 20) & 1)
4714 return False;
4715 op = Q ? Iop_CmpGT32Fx4 : Iop_CmpGT32Fx2;
4716 assign(res, binop(op, mkexpr(arg_n), mkexpr(arg_m)));
4717 DIP("vcgt.f32 %c%u, %c%u, %c%u\n",
4718 Q ? 'q' : 'd', dreg,
4719 Q ? 'q' : 'd', nreg, Q ? 'q' : 'd', mreg);
4720 }
4721 }
4722 } else {
4723 if (U == 1) {
4724 /* VACGE, VACGT */
4725 UInt op_bit = (theInstr >> 21) & 1;
4726 IROp op, op2;
4727 op2 = Q ? Iop_Abs32Fx4 : Iop_Abs32Fx2;
4728 if (op_bit) {
4729 op = Q ? Iop_CmpGT32Fx4 : Iop_CmpGT32Fx2;
4730 assign(res, binop(op,
4731 unop(op2, mkexpr(arg_n)),
4732 unop(op2, mkexpr(arg_m))));
4733 } else {
4734 op = Q ? Iop_CmpGE32Fx4 : Iop_CmpGE32Fx2;
4735 assign(res, binop(op,
4736 unop(op2, mkexpr(arg_n)),
4737 unop(op2, mkexpr(arg_m))));
4738 }
4739 DIP("vacg%c.f32 %c%u, %c%u, %c%u\n", op_bit ? 't' : 'e',
4740 Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', nreg,
4741 Q ? 'q' : 'd', mreg);
4742 }
4743 }
4744 break;
4745 case 15:
4746 if (B == 0) {
4747 if (U == 0) {
4748 /* VMAX, VMIN */
4749 IROp op;
4750 if ((theInstr >> 20) & 1)
4751 return False;
4752 if ((theInstr >> 21) & 1) {
4753 op = Q ? Iop_Min32Fx4 : Iop_Min32Fx2;
4754 DIP("vmin.f32 %c%u, %c%u, %c%u\n", Q ? 'q' : 'd', dreg,
4755 Q ? 'q' : 'd', nreg, Q ? 'q' : 'd', mreg);
4756 } else {
4757 op = Q ? Iop_Max32Fx4 : Iop_Max32Fx2;
4758 DIP("vmax.f32 %c%u, %c%u, %c%u\n", Q ? 'q' : 'd', dreg,
4759 Q ? 'q' : 'd', nreg, Q ? 'q' : 'd', mreg);
4760 }
4761 assign(res, binop(op, mkexpr(arg_n), mkexpr(arg_m)));
4762 } else {
4763 /* VPMAX, VPMIN */
4764 IROp op;
4765 if (Q)
4766 return False;
4767 if ((theInstr >> 20) & 1)
4768 return False;
4769 if ((theInstr >> 21) & 1) {
4770 op = Iop_PwMin32Fx2;
4771 DIP("vpmin.f32 d%u, d%u, d%u\n", dreg, nreg, mreg);
4772 } else {
4773 op = Iop_PwMax32Fx2;
4774 DIP("vpmax.f32 d%u, d%u, d%u\n", dreg, nreg, mreg);
4775 }
4776 assign(res, binop(op, mkexpr(arg_n), mkexpr(arg_m)));
4777 }
4778 } else {
4779 if (U == 0) {
4780 if ((C >> 1) == 0) {
4781 /* VRECPS */
4782 if ((theInstr >> 20) & 1)
4783 return False;
4784 assign(res, binop(Q ? Iop_Recps32Fx4 : Iop_Recps32Fx2,
4785 mkexpr(arg_n),
4786 mkexpr(arg_m)));
4787 DIP("vrecps.f32 %c%u, %c%u, %c%u\n", Q ? 'q' : 'd', dreg,
4788 Q ? 'q' : 'd', nreg, Q ? 'q' : 'd', mreg);
4789 } else {
4790 /* VRSQRTS */
4791 if ((theInstr >> 20) & 1)
4792 return False;
4793 assign(res, binop(Q ? Iop_Rsqrts32Fx4 : Iop_Rsqrts32Fx2,
4794 mkexpr(arg_n),
4795 mkexpr(arg_m)));
4796 DIP("vrsqrts.f32 %c%u, %c%u, %c%u\n", Q ? 'q' : 'd', dreg,
4797 Q ? 'q' : 'd', nreg, Q ? 'q' : 'd', mreg);
4798 }
4799 }
4800 }
4801 break;
4802 }
4803
4804 if (Q) {
4805 putQReg(dreg, mkexpr(res), condT);
4806 } else {
4807 putDRegI64(dreg, mkexpr(res), condT);
4808 }
4809
4810 return True;
4811}
4812
4813/* A7.4.2 Three registers of different length */
4814static
4815Bool dis_neon_data_3diff ( UInt theInstr, IRTemp condT )
4816{
4817 UInt A = (theInstr >> 8) & 0xf;
4818 UInt B = (theInstr >> 20) & 3;
4819 UInt U = (theInstr >> 24) & 1;
4820 UInt P = (theInstr >> 9) & 1;
4821 UInt mreg = get_neon_m_regno(theInstr);
4822 UInt nreg = get_neon_n_regno(theInstr);
4823 UInt dreg = get_neon_d_regno(theInstr);
4824 UInt size = B;
4825 ULong imm;
4826 IRTemp res, arg_m, arg_n, cond, tmp;
4827 IROp cvt, cvt2, cmp, op, op2, sh, add;
4828 switch (A) {
4829 case 0: case 1: case 2: case 3:
4830 /* VADDL, VADDW, VSUBL, VSUBW */
4831 if (dreg & 1)
4832 return False;
4833 dreg >>= 1;
4834 size = B;
4835 switch (size) {
4836 case 0:
sewardj5f438dd2011-06-16 11:36:23 +00004837 cvt = U ? Iop_Widen8Uto16x8 : Iop_Widen8Sto16x8;
sewardjd2664472010-08-22 12:44:20 +00004838 op = (A & 2) ? Iop_Sub16x8 : Iop_Add16x8;
4839 break;
4840 case 1:
sewardj5f438dd2011-06-16 11:36:23 +00004841 cvt = U ? Iop_Widen16Uto32x4 : Iop_Widen16Sto32x4;
sewardjd2664472010-08-22 12:44:20 +00004842 op = (A & 2) ? Iop_Sub32x4 : Iop_Add32x4;
4843 break;
4844 case 2:
sewardj5f438dd2011-06-16 11:36:23 +00004845 cvt = U ? Iop_Widen32Uto64x2 : Iop_Widen32Sto64x2;
sewardjd2664472010-08-22 12:44:20 +00004846 op = (A & 2) ? Iop_Sub64x2 : Iop_Add64x2;
4847 break;
4848 case 3:
4849 return False;
4850 default:
4851 vassert(0);
4852 }
4853 arg_n = newTemp(Ity_V128);
4854 arg_m = newTemp(Ity_V128);
4855 if (A & 1) {
4856 if (nreg & 1)
4857 return False;
4858 nreg >>= 1;
4859 assign(arg_n, getQReg(nreg));
4860 } else {
4861 assign(arg_n, unop(cvt, getDRegI64(nreg)));
4862 }
4863 assign(arg_m, unop(cvt, getDRegI64(mreg)));
4864 putQReg(dreg, binop(op, mkexpr(arg_n), mkexpr(arg_m)),
4865 condT);
4866 DIP("v%s%c.%c%u q%u, %c%u, d%u\n", (A & 2) ? "sub" : "add",
4867 (A & 1) ? 'w' : 'l', U ? 'u' : 's', 8 << size, dreg,
4868 (A & 1) ? 'q' : 'd', nreg, mreg);
4869 return True;
4870 case 4:
4871 /* VADDHN, VRADDHN */
4872 if (mreg & 1)
4873 return False;
4874 mreg >>= 1;
4875 if (nreg & 1)
4876 return False;
4877 nreg >>= 1;
4878 size = B;
4879 switch (size) {
4880 case 0:
4881 op = Iop_Add16x8;
sewardj5f438dd2011-06-16 11:36:23 +00004882 cvt = Iop_NarrowUn16to8x8;
sewardjd2664472010-08-22 12:44:20 +00004883 sh = Iop_ShrN16x8;
4884 imm = 1U << 7;
4885 imm = (imm << 16) | imm;
4886 imm = (imm << 32) | imm;
4887 break;
4888 case 1:
4889 op = Iop_Add32x4;
sewardj5f438dd2011-06-16 11:36:23 +00004890 cvt = Iop_NarrowUn32to16x4;
sewardjd2664472010-08-22 12:44:20 +00004891 sh = Iop_ShrN32x4;
4892 imm = 1U << 15;
4893 imm = (imm << 32) | imm;
4894 break;
4895 case 2:
4896 op = Iop_Add64x2;
sewardj5f438dd2011-06-16 11:36:23 +00004897 cvt = Iop_NarrowUn64to32x2;
sewardjd2664472010-08-22 12:44:20 +00004898 sh = Iop_ShrN64x2;
4899 imm = 1U << 31;
4900 break;
4901 case 3:
4902 return False;
4903 default:
4904 vassert(0);
4905 }
4906 tmp = newTemp(Ity_V128);
4907 res = newTemp(Ity_V128);
4908 assign(tmp, binop(op, getQReg(nreg), getQReg(mreg)));
4909 if (U) {
4910 /* VRADDHN */
4911 assign(res, binop(op, mkexpr(tmp),
4912 binop(Iop_64HLtoV128, mkU64(imm), mkU64(imm))));
4913 } else {
4914 assign(res, mkexpr(tmp));
4915 }
4916 putDRegI64(dreg, unop(cvt, binop(sh, mkexpr(res), mkU8(8 << size))),
4917 condT);
4918 DIP("v%saddhn.i%u d%u, q%u, q%u\n", U ? "r" : "", 16 << size, dreg,
4919 nreg, mreg);
4920 return True;
4921 case 5:
4922 /* VABAL */
4923 if (!((theInstr >> 23) & 1)) {
4924 vpanic("VABA should not be in dis_neon_data_3diff\n");
4925 }
4926 if (dreg & 1)
4927 return False;
4928 dreg >>= 1;
4929 switch (size) {
4930 case 0:
4931 cmp = U ? Iop_CmpGT8Ux8 : Iop_CmpGT8Sx8;
sewardj5f438dd2011-06-16 11:36:23 +00004932 cvt = U ? Iop_Widen8Uto16x8 : Iop_Widen8Sto16x8;
4933 cvt2 = Iop_Widen8Sto16x8;
sewardjd2664472010-08-22 12:44:20 +00004934 op = Iop_Sub16x8;
4935 op2 = Iop_Add16x8;
4936 break;
4937 case 1:
4938 cmp = U ? Iop_CmpGT16Ux4 : Iop_CmpGT16Sx4;
sewardj5f438dd2011-06-16 11:36:23 +00004939 cvt = U ? Iop_Widen16Uto32x4 : Iop_Widen16Sto32x4;
4940 cvt2 = Iop_Widen16Sto32x4;
sewardjd2664472010-08-22 12:44:20 +00004941 op = Iop_Sub32x4;
4942 op2 = Iop_Add32x4;
4943 break;
4944 case 2:
4945 cmp = U ? Iop_CmpGT32Ux2 : Iop_CmpGT32Sx2;
sewardj5f438dd2011-06-16 11:36:23 +00004946 cvt = U ? Iop_Widen32Uto64x2 : Iop_Widen32Sto64x2;
4947 cvt2 = Iop_Widen32Sto64x2;
sewardjd2664472010-08-22 12:44:20 +00004948 op = Iop_Sub64x2;
4949 op2 = Iop_Add64x2;
4950 break;
4951 case 3:
4952 return False;
4953 default:
4954 vassert(0);
4955 }
4956 arg_n = newTemp(Ity_V128);
4957 arg_m = newTemp(Ity_V128);
4958 cond = newTemp(Ity_V128);
4959 res = newTemp(Ity_V128);
4960 assign(arg_n, unop(cvt, getDRegI64(nreg)));
4961 assign(arg_m, unop(cvt, getDRegI64(mreg)));
4962 assign(cond, unop(cvt2, binop(cmp, getDRegI64(nreg),
4963 getDRegI64(mreg))));
4964 assign(res, binop(op2,
4965 binop(Iop_OrV128,
4966 binop(Iop_AndV128,
4967 binop(op, mkexpr(arg_n), mkexpr(arg_m)),
4968 mkexpr(cond)),
4969 binop(Iop_AndV128,
4970 binop(op, mkexpr(arg_m), mkexpr(arg_n)),
4971 unop(Iop_NotV128, mkexpr(cond)))),
4972 getQReg(dreg)));
4973 putQReg(dreg, mkexpr(res), condT);
4974 DIP("vabal.%c%u q%u, d%u, d%u\n", U ? 'u' : 's', 8 << size, dreg,
4975 nreg, mreg);
4976 return True;
4977 case 6:
4978 /* VSUBHN, VRSUBHN */
4979 if (mreg & 1)
4980 return False;
4981 mreg >>= 1;
4982 if (nreg & 1)
4983 return False;
4984 nreg >>= 1;
4985 size = B;
4986 switch (size) {
4987 case 0:
4988 op = Iop_Sub16x8;
4989 op2 = Iop_Add16x8;
sewardj5f438dd2011-06-16 11:36:23 +00004990 cvt = Iop_NarrowUn16to8x8;
sewardjd2664472010-08-22 12:44:20 +00004991 sh = Iop_ShrN16x8;
4992 imm = 1U << 7;
4993 imm = (imm << 16) | imm;
4994 imm = (imm << 32) | imm;
4995 break;
4996 case 1:
4997 op = Iop_Sub32x4;
4998 op2 = Iop_Add32x4;
sewardj5f438dd2011-06-16 11:36:23 +00004999 cvt = Iop_NarrowUn32to16x4;
sewardjd2664472010-08-22 12:44:20 +00005000 sh = Iop_ShrN32x4;
5001 imm = 1U << 15;
5002 imm = (imm << 32) | imm;
5003 break;
5004 case 2:
5005 op = Iop_Sub64x2;
5006 op2 = Iop_Add64x2;
sewardj5f438dd2011-06-16 11:36:23 +00005007 cvt = Iop_NarrowUn64to32x2;
sewardjd2664472010-08-22 12:44:20 +00005008 sh = Iop_ShrN64x2;
5009 imm = 1U << 31;
5010 break;
5011 case 3:
5012 return False;
5013 default:
5014 vassert(0);
5015 }
5016 tmp = newTemp(Ity_V128);
5017 res = newTemp(Ity_V128);
5018 assign(tmp, binop(op, getQReg(nreg), getQReg(mreg)));
5019 if (U) {
5020 /* VRSUBHN */
5021 assign(res, binop(op2, mkexpr(tmp),
5022 binop(Iop_64HLtoV128, mkU64(imm), mkU64(imm))));
5023 } else {
5024 assign(res, mkexpr(tmp));
5025 }
5026 putDRegI64(dreg, unop(cvt, binop(sh, mkexpr(res), mkU8(8 << size))),
5027 condT);
5028 DIP("v%ssubhn.i%u d%u, q%u, q%u\n", U ? "r" : "", 16 << size, dreg,
5029 nreg, mreg);
5030 return True;
5031 case 7:
5032 /* VABDL */
5033 if (!((theInstr >> 23) & 1)) {
5034 vpanic("VABL should not be in dis_neon_data_3diff\n");
5035 }
5036 if (dreg & 1)
5037 return False;
5038 dreg >>= 1;
5039 switch (size) {
5040 case 0:
5041 cmp = U ? Iop_CmpGT8Ux8 : Iop_CmpGT8Sx8;
sewardj5f438dd2011-06-16 11:36:23 +00005042 cvt = U ? Iop_Widen8Uto16x8 : Iop_Widen8Sto16x8;
5043 cvt2 = Iop_Widen8Sto16x8;
sewardjd2664472010-08-22 12:44:20 +00005044 op = Iop_Sub16x8;
5045 break;
5046 case 1:
5047 cmp = U ? Iop_CmpGT16Ux4 : Iop_CmpGT16Sx4;
sewardj5f438dd2011-06-16 11:36:23 +00005048 cvt = U ? Iop_Widen16Uto32x4 : Iop_Widen16Sto32x4;
5049 cvt2 = Iop_Widen16Sto32x4;
sewardjd2664472010-08-22 12:44:20 +00005050 op = Iop_Sub32x4;
5051 break;
5052 case 2:
5053 cmp = U ? Iop_CmpGT32Ux2 : Iop_CmpGT32Sx2;
sewardj5f438dd2011-06-16 11:36:23 +00005054 cvt = U ? Iop_Widen32Uto64x2 : Iop_Widen32Sto64x2;
5055 cvt2 = Iop_Widen32Sto64x2;
sewardjd2664472010-08-22 12:44:20 +00005056 op = Iop_Sub64x2;
5057 break;
5058 case 3:
5059 return False;
5060 default:
5061 vassert(0);
5062 }
5063 arg_n = newTemp(Ity_V128);
5064 arg_m = newTemp(Ity_V128);
5065 cond = newTemp(Ity_V128);
5066 res = newTemp(Ity_V128);
5067 assign(arg_n, unop(cvt, getDRegI64(nreg)));
5068 assign(arg_m, unop(cvt, getDRegI64(mreg)));
5069 assign(cond, unop(cvt2, binop(cmp, getDRegI64(nreg),
5070 getDRegI64(mreg))));
5071 assign(res, binop(Iop_OrV128,
5072 binop(Iop_AndV128,
5073 binop(op, mkexpr(arg_n), mkexpr(arg_m)),
5074 mkexpr(cond)),
5075 binop(Iop_AndV128,
5076 binop(op, mkexpr(arg_m), mkexpr(arg_n)),
5077 unop(Iop_NotV128, mkexpr(cond)))));
5078 putQReg(dreg, mkexpr(res), condT);
5079 DIP("vabdl.%c%u q%u, d%u, d%u\n", U ? 'u' : 's', 8 << size, dreg,
5080 nreg, mreg);
5081 return True;
5082 case 8:
5083 case 10:
5084 /* VMLAL, VMLSL (integer) */
5085 if (dreg & 1)
5086 return False;
5087 dreg >>= 1;
5088 size = B;
5089 switch (size) {
5090 case 0:
5091 op = U ? Iop_Mull8Ux8 : Iop_Mull8Sx8;
5092 op2 = P ? Iop_Sub16x8 : Iop_Add16x8;
5093 break;
5094 case 1:
5095 op = U ? Iop_Mull16Ux4 : Iop_Mull16Sx4;
5096 op2 = P ? Iop_Sub32x4 : Iop_Add32x4;
5097 break;
5098 case 2:
5099 op = U ? Iop_Mull32Ux2 : Iop_Mull32Sx2;
5100 op2 = P ? Iop_Sub64x2 : Iop_Add64x2;
5101 break;
5102 case 3:
5103 return False;
5104 default:
5105 vassert(0);
5106 }
5107 res = newTemp(Ity_V128);
5108 assign(res, binop(op, getDRegI64(nreg),getDRegI64(mreg)));
5109 putQReg(dreg, binop(op2, getQReg(dreg), mkexpr(res)), condT);
5110 DIP("vml%cl.%c%u q%u, d%u, d%u\n", P ? 's' : 'a', U ? 'u' : 's',
5111 8 << size, dreg, nreg, mreg);
5112 return True;
5113 case 9:
5114 case 11:
5115 /* VQDMLAL, VQDMLSL */
5116 if (U)
5117 return False;
5118 if (dreg & 1)
5119 return False;
5120 dreg >>= 1;
5121 size = B;
5122 switch (size) {
5123 case 0: case 3:
5124 return False;
5125 case 1:
5126 op = Iop_QDMulLong16Sx4;
5127 cmp = Iop_CmpEQ16x4;
5128 add = P ? Iop_QSub32Sx4 : Iop_QAdd32Sx4;
5129 op2 = P ? Iop_Sub32x4 : Iop_Add32x4;
5130 imm = 1LL << 15;
5131 imm = (imm << 16) | imm;
5132 imm = (imm << 32) | imm;
5133 break;
5134 case 2:
5135 op = Iop_QDMulLong32Sx2;
5136 cmp = Iop_CmpEQ32x2;
5137 add = P ? Iop_QSub64Sx2 : Iop_QAdd64Sx2;
5138 op2 = P ? Iop_Sub64x2 : Iop_Add64x2;
5139 imm = 1LL << 31;
5140 imm = (imm << 32) | imm;
5141 break;
5142 default:
5143 vassert(0);
5144 }
5145 res = newTemp(Ity_V128);
5146 tmp = newTemp(Ity_V128);
5147 assign(res, binop(op, getDRegI64(nreg), getDRegI64(mreg)));
5148#ifndef DISABLE_QC_FLAG
5149 assign(tmp, binop(op2, getQReg(dreg), mkexpr(res)));
5150 setFlag_QC(mkexpr(tmp), binop(add, getQReg(dreg), mkexpr(res)),
5151 True, condT);
5152 setFlag_QC(binop(Iop_And64,
5153 binop(cmp, getDRegI64(nreg), mkU64(imm)),
5154 binop(cmp, getDRegI64(mreg), mkU64(imm))),
5155 mkU64(0),
5156 False, condT);
5157#endif
5158 putQReg(dreg, binop(add, getQReg(dreg), mkexpr(res)), condT);
5159 DIP("vqdml%cl.s%u q%u, d%u, d%u\n", P ? 's' : 'a', 8 << size, dreg,
5160 nreg, mreg);
5161 return True;
5162 case 12:
5163 case 14:
5164 /* VMULL (integer or polynomial) */
5165 if (dreg & 1)
5166 return False;
5167 dreg >>= 1;
5168 size = B;
5169 switch (size) {
5170 case 0:
5171 op = (U) ? Iop_Mull8Ux8 : Iop_Mull8Sx8;
5172 if (P)
5173 op = Iop_PolynomialMull8x8;
5174 break;
5175 case 1:
5176 op = (U) ? Iop_Mull16Ux4 : Iop_Mull16Sx4;
5177 break;
5178 case 2:
5179 op = (U) ? Iop_Mull32Ux2 : Iop_Mull32Sx2;
5180 break;
5181 default:
5182 vassert(0);
5183 }
5184 putQReg(dreg, binop(op, getDRegI64(nreg),
5185 getDRegI64(mreg)), condT);
5186 DIP("vmull.%c%u q%u, d%u, d%u\n", P ? 'p' : (U ? 'u' : 's'),
5187 8 << size, dreg, nreg, mreg);
5188 return True;
5189 case 13:
5190 /* VQDMULL */
5191 if (U)
5192 return False;
5193 if (dreg & 1)
5194 return False;
5195 dreg >>= 1;
5196 size = B;
5197 switch (size) {
5198 case 0:
5199 case 3:
5200 return False;
5201 case 1:
5202 op = Iop_QDMulLong16Sx4;
5203 op2 = Iop_CmpEQ16x4;
5204 imm = 1LL << 15;
5205 imm = (imm << 16) | imm;
5206 imm = (imm << 32) | imm;
5207 break;
5208 case 2:
5209 op = Iop_QDMulLong32Sx2;
5210 op2 = Iop_CmpEQ32x2;
5211 imm = 1LL << 31;
5212 imm = (imm << 32) | imm;
5213 break;
5214 default:
5215 vassert(0);
5216 }
5217 putQReg(dreg, binop(op, getDRegI64(nreg), getDRegI64(mreg)),
5218 condT);
5219#ifndef DISABLE_QC_FLAG
5220 setFlag_QC(binop(Iop_And64,
5221 binop(op2, getDRegI64(nreg), mkU64(imm)),
5222 binop(op2, getDRegI64(mreg), mkU64(imm))),
5223 mkU64(0),
5224 False, condT);
5225#endif
5226 DIP("vqdmull.s%u q%u, d%u, d%u\n", 8 << size, dreg, nreg, mreg);
5227 return True;
5228 default:
5229 return False;
5230 }
5231 return False;
5232}
5233
5234/* A7.4.3 Two registers and a scalar */
5235static
5236Bool dis_neon_data_2reg_and_scalar ( UInt theInstr, IRTemp condT )
5237{
5238# define INSN(_bMax,_bMin) SLICE_UInt(theInstr, (_bMax), (_bMin))
5239 UInt U = INSN(24,24);
5240 UInt dreg = get_neon_d_regno(theInstr & ~(1 << 6));
5241 UInt nreg = get_neon_n_regno(theInstr & ~(1 << 6));
5242 UInt mreg = get_neon_m_regno(theInstr & ~(1 << 6));
5243 UInt size = INSN(21,20);
5244 UInt index;
5245 UInt Q = INSN(24,24);
5246
5247 if (INSN(27,25) != 1 || INSN(23,23) != 1
5248 || INSN(6,6) != 1 || INSN(4,4) != 0)
5249 return False;
5250
5251 /* VMLA, VMLS (scalar) */
5252 if ((INSN(11,8) & BITS4(1,0,1,0)) == BITS4(0,0,0,0)) {
5253 IRTemp res, arg_m, arg_n;
5254 IROp dup, get, op, op2, add, sub;
5255 if (Q) {
5256 if ((dreg & 1) || (nreg & 1))
5257 return False;
5258 dreg >>= 1;
5259 nreg >>= 1;
5260 res = newTemp(Ity_V128);
5261 arg_m = newTemp(Ity_V128);
5262 arg_n = newTemp(Ity_V128);
5263 assign(arg_n, getQReg(nreg));
5264 switch(size) {
5265 case 1:
5266 dup = Iop_Dup16x8;
5267 get = Iop_GetElem16x4;
5268 index = mreg >> 3;
5269 mreg &= 7;
5270 break;
5271 case 2:
5272 dup = Iop_Dup32x4;
5273 get = Iop_GetElem32x2;
5274 index = mreg >> 4;
5275 mreg &= 0xf;
5276 break;
5277 case 0:
5278 case 3:
5279 return False;
5280 default:
5281 vassert(0);
5282 }
5283 assign(arg_m, unop(dup, binop(get, getDRegI64(mreg), mkU8(index))));
5284 } else {
5285 res = newTemp(Ity_I64);
5286 arg_m = newTemp(Ity_I64);
5287 arg_n = newTemp(Ity_I64);
5288 assign(arg_n, getDRegI64(nreg));
5289 switch(size) {
5290 case 1:
5291 dup = Iop_Dup16x4;
5292 get = Iop_GetElem16x4;
5293 index = mreg >> 3;
5294 mreg &= 7;
5295 break;
5296 case 2:
5297 dup = Iop_Dup32x2;
5298 get = Iop_GetElem32x2;
5299 index = mreg >> 4;
5300 mreg &= 0xf;
5301 break;
5302 case 0:
5303 case 3:
5304 return False;
5305 default:
5306 vassert(0);
5307 }
5308 assign(arg_m, unop(dup, binop(get, getDRegI64(mreg), mkU8(index))));
5309 }
5310 if (INSN(8,8)) {
5311 switch (size) {
5312 case 2:
5313 op = Q ? Iop_Mul32Fx4 : Iop_Mul32Fx2;
5314 add = Q ? Iop_Add32Fx4 : Iop_Add32Fx2;
5315 sub = Q ? Iop_Sub32Fx4 : Iop_Sub32Fx2;
5316 break;
5317 case 0:
5318 case 1:
5319 case 3:
5320 return False;
5321 default:
5322 vassert(0);
5323 }
5324 } else {
5325 switch (size) {
5326 case 1:
5327 op = Q ? Iop_Mul16x8 : Iop_Mul16x4;
5328 add = Q ? Iop_Add16x8 : Iop_Add16x4;
5329 sub = Q ? Iop_Sub16x8 : Iop_Sub16x4;
5330 break;
5331 case 2:
5332 op = Q ? Iop_Mul32x4 : Iop_Mul32x2;
5333 add = Q ? Iop_Add32x4 : Iop_Add32x2;
5334 sub = Q ? Iop_Sub32x4 : Iop_Sub32x2;
5335 break;
5336 case 0:
5337 case 3:
5338 return False;
5339 default:
5340 vassert(0);
5341 }
5342 }
5343 op2 = INSN(10,10) ? sub : add;
5344 assign(res, binop(op, mkexpr(arg_n), mkexpr(arg_m)));
5345 if (Q)
5346 putQReg(dreg, binop(op2, getQReg(dreg), mkexpr(res)),
5347 condT);
5348 else
5349 putDRegI64(dreg, binop(op2, getDRegI64(dreg), mkexpr(res)),
5350 condT);
5351 DIP("vml%c.%c%u %c%u, %c%u, d%u[%u]\n", INSN(10,10) ? 's' : 'a',
5352 INSN(8,8) ? 'f' : 'i', 8 << size,
5353 Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', nreg, mreg, index);
5354 return True;
5355 }
5356
5357 /* VMLAL, VMLSL (scalar) */
5358 if ((INSN(11,8) & BITS4(1,0,1,1)) == BITS4(0,0,1,0)) {
5359 IRTemp res, arg_m, arg_n;
5360 IROp dup, get, op, op2, add, sub;
5361 if (dreg & 1)
5362 return False;
5363 dreg >>= 1;
5364 res = newTemp(Ity_V128);
5365 arg_m = newTemp(Ity_I64);
5366 arg_n = newTemp(Ity_I64);
5367 assign(arg_n, getDRegI64(nreg));
5368 switch(size) {
5369 case 1:
5370 dup = Iop_Dup16x4;
5371 get = Iop_GetElem16x4;
5372 index = mreg >> 3;
5373 mreg &= 7;
5374 break;
5375 case 2:
5376 dup = Iop_Dup32x2;
5377 get = Iop_GetElem32x2;
5378 index = mreg >> 4;
5379 mreg &= 0xf;
5380 break;
5381 case 0:
5382 case 3:
5383 return False;
5384 default:
5385 vassert(0);
5386 }
5387 assign(arg_m, unop(dup, binop(get, getDRegI64(mreg), mkU8(index))));
5388 switch (size) {
5389 case 1:
5390 op = U ? Iop_Mull16Ux4 : Iop_Mull16Sx4;
5391 add = Iop_Add32x4;
5392 sub = Iop_Sub32x4;
5393 break;
5394 case 2:
5395 op = U ? Iop_Mull32Ux2 : Iop_Mull32Sx2;
5396 add = Iop_Add64x2;
5397 sub = Iop_Sub64x2;
5398 break;
5399 case 0:
5400 case 3:
5401 return False;
5402 default:
5403 vassert(0);
5404 }
5405 op2 = INSN(10,10) ? sub : add;
5406 assign(res, binop(op, mkexpr(arg_n), mkexpr(arg_m)));
5407 putQReg(dreg, binop(op2, getQReg(dreg), mkexpr(res)), condT);
5408 DIP("vml%cl.%c%u q%u, d%u, d%u[%u]\n",
5409 INSN(10,10) ? 's' : 'a', U ? 'u' : 's',
5410 8 << size, dreg, nreg, mreg, index);
5411 return True;
5412 }
5413
5414 /* VQDMLAL, VQDMLSL (scalar) */
5415 if ((INSN(11,8) & BITS4(1,0,1,1)) == BITS4(0,0,1,1) && !U) {
5416 IRTemp res, arg_m, arg_n, tmp;
5417 IROp dup, get, op, op2, add, cmp;
5418 UInt P = INSN(10,10);
5419 ULong imm;
5420 if (dreg & 1)
5421 return False;
5422 dreg >>= 1;
5423 res = newTemp(Ity_V128);
5424 arg_m = newTemp(Ity_I64);
5425 arg_n = newTemp(Ity_I64);
5426 assign(arg_n, getDRegI64(nreg));
5427 switch(size) {
5428 case 1:
5429 dup = Iop_Dup16x4;
5430 get = Iop_GetElem16x4;
5431 index = mreg >> 3;
5432 mreg &= 7;
5433 break;
5434 case 2:
5435 dup = Iop_Dup32x2;
5436 get = Iop_GetElem32x2;
5437 index = mreg >> 4;
5438 mreg &= 0xf;
5439 break;
5440 case 0:
5441 case 3:
5442 return False;
5443 default:
5444 vassert(0);
5445 }
5446 assign(arg_m, unop(dup, binop(get, getDRegI64(mreg), mkU8(index))));
5447 switch (size) {
5448 case 0:
5449 case 3:
5450 return False;
5451 case 1:
5452 op = Iop_QDMulLong16Sx4;
5453 cmp = Iop_CmpEQ16x4;
5454 add = P ? Iop_QSub32Sx4 : Iop_QAdd32Sx4;
5455 op2 = P ? Iop_Sub32x4 : Iop_Add32x4;
5456 imm = 1LL << 15;
5457 imm = (imm << 16) | imm;
5458 imm = (imm << 32) | imm;
5459 break;
5460 case 2:
5461 op = Iop_QDMulLong32Sx2;
5462 cmp = Iop_CmpEQ32x2;
5463 add = P ? Iop_QSub64Sx2 : Iop_QAdd64Sx2;
5464 op2 = P ? Iop_Sub64x2 : Iop_Add64x2;
5465 imm = 1LL << 31;
5466 imm = (imm << 32) | imm;
5467 break;
5468 default:
5469 vassert(0);
5470 }
5471 res = newTemp(Ity_V128);
5472 tmp = newTemp(Ity_V128);
5473 assign(res, binop(op, mkexpr(arg_n), mkexpr(arg_m)));
5474#ifndef DISABLE_QC_FLAG
5475 assign(tmp, binop(op2, getQReg(dreg), mkexpr(res)));
5476 setFlag_QC(binop(Iop_And64,
5477 binop(cmp, mkexpr(arg_n), mkU64(imm)),
5478 binop(cmp, mkexpr(arg_m), mkU64(imm))),
5479 mkU64(0),
5480 False, condT);
5481 setFlag_QC(mkexpr(tmp), binop(add, getQReg(dreg), mkexpr(res)),
5482 True, condT);
5483#endif
5484 putQReg(dreg, binop(add, getQReg(dreg), mkexpr(res)), condT);
5485 DIP("vqdml%cl.s%u q%u, d%u, d%u[%u]\n", P ? 's' : 'a', 8 << size,
5486 dreg, nreg, mreg, index);
5487 return True;
5488 }
5489
5490 /* VMUL (by scalar) */
5491 if ((INSN(11,8) & BITS4(1,1,1,0)) == BITS4(1,0,0,0)) {
5492 IRTemp res, arg_m, arg_n;
5493 IROp dup, get, op;
5494 if (Q) {
5495 if ((dreg & 1) || (nreg & 1))
5496 return False;
5497 dreg >>= 1;
5498 nreg >>= 1;
5499 res = newTemp(Ity_V128);
5500 arg_m = newTemp(Ity_V128);
5501 arg_n = newTemp(Ity_V128);
5502 assign(arg_n, getQReg(nreg));
5503 switch(size) {
5504 case 1:
5505 dup = Iop_Dup16x8;
5506 get = Iop_GetElem16x4;
5507 index = mreg >> 3;
5508 mreg &= 7;
5509 break;
5510 case 2:
5511 dup = Iop_Dup32x4;
5512 get = Iop_GetElem32x2;
5513 index = mreg >> 4;
5514 mreg &= 0xf;
5515 break;
5516 case 0:
5517 case 3:
5518 return False;
5519 default:
5520 vassert(0);
5521 }
5522 assign(arg_m, unop(dup, binop(get, getDRegI64(mreg), mkU8(index))));
5523 } else {
5524 res = newTemp(Ity_I64);
5525 arg_m = newTemp(Ity_I64);
5526 arg_n = newTemp(Ity_I64);
5527 assign(arg_n, getDRegI64(nreg));
5528 switch(size) {
5529 case 1:
5530 dup = Iop_Dup16x4;
5531 get = Iop_GetElem16x4;
5532 index = mreg >> 3;
5533 mreg &= 7;
5534 break;
5535 case 2:
5536 dup = Iop_Dup32x2;
5537 get = Iop_GetElem32x2;
5538 index = mreg >> 4;
5539 mreg &= 0xf;
5540 break;
5541 case 0:
5542 case 3:
5543 return False;
5544 default:
5545 vassert(0);
5546 }
5547 assign(arg_m, unop(dup, binop(get, getDRegI64(mreg), mkU8(index))));
5548 }
sewardja561f892011-07-19 07:37:03 +00005549 if (INSN(8,8)) {
5550 switch (size) {
5551 case 2:
5552 op = Q ? Iop_Mul32Fx4 : Iop_Mul32Fx2;
5553 break;
5554 case 0:
5555 case 1:
5556 case 3:
5557 return False;
5558 default:
5559 vassert(0);
5560 }
5561 } else {
5562 switch (size) {
5563 case 1:
5564 op = Q ? Iop_Mul16x8 : Iop_Mul16x4;
5565 break;
5566 case 2:
5567 op = Q ? Iop_Mul32x4 : Iop_Mul32x2;
5568 break;
5569 case 0:
5570 case 3:
5571 return False;
5572 default:
5573 vassert(0);
5574 }
sewardjd2664472010-08-22 12:44:20 +00005575 }
5576 assign(res, binop(op, mkexpr(arg_n), mkexpr(arg_m)));
5577 if (Q)
5578 putQReg(dreg, mkexpr(res), condT);
5579 else
5580 putDRegI64(dreg, mkexpr(res), condT);
sewardja561f892011-07-19 07:37:03 +00005581 DIP("vmul.%c%u %c%u, %c%u, d%u[%u]\n", INSN(8,8) ? 'f' : 'i',
5582 8 << size, Q ? 'q' : 'd', dreg,
sewardjd2664472010-08-22 12:44:20 +00005583 Q ? 'q' : 'd', nreg, mreg, index);
5584 return True;
5585 }
5586
5587 /* VMULL (scalar) */
5588 if (INSN(11,8) == BITS4(1,0,1,0)) {
5589 IRTemp res, arg_m, arg_n;
5590 IROp dup, get, op;
5591 if (dreg & 1)
5592 return False;
5593 dreg >>= 1;
5594 res = newTemp(Ity_V128);
5595 arg_m = newTemp(Ity_I64);
5596 arg_n = newTemp(Ity_I64);
5597 assign(arg_n, getDRegI64(nreg));
5598 switch(size) {
5599 case 1:
5600 dup = Iop_Dup16x4;
5601 get = Iop_GetElem16x4;
5602 index = mreg >> 3;
5603 mreg &= 7;
5604 break;
5605 case 2:
5606 dup = Iop_Dup32x2;
5607 get = Iop_GetElem32x2;
5608 index = mreg >> 4;
5609 mreg &= 0xf;
5610 break;
5611 case 0:
5612 case 3:
5613 return False;
5614 default:
5615 vassert(0);
5616 }
5617 assign(arg_m, unop(dup, binop(get, getDRegI64(mreg), mkU8(index))));
5618 switch (size) {
5619 case 1: op = U ? Iop_Mull16Ux4 : Iop_Mull16Sx4; break;
5620 case 2: op = U ? Iop_Mull32Ux2 : Iop_Mull32Sx2; break;
5621 case 0: case 3: return False;
5622 default: vassert(0);
5623 }
5624 assign(res, binop(op, mkexpr(arg_n), mkexpr(arg_m)));
5625 putQReg(dreg, mkexpr(res), condT);
5626 DIP("vmull.%c%u q%u, d%u, d%u[%u]\n", U ? 'u' : 's', 8 << size, dreg,
5627 nreg, mreg, index);
5628 return True;
5629 }
5630
5631 /* VQDMULL */
5632 if (INSN(11,8) == BITS4(1,0,1,1) && !U) {
5633 IROp op ,op2, dup, get;
5634 ULong imm;
sewardj06122e72011-03-28 12:14:48 +00005635 IRTemp arg_m, arg_n;
sewardjd2664472010-08-22 12:44:20 +00005636 if (dreg & 1)
5637 return False;
5638 dreg >>= 1;
sewardjd2664472010-08-22 12:44:20 +00005639 arg_m = newTemp(Ity_I64);
5640 arg_n = newTemp(Ity_I64);
5641 assign(arg_n, getDRegI64(nreg));
5642 switch(size) {
5643 case 1:
5644 dup = Iop_Dup16x4;
5645 get = Iop_GetElem16x4;
5646 index = mreg >> 3;
5647 mreg &= 7;
5648 break;
5649 case 2:
5650 dup = Iop_Dup32x2;
5651 get = Iop_GetElem32x2;
5652 index = mreg >> 4;
5653 mreg &= 0xf;
5654 break;
5655 case 0:
5656 case 3:
5657 return False;
5658 default:
5659 vassert(0);
5660 }
5661 assign(arg_m, unop(dup, binop(get, getDRegI64(mreg), mkU8(index))));
5662 switch (size) {
5663 case 0:
5664 case 3:
5665 return False;
5666 case 1:
5667 op = Iop_QDMulLong16Sx4;
5668 op2 = Iop_CmpEQ16x4;
5669 imm = 1LL << 15;
5670 imm = (imm << 16) | imm;
5671 imm = (imm << 32) | imm;
5672 break;
5673 case 2:
5674 op = Iop_QDMulLong32Sx2;
5675 op2 = Iop_CmpEQ32x2;
5676 imm = 1LL << 31;
5677 imm = (imm << 32) | imm;
5678 break;
5679 default:
5680 vassert(0);
5681 }
5682 putQReg(dreg, binop(op, mkexpr(arg_n), mkexpr(arg_m)),
5683 condT);
5684#ifndef DISABLE_QC_FLAG
5685 setFlag_QC(binop(Iop_And64,
5686 binop(op2, mkexpr(arg_n), mkU64(imm)),
5687 binop(op2, mkexpr(arg_m), mkU64(imm))),
5688 mkU64(0),
5689 False, condT);
5690#endif
5691 DIP("vqdmull.s%u q%u, d%u, d%u[%u]\n", 8 << size, dreg, nreg, mreg,
5692 index);
5693 return True;
5694 }
5695
5696 /* VQDMULH */
5697 if (INSN(11,8) == BITS4(1,1,0,0)) {
5698 IROp op ,op2, dup, get;
5699 ULong imm;
5700 IRTemp res, arg_m, arg_n;
5701 if (Q) {
5702 if ((dreg & 1) || (nreg & 1))
5703 return False;
5704 dreg >>= 1;
5705 nreg >>= 1;
5706 res = newTemp(Ity_V128);
5707 arg_m = newTemp(Ity_V128);
5708 arg_n = newTemp(Ity_V128);
5709 assign(arg_n, getQReg(nreg));
5710 switch(size) {
5711 case 1:
5712 dup = Iop_Dup16x8;
5713 get = Iop_GetElem16x4;
5714 index = mreg >> 3;
5715 mreg &= 7;
5716 break;
5717 case 2:
5718 dup = Iop_Dup32x4;
5719 get = Iop_GetElem32x2;
5720 index = mreg >> 4;
5721 mreg &= 0xf;
5722 break;
5723 case 0:
5724 case 3:
5725 return False;
5726 default:
5727 vassert(0);
5728 }
5729 assign(arg_m, unop(dup, binop(get, getDRegI64(mreg), mkU8(index))));
5730 } else {
5731 res = newTemp(Ity_I64);
5732 arg_m = newTemp(Ity_I64);
5733 arg_n = newTemp(Ity_I64);
5734 assign(arg_n, getDRegI64(nreg));
5735 switch(size) {
5736 case 1:
5737 dup = Iop_Dup16x4;
5738 get = Iop_GetElem16x4;
5739 index = mreg >> 3;
5740 mreg &= 7;
5741 break;
5742 case 2:
5743 dup = Iop_Dup32x2;
5744 get = Iop_GetElem32x2;
5745 index = mreg >> 4;
5746 mreg &= 0xf;
5747 break;
5748 case 0:
5749 case 3:
5750 return False;
5751 default:
5752 vassert(0);
5753 }
5754 assign(arg_m, unop(dup, binop(get, getDRegI64(mreg), mkU8(index))));
5755 }
5756 switch (size) {
5757 case 0:
5758 case 3:
5759 return False;
5760 case 1:
5761 op = Q ? Iop_QDMulHi16Sx8 : Iop_QDMulHi16Sx4;
5762 op2 = Q ? Iop_CmpEQ16x8 : Iop_CmpEQ16x4;
5763 imm = 1LL << 15;
5764 imm = (imm << 16) | imm;
5765 imm = (imm << 32) | imm;
5766 break;
5767 case 2:
5768 op = Q ? Iop_QDMulHi32Sx4 : Iop_QDMulHi32Sx2;
5769 op2 = Q ? Iop_CmpEQ32x4 : Iop_CmpEQ32x2;
5770 imm = 1LL << 31;
5771 imm = (imm << 32) | imm;
5772 break;
5773 default:
5774 vassert(0);
5775 }
5776 assign(res, binop(op, mkexpr(arg_n), mkexpr(arg_m)));
5777#ifndef DISABLE_QC_FLAG
5778 setFlag_QC(binop(Q ? Iop_AndV128 : Iop_And64,
5779 binop(op2, mkexpr(arg_n),
5780 Q ? mkU128(imm) : mkU64(imm)),
5781 binop(op2, mkexpr(arg_m),
5782 Q ? mkU128(imm) : mkU64(imm))),
5783 Q ? mkU128(0) : mkU64(0),
5784 Q, condT);
5785#endif
5786 if (Q)
5787 putQReg(dreg, mkexpr(res), condT);
5788 else
5789 putDRegI64(dreg, mkexpr(res), condT);
5790 DIP("vqdmulh.s%u %c%u, %c%u, d%u[%u]\n",
5791 8 << size, Q ? 'q' : 'd', dreg,
5792 Q ? 'q' : 'd', nreg, mreg, index);
5793 return True;
5794 }
5795
5796 /* VQRDMULH (scalar) */
5797 if (INSN(11,8) == BITS4(1,1,0,1)) {
5798 IROp op ,op2, dup, get;
5799 ULong imm;
5800 IRTemp res, arg_m, arg_n;
5801 if (Q) {
5802 if ((dreg & 1) || (nreg & 1))
5803 return False;
5804 dreg >>= 1;
5805 nreg >>= 1;
5806 res = newTemp(Ity_V128);
5807 arg_m = newTemp(Ity_V128);
5808 arg_n = newTemp(Ity_V128);
5809 assign(arg_n, getQReg(nreg));
5810 switch(size) {
5811 case 1:
5812 dup = Iop_Dup16x8;
5813 get = Iop_GetElem16x4;
5814 index = mreg >> 3;
5815 mreg &= 7;
5816 break;
5817 case 2:
5818 dup = Iop_Dup32x4;
5819 get = Iop_GetElem32x2;
5820 index = mreg >> 4;
5821 mreg &= 0xf;
5822 break;
5823 case 0:
5824 case 3:
5825 return False;
5826 default:
5827 vassert(0);
5828 }
5829 assign(arg_m, unop(dup, binop(get, getDRegI64(mreg), mkU8(index))));
5830 } else {
5831 res = newTemp(Ity_I64);
5832 arg_m = newTemp(Ity_I64);
5833 arg_n = newTemp(Ity_I64);
5834 assign(arg_n, getDRegI64(nreg));
5835 switch(size) {
5836 case 1:
5837 dup = Iop_Dup16x4;
5838 get = Iop_GetElem16x4;
5839 index = mreg >> 3;
5840 mreg &= 7;
5841 break;
5842 case 2:
5843 dup = Iop_Dup32x2;
5844 get = Iop_GetElem32x2;
5845 index = mreg >> 4;
5846 mreg &= 0xf;
5847 break;
5848 case 0:
5849 case 3:
5850 return False;
5851 default:
5852 vassert(0);
5853 }
5854 assign(arg_m, unop(dup, binop(get, getDRegI64(mreg), mkU8(index))));
5855 }
5856 switch (size) {
5857 case 0:
5858 case 3:
5859 return False;
5860 case 1:
5861 op = Q ? Iop_QRDMulHi16Sx8 : Iop_QRDMulHi16Sx4;
5862 op2 = Q ? Iop_CmpEQ16x8 : Iop_CmpEQ16x4;
5863 imm = 1LL << 15;
5864 imm = (imm << 16) | imm;
5865 imm = (imm << 32) | imm;
5866 break;
5867 case 2:
5868 op = Q ? Iop_QRDMulHi32Sx4 : Iop_QRDMulHi32Sx2;
5869 op2 = Q ? Iop_CmpEQ32x4 : Iop_CmpEQ32x2;
5870 imm = 1LL << 31;
5871 imm = (imm << 32) | imm;
5872 break;
5873 default:
5874 vassert(0);
5875 }
5876 assign(res, binop(op, mkexpr(arg_n), mkexpr(arg_m)));
5877#ifndef DISABLE_QC_FLAG
5878 setFlag_QC(binop(Q ? Iop_AndV128 : Iop_And64,
5879 binop(op2, mkexpr(arg_n),
5880 Q ? mkU128(imm) : mkU64(imm)),
5881 binop(op2, mkexpr(arg_m),
5882 Q ? mkU128(imm) : mkU64(imm))),
5883 Q ? mkU128(0) : mkU64(0),
5884 Q, condT);
5885#endif
5886 if (Q)
5887 putQReg(dreg, mkexpr(res), condT);
5888 else
5889 putDRegI64(dreg, mkexpr(res), condT);
5890 DIP("vqrdmulh.s%u %c%u, %c%u, d%u[%u]\n",
5891 8 << size, Q ? 'q' : 'd', dreg,
5892 Q ? 'q' : 'd', nreg, mreg, index);
5893 return True;
5894 }
5895
5896 return False;
5897# undef INSN
5898}
5899
5900/* A7.4.4 Two registers and a shift amount */
5901static
5902Bool dis_neon_data_2reg_and_shift ( UInt theInstr, IRTemp condT )
5903{
5904 UInt A = (theInstr >> 8) & 0xf;
5905 UInt B = (theInstr >> 6) & 1;
5906 UInt L = (theInstr >> 7) & 1;
5907 UInt U = (theInstr >> 24) & 1;
5908 UInt Q = B;
5909 UInt imm6 = (theInstr >> 16) & 0x3f;
5910 UInt shift_imm;
5911 UInt size = 4;
5912 UInt tmp;
5913 UInt mreg = get_neon_m_regno(theInstr);
5914 UInt dreg = get_neon_d_regno(theInstr);
5915 ULong imm = 0;
5916 IROp op, cvt, add = Iop_INVALID, cvt2, op_rev;
5917 IRTemp reg_m, res, mask;
5918
5919 if (L == 0 && ((theInstr >> 19) & 7) == 0)
5920 /* It is one reg and immediate */
5921 return False;
5922
5923 tmp = (L << 6) | imm6;
5924 if (tmp & 0x40) {
5925 size = 3;
5926 shift_imm = 64 - imm6;
5927 } else if (tmp & 0x20) {
5928 size = 2;
5929 shift_imm = 64 - imm6;
5930 } else if (tmp & 0x10) {
5931 size = 1;
5932 shift_imm = 32 - imm6;
5933 } else if (tmp & 0x8) {
5934 size = 0;
5935 shift_imm = 16 - imm6;
5936 } else {
5937 return False;
5938 }
5939
5940 switch (A) {
5941 case 3:
5942 case 2:
5943 /* VRSHR, VRSRA */
5944 if (shift_imm > 0) {
5945 IRExpr *imm_val;
5946 imm = 1L;
5947 switch (size) {
5948 case 0:
5949 imm = (imm << 8) | imm;
5950 /* fall through */
5951 case 1:
5952 imm = (imm << 16) | imm;
5953 /* fall through */
5954 case 2:
5955 imm = (imm << 32) | imm;
5956 /* fall through */
5957 case 3:
5958 break;
5959 default:
5960 vassert(0);
5961 }
5962 if (Q) {
5963 reg_m = newTemp(Ity_V128);
5964 res = newTemp(Ity_V128);
5965 imm_val = binop(Iop_64HLtoV128, mkU64(imm), mkU64(imm));
5966 assign(reg_m, getQReg(mreg));
5967 switch (size) {
5968 case 0:
5969 add = Iop_Add8x16;
5970 op = U ? Iop_ShrN8x16 : Iop_SarN8x16;
5971 break;
5972 case 1:
5973 add = Iop_Add16x8;
5974 op = U ? Iop_ShrN16x8 : Iop_SarN16x8;
5975 break;
5976 case 2:
5977 add = Iop_Add32x4;
5978 op = U ? Iop_ShrN32x4 : Iop_SarN32x4;
5979 break;
5980 case 3:
5981 add = Iop_Add64x2;
5982 op = U ? Iop_ShrN64x2 : Iop_SarN64x2;
5983 break;
5984 default:
5985 vassert(0);
5986 }
5987 } else {
5988 reg_m = newTemp(Ity_I64);
5989 res = newTemp(Ity_I64);
5990 imm_val = mkU64(imm);
5991 assign(reg_m, getDRegI64(mreg));
5992 switch (size) {
5993 case 0:
5994 add = Iop_Add8x8;
5995 op = U ? Iop_ShrN8x8 : Iop_SarN8x8;
5996 break;
5997 case 1:
5998 add = Iop_Add16x4;
5999 op = U ? Iop_ShrN16x4 : Iop_SarN16x4;
6000 break;
6001 case 2:
6002 add = Iop_Add32x2;
6003 op = U ? Iop_ShrN32x2 : Iop_SarN32x2;
6004 break;
6005 case 3:
6006 add = Iop_Add64;
6007 op = U ? Iop_Shr64 : Iop_Sar64;
6008 break;
6009 default:
6010 vassert(0);
6011 }
6012 }
6013 assign(res,
6014 binop(add,
6015 binop(op,
6016 mkexpr(reg_m),
6017 mkU8(shift_imm)),
6018 binop(Q ? Iop_AndV128 : Iop_And64,
6019 binop(op,
6020 mkexpr(reg_m),
6021 mkU8(shift_imm - 1)),
6022 imm_val)));
6023 } else {
6024 if (Q) {
6025 res = newTemp(Ity_V128);
6026 assign(res, getQReg(mreg));
6027 } else {
6028 res = newTemp(Ity_I64);
6029 assign(res, getDRegI64(mreg));
6030 }
6031 }
6032 if (A == 3) {
6033 if (Q) {
6034 putQReg(dreg, binop(add, mkexpr(res), getQReg(dreg)),
6035 condT);
6036 } else {
6037 putDRegI64(dreg, binop(add, mkexpr(res), getDRegI64(dreg)),
6038 condT);
6039 }
6040 DIP("vrsra.%c%u %c%u, %c%u, #%u\n",
6041 U ? 'u' : 's', 8 << size,
6042 Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', mreg, shift_imm);
6043 } else {
6044 if (Q) {
6045 putQReg(dreg, mkexpr(res), condT);
6046 } else {
6047 putDRegI64(dreg, mkexpr(res), condT);
6048 }
6049 DIP("vrshr.%c%u %c%u, %c%u, #%u\n", U ? 'u' : 's', 8 << size,
6050 Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', mreg, shift_imm);
6051 }
6052 return True;
6053 case 1:
6054 case 0:
6055 /* VSHR, VSRA */
6056 if (Q) {
6057 reg_m = newTemp(Ity_V128);
6058 assign(reg_m, getQReg(mreg));
6059 res = newTemp(Ity_V128);
6060 } else {
6061 reg_m = newTemp(Ity_I64);
6062 assign(reg_m, getDRegI64(mreg));
6063 res = newTemp(Ity_I64);
6064 }
6065 if (Q) {
6066 switch (size) {
6067 case 0:
6068 op = U ? Iop_ShrN8x16 : Iop_SarN8x16;
6069 add = Iop_Add8x16;
6070 break;
6071 case 1:
6072 op = U ? Iop_ShrN16x8 : Iop_SarN16x8;
6073 add = Iop_Add16x8;
6074 break;
6075 case 2:
6076 op = U ? Iop_ShrN32x4 : Iop_SarN32x4;
6077 add = Iop_Add32x4;
6078 break;
6079 case 3:
6080 op = U ? Iop_ShrN64x2 : Iop_SarN64x2;
6081 add = Iop_Add64x2;
6082 break;
6083 default:
6084 vassert(0);
6085 }
6086 } else {
6087 switch (size) {
6088 case 0:
6089 op = U ? Iop_ShrN8x8 : Iop_SarN8x8;
6090 add = Iop_Add8x8;
6091 break;
6092 case 1:
6093 op = U ? Iop_ShrN16x4 : Iop_SarN16x4;
6094 add = Iop_Add16x4;
6095 break;
6096 case 2:
6097 op = U ? Iop_ShrN32x2 : Iop_SarN32x2;
6098 add = Iop_Add32x2;
6099 break;
6100 case 3:
6101 op = U ? Iop_Shr64 : Iop_Sar64;
6102 add = Iop_Add64;
6103 break;
6104 default:
6105 vassert(0);
6106 }
6107 }
6108 assign(res, binop(op, mkexpr(reg_m), mkU8(shift_imm)));
6109 if (A == 1) {
6110 if (Q) {
6111 putQReg(dreg, binop(add, mkexpr(res), getQReg(dreg)),
6112 condT);
6113 } else {
6114 putDRegI64(dreg, binop(add, mkexpr(res), getDRegI64(dreg)),
6115 condT);
6116 }
6117 DIP("vsra.%c%u %c%u, %c%u, #%u\n", U ? 'u' : 's', 8 << size,
6118 Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', mreg, shift_imm);
6119 } else {
6120 if (Q) {
6121 putQReg(dreg, mkexpr(res), condT);
6122 } else {
6123 putDRegI64(dreg, mkexpr(res), condT);
6124 }
6125 DIP("vshr.%c%u %c%u, %c%u, #%u\n", U ? 'u' : 's', 8 << size,
6126 Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', mreg, shift_imm);
6127 }
6128 return True;
6129 case 4:
6130 /* VSRI */
6131 if (!U)
6132 return False;
6133 if (Q) {
6134 res = newTemp(Ity_V128);
6135 mask = newTemp(Ity_V128);
6136 } else {
6137 res = newTemp(Ity_I64);
6138 mask = newTemp(Ity_I64);
6139 }
6140 switch (size) {
6141 case 0: op = Q ? Iop_ShrN8x16 : Iop_ShrN8x8; break;
6142 case 1: op = Q ? Iop_ShrN16x8 : Iop_ShrN16x4; break;
6143 case 2: op = Q ? Iop_ShrN32x4 : Iop_ShrN32x2; break;
6144 case 3: op = Q ? Iop_ShrN64x2 : Iop_Shr64; break;
6145 default: vassert(0);
6146 }
6147 if (Q) {
6148 assign(mask, binop(op, binop(Iop_64HLtoV128,
6149 mkU64(0xFFFFFFFFFFFFFFFFLL),
6150 mkU64(0xFFFFFFFFFFFFFFFFLL)),
6151 mkU8(shift_imm)));
6152 assign(res, binop(Iop_OrV128,
6153 binop(Iop_AndV128,
6154 getQReg(dreg),
6155 unop(Iop_NotV128,
6156 mkexpr(mask))),
6157 binop(op,
6158 getQReg(mreg),
6159 mkU8(shift_imm))));
6160 putQReg(dreg, mkexpr(res), condT);
6161 } else {
6162 assign(mask, binop(op, mkU64(0xFFFFFFFFFFFFFFFFLL),
6163 mkU8(shift_imm)));
6164 assign(res, binop(Iop_Or64,
6165 binop(Iop_And64,
6166 getDRegI64(dreg),
6167 unop(Iop_Not64,
6168 mkexpr(mask))),
6169 binop(op,
6170 getDRegI64(mreg),
6171 mkU8(shift_imm))));
6172 putDRegI64(dreg, mkexpr(res), condT);
6173 }
6174 DIP("vsri.%u %c%u, %c%u, #%u\n",
6175 8 << size, Q ? 'q' : 'd', dreg,
6176 Q ? 'q' : 'd', mreg, shift_imm);
6177 return True;
6178 case 5:
6179 if (U) {
6180 /* VSLI */
6181 shift_imm = 8 * (1 << size) - shift_imm;
6182 if (Q) {
6183 res = newTemp(Ity_V128);
6184 mask = newTemp(Ity_V128);
6185 } else {
6186 res = newTemp(Ity_I64);
6187 mask = newTemp(Ity_I64);
6188 }
6189 switch (size) {
6190 case 0: op = Q ? Iop_ShlN8x16 : Iop_ShlN8x8; break;
6191 case 1: op = Q ? Iop_ShlN16x8 : Iop_ShlN16x4; break;
6192 case 2: op = Q ? Iop_ShlN32x4 : Iop_ShlN32x2; break;
6193 case 3: op = Q ? Iop_ShlN64x2 : Iop_Shl64; break;
6194 default: vassert(0);
6195 }
6196 if (Q) {
6197 assign(mask, binop(op, binop(Iop_64HLtoV128,
6198 mkU64(0xFFFFFFFFFFFFFFFFLL),
6199 mkU64(0xFFFFFFFFFFFFFFFFLL)),
6200 mkU8(shift_imm)));
6201 assign(res, binop(Iop_OrV128,
6202 binop(Iop_AndV128,
6203 getQReg(dreg),
6204 unop(Iop_NotV128,
6205 mkexpr(mask))),
6206 binop(op,
6207 getQReg(mreg),
6208 mkU8(shift_imm))));
6209 putQReg(dreg, mkexpr(res), condT);
6210 } else {
6211 assign(mask, binop(op, mkU64(0xFFFFFFFFFFFFFFFFLL),
6212 mkU8(shift_imm)));
6213 assign(res, binop(Iop_Or64,
6214 binop(Iop_And64,
6215 getDRegI64(dreg),
6216 unop(Iop_Not64,
6217 mkexpr(mask))),
6218 binop(op,
6219 getDRegI64(mreg),
6220 mkU8(shift_imm))));
6221 putDRegI64(dreg, mkexpr(res), condT);
6222 }
6223 DIP("vsli.%u %c%u, %c%u, #%u\n",
6224 8 << size, Q ? 'q' : 'd', dreg,
6225 Q ? 'q' : 'd', mreg, shift_imm);
6226 return True;
6227 } else {
6228 /* VSHL #imm */
6229 shift_imm = 8 * (1 << size) - shift_imm;
6230 if (Q) {
6231 res = newTemp(Ity_V128);
6232 } else {
6233 res = newTemp(Ity_I64);
6234 }
6235 switch (size) {
6236 case 0: op = Q ? Iop_ShlN8x16 : Iop_ShlN8x8; break;
6237 case 1: op = Q ? Iop_ShlN16x8 : Iop_ShlN16x4; break;
6238 case 2: op = Q ? Iop_ShlN32x4 : Iop_ShlN32x2; break;
6239 case 3: op = Q ? Iop_ShlN64x2 : Iop_Shl64; break;
6240 default: vassert(0);
6241 }
6242 assign(res, binop(op, Q ? getQReg(mreg) : getDRegI64(mreg),
6243 mkU8(shift_imm)));
6244 if (Q) {
6245 putQReg(dreg, mkexpr(res), condT);
6246 } else {
6247 putDRegI64(dreg, mkexpr(res), condT);
6248 }
6249 DIP("vshl.i%u %c%u, %c%u, #%u\n",
6250 8 << size, Q ? 'q' : 'd', dreg,
6251 Q ? 'q' : 'd', mreg, shift_imm);
6252 return True;
6253 }
6254 break;
6255 case 6:
6256 case 7:
6257 /* VQSHL, VQSHLU */
6258 shift_imm = 8 * (1 << size) - shift_imm;
6259 if (U) {
6260 if (A & 1) {
6261 switch (size) {
6262 case 0:
6263 op = Q ? Iop_QShlN8x16 : Iop_QShlN8x8;
6264 op_rev = Q ? Iop_ShrN8x16 : Iop_ShrN8x8;
6265 break;
6266 case 1:
6267 op = Q ? Iop_QShlN16x8 : Iop_QShlN16x4;
6268 op_rev = Q ? Iop_ShrN16x8 : Iop_ShrN16x4;
6269 break;
6270 case 2:
6271 op = Q ? Iop_QShlN32x4 : Iop_QShlN32x2;
6272 op_rev = Q ? Iop_ShrN32x4 : Iop_ShrN32x2;
6273 break;
6274 case 3:
6275 op = Q ? Iop_QShlN64x2 : Iop_QShlN64x1;
6276 op_rev = Q ? Iop_ShrN64x2 : Iop_Shr64;
6277 break;
6278 default:
6279 vassert(0);
6280 }
6281 DIP("vqshl.u%u %c%u, %c%u, #%u\n",
6282 8 << size,
6283 Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', mreg, shift_imm);
6284 } else {
6285 switch (size) {
6286 case 0:
6287 op = Q ? Iop_QShlN8Sx16 : Iop_QShlN8Sx8;
6288 op_rev = Q ? Iop_ShrN8x16 : Iop_ShrN8x8;
6289 break;
6290 case 1:
6291 op = Q ? Iop_QShlN16Sx8 : Iop_QShlN16Sx4;
6292 op_rev = Q ? Iop_ShrN16x8 : Iop_ShrN16x4;
6293 break;
6294 case 2:
6295 op = Q ? Iop_QShlN32Sx4 : Iop_QShlN32Sx2;
6296 op_rev = Q ? Iop_ShrN32x4 : Iop_ShrN32x2;
6297 break;
6298 case 3:
6299 op = Q ? Iop_QShlN64Sx2 : Iop_QShlN64Sx1;
6300 op_rev = Q ? Iop_ShrN64x2 : Iop_Shr64;
6301 break;
6302 default:
6303 vassert(0);
6304 }
6305 DIP("vqshlu.s%u %c%u, %c%u, #%u\n",
6306 8 << size,
6307 Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', mreg, shift_imm);
6308 }
6309 } else {
6310 if (!(A & 1))
6311 return False;
6312 switch (size) {
6313 case 0:
6314 op = Q ? Iop_QSalN8x16 : Iop_QSalN8x8;
6315 op_rev = Q ? Iop_SarN8x16 : Iop_SarN8x8;
6316 break;
6317 case 1:
6318 op = Q ? Iop_QSalN16x8 : Iop_QSalN16x4;
6319 op_rev = Q ? Iop_SarN16x8 : Iop_SarN16x4;
6320 break;
6321 case 2:
6322 op = Q ? Iop_QSalN32x4 : Iop_QSalN32x2;
6323 op_rev = Q ? Iop_SarN32x4 : Iop_SarN32x2;
6324 break;
6325 case 3:
6326 op = Q ? Iop_QSalN64x2 : Iop_QSalN64x1;
6327 op_rev = Q ? Iop_SarN64x2 : Iop_Sar64;
6328 break;
6329 default:
6330 vassert(0);
6331 }
6332 DIP("vqshl.s%u %c%u, %c%u, #%u\n",
6333 8 << size,
6334 Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', mreg, shift_imm);
6335 }
6336 if (Q) {
6337 tmp = newTemp(Ity_V128);
6338 res = newTemp(Ity_V128);
6339 reg_m = newTemp(Ity_V128);
6340 assign(reg_m, getQReg(mreg));
6341 } else {
6342 tmp = newTemp(Ity_I64);
6343 res = newTemp(Ity_I64);
6344 reg_m = newTemp(Ity_I64);
6345 assign(reg_m, getDRegI64(mreg));
6346 }
6347 assign(res, binop(op, mkexpr(reg_m), mkU8(shift_imm)));
6348#ifndef DISABLE_QC_FLAG
6349 assign(tmp, binop(op_rev, mkexpr(res), mkU8(shift_imm)));
6350 setFlag_QC(mkexpr(tmp), mkexpr(reg_m), Q, condT);
6351#endif
6352 if (Q)
6353 putQReg(dreg, mkexpr(res), condT);
6354 else
6355 putDRegI64(dreg, mkexpr(res), condT);
6356 return True;
6357 case 8:
6358 if (!U) {
6359 if (L == 1)
6360 return False;
6361 size++;
6362 dreg = ((theInstr >> 18) & 0x10) | ((theInstr >> 12) & 0xF);
6363 mreg = ((theInstr >> 1) & 0x10) | (theInstr & 0xF);
6364 if (mreg & 1)
6365 return False;
6366 mreg >>= 1;
6367 if (!B) {
6368 /* VSHRN*/
6369 IROp narOp;
6370 reg_m = newTemp(Ity_V128);
6371 assign(reg_m, getQReg(mreg));
6372 res = newTemp(Ity_I64);
6373 switch (size) {
6374 case 1:
6375 op = Iop_ShrN16x8;
sewardj5f438dd2011-06-16 11:36:23 +00006376 narOp = Iop_NarrowUn16to8x8;
sewardjd2664472010-08-22 12:44:20 +00006377 break;
6378 case 2:
6379 op = Iop_ShrN32x4;
sewardj5f438dd2011-06-16 11:36:23 +00006380 narOp = Iop_NarrowUn32to16x4;
sewardjd2664472010-08-22 12:44:20 +00006381 break;
6382 case 3:
6383 op = Iop_ShrN64x2;
sewardj5f438dd2011-06-16 11:36:23 +00006384 narOp = Iop_NarrowUn64to32x2;
sewardjd2664472010-08-22 12:44:20 +00006385 break;
6386 default:
6387 vassert(0);
6388 }
6389 assign(res, unop(narOp,
6390 binop(op,
6391 mkexpr(reg_m),
6392 mkU8(shift_imm))));
6393 putDRegI64(dreg, mkexpr(res), condT);
6394 DIP("vshrn.i%u d%u, q%u, #%u\n", 8 << size, dreg, mreg,
6395 shift_imm);
6396 return True;
6397 } else {
6398 /* VRSHRN */
6399 IROp addOp, shOp, narOp;
6400 IRExpr *imm_val;
6401 reg_m = newTemp(Ity_V128);
6402 assign(reg_m, getQReg(mreg));
6403 res = newTemp(Ity_I64);
6404 imm = 1L;
6405 switch (size) {
6406 case 0: imm = (imm << 8) | imm; /* fall through */
6407 case 1: imm = (imm << 16) | imm; /* fall through */
6408 case 2: imm = (imm << 32) | imm; /* fall through */
6409 case 3: break;
6410 default: vassert(0);
6411 }
6412 imm_val = binop(Iop_64HLtoV128, mkU64(imm), mkU64(imm));
6413 switch (size) {
6414 case 1:
6415 addOp = Iop_Add16x8;
6416 shOp = Iop_ShrN16x8;
sewardj5f438dd2011-06-16 11:36:23 +00006417 narOp = Iop_NarrowUn16to8x8;
sewardjd2664472010-08-22 12:44:20 +00006418 break;
6419 case 2:
6420 addOp = Iop_Add32x4;
6421 shOp = Iop_ShrN32x4;
sewardj5f438dd2011-06-16 11:36:23 +00006422 narOp = Iop_NarrowUn32to16x4;
sewardjd2664472010-08-22 12:44:20 +00006423 break;
6424 case 3:
6425 addOp = Iop_Add64x2;
6426 shOp = Iop_ShrN64x2;
sewardj5f438dd2011-06-16 11:36:23 +00006427 narOp = Iop_NarrowUn64to32x2;
sewardjd2664472010-08-22 12:44:20 +00006428 break;
6429 default:
6430 vassert(0);
6431 }
6432 assign(res, unop(narOp,
6433 binop(addOp,
6434 binop(shOp,
6435 mkexpr(reg_m),
6436 mkU8(shift_imm)),
6437 binop(Iop_AndV128,
6438 binop(shOp,
6439 mkexpr(reg_m),
6440 mkU8(shift_imm - 1)),
6441 imm_val))));
6442 putDRegI64(dreg, mkexpr(res), condT);
6443 if (shift_imm == 0) {
6444 DIP("vmov%u d%u, q%u, #%u\n", 8 << size, dreg, mreg,
6445 shift_imm);
6446 } else {
6447 DIP("vrshrn.i%u d%u, q%u, #%u\n", 8 << size, dreg, mreg,
6448 shift_imm);
6449 }
6450 return True;
6451 }
6452 } else {
6453 /* fall through */
6454 }
6455 case 9:
6456 dreg = ((theInstr >> 18) & 0x10) | ((theInstr >> 12) & 0xF);
6457 mreg = ((theInstr >> 1) & 0x10) | (theInstr & 0xF);
6458 if (mreg & 1)
6459 return False;
6460 mreg >>= 1;
6461 size++;
6462 if ((theInstr >> 8) & 1) {
6463 switch (size) {
6464 case 1:
6465 op = U ? Iop_ShrN16x8 : Iop_SarN16x8;
sewardj5f438dd2011-06-16 11:36:23 +00006466 cvt = U ? Iop_QNarrowUn16Uto8Ux8 : Iop_QNarrowUn16Sto8Sx8;
6467 cvt2 = U ? Iop_Widen8Uto16x8 : Iop_Widen8Sto16x8;
sewardjd2664472010-08-22 12:44:20 +00006468 break;
6469 case 2:
6470 op = U ? Iop_ShrN32x4 : Iop_SarN32x4;
sewardj5f438dd2011-06-16 11:36:23 +00006471 cvt = U ? Iop_QNarrowUn32Uto16Ux4 : Iop_QNarrowUn32Sto16Sx4;
6472 cvt2 = U ? Iop_Widen16Uto32x4 : Iop_Widen16Sto32x4;
sewardjd2664472010-08-22 12:44:20 +00006473 break;
6474 case 3:
6475 op = U ? Iop_ShrN64x2 : Iop_SarN64x2;
sewardj5f438dd2011-06-16 11:36:23 +00006476 cvt = U ? Iop_QNarrowUn64Uto32Ux2 : Iop_QNarrowUn64Sto32Sx2;
6477 cvt2 = U ? Iop_Widen32Uto64x2 : Iop_Widen32Sto64x2;
sewardjd2664472010-08-22 12:44:20 +00006478 break;
6479 default:
6480 vassert(0);
6481 }
6482 DIP("vq%sshrn.%c%u d%u, q%u, #%u\n", B ? "r" : "",
6483 U ? 'u' : 's', 8 << size, dreg, mreg, shift_imm);
6484 } else {
6485 vassert(U);
6486 switch (size) {
6487 case 1:
6488 op = Iop_SarN16x8;
sewardj5f438dd2011-06-16 11:36:23 +00006489 cvt = Iop_QNarrowUn16Sto8Ux8;
6490 cvt2 = Iop_Widen8Uto16x8;
sewardjd2664472010-08-22 12:44:20 +00006491 break;
6492 case 2:
6493 op = Iop_SarN32x4;
sewardj5f438dd2011-06-16 11:36:23 +00006494 cvt = Iop_QNarrowUn32Sto16Ux4;
6495 cvt2 = Iop_Widen16Uto32x4;
sewardjd2664472010-08-22 12:44:20 +00006496 break;
6497 case 3:
6498 op = Iop_SarN64x2;
sewardj5f438dd2011-06-16 11:36:23 +00006499 cvt = Iop_QNarrowUn64Sto32Ux2;
6500 cvt2 = Iop_Widen32Uto64x2;
sewardjd2664472010-08-22 12:44:20 +00006501 break;
6502 default:
6503 vassert(0);
6504 }
6505 DIP("vq%sshrun.s%u d%u, q%u, #%u\n", B ? "r" : "",
6506 8 << size, dreg, mreg, shift_imm);
6507 }
6508 if (B) {
6509 if (shift_imm > 0) {
6510 imm = 1;
6511 switch (size) {
6512 case 1: imm = (imm << 16) | imm; /* fall through */
6513 case 2: imm = (imm << 32) | imm; /* fall through */
6514 case 3: break;
6515 case 0: default: vassert(0);
6516 }
6517 switch (size) {
6518 case 1: add = Iop_Add16x8; break;
6519 case 2: add = Iop_Add32x4; break;
6520 case 3: add = Iop_Add64x2; break;
6521 case 0: default: vassert(0);
6522 }
6523 }
6524 }
6525 reg_m = newTemp(Ity_V128);
6526 res = newTemp(Ity_V128);
6527 assign(reg_m, getQReg(mreg));
6528 if (B) {
6529 /* VQRSHRN, VQRSHRUN */
6530 assign(res, binop(add,
6531 binop(op, mkexpr(reg_m), mkU8(shift_imm)),
6532 binop(Iop_AndV128,
6533 binop(op,
6534 mkexpr(reg_m),
6535 mkU8(shift_imm - 1)),
6536 mkU128(imm))));
6537 } else {
6538 /* VQSHRN, VQSHRUN */
6539 assign(res, binop(op, mkexpr(reg_m), mkU8(shift_imm)));
6540 }
6541#ifndef DISABLE_QC_FLAG
6542 setFlag_QC(unop(cvt2, unop(cvt, mkexpr(res))), mkexpr(res),
6543 True, condT);
6544#endif
6545 putDRegI64(dreg, unop(cvt, mkexpr(res)), condT);
6546 return True;
6547 case 10:
6548 /* VSHLL
6549 VMOVL ::= VSHLL #0 */
6550 if (B)
6551 return False;
6552 if (dreg & 1)
6553 return False;
6554 dreg >>= 1;
6555 shift_imm = (8 << size) - shift_imm;
6556 res = newTemp(Ity_V128);
6557 switch (size) {
6558 case 0:
6559 op = Iop_ShlN16x8;
sewardj5f438dd2011-06-16 11:36:23 +00006560 cvt = U ? Iop_Widen8Uto16x8 : Iop_Widen8Sto16x8;
sewardjd2664472010-08-22 12:44:20 +00006561 break;
6562 case 1:
6563 op = Iop_ShlN32x4;
sewardj5f438dd2011-06-16 11:36:23 +00006564 cvt = U ? Iop_Widen16Uto32x4 : Iop_Widen16Sto32x4;
sewardjd2664472010-08-22 12:44:20 +00006565 break;
6566 case 2:
6567 op = Iop_ShlN64x2;
sewardj5f438dd2011-06-16 11:36:23 +00006568 cvt = U ? Iop_Widen32Uto64x2 : Iop_Widen32Sto64x2;
sewardjd2664472010-08-22 12:44:20 +00006569 break;
6570 case 3:
6571 return False;
6572 default:
6573 vassert(0);
6574 }
6575 assign(res, binop(op, unop(cvt, getDRegI64(mreg)), mkU8(shift_imm)));
6576 putQReg(dreg, mkexpr(res), condT);
6577 if (shift_imm == 0) {
6578 DIP("vmovl.%c%u q%u, d%u\n", U ? 'u' : 's', 8 << size,
6579 dreg, mreg);
6580 } else {
6581 DIP("vshll.%c%u q%u, d%u, #%u\n", U ? 'u' : 's', 8 << size,
6582 dreg, mreg, shift_imm);
6583 }
6584 return True;
6585 case 14:
6586 case 15:
6587 /* VCVT floating-point <-> fixed-point */
6588 if ((theInstr >> 8) & 1) {
6589 if (U) {
6590 op = Q ? Iop_F32ToFixed32Ux4_RZ : Iop_F32ToFixed32Ux2_RZ;
6591 } else {
6592 op = Q ? Iop_F32ToFixed32Sx4_RZ : Iop_F32ToFixed32Sx2_RZ;
6593 }
6594 DIP("vcvt.%c32.f32 %c%u, %c%u, #%u\n", U ? 'u' : 's',
6595 Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', mreg,
6596 64 - ((theInstr >> 16) & 0x3f));
6597 } else {
6598 if (U) {
6599 op = Q ? Iop_Fixed32UToF32x4_RN : Iop_Fixed32UToF32x2_RN;
6600 } else {
6601 op = Q ? Iop_Fixed32SToF32x4_RN : Iop_Fixed32SToF32x2_RN;
6602 }
6603 DIP("vcvt.f32.%c32 %c%u, %c%u, #%u\n", U ? 'u' : 's',
6604 Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', mreg,
6605 64 - ((theInstr >> 16) & 0x3f));
6606 }
6607 if (((theInstr >> 21) & 1) == 0)
6608 return False;
6609 if (Q) {
6610 putQReg(dreg, binop(op, getQReg(mreg),
6611 mkU8(64 - ((theInstr >> 16) & 0x3f))), condT);
6612 } else {
6613 putDRegI64(dreg, binop(op, getDRegI64(mreg),
6614 mkU8(64 - ((theInstr >> 16) & 0x3f))), condT);
6615 }
6616 return True;
6617 default:
6618 return False;
6619
6620 }
6621 return False;
6622}
6623
6624/* A7.4.5 Two registers, miscellaneous */
6625static
6626Bool dis_neon_data_2reg_misc ( UInt theInstr, IRTemp condT )
6627{
6628 UInt A = (theInstr >> 16) & 3;
6629 UInt B = (theInstr >> 6) & 0x1f;
6630 UInt Q = (theInstr >> 6) & 1;
6631 UInt U = (theInstr >> 24) & 1;
6632 UInt size = (theInstr >> 18) & 3;
6633 UInt dreg = get_neon_d_regno(theInstr);
6634 UInt mreg = get_neon_m_regno(theInstr);
6635 UInt F = (theInstr >> 10) & 1;
6636 IRTemp arg_d;
6637 IRTemp arg_m;
6638 IRTemp res;
6639 switch (A) {
6640 case 0:
6641 if (Q) {
6642 arg_m = newTemp(Ity_V128);
6643 res = newTemp(Ity_V128);
6644 assign(arg_m, getQReg(mreg));
6645 } else {
6646 arg_m = newTemp(Ity_I64);
6647 res = newTemp(Ity_I64);
6648 assign(arg_m, getDRegI64(mreg));
6649 }
6650 switch (B >> 1) {
6651 case 0: {
6652 /* VREV64 */
6653 IROp op;
6654 switch (size) {
6655 case 0:
6656 op = Q ? Iop_Reverse64_8x16 : Iop_Reverse64_8x8;
6657 break;
6658 case 1:
6659 op = Q ? Iop_Reverse64_16x8 : Iop_Reverse64_16x4;
6660 break;
6661 case 2:
6662 op = Q ? Iop_Reverse64_32x4 : Iop_Reverse64_32x2;
6663 break;
6664 case 3:
6665 return False;
6666 default:
6667 vassert(0);
6668 }
6669 assign(res, unop(op, mkexpr(arg_m)));
6670 DIP("vrev64.%u %c%u, %c%u\n", 8 << size,
6671 Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', mreg);
6672 break;
6673 }
6674 case 1: {
6675 /* VREV32 */
6676 IROp op;
6677 switch (size) {
6678 case 0:
6679 op = Q ? Iop_Reverse32_8x16 : Iop_Reverse32_8x8;
6680 break;
6681 case 1:
6682 op = Q ? Iop_Reverse32_16x8 : Iop_Reverse32_16x4;
6683 break;
6684 case 2:
6685 case 3:
6686 return False;
6687 default:
6688 vassert(0);
6689 }
6690 assign(res, unop(op, mkexpr(arg_m)));
6691 DIP("vrev32.%u %c%u, %c%u\n", 8 << size,
6692 Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', mreg);
6693 break;
6694 }
6695 case 2: {
6696 /* VREV16 */
6697 IROp op;
6698 switch (size) {
6699 case 0:
6700 op = Q ? Iop_Reverse16_8x16 : Iop_Reverse16_8x8;
6701 break;
6702 case 1:
6703 case 2:
6704 case 3:
6705 return False;
6706 default:
6707 vassert(0);
6708 }
6709 assign(res, unop(op, mkexpr(arg_m)));
6710 DIP("vrev16.%u %c%u, %c%u\n", 8 << size,
6711 Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', mreg);
6712 break;
6713 }
6714 case 3:
6715 return False;
6716 case 4:
6717 case 5: {
6718 /* VPADDL */
6719 IROp op;
6720 U = (theInstr >> 7) & 1;
6721 if (Q) {
6722 switch (size) {
6723 case 0: op = U ? Iop_PwAddL8Ux16 : Iop_PwAddL8Sx16; break;
6724 case 1: op = U ? Iop_PwAddL16Ux8 : Iop_PwAddL16Sx8; break;
6725 case 2: op = U ? Iop_PwAddL32Ux4 : Iop_PwAddL32Sx4; break;
6726 case 3: return False;
6727 default: vassert(0);
6728 }
6729 } else {
6730 switch (size) {
6731 case 0: op = U ? Iop_PwAddL8Ux8 : Iop_PwAddL8Sx8; break;
6732 case 1: op = U ? Iop_PwAddL16Ux4 : Iop_PwAddL16Sx4; break;
6733 case 2: op = U ? Iop_PwAddL32Ux2 : Iop_PwAddL32Sx2; break;
6734 case 3: return False;
6735 default: vassert(0);
6736 }
6737 }
6738 assign(res, unop(op, mkexpr(arg_m)));
6739 DIP("vpaddl.%c%u %c%u, %c%u\n", U ? 'u' : 's', 8 << size,
6740 Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', mreg);
6741 break;
6742 }
6743 case 6:
6744 case 7:
6745 return False;
6746 case 8: {
6747 /* VCLS */
6748 IROp op;
6749 switch (size) {
6750 case 0: op = Q ? Iop_Cls8Sx16 : Iop_Cls8Sx8; break;
6751 case 1: op = Q ? Iop_Cls16Sx8 : Iop_Cls16Sx4; break;
6752 case 2: op = Q ? Iop_Cls32Sx4 : Iop_Cls32Sx2; break;
6753 case 3: return False;
6754 default: vassert(0);
6755 }
6756 assign(res, unop(op, mkexpr(arg_m)));
6757 DIP("vcls.s%u %c%u, %c%u\n", 8 << size, Q ? 'q' : 'd', dreg,
6758 Q ? 'q' : 'd', mreg);
6759 break;
6760 }
6761 case 9: {
6762 /* VCLZ */
6763 IROp op;
6764 switch (size) {
6765 case 0: op = Q ? Iop_Clz8Sx16 : Iop_Clz8Sx8; break;
6766 case 1: op = Q ? Iop_Clz16Sx8 : Iop_Clz16Sx4; break;
6767 case 2: op = Q ? Iop_Clz32Sx4 : Iop_Clz32Sx2; break;
6768 case 3: return False;
6769 default: vassert(0);
6770 }
6771 assign(res, unop(op, mkexpr(arg_m)));
6772 DIP("vclz.i%u %c%u, %c%u\n", 8 << size, Q ? 'q' : 'd', dreg,
6773 Q ? 'q' : 'd', mreg);
6774 break;
6775 }
6776 case 10:
6777 /* VCNT */
6778 assign(res, unop(Q ? Iop_Cnt8x16 : Iop_Cnt8x8, mkexpr(arg_m)));
6779 DIP("vcnt.8 %c%u, %c%u\n", Q ? 'q' : 'd', dreg, Q ? 'q' : 'd',
6780 mreg);
6781 break;
6782 case 11:
6783 /* VMVN */
6784 if (Q)
6785 assign(res, unop(Iop_NotV128, mkexpr(arg_m)));
6786 else
6787 assign(res, unop(Iop_Not64, mkexpr(arg_m)));
6788 DIP("vmvn %c%u, %c%u\n", Q ? 'q' : 'd', dreg, Q ? 'q' : 'd',
6789 mreg);
6790 break;
6791 case 12:
6792 case 13: {
6793 /* VPADAL */
6794 IROp op, add_op;
6795 U = (theInstr >> 7) & 1;
6796 if (Q) {
6797 switch (size) {
6798 case 0:
6799 op = U ? Iop_PwAddL8Ux16 : Iop_PwAddL8Sx16;
6800 add_op = Iop_Add16x8;
6801 break;
6802 case 1:
6803 op = U ? Iop_PwAddL16Ux8 : Iop_PwAddL16Sx8;
6804 add_op = Iop_Add32x4;
6805 break;
6806 case 2:
6807 op = U ? Iop_PwAddL32Ux4 : Iop_PwAddL32Sx4;
6808 add_op = Iop_Add64x2;
6809 break;
6810 case 3:
6811 return False;
6812 default:
6813 vassert(0);
6814 }
6815 } else {
6816 switch (size) {
6817 case 0:
6818 op = U ? Iop_PwAddL8Ux8 : Iop_PwAddL8Sx8;
6819 add_op = Iop_Add16x4;
6820 break;
6821 case 1:
6822 op = U ? Iop_PwAddL16Ux4 : Iop_PwAddL16Sx4;
6823 add_op = Iop_Add32x2;
6824 break;
6825 case 2:
6826 op = U ? Iop_PwAddL32Ux2 : Iop_PwAddL32Sx2;
6827 add_op = Iop_Add64;
6828 break;
6829 case 3:
6830 return False;
6831 default:
6832 vassert(0);
6833 }
6834 }
6835 if (Q) {
6836 arg_d = newTemp(Ity_V128);
6837 assign(arg_d, getQReg(dreg));
6838 } else {
6839 arg_d = newTemp(Ity_I64);
6840 assign(arg_d, getDRegI64(dreg));
6841 }
6842 assign(res, binop(add_op, unop(op, mkexpr(arg_m)),
6843 mkexpr(arg_d)));
6844 DIP("vpadal.%c%u %c%u, %c%u\n", U ? 'u' : 's', 8 << size,
6845 Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', mreg);
6846 break;
6847 }
6848 case 14: {
6849 /* VQABS */
6850 IROp op_sub, op_qsub, op_cmp;
6851 IRTemp mask, tmp;
6852 IRExpr *zero1, *zero2;
6853 IRExpr *neg, *neg2;
6854 if (Q) {
6855 zero1 = binop(Iop_64HLtoV128, mkU64(0), mkU64(0));
6856 zero2 = binop(Iop_64HLtoV128, mkU64(0), mkU64(0));
6857 mask = newTemp(Ity_V128);
6858 tmp = newTemp(Ity_V128);
6859 } else {
6860 zero1 = mkU64(0);
6861 zero2 = mkU64(0);
6862 mask = newTemp(Ity_I64);
6863 tmp = newTemp(Ity_I64);
6864 }
6865 switch (size) {
6866 case 0:
6867 op_sub = Q ? Iop_Sub8x16 : Iop_Sub8x8;
6868 op_qsub = Q ? Iop_QSub8Sx16 : Iop_QSub8Sx8;
6869 op_cmp = Q ? Iop_CmpGT8Sx16 : Iop_CmpGT8Sx8;
6870 break;
6871 case 1:
6872 op_sub = Q ? Iop_Sub16x8 : Iop_Sub16x4;
6873 op_qsub = Q ? Iop_QSub16Sx8 : Iop_QSub16Sx4;
6874 op_cmp = Q ? Iop_CmpGT16Sx8 : Iop_CmpGT16Sx4;
6875 break;
6876 case 2:
6877 op_sub = Q ? Iop_Sub32x4 : Iop_Sub32x2;
6878 op_qsub = Q ? Iop_QSub32Sx4 : Iop_QSub32Sx2;
6879 op_cmp = Q ? Iop_CmpGT32Sx4 : Iop_CmpGT32Sx2;
6880 break;
6881 case 3:
6882 return False;
6883 default:
6884 vassert(0);
6885 }
6886 assign(mask, binop(op_cmp, mkexpr(arg_m), zero1));
6887 neg = binop(op_qsub, zero2, mkexpr(arg_m));
6888 neg2 = binop(op_sub, zero2, mkexpr(arg_m));
6889 assign(res, binop(Q ? Iop_OrV128 : Iop_Or64,
6890 binop(Q ? Iop_AndV128 : Iop_And64,
6891 mkexpr(mask),
6892 mkexpr(arg_m)),
6893 binop(Q ? Iop_AndV128 : Iop_And64,
6894 unop(Q ? Iop_NotV128 : Iop_Not64,
6895 mkexpr(mask)),
6896 neg)));
6897#ifndef DISABLE_QC_FLAG
6898 assign(tmp, binop(Q ? Iop_OrV128 : Iop_Or64,
6899 binop(Q ? Iop_AndV128 : Iop_And64,
6900 mkexpr(mask),
6901 mkexpr(arg_m)),
6902 binop(Q ? Iop_AndV128 : Iop_And64,
6903 unop(Q ? Iop_NotV128 : Iop_Not64,
6904 mkexpr(mask)),
6905 neg2)));
6906 setFlag_QC(mkexpr(res), mkexpr(tmp), Q, condT);
6907#endif
6908 DIP("vqabs.s%u %c%u, %c%u\n", 8 << size, Q ? 'q' : 'd', dreg,
6909 Q ? 'q' : 'd', mreg);
6910 break;
6911 }
6912 case 15: {
6913 /* VQNEG */
6914 IROp op, op2;
6915 IRExpr *zero;
6916 if (Q) {
6917 zero = binop(Iop_64HLtoV128, mkU64(0), mkU64(0));
6918 } else {
6919 zero = mkU64(0);
6920 }
6921 switch (size) {
6922 case 0:
6923 op = Q ? Iop_QSub8Sx16 : Iop_QSub8Sx8;
6924 op2 = Q ? Iop_Sub8x16 : Iop_Sub8x8;
6925 break;
6926 case 1:
6927 op = Q ? Iop_QSub16Sx8 : Iop_QSub16Sx4;
6928 op2 = Q ? Iop_Sub16x8 : Iop_Sub16x4;
6929 break;
6930 case 2:
6931 op = Q ? Iop_QSub32Sx4 : Iop_QSub32Sx2;
6932 op2 = Q ? Iop_Sub32x4 : Iop_Sub32x2;
6933 break;
6934 case 3:
6935 return False;
6936 default:
6937 vassert(0);
6938 }
6939 assign(res, binop(op, zero, mkexpr(arg_m)));
6940#ifndef DISABLE_QC_FLAG
6941 setFlag_QC(mkexpr(res), binop(op2, zero, mkexpr(arg_m)),
6942 Q, condT);
6943#endif
6944 DIP("vqneg.s%u %c%u, %c%u\n", 8 << size, Q ? 'q' : 'd', dreg,
6945 Q ? 'q' : 'd', mreg);
6946 break;
6947 }
6948 default:
6949 vassert(0);
6950 }
6951 if (Q) {
6952 putQReg(dreg, mkexpr(res), condT);
6953 } else {
6954 putDRegI64(dreg, mkexpr(res), condT);
6955 }
6956 return True;
6957 case 1:
6958 if (Q) {
6959 arg_m = newTemp(Ity_V128);
6960 res = newTemp(Ity_V128);
6961 assign(arg_m, getQReg(mreg));
6962 } else {
6963 arg_m = newTemp(Ity_I64);
6964 res = newTemp(Ity_I64);
6965 assign(arg_m, getDRegI64(mreg));
6966 }
6967 switch ((B >> 1) & 0x7) {
6968 case 0: {
6969 /* VCGT #0 */
6970 IRExpr *zero;
6971 IROp op;
6972 if (Q) {
6973 zero = binop(Iop_64HLtoV128, mkU64(0), mkU64(0));
6974 } else {
6975 zero = mkU64(0);
6976 }
6977 if (F) {
6978 switch (size) {
6979 case 0: case 1: case 3: return False;
6980 case 2: op = Q ? Iop_CmpGT32Fx4 : Iop_CmpGT32Fx2; break;
6981 default: vassert(0);
6982 }
6983 } else {
6984 switch (size) {
6985 case 0: op = Q ? Iop_CmpGT8Sx16 : Iop_CmpGT8Sx8; break;
6986 case 1: op = Q ? Iop_CmpGT16Sx8 : Iop_CmpGT16Sx4; break;
6987 case 2: op = Q ? Iop_CmpGT32Sx4 : Iop_CmpGT32Sx2; break;
6988 case 3: return False;
6989 default: vassert(0);
6990 }
6991 }
6992 assign(res, binop(op, mkexpr(arg_m), zero));
6993 DIP("vcgt.%c%u %c%u, %c%u, #0\n", F ? 'f' : 's', 8 << size,
6994 Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', mreg);
6995 break;
6996 }
6997 case 1: {
6998 /* VCGE #0 */
6999 IROp op;
7000 IRExpr *zero;
7001 if (Q) {
7002 zero = binop(Iop_64HLtoV128, mkU64(0), mkU64(0));
7003 } else {
7004 zero = mkU64(0);
7005 }
7006 if (F) {
7007 switch (size) {
7008 case 0: case 1: case 3: return False;
7009 case 2: op = Q ? Iop_CmpGE32Fx4 : Iop_CmpGE32Fx2; break;
7010 default: vassert(0);
7011 }
7012 assign(res, binop(op, mkexpr(arg_m), zero));
7013 } else {
7014 switch (size) {
7015 case 0: op = Q ? Iop_CmpGT8Sx16 : Iop_CmpGT8Sx8; break;
7016 case 1: op = Q ? Iop_CmpGT16Sx8 : Iop_CmpGT16Sx4; break;
7017 case 2: op = Q ? Iop_CmpGT32Sx4 : Iop_CmpGT32Sx2; break;
7018 case 3: return False;
7019 default: vassert(0);
7020 }
7021 assign(res, unop(Q ? Iop_NotV128 : Iop_Not64,
7022 binop(op, zero, mkexpr(arg_m))));
7023 }
7024 DIP("vcge.%c%u %c%u, %c%u, #0\n", F ? 'f' : 's', 8 << size,
7025 Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', mreg);
7026 break;
7027 }
7028 case 2: {
7029 /* VCEQ #0 */
7030 IROp op;
7031 IRExpr *zero;
7032 if (F) {
7033 if (Q) {
7034 zero = binop(Iop_64HLtoV128, mkU64(0), mkU64(0));
7035 } else {
7036 zero = mkU64(0);
7037 }
7038 switch (size) {
7039 case 0: case 1: case 3: return False;
7040 case 2: op = Q ? Iop_CmpEQ32Fx4 : Iop_CmpEQ32Fx2; break;
7041 default: vassert(0);
7042 }
7043 assign(res, binop(op, zero, mkexpr(arg_m)));
7044 } else {
7045 switch (size) {
7046 case 0: op = Q ? Iop_CmpNEZ8x16 : Iop_CmpNEZ8x8; break;
7047 case 1: op = Q ? Iop_CmpNEZ16x8 : Iop_CmpNEZ16x4; break;
7048 case 2: op = Q ? Iop_CmpNEZ32x4 : Iop_CmpNEZ32x2; break;
7049 case 3: return False;
7050 default: vassert(0);
7051 }
7052 assign(res, unop(Q ? Iop_NotV128 : Iop_Not64,
7053 unop(op, mkexpr(arg_m))));
7054 }
7055 DIP("vceq.%c%u %c%u, %c%u, #0\n", F ? 'f' : 'i', 8 << size,
7056 Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', mreg);
7057 break;
7058 }
7059 case 3: {
7060 /* VCLE #0 */
7061 IRExpr *zero;
7062 IROp op;
7063 if (Q) {
7064 zero = binop(Iop_64HLtoV128, mkU64(0), mkU64(0));
7065 } else {
7066 zero = mkU64(0);
7067 }
7068 if (F) {
7069 switch (size) {
7070 case 0: case 1: case 3: return False;
7071 case 2: op = Q ? Iop_CmpGE32Fx4 : Iop_CmpGE32Fx2; break;
7072 default: vassert(0);
7073 }
7074 assign(res, binop(op, zero, mkexpr(arg_m)));
7075 } else {
7076 switch (size) {
7077 case 0: op = Q ? Iop_CmpGT8Sx16 : Iop_CmpGT8Sx8; break;
7078 case 1: op = Q ? Iop_CmpGT16Sx8 : Iop_CmpGT16Sx4; break;
7079 case 2: op = Q ? Iop_CmpGT32Sx4 : Iop_CmpGT32Sx2; break;
7080 case 3: return False;
7081 default: vassert(0);
7082 }
7083 assign(res, unop(Q ? Iop_NotV128 : Iop_Not64,
7084 binop(op, mkexpr(arg_m), zero)));
7085 }
7086 DIP("vcle.%c%u %c%u, %c%u, #0\n", F ? 'f' : 's', 8 << size,
7087 Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', mreg);
7088 break;
7089 }
7090 case 4: {
7091 /* VCLT #0 */
7092 IROp op;
7093 IRExpr *zero;
7094 if (Q) {
7095 zero = binop(Iop_64HLtoV128, mkU64(0), mkU64(0));
7096 } else {
7097 zero = mkU64(0);
7098 }
7099 if (F) {
7100 switch (size) {
7101 case 0: case 1: case 3: return False;
7102 case 2: op = Q ? Iop_CmpGT32Fx4 : Iop_CmpGT32Fx2; break;
7103 default: vassert(0);
7104 }
7105 assign(res, binop(op, zero, mkexpr(arg_m)));
7106 } else {
7107 switch (size) {
7108 case 0: op = Q ? Iop_CmpGT8Sx16 : Iop_CmpGT8Sx8; break;
7109 case 1: op = Q ? Iop_CmpGT16Sx8 : Iop_CmpGT16Sx4; break;
7110 case 2: op = Q ? Iop_CmpGT32Sx4 : Iop_CmpGT32Sx2; break;
7111 case 3: return False;
7112 default: vassert(0);
7113 }
7114 assign(res, binop(op, zero, mkexpr(arg_m)));
7115 }
7116 DIP("vclt.%c%u %c%u, %c%u, #0\n", F ? 'f' : 's', 8 << size,
7117 Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', mreg);
7118 break;
7119 }
7120 case 5:
7121 return False;
7122 case 6: {
7123 /* VABS */
7124 if (!F) {
7125 IROp op;
7126 switch(size) {
7127 case 0: op = Q ? Iop_Abs8x16 : Iop_Abs8x8; break;
7128 case 1: op = Q ? Iop_Abs16x8 : Iop_Abs16x4; break;
7129 case 2: op = Q ? Iop_Abs32x4 : Iop_Abs32x2; break;
7130 case 3: return False;
7131 default: vassert(0);
7132 }
7133 assign(res, unop(op, mkexpr(arg_m)));
7134 } else {
7135 assign(res, unop(Q ? Iop_Abs32Fx4 : Iop_Abs32Fx2,
7136 mkexpr(arg_m)));
7137 }
7138 DIP("vabs.%c%u %c%u, %c%u\n",
7139 F ? 'f' : 's', 8 << size, Q ? 'q' : 'd', dreg,
7140 Q ? 'q' : 'd', mreg);
7141 break;
7142 }
7143 case 7: {
7144 /* VNEG */
7145 IROp op;
7146 IRExpr *zero;
7147 if (F) {
7148 switch (size) {
7149 case 0: case 1: case 3: return False;
7150 case 2: op = Q ? Iop_Neg32Fx4 : Iop_Neg32Fx2; break;
7151 default: vassert(0);
7152 }
7153 assign(res, unop(op, mkexpr(arg_m)));
7154 } else {
7155 if (Q) {
7156 zero = binop(Iop_64HLtoV128, mkU64(0), mkU64(0));
7157 } else {
7158 zero = mkU64(0);
7159 }
7160 switch (size) {
7161 case 0: op = Q ? Iop_Sub8x16 : Iop_Sub8x8; break;
7162 case 1: op = Q ? Iop_Sub16x8 : Iop_Sub16x4; break;
7163 case 2: op = Q ? Iop_Sub32x4 : Iop_Sub32x2; break;
7164 case 3: return False;
7165 default: vassert(0);
7166 }
7167 assign(res, binop(op, zero, mkexpr(arg_m)));
7168 }
7169 DIP("vneg.%c%u %c%u, %c%u\n",
7170 F ? 'f' : 's', 8 << size, Q ? 'q' : 'd', dreg,
7171 Q ? 'q' : 'd', mreg);
7172 break;
7173 }
7174 default:
7175 vassert(0);
7176 }
7177 if (Q) {
7178 putQReg(dreg, mkexpr(res), condT);
7179 } else {
7180 putDRegI64(dreg, mkexpr(res), condT);
7181 }
7182 return True;
7183 case 2:
7184 if ((B >> 1) == 0) {
7185 /* VSWP */
7186 if (Q) {
7187 arg_m = newTemp(Ity_V128);
7188 assign(arg_m, getQReg(mreg));
7189 putQReg(mreg, getQReg(dreg), condT);
7190 putQReg(dreg, mkexpr(arg_m), condT);
7191 } else {
7192 arg_m = newTemp(Ity_I64);
7193 assign(arg_m, getDRegI64(mreg));
7194 putDRegI64(mreg, getDRegI64(dreg), condT);
7195 putDRegI64(dreg, mkexpr(arg_m), condT);
7196 }
7197 DIP("vswp %c%u, %c%u\n",
7198 Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', mreg);
7199 return True;
7200 } else if ((B >> 1) == 1) {
7201 /* VTRN */
7202 IROp op_lo, op_hi;
7203 IRTemp res1, res2;
7204 if (Q) {
7205 arg_m = newTemp(Ity_V128);
7206 arg_d = newTemp(Ity_V128);
7207 res1 = newTemp(Ity_V128);
7208 res2 = newTemp(Ity_V128);
7209 assign(arg_m, getQReg(mreg));
7210 assign(arg_d, getQReg(dreg));
7211 } else {
7212 res1 = newTemp(Ity_I64);
7213 res2 = newTemp(Ity_I64);
7214 arg_m = newTemp(Ity_I64);
7215 arg_d = newTemp(Ity_I64);
7216 assign(arg_m, getDRegI64(mreg));
7217 assign(arg_d, getDRegI64(dreg));
7218 }
7219 if (Q) {
7220 switch (size) {
7221 case 0:
7222 op_lo = Iop_InterleaveOddLanes8x16;
7223 op_hi = Iop_InterleaveEvenLanes8x16;
7224 break;
7225 case 1:
7226 op_lo = Iop_InterleaveOddLanes16x8;
7227 op_hi = Iop_InterleaveEvenLanes16x8;
7228 break;
7229 case 2:
7230 op_lo = Iop_InterleaveOddLanes32x4;
7231 op_hi = Iop_InterleaveEvenLanes32x4;
7232 break;
7233 case 3:
7234 return False;
7235 default:
7236 vassert(0);
7237 }
7238 } else {
7239 switch (size) {
7240 case 0:
7241 op_lo = Iop_InterleaveOddLanes8x8;
7242 op_hi = Iop_InterleaveEvenLanes8x8;
7243 break;
7244 case 1:
7245 op_lo = Iop_InterleaveOddLanes16x4;
7246 op_hi = Iop_InterleaveEvenLanes16x4;
7247 break;
7248 case 2:
sewardjebba9ee2010-09-22 16:27:08 +00007249 op_lo = Iop_InterleaveLO32x2;
7250 op_hi = Iop_InterleaveHI32x2;
sewardjd2664472010-08-22 12:44:20 +00007251 break;
7252 case 3:
7253 return False;
7254 default:
7255 vassert(0);
7256 }
7257 }
7258 assign(res1, binop(op_lo, mkexpr(arg_m), mkexpr(arg_d)));
7259 assign(res2, binop(op_hi, mkexpr(arg_m), mkexpr(arg_d)));
7260 if (Q) {
7261 putQReg(dreg, mkexpr(res1), condT);
7262 putQReg(mreg, mkexpr(res2), condT);
7263 } else {
7264 putDRegI64(dreg, mkexpr(res1), condT);
7265 putDRegI64(mreg, mkexpr(res2), condT);
7266 }
7267 DIP("vtrn.%u %c%u, %c%u\n",
7268 8 << size, Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', mreg);
7269 return True;
7270 } else if ((B >> 1) == 2) {
7271 /* VUZP */
7272 IROp op_lo, op_hi;
7273 IRTemp res1, res2;
7274 if (!Q && size == 2)
7275 return False;
7276 if (Q) {
7277 arg_m = newTemp(Ity_V128);
7278 arg_d = newTemp(Ity_V128);
7279 res1 = newTemp(Ity_V128);
7280 res2 = newTemp(Ity_V128);
7281 assign(arg_m, getQReg(mreg));
7282 assign(arg_d, getQReg(dreg));
7283 } else {
7284 res1 = newTemp(Ity_I64);
7285 res2 = newTemp(Ity_I64);
7286 arg_m = newTemp(Ity_I64);
7287 arg_d = newTemp(Ity_I64);
7288 assign(arg_m, getDRegI64(mreg));
7289 assign(arg_d, getDRegI64(dreg));
7290 }
7291 switch (size) {
7292 case 0:
7293 op_lo = Q ? Iop_CatOddLanes8x16 : Iop_CatOddLanes8x8;
7294 op_hi = Q ? Iop_CatEvenLanes8x16 : Iop_CatEvenLanes8x8;
7295 break;
7296 case 1:
7297 op_lo = Q ? Iop_CatOddLanes16x8 : Iop_CatOddLanes16x4;
7298 op_hi = Q ? Iop_CatEvenLanes16x8 : Iop_CatEvenLanes16x4;
7299 break;
7300 case 2:
7301 op_lo = Iop_CatOddLanes32x4;
7302 op_hi = Iop_CatEvenLanes32x4;
7303 break;
7304 case 3:
7305 return False;
7306 default:
7307 vassert(0);
7308 }
7309 assign(res1, binop(op_lo, mkexpr(arg_m), mkexpr(arg_d)));
7310 assign(res2, binop(op_hi, mkexpr(arg_m), mkexpr(arg_d)));
7311 if (Q) {
7312 putQReg(dreg, mkexpr(res1), condT);
7313 putQReg(mreg, mkexpr(res2), condT);
7314 } else {
7315 putDRegI64(dreg, mkexpr(res1), condT);
7316 putDRegI64(mreg, mkexpr(res2), condT);
7317 }
7318 DIP("vuzp.%u %c%u, %c%u\n",
7319 8 << size, Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', mreg);
7320 return True;
7321 } else if ((B >> 1) == 3) {
7322 /* VZIP */
7323 IROp op_lo, op_hi;
7324 IRTemp res1, res2;
7325 if (!Q && size == 2)
7326 return False;
7327 if (Q) {
7328 arg_m = newTemp(Ity_V128);
7329 arg_d = newTemp(Ity_V128);
7330 res1 = newTemp(Ity_V128);
7331 res2 = newTemp(Ity_V128);
7332 assign(arg_m, getQReg(mreg));
7333 assign(arg_d, getQReg(dreg));
7334 } else {
7335 res1 = newTemp(Ity_I64);
7336 res2 = newTemp(Ity_I64);
7337 arg_m = newTemp(Ity_I64);
7338 arg_d = newTemp(Ity_I64);
7339 assign(arg_m, getDRegI64(mreg));
7340 assign(arg_d, getDRegI64(dreg));
7341 }
7342 switch (size) {
7343 case 0:
sewardjb0d80ea2010-10-06 20:47:22 +00007344 op_lo = Q ? Iop_InterleaveHI8x16 : Iop_InterleaveHI8x8;
sewardjd2664472010-08-22 12:44:20 +00007345 op_hi = Q ? Iop_InterleaveLO8x16 : Iop_InterleaveLO8x8;
7346 break;
7347 case 1:
7348 op_lo = Q ? Iop_InterleaveHI16x8 : Iop_InterleaveHI16x4;
7349 op_hi = Q ? Iop_InterleaveLO16x8 : Iop_InterleaveLO16x4;
7350 break;
7351 case 2:
7352 op_lo = Iop_InterleaveHI32x4;
7353 op_hi = Iop_InterleaveLO32x4;
7354 break;
7355 case 3:
7356 return False;
7357 default:
7358 vassert(0);
7359 }
7360 assign(res1, binop(op_lo, mkexpr(arg_m), mkexpr(arg_d)));
7361 assign(res2, binop(op_hi, mkexpr(arg_m), mkexpr(arg_d)));
7362 if (Q) {
7363 putQReg(dreg, mkexpr(res1), condT);
7364 putQReg(mreg, mkexpr(res2), condT);
7365 } else {
7366 putDRegI64(dreg, mkexpr(res1), condT);
7367 putDRegI64(mreg, mkexpr(res2), condT);
7368 }
7369 DIP("vzip.%u %c%u, %c%u\n",
7370 8 << size, Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', mreg);
7371 return True;
7372 } else if (B == 8) {
7373 /* VMOVN */
7374 IROp op;
7375 mreg >>= 1;
7376 switch (size) {
sewardj5f438dd2011-06-16 11:36:23 +00007377 case 0: op = Iop_NarrowUn16to8x8; break;
7378 case 1: op = Iop_NarrowUn32to16x4; break;
7379 case 2: op = Iop_NarrowUn64to32x2; break;
sewardjd2664472010-08-22 12:44:20 +00007380 case 3: return False;
7381 default: vassert(0);
7382 }
7383 putDRegI64(dreg, unop(op, getQReg(mreg)), condT);
7384 DIP("vmovn.i%u d%u, q%u\n", 16 << size, dreg, mreg);
7385 return True;
7386 } else if (B == 9 || (B >> 1) == 5) {
7387 /* VQMOVN, VQMOVUN */
7388 IROp op, op2;
7389 IRTemp tmp;
7390 dreg = ((theInstr >> 18) & 0x10) | ((theInstr >> 12) & 0xF);
7391 mreg = ((theInstr >> 1) & 0x10) | (theInstr & 0xF);
7392 if (mreg & 1)
7393 return False;
7394 mreg >>= 1;
7395 switch (size) {
sewardj5f438dd2011-06-16 11:36:23 +00007396 case 0: op2 = Iop_NarrowUn16to8x8; break;
7397 case 1: op2 = Iop_NarrowUn32to16x4; break;
7398 case 2: op2 = Iop_NarrowUn64to32x2; break;
sewardjd2664472010-08-22 12:44:20 +00007399 case 3: return False;
7400 default: vassert(0);
7401 }
7402 switch (B & 3) {
7403 case 0:
7404 vassert(0);
7405 case 1:
7406 switch (size) {
sewardj5f438dd2011-06-16 11:36:23 +00007407 case 0: op = Iop_QNarrowUn16Sto8Ux8; break;
7408 case 1: op = Iop_QNarrowUn32Sto16Ux4; break;
7409 case 2: op = Iop_QNarrowUn64Sto32Ux2; break;
sewardjd2664472010-08-22 12:44:20 +00007410 case 3: return False;
7411 default: vassert(0);
7412 }
7413 DIP("vqmovun.s%u d%u, q%u\n", 16 << size, dreg, mreg);
7414 break;
7415 case 2:
7416 switch (size) {
sewardj5f438dd2011-06-16 11:36:23 +00007417 case 0: op = Iop_QNarrowUn16Sto8Sx8; break;
7418 case 1: op = Iop_QNarrowUn32Sto16Sx4; break;
7419 case 2: op = Iop_QNarrowUn64Sto32Sx2; break;
sewardjd2664472010-08-22 12:44:20 +00007420 case 3: return False;
7421 default: vassert(0);
7422 }
7423 DIP("vqmovn.s%u d%u, q%u\n", 16 << size, dreg, mreg);
7424 break;
7425 case 3:
7426 switch (size) {
sewardj5f438dd2011-06-16 11:36:23 +00007427 case 0: op = Iop_QNarrowUn16Uto8Ux8; break;
7428 case 1: op = Iop_QNarrowUn32Uto16Ux4; break;
7429 case 2: op = Iop_QNarrowUn64Uto32Ux2; break;
sewardjd2664472010-08-22 12:44:20 +00007430 case 3: return False;
7431 default: vassert(0);
7432 }
7433 DIP("vqmovn.u%u d%u, q%u\n", 16 << size, dreg, mreg);
7434 break;
7435 default:
7436 vassert(0);
7437 }
7438 res = newTemp(Ity_I64);
7439 tmp = newTemp(Ity_I64);
7440 assign(res, unop(op, getQReg(mreg)));
7441#ifndef DISABLE_QC_FLAG
7442 assign(tmp, unop(op2, getQReg(mreg)));
7443 setFlag_QC(mkexpr(res), mkexpr(tmp), False, condT);
7444#endif
7445 putDRegI64(dreg, mkexpr(res), condT);
7446 return True;
7447 } else if (B == 12) {
7448 /* VSHLL (maximum shift) */
7449 IROp op, cvt;
7450 UInt shift_imm;
7451 if (Q)
7452 return False;
7453 if (dreg & 1)
7454 return False;
7455 dreg >>= 1;
7456 shift_imm = 8 << size;
7457 res = newTemp(Ity_V128);
7458 switch (size) {
sewardj5f438dd2011-06-16 11:36:23 +00007459 case 0: op = Iop_ShlN16x8; cvt = Iop_Widen8Uto16x8; break;
7460 case 1: op = Iop_ShlN32x4; cvt = Iop_Widen16Uto32x4; break;
7461 case 2: op = Iop_ShlN64x2; cvt = Iop_Widen32Uto64x2; break;
sewardjd2664472010-08-22 12:44:20 +00007462 case 3: return False;
7463 default: vassert(0);
7464 }
7465 assign(res, binop(op, unop(cvt, getDRegI64(mreg)),
7466 mkU8(shift_imm)));
7467 putQReg(dreg, mkexpr(res), condT);
7468 DIP("vshll.i%u q%u, d%u, #%u\n", 8 << size, dreg, mreg, 8 << size);
7469 return True;
7470 } else if ((B >> 3) == 3 && (B & 3) == 0) {
7471 /* VCVT (half<->single) */
7472 /* Half-precision extensions are needed to run this */
7473 vassert(0); // ATC
7474 if (((theInstr >> 18) & 3) != 1)
7475 return False;
7476 if ((theInstr >> 8) & 1) {
7477 if (dreg & 1)
7478 return False;
7479 dreg >>= 1;
7480 putQReg(dreg, unop(Iop_F16toF32x4, getDRegI64(mreg)),
7481 condT);
7482 DIP("vcvt.f32.f16 q%u, d%u\n", dreg, mreg);
7483 } else {
7484 if (mreg & 1)
7485 return False;
7486 mreg >>= 1;
7487 putDRegI64(dreg, unop(Iop_F32toF16x4, getQReg(mreg)),
7488 condT);
7489 DIP("vcvt.f16.f32 d%u, q%u\n", dreg, mreg);
7490 }
7491 return True;
7492 } else {
7493 return False;
7494 }
7495 vassert(0);
7496 return True;
7497 case 3:
7498 if (((B >> 1) & BITS4(1,1,0,1)) == BITS4(1,0,0,0)) {
7499 /* VRECPE */
7500 IROp op;
7501 F = (theInstr >> 8) & 1;
7502 if (size != 2)
7503 return False;
7504 if (Q) {
7505 op = F ? Iop_Recip32Fx4 : Iop_Recip32x4;
7506 putQReg(dreg, unop(op, getQReg(mreg)), condT);
7507 DIP("vrecpe.%c32 q%u, q%u\n", F ? 'f' : 'u', dreg, mreg);
7508 } else {
7509 op = F ? Iop_Recip32Fx2 : Iop_Recip32x2;
7510 putDRegI64(dreg, unop(op, getDRegI64(mreg)), condT);
7511 DIP("vrecpe.%c32 d%u, d%u\n", F ? 'f' : 'u', dreg, mreg);
7512 }
7513 return True;
7514 } else if (((B >> 1) & BITS4(1,1,0,1)) == BITS4(1,0,0,1)) {
7515 /* VRSQRTE */
7516 IROp op;
7517 F = (B >> 2) & 1;
7518 if (size != 2)
7519 return False;
7520 if (F) {
7521 /* fp */
7522 op = Q ? Iop_Rsqrte32Fx4 : Iop_Rsqrte32Fx2;
7523 } else {
7524 /* unsigned int */
7525 op = Q ? Iop_Rsqrte32x4 : Iop_Rsqrte32x2;
7526 }
7527 if (Q) {
7528 putQReg(dreg, unop(op, getQReg(mreg)), condT);
7529 DIP("vrsqrte.%c32 q%u, q%u\n", F ? 'f' : 'u', dreg, mreg);
7530 } else {
7531 putDRegI64(dreg, unop(op, getDRegI64(mreg)), condT);
7532 DIP("vrsqrte.%c32 d%u, d%u\n", F ? 'f' : 'u', dreg, mreg);
7533 }
7534 return True;
7535 } else if ((B >> 3) == 3) {
7536 /* VCVT (fp<->integer) */
7537 IROp op;
7538 if (size != 2)
7539 return False;
7540 switch ((B >> 1) & 3) {
7541 case 0:
7542 op = Q ? Iop_I32StoFx4 : Iop_I32StoFx2;
7543 DIP("vcvt.f32.s32 %c%u, %c%u\n",
7544 Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', mreg);
7545 break;
7546 case 1:
7547 op = Q ? Iop_I32UtoFx4 : Iop_I32UtoFx2;
7548 DIP("vcvt.f32.u32 %c%u, %c%u\n",
7549 Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', mreg);
7550 break;
7551 case 2:
7552 op = Q ? Iop_FtoI32Sx4_RZ : Iop_FtoI32Sx2_RZ;
7553 DIP("vcvt.s32.f32 %c%u, %c%u\n",
7554 Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', mreg);
7555 break;
7556 case 3:
7557 op = Q ? Iop_FtoI32Ux4_RZ : Iop_FtoI32Ux2_RZ;
7558 DIP("vcvt.u32.f32 %c%u, %c%u\n",
7559 Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', mreg);
7560 break;
7561 default:
7562 vassert(0);
7563 }
7564 if (Q) {
7565 putQReg(dreg, unop(op, getQReg(mreg)), condT);
7566 } else {
7567 putDRegI64(dreg, unop(op, getDRegI64(mreg)), condT);
7568 }
7569 return True;
7570 } else {
7571 return False;
7572 }
7573 vassert(0);
7574 return True;
7575 default:
7576 vassert(0);
7577 }
7578 return False;
7579}
7580
7581/* A7.4.6 One register and a modified immediate value */
7582static
7583void ppNeonImm(UInt imm, UInt cmode, UInt op)
7584{
7585 int i;
7586 switch (cmode) {
7587 case 0: case 1: case 8: case 9:
7588 vex_printf("0x%x", imm);
7589 break;
7590 case 2: case 3: case 10: case 11:
7591 vex_printf("0x%x00", imm);
7592 break;
7593 case 4: case 5:
7594 vex_printf("0x%x0000", imm);
7595 break;
7596 case 6: case 7:
7597 vex_printf("0x%x000000", imm);
7598 break;
7599 case 12:
7600 vex_printf("0x%xff", imm);
7601 break;
7602 case 13:
7603 vex_printf("0x%xffff", imm);
7604 break;
7605 case 14:
7606 if (op) {
7607 vex_printf("0x");
7608 for (i = 7; i >= 0; i--)
7609 vex_printf("%s", (imm & (1 << i)) ? "ff" : "00");
7610 } else {
7611 vex_printf("0x%x", imm);
7612 }
7613 break;
7614 case 15:
7615 vex_printf("0x%x", imm);
7616 break;
7617 }
7618}
7619
7620static
7621const char *ppNeonImmType(UInt cmode, UInt op)
7622{
7623 switch (cmode) {
7624 case 0 ... 7:
7625 case 12: case 13:
7626 return "i32";
7627 case 8 ... 11:
7628 return "i16";
7629 case 14:
7630 if (op)
7631 return "i64";
7632 else
7633 return "i8";
7634 case 15:
7635 if (op)
7636 vassert(0);
7637 else
7638 return "f32";
7639 default:
7640 vassert(0);
7641 }
7642}
7643
7644static
7645void DIPimm(UInt imm, UInt cmode, UInt op,
7646 const char *instr, UInt Q, UInt dreg)
7647{
7648 if (vex_traceflags & VEX_TRACE_FE) {
7649 vex_printf("%s.%s %c%u, #", instr,
7650 ppNeonImmType(cmode, op), Q ? 'q' : 'd', dreg);
7651 ppNeonImm(imm, cmode, op);
7652 vex_printf("\n");
7653 }
7654}
7655
7656static
7657Bool dis_neon_data_1reg_and_imm ( UInt theInstr, IRTemp condT )
7658{
7659 UInt dreg = get_neon_d_regno(theInstr);
7660 ULong imm_raw = ((theInstr >> 17) & 0x80) | ((theInstr >> 12) & 0x70) |
7661 (theInstr & 0xf);
7662 ULong imm_raw_pp = imm_raw;
7663 UInt cmode = (theInstr >> 8) & 0xf;
7664 UInt op_bit = (theInstr >> 5) & 1;
7665 ULong imm = 0;
7666 UInt Q = (theInstr >> 6) & 1;
7667 int i, j;
7668 UInt tmp;
7669 IRExpr *imm_val;
7670 IRExpr *expr;
7671 IRTemp tmp_var;
7672 switch(cmode) {
7673 case 7: case 6:
7674 imm_raw = imm_raw << 8;
7675 /* fallthrough */
7676 case 5: case 4:
7677 imm_raw = imm_raw << 8;
7678 /* fallthrough */
7679 case 3: case 2:
7680 imm_raw = imm_raw << 8;
7681 /* fallthrough */
7682 case 0: case 1:
7683 imm = (imm_raw << 32) | imm_raw;
7684 break;
7685 case 11: case 10:
7686 imm_raw = imm_raw << 8;
7687 /* fallthrough */
7688 case 9: case 8:
7689 imm_raw = (imm_raw << 16) | imm_raw;
7690 imm = (imm_raw << 32) | imm_raw;
7691 break;
7692 case 13:
7693 imm_raw = (imm_raw << 8) | 0xff;
7694 /* fallthrough */
7695 case 12:
7696 imm_raw = (imm_raw << 8) | 0xff;
7697 imm = (imm_raw << 32) | imm_raw;
7698 break;
7699 case 14:
7700 if (! op_bit) {
7701 for(i = 0; i < 8; i++) {
7702 imm = (imm << 8) | imm_raw;
7703 }
7704 } else {
7705 for(i = 7; i >= 0; i--) {
7706 tmp = 0;
7707 for(j = 0; j < 8; j++) {
7708 tmp = (tmp << 1) | ((imm_raw >> i) & 1);
7709 }
7710 imm = (imm << 8) | tmp;
7711 }
7712 }
7713 break;
7714 case 15:
7715 imm = (imm_raw & 0x80) << 5;
sewardjf7558392011-07-19 15:48:29 +00007716 imm |= ((~imm_raw & 0x40) << 5);
sewardjd2664472010-08-22 12:44:20 +00007717 for(i = 1; i <= 4; i++)
7718 imm |= (imm_raw & 0x40) << i;
7719 imm |= (imm_raw & 0x7f);
7720 imm = imm << 19;
7721 imm = (imm << 32) | imm;
7722 break;
7723 default:
7724 return False;
7725 }
7726 if (Q) {
7727 imm_val = binop(Iop_64HLtoV128, mkU64(imm), mkU64(imm));
7728 } else {
7729 imm_val = mkU64(imm);
7730 }
7731 if (((op_bit == 0) &&
7732 (((cmode & 9) == 0) || ((cmode & 13) == 8) || ((cmode & 12) == 12))) ||
7733 ((op_bit == 1) && (cmode == 14))) {
7734 /* VMOV (immediate) */
7735 if (Q) {
7736 putQReg(dreg, imm_val, condT);
7737 } else {
7738 putDRegI64(dreg, imm_val, condT);
7739 }
7740 DIPimm(imm_raw_pp, cmode, op_bit, "vmov", Q, dreg);
7741 return True;
7742 }
7743 if ((op_bit == 1) &&
7744 (((cmode & 9) == 0) || ((cmode & 13) == 8) || ((cmode & 14) == 12))) {
7745 /* VMVN (immediate) */
7746 if (Q) {
7747 putQReg(dreg, unop(Iop_NotV128, imm_val), condT);
7748 } else {
7749 putDRegI64(dreg, unop(Iop_Not64, imm_val), condT);
7750 }
7751 DIPimm(imm_raw_pp, cmode, op_bit, "vmvn", Q, dreg);
7752 return True;
7753 }
7754 if (Q) {
7755 tmp_var = newTemp(Ity_V128);
7756 assign(tmp_var, getQReg(dreg));
7757 } else {
7758 tmp_var = newTemp(Ity_I64);
7759 assign(tmp_var, getDRegI64(dreg));
7760 }
7761 if ((op_bit == 0) && (((cmode & 9) == 1) || ((cmode & 13) == 9))) {
7762 /* VORR (immediate) */
7763 if (Q)
7764 expr = binop(Iop_OrV128, mkexpr(tmp_var), imm_val);
7765 else
7766 expr = binop(Iop_Or64, mkexpr(tmp_var), imm_val);
7767 DIPimm(imm_raw_pp, cmode, op_bit, "vorr", Q, dreg);
7768 } else if ((op_bit == 1) && (((cmode & 9) == 1) || ((cmode & 13) == 9))) {
7769 /* VBIC (immediate) */
7770 if (Q)
7771 expr = binop(Iop_AndV128, mkexpr(tmp_var),
7772 unop(Iop_NotV128, imm_val));
7773 else
7774 expr = binop(Iop_And64, mkexpr(tmp_var), unop(Iop_Not64, imm_val));
7775 DIPimm(imm_raw_pp, cmode, op_bit, "vbic", Q, dreg);
7776 } else {
7777 return False;
7778 }
7779 if (Q)
7780 putQReg(dreg, expr, condT);
7781 else
7782 putDRegI64(dreg, expr, condT);
7783 return True;
7784}
7785
7786/* A7.4 Advanced SIMD data-processing instructions */
7787static
7788Bool dis_neon_data_processing ( UInt theInstr, IRTemp condT )
7789{
7790 UInt A = (theInstr >> 19) & 0x1F;
7791 UInt B = (theInstr >> 8) & 0xF;
7792 UInt C = (theInstr >> 4) & 0xF;
7793 UInt U = (theInstr >> 24) & 0x1;
7794
7795 if (! (A & 0x10)) {
7796 return dis_neon_data_3same(theInstr, condT);
7797 }
7798 if (((A & 0x17) == 0x10) && ((C & 0x9) == 0x1)) {
7799 return dis_neon_data_1reg_and_imm(theInstr, condT);
7800 }
7801 if ((C & 1) == 1) {
7802 return dis_neon_data_2reg_and_shift(theInstr, condT);
7803 }
7804 if (((C & 5) == 0) && (((A & 0x14) == 0x10) || ((A & 0x16) == 0x14))) {
7805 return dis_neon_data_3diff(theInstr, condT);
7806 }
7807 if (((C & 5) == 4) && (((A & 0x14) == 0x10) || ((A & 0x16) == 0x14))) {
7808 return dis_neon_data_2reg_and_scalar(theInstr, condT);
7809 }
7810 if ((A & 0x16) == 0x16) {
7811 if ((U == 0) && ((C & 1) == 0)) {
7812 return dis_neon_vext(theInstr, condT);
7813 }
7814 if ((U != 1) || ((C & 1) == 1))
7815 return False;
7816 if ((B & 8) == 0) {
7817 return dis_neon_data_2reg_misc(theInstr, condT);
7818 }
7819 if ((B & 12) == 8) {
7820 return dis_neon_vtb(theInstr, condT);
7821 }
7822 if ((B == 12) && ((C & 9) == 0)) {
7823 return dis_neon_vdup(theInstr, condT);
7824 }
7825 }
7826 return False;
7827}
7828
7829
7830/*------------------------------------------------------------*/
7831/*--- NEON loads and stores ---*/
7832/*------------------------------------------------------------*/
7833
7834/* For NEON memory operations, we use the standard scheme to handle
7835 conditionalisation: generate a jump around the instruction if the
7836 condition is false. That's only necessary in Thumb mode, however,
7837 since in ARM mode NEON instructions are unconditional. */
7838
7839/* A helper function for what follows. It assumes we already went
7840 uncond as per comments at the top of this section. */
7841static
7842void mk_neon_elem_load_to_one_lane( UInt rD, UInt inc, UInt index,
7843 UInt N, UInt size, IRTemp addr )
7844{
7845 UInt i;
7846 switch (size) {
7847 case 0:
7848 putDRegI64(rD, triop(Iop_SetElem8x8, getDRegI64(rD), mkU8(index),
7849 loadLE(Ity_I8, mkexpr(addr))), IRTemp_INVALID);
7850 break;
7851 case 1:
7852 putDRegI64(rD, triop(Iop_SetElem16x4, getDRegI64(rD), mkU8(index),
7853 loadLE(Ity_I16, mkexpr(addr))), IRTemp_INVALID);
7854 break;
7855 case 2:
7856 putDRegI64(rD, triop(Iop_SetElem32x2, getDRegI64(rD), mkU8(index),
7857 loadLE(Ity_I32, mkexpr(addr))), IRTemp_INVALID);
7858 break;
7859 default:
7860 vassert(0);
7861 }
7862 for (i = 1; i <= N; i++) {
7863 switch (size) {
7864 case 0:
7865 putDRegI64(rD + i * inc,
7866 triop(Iop_SetElem8x8,
7867 getDRegI64(rD + i * inc),
7868 mkU8(index),
7869 loadLE(Ity_I8, binop(Iop_Add32,
7870 mkexpr(addr),
7871 mkU32(i * 1)))),
7872 IRTemp_INVALID);
7873 break;
7874 case 1:
7875 putDRegI64(rD + i * inc,
7876 triop(Iop_SetElem16x4,
7877 getDRegI64(rD + i * inc),
7878 mkU8(index),
7879 loadLE(Ity_I16, binop(Iop_Add32,
7880 mkexpr(addr),
7881 mkU32(i * 2)))),
7882 IRTemp_INVALID);
7883 break;
7884 case 2:
7885 putDRegI64(rD + i * inc,
7886 triop(Iop_SetElem32x2,
7887 getDRegI64(rD + i * inc),
7888 mkU8(index),
7889 loadLE(Ity_I32, binop(Iop_Add32,
7890 mkexpr(addr),
7891 mkU32(i * 4)))),
7892 IRTemp_INVALID);
7893 break;
7894 default:
7895 vassert(0);
7896 }
7897 }
7898}
7899
7900/* A(nother) helper function for what follows. It assumes we already
7901 went uncond as per comments at the top of this section. */
7902static
7903void mk_neon_elem_store_from_one_lane( UInt rD, UInt inc, UInt index,
7904 UInt N, UInt size, IRTemp addr )
7905{
7906 UInt i;
7907 switch (size) {
7908 case 0:
7909 storeLE(mkexpr(addr),
7910 binop(Iop_GetElem8x8, getDRegI64(rD), mkU8(index)));
7911 break;
7912 case 1:
7913 storeLE(mkexpr(addr),
7914 binop(Iop_GetElem16x4, getDRegI64(rD), mkU8(index)));
7915 break;
7916 case 2:
7917 storeLE(mkexpr(addr),
7918 binop(Iop_GetElem32x2, getDRegI64(rD), mkU8(index)));
7919 break;
7920 default:
7921 vassert(0);
7922 }
7923 for (i = 1; i <= N; i++) {
7924 switch (size) {
7925 case 0:
7926 storeLE(binop(Iop_Add32, mkexpr(addr), mkU32(i * 1)),
7927 binop(Iop_GetElem8x8, getDRegI64(rD + i * inc),
7928 mkU8(index)));
7929 break;
7930 case 1:
7931 storeLE(binop(Iop_Add32, mkexpr(addr), mkU32(i * 2)),
7932 binop(Iop_GetElem16x4, getDRegI64(rD + i * inc),
7933 mkU8(index)));
7934 break;
7935 case 2:
7936 storeLE(binop(Iop_Add32, mkexpr(addr), mkU32(i * 4)),
7937 binop(Iop_GetElem32x2, getDRegI64(rD + i * inc),
7938 mkU8(index)));
7939 break;
7940 default:
7941 vassert(0);
7942 }
7943 }
7944}
7945
7946/* A7.7 Advanced SIMD element or structure load/store instructions */
7947static
sewardj28958322011-07-21 22:45:42 +00007948Bool dis_neon_load_or_store ( UInt theInstr,
7949 Bool isT, IRTemp condT )
sewardjd2664472010-08-22 12:44:20 +00007950{
7951# define INSN(_bMax,_bMin) SLICE_UInt(theInstr, (_bMax), (_bMin))
sewardj28958322011-07-21 22:45:42 +00007952 UInt bA = INSN(23,23);
7953 UInt fB = INSN(11,8);
7954 UInt bL = INSN(21,21);
sewardjd2664472010-08-22 12:44:20 +00007955 UInt rD = (INSN(22,22) << 4) | INSN(15,12);
7956 UInt rN = INSN(19,16);
7957 UInt rM = INSN(3,0);
7958 UInt N, size, i, j;
7959 UInt inc;
7960 UInt regs = 1;
sewardjd2664472010-08-22 12:44:20 +00007961
7962 if (isT) {
7963 vassert(condT != IRTemp_INVALID);
7964 } else {
7965 vassert(condT == IRTemp_INVALID);
7966 }
7967 /* So now, if condT is not IRTemp_INVALID, we know we're
7968 dealing with Thumb code. */
7969
7970 if (INSN(20,20) != 0)
7971 return False;
7972
sewardj21eaf242010-08-31 09:18:22 +00007973 IRTemp initialRn = newTemp(Ity_I32);
7974 assign(initialRn, isT ? getIRegT(rN) : getIRegA(rN));
7975
7976 IRTemp initialRm = newTemp(Ity_I32);
7977 assign(initialRm, isT ? getIRegT(rM) : getIRegA(rM));
7978
sewardj28958322011-07-21 22:45:42 +00007979 /* There are 3 cases:
7980 (1) VSTn / VLDn (n-element structure from/to one lane)
7981 (2) VLDn (single element to all lanes)
7982 (3) VSTn / VLDn (multiple n-element structures)
7983 */
7984 if (bA) {
7985 N = fB & 3;
7986 if ((fB >> 2) < 3) {
7987 /* ------------ Case (1) ------------
7988 VSTn / VLDn (n-element structure from/to one lane) */
sewardjd2664472010-08-22 12:44:20 +00007989
sewardj28958322011-07-21 22:45:42 +00007990 size = fB >> 2;
sewardjd2664472010-08-22 12:44:20 +00007991
7992 switch (size) {
7993 case 0: i = INSN(7,5); inc = 1; break;
7994 case 1: i = INSN(7,6); inc = INSN(5,5) ? 2 : 1; break;
7995 case 2: i = INSN(7,7); inc = INSN(6,6) ? 2 : 1; break;
7996 case 3: return False;
7997 default: vassert(0);
7998 }
7999
sewardj21eaf242010-08-31 09:18:22 +00008000 IRTemp addr = newTemp(Ity_I32);
8001 assign(addr, mkexpr(initialRn));
sewardjd2664472010-08-22 12:44:20 +00008002
8003 // go uncond
8004 if (condT != IRTemp_INVALID)
8005 mk_skip_over_T32_if_cond_is_false(condT);
8006 // now uncond
8007
sewardj28958322011-07-21 22:45:42 +00008008 if (bL)
sewardjd2664472010-08-22 12:44:20 +00008009 mk_neon_elem_load_to_one_lane(rD, inc, i, N, size, addr);
8010 else
8011 mk_neon_elem_store_from_one_lane(rD, inc, i, N, size, addr);
sewardj28958322011-07-21 22:45:42 +00008012 DIP("v%s%u.%u {", bL ? "ld" : "st", N + 1, 8 << size);
sewardjd2664472010-08-22 12:44:20 +00008013 for (j = 0; j <= N; j++) {
8014 if (j)
8015 DIP(", ");
8016 DIP("d%u[%u]", rD + j * inc, i);
8017 }
sewardj17bf0aa2010-08-31 09:29:51 +00008018 DIP("}, [r%u]", rN);
8019 if (rM != 13 && rM != 15) {
8020 DIP(", r%u\n", rM);
8021 } else {
8022 DIP("%s\n", (rM != 15) ? "!" : "");
8023 }
sewardjd2664472010-08-22 12:44:20 +00008024 } else {
sewardj28958322011-07-21 22:45:42 +00008025 /* ------------ Case (2) ------------
8026 VLDn (single element to all lanes) */
sewardjd2664472010-08-22 12:44:20 +00008027 UInt r;
sewardj28958322011-07-21 22:45:42 +00008028 if (bL == 0)
sewardjd2664472010-08-22 12:44:20 +00008029 return False;
8030
8031 inc = INSN(5,5) + 1;
8032 size = INSN(7,6);
8033
8034 /* size == 3 and size == 2 cases differ in alignment constraints */
8035 if (size == 3 && N == 3 && INSN(4,4) == 1)
8036 size = 2;
8037
8038 if (size == 0 && N == 0 && INSN(4,4) == 1)
8039 return False;
8040 if (N == 2 && INSN(4,4) == 1)
8041 return False;
8042 if (size == 3)
8043 return False;
8044
8045 // go uncond
8046 if (condT != IRTemp_INVALID)
8047 mk_skip_over_T32_if_cond_is_false(condT);
8048 // now uncond
8049
sewardj21eaf242010-08-31 09:18:22 +00008050 IRTemp addr = newTemp(Ity_I32);
8051 assign(addr, mkexpr(initialRn));
sewardjd2664472010-08-22 12:44:20 +00008052
8053 if (N == 0 && INSN(5,5))
8054 regs = 2;
8055
8056 for (r = 0; r < regs; r++) {
8057 switch (size) {
8058 case 0:
8059 putDRegI64(rD + r, unop(Iop_Dup8x8,
8060 loadLE(Ity_I8, mkexpr(addr))),
8061 IRTemp_INVALID);
8062 break;
8063 case 1:
8064 putDRegI64(rD + r, unop(Iop_Dup16x4,
8065 loadLE(Ity_I16, mkexpr(addr))),
8066 IRTemp_INVALID);
8067 break;
8068 case 2:
8069 putDRegI64(rD + r, unop(Iop_Dup32x2,
8070 loadLE(Ity_I32, mkexpr(addr))),
8071 IRTemp_INVALID);
8072 break;
8073 default:
8074 vassert(0);
8075 }
8076 for (i = 1; i <= N; i++) {
8077 switch (size) {
8078 case 0:
8079 putDRegI64(rD + r + i * inc,
8080 unop(Iop_Dup8x8,
8081 loadLE(Ity_I8, binop(Iop_Add32,
8082 mkexpr(addr),
8083 mkU32(i * 1)))),
8084 IRTemp_INVALID);
8085 break;
8086 case 1:
8087 putDRegI64(rD + r + i * inc,
8088 unop(Iop_Dup16x4,
8089 loadLE(Ity_I16, binop(Iop_Add32,
8090 mkexpr(addr),
8091 mkU32(i * 2)))),
8092 IRTemp_INVALID);
8093 break;
8094 case 2:
8095 putDRegI64(rD + r + i * inc,
8096 unop(Iop_Dup32x2,
8097 loadLE(Ity_I32, binop(Iop_Add32,
8098 mkexpr(addr),
8099 mkU32(i * 4)))),
8100 IRTemp_INVALID);
8101 break;
8102 default:
8103 vassert(0);
8104 }
8105 }
8106 }
8107 DIP("vld%u.%u {", N + 1, 8 << size);
8108 for (r = 0; r < regs; r++) {
8109 for (i = 0; i <= N; i++) {
8110 if (i || r)
8111 DIP(", ");
8112 DIP("d%u[]", rD + r + i * inc);
8113 }
8114 }
sewardj17bf0aa2010-08-31 09:29:51 +00008115 DIP("}, [r%u]", rN);
8116 if (rM != 13 && rM != 15) {
8117 DIP(", r%u\n", rM);
8118 } else {
8119 DIP("%s\n", (rM != 15) ? "!" : "");
8120 }
sewardjd2664472010-08-22 12:44:20 +00008121 }
8122 /* Writeback. We're uncond here, so no condT-ing. */
8123 if (rM != 15) {
8124 if (rM == 13) {
8125 IRExpr* e = binop(Iop_Add32,
sewardj21eaf242010-08-31 09:18:22 +00008126 mkexpr(initialRn),
sewardjd2664472010-08-22 12:44:20 +00008127 mkU32((1 << size) * (N + 1)));
8128 if (isT)
8129 putIRegT(rN, e, IRTemp_INVALID);
8130 else
8131 putIRegA(rN, e, IRTemp_INVALID, Ijk_Boring);
8132 } else {
sewardj21eaf242010-08-31 09:18:22 +00008133 IRExpr* e = binop(Iop_Add32,
8134 mkexpr(initialRn),
8135 mkexpr(initialRm));
sewardjd2664472010-08-22 12:44:20 +00008136 if (isT)
8137 putIRegT(rN, e, IRTemp_INVALID);
8138 else
8139 putIRegA(rN, e, IRTemp_INVALID, Ijk_Boring);
8140 }
8141 }
8142 return True;
8143 } else {
sewardj28958322011-07-21 22:45:42 +00008144 /* ------------ Case (3) ------------
8145 VSTn / VLDn (multiple n-element structures) */
sewardjd2664472010-08-22 12:44:20 +00008146 IRTemp tmp;
8147 UInt r, elems;
sewardj28958322011-07-21 22:45:42 +00008148 if (fB == BITS4(0,0,1,0) || fB == BITS4(0,1,1,0)
8149 || fB == BITS4(0,1,1,1) || fB == BITS4(1,0,1,0)) {
sewardjd2664472010-08-22 12:44:20 +00008150 N = 0;
sewardj28958322011-07-21 22:45:42 +00008151 } else if (fB == BITS4(0,0,1,1) || fB == BITS4(1,0,0,0)
8152 || fB == BITS4(1,0,0,1)) {
sewardjd2664472010-08-22 12:44:20 +00008153 N = 1;
sewardj28958322011-07-21 22:45:42 +00008154 } else if (fB == BITS4(0,1,0,0) || fB == BITS4(0,1,0,1)) {
sewardjd2664472010-08-22 12:44:20 +00008155 N = 2;
sewardj28958322011-07-21 22:45:42 +00008156 } else if (fB == BITS4(0,0,0,0) || fB == BITS4(0,0,0,1)) {
sewardjd2664472010-08-22 12:44:20 +00008157 N = 3;
8158 } else {
8159 return False;
8160 }
sewardj28958322011-07-21 22:45:42 +00008161 inc = (fB & 1) + 1;
8162 if (N == 1 && fB == BITS4(0,0,1,1)) {
sewardjd2664472010-08-22 12:44:20 +00008163 regs = 2;
8164 } else if (N == 0) {
sewardj28958322011-07-21 22:45:42 +00008165 if (fB == BITS4(1,0,1,0)) {
sewardjd2664472010-08-22 12:44:20 +00008166 regs = 2;
sewardj28958322011-07-21 22:45:42 +00008167 } else if (fB == BITS4(0,1,1,0)) {
sewardjd2664472010-08-22 12:44:20 +00008168 regs = 3;
sewardj28958322011-07-21 22:45:42 +00008169 } else if (fB == BITS4(0,0,1,0)) {
sewardjd2664472010-08-22 12:44:20 +00008170 regs = 4;
8171 }
8172 }
8173
8174 size = INSN(7,6);
8175 if (N == 0 && size == 3)
8176 size = 2;
8177 if (size == 3)
8178 return False;
8179
8180 elems = 8 / (1 << size);
8181
8182 // go uncond
8183 if (condT != IRTemp_INVALID)
8184 mk_skip_over_T32_if_cond_is_false(condT);
8185 // now uncond
8186
sewardj21eaf242010-08-31 09:18:22 +00008187 IRTemp addr = newTemp(Ity_I32);
8188 assign(addr, mkexpr(initialRn));
sewardjd2664472010-08-22 12:44:20 +00008189
8190 for (r = 0; r < regs; r++) {
8191 for (i = 0; i < elems; i++) {
sewardj28958322011-07-21 22:45:42 +00008192 if (bL)
sewardjd2664472010-08-22 12:44:20 +00008193 mk_neon_elem_load_to_one_lane(rD + r, inc, i, N, size, addr);
8194 else
8195 mk_neon_elem_store_from_one_lane(rD + r, inc, i, N, size, addr);
8196 tmp = newTemp(Ity_I32);
8197 assign(tmp, binop(Iop_Add32, mkexpr(addr),
8198 mkU32((1 << size) * (N + 1))));
8199 addr = tmp;
8200 }
8201 }
8202 /* Writeback */
8203 if (rM != 15) {
8204 if (rM == 13) {
8205 IRExpr* e = binop(Iop_Add32,
sewardj21eaf242010-08-31 09:18:22 +00008206 mkexpr(initialRn),
sewardjd2664472010-08-22 12:44:20 +00008207 mkU32(8 * (N + 1) * regs));
8208 if (isT)
8209 putIRegT(rN, e, IRTemp_INVALID);
8210 else
8211 putIRegA(rN, e, IRTemp_INVALID, Ijk_Boring);
8212 } else {
sewardj21eaf242010-08-31 09:18:22 +00008213 IRExpr* e = binop(Iop_Add32,
8214 mkexpr(initialRn),
8215 mkexpr(initialRm));
sewardjd2664472010-08-22 12:44:20 +00008216 if (isT)
8217 putIRegT(rN, e, IRTemp_INVALID);
8218 else
8219 putIRegA(rN, e, IRTemp_INVALID, Ijk_Boring);
8220 }
8221 }
sewardj28958322011-07-21 22:45:42 +00008222 DIP("v%s%u.%u {", bL ? "ld" : "st", N + 1, 8 << INSN(7,6));
sewardjd2664472010-08-22 12:44:20 +00008223 if ((inc == 1 && regs * (N + 1) > 1)
8224 || (inc == 2 && regs > 1 && N > 0)) {
8225 DIP("d%u-d%u", rD, rD + regs * (N + 1) - 1);
8226 } else {
8227 for (r = 0; r < regs; r++) {
8228 for (i = 0; i <= N; i++) {
8229 if (i || r)
8230 DIP(", ");
8231 DIP("d%u", rD + r + i * inc);
8232 }
8233 }
8234 }
sewardj17bf0aa2010-08-31 09:29:51 +00008235 DIP("}, [r%u]", rN);
8236 if (rM != 13 && rM != 15) {
8237 DIP(", r%u\n", rM);
8238 } else {
8239 DIP("%s\n", (rM != 15) ? "!" : "");
8240 }
sewardjd2664472010-08-22 12:44:20 +00008241 return True;
8242 }
8243# undef INSN
8244}
8245
8246
8247/*------------------------------------------------------------*/
8248/*--- NEON, top level control ---*/
8249/*------------------------------------------------------------*/
8250
8251/* Both ARM and Thumb */
8252
8253/* Translate a NEON instruction. If successful, returns
8254 True and *dres may or may not be updated. If failure, returns
8255 False and doesn't change *dres nor create any IR.
8256
8257 The Thumb and ARM encodings are similar for the 24 bottom bits, but
8258 the top 8 bits are slightly different. In both cases, the caller
8259 must pass the entire 32 bits. Callers may pass any instruction;
8260 this ignores non-NEON ones.
8261
8262 Caller must supply an IRTemp 'condT' holding the gating condition,
8263 or IRTemp_INVALID indicating the insn is always executed. In ARM
8264 code, this must always be IRTemp_INVALID because NEON insns are
8265 unconditional for ARM.
8266
8267 Finally, the caller must indicate whether this occurs in ARM or in
8268 Thumb code.
8269*/
8270static Bool decode_NEON_instruction (
8271 /*MOD*/DisResult* dres,
8272 UInt insn32,
8273 IRTemp condT,
8274 Bool isT
8275 )
8276{
8277# define INSN(_bMax,_bMin) SLICE_UInt(insn32, (_bMax), (_bMin))
8278
8279 /* There are two kinds of instruction to deal with: load/store and
8280 data processing. In each case, in ARM mode we merely identify
8281 the kind, and pass it on to the relevant sub-handler. In Thumb
8282 mode we identify the kind, swizzle the bits around to make it
8283 have the same encoding as in ARM, and hand it on to the
8284 sub-handler.
8285 */
8286
8287 /* In ARM mode, NEON instructions can't be conditional. */
8288 if (!isT)
8289 vassert(condT == IRTemp_INVALID);
8290
8291 /* Data processing:
8292 Thumb: 111U 1111 AAAA Axxx xxxx BBBB CCCC xxxx
8293 ARM: 1111 001U AAAA Axxx xxxx BBBB CCCC xxxx
8294 */
8295 if (!isT && INSN(31,25) == BITS7(1,1,1,1,0,0,1)) {
8296 // ARM, DP
8297 return dis_neon_data_processing(INSN(31,0), condT);
8298 }
8299 if (isT && INSN(31,29) == BITS3(1,1,1)
8300 && INSN(27,24) == BITS4(1,1,1,1)) {
8301 // Thumb, DP
8302 UInt reformatted = INSN(23,0);
8303 reformatted |= (INSN(28,28) << 24); // U bit
8304 reformatted |= (BITS7(1,1,1,1,0,0,1) << 25);
8305 return dis_neon_data_processing(reformatted, condT);
8306 }
8307
8308 /* Load/store:
8309 Thumb: 1111 1001 AxL0 xxxx xxxx BBBB xxxx xxxx
8310 ARM: 1111 0100 AxL0 xxxx xxxx BBBB xxxx xxxx
8311 */
8312 if (!isT && INSN(31,24) == BITS8(1,1,1,1,0,1,0,0)) {
8313 // ARM, memory
sewardj28958322011-07-21 22:45:42 +00008314 return dis_neon_load_or_store(INSN(31,0), isT, condT);
sewardjd2664472010-08-22 12:44:20 +00008315 }
8316 if (isT && INSN(31,24) == BITS8(1,1,1,1,1,0,0,1)) {
8317 UInt reformatted = INSN(23,0);
8318 reformatted |= (BITS8(1,1,1,1,0,1,0,0) << 24);
sewardj28958322011-07-21 22:45:42 +00008319 return dis_neon_load_or_store(reformatted, isT, condT);
sewardjd2664472010-08-22 12:44:20 +00008320 }
8321
8322 /* Doesn't match. */
8323 return False;
8324
8325# undef INSN
8326}
8327
8328
8329/*------------------------------------------------------------*/
sewardj1f139f52010-08-29 12:33:02 +00008330/*--- V6 MEDIA instructions ---*/
8331/*------------------------------------------------------------*/
8332
8333/* Both ARM and Thumb */
8334
8335/* Translate a V6 media instruction. If successful, returns
8336 True and *dres may or may not be updated. If failure, returns
8337 False and doesn't change *dres nor create any IR.
8338
8339 The Thumb and ARM encodings are completely different. In Thumb
8340 mode, the caller must pass the entire 32 bits. In ARM mode it must
8341 pass the lower 28 bits. Apart from that, callers may pass any
8342 instruction; this function ignores anything it doesn't recognise.
8343
8344 Caller must supply an IRTemp 'condT' holding the gating condition,
8345 or IRTemp_INVALID indicating the insn is always executed.
8346
8347 Caller must also supply an ARMCondcode 'cond'. This is only used
8348 for debug printing, no other purpose. For ARM, this is simply the
8349 top 4 bits of the original instruction. For Thumb, the condition
8350 is not (really) known until run time, and so ARMCondAL should be
8351 passed, only so that printing of these instructions does not show
8352 any condition.
8353
8354 Finally, the caller must indicate whether this occurs in ARM or in
8355 Thumb code.
8356*/
8357static Bool decode_V6MEDIA_instruction (
8358 /*MOD*/DisResult* dres,
8359 UInt insnv6m,
8360 IRTemp condT,
8361 ARMCondcode conq,
8362 Bool isT
8363 )
8364{
8365# define INSNA(_bMax,_bMin) SLICE_UInt(insnv6m, (_bMax), (_bMin))
8366# define INSNT0(_bMax,_bMin) SLICE_UInt( ((insnv6m >> 16) & 0xFFFF), \
8367 (_bMax), (_bMin) )
8368# define INSNT1(_bMax,_bMin) SLICE_UInt( ((insnv6m >> 0) & 0xFFFF), \
8369 (_bMax), (_bMin) )
8370 HChar dis_buf[128];
8371 dis_buf[0] = 0;
8372
8373 if (isT) {
8374 vassert(conq == ARMCondAL);
8375 } else {
8376 vassert(INSNA(31,28) == BITS4(0,0,0,0)); // caller's obligation
8377 vassert(conq >= ARMCondEQ && conq <= ARMCondAL);
8378 }
8379
8380 /* ----------- smulbb, smulbt, smultb, smultt ----------- */
8381 {
8382 UInt regD = 99, regM = 99, regN = 99, bitM = 0, bitN = 0;
8383 Bool gate = False;
8384
8385 if (isT) {
8386 if (INSNT0(15,4) == 0xFB1 && INSNT1(15,12) == BITS4(1,1,1,1)
8387 && INSNT1(7,6) == BITS2(0,0)) {
8388 regD = INSNT1(11,8);
8389 regM = INSNT1(3,0);
8390 regN = INSNT0(3,0);
8391 bitM = INSNT1(4,4);
8392 bitN = INSNT1(5,5);
8393 if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
8394 gate = True;
8395 }
8396 } else {
8397 if (BITS8(0,0,0,1,0,1,1,0) == INSNA(27,20) &&
8398 BITS4(0,0,0,0) == INSNA(15,12) &&
8399 BITS4(1,0,0,0) == (INSNA(7,4) & BITS4(1,0,0,1)) ) {
8400 regD = INSNA(19,16);
8401 regM = INSNA(11,8);
8402 regN = INSNA(3,0);
8403 bitM = INSNA(6,6);
8404 bitN = INSNA(5,5);
8405 if (regD != 15 && regN != 15 && regM != 15)
8406 gate = True;
8407 }
8408 }
8409
8410 if (gate) {
8411 IRTemp srcN = newTemp(Ity_I32);
8412 IRTemp srcM = newTemp(Ity_I32);
8413 IRTemp res = newTemp(Ity_I32);
8414
8415 assign( srcN, binop(Iop_Sar32,
8416 binop(Iop_Shl32,
8417 isT ? getIRegT(regN) : getIRegA(regN),
8418 mkU8(bitN ? 0 : 16)), mkU8(16)) );
8419 assign( srcM, binop(Iop_Sar32,
8420 binop(Iop_Shl32,
8421 isT ? getIRegT(regM) : getIRegA(regM),
8422 mkU8(bitM ? 0 : 16)), mkU8(16)) );
8423 assign( res, binop(Iop_Mul32, mkexpr(srcN), mkexpr(srcM)) );
8424
8425 if (isT)
8426 putIRegT( regD, mkexpr(res), condT );
8427 else
8428 putIRegA( regD, mkexpr(res), condT, Ijk_Boring );
8429
8430 DIP( "smul%c%c%s r%u, r%u, r%u\n", bitN ? 't' : 'b', bitM ? 't' : 'b',
8431 nCC(conq), regD, regN, regM );
8432 return True;
8433 }
8434 /* fall through */
8435 }
8436
8437 /* ------------ smulwb<y><c> <Rd>,<Rn>,<Rm> ------------- */
8438 /* ------------ smulwt<y><c> <Rd>,<Rn>,<Rm> ------------- */
8439 {
8440 UInt regD = 99, regN = 99, regM = 99, bitM = 0;
8441 Bool gate = False;
8442
8443 if (isT) {
8444 if (INSNT0(15,4) == 0xFB3 && INSNT1(15,12) == BITS4(1,1,1,1)
8445 && INSNT1(7,5) == BITS3(0,0,0)) {
8446 regN = INSNT0(3,0);
8447 regD = INSNT1(11,8);
8448 regM = INSNT1(3,0);
8449 bitM = INSNT1(4,4);
8450 if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
8451 gate = True;
8452 }
8453 } else {
8454 if (INSNA(27,20) == BITS8(0,0,0,1,0,0,1,0) &&
8455 INSNA(15,12) == BITS4(0,0,0,0) &&
8456 (INSNA(7,4) & BITS4(1,0,1,1)) == BITS4(1,0,1,0)) {
8457 regD = INSNA(19,16);
8458 regN = INSNA(3,0);
8459 regM = INSNA(11,8);
8460 bitM = INSNA(6,6);
8461 if (regD != 15 && regN != 15 && regM != 15)
8462 gate = True;
8463 }
8464 }
8465
8466 if (gate) {
8467 IRTemp irt_prod = newTemp(Ity_I64);
8468
8469 assign( irt_prod,
8470 binop(Iop_MullS32,
8471 isT ? getIRegT(regN) : getIRegA(regN),
8472 binop(Iop_Sar32,
8473 binop(Iop_Shl32,
8474 isT ? getIRegT(regM) : getIRegA(regM),
8475 mkU8(bitM ? 0 : 16)),
8476 mkU8(16))) );
8477
8478 IRExpr* ire_result = binop(Iop_Or32,
8479 binop( Iop_Shl32,
8480 unop(Iop_64HIto32, mkexpr(irt_prod)),
8481 mkU8(16) ),
8482 binop( Iop_Shr32,
8483 unop(Iop_64to32, mkexpr(irt_prod)),
8484 mkU8(16) ) );
8485
8486 if (isT)
8487 putIRegT( regD, ire_result, condT );
8488 else
8489 putIRegA( regD, ire_result, condT, Ijk_Boring );
8490
8491 DIP("smulw%c%s r%u, r%u, r%u\n",
8492 bitM ? 't' : 'b', nCC(conq),regD,regN,regM);
8493 return True;
8494 }
8495 /* fall through */
8496 }
8497
8498 /* ------------ pkhbt<c> Rd, Rn, Rm {,LSL #imm} ------------- */
8499 /* ------------ pkhtb<c> Rd, Rn, Rm {,ASR #imm} ------------- */
8500 {
8501 UInt regD = 99, regN = 99, regM = 99, imm5 = 99, shift_type = 99;
8502 Bool tbform = False;
8503 Bool gate = False;
8504
8505 if (isT) {
8506 if (INSNT0(15,4) == 0xEAC
8507 && INSNT1(15,15) == 0 && INSNT1(4,4) == 0) {
8508 regN = INSNT0(3,0);
8509 regD = INSNT1(11,8);
8510 regM = INSNT1(3,0);
8511 imm5 = (INSNT1(14,12) << 2) | INSNT1(7,6);
8512 shift_type = (INSNT1(5,5) << 1) | 0;
8513 tbform = (INSNT1(5,5) == 0) ? False : True;
8514 if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
8515 gate = True;
8516 }
8517 } else {
8518 if (INSNA(27,20) == BITS8(0,1,1,0,1,0,0,0) &&
8519 INSNA(5,4) == BITS2(0,1) &&
8520 (INSNA(6,6) == 0 || INSNA(6,6) == 1) ) {
8521 regD = INSNA(15,12);
8522 regN = INSNA(19,16);
8523 regM = INSNA(3,0);
8524 imm5 = INSNA(11,7);
8525 shift_type = (INSNA(6,6) << 1) | 0;
8526 tbform = (INSNA(6,6) == 0) ? False : True;
8527 if (regD != 15 && regN != 15 && regM != 15)
8528 gate = True;
8529 }
8530 }
8531
8532 if (gate) {
8533 IRTemp irt_regM = newTemp(Ity_I32);
8534 IRTemp irt_regM_shift = newTemp(Ity_I32);
8535 assign( irt_regM, isT ? getIRegT(regM) : getIRegA(regM) );
8536 compute_result_and_C_after_shift_by_imm5(
8537 dis_buf, &irt_regM_shift, NULL, irt_regM, shift_type, imm5, regM );
8538
8539 UInt mask = (tbform == True) ? 0x0000FFFF : 0xFFFF0000;
8540 IRExpr* ire_result
8541 = binop( Iop_Or32,
8542 binop(Iop_And32, mkexpr(irt_regM_shift), mkU32(mask)),
8543 binop(Iop_And32, isT ? getIRegT(regN) : getIRegA(regN),
8544 unop(Iop_Not32, mkU32(mask))) );
8545
8546 if (isT)
8547 putIRegT( regD, ire_result, condT );
8548 else
8549 putIRegA( regD, ire_result, condT, Ijk_Boring );
8550
8551 DIP( "pkh%s%s r%u, r%u, r%u %s\n", tbform ? "tb" : "bt",
8552 nCC(conq), regD, regN, regM, dis_buf );
8553
8554 return True;
8555 }
8556 /* fall through */
8557 }
8558
8559 /* ---------- usat<c> <Rd>,#<imm5>,<Rn>{,<shift>} ----------- */
8560 {
8561 UInt regD = 99, regN = 99, shift_type = 99, imm5 = 99, sat_imm = 99;
8562 Bool gate = False;
8563
8564 if (isT) {
8565 if (INSNT0(15,6) == BITS10(1,1,1,1,0,0,1,1,1,0)
8566 && INSNT0(4,4) == 0
8567 && INSNT1(15,15) == 0 && INSNT1(5,5) == 0) {
8568 regD = INSNT1(11,8);
8569 regN = INSNT0(3,0);
8570 shift_type = (INSNT0(5,5) << 1) | 0;
8571 imm5 = (INSNT1(14,12) << 2) | INSNT1(7,6);
8572 sat_imm = INSNT1(4,0);
8573 if (!isBadRegT(regD) && !isBadRegT(regN))
8574 gate = True;
8575 if (shift_type == BITS2(1,0) && imm5 == 0)
8576 gate = False;
8577 }
8578 } else {
8579 if (INSNA(27,21) == BITS7(0,1,1,0,1,1,1) &&
8580 INSNA(5,4) == BITS2(0,1)) {
8581 regD = INSNA(15,12);
8582 regN = INSNA(3,0);
8583 shift_type = (INSNA(6,6) << 1) | 0;
8584 imm5 = INSNA(11,7);
8585 sat_imm = INSNA(20,16);
8586 if (regD != 15 && regN != 15)
8587 gate = True;
8588 }
8589 }
8590
8591 if (gate) {
8592 IRTemp irt_regN = newTemp(Ity_I32);
8593 IRTemp irt_regN_shift = newTemp(Ity_I32);
8594 IRTemp irt_sat_Q = newTemp(Ity_I32);
8595 IRTemp irt_result = newTemp(Ity_I32);
8596
8597 assign( irt_regN, isT ? getIRegT(regN) : getIRegA(regN) );
8598 compute_result_and_C_after_shift_by_imm5(
8599 dis_buf, &irt_regN_shift, NULL,
8600 irt_regN, shift_type, imm5, regN );
8601
8602 armUnsignedSatQ( &irt_result, &irt_sat_Q, irt_regN_shift, sat_imm );
8603 or_into_QFLAG32( mkexpr(irt_sat_Q), condT );
8604
8605 if (isT)
8606 putIRegT( regD, mkexpr(irt_result), condT );
8607 else
8608 putIRegA( regD, mkexpr(irt_result), condT, Ijk_Boring );
8609
8610 DIP("usat%s r%u, #0x%04x, %s\n",
8611 nCC(conq), regD, imm5, dis_buf);
8612 return True;
8613 }
8614 /* fall through */
8615 }
8616
8617 /* ----------- ssat<c> <Rd>,#<imm5>,<Rn>{,<shift>} ----------- */
8618 {
8619 UInt regD = 99, regN = 99, shift_type = 99, imm5 = 99, sat_imm = 99;
8620 Bool gate = False;
8621
8622 if (isT) {
8623 if (INSNT0(15,6) == BITS10(1,1,1,1,0,0,1,1,0,0)
8624 && INSNT0(4,4) == 0
8625 && INSNT1(15,15) == 0 && INSNT1(5,5) == 0) {
8626 regD = INSNT1(11,8);
8627 regN = INSNT0(3,0);
8628 shift_type = (INSNT0(5,5) << 1) | 0;
8629 imm5 = (INSNT1(14,12) << 2) | INSNT1(7,6);
8630 sat_imm = INSNT1(4,0) + 1;
8631 if (!isBadRegT(regD) && !isBadRegT(regN))
8632 gate = True;
8633 if (shift_type == BITS2(1,0) && imm5 == 0)
8634 gate = False;
8635 }
8636 } else {
8637 if (INSNA(27,21) == BITS7(0,1,1,0,1,0,1) &&
8638 INSNA(5,4) == BITS2(0,1)) {
8639 regD = INSNA(15,12);
8640 regN = INSNA(3,0);
8641 shift_type = (INSNA(6,6) << 1) | 0;
8642 imm5 = INSNA(11,7);
8643 sat_imm = INSNA(20,16) + 1;
8644 if (regD != 15 && regN != 15)
8645 gate = True;
8646 }
8647 }
8648
8649 if (gate) {
8650 IRTemp irt_regN = newTemp(Ity_I32);
8651 IRTemp irt_regN_shift = newTemp(Ity_I32);
8652 IRTemp irt_sat_Q = newTemp(Ity_I32);
8653 IRTemp irt_result = newTemp(Ity_I32);
8654
8655 assign( irt_regN, isT ? getIRegT(regN) : getIRegA(regN) );
8656 compute_result_and_C_after_shift_by_imm5(
8657 dis_buf, &irt_regN_shift, NULL,
8658 irt_regN, shift_type, imm5, regN );
8659
8660 armSignedSatQ( irt_regN_shift, sat_imm, &irt_result, &irt_sat_Q );
8661 or_into_QFLAG32( mkexpr(irt_sat_Q), condT );
8662
8663 if (isT)
8664 putIRegT( regD, mkexpr(irt_result), condT );
8665 else
8666 putIRegA( regD, mkexpr(irt_result), condT, Ijk_Boring );
8667
8668 DIP( "ssat%s r%u, #0x%04x, %s\n",
8669 nCC(conq), regD, imm5, dis_buf);
8670 return True;
8671 }
8672 /* fall through */
8673 }
8674
8675 /* -------------- usat16<c> <Rd>,#<imm4>,<Rn> --------------- */
8676 {
8677 UInt regD = 99, regN = 99, sat_imm = 99;
8678 Bool gate = False;
8679
8680 if (isT) {
8681 if (INSNT0(15,4) == 0xF3A && (INSNT1(15,0) & 0xF0F0) == 0x0000) {
8682 regN = INSNT0(3,0);
8683 regD = INSNT1(11,8);
8684 sat_imm = INSNT1(3,0);
8685 if (!isBadRegT(regD) && !isBadRegT(regN))
8686 gate = True;
8687 }
8688 } else {
8689 if (INSNA(27,20) == BITS8(0,1,1,0,1,1,1,0) &&
8690 INSNA(11,8) == BITS4(1,1,1,1) &&
8691 INSNA(7,4) == BITS4(0,0,1,1)) {
8692 regD = INSNA(15,12);
8693 regN = INSNA(3,0);
8694 sat_imm = INSNA(19,16);
8695 if (regD != 15 && regN != 15)
8696 gate = True;
8697 }
8698 }
8699
8700 if (gate) {
8701 IRTemp irt_regN = newTemp(Ity_I32);
8702 IRTemp irt_regN_lo = newTemp(Ity_I32);
8703 IRTemp irt_regN_hi = newTemp(Ity_I32);
8704 IRTemp irt_Q_lo = newTemp(Ity_I32);
8705 IRTemp irt_Q_hi = newTemp(Ity_I32);
8706 IRTemp irt_res_lo = newTemp(Ity_I32);
8707 IRTemp irt_res_hi = newTemp(Ity_I32);
8708
8709 assign( irt_regN, isT ? getIRegT(regN) : getIRegA(regN) );
8710 assign( irt_regN_lo, binop( Iop_Sar32,
8711 binop(Iop_Shl32, mkexpr(irt_regN), mkU8(16)),
8712 mkU8(16)) );
8713 assign( irt_regN_hi, binop(Iop_Sar32, mkexpr(irt_regN), mkU8(16)) );
8714
8715 armUnsignedSatQ( &irt_res_lo, &irt_Q_lo, irt_regN_lo, sat_imm );
8716 or_into_QFLAG32( mkexpr(irt_Q_lo), condT );
8717
8718 armUnsignedSatQ( &irt_res_hi, &irt_Q_hi, irt_regN_hi, sat_imm );
8719 or_into_QFLAG32( mkexpr(irt_Q_hi), condT );
8720
8721 IRExpr* ire_result = binop( Iop_Or32,
8722 binop(Iop_Shl32, mkexpr(irt_res_hi), mkU8(16)),
8723 mkexpr(irt_res_lo) );
8724
8725 if (isT)
8726 putIRegT( regD, ire_result, condT );
8727 else
8728 putIRegA( regD, ire_result, condT, Ijk_Boring );
8729
8730 DIP( "usat16%s r%u, #0x%04x, r%u\n", nCC(conq), regD, sat_imm, regN );
8731 return True;
8732 }
8733 /* fall through */
8734 }
8735
8736 /* -------------- uadd16<c> <Rd>,<Rn>,<Rm> -------------- */
8737 {
8738 UInt regD = 99, regN = 99, regM = 99;
8739 Bool gate = False;
8740
8741 if (isT) {
8742 if (INSNT0(15,4) == 0xFA9 && (INSNT1(15,0) & 0xF0F0) == 0xF040) {
8743 regN = INSNT0(3,0);
8744 regD = INSNT1(11,8);
8745 regM = INSNT1(3,0);
8746 if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
8747 gate = True;
8748 }
8749 } else {
8750 if (INSNA(27,20) == BITS8(0,1,1,0,0,1,0,1) &&
8751 INSNA(11,8) == BITS4(1,1,1,1) &&
8752 INSNA(7,4) == BITS4(0,0,0,1)) {
8753 regD = INSNA(15,12);
8754 regN = INSNA(19,16);
8755 regM = INSNA(3,0);
8756 if (regD != 15 && regN != 15 && regM != 15)
8757 gate = True;
8758 }
8759 }
8760
8761 if (gate) {
sewardje2ea1762010-09-22 00:56:37 +00008762 IRTemp rNt = newTemp(Ity_I32);
8763 IRTemp rMt = newTemp(Ity_I32);
8764 IRTemp res = newTemp(Ity_I32);
8765 IRTemp reso = newTemp(Ity_I32);
sewardj1f139f52010-08-29 12:33:02 +00008766
sewardje2ea1762010-09-22 00:56:37 +00008767 assign( rNt, isT ? getIRegT(regN) : getIRegA(regN) );
8768 assign( rMt, isT ? getIRegT(regM) : getIRegA(regM) );
sewardj1f139f52010-08-29 12:33:02 +00008769
sewardje2ea1762010-09-22 00:56:37 +00008770 assign(res, binop(Iop_Add16x2, mkexpr(rNt), mkexpr(rMt)));
sewardj1f139f52010-08-29 12:33:02 +00008771 if (isT)
sewardje2ea1762010-09-22 00:56:37 +00008772 putIRegT( regD, mkexpr(res), condT );
sewardj1f139f52010-08-29 12:33:02 +00008773 else
sewardje2ea1762010-09-22 00:56:37 +00008774 putIRegA( regD, mkexpr(res), condT, Ijk_Boring );
8775
8776 assign(reso, binop(Iop_HAdd16Ux2, mkexpr(rNt), mkexpr(rMt)));
8777 set_GE_32_10_from_bits_31_15(reso, condT);
sewardj1f139f52010-08-29 12:33:02 +00008778
8779 DIP("uadd16%s r%u, r%u, r%u\n", nCC(conq),regD,regN,regM);
8780 return True;
8781 }
8782 /* fall through */
8783 }
8784
sewardj22ac5962010-09-20 22:35:35 +00008785 /* -------------- sadd16<c> <Rd>,<Rn>,<Rm> -------------- */
8786 {
8787 UInt regD = 99, regN = 99, regM = 99;
8788 Bool gate = False;
8789
8790 if (isT) {
8791 if (INSNT0(15,4) == 0xFA9 && (INSNT1(15,0) & 0xF0F0) == 0xF000) {
8792 regN = INSNT0(3,0);
8793 regD = INSNT1(11,8);
8794 regM = INSNT1(3,0);
8795 if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
8796 gate = True;
8797 }
8798 } else {
8799 if (INSNA(27,20) == BITS8(0,1,1,0,0,0,0,1) &&
8800 INSNA(11,8) == BITS4(1,1,1,1) &&
8801 INSNA(7,4) == BITS4(0,0,0,1)) {
8802 regD = INSNA(15,12);
8803 regN = INSNA(19,16);
8804 regM = INSNA(3,0);
8805 if (regD != 15 && regN != 15 && regM != 15)
8806 gate = True;
8807 }
8808 }
8809
8810 if (gate) {
sewardje2ea1762010-09-22 00:56:37 +00008811 IRTemp rNt = newTemp(Ity_I32);
8812 IRTemp rMt = newTemp(Ity_I32);
8813 IRTemp res = newTemp(Ity_I32);
8814 IRTemp reso = newTemp(Ity_I32);
sewardj22ac5962010-09-20 22:35:35 +00008815
sewardje2ea1762010-09-22 00:56:37 +00008816 assign( rNt, isT ? getIRegT(regN) : getIRegA(regN) );
8817 assign( rMt, isT ? getIRegT(regM) : getIRegA(regM) );
sewardj22ac5962010-09-20 22:35:35 +00008818
sewardje2ea1762010-09-22 00:56:37 +00008819 assign(res, binop(Iop_Add16x2, mkexpr(rNt), mkexpr(rMt)));
sewardj22ac5962010-09-20 22:35:35 +00008820 if (isT)
sewardje2ea1762010-09-22 00:56:37 +00008821 putIRegT( regD, mkexpr(res), condT );
sewardj22ac5962010-09-20 22:35:35 +00008822 else
sewardje2ea1762010-09-22 00:56:37 +00008823 putIRegA( regD, mkexpr(res), condT, Ijk_Boring );
8824
8825 assign(reso, unop(Iop_Not32,
8826 binop(Iop_HAdd16Sx2, mkexpr(rNt), mkexpr(rMt))));
8827 set_GE_32_10_from_bits_31_15(reso, condT);
sewardj22ac5962010-09-20 22:35:35 +00008828
8829 DIP("sadd16%s r%u, r%u, r%u\n", nCC(conq),regD,regN,regM);
8830 return True;
8831 }
8832 /* fall through */
8833 }
8834
sewardj1f139f52010-08-29 12:33:02 +00008835 /* ---------------- usub16<c> <Rd>,<Rn>,<Rm> ---------------- */
8836 {
8837 UInt regD = 99, regN = 99, regM = 99;
8838 Bool gate = False;
8839
8840 if (isT) {
8841 if (INSNT0(15,4) == 0xFAD && (INSNT1(15,0) & 0xF0F0) == 0xF040) {
8842 regN = INSNT0(3,0);
8843 regD = INSNT1(11,8);
8844 regM = INSNT1(3,0);
8845 if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
8846 gate = True;
8847 }
8848 } else {
8849 if (INSNA(27,20) == BITS8(0,1,1,0,0,1,0,1) &&
8850 INSNA(11,8) == BITS4(1,1,1,1) &&
8851 INSNA(7,4) == BITS4(0,1,1,1)) {
8852 regD = INSNA(15,12);
8853 regN = INSNA(19,16);
8854 regM = INSNA(3,0);
8855 if (regD != 15 && regN != 15 && regM != 15)
8856 gate = True;
8857 }
8858 }
8859
8860 if (gate) {
sewardje2ea1762010-09-22 00:56:37 +00008861 IRTemp rNt = newTemp(Ity_I32);
8862 IRTemp rMt = newTemp(Ity_I32);
8863 IRTemp res = newTemp(Ity_I32);
8864 IRTemp reso = newTemp(Ity_I32);
sewardj1f139f52010-08-29 12:33:02 +00008865
sewardje2ea1762010-09-22 00:56:37 +00008866 assign( rNt, isT ? getIRegT(regN) : getIRegA(regN) );
8867 assign( rMt, isT ? getIRegT(regM) : getIRegA(regM) );
sewardj1f139f52010-08-29 12:33:02 +00008868
sewardje2ea1762010-09-22 00:56:37 +00008869 assign(res, binop(Iop_Sub16x2, mkexpr(rNt), mkexpr(rMt)));
sewardj1f139f52010-08-29 12:33:02 +00008870 if (isT)
sewardje2ea1762010-09-22 00:56:37 +00008871 putIRegT( regD, mkexpr(res), condT );
sewardj1f139f52010-08-29 12:33:02 +00008872 else
sewardje2ea1762010-09-22 00:56:37 +00008873 putIRegA( regD, mkexpr(res), condT, Ijk_Boring );
sewardj1f139f52010-08-29 12:33:02 +00008874
sewardje2ea1762010-09-22 00:56:37 +00008875 assign(reso, unop(Iop_Not32,
8876 binop(Iop_HSub16Ux2, mkexpr(rNt), mkexpr(rMt))));
8877 set_GE_32_10_from_bits_31_15(reso, condT);
8878
8879 DIP("usub16%s r%u, r%u, r%u\n", nCC(conq),regD,regN,regM);
sewardj1f139f52010-08-29 12:33:02 +00008880 return True;
8881 }
8882 /* fall through */
8883 }
8884
sewardj22ac5962010-09-20 22:35:35 +00008885 /* -------------- ssub16<c> <Rd>,<Rn>,<Rm> -------------- */
8886 {
8887 UInt regD = 99, regN = 99, regM = 99;
8888 Bool gate = False;
8889
8890 if (isT) {
8891 if (INSNT0(15,4) == 0xFAD && (INSNT1(15,0) & 0xF0F0) == 0xF000) {
8892 regN = INSNT0(3,0);
8893 regD = INSNT1(11,8);
8894 regM = INSNT1(3,0);
8895 if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
8896 gate = True;
8897 }
8898 } else {
8899 if (INSNA(27,20) == BITS8(0,1,1,0,0,0,0,1) &&
8900 INSNA(11,8) == BITS4(1,1,1,1) &&
8901 INSNA(7,4) == BITS4(0,1,1,1)) {
8902 regD = INSNA(15,12);
8903 regN = INSNA(19,16);
8904 regM = INSNA(3,0);
8905 if (regD != 15 && regN != 15 && regM != 15)
8906 gate = True;
8907 }
8908 }
8909
8910 if (gate) {
sewardje2ea1762010-09-22 00:56:37 +00008911 IRTemp rNt = newTemp(Ity_I32);
8912 IRTemp rMt = newTemp(Ity_I32);
8913 IRTemp res = newTemp(Ity_I32);
8914 IRTemp reso = newTemp(Ity_I32);
sewardj22ac5962010-09-20 22:35:35 +00008915
sewardje2ea1762010-09-22 00:56:37 +00008916 assign( rNt, isT ? getIRegT(regN) : getIRegA(regN) );
8917 assign( rMt, isT ? getIRegT(regM) : getIRegA(regM) );
sewardj22ac5962010-09-20 22:35:35 +00008918
sewardje2ea1762010-09-22 00:56:37 +00008919 assign(res, binop(Iop_Sub16x2, mkexpr(rNt), mkexpr(rMt)));
sewardj22ac5962010-09-20 22:35:35 +00008920 if (isT)
sewardje2ea1762010-09-22 00:56:37 +00008921 putIRegT( regD, mkexpr(res), condT );
sewardj22ac5962010-09-20 22:35:35 +00008922 else
sewardje2ea1762010-09-22 00:56:37 +00008923 putIRegA( regD, mkexpr(res), condT, Ijk_Boring );
8924
8925 assign(reso, unop(Iop_Not32,
8926 binop(Iop_HSub16Sx2, mkexpr(rNt), mkexpr(rMt))));
8927 set_GE_32_10_from_bits_31_15(reso, condT);
sewardj22ac5962010-09-20 22:35:35 +00008928
8929 DIP("ssub16%s r%u, r%u, r%u\n", nCC(conq),regD,regN,regM);
8930 return True;
8931 }
8932 /* fall through */
8933 }
8934
sewardj1f139f52010-08-29 12:33:02 +00008935 /* ----------------- uadd8<c> <Rd>,<Rn>,<Rm> ---------------- */
8936 {
8937 UInt regD = 99, regN = 99, regM = 99;
8938 Bool gate = False;
8939
8940 if (isT) {
8941 if (INSNT0(15,4) == 0xFA8 && (INSNT1(15,0) & 0xF0F0) == 0xF040) {
8942 regN = INSNT0(3,0);
8943 regD = INSNT1(11,8);
8944 regM = INSNT1(3,0);
8945 if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
8946 gate = True;
8947 }
8948 } else {
8949 if (INSNA(27,20) == BITS8(0,1,1,0,0,1,0,1) &&
8950 INSNA(11,8) == BITS4(1,1,1,1) &&
8951 (INSNA(7,4) == BITS4(1,0,0,1))) {
8952 regD = INSNA(15,12);
8953 regN = INSNA(19,16);
8954 regM = INSNA(3,0);
8955 if (regD != 15 && regN != 15 && regM != 15)
8956 gate = True;
8957 }
8958 }
8959
8960 if (gate) {
sewardje2ea1762010-09-22 00:56:37 +00008961 IRTemp rNt = newTemp(Ity_I32);
8962 IRTemp rMt = newTemp(Ity_I32);
8963 IRTemp res = newTemp(Ity_I32);
8964 IRTemp reso = newTemp(Ity_I32);
sewardj1f139f52010-08-29 12:33:02 +00008965
sewardje2ea1762010-09-22 00:56:37 +00008966 assign( rNt, isT ? getIRegT(regN) : getIRegA(regN) );
8967 assign( rMt, isT ? getIRegT(regM) : getIRegA(regM) );
sewardj1f139f52010-08-29 12:33:02 +00008968
sewardje2ea1762010-09-22 00:56:37 +00008969 assign(res, binop(Iop_Add8x4, mkexpr(rNt), mkexpr(rMt)));
sewardj1f139f52010-08-29 12:33:02 +00008970 if (isT)
sewardje2ea1762010-09-22 00:56:37 +00008971 putIRegT( regD, mkexpr(res), condT );
sewardj1f139f52010-08-29 12:33:02 +00008972 else
sewardje2ea1762010-09-22 00:56:37 +00008973 putIRegA( regD, mkexpr(res), condT, Ijk_Boring );
sewardj1f139f52010-08-29 12:33:02 +00008974
sewardje2ea1762010-09-22 00:56:37 +00008975 assign(reso, binop(Iop_HAdd8Ux4, mkexpr(rNt), mkexpr(rMt)));
8976 set_GE_3_2_1_0_from_bits_31_23_15_7(reso, condT);
8977
8978 DIP("uadd8%s r%u, r%u, r%u\n", nCC(conq),regD,regN,regM);
8979 return True;
8980 }
8981 /* fall through */
8982 }
8983
8984 /* ------------------- sadd8<c> <Rd>,<Rn>,<Rm> ------------------ */
8985 {
8986 UInt regD = 99, regN = 99, regM = 99;
8987 Bool gate = False;
8988
8989 if (isT) {
8990 if (INSNT0(15,4) == 0xFA8 && (INSNT1(15,0) & 0xF0F0) == 0xF000) {
8991 regN = INSNT0(3,0);
8992 regD = INSNT1(11,8);
8993 regM = INSNT1(3,0);
8994 if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
8995 gate = True;
8996 }
8997 } else {
8998 if (INSNA(27,20) == BITS8(0,1,1,0,0,0,0,1) &&
8999 INSNA(11,8) == BITS4(1,1,1,1) &&
9000 (INSNA(7,4) == BITS4(1,0,0,1))) {
9001 regD = INSNA(15,12);
9002 regN = INSNA(19,16);
9003 regM = INSNA(3,0);
9004 if (regD != 15 && regN != 15 && regM != 15)
9005 gate = True;
9006 }
9007 }
9008
9009 if (gate) {
9010 IRTemp rNt = newTemp(Ity_I32);
9011 IRTemp rMt = newTemp(Ity_I32);
9012 IRTemp res = newTemp(Ity_I32);
9013 IRTemp reso = newTemp(Ity_I32);
9014
9015 assign( rNt, isT ? getIRegT(regN) : getIRegA(regN) );
9016 assign( rMt, isT ? getIRegT(regM) : getIRegA(regM) );
9017
9018 assign(res, binop(Iop_Add8x4, mkexpr(rNt), mkexpr(rMt)));
9019 if (isT)
9020 putIRegT( regD, mkexpr(res), condT );
9021 else
9022 putIRegA( regD, mkexpr(res), condT, Ijk_Boring );
9023
9024 assign(reso, unop(Iop_Not32,
9025 binop(Iop_HAdd8Sx4, mkexpr(rNt), mkexpr(rMt))));
9026 set_GE_3_2_1_0_from_bits_31_23_15_7(reso, condT);
9027
9028 DIP("sadd8%s r%u, r%u, r%u\n", nCC(conq),regD,regN,regM);
sewardj1f139f52010-08-29 12:33:02 +00009029 return True;
9030 }
9031 /* fall through */
9032 }
9033
9034 /* ------------------- usub8<c> <Rd>,<Rn>,<Rm> ------------------ */
9035 {
9036 UInt regD = 99, regN = 99, regM = 99;
9037 Bool gate = False;
9038
9039 if (isT) {
9040 if (INSNT0(15,4) == 0xFAC && (INSNT1(15,0) & 0xF0F0) == 0xF040) {
9041 regN = INSNT0(3,0);
9042 regD = INSNT1(11,8);
9043 regM = INSNT1(3,0);
9044 if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
9045 gate = True;
9046 }
9047 } else {
9048 if (INSNA(27,20) == BITS8(0,1,1,0,0,1,0,1) &&
9049 INSNA(11,8) == BITS4(1,1,1,1) &&
9050 (INSNA(7,4) == BITS4(1,1,1,1))) {
9051 regD = INSNA(15,12);
9052 regN = INSNA(19,16);
9053 regM = INSNA(3,0);
9054 if (regD != 15 && regN != 15 && regM != 15)
9055 gate = True;
9056 }
9057 }
9058
9059 if (gate) {
sewardje2ea1762010-09-22 00:56:37 +00009060 IRTemp rNt = newTemp(Ity_I32);
9061 IRTemp rMt = newTemp(Ity_I32);
9062 IRTemp res = newTemp(Ity_I32);
9063 IRTemp reso = newTemp(Ity_I32);
sewardj1f139f52010-08-29 12:33:02 +00009064
sewardje2ea1762010-09-22 00:56:37 +00009065 assign( rNt, isT ? getIRegT(regN) : getIRegA(regN) );
9066 assign( rMt, isT ? getIRegT(regM) : getIRegA(regM) );
sewardj1f139f52010-08-29 12:33:02 +00009067
sewardje2ea1762010-09-22 00:56:37 +00009068 assign(res, binop(Iop_Sub8x4, mkexpr(rNt), mkexpr(rMt)));
sewardj1f139f52010-08-29 12:33:02 +00009069 if (isT)
sewardje2ea1762010-09-22 00:56:37 +00009070 putIRegT( regD, mkexpr(res), condT );
sewardj1f139f52010-08-29 12:33:02 +00009071 else
sewardje2ea1762010-09-22 00:56:37 +00009072 putIRegA( regD, mkexpr(res), condT, Ijk_Boring );
sewardj1f139f52010-08-29 12:33:02 +00009073
sewardje2ea1762010-09-22 00:56:37 +00009074 assign(reso, unop(Iop_Not32,
9075 binop(Iop_HSub8Ux4, mkexpr(rNt), mkexpr(rMt))));
9076 set_GE_3_2_1_0_from_bits_31_23_15_7(reso, condT);
9077
9078 DIP("usub8%s r%u, r%u, r%u\n", nCC(conq),regD,regN,regM);
9079 return True;
9080 }
9081 /* fall through */
9082 }
9083
9084 /* ------------------- ssub8<c> <Rd>,<Rn>,<Rm> ------------------ */
9085 {
9086 UInt regD = 99, regN = 99, regM = 99;
9087 Bool gate = False;
9088
9089 if (isT) {
9090 if (INSNT0(15,4) == 0xFAC && (INSNT1(15,0) & 0xF0F0) == 0xF000) {
9091 regN = INSNT0(3,0);
9092 regD = INSNT1(11,8);
9093 regM = INSNT1(3,0);
9094 if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
9095 gate = True;
9096 }
9097 } else {
9098 if (INSNA(27,20) == BITS8(0,1,1,0,0,0,0,1) &&
9099 INSNA(11,8) == BITS4(1,1,1,1) &&
9100 INSNA(7,4) == BITS4(1,1,1,1)) {
9101 regD = INSNA(15,12);
9102 regN = INSNA(19,16);
9103 regM = INSNA(3,0);
9104 if (regD != 15 && regN != 15 && regM != 15)
9105 gate = True;
9106 }
9107 }
9108
9109 if (gate) {
9110 IRTemp rNt = newTemp(Ity_I32);
9111 IRTemp rMt = newTemp(Ity_I32);
9112 IRTemp res = newTemp(Ity_I32);
9113 IRTemp reso = newTemp(Ity_I32);
9114
9115 assign( rNt, isT ? getIRegT(regN) : getIRegA(regN) );
9116 assign( rMt, isT ? getIRegT(regM) : getIRegA(regM) );
9117
9118 assign(res, binop(Iop_Sub8x4, mkexpr(rNt), mkexpr(rMt)));
9119 if (isT)
9120 putIRegT( regD, mkexpr(res), condT );
9121 else
9122 putIRegA( regD, mkexpr(res), condT, Ijk_Boring );
9123
9124 assign(reso, unop(Iop_Not32,
9125 binop(Iop_HSub8Sx4, mkexpr(rNt), mkexpr(rMt))));
9126 set_GE_3_2_1_0_from_bits_31_23_15_7(reso, condT);
9127
9128 DIP("ssub8%s r%u, r%u, r%u\n", nCC(conq),regD,regN,regM);
9129 return True;
9130 }
9131 /* fall through */
9132 }
9133
9134 /* ------------------ qadd8<c> <Rd>,<Rn>,<Rm> ------------------- */
9135 {
9136 UInt regD = 99, regN = 99, regM = 99;
9137 Bool gate = False;
9138
9139 if (isT) {
9140 if (INSNT0(15,4) == 0xFA8 && (INSNT1(15,0) & 0xF0F0) == 0xF010) {
9141 regN = INSNT0(3,0);
9142 regD = INSNT1(11,8);
9143 regM = INSNT1(3,0);
9144 if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
9145 gate = True;
9146 }
9147 } else {
9148 if (INSNA(27,20) == BITS8(0,1,1,0,0,0,1,0) &&
9149 INSNA(11,8) == BITS4(1,1,1,1) &&
9150 INSNA(7,4) == BITS4(1,0,0,1)) {
9151 regD = INSNA(15,12);
9152 regN = INSNA(19,16);
9153 regM = INSNA(3,0);
9154 if (regD != 15 && regN != 15 && regM != 15)
9155 gate = True;
9156 }
9157 }
9158
9159 if (gate) {
9160 IRTemp rNt = newTemp(Ity_I32);
9161 IRTemp rMt = newTemp(Ity_I32);
9162 IRTemp res_q = newTemp(Ity_I32);
9163
9164 assign( rNt, isT ? getIRegT(regN) : getIRegA(regN) );
9165 assign( rMt, isT ? getIRegT(regM) : getIRegA(regM) );
9166
9167 assign(res_q, binop(Iop_QAdd8Sx4, mkexpr(rNt), mkexpr(rMt)));
9168 if (isT)
9169 putIRegT( regD, mkexpr(res_q), condT );
9170 else
9171 putIRegA( regD, mkexpr(res_q), condT, Ijk_Boring );
9172
9173 DIP("qadd8%s r%u, r%u, r%u\n", nCC(conq),regD,regN,regM);
9174 return True;
9175 }
9176 /* fall through */
9177 }
9178
9179 /* ------------------ qsub8<c> <Rd>,<Rn>,<Rm> ------------------- */
9180 {
9181 UInt regD = 99, regN = 99, regM = 99;
9182 Bool gate = False;
9183
9184 if (isT) {
9185 if (INSNT0(15,4) == 0xFAC && (INSNT1(15,0) & 0xF0F0) == 0xF010) {
9186 regN = INSNT0(3,0);
9187 regD = INSNT1(11,8);
9188 regM = INSNT1(3,0);
9189 if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
9190 gate = True;
9191 }
9192 } else {
9193 if (INSNA(27,20) == BITS8(0,1,1,0,0,0,1,0) &&
9194 INSNA(11,8) == BITS4(1,1,1,1) &&
9195 INSNA(7,4) == BITS4(1,1,1,1)) {
9196 regD = INSNA(15,12);
9197 regN = INSNA(19,16);
9198 regM = INSNA(3,0);
9199 if (regD != 15 && regN != 15 && regM != 15)
9200 gate = True;
9201 }
9202 }
9203
9204 if (gate) {
9205 IRTemp rNt = newTemp(Ity_I32);
9206 IRTemp rMt = newTemp(Ity_I32);
9207 IRTemp res_q = newTemp(Ity_I32);
9208
9209 assign( rNt, isT ? getIRegT(regN) : getIRegA(regN) );
9210 assign( rMt, isT ? getIRegT(regM) : getIRegA(regM) );
9211
9212 assign(res_q, binop(Iop_QSub8Sx4, mkexpr(rNt), mkexpr(rMt)));
9213 if (isT)
9214 putIRegT( regD, mkexpr(res_q), condT );
9215 else
9216 putIRegA( regD, mkexpr(res_q), condT, Ijk_Boring );
9217
9218 DIP("qsub8%s r%u, r%u, r%u\n", nCC(conq),regD,regN,regM);
9219 return True;
9220 }
9221 /* fall through */
9222 }
9223
9224 /* ------------------ uqadd8<c> <Rd>,<Rn>,<Rm> ------------------ */
9225 {
9226 UInt regD = 99, regN = 99, regM = 99;
9227 Bool gate = False;
9228
9229 if (isT) {
9230 if (INSNT0(15,4) == 0xFA8 && (INSNT1(15,0) & 0xF0F0) == 0xF050) {
9231 regN = INSNT0(3,0);
9232 regD = INSNT1(11,8);
9233 regM = INSNT1(3,0);
9234 if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
9235 gate = True;
9236 }
9237 } else {
9238 if (INSNA(27,20) == BITS8(0,1,1,0,0,1,1,0) &&
9239 INSNA(11,8) == BITS4(1,1,1,1) &&
9240 (INSNA(7,4) == BITS4(1,0,0,1))) {
9241 regD = INSNA(15,12);
9242 regN = INSNA(19,16);
9243 regM = INSNA(3,0);
9244 if (regD != 15 && regN != 15 && regM != 15)
9245 gate = True;
9246 }
9247 }
9248
9249 if (gate) {
9250 IRTemp rNt = newTemp(Ity_I32);
9251 IRTemp rMt = newTemp(Ity_I32);
9252 IRTemp res_q = newTemp(Ity_I32);
9253
9254 assign( rNt, isT ? getIRegT(regN) : getIRegA(regN) );
9255 assign( rMt, isT ? getIRegT(regM) : getIRegA(regM) );
9256
9257 assign(res_q, binop(Iop_QAdd8Ux4, mkexpr(rNt), mkexpr(rMt)));
9258 if (isT)
9259 putIRegT( regD, mkexpr(res_q), condT );
9260 else
9261 putIRegA( regD, mkexpr(res_q), condT, Ijk_Boring );
9262
9263 DIP("uqadd8%s r%u, r%u, r%u\n", nCC(conq),regD,regN,regM);
9264 return True;
9265 }
9266 /* fall through */
9267 }
9268
9269 /* ------------------ uqsub8<c> <Rd>,<Rn>,<Rm> ------------------ */
9270 {
9271 UInt regD = 99, regN = 99, regM = 99;
9272 Bool gate = False;
9273
9274 if (isT) {
9275 if (INSNT0(15,4) == 0xFAC && (INSNT1(15,0) & 0xF0F0) == 0xF050) {
9276 regN = INSNT0(3,0);
9277 regD = INSNT1(11,8);
9278 regM = INSNT1(3,0);
9279 if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
9280 gate = True;
9281 }
9282 } else {
9283 if (INSNA(27,20) == BITS8(0,1,1,0,0,1,1,0) &&
9284 INSNA(11,8) == BITS4(1,1,1,1) &&
9285 (INSNA(7,4) == BITS4(1,1,1,1))) {
9286 regD = INSNA(15,12);
9287 regN = INSNA(19,16);
9288 regM = INSNA(3,0);
9289 if (regD != 15 && regN != 15 && regM != 15)
9290 gate = True;
9291 }
9292 }
9293
9294 if (gate) {
9295 IRTemp rNt = newTemp(Ity_I32);
9296 IRTemp rMt = newTemp(Ity_I32);
9297 IRTemp res_q = newTemp(Ity_I32);
9298
9299 assign( rNt, isT ? getIRegT(regN) : getIRegA(regN) );
9300 assign( rMt, isT ? getIRegT(regM) : getIRegA(regM) );
9301
9302 assign(res_q, binop(Iop_QSub8Ux4, mkexpr(rNt), mkexpr(rMt)));
9303 if (isT)
9304 putIRegT( regD, mkexpr(res_q), condT );
9305 else
9306 putIRegA( regD, mkexpr(res_q), condT, Ijk_Boring );
9307
9308 DIP("uqsub8%s r%u, r%u, r%u\n", nCC(conq),regD,regN,regM);
9309 return True;
9310 }
9311 /* fall through */
9312 }
9313
9314 /* ----------------- uhadd8<c> <Rd>,<Rn>,<Rm> ------------------- */
9315 {
9316 UInt regD = 99, regN = 99, regM = 99;
9317 Bool gate = False;
9318
9319 if (isT) {
9320 if (INSNT0(15,4) == 0xFA8 && (INSNT1(15,0) & 0xF0F0) == 0xF060) {
9321 regN = INSNT0(3,0);
9322 regD = INSNT1(11,8);
9323 regM = INSNT1(3,0);
9324 if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
9325 gate = True;
9326 }
9327 } else {
9328 if (INSNA(27,20) == BITS8(0,1,1,0,0,1,1,1) &&
9329 INSNA(11,8) == BITS4(1,1,1,1) &&
9330 INSNA(7,4) == BITS4(1,0,0,1)) {
9331 regD = INSNA(15,12);
9332 regN = INSNA(19,16);
9333 regM = INSNA(3,0);
9334 if (regD != 15 && regN != 15 && regM != 15)
9335 gate = True;
9336 }
9337 }
9338
9339 if (gate) {
9340 IRTemp rNt = newTemp(Ity_I32);
9341 IRTemp rMt = newTemp(Ity_I32);
9342 IRTemp res_q = newTemp(Ity_I32);
9343
9344 assign( rNt, isT ? getIRegT(regN) : getIRegA(regN) );
9345 assign( rMt, isT ? getIRegT(regM) : getIRegA(regM) );
9346
9347 assign(res_q, binop(Iop_HAdd8Ux4, mkexpr(rNt), mkexpr(rMt)));
9348 if (isT)
9349 putIRegT( regD, mkexpr(res_q), condT );
9350 else
9351 putIRegA( regD, mkexpr(res_q), condT, Ijk_Boring );
9352
9353 DIP("uhadd8%s r%u, r%u, r%u\n", nCC(conq),regD,regN,regM);
9354 return True;
9355 }
9356 /* fall through */
9357 }
9358
sewardj9de28092012-06-22 09:27:54 +00009359 /* ----------------- uhadd16<c> <Rd>,<Rn>,<Rm> ------------------- */
9360 {
9361 UInt regD = 99, regN = 99, regM = 99;
9362 Bool gate = False;
9363
9364 if (isT) {
9365 if (INSNT0(15,4) == 0xFA9 && (INSNT1(15,0) & 0xF0F0) == 0xF060) {
9366 regN = INSNT0(3,0);
9367 regD = INSNT1(11,8);
9368 regM = INSNT1(3,0);
9369 if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
9370 gate = True;
9371 }
9372 } else {
9373 if (INSNA(27,20) == BITS8(0,1,1,0,0,1,1,1) &&
9374 INSNA(11,8) == BITS4(1,1,1,1) &&
9375 INSNA(7,4) == BITS4(0,0,0,1)) {
9376 regD = INSNA(15,12);
9377 regN = INSNA(19,16);
9378 regM = INSNA(3,0);
9379 if (regD != 15 && regN != 15 && regM != 15)
9380 gate = True;
9381 }
9382 }
9383
9384 if (gate) {
9385 IRTemp rNt = newTemp(Ity_I32);
9386 IRTemp rMt = newTemp(Ity_I32);
9387 IRTemp res_q = newTemp(Ity_I32);
9388
9389 assign( rNt, isT ? getIRegT(regN) : getIRegA(regN) );
9390 assign( rMt, isT ? getIRegT(regM) : getIRegA(regM) );
9391
9392 assign(res_q, binop(Iop_HAdd16Ux2, mkexpr(rNt), mkexpr(rMt)));
9393 if (isT)
9394 putIRegT( regD, mkexpr(res_q), condT );
9395 else
9396 putIRegA( regD, mkexpr(res_q), condT, Ijk_Boring );
9397
9398 DIP("uhadd16%s r%u, r%u, r%u\n", nCC(conq),regD,regN,regM);
9399 return True;
9400 }
9401 /* fall through */
9402 }
9403
sewardje2ea1762010-09-22 00:56:37 +00009404 /* ----------------- shadd8<c> <Rd>,<Rn>,<Rm> ------------------- */
9405 {
9406 UInt regD = 99, regN = 99, regM = 99;
9407 Bool gate = False;
9408
9409 if (isT) {
9410 if (INSNT0(15,4) == 0xFA8 && (INSNT1(15,0) & 0xF0F0) == 0xF020) {
9411 regN = INSNT0(3,0);
9412 regD = INSNT1(11,8);
9413 regM = INSNT1(3,0);
9414 if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
9415 gate = True;
9416 }
9417 } else {
9418 if (INSNA(27,20) == BITS8(0,1,1,0,0,0,1,1) &&
9419 INSNA(11,8) == BITS4(1,1,1,1) &&
9420 INSNA(7,4) == BITS4(1,0,0,1)) {
9421 regD = INSNA(15,12);
9422 regN = INSNA(19,16);
9423 regM = INSNA(3,0);
9424 if (regD != 15 && regN != 15 && regM != 15)
9425 gate = True;
9426 }
9427 }
9428
9429 if (gate) {
9430 IRTemp rNt = newTemp(Ity_I32);
9431 IRTemp rMt = newTemp(Ity_I32);
9432 IRTemp res_q = newTemp(Ity_I32);
9433
9434 assign( rNt, isT ? getIRegT(regN) : getIRegA(regN) );
9435 assign( rMt, isT ? getIRegT(regM) : getIRegA(regM) );
9436
9437 assign(res_q, binop(Iop_HAdd8Sx4, mkexpr(rNt), mkexpr(rMt)));
9438 if (isT)
9439 putIRegT( regD, mkexpr(res_q), condT );
9440 else
9441 putIRegA( regD, mkexpr(res_q), condT, Ijk_Boring );
9442
9443 DIP("shadd8%s r%u, r%u, r%u\n", nCC(conq),regD,regN,regM);
sewardj1f139f52010-08-29 12:33:02 +00009444 return True;
9445 }
9446 /* fall through */
9447 }
9448
9449 /* ------------------ qadd16<c> <Rd>,<Rn>,<Rm> ------------------ */
9450 {
9451 UInt regD = 99, regN = 99, regM = 99;
9452 Bool gate = False;
9453
9454 if (isT) {
9455 if (INSNT0(15,4) == 0xFA9 && (INSNT1(15,0) & 0xF0F0) == 0xF010) {
9456 regN = INSNT0(3,0);
9457 regD = INSNT1(11,8);
9458 regM = INSNT1(3,0);
9459 if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
9460 gate = True;
9461 }
9462 } else {
9463 if (INSNA(27,20) == BITS8(0,1,1,0,0,0,1,0) &&
9464 INSNA(11,8) == BITS4(1,1,1,1) &&
9465 INSNA(7,4) == BITS4(0,0,0,1)) {
9466 regD = INSNA(15,12);
9467 regN = INSNA(19,16);
9468 regM = INSNA(3,0);
9469 if (regD != 15 && regN != 15 && regM != 15)
9470 gate = True;
9471 }
9472 }
9473
9474 if (gate) {
sewardje2ea1762010-09-22 00:56:37 +00009475 IRTemp rNt = newTemp(Ity_I32);
9476 IRTemp rMt = newTemp(Ity_I32);
9477 IRTemp res_q = newTemp(Ity_I32);
sewardj1f139f52010-08-29 12:33:02 +00009478
sewardje2ea1762010-09-22 00:56:37 +00009479 assign( rNt, isT ? getIRegT(regN) : getIRegA(regN) );
9480 assign( rMt, isT ? getIRegT(regM) : getIRegA(regM) );
sewardj1f139f52010-08-29 12:33:02 +00009481
sewardje2ea1762010-09-22 00:56:37 +00009482 assign(res_q, binop(Iop_QAdd16Sx2, mkexpr(rNt), mkexpr(rMt)));
sewardj1f139f52010-08-29 12:33:02 +00009483 if (isT)
sewardje2ea1762010-09-22 00:56:37 +00009484 putIRegT( regD, mkexpr(res_q), condT );
sewardj1f139f52010-08-29 12:33:02 +00009485 else
sewardje2ea1762010-09-22 00:56:37 +00009486 putIRegA( regD, mkexpr(res_q), condT, Ijk_Boring );
sewardj1f139f52010-08-29 12:33:02 +00009487
sewardje2ea1762010-09-22 00:56:37 +00009488 DIP("qadd16%s r%u, r%u, r%u\n", nCC(conq),regD,regN,regM);
sewardj1f139f52010-08-29 12:33:02 +00009489 return True;
9490 }
9491 /* fall through */
9492 }
9493
9494 /* ------------------ qsub16<c> <Rd>,<Rn>,<Rm> ------------------ */
9495 {
9496 UInt regD = 99, regN = 99, regM = 99;
9497 Bool gate = False;
9498
sewardje2ea1762010-09-22 00:56:37 +00009499 if (isT) {
sewardj1f139f52010-08-29 12:33:02 +00009500 if (INSNT0(15,4) == 0xFAD && (INSNT1(15,0) & 0xF0F0) == 0xF010) {
9501 regN = INSNT0(3,0);
9502 regD = INSNT1(11,8);
9503 regM = INSNT1(3,0);
9504 if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
9505 gate = True;
9506 }
9507 } else {
9508 if (INSNA(27,20) == BITS8(0,1,1,0,0,0,1,0) &&
9509 INSNA(11,8) == BITS4(1,1,1,1) &&
9510 INSNA(7,4) == BITS4(0,1,1,1)) {
9511 regD = INSNA(15,12);
9512 regN = INSNA(19,16);
9513 regM = INSNA(3,0);
9514 if (regD != 15 && regN != 15 && regM != 15)
9515 gate = True;
9516 }
9517 }
9518
9519 if (gate) {
sewardje2ea1762010-09-22 00:56:37 +00009520 IRTemp rNt = newTemp(Ity_I32);
9521 IRTemp rMt = newTemp(Ity_I32);
9522 IRTemp res_q = newTemp(Ity_I32);
sewardj1f139f52010-08-29 12:33:02 +00009523
sewardje2ea1762010-09-22 00:56:37 +00009524 assign( rNt, isT ? getIRegT(regN) : getIRegA(regN) );
9525 assign( rMt, isT ? getIRegT(regM) : getIRegA(regM) );
sewardj1f139f52010-08-29 12:33:02 +00009526
sewardje2ea1762010-09-22 00:56:37 +00009527 assign(res_q, binop(Iop_QSub16Sx2, mkexpr(rNt), mkexpr(rMt)));
sewardj1f139f52010-08-29 12:33:02 +00009528 if (isT)
sewardje2ea1762010-09-22 00:56:37 +00009529 putIRegT( regD, mkexpr(res_q), condT );
sewardj1f139f52010-08-29 12:33:02 +00009530 else
sewardje2ea1762010-09-22 00:56:37 +00009531 putIRegA( regD, mkexpr(res_q), condT, Ijk_Boring );
sewardj1f139f52010-08-29 12:33:02 +00009532
sewardje2ea1762010-09-22 00:56:37 +00009533 DIP("qsub16%s r%u, r%u, r%u\n", nCC(conq),regD,regN,regM);
sewardj1f139f52010-08-29 12:33:02 +00009534 return True;
9535 }
9536 /* fall through */
9537 }
9538
sewardje2ea1762010-09-22 00:56:37 +00009539 /////////////////////////////////////////////////////////////////
9540 /////////////////////////////////////////////////////////////////
9541 /////////////////////////////////////////////////////////////////
9542 /////////////////////////////////////////////////////////////////
9543 /////////////////////////////////////////////////////////////////
9544
sewardj1f139f52010-08-29 12:33:02 +00009545 /* ------------------- qsax<c> <Rd>,<Rn>,<Rm> ------------------- */
9546 /* note: the hardware seems to construct the result differently
9547 from wot the manual says. */
9548 {
9549 UInt regD = 99, regN = 99, regM = 99;
9550 Bool gate = False;
9551
9552 if (isT) {
9553 if (INSNT0(15,4) == 0xFAE && (INSNT1(15,0) & 0xF0F0) == 0xF010) {
9554 regN = INSNT0(3,0);
9555 regD = INSNT1(11,8);
9556 regM = INSNT1(3,0);
9557 if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
9558 gate = True;
9559 }
9560 } else {
9561 if (INSNA(27,20) == BITS8(0,1,1,0,0,0,1,0) &&
9562 INSNA(11,8) == BITS4(1,1,1,1) &&
9563 INSNA(7,4) == BITS4(0,1,0,1)) {
9564 regD = INSNA(15,12);
9565 regN = INSNA(19,16);
9566 regM = INSNA(3,0);
9567 if (regD != 15 && regN != 15 && regM != 15)
9568 gate = True;
9569 }
9570 }
9571
9572 if (gate) {
9573 IRTemp irt_regN = newTemp(Ity_I32);
9574 IRTemp irt_regM = newTemp(Ity_I32);
9575 IRTemp irt_sum = newTemp(Ity_I32);
9576 IRTemp irt_diff = newTemp(Ity_I32);
9577 IRTemp irt_sum_res = newTemp(Ity_I32);
9578 IRTemp irt_diff_res = newTemp(Ity_I32);
9579
9580 assign( irt_regN, isT ? getIRegT(regN) : getIRegA(regN) );
9581 assign( irt_regM, isT ? getIRegT(regM) : getIRegA(regM) );
9582
9583 assign( irt_diff,
9584 binop( Iop_Sub32,
9585 binop( Iop_Sar32, mkexpr(irt_regN), mkU8(16) ),
9586 binop( Iop_Sar32,
9587 binop(Iop_Shl32, mkexpr(irt_regM), mkU8(16)),
9588 mkU8(16) ) ) );
9589 armSignedSatQ( irt_diff, 0x10, &irt_diff_res, NULL);
9590
9591 assign( irt_sum,
9592 binop( Iop_Add32,
9593 binop( Iop_Sar32,
9594 binop( Iop_Shl32, mkexpr(irt_regN), mkU8(16) ),
9595 mkU8(16) ),
9596 binop( Iop_Sar32, mkexpr(irt_regM), mkU8(16) )) );
9597 armSignedSatQ( irt_sum, 0x10, &irt_sum_res, NULL );
9598
9599 IRExpr* ire_result = binop( Iop_Or32,
9600 binop( Iop_Shl32, mkexpr(irt_diff_res),
9601 mkU8(16) ),
9602 binop( Iop_And32, mkexpr(irt_sum_res),
9603 mkU32(0xFFFF)) );
9604
9605 if (isT)
9606 putIRegT( regD, ire_result, condT );
9607 else
9608 putIRegA( regD, ire_result, condT, Ijk_Boring );
9609
9610 DIP( "qsax%s r%u, r%u, r%u\n", nCC(conq), regD, regN, regM );
9611 return True;
9612 }
9613 /* fall through */
9614 }
9615
9616 /* ------------------- qasx<c> <Rd>,<Rn>,<Rm> ------------------- */
9617 {
9618 UInt regD = 99, regN = 99, regM = 99;
9619 Bool gate = False;
9620
9621 if (isT) {
9622 if (INSNT0(15,4) == 0xFAA && (INSNT1(15,0) & 0xF0F0) == 0xF010) {
9623 regN = INSNT0(3,0);
9624 regD = INSNT1(11,8);
9625 regM = INSNT1(3,0);
9626 if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
9627 gate = True;
9628 }
9629 } else {
9630 if (INSNA(27,20) == BITS8(0,1,1,0,0,0,1,0) &&
9631 INSNA(11,8) == BITS4(1,1,1,1) &&
9632 INSNA(7,4) == BITS4(0,0,1,1)) {
9633 regD = INSNA(15,12);
9634 regN = INSNA(19,16);
9635 regM = INSNA(3,0);
9636 if (regD != 15 && regN != 15 && regM != 15)
9637 gate = True;
9638 }
9639 }
9640
9641 if (gate) {
9642 IRTemp irt_regN = newTemp(Ity_I32);
9643 IRTemp irt_regM = newTemp(Ity_I32);
9644 IRTemp irt_sum = newTemp(Ity_I32);
9645 IRTemp irt_diff = newTemp(Ity_I32);
9646 IRTemp irt_res_sum = newTemp(Ity_I32);
9647 IRTemp irt_res_diff = newTemp(Ity_I32);
9648
9649 assign( irt_regN, isT ? getIRegT(regN) : getIRegA(regN) );
9650 assign( irt_regM, isT ? getIRegT(regM) : getIRegA(regM) );
9651
9652 assign( irt_diff,
9653 binop( Iop_Sub32,
9654 binop( Iop_Sar32,
9655 binop( Iop_Shl32, mkexpr(irt_regN), mkU8(16) ),
9656 mkU8(16) ),
9657 binop( Iop_Sar32, mkexpr(irt_regM), mkU8(16) ) ) );
9658 armSignedSatQ( irt_diff, 0x10, &irt_res_diff, NULL );
9659
9660 assign( irt_sum,
9661 binop( Iop_Add32,
9662 binop( Iop_Sar32, mkexpr(irt_regN), mkU8(16) ),
9663 binop( Iop_Sar32,
9664 binop( Iop_Shl32, mkexpr(irt_regM), mkU8(16) ),
9665 mkU8(16) ) ) );
9666 armSignedSatQ( irt_sum, 0x10, &irt_res_sum, NULL );
9667
9668 IRExpr* ire_result
9669 = binop( Iop_Or32,
9670 binop( Iop_Shl32, mkexpr(irt_res_sum), mkU8(16) ),
9671 binop( Iop_And32, mkexpr(irt_res_diff), mkU32(0xFFFF) ) );
9672
9673 if (isT)
9674 putIRegT( regD, ire_result, condT );
9675 else
9676 putIRegA( regD, ire_result, condT, Ijk_Boring );
9677
9678 DIP( "qasx%s r%u, r%u, r%u\n", nCC(conq), regD, regN, regM );
9679 return True;
9680 }
9681 /* fall through */
9682 }
9683
sewardj22ac5962010-09-20 22:35:35 +00009684 /* ------------------- sasx<c> <Rd>,<Rn>,<Rm> ------------------- */
9685 {
9686 UInt regD = 99, regN = 99, regM = 99;
9687 Bool gate = False;
9688
9689 if (isT) {
9690 if (INSNT0(15,4) == 0xFAA && (INSNT1(15,0) & 0xF0F0) == 0xF000) {
9691 regN = INSNT0(3,0);
9692 regD = INSNT1(11,8);
9693 regM = INSNT1(3,0);
9694 if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
9695 gate = True;
9696 }
9697 } else {
9698 if (INSNA(27,20) == BITS8(0,1,1,0,0,0,0,1) &&
9699 INSNA(11,8) == BITS4(1,1,1,1) &&
9700 INSNA(7,4) == BITS4(0,0,1,1)) {
9701 regD = INSNA(15,12);
9702 regN = INSNA(19,16);
9703 regM = INSNA(3,0);
9704 if (regD != 15 && regN != 15 && regM != 15)
9705 gate = True;
9706 }
9707 }
9708
9709 if (gate) {
9710 IRTemp irt_regN = newTemp(Ity_I32);
9711 IRTemp irt_regM = newTemp(Ity_I32);
9712 IRTemp irt_sum = newTemp(Ity_I32);
9713 IRTemp irt_diff = newTemp(Ity_I32);
9714
9715 assign( irt_regN, isT ? getIRegT(regN) : getIRegA(regN) );
9716 assign( irt_regM, isT ? getIRegT(regM) : getIRegA(regM) );
9717
9718 assign( irt_diff,
9719 binop( Iop_Sub32,
9720 binop( Iop_Sar32,
9721 binop( Iop_Shl32, mkexpr(irt_regN), mkU8(16) ),
9722 mkU8(16) ),
9723 binop( Iop_Sar32, mkexpr(irt_regM), mkU8(16) ) ) );
9724
9725 assign( irt_sum,
9726 binop( Iop_Add32,
9727 binop( Iop_Sar32, mkexpr(irt_regN), mkU8(16) ),
9728 binop( Iop_Sar32,
9729 binop( Iop_Shl32, mkexpr(irt_regM), mkU8(16) ),
9730 mkU8(16) ) ) );
9731
9732 IRExpr* ire_result
9733 = binop( Iop_Or32,
9734 binop( Iop_Shl32, mkexpr(irt_sum), mkU8(16) ),
9735 binop( Iop_And32, mkexpr(irt_diff), mkU32(0xFFFF) ) );
9736
9737 IRTemp ge10 = newTemp(Ity_I32);
9738 assign(ge10, unop(Iop_Not32, mkexpr(irt_diff)));
9739 put_GEFLAG32( 0, 31, mkexpr(ge10), condT );
9740 put_GEFLAG32( 1, 31, mkexpr(ge10), condT );
9741
9742 IRTemp ge32 = newTemp(Ity_I32);
9743 assign(ge32, unop(Iop_Not32, mkexpr(irt_sum)));
9744 put_GEFLAG32( 2, 31, mkexpr(ge32), condT );
9745 put_GEFLAG32( 3, 31, mkexpr(ge32), condT );
9746
9747 if (isT)
9748 putIRegT( regD, ire_result, condT );
9749 else
9750 putIRegA( regD, ire_result, condT, Ijk_Boring );
9751
9752 DIP( "sasx%s r%u, r%u, r%u\n", nCC(conq), regD, regN, regM );
9753 return True;
9754 }
9755 /* fall through */
9756 }
9757
sewardj1f139f52010-08-29 12:33:02 +00009758 /* --------------- smuad, smuadx<c><Rd>,<Rn>,<Rm> --------------- */
sewardj310d6b22010-10-18 16:29:40 +00009759 /* --------------- smsad, smsadx<c><Rd>,<Rn>,<Rm> --------------- */
sewardj1f139f52010-08-29 12:33:02 +00009760 {
9761 UInt regD = 99, regN = 99, regM = 99, bitM = 99;
sewardj310d6b22010-10-18 16:29:40 +00009762 Bool gate = False, isAD = False;
sewardj1f139f52010-08-29 12:33:02 +00009763
9764 if (isT) {
sewardj310d6b22010-10-18 16:29:40 +00009765 if ((INSNT0(15,4) == 0xFB2 || INSNT0(15,4) == 0xFB4)
9766 && (INSNT1(15,0) & 0xF0E0) == 0xF000) {
sewardj1f139f52010-08-29 12:33:02 +00009767 regN = INSNT0(3,0);
9768 regD = INSNT1(11,8);
9769 regM = INSNT1(3,0);
9770 bitM = INSNT1(4,4);
sewardj310d6b22010-10-18 16:29:40 +00009771 isAD = INSNT0(15,4) == 0xFB2;
sewardj1f139f52010-08-29 12:33:02 +00009772 if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
9773 gate = True;
9774 }
9775 } else {
9776 if (INSNA(27,20) == BITS8(0,1,1,1,0,0,0,0) &&
9777 INSNA(15,12) == BITS4(1,1,1,1) &&
sewardj310d6b22010-10-18 16:29:40 +00009778 (INSNA(7,4) & BITS4(1,0,0,1)) == BITS4(0,0,0,1) ) {
sewardj1f139f52010-08-29 12:33:02 +00009779 regD = INSNA(19,16);
9780 regN = INSNA(3,0);
9781 regM = INSNA(11,8);
9782 bitM = INSNA(5,5);
sewardj310d6b22010-10-18 16:29:40 +00009783 isAD = INSNA(6,6) == 0;
sewardj1f139f52010-08-29 12:33:02 +00009784 if (regD != 15 && regN != 15 && regM != 15)
9785 gate = True;
9786 }
9787 }
9788
9789 if (gate) {
9790 IRTemp irt_regN = newTemp(Ity_I32);
9791 IRTemp irt_regM = newTemp(Ity_I32);
9792 IRTemp irt_prod_lo = newTemp(Ity_I32);
9793 IRTemp irt_prod_hi = newTemp(Ity_I32);
9794 IRTemp tmpM = newTemp(Ity_I32);
9795
9796 assign( irt_regN, isT ? getIRegT(regN) : getIRegA(regN) );
9797
9798 assign( tmpM, isT ? getIRegT(regM) : getIRegA(regM) );
9799 assign( irt_regM, genROR32(tmpM, (bitM & 1) ? 16 : 0) );
9800
9801 assign( irt_prod_lo,
9802 binop( Iop_Mul32,
9803 binop( Iop_Sar32,
9804 binop(Iop_Shl32, mkexpr(irt_regN), mkU8(16)),
9805 mkU8(16) ),
9806 binop( Iop_Sar32,
9807 binop(Iop_Shl32, mkexpr(irt_regM), mkU8(16)),
9808 mkU8(16) ) ) );
9809 assign( irt_prod_hi, binop(Iop_Mul32,
9810 binop(Iop_Sar32, mkexpr(irt_regN), mkU8(16)),
9811 binop(Iop_Sar32, mkexpr(irt_regM), mkU8(16))) );
9812 IRExpr* ire_result
sewardj310d6b22010-10-18 16:29:40 +00009813 = binop( isAD ? Iop_Add32 : Iop_Sub32,
9814 mkexpr(irt_prod_lo), mkexpr(irt_prod_hi) );
sewardj1f139f52010-08-29 12:33:02 +00009815
9816 if (isT)
9817 putIRegT( regD, ire_result, condT );
9818 else
9819 putIRegA( regD, ire_result, condT, Ijk_Boring );
9820
sewardj310d6b22010-10-18 16:29:40 +00009821 if (isAD) {
9822 or_into_QFLAG32(
9823 signed_overflow_after_Add32( ire_result,
9824 irt_prod_lo, irt_prod_hi ),
9825 condT
9826 );
9827 }
sewardj1f139f52010-08-29 12:33:02 +00009828
sewardj310d6b22010-10-18 16:29:40 +00009829 DIP("smu%cd%s%s r%u, r%u, r%u\n",
9830 isAD ? 'a' : 's',
sewardj1f139f52010-08-29 12:33:02 +00009831 bitM ? "x" : "", nCC(conq), regD, regN, regM);
9832 return True;
9833 }
9834 /* fall through */
9835 }
9836
9837 /* --------------- smlad{X}<c> <Rd>,<Rn>,<Rm>,<Ra> -------------- */
sewardj310d6b22010-10-18 16:29:40 +00009838 /* --------------- smlsd{X}<c> <Rd>,<Rn>,<Rm>,<Ra> -------------- */
sewardj1f139f52010-08-29 12:33:02 +00009839 {
9840 UInt regD = 99, regN = 99, regM = 99, regA = 99, bitM = 99;
sewardj310d6b22010-10-18 16:29:40 +00009841 Bool gate = False, isAD = False;
sewardj1f139f52010-08-29 12:33:02 +00009842
9843 if (isT) {
sewardj310d6b22010-10-18 16:29:40 +00009844 if ((INSNT0(15,4) == 0xFB2 || INSNT0(15,4) == 0xFB4)
9845 && INSNT1(7,5) == BITS3(0,0,0)) {
sewardj1f139f52010-08-29 12:33:02 +00009846 regN = INSNT0(3,0);
9847 regD = INSNT1(11,8);
9848 regM = INSNT1(3,0);
9849 regA = INSNT1(15,12);
9850 bitM = INSNT1(4,4);
sewardj310d6b22010-10-18 16:29:40 +00009851 isAD = INSNT0(15,4) == 0xFB2;
sewardj1f139f52010-08-29 12:33:02 +00009852 if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM)
9853 && !isBadRegT(regA))
9854 gate = True;
9855 }
9856 } else {
9857 if (INSNA(27,20) == BITS8(0,1,1,1,0,0,0,0) &&
sewardj310d6b22010-10-18 16:29:40 +00009858 (INSNA(7,4) & BITS4(1,0,0,1)) == BITS4(0,0,0,1)) {
sewardj1f139f52010-08-29 12:33:02 +00009859 regD = INSNA(19,16);
9860 regA = INSNA(15,12);
9861 regN = INSNA(3,0);
9862 regM = INSNA(11,8);
9863 bitM = INSNA(5,5);
sewardj310d6b22010-10-18 16:29:40 +00009864 isAD = INSNA(6,6) == 0;
sewardj1f139f52010-08-29 12:33:02 +00009865 if (regD != 15 && regN != 15 && regM != 15 && regA != 15)
9866 gate = True;
9867 }
9868 }
9869
9870 if (gate) {
9871 IRTemp irt_regN = newTemp(Ity_I32);
9872 IRTemp irt_regM = newTemp(Ity_I32);
9873 IRTemp irt_regA = newTemp(Ity_I32);
9874 IRTemp irt_prod_lo = newTemp(Ity_I32);
9875 IRTemp irt_prod_hi = newTemp(Ity_I32);
9876 IRTemp irt_sum = newTemp(Ity_I32);
9877 IRTemp tmpM = newTemp(Ity_I32);
9878
9879 assign( irt_regN, isT ? getIRegT(regN) : getIRegA(regN) );
9880 assign( irt_regA, isT ? getIRegT(regA) : getIRegA(regA) );
9881
9882 assign( tmpM, isT ? getIRegT(regM) : getIRegA(regM) );
9883 assign( irt_regM, genROR32(tmpM, (bitM & 1) ? 16 : 0) );
9884
9885 assign( irt_prod_lo,
9886 binop(Iop_Mul32,
9887 binop(Iop_Sar32,
9888 binop( Iop_Shl32, mkexpr(irt_regN), mkU8(16) ),
9889 mkU8(16)),
9890 binop(Iop_Sar32,
9891 binop( Iop_Shl32, mkexpr(irt_regM), mkU8(16) ),
9892 mkU8(16))) );
9893 assign( irt_prod_hi,
9894 binop( Iop_Mul32,
9895 binop( Iop_Sar32, mkexpr(irt_regN), mkU8(16) ),
9896 binop( Iop_Sar32, mkexpr(irt_regM), mkU8(16) ) ) );
sewardj310d6b22010-10-18 16:29:40 +00009897 assign( irt_sum, binop( isAD ? Iop_Add32 : Iop_Sub32,
sewardj1f139f52010-08-29 12:33:02 +00009898 mkexpr(irt_prod_lo), mkexpr(irt_prod_hi) ) );
9899
9900 IRExpr* ire_result = binop(Iop_Add32, mkexpr(irt_sum), mkexpr(irt_regA));
9901
9902 if (isT)
9903 putIRegT( regD, ire_result, condT );
9904 else
9905 putIRegA( regD, ire_result, condT, Ijk_Boring );
9906
sewardj310d6b22010-10-18 16:29:40 +00009907 if (isAD) {
9908 or_into_QFLAG32(
9909 signed_overflow_after_Add32( mkexpr(irt_sum),
9910 irt_prod_lo, irt_prod_hi ),
9911 condT
9912 );
9913 }
sewardj1f139f52010-08-29 12:33:02 +00009914
sewardj310d6b22010-10-18 16:29:40 +00009915 or_into_QFLAG32(
9916 signed_overflow_after_Add32( ire_result, irt_sum, irt_regA ),
9917 condT
9918 );
9919
9920 DIP("sml%cd%s%s r%u, r%u, r%u, r%u\n",
9921 isAD ? 'a' : 's',
sewardj1f139f52010-08-29 12:33:02 +00009922 bitM ? "x" : "", nCC(conq), regD, regN, regM, regA);
9923 return True;
9924 }
9925 /* fall through */
9926 }
9927
9928 /* ----- smlabb, smlabt, smlatb, smlatt <Rd>,<Rn>,<Rm>,<Ra> ----- */
9929 {
9930 UInt regD = 99, regN = 99, regM = 99, regA = 99, bitM = 99, bitN = 99;
9931 Bool gate = False;
9932
9933 if (isT) {
9934 if (INSNT0(15,4) == 0xFB1 && INSNT1(7,6) == BITS2(0,0)) {
9935 regN = INSNT0(3,0);
9936 regD = INSNT1(11,8);
9937 regM = INSNT1(3,0);
9938 regA = INSNT1(15,12);
9939 bitM = INSNT1(4,4);
9940 bitN = INSNT1(5,5);
9941 if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM)
9942 && !isBadRegT(regA))
9943 gate = True;
9944 }
9945 } else {
9946 if (INSNA(27,20) == BITS8(0,0,0,1,0,0,0,0) &&
9947 (INSNA(7,4) & BITS4(1,0,0,1)) == BITS4(1,0,0,0)) {
9948 regD = INSNA(19,16);
9949 regN = INSNA(3,0);
9950 regM = INSNA(11,8);
9951 regA = INSNA(15,12);
9952 bitM = INSNA(6,6);
9953 bitN = INSNA(5,5);
9954 if (regD != 15 && regN != 15 && regM != 15 && regA != 15)
9955 gate = True;
9956 }
9957 }
9958
9959 if (gate) {
9960 IRTemp irt_regA = newTemp(Ity_I32);
9961 IRTemp irt_prod = newTemp(Ity_I32);
9962
9963 assign( irt_prod,
9964 binop(Iop_Mul32,
9965 binop(Iop_Sar32,
9966 binop(Iop_Shl32,
9967 isT ? getIRegT(regN) : getIRegA(regN),
9968 mkU8(bitN ? 0 : 16)),
9969 mkU8(16)),
9970 binop(Iop_Sar32,
9971 binop(Iop_Shl32,
9972 isT ? getIRegT(regM) : getIRegA(regM),
9973 mkU8(bitM ? 0 : 16)),
9974 mkU8(16))) );
9975
9976 assign( irt_regA, isT ? getIRegT(regA) : getIRegA(regA) );
9977
9978 IRExpr* ire_result = binop(Iop_Add32, mkexpr(irt_prod), mkexpr(irt_regA));
9979
9980 if (isT)
9981 putIRegT( regD, ire_result, condT );
9982 else
9983 putIRegA( regD, ire_result, condT, Ijk_Boring );
9984
sewardj310d6b22010-10-18 16:29:40 +00009985 or_into_QFLAG32(
9986 signed_overflow_after_Add32( ire_result, irt_prod, irt_regA ),
9987 condT
9988 );
sewardj1f139f52010-08-29 12:33:02 +00009989
9990 DIP( "smla%c%c%s r%u, r%u, r%u, r%u\n",
9991 bitN ? 't' : 'b', bitM ? 't' : 'b',
9992 nCC(conq), regD, regN, regM, regA );
9993 return True;
9994 }
9995 /* fall through */
9996 }
9997
sewardj22ac5962010-09-20 22:35:35 +00009998 /* ----- smlawb, smlawt <Rd>,<Rn>,<Rm>,<Ra> ----- */
9999 {
10000 UInt regD = 99, regN = 99, regM = 99, regA = 99, bitM = 99;
10001 Bool gate = False;
10002
10003 if (isT) {
10004 if (INSNT0(15,4) == 0xFB3 && INSNT1(7,5) == BITS3(0,0,0)) {
10005 regN = INSNT0(3,0);
10006 regD = INSNT1(11,8);
10007 regM = INSNT1(3,0);
10008 regA = INSNT1(15,12);
10009 bitM = INSNT1(4,4);
10010 if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM)
10011 && !isBadRegT(regA))
10012 gate = True;
10013 }
10014 } else {
10015 if (INSNA(27,20) == BITS8(0,0,0,1,0,0,1,0) &&
10016 (INSNA(7,4) & BITS4(1,0,1,1)) == BITS4(1,0,0,0)) {
10017 regD = INSNA(19,16);
10018 regN = INSNA(3,0);
10019 regM = INSNA(11,8);
10020 regA = INSNA(15,12);
10021 bitM = INSNA(6,6);
10022 if (regD != 15 && regN != 15 && regM != 15 && regA != 15)
10023 gate = True;
10024 }
10025 }
10026
10027 if (gate) {
10028 IRTemp irt_regA = newTemp(Ity_I32);
10029 IRTemp irt_prod = newTemp(Ity_I64);
10030
10031 assign( irt_prod,
10032 binop(Iop_MullS32,
10033 isT ? getIRegT(regN) : getIRegA(regN),
10034 binop(Iop_Sar32,
10035 binop(Iop_Shl32,
10036 isT ? getIRegT(regM) : getIRegA(regM),
10037 mkU8(bitM ? 0 : 16)),
10038 mkU8(16))) );
10039
10040 assign( irt_regA, isT ? getIRegT(regA) : getIRegA(regA) );
10041
10042 IRTemp prod32 = newTemp(Ity_I32);
10043 assign(prod32,
10044 binop(Iop_Or32,
10045 binop(Iop_Shl32, unop(Iop_64HIto32, mkexpr(irt_prod)), mkU8(16)),
10046 binop(Iop_Shr32, unop(Iop_64to32, mkexpr(irt_prod)), mkU8(16))
10047 ));
10048
10049 IRExpr* ire_result = binop(Iop_Add32, mkexpr(prod32), mkexpr(irt_regA));
10050
10051 if (isT)
10052 putIRegT( regD, ire_result, condT );
10053 else
10054 putIRegA( regD, ire_result, condT, Ijk_Boring );
10055
sewardj310d6b22010-10-18 16:29:40 +000010056 or_into_QFLAG32(
10057 signed_overflow_after_Add32( ire_result, prod32, irt_regA ),
10058 condT
10059 );
sewardj22ac5962010-09-20 22:35:35 +000010060
10061 DIP( "smlaw%c%s r%u, r%u, r%u, r%u\n",
10062 bitM ? 't' : 'b',
10063 nCC(conq), regD, regN, regM, regA );
10064 return True;
10065 }
10066 /* fall through */
10067 }
10068
sewardj1f139f52010-08-29 12:33:02 +000010069 /* ------------------- sel<c> <Rd>,<Rn>,<Rm> -------------------- */
10070 /* fixme: fix up the test in v6media.c so that we can pass the ge
10071 flags as part of the test. */
10072 {
10073 UInt regD = 99, regN = 99, regM = 99;
10074 Bool gate = False;
10075
10076 if (isT) {
10077 if (INSNT0(15,4) == 0xFAA && (INSNT1(15,0) & 0xF0F0) == 0xF080) {
10078 regN = INSNT0(3,0);
10079 regD = INSNT1(11,8);
10080 regM = INSNT1(3,0);
10081 if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
10082 gate = True;
10083 }
10084 } else {
10085 if (INSNA(27,20) == BITS8(0,1,1,0,1,0,0,0) &&
10086 INSNA(11,8) == BITS4(1,1,1,1) &&
10087 INSNA(7,4) == BITS4(1,0,1,1)) {
10088 regD = INSNA(15,12);
10089 regN = INSNA(19,16);
10090 regM = INSNA(3,0);
10091 if (regD != 15 && regN != 15 && regM != 15)
10092 gate = True;
10093 }
10094 }
10095
10096 if (gate) {
10097 IRTemp irt_ge_flag0 = newTemp(Ity_I32);
10098 IRTemp irt_ge_flag1 = newTemp(Ity_I32);
10099 IRTemp irt_ge_flag2 = newTemp(Ity_I32);
10100 IRTemp irt_ge_flag3 = newTemp(Ity_I32);
10101
10102 assign( irt_ge_flag0, get_GEFLAG32(0) );
10103 assign( irt_ge_flag1, get_GEFLAG32(1) );
10104 assign( irt_ge_flag2, get_GEFLAG32(2) );
10105 assign( irt_ge_flag3, get_GEFLAG32(3) );
10106
10107 IRExpr* ire_ge_flag0_or
10108 = binop(Iop_Or32, mkexpr(irt_ge_flag0),
10109 binop(Iop_Sub32, mkU32(0), mkexpr(irt_ge_flag0)));
10110 IRExpr* ire_ge_flag1_or
10111 = binop(Iop_Or32, mkexpr(irt_ge_flag1),
10112 binop(Iop_Sub32, mkU32(0), mkexpr(irt_ge_flag1)));
10113 IRExpr* ire_ge_flag2_or
10114 = binop(Iop_Or32, mkexpr(irt_ge_flag2),
10115 binop(Iop_Sub32, mkU32(0), mkexpr(irt_ge_flag2)));
10116 IRExpr* ire_ge_flag3_or
10117 = binop(Iop_Or32, mkexpr(irt_ge_flag3),
10118 binop(Iop_Sub32, mkU32(0), mkexpr(irt_ge_flag3)));
10119
10120 IRExpr* ire_ge_flags
10121 = binop( Iop_Or32,
10122 binop(Iop_Or32,
10123 binop(Iop_And32,
10124 binop(Iop_Sar32, ire_ge_flag0_or, mkU8(31)),
10125 mkU32(0x000000ff)),
10126 binop(Iop_And32,
10127 binop(Iop_Sar32, ire_ge_flag1_or, mkU8(31)),
10128 mkU32(0x0000ff00))),
10129 binop(Iop_Or32,
10130 binop(Iop_And32,
10131 binop(Iop_Sar32, ire_ge_flag2_or, mkU8(31)),
10132 mkU32(0x00ff0000)),
10133 binop(Iop_And32,
10134 binop(Iop_Sar32, ire_ge_flag3_or, mkU8(31)),
10135 mkU32(0xff000000))) );
10136
10137 IRExpr* ire_result
10138 = binop(Iop_Or32,
10139 binop(Iop_And32,
10140 isT ? getIRegT(regN) : getIRegA(regN),
10141 ire_ge_flags ),
10142 binop(Iop_And32,
10143 isT ? getIRegT(regM) : getIRegA(regM),
10144 unop(Iop_Not32, ire_ge_flags)));
10145
10146 if (isT)
10147 putIRegT( regD, ire_result, condT );
10148 else
10149 putIRegA( regD, ire_result, condT, Ijk_Boring );
10150
10151 DIP("sel%s r%u, r%u, r%u\n", nCC(conq), regD, regN, regM );
10152 return True;
10153 }
10154 /* fall through */
10155 }
10156
sewardj1f139f52010-08-29 12:33:02 +000010157 /* ----------------- uxtab16<c> Rd,Rn,Rm{,rot} ------------------ */
10158 {
10159 UInt regD = 99, regN = 99, regM = 99, rotate = 99;
10160 Bool gate = False;
10161
10162 if (isT) {
10163 if (INSNT0(15,4) == 0xFA3 && (INSNT1(15,0) & 0xF0C0) == 0xF080) {
10164 regN = INSNT0(3,0);
10165 regD = INSNT1(11,8);
10166 regM = INSNT1(3,0);
10167 rotate = INSNT1(5,4);
10168 if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
10169 gate = True;
10170 }
10171 } else {
10172 if (INSNA(27,20) == BITS8(0,1,1,0,1,1,0,0) &&
10173 INSNA(9,4) == BITS6(0,0,0,1,1,1) ) {
10174 regD = INSNA(15,12);
10175 regN = INSNA(19,16);
10176 regM = INSNA(3,0);
10177 rotate = INSNA(11,10);
10178 if (regD != 15 && regN != 15 && regM != 15)
10179 gate = True;
10180 }
10181 }
10182
10183 if (gate) {
10184 IRTemp irt_regN = newTemp(Ity_I32);
10185 assign( irt_regN, isT ? getIRegT(regN) : getIRegA(regN) );
10186
10187 IRTemp irt_regM = newTemp(Ity_I32);
10188 assign( irt_regM, isT ? getIRegT(regM) : getIRegA(regM) );
10189
10190 IRTemp irt_rot = newTemp(Ity_I32);
10191 assign( irt_rot, binop(Iop_And32,
10192 genROR32(irt_regM, 8 * rotate),
10193 mkU32(0x00FF00FF)) );
10194
10195 IRExpr* resLo
10196 = binop(Iop_And32,
10197 binop(Iop_Add32, mkexpr(irt_regN), mkexpr(irt_rot)),
10198 mkU32(0x0000FFFF));
10199
10200 IRExpr* resHi
10201 = binop(Iop_Add32,
10202 binop(Iop_And32, mkexpr(irt_regN), mkU32(0xFFFF0000)),
10203 binop(Iop_And32, mkexpr(irt_rot), mkU32(0xFFFF0000)));
10204
10205 IRExpr* ire_result
10206 = binop( Iop_Or32, resHi, resLo );
10207
10208 if (isT)
10209 putIRegT( regD, ire_result, condT );
10210 else
10211 putIRegA( regD, ire_result, condT, Ijk_Boring );
10212
10213 DIP( "uxtab16%s r%u, r%u, r%u, ROR #%u\n",
10214 nCC(conq), regD, regN, regM, 8 * rotate );
10215 return True;
10216 }
10217 /* fall through */
10218 }
10219
sewardj310d6b22010-10-18 16:29:40 +000010220 /* --------------- usad8 Rd,Rn,Rm ---------------- */
10221 /* --------------- usada8 Rd,Rn,Rm,Ra ---------------- */
10222 {
10223 UInt rD = 99, rN = 99, rM = 99, rA = 99;
10224 Bool gate = False;
10225
10226 if (isT) {
10227 if (INSNT0(15,4) == 0xFB7 && INSNT1(7,4) == BITS4(0,0,0,0)) {
10228 rN = INSNT0(3,0);
10229 rA = INSNT1(15,12);
10230 rD = INSNT1(11,8);
10231 rM = INSNT1(3,0);
10232 if (!isBadRegT(rD) && !isBadRegT(rN) && !isBadRegT(rM) && rA != 13)
10233 gate = True;
10234 }
10235 } else {
10236 if (INSNA(27,20) == BITS8(0,1,1,1,1,0,0,0) &&
10237 INSNA(7,4) == BITS4(0,0,0,1) ) {
10238 rD = INSNA(19,16);
10239 rA = INSNA(15,12);
10240 rM = INSNA(11,8);
10241 rN = INSNA(3,0);
10242 if (rD != 15 && rN != 15 && rM != 15 /* but rA can be 15 */)
10243 gate = True;
10244 }
10245 }
10246 /* We allow rA == 15, to denote the usad8 (no accumulator) case. */
10247
10248 if (gate) {
10249 IRExpr* rNe = isT ? getIRegT(rN) : getIRegA(rN);
10250 IRExpr* rMe = isT ? getIRegT(rM) : getIRegA(rM);
10251 IRExpr* rAe = rA == 15 ? mkU32(0)
10252 : (isT ? getIRegT(rA) : getIRegA(rA));
10253 IRExpr* res = binop(Iop_Add32,
10254 binop(Iop_Sad8Ux4, rNe, rMe),
10255 rAe);
10256 if (isT)
10257 putIRegT( rD, res, condT );
10258 else
10259 putIRegA( rD, res, condT, Ijk_Boring );
10260
10261 if (rA == 15) {
10262 DIP( "usad8%s r%u, r%u, r%u\n",
10263 nCC(conq), rD, rN, rM );
10264 } else {
10265 DIP( "usada8%s r%u, r%u, r%u, r%u\n",
10266 nCC(conq), rD, rN, rM, rA );
10267 }
10268 return True;
10269 }
10270 /* fall through */
10271 }
10272
sewardj44ce46d2012-07-11 13:19:10 +000010273 /* ------------------ qadd<c> <Rd>,<Rn>,<Rm> ------------------- */
10274 {
10275 UInt regD = 99, regN = 99, regM = 99;
10276 Bool gate = False;
10277
10278 if (isT) {
10279 if (INSNT0(15,4) == 0xFA8 && (INSNT1(15,0) & 0xF0F0) == 0xF080) {
10280 regN = INSNT0(3,0);
10281 regD = INSNT1(11,8);
10282 regM = INSNT1(3,0);
10283 if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
10284 gate = True;
10285 }
10286 } else {
10287 if (INSNA(27,20) == BITS8(0,0,0,1,0,0,0,0) &&
10288 INSNA(11,8) == BITS4(0,0,0,0) &&
10289 INSNA(7,4) == BITS4(0,1,0,1)) {
10290 regD = INSNA(15,12);
10291 regN = INSNA(19,16);
10292 regM = INSNA(3,0);
10293 if (regD != 15 && regN != 15 && regM != 15)
10294 gate = True;
10295 }
10296 }
10297
10298 if (gate) {
10299 IRTemp rNt = newTemp(Ity_I32);
10300 IRTemp rMt = newTemp(Ity_I32);
10301 IRTemp res_q = newTemp(Ity_I32);
10302
10303 assign( rNt, isT ? getIRegT(regN) : getIRegA(regN) );
10304 assign( rMt, isT ? getIRegT(regM) : getIRegA(regM) );
10305
10306 assign(res_q, binop(Iop_QAdd32S, mkexpr(rMt), mkexpr(rNt)));
10307 if (isT)
10308 putIRegT( regD, mkexpr(res_q), condT );
10309 else
10310 putIRegA( regD, mkexpr(res_q), condT, Ijk_Boring );
10311
10312 or_into_QFLAG32(
10313 signed_overflow_after_Add32(
10314 binop(Iop_Add32, mkexpr(rMt), mkexpr(rNt)), rMt, rNt),
10315 condT
10316 );
10317
10318 DIP("qadd%s r%u, r%u, r%u\n", nCC(conq),regD,regM,regN);
10319 return True;
10320 }
10321 /* fall through */
10322 }
10323
10324 /* ------------------ qsub<c> <Rd>,<Rn>,<Rm> ------------------- */
10325 {
10326 UInt regD = 99, regN = 99, regM = 99;
10327 Bool gate = False;
10328
10329 if (isT) {
10330 if (INSNT0(15,4) == 0xFA8 && (INSNT1(15,0) & 0xF0F0) == 0xF0A0) {
10331 regN = INSNT0(3,0);
10332 regD = INSNT1(11,8);
10333 regM = INSNT1(3,0);
10334 if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
10335 gate = True;
10336 }
10337 } else {
10338 if (INSNA(27,20) == BITS8(0,0,0,1,0,0,1,0) &&
10339 INSNA(11,8) == BITS4(0,0,0,0) &&
10340 INSNA(7,4) == BITS4(0,1,0,1)) {
10341 regD = INSNA(15,12);
10342 regN = INSNA(19,16);
10343 regM = INSNA(3,0);
10344 if (regD != 15 && regN != 15 && regM != 15)
10345 gate = True;
10346 }
10347 }
10348
10349 if (gate) {
10350 IRTemp rNt = newTemp(Ity_I32);
10351 IRTemp rMt = newTemp(Ity_I32);
10352 IRTemp res_q = newTemp(Ity_I32);
10353
10354 assign( rNt, isT ? getIRegT(regN) : getIRegA(regN) );
10355 assign( rMt, isT ? getIRegT(regM) : getIRegA(regM) );
10356
10357 assign(res_q, binop(Iop_QSub32S, mkexpr(rMt), mkexpr(rNt)));
10358 if (isT)
10359 putIRegT( regD, mkexpr(res_q), condT );
10360 else
10361 putIRegA( regD, mkexpr(res_q), condT, Ijk_Boring );
10362
10363 or_into_QFLAG32(
10364 signed_overflow_after_Sub32(
10365 binop(Iop_Sub32, mkexpr(rMt), mkexpr(rNt)), rMt, rNt),
10366 condT
10367 );
10368
10369 DIP("qsub%s r%u, r%u, r%u\n", nCC(conq),regD,regM,regN);
10370 return True;
10371 }
10372 /* fall through */
10373 }
10374
sewardj1f139f52010-08-29 12:33:02 +000010375 /* ---------- Doesn't match anything. ---------- */
10376 return False;
10377
10378# undef INSNA
10379# undef INSNT0
10380# undef INSNT1
10381}
10382
10383
10384/*------------------------------------------------------------*/
sewardjd2664472010-08-22 12:44:20 +000010385/*--- LDMxx/STMxx helper (both ARM and Thumb32) ---*/
10386/*------------------------------------------------------------*/
10387
10388/* Generate IR for LDMxx and STMxx. This is complex. Assumes it's
10389 unconditional, so the caller must produce a jump-around before
10390 calling this, if the insn is to be conditional. Caller is
10391 responsible for all validation of parameters. For LDMxx, if PC is
10392 amongst the values loaded, caller is also responsible for
10393 generating the jump. */
10394static void mk_ldm_stm ( Bool arm, /* True: ARM, False: Thumb */
10395 UInt rN, /* base reg */
10396 UInt bINC, /* 1: inc, 0: dec */
10397 UInt bBEFORE, /* 1: inc/dec before, 0: after */
10398 UInt bW, /* 1: writeback to Rn */
10399 UInt bL, /* 1: load, 0: store */
10400 UInt regList )
10401{
10402 Int i, r, m, nRegs;
sewardjf5800652011-10-14 15:44:00 +000010403 IRTemp jk = Ijk_Boring;
sewardjd2664472010-08-22 12:44:20 +000010404
10405 /* Get hold of the old Rn value. We might need to write its value
10406 to memory during a store, and if it's also the writeback
10407 register then we need to get its value now. We can't treat it
10408 exactly like the other registers we're going to transfer,
10409 because for xxMDA and xxMDB writeback forms, the generated IR
10410 updates Rn in the guest state before any transfers take place.
10411 We have to do this as per comments below, in order that if Rn is
10412 the stack pointer then it always has a value is below or equal
10413 to any of the transfer addresses. Ick. */
10414 IRTemp oldRnT = newTemp(Ity_I32);
10415 assign(oldRnT, arm ? getIRegA(rN) : getIRegT(rN));
10416
10417 IRTemp anchorT = newTemp(Ity_I32);
10418 /* The old (Addison-Wesley) ARM ARM seems to say that LDMxx/STMxx
10419 ignore the bottom two bits of the address. However, Cortex-A8
10420 doesn't seem to care. Hence: */
10421 /* No .. don't force alignment .. */
10422 /* assign(anchorT, binop(Iop_And32, mkexpr(oldRnT), mkU32(~3U))); */
10423 /* Instead, use the potentially misaligned address directly. */
10424 assign(anchorT, mkexpr(oldRnT));
10425
10426 IROp opADDorSUB = bINC ? Iop_Add32 : Iop_Sub32;
10427 // bINC == 1: xxMIA, xxMIB
10428 // bINC == 0: xxMDA, xxMDB
10429
10430 // For xxMDA and xxMDB, update Rn first if necessary. We have
10431 // to do this first so that, for the common idiom of the transfers
10432 // faulting because we're pushing stuff onto a stack and the stack
10433 // is growing down onto allocate-on-fault pages (as Valgrind simulates),
10434 // we need to have the SP up-to-date "covering" (pointing below) the
10435 // transfer area. For the same reason, if we are doing xxMIA or xxMIB,
10436 // do the transfer first, and then update rN afterwards.
10437 nRegs = 0;
10438 for (i = 0; i < 16; i++) {
10439 if ((regList & (1 << i)) != 0)
10440 nRegs++;
10441 }
10442 if (bW == 1 && !bINC) {
10443 IRExpr* e = binop(opADDorSUB, mkexpr(oldRnT), mkU32(4*nRegs));
10444 if (arm)
10445 putIRegA( rN, e, IRTemp_INVALID, Ijk_Boring );
10446 else
10447 putIRegT( rN, e, IRTemp_INVALID );
10448 }
10449
10450 // Make up a list of the registers to transfer, and their offsets
10451 // in memory relative to the anchor. If the base reg (Rn) is part
10452 // of the transfer, then do it last for a load and first for a store.
10453 UInt xReg[16], xOff[16];
10454 Int nX = 0;
10455 m = 0;
10456 for (i = 0; i < 16; i++) {
10457 r = bINC ? i : (15-i);
10458 if (0 == (regList & (1<<r)))
10459 continue;
10460 if (bBEFORE)
10461 m++;
10462 /* paranoia: check we aren't transferring the writeback
10463 register during a load. Should be assured by decode-point
10464 check above. */
10465 if (bW == 1 && bL == 1)
10466 vassert(r != rN);
10467
10468 xOff[nX] = 4 * m;
10469 xReg[nX] = r;
10470 nX++;
10471
10472 if (!bBEFORE)
10473 m++;
10474 }
10475 vassert(m == nRegs);
10476 vassert(nX == nRegs);
10477 vassert(nX <= 16);
10478
10479 if (bW == 0 && (regList & (1<<rN)) != 0) {
10480 /* Non-writeback, and basereg is to be transferred. Do its
10481 transfer last for a load and first for a store. Requires
10482 reordering xOff/xReg. */
10483 if (0) {
10484 vex_printf("\nREG_LIST_PRE: (rN=%d)\n", rN);
10485 for (i = 0; i < nX; i++)
10486 vex_printf("reg %d off %d\n", xReg[i], xOff[i]);
10487 vex_printf("\n");
10488 }
10489
10490 vassert(nX > 0);
10491 for (i = 0; i < nX; i++) {
10492 if (xReg[i] == rN)
10493 break;
10494 }
10495 vassert(i < nX); /* else we didn't find it! */
10496 UInt tReg = xReg[i];
10497 UInt tOff = xOff[i];
10498 if (bL == 1) {
10499 /* load; make this transfer happen last */
10500 if (i < nX-1) {
10501 for (m = i+1; m < nX; m++) {
10502 xReg[m-1] = xReg[m];
10503 xOff[m-1] = xOff[m];
10504 }
10505 vassert(m == nX);
10506 xReg[m-1] = tReg;
10507 xOff[m-1] = tOff;
10508 }
10509 } else {
10510 /* store; make this transfer happen first */
10511 if (i > 0) {
10512 for (m = i-1; m >= 0; m--) {
10513 xReg[m+1] = xReg[m];
10514 xOff[m+1] = xOff[m];
10515 }
10516 vassert(m == -1);
10517 xReg[0] = tReg;
10518 xOff[0] = tOff;
10519 }
10520 }
10521
10522 if (0) {
10523 vex_printf("REG_LIST_POST:\n");
10524 for (i = 0; i < nX; i++)
10525 vex_printf("reg %d off %d\n", xReg[i], xOff[i]);
10526 vex_printf("\n");
10527 }
10528 }
10529
sewardjf5800652011-10-14 15:44:00 +000010530 /* According to the Cortex A8 TRM Sec. 5.2.1, LDM(1) with r13 as the base
10531 register and PC in the register list is a return for purposes of branch
10532 prediction.
10533 The ARM ARM Sec. C9.10.1 further specifies that writeback must be enabled
10534 to be counted in event 0x0E (Procedure return).*/
10535 if (rN == 13 && bL == 1 && bINC && !bBEFORE && bW == 1) {
10536 jk = Ijk_Ret;
10537 }
10538
sewardjd2664472010-08-22 12:44:20 +000010539 /* Actually generate the transfers */
10540 for (i = 0; i < nX; i++) {
10541 r = xReg[i];
10542 if (bL == 1) {
10543 IRExpr* e = loadLE(Ity_I32,
10544 binop(opADDorSUB, mkexpr(anchorT),
10545 mkU32(xOff[i])));
10546 if (arm) {
sewardjf5800652011-10-14 15:44:00 +000010547 putIRegA( r, e, IRTemp_INVALID, jk );
sewardjd2664472010-08-22 12:44:20 +000010548 } else {
10549 // no: putIRegT( r, e, IRTemp_INVALID );
10550 // putIRegT refuses to write to R15. But that might happen.
10551 // Since this is uncond, and we need to be able to
10552 // write the PC, just use the low level put:
10553 llPutIReg( r, e );
10554 }
10555 } else {
10556 /* if we're storing Rn, make sure we use the correct
10557 value, as per extensive comments above */
10558 storeLE( binop(opADDorSUB, mkexpr(anchorT), mkU32(xOff[i])),
10559 r == rN ? mkexpr(oldRnT)
10560 : (arm ? getIRegA(r) : getIRegT(r) ) );
10561 }
10562 }
10563
10564 // If we are doing xxMIA or xxMIB,
10565 // do the transfer first, and then update rN afterwards.
10566 if (bW == 1 && bINC) {
10567 IRExpr* e = binop(opADDorSUB, mkexpr(oldRnT), mkU32(4*nRegs));
10568 if (arm)
10569 putIRegA( rN, e, IRTemp_INVALID, Ijk_Boring );
10570 else
10571 putIRegT( rN, e, IRTemp_INVALID );
10572 }
10573}
10574
10575
10576/*------------------------------------------------------------*/
10577/*--- VFP (CP 10 and 11) instructions ---*/
10578/*------------------------------------------------------------*/
10579
10580/* Both ARM and Thumb */
10581
10582/* Translate a CP10 or CP11 instruction. If successful, returns
10583 True and *dres may or may not be updated. If failure, returns
10584 False and doesn't change *dres nor create any IR.
10585
10586 The ARM and Thumb encodings are identical for the low 28 bits of
10587 the insn (yay!) and that's what the caller must supply, iow, imm28
10588 has the top 4 bits masked out. Caller is responsible for
10589 determining whether the masked-out bits are valid for a CP10/11
10590 insn. The rules for the top 4 bits are:
10591
10592 ARM: 0000 to 1110 allowed, and this is the gating condition.
10593 1111 (NV) is not allowed.
10594
10595 Thumb: must be 1110. The gating condition is taken from
10596 ITSTATE in the normal way.
10597
10598 Conditionalisation:
10599
10600 Caller must supply an IRTemp 'condT' holding the gating condition,
10601 or IRTemp_INVALID indicating the insn is always executed.
10602
10603 Caller must also supply an ARMCondcode 'cond'. This is only used
10604 for debug printing, no other purpose. For ARM, this is simply the
10605 top 4 bits of the original instruction. For Thumb, the condition
10606 is not (really) known until run time, and so ARMCondAL should be
10607 passed, only so that printing of these instructions does not show
10608 any condition.
10609
10610 Finally, the caller must indicate whether this occurs in ARM or
10611 Thumb code.
10612*/
10613static Bool decode_CP10_CP11_instruction (
10614 /*MOD*/DisResult* dres,
10615 UInt insn28,
10616 IRTemp condT,
10617 ARMCondcode conq,
10618 Bool isT
10619 )
10620{
10621# define INSN(_bMax,_bMin) SLICE_UInt(insn28, (_bMax), (_bMin))
10622
10623 vassert(INSN(31,28) == BITS4(0,0,0,0)); // caller's obligation
10624
10625 if (isT) {
10626 vassert(conq == ARMCondAL);
10627 } else {
10628 vassert(conq >= ARMCondEQ && conq <= ARMCondAL);
10629 }
10630
10631 /* ----------------------------------------------------------- */
10632 /* -- VFP instructions -- double precision (mostly) -- */
10633 /* ----------------------------------------------------------- */
10634
10635 /* --------------------- fldmx, fstmx --------------------- */
10636 /*
10637 31 27 23 19 15 11 7 0
10638 P U WL
10639 C4-100, C5-26 1 FSTMX cond 1100 1000 Rn Dd 1011 offset
10640 C4-100, C5-28 2 FSTMIAX cond 1100 1010 Rn Dd 1011 offset
10641 C4-100, C5-30 3 FSTMDBX cond 1101 0010 Rn Dd 1011 offset
10642
10643 C4-42, C5-26 1 FLDMX cond 1100 1001 Rn Dd 1011 offset
10644 C4-42, C5-28 2 FLDMIAX cond 1100 1011 Rn Dd 1011 offset
10645 C4-42, C5-30 3 FLDMDBX cond 1101 0011 Rn Dd 1011 offset
10646
10647 Regs transferred: Dd .. D(d + (offset-3)/2)
10648 offset must be odd, must not imply a reg > 15
10649 IA/DB: Rn is changed by (4 + 8 x # regs transferred)
10650
10651 case coding:
10652 1 at-Rn (access at Rn)
10653 2 ia-Rn (access at Rn, then Rn += 4+8n)
10654 3 db-Rn (Rn -= 4+8n, then access at Rn)
10655 */
10656 if (BITS8(1,1,0,0,0,0,0,0) == (INSN(27,20) & BITS8(1,1,1,0,0,0,0,0))
10657 && INSN(11,8) == BITS4(1,0,1,1)) {
10658 UInt bP = (insn28 >> 24) & 1;
10659 UInt bU = (insn28 >> 23) & 1;
10660 UInt bW = (insn28 >> 21) & 1;
10661 UInt bL = (insn28 >> 20) & 1;
10662 UInt offset = (insn28 >> 0) & 0xFF;
10663 UInt rN = INSN(19,16);
10664 UInt dD = (INSN(22,22) << 4) | INSN(15,12);
10665 UInt nRegs = (offset - 1) / 2;
10666 UInt summary = 0;
10667 Int i;
10668
10669 /**/ if (bP == 0 && bU == 1 && bW == 0) {
10670 summary = 1;
10671 }
10672 else if (bP == 0 && bU == 1 && bW == 1) {
10673 summary = 2;
10674 }
10675 else if (bP == 1 && bU == 0 && bW == 1) {
10676 summary = 3;
10677 }
10678 else goto after_vfp_fldmx_fstmx;
10679
10680 /* no writebacks to r15 allowed. No use of r15 in thumb mode. */
10681 if (rN == 15 && (summary == 2 || summary == 3 || isT))
10682 goto after_vfp_fldmx_fstmx;
10683
10684 /* offset must be odd, and specify at least one register */
10685 if (0 == (offset & 1) || offset < 3)
10686 goto after_vfp_fldmx_fstmx;
10687
10688 /* can't transfer regs after D15 */
10689 if (dD + nRegs - 1 >= 32)
10690 goto after_vfp_fldmx_fstmx;
10691
10692 /* Now, we can't do a conditional load or store, since that very
10693 likely will generate an exception. So we have to take a side
10694 exit at this point if the condition is false. */
10695 if (condT != IRTemp_INVALID) {
10696 if (isT)
10697 mk_skip_over_T32_if_cond_is_false( condT );
10698 else
10699 mk_skip_over_A32_if_cond_is_false( condT );
10700 condT = IRTemp_INVALID;
10701 }
10702 /* Ok, now we're unconditional. Do the load or store. */
10703
10704 /* get the old Rn value */
10705 IRTemp rnT = newTemp(Ity_I32);
10706 assign(rnT, align4if(isT ? getIRegT(rN) : getIRegA(rN),
10707 rN == 15));
10708
10709 /* make a new value for Rn, post-insn */
10710 IRTemp rnTnew = IRTemp_INVALID;
10711 if (summary == 2 || summary == 3) {
10712 rnTnew = newTemp(Ity_I32);
10713 assign(rnTnew, binop(summary == 2 ? Iop_Add32 : Iop_Sub32,
10714 mkexpr(rnT),
10715 mkU32(4 + 8 * nRegs)));
10716 }
10717
10718 /* decide on the base transfer address */
10719 IRTemp taT = newTemp(Ity_I32);
10720 assign(taT, summary == 3 ? mkexpr(rnTnew) : mkexpr(rnT));
10721
10722 /* update Rn if necessary -- in case 3, we're moving it down, so
10723 update before any memory reference, in order to keep Memcheck
10724 and V's stack-extending logic (on linux) happy */
10725 if (summary == 3) {
10726 if (isT)
10727 putIRegT(rN, mkexpr(rnTnew), IRTemp_INVALID);
10728 else
10729 putIRegA(rN, mkexpr(rnTnew), IRTemp_INVALID, Ijk_Boring);
10730 }
10731
10732 /* generate the transfers */
10733 for (i = 0; i < nRegs; i++) {
10734 IRExpr* addr = binop(Iop_Add32, mkexpr(taT), mkU32(8*i));
10735 if (bL) {
10736 putDReg(dD + i, loadLE(Ity_F64, addr), IRTemp_INVALID);
10737 } else {
10738 storeLE(addr, getDReg(dD + i));
10739 }
10740 }
10741
10742 /* update Rn if necessary -- in case 2, we're moving it up, so
10743 update after any memory reference, in order to keep Memcheck
10744 and V's stack-extending logic (on linux) happy */
10745 if (summary == 2) {
10746 if (isT)
10747 putIRegT(rN, mkexpr(rnTnew), IRTemp_INVALID);
10748 else
10749 putIRegA(rN, mkexpr(rnTnew), IRTemp_INVALID, Ijk_Boring);
10750 }
10751
10752 HChar* nm = bL==1 ? "ld" : "st";
10753 switch (summary) {
10754 case 1: DIP("f%smx%s r%u, {d%u-d%u}\n",
10755 nm, nCC(conq), rN, dD, dD + nRegs - 1);
10756 break;
10757 case 2: DIP("f%smiax%s r%u!, {d%u-d%u}\n",
10758 nm, nCC(conq), rN, dD, dD + nRegs - 1);
10759 break;
10760 case 3: DIP("f%smdbx%s r%u!, {d%u-d%u}\n",
10761 nm, nCC(conq), rN, dD, dD + nRegs - 1);
10762 break;
10763 default: vassert(0);
10764 }
10765
10766 goto decode_success_vfp;
10767 /* FIXME alignment constraints? */
10768 }
10769
10770 after_vfp_fldmx_fstmx:
10771
10772 /* --------------------- fldmd, fstmd --------------------- */
10773 /*
10774 31 27 23 19 15 11 7 0
10775 P U WL
10776 C4-96, C5-26 1 FSTMD cond 1100 1000 Rn Dd 1011 offset
10777 C4-96, C5-28 2 FSTMDIA cond 1100 1010 Rn Dd 1011 offset
10778 C4-96, C5-30 3 FSTMDDB cond 1101 0010 Rn Dd 1011 offset
10779
10780 C4-38, C5-26 1 FLDMD cond 1100 1001 Rn Dd 1011 offset
10781 C4-38, C5-28 2 FLDMIAD cond 1100 1011 Rn Dd 1011 offset
10782 C4-38, C5-30 3 FLDMDBD cond 1101 0011 Rn Dd 1011 offset
10783
10784 Regs transferred: Dd .. D(d + (offset-2)/2)
10785 offset must be even, must not imply a reg > 15
10786 IA/DB: Rn is changed by (8 x # regs transferred)
10787
10788 case coding:
10789 1 at-Rn (access at Rn)
10790 2 ia-Rn (access at Rn, then Rn += 8n)
10791 3 db-Rn (Rn -= 8n, then access at Rn)
10792 */
10793 if (BITS8(1,1,0,0,0,0,0,0) == (INSN(27,20) & BITS8(1,1,1,0,0,0,0,0))
10794 && INSN(11,8) == BITS4(1,0,1,1)) {
10795 UInt bP = (insn28 >> 24) & 1;
10796 UInt bU = (insn28 >> 23) & 1;
10797 UInt bW = (insn28 >> 21) & 1;
10798 UInt bL = (insn28 >> 20) & 1;
10799 UInt offset = (insn28 >> 0) & 0xFF;
10800 UInt rN = INSN(19,16);
10801 UInt dD = (INSN(22,22) << 4) | INSN(15,12);
10802 UInt nRegs = offset / 2;
10803 UInt summary = 0;
10804 Int i;
10805
10806 /**/ if (bP == 0 && bU == 1 && bW == 0) {
10807 summary = 1;
10808 }
10809 else if (bP == 0 && bU == 1 && bW == 1) {
10810 summary = 2;
10811 }
10812 else if (bP == 1 && bU == 0 && bW == 1) {
10813 summary = 3;
10814 }
10815 else goto after_vfp_fldmd_fstmd;
10816
10817 /* no writebacks to r15 allowed. No use of r15 in thumb mode. */
10818 if (rN == 15 && (summary == 2 || summary == 3 || isT))
10819 goto after_vfp_fldmd_fstmd;
10820
10821 /* offset must be even, and specify at least one register */
10822 if (1 == (offset & 1) || offset < 2)
10823 goto after_vfp_fldmd_fstmd;
10824
10825 /* can't transfer regs after D15 */
10826 if (dD + nRegs - 1 >= 32)
10827 goto after_vfp_fldmd_fstmd;
10828
10829 /* Now, we can't do a conditional load or store, since that very
10830 likely will generate an exception. So we have to take a side
10831 exit at this point if the condition is false. */
10832 if (condT != IRTemp_INVALID) {
10833 if (isT)
10834 mk_skip_over_T32_if_cond_is_false( condT );
10835 else
10836 mk_skip_over_A32_if_cond_is_false( condT );
10837 condT = IRTemp_INVALID;
10838 }
10839 /* Ok, now we're unconditional. Do the load or store. */
10840
10841 /* get the old Rn value */
10842 IRTemp rnT = newTemp(Ity_I32);
10843 assign(rnT, align4if(isT ? getIRegT(rN) : getIRegA(rN),
10844 rN == 15));
10845
10846 /* make a new value for Rn, post-insn */
10847 IRTemp rnTnew = IRTemp_INVALID;
10848 if (summary == 2 || summary == 3) {
10849 rnTnew = newTemp(Ity_I32);
10850 assign(rnTnew, binop(summary == 2 ? Iop_Add32 : Iop_Sub32,
10851 mkexpr(rnT),
10852 mkU32(8 * nRegs)));
10853 }
10854
10855 /* decide on the base transfer address */
10856 IRTemp taT = newTemp(Ity_I32);
10857 assign(taT, summary == 3 ? mkexpr(rnTnew) : mkexpr(rnT));
10858
10859 /* update Rn if necessary -- in case 3, we're moving it down, so
10860 update before any memory reference, in order to keep Memcheck
10861 and V's stack-extending logic (on linux) happy */
10862 if (summary == 3) {
10863 if (isT)
10864 putIRegT(rN, mkexpr(rnTnew), IRTemp_INVALID);
10865 else
10866 putIRegA(rN, mkexpr(rnTnew), IRTemp_INVALID, Ijk_Boring);
10867 }
10868
10869 /* generate the transfers */
10870 for (i = 0; i < nRegs; i++) {
10871 IRExpr* addr = binop(Iop_Add32, mkexpr(taT), mkU32(8*i));
10872 if (bL) {
10873 putDReg(dD + i, loadLE(Ity_F64, addr), IRTemp_INVALID);
10874 } else {
10875 storeLE(addr, getDReg(dD + i));
10876 }
10877 }
10878
10879 /* update Rn if necessary -- in case 2, we're moving it up, so
10880 update after any memory reference, in order to keep Memcheck
10881 and V's stack-extending logic (on linux) happy */
10882 if (summary == 2) {
10883 if (isT)
10884 putIRegT(rN, mkexpr(rnTnew), IRTemp_INVALID);
10885 else
10886 putIRegA(rN, mkexpr(rnTnew), IRTemp_INVALID, Ijk_Boring);
10887 }
10888
10889 HChar* nm = bL==1 ? "ld" : "st";
10890 switch (summary) {
10891 case 1: DIP("f%smd%s r%u, {d%u-d%u}\n",
10892 nm, nCC(conq), rN, dD, dD + nRegs - 1);
10893 break;
10894 case 2: DIP("f%smiad%s r%u!, {d%u-d%u}\n",
10895 nm, nCC(conq), rN, dD, dD + nRegs - 1);
10896 break;
10897 case 3: DIP("f%smdbd%s r%u!, {d%u-d%u}\n",
10898 nm, nCC(conq), rN, dD, dD + nRegs - 1);
10899 break;
10900 default: vassert(0);
10901 }
10902
10903 goto decode_success_vfp;
10904 /* FIXME alignment constraints? */
10905 }
10906
10907 after_vfp_fldmd_fstmd:
10908
10909 /* ------------------- fmrx, fmxr ------------------- */
10910 if (BITS8(1,1,1,0,1,1,1,1) == INSN(27,20)
10911 && BITS4(1,0,1,0) == INSN(11,8)
10912 && BITS8(0,0,0,1,0,0,0,0) == (insn28 & 0xFF)) {
10913 UInt rD = INSN(15,12);
10914 UInt reg = INSN(19,16);
10915 if (reg == BITS4(0,0,0,1)) {
10916 if (rD == 15) {
10917 IRTemp nzcvT = newTemp(Ity_I32);
10918 /* When rD is 15, we are copying the top 4 bits of FPSCR
10919 into CPSR. That is, set the flags thunk to COPY and
10920 install FPSCR[31:28] as the value to copy. */
10921 assign(nzcvT, binop(Iop_And32,
10922 IRExpr_Get(OFFB_FPSCR, Ity_I32),
10923 mkU32(0xF0000000)));
10924 setFlags_D1(ARMG_CC_OP_COPY, nzcvT, condT);
10925 DIP("fmstat%s\n", nCC(conq));
10926 } else {
10927 /* Otherwise, merely transfer FPSCR to r0 .. r14. */
10928 IRExpr* e = IRExpr_Get(OFFB_FPSCR, Ity_I32);
10929 if (isT)
10930 putIRegT(rD, e, condT);
10931 else
10932 putIRegA(rD, e, condT, Ijk_Boring);
10933 DIP("fmrx%s r%u, fpscr\n", nCC(conq), rD);
10934 }
10935 goto decode_success_vfp;
10936 }
10937 /* fall through */
10938 }
10939
10940 if (BITS8(1,1,1,0,1,1,1,0) == INSN(27,20)
10941 && BITS4(1,0,1,0) == INSN(11,8)
10942 && BITS8(0,0,0,1,0,0,0,0) == (insn28 & 0xFF)) {
10943 UInt rD = INSN(15,12);
10944 UInt reg = INSN(19,16);
10945 if (reg == BITS4(0,0,0,1)) {
10946 putMiscReg32(OFFB_FPSCR,
10947 isT ? getIRegT(rD) : getIRegA(rD), condT);
10948 DIP("fmxr%s fpscr, r%u\n", nCC(conq), rD);
10949 goto decode_success_vfp;
10950 }
10951 /* fall through */
10952 }
10953
10954 /* --------------------- vmov --------------------- */
10955 // VMOV dM, rD, rN
10956 if (0x0C400B10 == (insn28 & 0x0FF00FD0)) {
10957 UInt dM = INSN(3,0) | (INSN(5,5) << 4);
10958 UInt rD = INSN(15,12); /* lo32 */
10959 UInt rN = INSN(19,16); /* hi32 */
sewardj93ba93f2010-09-22 16:15:50 +000010960 if (rD == 15 || rN == 15 || (isT && (rD == 13 || rN == 13))) {
sewardjd2664472010-08-22 12:44:20 +000010961 /* fall through */
10962 } else {
10963 putDReg(dM,
10964 unop(Iop_ReinterpI64asF64,
10965 binop(Iop_32HLto64,
10966 isT ? getIRegT(rN) : getIRegA(rN),
10967 isT ? getIRegT(rD) : getIRegA(rD))),
10968 condT);
10969 DIP("vmov%s d%u, r%u, r%u\n", nCC(conq), dM, rD, rN);
10970 goto decode_success_vfp;
10971 }
10972 /* fall through */
10973 }
10974
10975 // VMOV rD, rN, dM
10976 if (0x0C500B10 == (insn28 & 0x0FF00FD0)) {
10977 UInt dM = INSN(3,0) | (INSN(5,5) << 4);
10978 UInt rD = INSN(15,12); /* lo32 */
10979 UInt rN = INSN(19,16); /* hi32 */
sewardj93ba93f2010-09-22 16:15:50 +000010980 if (rD == 15 || rN == 15 || (isT && (rD == 13 || rN == 13))
10981 || rD == rN) {
sewardjd2664472010-08-22 12:44:20 +000010982 /* fall through */
10983 } else {
10984 IRTemp i64 = newTemp(Ity_I64);
10985 assign(i64, unop(Iop_ReinterpF64asI64, getDReg(dM)));
10986 IRExpr* hi32 = unop(Iop_64HIto32, mkexpr(i64));
10987 IRExpr* lo32 = unop(Iop_64to32, mkexpr(i64));
10988 if (isT) {
10989 putIRegT(rN, hi32, condT);
10990 putIRegT(rD, lo32, condT);
10991 } else {
10992 putIRegA(rN, hi32, condT, Ijk_Boring);
10993 putIRegA(rD, lo32, condT, Ijk_Boring);
10994 }
10995 DIP("vmov%s r%u, r%u, d%u\n", nCC(conq), rD, rN, dM);
10996 goto decode_success_vfp;
10997 }
10998 /* fall through */
10999 }
11000
sewardj93ba93f2010-09-22 16:15:50 +000011001 // VMOV sD, sD+1, rN, rM
11002 if (0x0C400A10 == (insn28 & 0x0FF00FD0)) {
11003 UInt sD = (INSN(3,0) << 1) | INSN(5,5);
11004 UInt rN = INSN(15,12);
11005 UInt rM = INSN(19,16);
11006 if (rM == 15 || rN == 15 || (isT && (rM == 13 || rN == 13))
11007 || sD == 31) {
11008 /* fall through */
11009 } else {
11010 putFReg(sD,
11011 unop(Iop_ReinterpI32asF32, isT ? getIRegT(rN) : getIRegA(rN)),
11012 condT);
11013 putFReg(sD+1,
11014 unop(Iop_ReinterpI32asF32, isT ? getIRegT(rM) : getIRegA(rM)),
11015 condT);
11016 DIP("vmov%s, s%u, s%u, r%u, r%u\n",
11017 nCC(conq), sD, sD + 1, rN, rM);
11018 goto decode_success_vfp;
11019 }
11020 }
11021
11022 // VMOV rN, rM, sD, sD+1
11023 if (0x0C500A10 == (insn28 & 0x0FF00FD0)) {
11024 UInt sD = (INSN(3,0) << 1) | INSN(5,5);
11025 UInt rN = INSN(15,12);
11026 UInt rM = INSN(19,16);
11027 if (rM == 15 || rN == 15 || (isT && (rM == 13 || rN == 13))
11028 || sD == 31 || rN == rM) {
11029 /* fall through */
11030 } else {
11031 IRExpr* res0 = unop(Iop_ReinterpF32asI32, getFReg(sD));
11032 IRExpr* res1 = unop(Iop_ReinterpF32asI32, getFReg(sD+1));
11033 if (isT) {
11034 putIRegT(rN, res0, condT);
11035 putIRegT(rM, res1, condT);
11036 } else {
11037 putIRegA(rN, res0, condT, Ijk_Boring);
11038 putIRegA(rM, res1, condT, Ijk_Boring);
11039 }
11040 DIP("vmov%s, r%u, r%u, s%u, s%u\n",
11041 nCC(conq), rN, rM, sD, sD + 1);
11042 goto decode_success_vfp;
11043 }
11044 }
11045
11046 // VMOV rD[x], rT (ARM core register to scalar)
sewardjd2664472010-08-22 12:44:20 +000011047 if (0x0E000B10 == (insn28 & 0x0F900F1F)) {
11048 UInt rD = (INSN(7,7) << 4) | INSN(19,16);
11049 UInt rT = INSN(15,12);
11050 UInt opc = (INSN(22,21) << 2) | INSN(6,5);
11051 UInt index;
sewardj93ba93f2010-09-22 16:15:50 +000011052 if (rT == 15 || (isT && rT == 13)) {
sewardjd2664472010-08-22 12:44:20 +000011053 /* fall through */
11054 } else {
11055 if ((opc & BITS4(1,0,0,0)) == BITS4(1,0,0,0)) {
11056 index = opc & 7;
11057 putDRegI64(rD, triop(Iop_SetElem8x8,
11058 getDRegI64(rD),
11059 mkU8(index),
11060 unop(Iop_32to8,
11061 isT ? getIRegT(rT) : getIRegA(rT))),
11062 condT);
11063 DIP("vmov%s.8 d%u[%u], r%u\n", nCC(conq), rD, index, rT);
11064 goto decode_success_vfp;
11065 }
11066 else if ((opc & BITS4(1,0,0,1)) == BITS4(0,0,0,1)) {
11067 index = (opc >> 1) & 3;
11068 putDRegI64(rD, triop(Iop_SetElem16x4,
11069 getDRegI64(rD),
11070 mkU8(index),
11071 unop(Iop_32to16,
11072 isT ? getIRegT(rT) : getIRegA(rT))),
11073 condT);
11074 DIP("vmov%s.16 d%u[%u], r%u\n", nCC(conq), rD, index, rT);
11075 goto decode_success_vfp;
11076 }
11077 else if ((opc & BITS4(1,0,1,1)) == BITS4(0,0,0,0)) {
11078 index = (opc >> 2) & 1;
11079 putDRegI64(rD, triop(Iop_SetElem32x2,
11080 getDRegI64(rD),
11081 mkU8(index),
11082 isT ? getIRegT(rT) : getIRegA(rT)),
11083 condT);
11084 DIP("vmov%s.32 d%u[%u], r%u\n", nCC(conq), rD, index, rT);
11085 goto decode_success_vfp;
11086 } else {
11087 /* fall through */
11088 }
11089 }
11090 }
11091
sewardj93ba93f2010-09-22 16:15:50 +000011092 // VMOV (scalar to ARM core register)
sewardjd2664472010-08-22 12:44:20 +000011093 // VMOV rT, rD[x]
11094 if (0x0E100B10 == (insn28 & 0x0F100F1F)) {
11095 UInt rN = (INSN(7,7) << 4) | INSN(19,16);
11096 UInt rT = INSN(15,12);
11097 UInt U = INSN(23,23);
11098 UInt opc = (INSN(22,21) << 2) | INSN(6,5);
11099 UInt index;
sewardj93ba93f2010-09-22 16:15:50 +000011100 if (rT == 15 || (isT && rT == 13)) {
sewardjd2664472010-08-22 12:44:20 +000011101 /* fall through */
11102 } else {
11103 if ((opc & BITS4(1,0,0,0)) == BITS4(1,0,0,0)) {
11104 index = opc & 7;
11105 IRExpr* e = unop(U ? Iop_8Uto32 : Iop_8Sto32,
11106 binop(Iop_GetElem8x8,
11107 getDRegI64(rN),
11108 mkU8(index)));
11109 if (isT)
11110 putIRegT(rT, e, condT);
11111 else
11112 putIRegA(rT, e, condT, Ijk_Boring);
11113 DIP("vmov%s.%c8 r%u, d%u[%u]\n", nCC(conq), U ? 'u' : 's',
11114 rT, rN, index);
11115 goto decode_success_vfp;
11116 }
11117 else if ((opc & BITS4(1,0,0,1)) == BITS4(0,0,0,1)) {
11118 index = (opc >> 1) & 3;
11119 IRExpr* e = unop(U ? Iop_16Uto32 : Iop_16Sto32,
11120 binop(Iop_GetElem16x4,
11121 getDRegI64(rN),
11122 mkU8(index)));
11123 if (isT)
11124 putIRegT(rT, e, condT);
11125 else
11126 putIRegA(rT, e, condT, Ijk_Boring);
11127 DIP("vmov%s.%c16 r%u, d%u[%u]\n", nCC(conq), U ? 'u' : 's',
11128 rT, rN, index);
11129 goto decode_success_vfp;
11130 }
11131 else if ((opc & BITS4(1,0,1,1)) == BITS4(0,0,0,0) && U == 0) {
11132 index = (opc >> 2) & 1;
11133 IRExpr* e = binop(Iop_GetElem32x2, getDRegI64(rN), mkU8(index));
11134 if (isT)
11135 putIRegT(rT, e, condT);
11136 else
11137 putIRegA(rT, e, condT, Ijk_Boring);
11138 DIP("vmov%s.32 r%u, d%u[%u]\n", nCC(conq), rT, rN, index);
11139 goto decode_success_vfp;
11140 } else {
11141 /* fall through */
11142 }
11143 }
11144 }
11145
11146 // VMOV.F32 sD, #imm
11147 // FCONSTS sD, #imm
11148 if (BITS8(1,1,1,0,1,0,1,1) == (INSN(27,20) & BITS8(1,1,1,1,1,0,1,1))
11149 && BITS4(0,0,0,0) == INSN(7,4) && INSN(11,8) == BITS4(1,0,1,0)) {
11150 UInt rD = (INSN(15,12) << 1) | INSN(22,22);
11151 UInt imm8 = (INSN(19,16) << 4) | INSN(3,0);
11152 UInt b = (imm8 >> 6) & 1;
11153 UInt imm;
11154 imm = (BITS8((imm8 >> 7) & 1,(~b) & 1,b,b,b,b,b,(imm8 >> 5) & 1) << 8)
11155 | ((imm8 & 0x1f) << 3);
11156 imm <<= 16;
11157 putFReg(rD, unop(Iop_ReinterpI32asF32, mkU32(imm)), condT);
11158 DIP("fconsts%s s%u #%u", nCC(conq), rD, imm8);
11159 goto decode_success_vfp;
11160 }
11161
11162 // VMOV.F64 dD, #imm
11163 // FCONSTD dD, #imm
11164 if (BITS8(1,1,1,0,1,0,1,1) == (INSN(27,20) & BITS8(1,1,1,1,1,0,1,1))
11165 && BITS4(0,0,0,0) == INSN(7,4) && INSN(11,8) == BITS4(1,0,1,1)) {
11166 UInt rD = INSN(15,12) | (INSN(22,22) << 4);
11167 UInt imm8 = (INSN(19,16) << 4) | INSN(3,0);
11168 UInt b = (imm8 >> 6) & 1;
11169 ULong imm;
11170 imm = (BITS8((imm8 >> 7) & 1,(~b) & 1,b,b,b,b,b,b) << 8)
11171 | BITS8(b,b,0,0,0,0,0,0) | (imm8 & 0x3f);
11172 imm <<= 48;
11173 putDReg(rD, unop(Iop_ReinterpI64asF64, mkU64(imm)), condT);
11174 DIP("fconstd%s d%u #%u", nCC(conq), rD, imm8);
11175 goto decode_success_vfp;
11176 }
11177
11178 /* ---------------------- vdup ------------------------- */
11179 // VDUP dD, rT
11180 // VDUP qD, rT
11181 if (BITS8(1,1,1,0,1,0,0,0) == (INSN(27,20) & BITS8(1,1,1,1,1,0,0,1))
11182 && BITS4(1,0,1,1) == INSN(11,8) && INSN(6,6) == 0 && INSN(4,4) == 1) {
11183 UInt rD = (INSN(7,7) << 4) | INSN(19,16);
11184 UInt rT = INSN(15,12);
11185 UInt Q = INSN(21,21);
11186 UInt size = (INSN(22,22) << 1) | INSN(5,5);
sewardj4d475472011-02-02 13:35:01 +000011187 if (rT == 15 || (isT && rT == 13) || size == 3 || (Q && (rD & 1))) {
sewardjd2664472010-08-22 12:44:20 +000011188 /* fall through */
11189 } else {
11190 IRExpr* e = isT ? getIRegT(rT) : getIRegA(rT);
11191 if (Q) {
11192 rD >>= 1;
11193 switch (size) {
11194 case 0:
11195 putQReg(rD, unop(Iop_Dup32x4, e), condT);
11196 break;
11197 case 1:
11198 putQReg(rD, unop(Iop_Dup16x8, unop(Iop_32to16, e)),
11199 condT);
11200 break;
11201 case 2:
11202 putQReg(rD, unop(Iop_Dup8x16, unop(Iop_32to8, e)),
11203 condT);
11204 break;
11205 default:
11206 vassert(0);
11207 }
11208 DIP("vdup.%u q%u, r%u\n", 32 / (1<<size), rD, rT);
11209 } else {
11210 switch (size) {
11211 case 0:
11212 putDRegI64(rD, unop(Iop_Dup32x2, e), condT);
11213 break;
11214 case 1:
11215 putDRegI64(rD, unop(Iop_Dup16x4, unop(Iop_32to16, e)),
11216 condT);
11217 break;
11218 case 2:
11219 putDRegI64(rD, unop(Iop_Dup8x8, unop(Iop_32to8, e)),
11220 condT);
11221 break;
11222 default:
11223 vassert(0);
11224 }
11225 DIP("vdup.%u d%u, r%u\n", 32 / (1<<size), rD, rT);
11226 }
11227 goto decode_success_vfp;
11228 }
11229 }
11230
11231 /* --------------------- f{ld,st}d --------------------- */
11232 // FLDD, FSTD
sewardj93ba93f2010-09-22 16:15:50 +000011233 if (BITS8(1,1,0,1,0,0,0,0) == (INSN(27,20) & BITS8(1,1,1,1,0,0,1,0))
sewardjd2664472010-08-22 12:44:20 +000011234 && BITS4(1,0,1,1) == INSN(11,8)) {
sewardj93ba93f2010-09-22 16:15:50 +000011235 UInt dD = INSN(15,12) | (INSN(22,22) << 4);
sewardjd2664472010-08-22 12:44:20 +000011236 UInt rN = INSN(19,16);
11237 UInt offset = (insn28 & 0xFF) << 2;
11238 UInt bU = (insn28 >> 23) & 1; /* 1: +offset 0: -offset */
11239 UInt bL = (insn28 >> 20) & 1; /* 1: load 0: store */
11240 /* make unconditional */
11241 if (condT != IRTemp_INVALID) {
11242 if (isT)
11243 mk_skip_over_T32_if_cond_is_false( condT );
11244 else
11245 mk_skip_over_A32_if_cond_is_false( condT );
11246 condT = IRTemp_INVALID;
11247 }
11248 IRTemp ea = newTemp(Ity_I32);
11249 assign(ea, binop(bU ? Iop_Add32 : Iop_Sub32,
11250 align4if(isT ? getIRegT(rN) : getIRegA(rN),
11251 rN == 15),
11252 mkU32(offset)));
11253 if (bL) {
11254 putDReg(dD, loadLE(Ity_F64,mkexpr(ea)), IRTemp_INVALID);
11255 } else {
11256 storeLE(mkexpr(ea), getDReg(dD));
11257 }
11258 DIP("f%sd%s d%u, [r%u, %c#%u]\n",
11259 bL ? "ld" : "st", nCC(conq), dD, rN,
11260 bU ? '+' : '-', offset);
11261 goto decode_success_vfp;
11262 }
11263
11264 /* --------------------- dp insns (D) --------------------- */
sewardj93ba93f2010-09-22 16:15:50 +000011265 if (BITS8(1,1,1,0,0,0,0,0) == (INSN(27,20) & BITS8(1,1,1,1,0,0,0,0))
sewardjd2664472010-08-22 12:44:20 +000011266 && BITS4(1,0,1,1) == INSN(11,8)
sewardj93ba93f2010-09-22 16:15:50 +000011267 && BITS4(0,0,0,0) == (INSN(7,4) & BITS4(0,0,0,1))) {
11268 UInt dM = INSN(3,0) | (INSN(5,5) << 4); /* argR */
11269 UInt dD = INSN(15,12) | (INSN(22,22) << 4); /* dst/acc */
11270 UInt dN = INSN(19,16) | (INSN(7,7) << 4); /* argL */
sewardjd2664472010-08-22 12:44:20 +000011271 UInt bP = (insn28 >> 23) & 1;
11272 UInt bQ = (insn28 >> 21) & 1;
11273 UInt bR = (insn28 >> 20) & 1;
11274 UInt bS = (insn28 >> 6) & 1;
11275 UInt opc = (bP << 3) | (bQ << 2) | (bR << 1) | bS;
11276 IRExpr* rm = get_FAKE_roundingmode(); /* XXXROUNDINGFIXME */
11277 switch (opc) {
11278 case BITS4(0,0,0,0): /* MAC: d + n * m */
11279 putDReg(dD, triop(Iop_AddF64, rm,
11280 getDReg(dD),
11281 triop(Iop_MulF64, rm, getDReg(dN),
11282 getDReg(dM))),
11283 condT);
11284 DIP("fmacd%s d%u, d%u, d%u\n", nCC(conq), dD, dN, dM);
11285 goto decode_success_vfp;
sewardj93ba93f2010-09-22 16:15:50 +000011286 case BITS4(0,0,0,1): /* NMAC: d + -(n * m) */
11287 putDReg(dD, triop(Iop_AddF64, rm,
sewardjd2664472010-08-22 12:44:20 +000011288 getDReg(dD),
sewardj93ba93f2010-09-22 16:15:50 +000011289 unop(Iop_NegF64,
11290 triop(Iop_MulF64, rm, getDReg(dN),
11291 getDReg(dM)))),
sewardjd2664472010-08-22 12:44:20 +000011292 condT);
11293 DIP("fnmacd%s d%u, d%u, d%u\n", nCC(conq), dD, dN, dM);
11294 goto decode_success_vfp;
11295 case BITS4(0,0,1,0): /* MSC: - d + n * m */
11296 putDReg(dD, triop(Iop_AddF64, rm,
11297 unop(Iop_NegF64, getDReg(dD)),
11298 triop(Iop_MulF64, rm, getDReg(dN),
11299 getDReg(dM))),
11300 condT);
11301 DIP("fmscd%s d%u, d%u, d%u\n", nCC(conq), dD, dN, dM);
11302 goto decode_success_vfp;
sewardj93ba93f2010-09-22 16:15:50 +000011303 case BITS4(0,0,1,1): /* NMSC: - d + -(n * m) */
11304 putDReg(dD, triop(Iop_AddF64, rm,
sewardjd2664472010-08-22 12:44:20 +000011305 unop(Iop_NegF64, getDReg(dD)),
sewardj93ba93f2010-09-22 16:15:50 +000011306 unop(Iop_NegF64,
11307 triop(Iop_MulF64, rm, getDReg(dN),
11308 getDReg(dM)))),
sewardjd2664472010-08-22 12:44:20 +000011309 condT);
11310 DIP("fnmscd%s d%u, d%u, d%u\n", nCC(conq), dD, dN, dM);
11311 goto decode_success_vfp;
11312 case BITS4(0,1,0,0): /* MUL: n * m */
11313 putDReg(dD, triop(Iop_MulF64, rm, getDReg(dN), getDReg(dM)),
11314 condT);
11315 DIP("fmuld%s d%u, d%u, d%u\n", nCC(conq), dD, dN, dM);
11316 goto decode_success_vfp;
11317 case BITS4(0,1,0,1): /* NMUL: - n * m */
11318 putDReg(dD, unop(Iop_NegF64,
11319 triop(Iop_MulF64, rm, getDReg(dN),
11320 getDReg(dM))),
11321 condT);
11322 DIP("fnmuld%s d%u, d%u, d%u\n", nCC(conq), dD, dN, dM);
11323 goto decode_success_vfp;
11324 case BITS4(0,1,1,0): /* ADD: n + m */
11325 putDReg(dD, triop(Iop_AddF64, rm, getDReg(dN), getDReg(dM)),
11326 condT);
11327 DIP("faddd%s d%u, d%u, d%u\n", nCC(conq), dD, dN, dM);
11328 goto decode_success_vfp;
11329 case BITS4(0,1,1,1): /* SUB: n - m */
11330 putDReg(dD, triop(Iop_SubF64, rm, getDReg(dN), getDReg(dM)),
11331 condT);
11332 DIP("fsubd%s d%u, d%u, d%u\n", nCC(conq), dD, dN, dM);
11333 goto decode_success_vfp;
11334 case BITS4(1,0,0,0): /* DIV: n / m */
11335 putDReg(dD, triop(Iop_DivF64, rm, getDReg(dN), getDReg(dM)),
11336 condT);
11337 DIP("fdivd%s d%u, d%u, d%u\n", nCC(conq), dD, dN, dM);
11338 goto decode_success_vfp;
11339 default:
11340 break;
11341 }
11342 }
11343
11344 /* --------------------- compares (D) --------------------- */
11345 /* 31 27 23 19 15 11 7 3
11346 28 24 20 16 12 8 4 0
sewardj93ba93f2010-09-22 16:15:50 +000011347 FCMPD cond 1110 1D11 0100 Dd 1011 0100 Dm
11348 FCMPED cond 1110 1D11 0100 Dd 1011 1100 Dm
11349 FCMPZD cond 1110 1D11 0101 Dd 1011 0100 0000
11350 FCMPZED cond 1110 1D11 0101 Dd 1011 1100 0000
sewardjd2664472010-08-22 12:44:20 +000011351 Z N
11352
11353 Z=0 Compare Dd vs Dm and set FPSCR 31:28 accordingly
11354 Z=1 Compare Dd vs zero
11355
11356 N=1 generates Invalid Operation exn if either arg is any kind of NaN
11357 N=0 generates Invalid Operation exn if either arg is a signalling NaN
11358 (Not that we pay any attention to N here)
11359 */
sewardj93ba93f2010-09-22 16:15:50 +000011360 if (BITS8(1,1,1,0,1,0,1,1) == (INSN(27,20) & BITS8(1,1,1,1,1,0,1,1))
sewardjd2664472010-08-22 12:44:20 +000011361 && BITS4(0,1,0,0) == (INSN(19,16) & BITS4(1,1,1,0))
11362 && BITS4(1,0,1,1) == INSN(11,8)
sewardj93ba93f2010-09-22 16:15:50 +000011363 && BITS4(0,1,0,0) == (INSN(7,4) & BITS4(0,1,0,1))) {
sewardjd2664472010-08-22 12:44:20 +000011364 UInt bZ = (insn28 >> 16) & 1;
11365 UInt bN = (insn28 >> 7) & 1;
sewardj93ba93f2010-09-22 16:15:50 +000011366 UInt dD = INSN(15,12) | (INSN(22,22) << 4);
11367 UInt dM = INSN(3,0) | (INSN(5,5) << 4);
sewardjd2664472010-08-22 12:44:20 +000011368 if (bZ && INSN(3,0) != 0) {
11369 /* does not decode; fall through */
11370 } else {
11371 IRTemp argL = newTemp(Ity_F64);
11372 IRTemp argR = newTemp(Ity_F64);
11373 IRTemp irRes = newTemp(Ity_I32);
11374 assign(argL, getDReg(dD));
11375 assign(argR, bZ ? IRExpr_Const(IRConst_F64i(0)) : getDReg(dM));
11376 assign(irRes, binop(Iop_CmpF64, mkexpr(argL), mkexpr(argR)));
11377
11378 IRTemp nzcv = IRTemp_INVALID;
11379 IRTemp oldFPSCR = newTemp(Ity_I32);
11380 IRTemp newFPSCR = newTemp(Ity_I32);
11381
11382 /* This is where the fun starts. We have to convert 'irRes'
11383 from an IR-convention return result (IRCmpF64Result) to an
11384 ARM-encoded (N,Z,C,V) group. The final result is in the
11385 bottom 4 bits of 'nzcv'. */
11386 /* Map compare result from IR to ARM(nzcv) */
11387 /*
11388 FP cmp result | IR | ARM(nzcv)
11389 --------------------------------
11390 UN 0x45 0011
11391 LT 0x01 1000
11392 GT 0x00 0010
11393 EQ 0x40 0110
11394 */
11395 nzcv = mk_convert_IRCmpF64Result_to_NZCV(irRes);
11396
11397 /* And update FPSCR accordingly */
11398 assign(oldFPSCR, IRExpr_Get(OFFB_FPSCR, Ity_I32));
11399 assign(newFPSCR,
11400 binop(Iop_Or32,
11401 binop(Iop_And32, mkexpr(oldFPSCR), mkU32(0x0FFFFFFF)),
11402 binop(Iop_Shl32, mkexpr(nzcv), mkU8(28))));
11403
11404 putMiscReg32(OFFB_FPSCR, mkexpr(newFPSCR), condT);
11405
11406 if (bZ) {
11407 DIP("fcmpz%sd%s d%u\n", bN ? "e" : "", nCC(conq), dD);
11408 } else {
11409 DIP("fcmp%sd%s d%u, d%u\n", bN ? "e" : "", nCC(conq), dD, dM);
11410 }
11411 goto decode_success_vfp;
11412 }
11413 /* fall through */
11414 }
11415
11416 /* --------------------- unary (D) --------------------- */
sewardj93ba93f2010-09-22 16:15:50 +000011417 if (BITS8(1,1,1,0,1,0,1,1) == (INSN(27,20) & BITS8(1,1,1,1,1,0,1,1))
sewardjd2664472010-08-22 12:44:20 +000011418 && BITS4(0,0,0,0) == (INSN(19,16) & BITS4(1,1,1,0))
11419 && BITS4(1,0,1,1) == INSN(11,8)
sewardj93ba93f2010-09-22 16:15:50 +000011420 && BITS4(0,1,0,0) == (INSN(7,4) & BITS4(0,1,0,1))) {
11421 UInt dD = INSN(15,12) | (INSN(22,22) << 4);
11422 UInt dM = INSN(3,0) | (INSN(5,5) << 4);
sewardjd2664472010-08-22 12:44:20 +000011423 UInt b16 = (insn28 >> 16) & 1;
11424 UInt b7 = (insn28 >> 7) & 1;
11425 /**/ if (b16 == 0 && b7 == 0) {
11426 // FCPYD
11427 putDReg(dD, getDReg(dM), condT);
11428 DIP("fcpyd%s d%u, d%u\n", nCC(conq), dD, dM);
11429 goto decode_success_vfp;
11430 }
11431 else if (b16 == 0 && b7 == 1) {
11432 // FABSD
11433 putDReg(dD, unop(Iop_AbsF64, getDReg(dM)), condT);
11434 DIP("fabsd%s d%u, d%u\n", nCC(conq), dD, dM);
11435 goto decode_success_vfp;
11436 }
11437 else if (b16 == 1 && b7 == 0) {
11438 // FNEGD
11439 putDReg(dD, unop(Iop_NegF64, getDReg(dM)), condT);
11440 DIP("fnegd%s d%u, d%u\n", nCC(conq), dD, dM);
11441 goto decode_success_vfp;
11442 }
11443 else if (b16 == 1 && b7 == 1) {
11444 // FSQRTD
11445 IRExpr* rm = get_FAKE_roundingmode(); /* XXXROUNDINGFIXME */
11446 putDReg(dD, binop(Iop_SqrtF64, rm, getDReg(dM)), condT);
11447 DIP("fsqrtd%s d%u, d%u\n", nCC(conq), dD, dM);
11448 goto decode_success_vfp;
11449 }
11450 else
11451 vassert(0);
11452
11453 /* fall through */
11454 }
11455
11456 /* ----------------- I <-> D conversions ----------------- */
11457
11458 // F{S,U}ITOD dD, fM
sewardj93ba93f2010-09-22 16:15:50 +000011459 if (BITS8(1,1,1,0,1,0,1,1) == (INSN(27,20) & BITS8(1,1,1,1,1,0,1,1))
sewardjd2664472010-08-22 12:44:20 +000011460 && BITS4(1,0,0,0) == (INSN(19,16) & BITS4(1,1,1,1))
11461 && BITS4(1,0,1,1) == INSN(11,8)
11462 && BITS4(0,1,0,0) == (INSN(7,4) & BITS4(0,1,0,1))) {
11463 UInt bM = (insn28 >> 5) & 1;
11464 UInt fM = (INSN(3,0) << 1) | bM;
sewardj93ba93f2010-09-22 16:15:50 +000011465 UInt dD = INSN(15,12) | (INSN(22,22) << 4);
sewardjd2664472010-08-22 12:44:20 +000011466 UInt syned = (insn28 >> 7) & 1;
11467 if (syned) {
11468 // FSITOD
11469 putDReg(dD, unop(Iop_I32StoF64,
11470 unop(Iop_ReinterpF32asI32, getFReg(fM))),
11471 condT);
11472 DIP("fsitod%s d%u, s%u\n", nCC(conq), dD, fM);
11473 } else {
11474 // FUITOD
11475 putDReg(dD, unop(Iop_I32UtoF64,
11476 unop(Iop_ReinterpF32asI32, getFReg(fM))),
11477 condT);
11478 DIP("fuitod%s d%u, s%u\n", nCC(conq), dD, fM);
11479 }
11480 goto decode_success_vfp;
11481 }
11482
11483 // FTO{S,U}ID fD, dM
11484 if (BITS8(1,1,1,0,1,0,1,1) == (INSN(27,20) & BITS8(1,1,1,1,1,0,1,1))
11485 && BITS4(1,1,0,0) == (INSN(19,16) & BITS4(1,1,1,0))
11486 && BITS4(1,0,1,1) == INSN(11,8)
sewardj93ba93f2010-09-22 16:15:50 +000011487 && BITS4(0,1,0,0) == (INSN(7,4) & BITS4(0,1,0,1))) {
sewardjd2664472010-08-22 12:44:20 +000011488 UInt bD = (insn28 >> 22) & 1;
11489 UInt fD = (INSN(15,12) << 1) | bD;
sewardj93ba93f2010-09-22 16:15:50 +000011490 UInt dM = INSN(3,0) | (INSN(5,5) << 4);
sewardjd2664472010-08-22 12:44:20 +000011491 UInt bZ = (insn28 >> 7) & 1;
11492 UInt syned = (insn28 >> 16) & 1;
11493 IRTemp rmode = newTemp(Ity_I32);
11494 assign(rmode, bZ ? mkU32(Irrm_ZERO)
11495 : mkexpr(mk_get_IR_rounding_mode()));
11496 if (syned) {
11497 // FTOSID
11498 putFReg(fD, unop(Iop_ReinterpI32asF32,
11499 binop(Iop_F64toI32S, mkexpr(rmode),
11500 getDReg(dM))),
11501 condT);
11502 DIP("ftosi%sd%s s%u, d%u\n", bZ ? "z" : "",
11503 nCC(conq), fD, dM);
11504 } else {
11505 // FTOUID
11506 putFReg(fD, unop(Iop_ReinterpI32asF32,
11507 binop(Iop_F64toI32U, mkexpr(rmode),
11508 getDReg(dM))),
11509 condT);
11510 DIP("ftoui%sd%s s%u, d%u\n", bZ ? "z" : "",
11511 nCC(conq), fD, dM);
11512 }
11513 goto decode_success_vfp;
11514 }
11515
11516 /* ----------------------------------------------------------- */
11517 /* -- VFP instructions -- single precision -- */
11518 /* ----------------------------------------------------------- */
11519
11520 /* --------------------- fldms, fstms --------------------- */
11521 /*
11522 31 27 23 19 15 11 7 0
11523 P UDWL
11524 C4-98, C5-26 1 FSTMD cond 1100 1x00 Rn Fd 1010 offset
11525 C4-98, C5-28 2 FSTMDIA cond 1100 1x10 Rn Fd 1010 offset
11526 C4-98, C5-30 3 FSTMDDB cond 1101 0x10 Rn Fd 1010 offset
11527
11528 C4-40, C5-26 1 FLDMD cond 1100 1x01 Rn Fd 1010 offset
11529 C4-40, C5-26 2 FLDMIAD cond 1100 1x11 Rn Fd 1010 offset
11530 C4-40, C5-26 3 FLDMDBD cond 1101 0x11 Rn Fd 1010 offset
11531
11532 Regs transferred: F(Fd:D) .. F(Fd:d + offset)
11533 offset must not imply a reg > 15
11534 IA/DB: Rn is changed by (4 x # regs transferred)
11535
11536 case coding:
11537 1 at-Rn (access at Rn)
11538 2 ia-Rn (access at Rn, then Rn += 4n)
11539 3 db-Rn (Rn -= 4n, then access at Rn)
11540 */
11541 if (BITS8(1,1,0,0,0,0,0,0) == (INSN(27,20) & BITS8(1,1,1,0,0,0,0,0))
11542 && INSN(11,8) == BITS4(1,0,1,0)) {
11543 UInt bP = (insn28 >> 24) & 1;
11544 UInt bU = (insn28 >> 23) & 1;
11545 UInt bW = (insn28 >> 21) & 1;
11546 UInt bL = (insn28 >> 20) & 1;
11547 UInt bD = (insn28 >> 22) & 1;
11548 UInt offset = (insn28 >> 0) & 0xFF;
11549 UInt rN = INSN(19,16);
11550 UInt fD = (INSN(15,12) << 1) | bD;
11551 UInt nRegs = offset;
11552 UInt summary = 0;
11553 Int i;
11554
11555 /**/ if (bP == 0 && bU == 1 && bW == 0) {
11556 summary = 1;
11557 }
11558 else if (bP == 0 && bU == 1 && bW == 1) {
11559 summary = 2;
11560 }
11561 else if (bP == 1 && bU == 0 && bW == 1) {
11562 summary = 3;
11563 }
11564 else goto after_vfp_fldms_fstms;
11565
11566 /* no writebacks to r15 allowed. No use of r15 in thumb mode. */
11567 if (rN == 15 && (summary == 2 || summary == 3 || isT))
11568 goto after_vfp_fldms_fstms;
11569
11570 /* offset must specify at least one register */
11571 if (offset < 1)
11572 goto after_vfp_fldms_fstms;
11573
11574 /* can't transfer regs after S31 */
11575 if (fD + nRegs - 1 >= 32)
11576 goto after_vfp_fldms_fstms;
11577
11578 /* Now, we can't do a conditional load or store, since that very
11579 likely will generate an exception. So we have to take a side
11580 exit at this point if the condition is false. */
11581 if (condT != IRTemp_INVALID) {
11582 if (isT)
11583 mk_skip_over_T32_if_cond_is_false( condT );
11584 else
11585 mk_skip_over_A32_if_cond_is_false( condT );
11586 condT = IRTemp_INVALID;
11587 }
11588 /* Ok, now we're unconditional. Do the load or store. */
11589
11590 /* get the old Rn value */
11591 IRTemp rnT = newTemp(Ity_I32);
11592 assign(rnT, align4if(isT ? getIRegT(rN) : getIRegA(rN),
11593 rN == 15));
11594
11595 /* make a new value for Rn, post-insn */
11596 IRTemp rnTnew = IRTemp_INVALID;
11597 if (summary == 2 || summary == 3) {
11598 rnTnew = newTemp(Ity_I32);
11599 assign(rnTnew, binop(summary == 2 ? Iop_Add32 : Iop_Sub32,
11600 mkexpr(rnT),
11601 mkU32(4 * nRegs)));
11602 }
11603
11604 /* decide on the base transfer address */
11605 IRTemp taT = newTemp(Ity_I32);
11606 assign(taT, summary == 3 ? mkexpr(rnTnew) : mkexpr(rnT));
11607
11608 /* update Rn if necessary -- in case 3, we're moving it down, so
11609 update before any memory reference, in order to keep Memcheck
11610 and V's stack-extending logic (on linux) happy */
11611 if (summary == 3) {
11612 if (isT)
11613 putIRegT(rN, mkexpr(rnTnew), IRTemp_INVALID);
11614 else
11615 putIRegA(rN, mkexpr(rnTnew), IRTemp_INVALID, Ijk_Boring);
11616 }
11617
11618 /* generate the transfers */
11619 for (i = 0; i < nRegs; i++) {
11620 IRExpr* addr = binop(Iop_Add32, mkexpr(taT), mkU32(4*i));
11621 if (bL) {
11622 putFReg(fD + i, loadLE(Ity_F32, addr), IRTemp_INVALID);
11623 } else {
11624 storeLE(addr, getFReg(fD + i));
11625 }
11626 }
11627
11628 /* update Rn if necessary -- in case 2, we're moving it up, so
11629 update after any memory reference, in order to keep Memcheck
11630 and V's stack-extending logic (on linux) happy */
11631 if (summary == 2) {
11632 if (isT)
11633 putIRegT(rN, mkexpr(rnTnew), IRTemp_INVALID);
11634 else
11635 putIRegA(rN, mkexpr(rnTnew), IRTemp_INVALID, Ijk_Boring);
11636 }
11637
11638 HChar* nm = bL==1 ? "ld" : "st";
11639 switch (summary) {
11640 case 1: DIP("f%sms%s r%u, {s%u-s%u}\n",
11641 nm, nCC(conq), rN, fD, fD + nRegs - 1);
11642 break;
11643 case 2: DIP("f%smias%s r%u!, {s%u-s%u}\n",
11644 nm, nCC(conq), rN, fD, fD + nRegs - 1);
11645 break;
11646 case 3: DIP("f%smdbs%s r%u!, {s%u-s%u}\n",
11647 nm, nCC(conq), rN, fD, fD + nRegs - 1);
11648 break;
11649 default: vassert(0);
11650 }
11651
11652 goto decode_success_vfp;
11653 /* FIXME alignment constraints? */
11654 }
11655
11656 after_vfp_fldms_fstms:
11657
11658 /* --------------------- fmsr, fmrs --------------------- */
11659 if (BITS8(1,1,1,0,0,0,0,0) == (INSN(27,20) & BITS8(1,1,1,1,1,1,1,0))
11660 && BITS4(1,0,1,0) == INSN(11,8)
11661 && BITS4(0,0,0,0) == INSN(3,0)
11662 && BITS4(0,0,0,1) == (INSN(7,4) & BITS4(0,1,1,1))) {
11663 UInt rD = INSN(15,12);
11664 UInt b7 = (insn28 >> 7) & 1;
11665 UInt fN = (INSN(19,16) << 1) | b7;
11666 UInt b20 = (insn28 >> 20) & 1;
11667 if (rD == 15) {
11668 /* fall through */
11669 /* Let's assume that no sane person would want to do
11670 floating-point transfers to or from the program counter,
11671 and simply decline to decode the instruction. The ARM ARM
11672 doesn't seem to explicitly disallow this case, though. */
11673 } else {
11674 if (b20) {
11675 IRExpr* res = unop(Iop_ReinterpF32asI32, getFReg(fN));
11676 if (isT)
11677 putIRegT(rD, res, condT);
11678 else
11679 putIRegA(rD, res, condT, Ijk_Boring);
11680 DIP("fmrs%s r%u, s%u\n", nCC(conq), rD, fN);
11681 } else {
11682 putFReg(fN, unop(Iop_ReinterpI32asF32,
11683 isT ? getIRegT(rD) : getIRegA(rD)),
11684 condT);
11685 DIP("fmsr%s s%u, r%u\n", nCC(conq), fN, rD);
11686 }
11687 goto decode_success_vfp;
11688 }
11689 /* fall through */
11690 }
11691
11692 /* --------------------- f{ld,st}s --------------------- */
11693 // FLDS, FSTS
11694 if (BITS8(1,1,0,1,0,0,0,0) == (INSN(27,20) & BITS8(1,1,1,1,0,0,1,0))
11695 && BITS4(1,0,1,0) == INSN(11,8)) {
11696 UInt bD = (insn28 >> 22) & 1;
11697 UInt fD = (INSN(15,12) << 1) | bD;
11698 UInt rN = INSN(19,16);
11699 UInt offset = (insn28 & 0xFF) << 2;
11700 UInt bU = (insn28 >> 23) & 1; /* 1: +offset 0: -offset */
11701 UInt bL = (insn28 >> 20) & 1; /* 1: load 0: store */
11702 /* make unconditional */
11703 if (condT != IRTemp_INVALID) {
11704 if (isT)
11705 mk_skip_over_T32_if_cond_is_false( condT );
11706 else
11707 mk_skip_over_A32_if_cond_is_false( condT );
11708 condT = IRTemp_INVALID;
11709 }
11710 IRTemp ea = newTemp(Ity_I32);
11711 assign(ea, binop(bU ? Iop_Add32 : Iop_Sub32,
11712 align4if(isT ? getIRegT(rN) : getIRegA(rN),
11713 rN == 15),
11714 mkU32(offset)));
11715 if (bL) {
11716 putFReg(fD, loadLE(Ity_F32,mkexpr(ea)), IRTemp_INVALID);
11717 } else {
11718 storeLE(mkexpr(ea), getFReg(fD));
11719 }
11720 DIP("f%ss%s s%u, [r%u, %c#%u]\n",
11721 bL ? "ld" : "st", nCC(conq), fD, rN,
11722 bU ? '+' : '-', offset);
11723 goto decode_success_vfp;
11724 }
11725
11726 /* --------------------- dp insns (F) --------------------- */
11727 if (BITS8(1,1,1,0,0,0,0,0) == (INSN(27,20) & BITS8(1,1,1,1,0,0,0,0))
sewardj93ba93f2010-09-22 16:15:50 +000011728 && BITS4(1,0,1,0) == (INSN(11,8) & BITS4(1,1,1,0))
sewardjd2664472010-08-22 12:44:20 +000011729 && BITS4(0,0,0,0) == (INSN(7,4) & BITS4(0,0,0,1))) {
11730 UInt bM = (insn28 >> 5) & 1;
11731 UInt bD = (insn28 >> 22) & 1;
11732 UInt bN = (insn28 >> 7) & 1;
11733 UInt fM = (INSN(3,0) << 1) | bM; /* argR */
11734 UInt fD = (INSN(15,12) << 1) | bD; /* dst/acc */
11735 UInt fN = (INSN(19,16) << 1) | bN; /* argL */
11736 UInt bP = (insn28 >> 23) & 1;
11737 UInt bQ = (insn28 >> 21) & 1;
11738 UInt bR = (insn28 >> 20) & 1;
11739 UInt bS = (insn28 >> 6) & 1;
11740 UInt opc = (bP << 3) | (bQ << 2) | (bR << 1) | bS;
11741 IRExpr* rm = get_FAKE_roundingmode(); /* XXXROUNDINGFIXME */
11742 switch (opc) {
11743 case BITS4(0,0,0,0): /* MAC: d + n * m */
11744 putFReg(fD, triop(Iop_AddF32, rm,
11745 getFReg(fD),
11746 triop(Iop_MulF32, rm, getFReg(fN), getFReg(fM))),
11747 condT);
11748 DIP("fmacs%s s%u, s%u, s%u\n", nCC(conq), fD, fN, fM);
11749 goto decode_success_vfp;
sewardj93ba93f2010-09-22 16:15:50 +000011750 case BITS4(0,0,0,1): /* NMAC: d + -(n * m) */
11751 putFReg(fD, triop(Iop_AddF32, rm,
sewardjd2664472010-08-22 12:44:20 +000011752 getFReg(fD),
sewardj93ba93f2010-09-22 16:15:50 +000011753 unop(Iop_NegF32,
11754 triop(Iop_MulF32, rm, getFReg(fN),
11755 getFReg(fM)))),
sewardjd2664472010-08-22 12:44:20 +000011756 condT);
11757 DIP("fnmacs%s s%u, s%u, s%u\n", nCC(conq), fD, fN, fM);
11758 goto decode_success_vfp;
11759 case BITS4(0,0,1,0): /* MSC: - d + n * m */
11760 putFReg(fD, triop(Iop_AddF32, rm,
11761 unop(Iop_NegF32, getFReg(fD)),
11762 triop(Iop_MulF32, rm, getFReg(fN), getFReg(fM))),
11763 condT);
11764 DIP("fmscs%s s%u, s%u, s%u\n", nCC(conq), fD, fN, fM);
11765 goto decode_success_vfp;
sewardj93ba93f2010-09-22 16:15:50 +000011766 case BITS4(0,0,1,1): /* NMSC: - d + -(n * m) */
11767 putFReg(fD, triop(Iop_AddF32, rm,
11768 unop(Iop_NegF32, getFReg(fD)),
11769 unop(Iop_NegF32,
11770 triop(Iop_MulF32, rm,
11771 getFReg(fN),
11772 getFReg(fM)))),
11773 condT);
11774 DIP("fnmscs%s s%u, s%u, s%u\n", nCC(conq), fD, fN, fM);
11775 goto decode_success_vfp;
sewardjd2664472010-08-22 12:44:20 +000011776 case BITS4(0,1,0,0): /* MUL: n * m */
11777 putFReg(fD, triop(Iop_MulF32, rm, getFReg(fN), getFReg(fM)),
11778 condT);
11779 DIP("fmuls%s s%u, s%u, s%u\n", nCC(conq), fD, fN, fM);
11780 goto decode_success_vfp;
11781 case BITS4(0,1,0,1): /* NMUL: - n * m */
11782 putFReg(fD, unop(Iop_NegF32,
11783 triop(Iop_MulF32, rm, getFReg(fN),
11784 getFReg(fM))),
11785 condT);
11786 DIP("fnmuls%s s%u, s%u, s%u\n", nCC(conq), fD, fN, fM);
11787 goto decode_success_vfp;
11788 case BITS4(0,1,1,0): /* ADD: n + m */
11789 putFReg(fD, triop(Iop_AddF32, rm, getFReg(fN), getFReg(fM)),
11790 condT);
11791 DIP("fadds%s s%u, s%u, s%u\n", nCC(conq), fD, fN, fM);
11792 goto decode_success_vfp;
11793 case BITS4(0,1,1,1): /* SUB: n - m */
11794 putFReg(fD, triop(Iop_SubF32, rm, getFReg(fN), getFReg(fM)),
11795 condT);
11796 DIP("fsubs%s s%u, s%u, s%u\n", nCC(conq), fD, fN, fM);
11797 goto decode_success_vfp;
11798 case BITS4(1,0,0,0): /* DIV: n / m */
11799 putFReg(fD, triop(Iop_DivF32, rm, getFReg(fN), getFReg(fM)),
11800 condT);
11801 DIP("fdivs%s s%u, s%u, s%u\n", nCC(conq), fD, fN, fM);
11802 goto decode_success_vfp;
11803 default:
11804 break;
11805 }
11806 }
11807
11808 /* --------------------- compares (S) --------------------- */
11809 /* 31 27 23 19 15 11 7 3
11810 28 24 20 16 12 8 4 0
11811 FCMPS cond 1110 1D11 0100 Fd 1010 01M0 Fm
11812 FCMPES cond 1110 1D11 0100 Fd 1010 11M0 Fm
11813 FCMPZS cond 1110 1D11 0101 Fd 1010 0100 0000
11814 FCMPZED cond 1110 1D11 0101 Fd 1010 1100 0000
11815 Z N
11816
11817 Z=0 Compare Fd:D vs Fm:M and set FPSCR 31:28 accordingly
11818 Z=1 Compare Fd:D vs zero
11819
11820 N=1 generates Invalid Operation exn if either arg is any kind of NaN
11821 N=0 generates Invalid Operation exn if either arg is a signalling NaN
11822 (Not that we pay any attention to N here)
11823 */
11824 if (BITS8(1,1,1,0,1,0,1,1) == (INSN(27,20) & BITS8(1,1,1,1,1,0,1,1))
11825 && BITS4(0,1,0,0) == (INSN(19,16) & BITS4(1,1,1,0))
11826 && BITS4(1,0,1,0) == INSN(11,8)
11827 && BITS4(0,1,0,0) == (INSN(7,4) & BITS4(0,1,0,1))) {
11828 UInt bZ = (insn28 >> 16) & 1;
11829 UInt bN = (insn28 >> 7) & 1;
11830 UInt bD = (insn28 >> 22) & 1;
11831 UInt bM = (insn28 >> 5) & 1;
11832 UInt fD = (INSN(15,12) << 1) | bD;
11833 UInt fM = (INSN(3,0) << 1) | bM;
11834 if (bZ && (INSN(3,0) != 0 || (INSN(7,4) & 3) != 0)) {
11835 /* does not decode; fall through */
11836 } else {
11837 IRTemp argL = newTemp(Ity_F64);
11838 IRTemp argR = newTemp(Ity_F64);
11839 IRTemp irRes = newTemp(Ity_I32);
11840
11841 assign(argL, unop(Iop_F32toF64, getFReg(fD)));
11842 assign(argR, bZ ? IRExpr_Const(IRConst_F64i(0))
11843 : unop(Iop_F32toF64, getFReg(fM)));
11844 assign(irRes, binop(Iop_CmpF64, mkexpr(argL), mkexpr(argR)));
11845
11846 IRTemp nzcv = IRTemp_INVALID;
11847 IRTemp oldFPSCR = newTemp(Ity_I32);
11848 IRTemp newFPSCR = newTemp(Ity_I32);
11849
11850 /* This is where the fun starts. We have to convert 'irRes'
11851 from an IR-convention return result (IRCmpF64Result) to an
11852 ARM-encoded (N,Z,C,V) group. The final result is in the
11853 bottom 4 bits of 'nzcv'. */
11854 /* Map compare result from IR to ARM(nzcv) */
11855 /*
11856 FP cmp result | IR | ARM(nzcv)
11857 --------------------------------
11858 UN 0x45 0011
11859 LT 0x01 1000
11860 GT 0x00 0010
11861 EQ 0x40 0110
11862 */
11863 nzcv = mk_convert_IRCmpF64Result_to_NZCV(irRes);
11864
11865 /* And update FPSCR accordingly */
11866 assign(oldFPSCR, IRExpr_Get(OFFB_FPSCR, Ity_I32));
11867 assign(newFPSCR,
11868 binop(Iop_Or32,
11869 binop(Iop_And32, mkexpr(oldFPSCR), mkU32(0x0FFFFFFF)),
11870 binop(Iop_Shl32, mkexpr(nzcv), mkU8(28))));
11871
11872 putMiscReg32(OFFB_FPSCR, mkexpr(newFPSCR), condT);
11873
11874 if (bZ) {
11875 DIP("fcmpz%ss%s s%u\n", bN ? "e" : "", nCC(conq), fD);
11876 } else {
11877 DIP("fcmp%ss%s s%u, s%u\n", bN ? "e" : "",
11878 nCC(conq), fD, fM);
11879 }
11880 goto decode_success_vfp;
11881 }
11882 /* fall through */
11883 }
11884
11885 /* --------------------- unary (S) --------------------- */
11886 if (BITS8(1,1,1,0,1,0,1,1) == (INSN(27,20) & BITS8(1,1,1,1,1,0,1,1))
11887 && BITS4(0,0,0,0) == (INSN(19,16) & BITS4(1,1,1,0))
11888 && BITS4(1,0,1,0) == INSN(11,8)
11889 && BITS4(0,1,0,0) == (INSN(7,4) & BITS4(0,1,0,1))) {
11890 UInt bD = (insn28 >> 22) & 1;
11891 UInt bM = (insn28 >> 5) & 1;
11892 UInt fD = (INSN(15,12) << 1) | bD;
11893 UInt fM = (INSN(3,0) << 1) | bM;
11894 UInt b16 = (insn28 >> 16) & 1;
11895 UInt b7 = (insn28 >> 7) & 1;
11896 /**/ if (b16 == 0 && b7 == 0) {
11897 // FCPYS
11898 putFReg(fD, getFReg(fM), condT);
11899 DIP("fcpys%s s%u, s%u\n", nCC(conq), fD, fM);
11900 goto decode_success_vfp;
11901 }
11902 else if (b16 == 0 && b7 == 1) {
11903 // FABSS
11904 putFReg(fD, unop(Iop_AbsF32, getFReg(fM)), condT);
11905 DIP("fabss%s s%u, s%u\n", nCC(conq), fD, fM);
11906 goto decode_success_vfp;
11907 }
11908 else if (b16 == 1 && b7 == 0) {
11909 // FNEGS
11910 putFReg(fD, unop(Iop_NegF32, getFReg(fM)), condT);
11911 DIP("fnegs%s s%u, s%u\n", nCC(conq), fD, fM);
11912 goto decode_success_vfp;
11913 }
11914 else if (b16 == 1 && b7 == 1) {
11915 // FSQRTS
11916 IRExpr* rm = get_FAKE_roundingmode(); /* XXXROUNDINGFIXME */
11917 putFReg(fD, binop(Iop_SqrtF32, rm, getFReg(fM)), condT);
11918 DIP("fsqrts%s s%u, s%u\n", nCC(conq), fD, fM);
11919 goto decode_success_vfp;
11920 }
11921 else
11922 vassert(0);
11923
11924 /* fall through */
11925 }
11926
11927 /* ----------------- I <-> S conversions ----------------- */
11928
11929 // F{S,U}ITOS fD, fM
11930 /* These are more complex than FSITOD/FUITOD. In the D cases, a 32
11931 bit int will always fit within the 53 bit mantissa, so there's
11932 no possibility of a loss of precision, but that's obviously not
11933 the case here. Hence this case possibly requires rounding, and
11934 so it drags in the current rounding mode. */
11935 if (BITS8(1,1,1,0,1,0,1,1) == (INSN(27,20) & BITS8(1,1,1,1,1,0,1,1))
sewardj93ba93f2010-09-22 16:15:50 +000011936 && BITS4(1,0,0,0) == INSN(19,16)
11937 && BITS4(1,0,1,0) == (INSN(11,8) & BITS4(1,1,1,0))
sewardjd2664472010-08-22 12:44:20 +000011938 && BITS4(0,1,0,0) == (INSN(7,4) & BITS4(0,1,0,1))) {
11939 UInt bM = (insn28 >> 5) & 1;
11940 UInt bD = (insn28 >> 22) & 1;
11941 UInt fM = (INSN(3,0) << 1) | bM;
11942 UInt fD = (INSN(15,12) << 1) | bD;
11943 UInt syned = (insn28 >> 7) & 1;
11944 IRTemp rmode = newTemp(Ity_I32);
11945 assign(rmode, mkexpr(mk_get_IR_rounding_mode()));
11946 if (syned) {
11947 // FSITOS
11948 putFReg(fD, binop(Iop_F64toF32,
11949 mkexpr(rmode),
11950 unop(Iop_I32StoF64,
11951 unop(Iop_ReinterpF32asI32, getFReg(fM)))),
11952 condT);
11953 DIP("fsitos%s s%u, s%u\n", nCC(conq), fD, fM);
11954 } else {
11955 // FUITOS
11956 putFReg(fD, binop(Iop_F64toF32,
11957 mkexpr(rmode),
11958 unop(Iop_I32UtoF64,
11959 unop(Iop_ReinterpF32asI32, getFReg(fM)))),
11960 condT);
11961 DIP("fuitos%s s%u, s%u\n", nCC(conq), fD, fM);
11962 }
11963 goto decode_success_vfp;
11964 }
11965
11966 // FTO{S,U}IS fD, fM
11967 if (BITS8(1,1,1,0,1,0,1,1) == (INSN(27,20) & BITS8(1,1,1,1,1,0,1,1))
11968 && BITS4(1,1,0,0) == (INSN(19,16) & BITS4(1,1,1,0))
11969 && BITS4(1,0,1,0) == INSN(11,8)
11970 && BITS4(0,1,0,0) == (INSN(7,4) & BITS4(0,1,0,1))) {
11971 UInt bM = (insn28 >> 5) & 1;
11972 UInt bD = (insn28 >> 22) & 1;
11973 UInt fD = (INSN(15,12) << 1) | bD;
11974 UInt fM = (INSN(3,0) << 1) | bM;
11975 UInt bZ = (insn28 >> 7) & 1;
11976 UInt syned = (insn28 >> 16) & 1;
11977 IRTemp rmode = newTemp(Ity_I32);
11978 assign(rmode, bZ ? mkU32(Irrm_ZERO)
11979 : mkexpr(mk_get_IR_rounding_mode()));
11980 if (syned) {
11981 // FTOSIS
11982 putFReg(fD, unop(Iop_ReinterpI32asF32,
11983 binop(Iop_F64toI32S, mkexpr(rmode),
11984 unop(Iop_F32toF64, getFReg(fM)))),
11985 condT);
11986 DIP("ftosi%ss%s s%u, d%u\n", bZ ? "z" : "",
11987 nCC(conq), fD, fM);
11988 goto decode_success_vfp;
11989 } else {
11990 // FTOUIS
11991 putFReg(fD, unop(Iop_ReinterpI32asF32,
11992 binop(Iop_F64toI32U, mkexpr(rmode),
11993 unop(Iop_F32toF64, getFReg(fM)))),
11994 condT);
11995 DIP("ftoui%ss%s s%u, d%u\n", bZ ? "z" : "",
11996 nCC(conq), fD, fM);
11997 goto decode_success_vfp;
11998 }
11999 }
12000
12001 /* ----------------- S <-> D conversions ----------------- */
12002
12003 // FCVTDS
sewardj93ba93f2010-09-22 16:15:50 +000012004 if (BITS8(1,1,1,0,1,0,1,1) == (INSN(27,20) & BITS8(1,1,1,1,1,0,1,1))
sewardjd2664472010-08-22 12:44:20 +000012005 && BITS4(0,1,1,1) == INSN(19,16)
12006 && BITS4(1,0,1,0) == INSN(11,8)
12007 && BITS4(1,1,0,0) == (INSN(7,4) & BITS4(1,1,0,1))) {
sewardj93ba93f2010-09-22 16:15:50 +000012008 UInt dD = INSN(15,12) | (INSN(22,22) << 4);
sewardjd2664472010-08-22 12:44:20 +000012009 UInt bM = (insn28 >> 5) & 1;
12010 UInt fM = (INSN(3,0) << 1) | bM;
12011 putDReg(dD, unop(Iop_F32toF64, getFReg(fM)), condT);
12012 DIP("fcvtds%s d%u, s%u\n", nCC(conq), dD, fM);
12013 goto decode_success_vfp;
12014 }
12015
12016 // FCVTSD
12017 if (BITS8(1,1,1,0,1,0,1,1) == (INSN(27,20) & BITS8(1,1,1,1,1,0,1,1))
12018 && BITS4(0,1,1,1) == INSN(19,16)
12019 && BITS4(1,0,1,1) == INSN(11,8)
sewardj93ba93f2010-09-22 16:15:50 +000012020 && BITS4(1,1,0,0) == (INSN(7,4) & BITS4(1,1,0,1))) {
sewardjd2664472010-08-22 12:44:20 +000012021 UInt bD = (insn28 >> 22) & 1;
12022 UInt fD = (INSN(15,12) << 1) | bD;
sewardj93ba93f2010-09-22 16:15:50 +000012023 UInt dM = INSN(3,0) | (INSN(5,5) << 4);
sewardjd2664472010-08-22 12:44:20 +000012024 IRTemp rmode = newTemp(Ity_I32);
12025 assign(rmode, mkexpr(mk_get_IR_rounding_mode()));
12026 putFReg(fD, binop(Iop_F64toF32, mkexpr(rmode), getDReg(dM)),
12027 condT);
12028 DIP("fcvtsd%s s%u, d%u\n", nCC(conq), fD, dM);
12029 goto decode_success_vfp;
12030 }
12031
12032 /* FAILURE */
12033 return False;
12034
12035 decode_success_vfp:
12036 /* Check that any accepted insn really is a CP10 or CP11 insn, iow,
12037 assert that we aren't accepting, in this fn, insns that actually
12038 should be handled somewhere else. */
12039 vassert(INSN(11,9) == BITS3(1,0,1)); // 11:8 = 1010 or 1011
12040 return True;
12041
12042# undef INSN
12043}
12044
12045
sewardjc2c87162004-11-25 13:07:02 +000012046/*------------------------------------------------------------*/
sewardj80bea7b2010-01-09 11:43:21 +000012047/*--- Instructions in NV (never) space ---*/
12048/*------------------------------------------------------------*/
12049
sewardjd2664472010-08-22 12:44:20 +000012050/* ARM only */
12051/* Translate a NV space instruction. If successful, returns True and
12052 *dres may or may not be updated. If failure, returns False and
12053 doesn't change *dres nor create any IR.
12054
12055 Note that all NEON instructions (in ARM mode) are handled through
12056 here, since they are all in NV space.
12057*/
sewardj1fce8de2010-09-09 07:27:24 +000012058static Bool decode_NV_instruction ( /*MOD*/DisResult* dres,
12059 VexArchInfo* archinfo,
12060 UInt insn )
sewardj80bea7b2010-01-09 11:43:21 +000012061{
12062# define INSN(_bMax,_bMin) SLICE_UInt(insn, (_bMax), (_bMin))
12063# define INSN_COND SLICE_UInt(insn, 31, 28)
12064
12065 HChar dis_buf[128];
12066
12067 // Should only be called for NV instructions
12068 vassert(BITS4(1,1,1,1) == INSN_COND);
12069
12070 /* ------------------------ pld ------------------------ */
12071 if (BITS8(0,1,0,1, 0, 1,0,1) == (INSN(27,20) & BITS8(1,1,1,1,0,1,1,1))
12072 && BITS4(1,1,1,1) == INSN(15,12)) {
12073 UInt rN = INSN(19,16);
12074 UInt imm12 = INSN(11,0);
12075 UInt bU = INSN(23,23);
12076 DIP("pld [r%u, #%c%u]\n", rN, bU ? '+' : '-', imm12);
12077 return True;
12078 }
12079
12080 if (BITS8(0,1,1,1, 0, 1,0,1) == (INSN(27,20) & BITS8(1,1,1,1,0,1,1,1))
12081 && BITS4(1,1,1,1) == INSN(15,12)
12082 && 0 == INSN(4,4)) {
12083 UInt rN = INSN(19,16);
12084 UInt rM = INSN(3,0);
12085 UInt imm5 = INSN(11,7);
12086 UInt sh2 = INSN(6,5);
12087 UInt bU = INSN(23,23);
12088 if (rM != 15) {
12089 IRExpr* eaE = mk_EA_reg_plusminus_shifted_reg(rN, bU, rM,
12090 sh2, imm5, dis_buf);
12091 IRTemp eaT = newTemp(Ity_I32);
12092 /* Bind eaE to a temp merely for debugging-vex purposes, so we
12093 can check it's a plausible decoding. It will get removed
12094 by iropt a little later on. */
12095 vassert(eaE);
12096 assign(eaT, eaE);
12097 DIP("pld %s\n", dis_buf);
12098 return True;
12099 }
12100 /* fall through */
12101 }
12102
sewardj4c3839e2010-08-31 09:31:06 +000012103 /* ------------------------ pli ------------------------ */
12104 if (BITS8(0,1,0,0, 0, 1,0,1) == (INSN(27,20) & BITS8(1,1,1,1,0,1,1,1))
12105 && BITS4(1,1,1,1) == INSN(15,12)) {
12106 UInt rN = INSN(19,16);
12107 UInt imm12 = INSN(11,0);
12108 UInt bU = INSN(23,23);
12109 DIP("pli [r%u, #%c%u]\n", rN, bU ? '+' : '-', imm12);
12110 return True;
12111 }
12112
sewardjd2664472010-08-22 12:44:20 +000012113 /* --------------------- Interworking branches --------------------- */
12114
12115 // BLX (1), viz, unconditional branch and link to R15+simm24
12116 // and set CPSR.T = 1, that is, switch to Thumb mode
12117 if (INSN(31,25) == BITS7(1,1,1,1,1,0,1)) {
12118 UInt bitH = INSN(24,24);
12119 Int uimm24 = INSN(23,0);
12120 Int simm24 = (((uimm24 << 8) >> 8) << 2) + (bitH << 1);
12121 /* Now this is a bit tricky. Since we're decoding an ARM insn,
12122 it is implies that CPSR.T == 0. Hence the current insn's
12123 address is guaranteed to be of the form X--(30)--X00. So, no
12124 need to mask any bits off it. But need to set the lowest bit
12125 to 1 to denote we're in Thumb mode after this, since
12126 guest_R15T has CPSR.T as the lowest bit. And we can't chase
12127 into the call, so end the block at this point. */
12128 UInt dst = guest_R15_curr_instr_notENC + 8 + (simm24 | 1);
12129 putIRegA( 14, mkU32(guest_R15_curr_instr_notENC + 4),
12130 IRTemp_INVALID/*because AL*/, Ijk_Boring );
sewardjc6f970f2012-04-02 21:54:49 +000012131 llPutIReg(15, mkU32(dst));
12132 dres->jk_StopHere = Ijk_Call;
12133 dres->whatNext = Dis_StopHere;
sewardjd2664472010-08-22 12:44:20 +000012134 DIP("blx 0x%x (and switch to Thumb mode)\n", dst - 1);
12135 return True;
12136 }
12137
sewardj412098c2010-05-04 08:48:43 +000012138 /* ------------------- v7 barrier insns ------------------- */
12139 switch (insn) {
12140 case 0xF57FF06F: /* ISB */
12141 stmt( IRStmt_MBE(Imbe_Fence) );
12142 DIP("ISB\n");
12143 return True;
sewardje407ced2011-05-03 14:57:59 +000012144 case 0xF57FF04F: /* DSB sy */
12145 case 0xF57FF04E: /* DSB st */
12146 case 0xF57FF04B: /* DSB ish */
12147 case 0xF57FF04A: /* DSB ishst */
12148 case 0xF57FF047: /* DSB nsh */
12149 case 0xF57FF046: /* DSB nshst */
12150 case 0xF57FF043: /* DSB osh */
12151 case 0xF57FF042: /* DSB oshst */
sewardj412098c2010-05-04 08:48:43 +000012152 stmt( IRStmt_MBE(Imbe_Fence) );
12153 DIP("DSB\n");
12154 return True;
sewardje407ced2011-05-03 14:57:59 +000012155 case 0xF57FF05F: /* DMB sy */
12156 case 0xF57FF05E: /* DMB st */
12157 case 0xF57FF05B: /* DMB ish */
12158 case 0xF57FF05A: /* DMB ishst */
12159 case 0xF57FF057: /* DMB nsh */
12160 case 0xF57FF056: /* DMB nshst */
12161 case 0xF57FF053: /* DMB osh */
12162 case 0xF57FF052: /* DMB oshst */
sewardj412098c2010-05-04 08:48:43 +000012163 stmt( IRStmt_MBE(Imbe_Fence) );
12164 DIP("DMB\n");
12165 return True;
12166 default:
12167 break;
12168 }
12169
sewardj6d615ba2011-09-26 16:19:43 +000012170 /* ------------------- CLREX ------------------ */
12171 if (insn == 0xF57FF01F) {
12172 /* AFAICS, this simply cancels a (all?) reservations made by a
12173 (any?) preceding LDREX(es). Arrange to hand it through to
12174 the back end. */
12175 stmt( IRStmt_MBE(Imbe_CancelReservation) );
12176 DIP("clrex\n");
12177 return True;
12178 }
12179
sewardjd2664472010-08-22 12:44:20 +000012180 /* ------------------- NEON ------------------- */
sewardj1fce8de2010-09-09 07:27:24 +000012181 if (archinfo->hwcaps & VEX_HWCAPS_ARM_NEON) {
12182 Bool ok_neon = decode_NEON_instruction(
12183 dres, insn, IRTemp_INVALID/*unconditional*/,
12184 False/*!isT*/
12185 );
12186 if (ok_neon)
12187 return True;
sewardj1f139f52010-08-29 12:33:02 +000012188 }
sewardjd2664472010-08-22 12:44:20 +000012189
12190 // unrecognised
sewardj80bea7b2010-01-09 11:43:21 +000012191 return False;
12192
12193# undef INSN_COND
12194# undef INSN
12195}
12196
12197
12198/*------------------------------------------------------------*/
sewardjd2664472010-08-22 12:44:20 +000012199/*--- Disassemble a single ARM instruction ---*/
sewardjc2c87162004-11-25 13:07:02 +000012200/*------------------------------------------------------------*/
12201
sewardjd2664472010-08-22 12:44:20 +000012202/* Disassemble a single ARM instruction into IR. The instruction is
12203 located in host memory at guest_instr, and has (decoded) guest IP
12204 of guest_R15_curr_instr_notENC, which will have been set before the
12205 call here. */
sewardj6c299f32009-12-31 18:00:12 +000012206
sewardjd2664472010-08-22 12:44:20 +000012207static
sewardj6c299f32009-12-31 18:00:12 +000012208DisResult disInstr_ARM_WRK (
sewardj6c299f32009-12-31 18:00:12 +000012209 Bool (*resteerOkFn) ( /*opaque*/void*, Addr64 ),
sewardj82f56882010-01-17 09:36:11 +000012210 Bool resteerCisOk,
sewardj6c299f32009-12-31 18:00:12 +000012211 void* callback_opaque,
12212 UChar* guest_instr,
12213 VexArchInfo* archinfo,
12214 VexAbiInfo* abiinfo
12215 )
sewardjc2c87162004-11-25 13:07:02 +000012216{
sewardj6c299f32009-12-31 18:00:12 +000012217 // A macro to fish bits out of 'insn'.
sewardj80bea7b2010-01-09 11:43:21 +000012218# define INSN(_bMax,_bMin) SLICE_UInt(insn, (_bMax), (_bMin))
12219# define INSN_COND SLICE_UInt(insn, 31, 28)
sewardj6c299f32009-12-31 18:00:12 +000012220
12221 DisResult dres;
12222 UInt insn;
12223 //Bool allow_VFP = False;
12224 //UInt hwcaps = archinfo->hwcaps;
12225 IRTemp condT; /* :: Ity_I32 */
12226 UInt summary;
12227 HChar dis_buf[128]; // big enough to hold LDMIA etc text
12228
12229 /* What insn variants are we supporting today? */
12230 //allow_VFP = (0 != (hwcaps & VEX_HWCAPS_ARM_VFP));
12231 // etc etc
12232
12233 /* Set result defaults. */
sewardjc6f970f2012-04-02 21:54:49 +000012234 dres.whatNext = Dis_Continue;
12235 dres.len = 4;
12236 dres.continueAt = 0;
12237 dres.jk_StopHere = Ijk_INVALID;
sewardj6c299f32009-12-31 18:00:12 +000012238
12239 /* Set default actions for post-insn handling of writes to r15, if
12240 required. */
12241 r15written = False;
12242 r15guard = IRTemp_INVALID; /* unconditional */
12243 r15kind = Ijk_Boring;
sewardjc2c87162004-11-25 13:07:02 +000012244
sewardjc2c87162004-11-25 13:07:02 +000012245 /* At least this is simple on ARM: insns are all 4 bytes long, and
12246 4-aligned. So just fish the whole thing out of memory right now
12247 and have done. */
sewardj6c299f32009-12-31 18:00:12 +000012248 insn = getUIntLittleEndianly( guest_instr );
sewardjc2c87162004-11-25 13:07:02 +000012249
sewardj6c299f32009-12-31 18:00:12 +000012250 if (0) vex_printf("insn: 0x%x\n", insn);
sewardjc2c87162004-11-25 13:07:02 +000012251
sewardjd2664472010-08-22 12:44:20 +000012252 DIP("\t(arm) 0x%x: ", (UInt)guest_R15_curr_instr_notENC);
cerionc60c01e2004-12-02 20:19:22 +000012253
sewardjd2664472010-08-22 12:44:20 +000012254 vassert(0 == (guest_R15_curr_instr_notENC & 3));
sewardjc2c87162004-11-25 13:07:02 +000012255
sewardj6c299f32009-12-31 18:00:12 +000012256 /* ----------------------------------------------------------- */
cerionc60c01e2004-12-02 20:19:22 +000012257
sewardj6c299f32009-12-31 18:00:12 +000012258 /* Spot "Special" instructions (see comment at top of file). */
sewardjc2c87162004-11-25 13:07:02 +000012259 {
sewardj6c299f32009-12-31 18:00:12 +000012260 UChar* code = (UChar*)guest_instr;
12261 /* Spot the 16-byte preamble:
sewardjcca71942004-12-02 23:35:18 +000012262
sewardj6c299f32009-12-31 18:00:12 +000012263 e1a0c1ec mov r12, r12, ROR #3
12264 e1a0c6ec mov r12, r12, ROR #13
12265 e1a0ceec mov r12, r12, ROR #29
12266 e1a0c9ec mov r12, r12, ROR #19
12267 */
12268 UInt word1 = 0xE1A0C1EC;
12269 UInt word2 = 0xE1A0C6EC;
12270 UInt word3 = 0xE1A0CEEC;
12271 UInt word4 = 0xE1A0C9EC;
12272 if (getUIntLittleEndianly(code+ 0) == word1 &&
12273 getUIntLittleEndianly(code+ 4) == word2 &&
12274 getUIntLittleEndianly(code+ 8) == word3 &&
12275 getUIntLittleEndianly(code+12) == word4) {
12276 /* Got a "Special" instruction preamble. Which one is it? */
12277 if (getUIntLittleEndianly(code+16) == 0xE18AA00A
12278 /* orr r10,r10,r10 */) {
12279 /* R3 = client_request ( R4 ) */
12280 DIP("r3 = client_request ( %%r4 )\n");
sewardjc6f970f2012-04-02 21:54:49 +000012281 llPutIReg(15, mkU32( guest_R15_curr_instr_notENC + 20 ));
12282 dres.jk_StopHere = Ijk_ClientReq;
12283 dres.whatNext = Dis_StopHere;
sewardj6c299f32009-12-31 18:00:12 +000012284 goto decode_success;
12285 }
12286 else
12287 if (getUIntLittleEndianly(code+16) == 0xE18BB00B
12288 /* orr r11,r11,r11 */) {
12289 /* R3 = guest_NRADDR */
12290 DIP("r3 = guest_NRADDR\n");
12291 dres.len = 20;
12292 llPutIReg(3, IRExpr_Get( OFFB_NRADDR, Ity_I32 ));
12293 goto decode_success;
12294 }
12295 else
12296 if (getUIntLittleEndianly(code+16) == 0xE18CC00C
12297 /* orr r12,r12,r12 */) {
12298 /* branch-and-link-to-noredir R4 */
12299 DIP("branch-and-link-to-noredir r4\n");
sewardjd2664472010-08-22 12:44:20 +000012300 llPutIReg(14, mkU32( guest_R15_curr_instr_notENC + 20) );
sewardjc6f970f2012-04-02 21:54:49 +000012301 llPutIReg(15, llGetIReg(4));
12302 dres.jk_StopHere = Ijk_NoRedir;
12303 dres.whatNext = Dis_StopHere;
sewardj6c299f32009-12-31 18:00:12 +000012304 goto decode_success;
12305 }
12306 /* We don't know what it is. Set opc1/opc2 so decode_failure
12307 can print the insn following the Special-insn preamble. */
12308 insn = getUIntLittleEndianly(code+16);
12309 goto decode_failure;
12310 /*NOTREACHED*/
12311 }
12312
12313 }
12314
12315 /* ----------------------------------------------------------- */
12316
sewardjd2664472010-08-22 12:44:20 +000012317 /* Main ARM instruction decoder starts here. */
sewardj6c299f32009-12-31 18:00:12 +000012318
12319 /* Deal with the condition. Strategy is to merely generate a
sewardjd2664472010-08-22 12:44:20 +000012320 condition temporary at this point (or IRTemp_INVALID, meaning
sewardj6c299f32009-12-31 18:00:12 +000012321 unconditional). We leave it to lower-level instruction decoders
12322 to decide whether they can generate straight-line code, or
12323 whether they must generate a side exit before the instruction.
12324 condT :: Ity_I32 and is always either zero or one. */
12325 condT = IRTemp_INVALID;
12326 switch ( (ARMCondcode)INSN_COND ) {
sewardj80bea7b2010-01-09 11:43:21 +000012327 case ARMCondNV: {
12328 // Illegal instruction prior to v5 (see ARM ARM A3-5), but
12329 // some cases are acceptable
sewardj1fce8de2010-09-09 07:27:24 +000012330 Bool ok = decode_NV_instruction(&dres, archinfo, insn);
sewardj80bea7b2010-01-09 11:43:21 +000012331 if (ok)
12332 goto decode_success;
12333 else
12334 goto decode_failure;
12335 }
sewardj6c299f32009-12-31 18:00:12 +000012336 case ARMCondAL: // Always executed
12337 break;
12338 case ARMCondEQ: case ARMCondNE: case ARMCondHS: case ARMCondLO:
12339 case ARMCondMI: case ARMCondPL: case ARMCondVS: case ARMCondVC:
12340 case ARMCondHI: case ARMCondLS: case ARMCondGE: case ARMCondLT:
12341 case ARMCondGT: case ARMCondLE:
12342 condT = newTemp(Ity_I32);
12343 assign( condT, mk_armg_calculate_condition( INSN_COND ));
12344 break;
12345 }
12346
12347 /* ----------------------------------------------------------- */
12348 /* -- ARMv5 integer instructions -- */
12349 /* ----------------------------------------------------------- */
12350
12351 /* ---------------- Data processing ops ------------------- */
12352
12353 if (0 == (INSN(27,20) & BITS8(1,1,0,0,0,0,0,0))
12354 && !(INSN(25,25) == 0 && INSN(7,7) == 1 && INSN(4,4) == 1)) {
12355 IRTemp shop = IRTemp_INVALID; /* shifter operand */
12356 IRTemp shco = IRTemp_INVALID; /* shifter carry out */
12357 UInt rD = (insn >> 12) & 0xF; /* 15:12 */
12358 UInt rN = (insn >> 16) & 0xF; /* 19:16 */
12359 UInt bitS = (insn >> 20) & 1; /* 20:20 */
12360 IRTemp rNt = IRTemp_INVALID;
12361 IRTemp res = IRTemp_INVALID;
12362 IRTemp oldV = IRTemp_INVALID;
12363 IRTemp oldC = IRTemp_INVALID;
12364 HChar* name = NULL;
12365 IROp op = Iop_INVALID;
12366 Bool ok;
12367
12368 switch (INSN(24,21)) {
12369
12370 /* --------- ADD, SUB, AND, OR --------- */
12371 case BITS4(0,1,0,0): /* ADD: Rd = Rn + shifter_operand */
12372 name = "add"; op = Iop_Add32; goto rd_eq_rn_op_SO;
12373 case BITS4(0,0,1,0): /* SUB: Rd = Rn - shifter_operand */
12374 name = "sub"; op = Iop_Sub32; goto rd_eq_rn_op_SO;
12375 case BITS4(0,0,1,1): /* RSB: Rd = shifter_operand - Rn */
12376 name = "rsb"; op = Iop_Sub32; goto rd_eq_rn_op_SO;
12377 case BITS4(0,0,0,0): /* AND: Rd = Rn & shifter_operand */
12378 name = "and"; op = Iop_And32; goto rd_eq_rn_op_SO;
12379 case BITS4(1,1,0,0): /* OR: Rd = Rn | shifter_operand */
12380 name = "orr"; op = Iop_Or32; goto rd_eq_rn_op_SO;
12381 case BITS4(0,0,0,1): /* EOR: Rd = Rn ^ shifter_operand */
12382 name = "eor"; op = Iop_Xor32; goto rd_eq_rn_op_SO;
12383 case BITS4(1,1,1,0): /* BIC: Rd = Rn & ~shifter_operand */
12384 name = "bic"; op = Iop_And32; goto rd_eq_rn_op_SO;
12385 rd_eq_rn_op_SO: {
12386 Bool isRSB = False;
12387 Bool isBIC = False;
12388 switch (INSN(24,21)) {
12389 case BITS4(0,0,1,1):
12390 vassert(op == Iop_Sub32); isRSB = True; break;
12391 case BITS4(1,1,1,0):
12392 vassert(op == Iop_And32); isBIC = True; break;
12393 default:
12394 break;
12395 }
12396 rNt = newTemp(Ity_I32);
sewardjd2664472010-08-22 12:44:20 +000012397 assign(rNt, getIRegA(rN));
sewardj6c299f32009-12-31 18:00:12 +000012398 ok = mk_shifter_operand(
12399 INSN(25,25), INSN(11,0),
12400 &shop, bitS ? &shco : NULL, dis_buf
12401 );
12402 if (!ok)
12403 break;
12404 res = newTemp(Ity_I32);
12405 // compute the main result
12406 if (isRSB) {
12407 // reverse-subtract: shifter_operand - Rn
12408 vassert(op == Iop_Sub32);
12409 assign(res, binop(op, mkexpr(shop), mkexpr(rNt)) );
12410 } else if (isBIC) {
12411 // andn: shifter_operand & ~Rn
12412 vassert(op == Iop_And32);
12413 assign(res, binop(op, mkexpr(rNt),
12414 unop(Iop_Not32, mkexpr(shop))) );
12415 } else {
12416 // normal: Rn op shifter_operand
12417 assign(res, binop(op, mkexpr(rNt), mkexpr(shop)) );
12418 }
12419 // but don't commit it until after we've finished
12420 // all necessary reads from the guest state
12421 if (bitS
12422 && (op == Iop_And32 || op == Iop_Or32 || op == Iop_Xor32)) {
12423 oldV = newTemp(Ity_I32);
12424 assign( oldV, mk_armg_calculate_flag_v() );
12425 }
sewardjd2664472010-08-22 12:44:20 +000012426 // can't safely read guest state after here
sewardj6c299f32009-12-31 18:00:12 +000012427 // now safe to put the main result
sewardjd2664472010-08-22 12:44:20 +000012428 putIRegA( rD, mkexpr(res), condT, Ijk_Boring );
sewardj6c299f32009-12-31 18:00:12 +000012429 // XXXX!! not safe to read any guest state after
12430 // this point (I think the code below doesn't do that).
12431 if (!bitS)
12432 vassert(shco == IRTemp_INVALID);
12433 /* Update the flags thunk if necessary */
12434 if (bitS) {
12435 vassert(shco != IRTemp_INVALID);
12436 switch (op) {
12437 case Iop_Add32:
12438 setFlags_D1_D2( ARMG_CC_OP_ADD, rNt, shop, condT );
12439 break;
12440 case Iop_Sub32:
12441 if (isRSB) {
12442 setFlags_D1_D2( ARMG_CC_OP_SUB, shop, rNt, condT );
12443 } else {
12444 setFlags_D1_D2( ARMG_CC_OP_SUB, rNt, shop, condT );
12445 }
12446 break;
12447 case Iop_And32: /* BIC and AND set the flags the same */
12448 case Iop_Or32:
12449 case Iop_Xor32:
12450 // oldV has been read just above
12451 setFlags_D1_D2_ND( ARMG_CC_OP_LOGIC,
12452 res, shco, oldV, condT );
12453 break;
12454 default:
12455 vassert(0);
12456 }
12457 }
12458 DIP("%s%s%s r%u, r%u, %s\n",
12459 name, nCC(INSN_COND), bitS ? "s" : "", rD, rN, dis_buf );
12460 goto decode_success;
12461 }
12462
12463 /* --------- MOV, MVN --------- */
12464 case BITS4(1,1,0,1): /* MOV: Rd = shifter_operand */
12465 case BITS4(1,1,1,1): { /* MVN: Rd = not(shifter_operand) */
12466 Bool isMVN = INSN(24,21) == BITS4(1,1,1,1);
sewardjf5800652011-10-14 15:44:00 +000012467 IRTemp jk = Ijk_Boring;
sewardj6c299f32009-12-31 18:00:12 +000012468 if (rN != 0)
12469 break; /* rN must be zero */
12470 ok = mk_shifter_operand(
12471 INSN(25,25), INSN(11,0),
12472 &shop, bitS ? &shco : NULL, dis_buf
12473 );
12474 if (!ok)
12475 break;
12476 res = newTemp(Ity_I32);
12477 assign( res, isMVN ? unop(Iop_Not32, mkexpr(shop))
12478 : mkexpr(shop) );
12479 if (bitS) {
12480 vassert(shco != IRTemp_INVALID);
12481 oldV = newTemp(Ity_I32);
12482 assign( oldV, mk_armg_calculate_flag_v() );
12483 } else {
12484 vassert(shco == IRTemp_INVALID);
12485 }
sewardjf5800652011-10-14 15:44:00 +000012486 /* According to the Cortex A8 TRM Sec. 5.2.1, MOV PC, r14 is a
12487 return for purposes of branch prediction. */
12488 if (!isMVN && INSN(11,0) == 14) {
12489 jk = Ijk_Ret;
12490 }
sewardj6c299f32009-12-31 18:00:12 +000012491 // can't safely read guest state after here
sewardjf5800652011-10-14 15:44:00 +000012492 putIRegA( rD, mkexpr(res), condT, jk );
sewardj6c299f32009-12-31 18:00:12 +000012493 /* Update the flags thunk if necessary */
12494 if (bitS) {
12495 setFlags_D1_D2_ND( ARMG_CC_OP_LOGIC,
12496 res, shco, oldV, condT );
12497 }
12498 DIP("%s%s%s r%u, %s\n",
12499 isMVN ? "mvn" : "mov",
12500 nCC(INSN_COND), bitS ? "s" : "", rD, dis_buf );
12501 goto decode_success;
12502 }
12503
12504 /* --------- CMP --------- */
12505 case BITS4(1,0,1,0): /* CMP: (void) Rn - shifter_operand */
12506 case BITS4(1,0,1,1): { /* CMN: (void) Rn + shifter_operand */
12507 Bool isCMN = INSN(24,21) == BITS4(1,0,1,1);
12508 if (rD != 0)
12509 break; /* rD must be zero */
12510 if (bitS == 0)
12511 break; /* if S (bit 20) is not set, it's not CMP/CMN */
12512 rNt = newTemp(Ity_I32);
sewardjd2664472010-08-22 12:44:20 +000012513 assign(rNt, getIRegA(rN));
sewardj6c299f32009-12-31 18:00:12 +000012514 ok = mk_shifter_operand(
12515 INSN(25,25), INSN(11,0),
12516 &shop, NULL, dis_buf
12517 );
12518 if (!ok)
12519 break;
sewardjd2664472010-08-22 12:44:20 +000012520 // can't safely read guest state after here
sewardj6c299f32009-12-31 18:00:12 +000012521 /* Update the flags thunk. */
12522 setFlags_D1_D2( isCMN ? ARMG_CC_OP_ADD : ARMG_CC_OP_SUB,
12523 rNt, shop, condT );
12524 DIP("%s%s r%u, %s\n",
12525 isCMN ? "cmn" : "cmp",
12526 nCC(INSN_COND), rN, dis_buf );
12527 goto decode_success;
12528 }
12529
12530 /* --------- TST --------- */
12531 case BITS4(1,0,0,0): /* TST: (void) Rn & shifter_operand */
12532 case BITS4(1,0,0,1): { /* TEQ: (void) Rn ^ shifter_operand */
12533 Bool isTEQ = INSN(24,21) == BITS4(1,0,0,1);
12534 if (rD != 0)
12535 break; /* rD must be zero */
12536 if (bitS == 0)
12537 break; /* if S (bit 20) is not set, it's not TST/TEQ */
12538 rNt = newTemp(Ity_I32);
sewardjd2664472010-08-22 12:44:20 +000012539 assign(rNt, getIRegA(rN));
sewardj6c299f32009-12-31 18:00:12 +000012540 ok = mk_shifter_operand(
12541 INSN(25,25), INSN(11,0),
12542 &shop, &shco, dis_buf
12543 );
12544 if (!ok)
12545 break;
12546 /* Update the flags thunk. */
12547 res = newTemp(Ity_I32);
12548 assign( res, binop(isTEQ ? Iop_Xor32 : Iop_And32,
12549 mkexpr(rNt), mkexpr(shop)) );
12550 oldV = newTemp(Ity_I32);
12551 assign( oldV, mk_armg_calculate_flag_v() );
sewardjd2664472010-08-22 12:44:20 +000012552 // can't safely read guest state after here
sewardj6c299f32009-12-31 18:00:12 +000012553 setFlags_D1_D2_ND( ARMG_CC_OP_LOGIC,
12554 res, shco, oldV, condT );
12555 DIP("%s%s r%u, %s\n",
12556 isTEQ ? "teq" : "tst",
12557 nCC(INSN_COND), rN, dis_buf );
12558 goto decode_success;
12559 }
12560
12561 /* --------- ADC, SBC, RSC --------- */
12562 case BITS4(0,1,0,1): /* ADC: Rd = Rn + shifter_operand + oldC */
12563 name = "adc"; goto rd_eq_rn_op_SO_op_oldC;
12564 case BITS4(0,1,1,0): /* SBC: Rd = Rn - shifter_operand - (oldC ^ 1) */
12565 name = "sbc"; goto rd_eq_rn_op_SO_op_oldC;
12566 case BITS4(0,1,1,1): /* RSC: Rd = shifter_operand - Rn - (oldC ^ 1) */
12567 name = "rsc"; goto rd_eq_rn_op_SO_op_oldC;
12568 rd_eq_rn_op_SO_op_oldC: {
sewardjd2664472010-08-22 12:44:20 +000012569 // FIXME: shco isn't used for anything. Get rid of it.
sewardj6c299f32009-12-31 18:00:12 +000012570 rNt = newTemp(Ity_I32);
sewardjd2664472010-08-22 12:44:20 +000012571 assign(rNt, getIRegA(rN));
sewardj6c299f32009-12-31 18:00:12 +000012572 ok = mk_shifter_operand(
12573 INSN(25,25), INSN(11,0),
12574 &shop, bitS ? &shco : NULL, dis_buf
12575 );
12576 if (!ok)
12577 break;
12578 oldC = newTemp(Ity_I32);
12579 assign( oldC, mk_armg_calculate_flag_c() );
12580 res = newTemp(Ity_I32);
12581 // compute the main result
12582 switch (INSN(24,21)) {
12583 case BITS4(0,1,0,1): /* ADC */
12584 assign(res,
12585 binop(Iop_Add32,
12586 binop(Iop_Add32, mkexpr(rNt), mkexpr(shop)),
12587 mkexpr(oldC) ));
12588 break;
12589 case BITS4(0,1,1,0): /* SBC */
12590 assign(res,
12591 binop(Iop_Sub32,
12592 binop(Iop_Sub32, mkexpr(rNt), mkexpr(shop)),
12593 binop(Iop_Xor32, mkexpr(oldC), mkU32(1)) ));
12594 break;
12595 case BITS4(0,1,1,1): /* RSC */
12596 assign(res,
12597 binop(Iop_Sub32,
12598 binop(Iop_Sub32, mkexpr(shop), mkexpr(rNt)),
12599 binop(Iop_Xor32, mkexpr(oldC), mkU32(1)) ));
12600 break;
12601 default:
12602 vassert(0);
12603 }
12604 // but don't commit it until after we've finished
12605 // all necessary reads from the guest state
12606 // now safe to put the main result
sewardjd2664472010-08-22 12:44:20 +000012607 putIRegA( rD, mkexpr(res), condT, Ijk_Boring );
sewardj6c299f32009-12-31 18:00:12 +000012608 // XXXX!! not safe to read any guest state after
12609 // this point (I think the code below doesn't do that).
12610 if (!bitS)
12611 vassert(shco == IRTemp_INVALID);
12612 /* Update the flags thunk if necessary */
12613 if (bitS) {
12614 vassert(shco != IRTemp_INVALID);
12615 switch (INSN(24,21)) {
12616 case BITS4(0,1,0,1): /* ADC */
12617 setFlags_D1_D2_ND( ARMG_CC_OP_ADC,
12618 rNt, shop, oldC, condT );
12619 break;
12620 case BITS4(0,1,1,0): /* SBC */
12621 setFlags_D1_D2_ND( ARMG_CC_OP_SBB,
12622 rNt, shop, oldC, condT );
12623 break;
12624 case BITS4(0,1,1,1): /* RSC */
12625 setFlags_D1_D2_ND( ARMG_CC_OP_SBB,
12626 shop, rNt, oldC, condT );
12627 break;
12628 default:
12629 vassert(0);
12630 }
12631 }
12632 DIP("%s%s%s r%u, r%u, %s\n",
12633 name, nCC(INSN_COND), bitS ? "s" : "", rD, rN, dis_buf );
12634 goto decode_success;
12635 }
12636
12637 /* --------- ??? --------- */
12638 default:
12639 break;
12640 }
12641 } /* if (0 == (INSN(27,20) & BITS8(1,1,0,0,0,0,0,0)) */
12642
12643 /* --------------------- Load/store (ubyte & word) -------- */
12644 // LDR STR LDRB STRB
12645 /* 31 27 23 19 15 11 6 4 3 # highest bit
12646 28 24 20 16 12
12647 A5-20 1 | 16 cond 0101 UB0L Rn Rd imm12
12648 A5-22 1 | 32 cond 0111 UBOL Rn Rd imm5 sh2 0 Rm
12649 A5-24 2 | 16 cond 0101 UB1L Rn Rd imm12
12650 A5-26 2 | 32 cond 0111 UB1L Rn Rd imm5 sh2 0 Rm
12651 A5-28 3 | 16 cond 0100 UB0L Rn Rd imm12
12652 A5-32 3 | 32 cond 0110 UB0L Rn Rd imm5 sh2 0 Rm
12653 */
12654 /* case coding:
12655 1 at-ea (access at ea)
12656 2 at-ea-then-upd (access at ea, then Rn = ea)
12657 3 at-Rn-then-upd (access at Rn, then Rn = ea)
12658 ea coding
12659 16 Rn +/- imm12
12660 32 Rn +/- Rm sh2 imm5
12661 */
12662 /* Quickly skip over all of this for hopefully most instructions */
12663 if ((INSN(27,24) & BITS4(1,1,0,0)) != BITS4(0,1,0,0))
12664 goto after_load_store_ubyte_or_word;
12665
12666 summary = 0;
12667
12668 /**/ if (INSN(27,24) == BITS4(0,1,0,1) && INSN(21,21) == 0) {
12669 summary = 1 | 16;
12670 }
12671 else if (INSN(27,24) == BITS4(0,1,1,1) && INSN(21,21) == 0
12672 && INSN(4,4) == 0) {
12673 summary = 1 | 32;
12674 }
12675 else if (INSN(27,24) == BITS4(0,1,0,1) && INSN(21,21) == 1) {
12676 summary = 2 | 16;
12677 }
12678 else if (INSN(27,24) == BITS4(0,1,1,1) && INSN(21,21) == 1
12679 && INSN(4,4) == 0) {
12680 summary = 2 | 32;
12681 }
12682 else if (INSN(27,24) == BITS4(0,1,0,0) && INSN(21,21) == 0) {
12683 summary = 3 | 16;
12684 }
12685 else if (INSN(27,24) == BITS4(0,1,1,0) && INSN(21,21) == 0
12686 && INSN(4,4) == 0) {
12687 summary = 3 | 32;
12688 }
12689 else goto after_load_store_ubyte_or_word;
12690
12691 { UInt rN = (insn >> 16) & 0xF; /* 19:16 */
12692 UInt rD = (insn >> 12) & 0xF; /* 15:12 */
12693 UInt rM = (insn >> 0) & 0xF; /* 3:0 */
12694 UInt bU = (insn >> 23) & 1; /* 23 */
12695 UInt bB = (insn >> 22) & 1; /* 22 */
12696 UInt bL = (insn >> 20) & 1; /* 20 */
12697 UInt imm12 = (insn >> 0) & 0xFFF; /* 11:0 */
12698 UInt imm5 = (insn >> 7) & 0x1F; /* 11:7 */
12699 UInt sh2 = (insn >> 5) & 3; /* 6:5 */
12700
12701 /* Skip some invalid cases, which would lead to two competing
12702 updates to the same register, or which are otherwise
12703 disallowed by the spec. */
12704 switch (summary) {
12705 case 1 | 16:
12706 break;
12707 case 1 | 32:
12708 if (rM == 15) goto after_load_store_ubyte_or_word;
12709 break;
12710 case 2 | 16: case 3 | 16:
12711 if (rN == 15) goto after_load_store_ubyte_or_word;
12712 if (bL == 1 && rN == rD) goto after_load_store_ubyte_or_word;
12713 break;
12714 case 2 | 32: case 3 | 32:
12715 if (rM == 15) goto after_load_store_ubyte_or_word;
12716 if (rN == 15) goto after_load_store_ubyte_or_word;
12717 if (rN == rM) goto after_load_store_ubyte_or_word;
12718 if (bL == 1 && rN == rD) goto after_load_store_ubyte_or_word;
12719 break;
12720 default:
12721 vassert(0);
12722 }
12723
12724 /* Now, we can't do a conditional load or store, since that very
12725 likely will generate an exception. So we have to take a side
12726 exit at this point if the condition is false. */
12727 if (condT != IRTemp_INVALID) {
sewardjd2664472010-08-22 12:44:20 +000012728 mk_skip_over_A32_if_cond_is_false( condT );
sewardj6c299f32009-12-31 18:00:12 +000012729 condT = IRTemp_INVALID;
12730 }
12731 /* Ok, now we're unconditional. Do the load or store. */
12732
12733 /* compute the effective address. Bind it to a tmp since we
12734 may need to use it twice. */
12735 IRExpr* eaE = NULL;
12736 switch (summary & 0xF0) {
12737 case 16:
12738 eaE = mk_EA_reg_plusminus_imm12( rN, bU, imm12, dis_buf );
12739 break;
12740 case 32:
12741 eaE = mk_EA_reg_plusminus_shifted_reg( rN, bU, rM, sh2, imm5,
12742 dis_buf );
12743 break;
12744 }
12745 vassert(eaE);
12746 IRTemp eaT = newTemp(Ity_I32);
12747 assign(eaT, eaE);
12748
12749 /* get the old Rn value */
12750 IRTemp rnT = newTemp(Ity_I32);
sewardjd2664472010-08-22 12:44:20 +000012751 assign(rnT, getIRegA(rN));
sewardj6c299f32009-12-31 18:00:12 +000012752
12753 /* decide on the transfer address */
12754 IRTemp taT = IRTemp_INVALID;
12755 switch (summary & 0x0F) {
12756 case 1: case 2: taT = eaT; break;
12757 case 3: taT = rnT; break;
12758 }
12759 vassert(taT != IRTemp_INVALID);
12760
12761 if (bL == 0) {
12762 /* Store. If necessary, update the base register before the
12763 store itself, so that the common idiom of "str rX, [sp,
12764 #-4]!" (store rX at sp-4, then do new sp = sp-4, a.k.a "push
12765 rX") doesn't cause Memcheck to complain that the access is
12766 below the stack pointer. Also, not updating sp before the
12767 store confuses Valgrind's dynamic stack-extending logic. So
12768 do it before the store. Hence we need to snarf the store
12769 data before doing the basereg update. */
12770
12771 /* get hold of the data to be stored */
12772 IRTemp rDt = newTemp(Ity_I32);
sewardjd2664472010-08-22 12:44:20 +000012773 assign(rDt, getIRegA(rD));
sewardj6c299f32009-12-31 18:00:12 +000012774
12775 /* Update Rn if necessary. */
12776 switch (summary & 0x0F) {
12777 case 2: case 3:
sewardjd2664472010-08-22 12:44:20 +000012778 putIRegA( rN, mkexpr(eaT), IRTemp_INVALID, Ijk_Boring );
sewardj6c299f32009-12-31 18:00:12 +000012779 break;
12780 }
12781
12782 /* generate the transfer */
12783 if (bB == 0) { // word store
12784 storeLE( mkexpr(taT), mkexpr(rDt) );
12785 } else { // byte store
12786 vassert(bB == 1);
12787 storeLE( mkexpr(taT), unop(Iop_32to8, mkexpr(rDt)) );
12788 }
12789
12790 } else {
12791 /* Load */
12792 vassert(bL == 1);
12793
12794 /* generate the transfer */
12795 if (bB == 0) { // word load
sewardjf5800652011-10-14 15:44:00 +000012796 IRTemp jk = Ijk_Boring;
12797 /* According to the Cortex A8 TRM Sec. 5.2.1, LDR(1) with r13 as the
12798 base register and PC as the destination register is a return for
12799 purposes of branch prediction.
12800 The ARM ARM Sec. C9.10.1 further specifies that it must use a
12801 post-increment by immediate addressing mode to be counted in
12802 event 0x0E (Procedure return).*/
12803 if (rN == 13 && summary == (3 | 16) && bB == 0) {
12804 jk = Ijk_Ret;
12805 }
sewardjd2664472010-08-22 12:44:20 +000012806 putIRegA( rD, loadLE(Ity_I32, mkexpr(taT)),
sewardjf5800652011-10-14 15:44:00 +000012807 IRTemp_INVALID, jk );
sewardj6c299f32009-12-31 18:00:12 +000012808 } else { // byte load
sewardjd2664472010-08-22 12:44:20 +000012809 vassert(bB == 1);
12810 putIRegA( rD, unop(Iop_8Uto32, loadLE(Ity_I8, mkexpr(taT))),
12811 IRTemp_INVALID, Ijk_Boring );
sewardj6c299f32009-12-31 18:00:12 +000012812 }
12813
12814 /* Update Rn if necessary. */
12815 switch (summary & 0x0F) {
12816 case 2: case 3:
12817 // should be assured by logic above:
12818 if (bL == 1)
12819 vassert(rD != rN); /* since we just wrote rD */
sewardjd2664472010-08-22 12:44:20 +000012820 putIRegA( rN, mkexpr(eaT), IRTemp_INVALID, Ijk_Boring );
sewardj6c299f32009-12-31 18:00:12 +000012821 break;
12822 }
12823 }
12824
12825 switch (summary & 0x0F) {
12826 case 1: DIP("%sr%s%s r%u, %s\n",
12827 bL == 0 ? "st" : "ld",
12828 bB == 0 ? "" : "b", nCC(INSN_COND), rD, dis_buf);
12829 break;
12830 case 2: DIP("%sr%s%s r%u, %s! (at-EA-then-Rn=EA)\n",
12831 bL == 0 ? "st" : "ld",
12832 bB == 0 ? "" : "b", nCC(INSN_COND), rD, dis_buf);
12833 break;
12834 case 3: DIP("%sr%s%s r%u, %s! (at-Rn-then-Rn=EA)\n",
12835 bL == 0 ? "st" : "ld",
12836 bB == 0 ? "" : "b", nCC(INSN_COND), rD, dis_buf);
12837 break;
12838 default: vassert(0);
12839 }
12840
12841 /* XXX deal with alignment constraints */
12842
12843 goto decode_success;
12844
12845 /* Complications:
12846
12847 For all loads: if the Amode specifies base register
12848 writeback, and the same register is specified for Rd and Rn,
12849 the results are UNPREDICTABLE.
12850
12851 For all loads and stores: if R15 is written, branch to
12852 that address afterwards.
12853
12854 STRB: straightforward
12855 LDRB: loaded data is zero extended
12856 STR: lowest 2 bits of address are ignored
12857 LDR: if the lowest 2 bits of the address are nonzero
12858 then the loaded value is rotated right by 8 * the lowest 2 bits
12859 */
12860 }
12861
12862 after_load_store_ubyte_or_word:
12863
12864 /* --------------------- Load/store (sbyte & hword) -------- */
12865 // LDRH LDRSH STRH LDRSB
12866 /* 31 27 23 19 15 11 7 3 # highest bit
12867 28 24 20 16 12 8 4 0
12868 A5-36 1 | 16 cond 0001 U10L Rn Rd im4h 1SH1 im4l
12869 A5-38 1 | 32 cond 0001 U00L Rn Rd 0000 1SH1 Rm
12870 A5-40 2 | 16 cond 0001 U11L Rn Rd im4h 1SH1 im4l
12871 A5-42 2 | 32 cond 0001 U01L Rn Rd 0000 1SH1 Rm
12872 A5-44 3 | 16 cond 0000 U10L Rn Rd im4h 1SH1 im4l
12873 A5-46 3 | 32 cond 0000 U00L Rn Rd 0000 1SH1 Rm
12874 */
12875 /* case coding:
12876 1 at-ea (access at ea)
12877 2 at-ea-then-upd (access at ea, then Rn = ea)
12878 3 at-Rn-then-upd (access at Rn, then Rn = ea)
12879 ea coding
12880 16 Rn +/- imm8
12881 32 Rn +/- Rm
12882 */
12883 /* Quickly skip over all of this for hopefully most instructions */
12884 if ((INSN(27,24) & BITS4(1,1,1,0)) != BITS4(0,0,0,0))
12885 goto after_load_store_sbyte_or_hword;
12886
12887 /* Check the "1SH1" thing. */
12888 if ((INSN(7,4) & BITS4(1,0,0,1)) != BITS4(1,0,0,1))
12889 goto after_load_store_sbyte_or_hword;
12890
12891 summary = 0;
12892
12893 /**/ if (INSN(27,24) == BITS4(0,0,0,1) && INSN(22,21) == BITS2(1,0)) {
12894 summary = 1 | 16;
12895 }
12896 else if (INSN(27,24) == BITS4(0,0,0,1) && INSN(22,21) == BITS2(0,0)) {
12897 summary = 1 | 32;
12898 }
12899 else if (INSN(27,24) == BITS4(0,0,0,1) && INSN(22,21) == BITS2(1,1)) {
12900 summary = 2 | 16;
12901 }
12902 else if (INSN(27,24) == BITS4(0,0,0,1) && INSN(22,21) == BITS2(0,1)) {
12903 summary = 2 | 32;
12904 }
12905 else if (INSN(27,24) == BITS4(0,0,0,0) && INSN(22,21) == BITS2(1,0)) {
12906 summary = 3 | 16;
12907 }
12908 else if (INSN(27,24) == BITS4(0,0,0,0) && INSN(22,21) == BITS2(0,0)) {
12909 summary = 3 | 32;
12910 }
12911 else goto after_load_store_sbyte_or_hword;
12912
12913 { UInt rN = (insn >> 16) & 0xF; /* 19:16 */
12914 UInt rD = (insn >> 12) & 0xF; /* 15:12 */
12915 UInt rM = (insn >> 0) & 0xF; /* 3:0 */
12916 UInt bU = (insn >> 23) & 1; /* 23 U=1 offset+, U=0 offset- */
12917 UInt bL = (insn >> 20) & 1; /* 20 L=1 load, L=0 store */
12918 UInt bH = (insn >> 5) & 1; /* H=1 halfword, H=0 byte */
12919 UInt bS = (insn >> 6) & 1; /* S=1 signed, S=0 unsigned */
12920 UInt imm8 = ((insn >> 4) & 0xF0) | (insn & 0xF); /* 11:8, 3:0 */
12921
12922 /* Skip combinations that are either meaningless or already
12923 handled by main word-or-unsigned-byte load-store
12924 instructions. */
12925 if (bS == 0 && bH == 0) /* "unsigned byte" */
12926 goto after_load_store_sbyte_or_hword;
12927 if (bS == 1 && bL == 0) /* "signed store" */
12928 goto after_load_store_sbyte_or_hword;
12929
12930 /* Require 11:8 == 0 for Rn +/- Rm cases */
12931 if ((summary & 32) != 0 && (imm8 & 0xF0) != 0)
12932 goto after_load_store_sbyte_or_hword;
12933
12934 /* Skip some invalid cases, which would lead to two competing
12935 updates to the same register, or which are otherwise
12936 disallowed by the spec. */
12937 switch (summary) {
12938 case 1 | 16:
12939 break;
12940 case 1 | 32:
12941 if (rM == 15) goto after_load_store_sbyte_or_hword;
12942 break;
12943 case 2 | 16: case 3 | 16:
12944 if (rN == 15) goto after_load_store_sbyte_or_hword;
12945 if (bL == 1 && rN == rD) goto after_load_store_sbyte_or_hword;
12946 break;
12947 case 2 | 32: case 3 | 32:
12948 if (rM == 15) goto after_load_store_sbyte_or_hword;
12949 if (rN == 15) goto after_load_store_sbyte_or_hword;
12950 if (rN == rM) goto after_load_store_sbyte_or_hword;
12951 if (bL == 1 && rN == rD) goto after_load_store_sbyte_or_hword;
12952 break;
12953 default:
12954 vassert(0);
12955 }
12956
12957 /* Now, we can't do a conditional load or store, since that very
12958 likely will generate an exception. So we have to take a side
12959 exit at this point if the condition is false. */
12960 if (condT != IRTemp_INVALID) {
sewardjd2664472010-08-22 12:44:20 +000012961 mk_skip_over_A32_if_cond_is_false( condT );
sewardj6c299f32009-12-31 18:00:12 +000012962 condT = IRTemp_INVALID;
12963 }
12964 /* Ok, now we're unconditional. Do the load or store. */
12965
12966 /* compute the effective address. Bind it to a tmp since we
12967 may need to use it twice. */
12968 IRExpr* eaE = NULL;
12969 switch (summary & 0xF0) {
12970 case 16:
12971 eaE = mk_EA_reg_plusminus_imm8( rN, bU, imm8, dis_buf );
12972 break;
12973 case 32:
12974 eaE = mk_EA_reg_plusminus_reg( rN, bU, rM, dis_buf );
12975 break;
12976 }
12977 vassert(eaE);
12978 IRTemp eaT = newTemp(Ity_I32);
12979 assign(eaT, eaE);
12980
12981 /* get the old Rn value */
12982 IRTemp rnT = newTemp(Ity_I32);
sewardjd2664472010-08-22 12:44:20 +000012983 assign(rnT, getIRegA(rN));
sewardj6c299f32009-12-31 18:00:12 +000012984
12985 /* decide on the transfer address */
12986 IRTemp taT = IRTemp_INVALID;
12987 switch (summary & 0x0F) {
12988 case 1: case 2: taT = eaT; break;
12989 case 3: taT = rnT; break;
12990 }
12991 vassert(taT != IRTemp_INVALID);
12992
12993 /* halfword store H 1 L 0 S 0
12994 uhalf load H 1 L 1 S 0
12995 shalf load H 1 L 1 S 1
12996 sbyte load H 0 L 1 S 1
12997 */
12998 HChar* name = NULL;
12999 /* generate the transfer */
13000 /**/ if (bH == 1 && bL == 0 && bS == 0) { // halfword store
sewardjd2664472010-08-22 12:44:20 +000013001 storeLE( mkexpr(taT), unop(Iop_32to16, getIRegA(rD)) );
sewardj6c299f32009-12-31 18:00:12 +000013002 name = "strh";
13003 }
13004 else if (bH == 1 && bL == 1 && bS == 0) { // uhalf load
sewardjd2664472010-08-22 12:44:20 +000013005 putIRegA( rD, unop(Iop_16Uto32, loadLE(Ity_I16, mkexpr(taT))),
13006 IRTemp_INVALID, Ijk_Boring );
sewardj6c299f32009-12-31 18:00:12 +000013007 name = "ldrh";
13008 }
13009 else if (bH == 1 && bL == 1 && bS == 1) { // shalf load
sewardjd2664472010-08-22 12:44:20 +000013010 putIRegA( rD, unop(Iop_16Sto32, loadLE(Ity_I16, mkexpr(taT))),
13011 IRTemp_INVALID, Ijk_Boring );
sewardj6c299f32009-12-31 18:00:12 +000013012 name = "ldrsh";
13013 }
13014 else if (bH == 0 && bL == 1 && bS == 1) { // sbyte load
sewardjd2664472010-08-22 12:44:20 +000013015 putIRegA( rD, unop(Iop_8Sto32, loadLE(Ity_I8, mkexpr(taT))),
13016 IRTemp_INVALID, Ijk_Boring );
sewardj6c299f32009-12-31 18:00:12 +000013017 name = "ldrsb";
13018 }
13019 else
13020 vassert(0); // should be assured by logic above
13021
13022 /* Update Rn if necessary. */
13023 switch (summary & 0x0F) {
13024 case 2: case 3:
13025 // should be assured by logic above:
13026 if (bL == 1)
13027 vassert(rD != rN); /* since we just wrote rD */
sewardjd2664472010-08-22 12:44:20 +000013028 putIRegA( rN, mkexpr(eaT), IRTemp_INVALID, Ijk_Boring );
sewardj6c299f32009-12-31 18:00:12 +000013029 break;
13030 }
13031
13032 switch (summary & 0x0F) {
13033 case 1: DIP("%s%s r%u, %s\n", name, nCC(INSN_COND), rD, dis_buf);
13034 break;
13035 case 2: DIP("%s%s r%u, %s! (at-EA-then-Rn=EA)\n",
13036 name, nCC(INSN_COND), rD, dis_buf);
13037 break;
13038 case 3: DIP("%s%s r%u, %s! (at-Rn-then-Rn=EA)\n",
13039 name, nCC(INSN_COND), rD, dis_buf);
13040 break;
13041 default: vassert(0);
13042 }
13043
13044 /* XXX deal with alignment constraints */
13045
13046 goto decode_success;
13047
13048 /* Complications:
13049
13050 For all loads: if the Amode specifies base register
13051 writeback, and the same register is specified for Rd and Rn,
13052 the results are UNPREDICTABLE.
13053
13054 For all loads and stores: if R15 is written, branch to
13055 that address afterwards.
13056
13057 Misaligned halfword stores => Unpredictable
13058 Misaligned halfword loads => Unpredictable
13059 */
13060 }
13061
13062 after_load_store_sbyte_or_hword:
13063
13064 /* --------------------- Load/store multiple -------------- */
13065 // LD/STMIA LD/STMIB LD/STMDA LD/STMDB
13066 // Remarkably complex and difficult to get right
13067 // match 27:20 as 100XX0WL
13068 if (BITS8(1,0,0,0,0,0,0,0) == (INSN(27,20) & BITS8(1,1,1,0,0,1,0,0))) {
13069 // A5-50 LD/STMIA cond 1000 10WL Rn RegList
13070 // A5-51 LD/STMIB cond 1001 10WL Rn RegList
13071 // A5-53 LD/STMDA cond 1000 00WL Rn RegList
13072 // A5-53 LD/STMDB cond 1001 00WL Rn RegList
13073 // 28 24 20 16 0
13074
sewardj6c299f32009-12-31 18:00:12 +000013075 UInt bINC = (insn >> 23) & 1;
13076 UInt bBEFORE = (insn >> 24) & 1;
13077
13078 UInt bL = (insn >> 20) & 1; /* load=1, store=0 */
13079 UInt bW = (insn >> 21) & 1; /* Rn wback=1, no wback=0 */
13080 UInt rN = (insn >> 16) & 0xF;
13081 UInt regList = insn & 0xFFFF;
13082 /* Skip some invalid cases, which would lead to two competing
13083 updates to the same register, or which are otherwise
13084 disallowed by the spec. Note the test above has required
13085 that S == 0, since that looks like a kernel-mode only thing.
13086 Done by forcing the real pattern, viz 100XXSWL to actually be
13087 100XX0WL. */
13088 if (rN == 15) goto after_load_store_multiple;
13089 // reglist can't be empty
13090 if (regList == 0) goto after_load_store_multiple;
13091 // if requested to writeback Rn, and this is a load instruction,
13092 // then Rn can't appear in RegList, since we'd have two competing
13093 // new values for Rn. We do however accept this case for store
13094 // instructions.
13095 if (bW == 1 && bL == 1 && ((1 << rN) & regList) > 0)
13096 goto after_load_store_multiple;
13097
13098 /* Now, we can't do a conditional load or store, since that very
13099 likely will generate an exception. So we have to take a side
13100 exit at this point if the condition is false. */
13101 if (condT != IRTemp_INVALID) {
sewardjd2664472010-08-22 12:44:20 +000013102 mk_skip_over_A32_if_cond_is_false( condT );
sewardj6c299f32009-12-31 18:00:12 +000013103 condT = IRTemp_INVALID;
13104 }
sewardj6c299f32009-12-31 18:00:12 +000013105
sewardjd2664472010-08-22 12:44:20 +000013106 /* Ok, now we're unconditional. Generate the IR. */
13107 mk_ldm_stm( True/*arm*/, rN, bINC, bBEFORE, bW, bL, regList );
sewardj6c299f32009-12-31 18:00:12 +000013108
sewardj6c299f32009-12-31 18:00:12 +000013109 DIP("%sm%c%c%s r%u%s, {0x%04x}\n",
13110 bL == 1 ? "ld" : "st", bINC ? 'i' : 'd', bBEFORE ? 'b' : 'a',
13111 nCC(INSN_COND),
13112 rN, bW ? "!" : "", regList);
13113
13114 goto decode_success;
13115 }
13116
13117 after_load_store_multiple:
13118
13119 /* --------------------- Control flow --------------------- */
13120 // B, BL (Branch, or Branch-and-Link, to immediate offset)
13121 //
13122 if (BITS8(1,0,1,0,0,0,0,0) == (INSN(27,20) & BITS8(1,1,1,0,0,0,0,0))) {
13123 UInt link = (insn >> 24) & 1;
13124 UInt uimm24 = insn & ((1<<24)-1);
13125 Int simm24 = (Int)uimm24;
sewardjd2664472010-08-22 12:44:20 +000013126 UInt dst = guest_R15_curr_instr_notENC + 8
13127 + (((simm24 << 8) >> 8) << 2);
sewardj6c299f32009-12-31 18:00:12 +000013128 IRJumpKind jk = link ? Ijk_Call : Ijk_Boring;
13129 if (link) {
sewardjd2664472010-08-22 12:44:20 +000013130 putIRegA(14, mkU32(guest_R15_curr_instr_notENC + 4),
13131 condT, Ijk_Boring);
sewardj6c299f32009-12-31 18:00:12 +000013132 }
13133 if (condT == IRTemp_INVALID) {
13134 /* unconditional transfer to 'dst'. See if we can simply
13135 continue tracing at the destination. */
13136 if (resteerOkFn( callback_opaque, (Addr64)dst )) {
13137 /* yes */
sewardj984d9b12010-01-15 10:53:21 +000013138 dres.whatNext = Dis_ResteerU;
sewardj6c299f32009-12-31 18:00:12 +000013139 dres.continueAt = (Addr64)dst;
13140 } else {
13141 /* no; terminate the SB at this point. */
sewardjc6f970f2012-04-02 21:54:49 +000013142 llPutIReg(15, mkU32(dst));
13143 dres.jk_StopHere = jk;
13144 dres.whatNext = Dis_StopHere;
sewardj6c299f32009-12-31 18:00:12 +000013145 }
13146 DIP("b%s 0x%x\n", link ? "l" : "", dst);
13147 } else {
13148 /* conditional transfer to 'dst' */
sewardj82f56882010-01-17 09:36:11 +000013149 HChar* comment = "";
13150
13151 /* First see if we can do some speculative chasing into one
13152 arm or the other. Be conservative and only chase if
13153 !link, that is, this is a normal conditional branch to a
13154 known destination. */
13155 if (!link
13156 && resteerCisOk
13157 && vex_control.guest_chase_cond
sewardjd2664472010-08-22 12:44:20 +000013158 && dst < guest_R15_curr_instr_notENC
sewardj82f56882010-01-17 09:36:11 +000013159 && resteerOkFn( callback_opaque, (Addr64)(Addr32)dst) ) {
13160 /* Speculation: assume this backward branch is taken. So
13161 we need to emit a side-exit to the insn following this
13162 one, on the negation of the condition, and continue at
13163 the branch target address (dst). */
13164 stmt( IRStmt_Exit( unop(Iop_Not1,
13165 unop(Iop_32to1, mkexpr(condT))),
13166 Ijk_Boring,
sewardjc6f970f2012-04-02 21:54:49 +000013167 IRConst_U32(guest_R15_curr_instr_notENC+4),
13168 OFFB_R15T ));
sewardj82f56882010-01-17 09:36:11 +000013169 dres.whatNext = Dis_ResteerC;
13170 dres.continueAt = (Addr64)(Addr32)dst;
13171 comment = "(assumed taken)";
13172 }
13173 else
13174 if (!link
13175 && resteerCisOk
13176 && vex_control.guest_chase_cond
sewardjd2664472010-08-22 12:44:20 +000013177 && dst >= guest_R15_curr_instr_notENC
sewardj82f56882010-01-17 09:36:11 +000013178 && resteerOkFn( callback_opaque,
sewardjd2664472010-08-22 12:44:20 +000013179 (Addr64)(Addr32)
13180 (guest_R15_curr_instr_notENC+4)) ) {
sewardj82f56882010-01-17 09:36:11 +000013181 /* Speculation: assume this forward branch is not taken.
13182 So we need to emit a side-exit to dst (the dest) and
13183 continue disassembling at the insn immediately
13184 following this one. */
13185 stmt( IRStmt_Exit( unop(Iop_32to1, mkexpr(condT)),
13186 Ijk_Boring,
sewardjc6f970f2012-04-02 21:54:49 +000013187 IRConst_U32(dst),
13188 OFFB_R15T ));
sewardj82f56882010-01-17 09:36:11 +000013189 dres.whatNext = Dis_ResteerC;
sewardjd2664472010-08-22 12:44:20 +000013190 dres.continueAt = (Addr64)(Addr32)
13191 (guest_R15_curr_instr_notENC+4);
sewardj82f56882010-01-17 09:36:11 +000013192 comment = "(assumed not taken)";
13193 }
13194 else {
13195 /* Conservative default translation - end the block at
13196 this point. */
13197 stmt( IRStmt_Exit( unop(Iop_32to1, mkexpr(condT)),
sewardjc6f970f2012-04-02 21:54:49 +000013198 jk, IRConst_U32(dst), OFFB_R15T ));
13199 llPutIReg(15, mkU32(guest_R15_curr_instr_notENC + 4));
13200 dres.jk_StopHere = Ijk_Boring;
13201 dres.whatNext = Dis_StopHere;
sewardj82f56882010-01-17 09:36:11 +000013202 }
13203 DIP("b%s%s 0x%x %s\n", link ? "l" : "", nCC(INSN_COND),
13204 dst, comment);
sewardj6c299f32009-12-31 18:00:12 +000013205 }
13206 goto decode_success;
13207 }
13208
sewardjd2664472010-08-22 12:44:20 +000013209 // B, BL (Branch, or Branch-and-Link, to a register)
13210 // NB: interworking branch
sewardj6c299f32009-12-31 18:00:12 +000013211 if (INSN(27,20) == BITS8(0,0,0,1,0,0,1,0)
13212 && INSN(19,12) == BITS8(1,1,1,1,1,1,1,1)
13213 && (INSN(11,4) == BITS8(1,1,1,1,0,0,1,1)
13214 || INSN(11,4) == BITS8(1,1,1,1,0,0,0,1))) {
sewardjb706a0f2011-07-19 08:20:24 +000013215 IRTemp dst = newTemp(Ity_I32);
sewardj6c299f32009-12-31 18:00:12 +000013216 UInt link = (INSN(11,4) >> 1) & 1;
13217 UInt rM = INSN(3,0);
13218 // we don't decode the case (link && rM == 15), as that's
13219 // Unpredictable.
13220 if (!(link && rM == 15)) {
13221 if (condT != IRTemp_INVALID) {
sewardjd2664472010-08-22 12:44:20 +000013222 mk_skip_over_A32_if_cond_is_false( condT );
sewardj6c299f32009-12-31 18:00:12 +000013223 }
sewardjd2664472010-08-22 12:44:20 +000013224 // rM contains an interworking address exactly as we require
13225 // (with continuation CPSR.T in bit 0), so we can use it
13226 // as-is, with no masking.
sewardjb706a0f2011-07-19 08:20:24 +000013227 assign( dst, getIRegA(rM) );
sewardj6c299f32009-12-31 18:00:12 +000013228 if (link) {
sewardjd2664472010-08-22 12:44:20 +000013229 putIRegA( 14, mkU32(guest_R15_curr_instr_notENC + 4),
13230 IRTemp_INVALID/*because AL*/, Ijk_Boring );
sewardj6c299f32009-12-31 18:00:12 +000013231 }
sewardjc6f970f2012-04-02 21:54:49 +000013232 llPutIReg(15, mkexpr(dst));
13233 dres.jk_StopHere = link ? Ijk_Call
13234 : (rM == 14 ? Ijk_Ret : Ijk_Boring);
13235 dres.whatNext = Dis_StopHere;
sewardj6c299f32009-12-31 18:00:12 +000013236 if (condT == IRTemp_INVALID) {
13237 DIP("b%sx r%u\n", link ? "l" : "", rM);
13238 } else {
13239 DIP("b%sx%s r%u\n", link ? "l" : "", nCC(INSN_COND), rM);
13240 }
sewardjc2c87162004-11-25 13:07:02 +000013241 goto decode_success;
13242 }
sewardj6c299f32009-12-31 18:00:12 +000013243 /* else: (link && rM == 15): just fall through */
sewardjc2c87162004-11-25 13:07:02 +000013244 }
cerionc60c01e2004-12-02 20:19:22 +000013245
sewardjd2664472010-08-22 12:44:20 +000013246 /* --- NB: ARM interworking branches are in NV space, hence
13247 are handled elsewhere by decode_NV_instruction.
13248 ---
13249 */
13250
sewardj6c299f32009-12-31 18:00:12 +000013251 /* --------------------- Clz --------------------- */
13252 // CLZ
13253 if (INSN(27,20) == BITS8(0,0,0,1,0,1,1,0)
13254 && INSN(19,16) == BITS4(1,1,1,1)
13255 && INSN(11,4) == BITS8(1,1,1,1,0,0,0,1)) {
13256 UInt rD = INSN(15,12);
13257 UInt rM = INSN(3,0);
13258 IRTemp arg = newTemp(Ity_I32);
13259 IRTemp res = newTemp(Ity_I32);
sewardjd2664472010-08-22 12:44:20 +000013260 assign(arg, getIRegA(rM));
sewardj6c299f32009-12-31 18:00:12 +000013261 assign(res, IRExpr_Mux0X(
13262 unop(Iop_1Uto8,binop(Iop_CmpEQ32, mkexpr(arg),
13263 mkU32(0))),
13264 unop(Iop_Clz32, mkexpr(arg)),
13265 mkU32(32)
13266 ));
sewardjd2664472010-08-22 12:44:20 +000013267 putIRegA(rD, mkexpr(res), condT, Ijk_Boring);
sewardj6c299f32009-12-31 18:00:12 +000013268 DIP("clz%s r%u, r%u\n", nCC(INSN_COND), rD, rM);
13269 goto decode_success;
cerionc60c01e2004-12-02 20:19:22 +000013270 }
cerionc60c01e2004-12-02 20:19:22 +000013271
sewardj6c299f32009-12-31 18:00:12 +000013272 /* --------------------- Mul etc --------------------- */
13273 // MUL
13274 if (BITS8(0,0,0,0,0,0,0,0) == (INSN(27,20) & BITS8(1,1,1,1,1,1,1,0))
13275 && INSN(15,12) == BITS4(0,0,0,0)
13276 && INSN(7,4) == BITS4(1,0,0,1)) {
13277 UInt bitS = (insn >> 20) & 1; /* 20:20 */
13278 UInt rD = INSN(19,16);
13279 UInt rS = INSN(11,8);
13280 UInt rM = INSN(3,0);
13281 if (rD == 15 || rM == 15 || rS == 15) {
13282 /* Unpredictable; don't decode; fall through */
13283 } else {
13284 IRTemp argL = newTemp(Ity_I32);
13285 IRTemp argR = newTemp(Ity_I32);
13286 IRTemp res = newTemp(Ity_I32);
13287 IRTemp oldC = IRTemp_INVALID;
13288 IRTemp oldV = IRTemp_INVALID;
sewardjd2664472010-08-22 12:44:20 +000013289 assign( argL, getIRegA(rM));
13290 assign( argR, getIRegA(rS));
sewardj6c299f32009-12-31 18:00:12 +000013291 assign( res, binop(Iop_Mul32, mkexpr(argL), mkexpr(argR)) );
13292 if (bitS) {
13293 oldC = newTemp(Ity_I32);
13294 assign(oldC, mk_armg_calculate_flag_c());
13295 oldV = newTemp(Ity_I32);
13296 assign(oldV, mk_armg_calculate_flag_v());
cerionb85e8bb2005-02-16 08:54:33 +000013297 }
sewardj6c299f32009-12-31 18:00:12 +000013298 // now update guest state
sewardjd2664472010-08-22 12:44:20 +000013299 putIRegA( rD, mkexpr(res), condT, Ijk_Boring );
sewardj6c299f32009-12-31 18:00:12 +000013300 if (bitS) {
13301 IRTemp pair = newTemp(Ity_I32);
13302 assign( pair, binop(Iop_Or32,
13303 binop(Iop_Shl32, mkexpr(oldC), mkU8(1)),
13304 mkexpr(oldV)) );
13305 setFlags_D1_ND( ARMG_CC_OP_MUL, res, pair, condT );
cerionb85e8bb2005-02-16 08:54:33 +000013306 }
sewardj6c299f32009-12-31 18:00:12 +000013307 DIP("mul%c%s r%u, r%u, r%u\n",
13308 bitS ? 's' : ' ', nCC(INSN_COND), rD, rM, rS);
13309 goto decode_success;
cerionb85e8bb2005-02-16 08:54:33 +000013310 }
sewardj6c299f32009-12-31 18:00:12 +000013311 /* fall through */
13312 }
cerionf7da63d2004-12-09 19:04:57 +000013313
sewardj6c299f32009-12-31 18:00:12 +000013314 // MLA, MLS
13315 if (BITS8(0,0,0,0,0,0,1,0) == (INSN(27,20) & BITS8(1,1,1,1,1,0,1,0))
13316 && INSN(7,4) == BITS4(1,0,0,1)) {
13317 UInt bitS = (insn >> 20) & 1; /* 20:20 */
13318 UInt isMLS = (insn >> 22) & 1; /* 22:22 */
13319 UInt rD = INSN(19,16);
13320 UInt rN = INSN(15,12);
13321 UInt rS = INSN(11,8);
13322 UInt rM = INSN(3,0);
13323 if (bitS == 1 && isMLS == 1) {
13324 /* This isn't allowed (MLS that sets flags). don't decode;
13325 fall through */
cerionb85e8bb2005-02-16 08:54:33 +000013326 }
sewardj6c299f32009-12-31 18:00:12 +000013327 else
13328 if (rD == 15 || rM == 15 || rS == 15 || rN == 15) {
13329 /* Unpredictable; don't decode; fall through */
13330 } else {
13331 IRTemp argL = newTemp(Ity_I32);
13332 IRTemp argR = newTemp(Ity_I32);
13333 IRTemp argP = newTemp(Ity_I32);
13334 IRTemp res = newTemp(Ity_I32);
13335 IRTemp oldC = IRTemp_INVALID;
13336 IRTemp oldV = IRTemp_INVALID;
sewardjd2664472010-08-22 12:44:20 +000013337 assign( argL, getIRegA(rM));
13338 assign( argR, getIRegA(rS));
13339 assign( argP, getIRegA(rN));
sewardj6c299f32009-12-31 18:00:12 +000013340 assign( res, binop(isMLS ? Iop_Sub32 : Iop_Add32,
13341 mkexpr(argP),
13342 binop(Iop_Mul32, mkexpr(argL), mkexpr(argR)) ));
13343 if (bitS) {
13344 vassert(!isMLS); // guaranteed above
13345 oldC = newTemp(Ity_I32);
13346 assign(oldC, mk_armg_calculate_flag_c());
13347 oldV = newTemp(Ity_I32);
13348 assign(oldV, mk_armg_calculate_flag_v());
13349 }
13350 // now update guest state
sewardjd2664472010-08-22 12:44:20 +000013351 putIRegA( rD, mkexpr(res), condT, Ijk_Boring );
sewardj6c299f32009-12-31 18:00:12 +000013352 if (bitS) {
13353 IRTemp pair = newTemp(Ity_I32);
13354 assign( pair, binop(Iop_Or32,
13355 binop(Iop_Shl32, mkexpr(oldC), mkU8(1)),
13356 mkexpr(oldV)) );
13357 setFlags_D1_ND( ARMG_CC_OP_MUL, res, pair, condT );
13358 }
13359 DIP("ml%c%c%s r%u, r%u, r%u, r%u\n",
sewardjd2664472010-08-22 12:44:20 +000013360 isMLS ? 's' : 'a', bitS ? 's' : ' ',
13361 nCC(INSN_COND), rD, rM, rS, rN);
sewardj6c299f32009-12-31 18:00:12 +000013362 goto decode_success;
13363 }
13364 /* fall through */
13365 }
13366
13367 // SMULL, UMULL
13368 if (BITS8(0,0,0,0,1,0,0,0) == (INSN(27,20) & BITS8(1,1,1,1,1,0,1,0))
13369 && INSN(7,4) == BITS4(1,0,0,1)) {
13370 UInt bitS = (insn >> 20) & 1; /* 20:20 */
13371 UInt rDhi = INSN(19,16);
13372 UInt rDlo = INSN(15,12);
13373 UInt rS = INSN(11,8);
13374 UInt rM = INSN(3,0);
13375 UInt isS = (INSN(27,20) >> 2) & 1; /* 22:22 */
13376 if (rDhi == 15 || rDlo == 15 || rM == 15 || rS == 15 || rDhi == rDlo) {
13377 /* Unpredictable; don't decode; fall through */
13378 } else {
13379 IRTemp argL = newTemp(Ity_I32);
13380 IRTemp argR = newTemp(Ity_I32);
13381 IRTemp res = newTemp(Ity_I64);
13382 IRTemp resHi = newTemp(Ity_I32);
13383 IRTemp resLo = newTemp(Ity_I32);
13384 IRTemp oldC = IRTemp_INVALID;
13385 IRTemp oldV = IRTemp_INVALID;
13386 IROp mulOp = isS ? Iop_MullS32 : Iop_MullU32;
sewardjd2664472010-08-22 12:44:20 +000013387 assign( argL, getIRegA(rM));
13388 assign( argR, getIRegA(rS));
sewardj6c299f32009-12-31 18:00:12 +000013389 assign( res, binop(mulOp, mkexpr(argL), mkexpr(argR)) );
13390 assign( resHi, unop(Iop_64HIto32, mkexpr(res)) );
13391 assign( resLo, unop(Iop_64to32, mkexpr(res)) );
13392 if (bitS) {
13393 oldC = newTemp(Ity_I32);
13394 assign(oldC, mk_armg_calculate_flag_c());
13395 oldV = newTemp(Ity_I32);
13396 assign(oldV, mk_armg_calculate_flag_v());
13397 }
13398 // now update guest state
sewardjd2664472010-08-22 12:44:20 +000013399 putIRegA( rDhi, mkexpr(resHi), condT, Ijk_Boring );
13400 putIRegA( rDlo, mkexpr(resLo), condT, Ijk_Boring );
sewardj6c299f32009-12-31 18:00:12 +000013401 if (bitS) {
13402 IRTemp pair = newTemp(Ity_I32);
13403 assign( pair, binop(Iop_Or32,
13404 binop(Iop_Shl32, mkexpr(oldC), mkU8(1)),
13405 mkexpr(oldV)) );
13406 setFlags_D1_D2_ND( ARMG_CC_OP_MULL, resLo, resHi, pair, condT );
13407 }
13408 DIP("%cmull%c%s r%u, r%u, r%u, r%u\n",
13409 isS ? 's' : 'u', bitS ? 's' : ' ',
13410 nCC(INSN_COND), rDlo, rDhi, rM, rS);
13411 goto decode_success;
13412 }
13413 /* fall through */
13414 }
13415
13416 // SMLAL, UMLAL
13417 if (BITS8(0,0,0,0,1,0,1,0) == (INSN(27,20) & BITS8(1,1,1,1,1,0,1,0))
13418 && INSN(7,4) == BITS4(1,0,0,1)) {
13419 UInt bitS = (insn >> 20) & 1; /* 20:20 */
13420 UInt rDhi = INSN(19,16);
13421 UInt rDlo = INSN(15,12);
13422 UInt rS = INSN(11,8);
13423 UInt rM = INSN(3,0);
13424 UInt isS = (INSN(27,20) >> 2) & 1; /* 22:22 */
13425 if (rDhi == 15 || rDlo == 15 || rM == 15 || rS == 15 || rDhi == rDlo) {
13426 /* Unpredictable; don't decode; fall through */
13427 } else {
13428 IRTemp argL = newTemp(Ity_I32);
13429 IRTemp argR = newTemp(Ity_I32);
13430 IRTemp old = newTemp(Ity_I64);
13431 IRTemp res = newTemp(Ity_I64);
13432 IRTemp resHi = newTemp(Ity_I32);
13433 IRTemp resLo = newTemp(Ity_I32);
13434 IRTemp oldC = IRTemp_INVALID;
13435 IRTemp oldV = IRTemp_INVALID;
13436 IROp mulOp = isS ? Iop_MullS32 : Iop_MullU32;
sewardjd2664472010-08-22 12:44:20 +000013437 assign( argL, getIRegA(rM));
13438 assign( argR, getIRegA(rS));
13439 assign( old, binop(Iop_32HLto64, getIRegA(rDhi), getIRegA(rDlo)) );
sewardj6c299f32009-12-31 18:00:12 +000013440 assign( res, binop(Iop_Add64,
13441 mkexpr(old),
13442 binop(mulOp, mkexpr(argL), mkexpr(argR))) );
13443 assign( resHi, unop(Iop_64HIto32, mkexpr(res)) );
13444 assign( resLo, unop(Iop_64to32, mkexpr(res)) );
13445 if (bitS) {
13446 oldC = newTemp(Ity_I32);
13447 assign(oldC, mk_armg_calculate_flag_c());
13448 oldV = newTemp(Ity_I32);
13449 assign(oldV, mk_armg_calculate_flag_v());
13450 }
13451 // now update guest state
sewardjd2664472010-08-22 12:44:20 +000013452 putIRegA( rDhi, mkexpr(resHi), condT, Ijk_Boring );
13453 putIRegA( rDlo, mkexpr(resLo), condT, Ijk_Boring );
sewardj6c299f32009-12-31 18:00:12 +000013454 if (bitS) {
13455 IRTemp pair = newTemp(Ity_I32);
13456 assign( pair, binop(Iop_Or32,
13457 binop(Iop_Shl32, mkexpr(oldC), mkU8(1)),
13458 mkexpr(oldV)) );
13459 setFlags_D1_D2_ND( ARMG_CC_OP_MULL, resLo, resHi, pair, condT );
13460 }
13461 DIP("%cmlal%c%s r%u, r%u, r%u, r%u\n",
13462 isS ? 's' : 'u', bitS ? 's' : ' ', nCC(INSN_COND),
13463 rDlo, rDhi, rM, rS);
13464 goto decode_success;
13465 }
13466 /* fall through */
13467 }
13468
13469 /* --------------------- Msr etc --------------------- */
13470
sewardj1f139f52010-08-29 12:33:02 +000013471 // MSR apsr, #imm
13472 if (INSN(27,20) == BITS8(0,0,1,1,0,0,1,0)
13473 && INSN(17,12) == BITS6(0,0,1,1,1,1)) {
13474 UInt write_ge = INSN(18,18);
13475 UInt write_nzcvq = INSN(19,19);
13476 if (write_nzcvq || write_ge) {
sewardj6c299f32009-12-31 18:00:12 +000013477 UInt imm = (INSN(11,0) >> 0) & 0xFF;
13478 UInt rot = 2 * ((INSN(11,0) >> 8) & 0xF);
13479 IRTemp immT = newTemp(Ity_I32);
13480 vassert(rot <= 30);
13481 imm = ROR32(imm, rot);
sewardj1f139f52010-08-29 12:33:02 +000013482 assign(immT, mkU32(imm));
13483 desynthesise_APSR( write_nzcvq, write_ge, immT, condT );
13484 DIP("msr%s cpsr%s%sf, #0x%08x\n", nCC(INSN_COND),
13485 write_nzcvq ? "f" : "", write_ge ? "g" : "", imm);
sewardj6c299f32009-12-31 18:00:12 +000013486 goto decode_success;
13487 }
13488 /* fall through */
13489 }
13490
sewardj1f139f52010-08-29 12:33:02 +000013491 // MSR apsr, reg
13492 if (INSN(27,20) == BITS8(0,0,0,1,0,0,1,0)
13493 && INSN(17,12) == BITS6(0,0,1,1,1,1)
13494 && INSN(11,4) == BITS8(0,0,0,0,0,0,0,0)) {
13495 UInt rN = INSN(3,0);
13496 UInt write_ge = INSN(18,18);
13497 UInt write_nzcvq = INSN(19,19);
13498 if (rN != 15 && (write_nzcvq || write_ge)) {
13499 IRTemp rNt = newTemp(Ity_I32);
13500 assign(rNt, getIRegA(rN));
13501 desynthesise_APSR( write_nzcvq, write_ge, rNt, condT );
13502 DIP("msr%s cpsr_%s%s, r%u\n", nCC(INSN_COND),
13503 write_nzcvq ? "f" : "", write_ge ? "g" : "", rN);
sewardjd2664472010-08-22 12:44:20 +000013504 goto decode_success;
13505 }
13506 /* fall through */
13507 }
13508
13509 // MRS rD, cpsr
sewardj1f139f52010-08-29 12:33:02 +000013510 if ((insn & 0x0FFF0FFF) == 0x010F0000) {
sewardj6c299f32009-12-31 18:00:12 +000013511 UInt rD = INSN(15,12);
sewardj1f139f52010-08-29 12:33:02 +000013512 if (rD != 15) {
13513 IRTemp apsr = synthesise_APSR();
13514 putIRegA( rD, mkexpr(apsr), condT, Ijk_Boring );
sewardj6c299f32009-12-31 18:00:12 +000013515 DIP("mrs%s r%u, cpsr\n", nCC(INSN_COND), rD);
13516 goto decode_success;
13517 }
13518 /* fall through */
13519 }
13520
13521 /* --------------------- Svc --------------------- */
13522 if (BITS8(1,1,1,1,0,0,0,0) == (INSN(27,20) & BITS8(1,1,1,1,0,0,0,0))) {
13523 UInt imm24 = (insn >> 0) & 0xFFFFFF;
13524 if (imm24 == 0) {
13525 /* A syscall. We can't do this conditionally, hence: */
13526 if (condT != IRTemp_INVALID) {
sewardjd2664472010-08-22 12:44:20 +000013527 mk_skip_over_A32_if_cond_is_false( condT );
sewardj6c299f32009-12-31 18:00:12 +000013528 }
13529 // AL after here
sewardjc6f970f2012-04-02 21:54:49 +000013530 llPutIReg(15, mkU32( guest_R15_curr_instr_notENC + 4 ));
13531 dres.jk_StopHere = Ijk_Sys_syscall;
13532 dres.whatNext = Dis_StopHere;
sewardj6c299f32009-12-31 18:00:12 +000013533 DIP("svc%s #0x%08x\n", nCC(INSN_COND), imm24);
13534 goto decode_success;
13535 }
13536 /* fall through */
13537 }
13538
13539 /* ------------------------ swp ------------------------ */
13540
13541 // SWP, SWPB
13542 if (BITS8(0,0,0,1,0,0,0,0) == (INSN(27,20) & BITS8(1,1,1,1,1,0,1,1))
13543 && BITS4(0,0,0,0) == INSN(11,8)
13544 && BITS4(1,0,0,1) == INSN(7,4)) {
13545 UInt rN = INSN(19,16);
13546 UInt rD = INSN(15,12);
13547 UInt rM = INSN(3,0);
13548 IRTemp tRn = newTemp(Ity_I32);
13549 IRTemp tNew = newTemp(Ity_I32);
13550 IRTemp tOld = IRTemp_INVALID;
13551 IRTemp tSC1 = newTemp(Ity_I1);
13552 UInt isB = (insn >> 22) & 1;
13553
13554 if (rD == 15 || rN == 15 || rM == 15 || rN == rM || rN == rD) {
13555 /* undecodable; fall through */
13556 } else {
13557 /* make unconditional */
13558 if (condT != IRTemp_INVALID) {
sewardjd2664472010-08-22 12:44:20 +000013559 mk_skip_over_A32_if_cond_is_false( condT );
sewardj6c299f32009-12-31 18:00:12 +000013560 condT = IRTemp_INVALID;
13561 }
13562 /* Ok, now we're unconditional. Generate a LL-SC loop. */
sewardjd2664472010-08-22 12:44:20 +000013563 assign(tRn, getIRegA(rN));
13564 assign(tNew, getIRegA(rM));
sewardj6c299f32009-12-31 18:00:12 +000013565 if (isB) {
13566 /* swpb */
13567 tOld = newTemp(Ity_I8);
13568 stmt( IRStmt_LLSC(Iend_LE, tOld, mkexpr(tRn),
13569 NULL/*=>isLL*/) );
13570 stmt( IRStmt_LLSC(Iend_LE, tSC1, mkexpr(tRn),
13571 unop(Iop_32to8, mkexpr(tNew))) );
13572 } else {
13573 /* swp */
13574 tOld = newTemp(Ity_I32);
13575 stmt( IRStmt_LLSC(Iend_LE, tOld, mkexpr(tRn),
13576 NULL/*=>isLL*/) );
13577 stmt( IRStmt_LLSC(Iend_LE, tSC1, mkexpr(tRn),
13578 mkexpr(tNew)) );
13579 }
13580 stmt( IRStmt_Exit(unop(Iop_Not1, mkexpr(tSC1)),
13581 /*Ijk_NoRedir*/Ijk_Boring,
sewardjc6f970f2012-04-02 21:54:49 +000013582 IRConst_U32(guest_R15_curr_instr_notENC),
13583 OFFB_R15T ));
sewardjd2664472010-08-22 12:44:20 +000013584 putIRegA(rD, isB ? unop(Iop_8Uto32, mkexpr(tOld)) : mkexpr(tOld),
13585 IRTemp_INVALID, Ijk_Boring);
sewardj6c299f32009-12-31 18:00:12 +000013586 DIP("swp%s%s r%u, r%u, [r%u]\n",
13587 isB ? "b" : "", nCC(INSN_COND), rD, rM, rN);
13588 goto decode_success;
13589 }
13590 /* fall through */
13591 }
13592
13593 /* ----------------------------------------------------------- */
sewardj6c299f32009-12-31 18:00:12 +000013594 /* -- ARMv6 instructions -- */
13595 /* ----------------------------------------------------------- */
13596
sewardjff7f5b72011-07-11 11:43:38 +000013597 /* ------------------- {ldr,str}ex{,b,h,d} ------------------- */
sewardj6c299f32009-12-31 18:00:12 +000013598
sewardjff7f5b72011-07-11 11:43:38 +000013599 // LDREXD, LDREX, LDREXH, LDREXB
13600 if (0x01900F9F == (insn & 0x0F900FFF)) {
13601 UInt rT = INSN(15,12);
13602 UInt rN = INSN(19,16);
13603 IRType ty = Ity_INVALID;
13604 IROp widen = Iop_INVALID;
13605 HChar* nm = NULL;
13606 Bool valid = True;
13607 switch (INSN(22,21)) {
13608 case 0: nm = ""; ty = Ity_I32; break;
13609 case 1: nm = "d"; ty = Ity_I64; break;
13610 case 2: nm = "b"; ty = Ity_I8; widen = Iop_8Uto32; break;
13611 case 3: nm = "h"; ty = Ity_I16; widen = Iop_16Uto32; break;
13612 default: vassert(0);
13613 }
13614 if (ty == Ity_I32 || ty == Ity_I16 || ty == Ity_I8) {
13615 if (rT == 15 || rN == 15)
13616 valid = False;
sewardj6c299f32009-12-31 18:00:12 +000013617 } else {
sewardjff7f5b72011-07-11 11:43:38 +000013618 vassert(ty == Ity_I64);
13619 if ((rT & 1) == 1 || rT == 14 || rN == 15)
13620 valid = False;
13621 }
13622 if (valid) {
sewardj6c299f32009-12-31 18:00:12 +000013623 IRTemp res;
13624 /* make unconditional */
13625 if (condT != IRTemp_INVALID) {
sewardjff7f5b72011-07-11 11:43:38 +000013626 mk_skip_over_A32_if_cond_is_false( condT );
13627 condT = IRTemp_INVALID;
sewardj6c299f32009-12-31 18:00:12 +000013628 }
13629 /* Ok, now we're unconditional. Do the load. */
sewardjff7f5b72011-07-11 11:43:38 +000013630 res = newTemp(ty);
13631 // FIXME: assumes little-endian guest
sewardjd2664472010-08-22 12:44:20 +000013632 stmt( IRStmt_LLSC(Iend_LE, res, getIRegA(rN),
13633 NULL/*this is a load*/) );
sewardjff7f5b72011-07-11 11:43:38 +000013634 if (ty == Ity_I64) {
13635 // FIXME: assumes little-endian guest
13636 putIRegA(rT+0, unop(Iop_64to32, mkexpr(res)),
13637 IRTemp_INVALID, Ijk_Boring);
13638 putIRegA(rT+1, unop(Iop_64HIto32, mkexpr(res)),
13639 IRTemp_INVALID, Ijk_Boring);
13640 DIP("ldrex%s%s r%u, r%u, [r%u]\n",
13641 nm, nCC(INSN_COND), rT+0, rT+1, rN);
13642 } else {
13643 putIRegA(rT, widen == Iop_INVALID
13644 ? mkexpr(res) : unop(widen, mkexpr(res)),
13645 IRTemp_INVALID, Ijk_Boring);
13646 DIP("ldrex%s%s r%u, [r%u]\n", nm, nCC(INSN_COND), rT, rN);
13647 }
sewardj6c299f32009-12-31 18:00:12 +000013648 goto decode_success;
13649 }
sewardjff7f5b72011-07-11 11:43:38 +000013650 /* undecodable; fall through */
sewardj6c299f32009-12-31 18:00:12 +000013651 }
13652
sewardjff7f5b72011-07-11 11:43:38 +000013653 // STREXD, STREX, STREXH, STREXB
13654 if (0x01800F90 == (insn & 0x0F900FF0)) {
13655 UInt rT = INSN(3,0);
13656 UInt rN = INSN(19,16);
13657 UInt rD = INSN(15,12);
13658 IRType ty = Ity_INVALID;
13659 IROp narrow = Iop_INVALID;
13660 HChar* nm = NULL;
13661 Bool valid = True;
13662 switch (INSN(22,21)) {
13663 case 0: nm = ""; ty = Ity_I32; break;
13664 case 1: nm = "d"; ty = Ity_I64; break;
13665 case 2: nm = "b"; ty = Ity_I8; narrow = Iop_32to8; break;
13666 case 3: nm = "h"; ty = Ity_I16; narrow = Iop_32to16; break;
13667 default: vassert(0);
13668 }
13669 if (ty == Ity_I32 || ty == Ity_I16 || ty == Ity_I8) {
13670 if (rD == 15 || rN == 15 || rT == 15
13671 || rD == rN || rD == rT)
13672 valid = False;
sewardj6c299f32009-12-31 18:00:12 +000013673 } else {
sewardjff7f5b72011-07-11 11:43:38 +000013674 vassert(ty == Ity_I64);
13675 if (rD == 15 || (rT & 1) == 1 || rT == 14 || rN == 15
13676 || rD == rN || rD == rT || rD == rT+1)
13677 valid = False;
13678 }
13679 if (valid) {
13680 IRTemp resSC1, resSC32, data;
sewardj6c299f32009-12-31 18:00:12 +000013681 /* make unconditional */
13682 if (condT != IRTemp_INVALID) {
sewardjd2664472010-08-22 12:44:20 +000013683 mk_skip_over_A32_if_cond_is_false( condT );
sewardj6c299f32009-12-31 18:00:12 +000013684 condT = IRTemp_INVALID;
13685 }
sewardj6c299f32009-12-31 18:00:12 +000013686 /* Ok, now we're unconditional. Do the store. */
sewardjff7f5b72011-07-11 11:43:38 +000013687 data = newTemp(ty);
13688 assign(data,
13689 ty == Ity_I64
13690 // FIXME: assumes little-endian guest
13691 ? binop(Iop_32HLto64, getIRegA(rT+1), getIRegA(rT+0))
13692 : narrow == Iop_INVALID
13693 ? getIRegA(rT)
13694 : unop(narrow, getIRegA(rT)));
sewardj6c299f32009-12-31 18:00:12 +000013695 resSC1 = newTemp(Ity_I1);
sewardjff7f5b72011-07-11 11:43:38 +000013696 // FIXME: assumes little-endian guest
13697 stmt( IRStmt_LLSC(Iend_LE, resSC1, getIRegA(rN), mkexpr(data)) );
sewardj6c299f32009-12-31 18:00:12 +000013698
13699 /* Set rD to 1 on failure, 0 on success. Currently we have
13700 resSC1 == 0 on failure, 1 on success. */
13701 resSC32 = newTemp(Ity_I32);
13702 assign(resSC32,
13703 unop(Iop_1Uto32, unop(Iop_Not1, mkexpr(resSC1))));
13704
sewardjd2664472010-08-22 12:44:20 +000013705 putIRegA(rD, mkexpr(resSC32),
13706 IRTemp_INVALID, Ijk_Boring);
sewardjff7f5b72011-07-11 11:43:38 +000013707 if (ty == Ity_I64) {
13708 DIP("strex%s%s r%u, r%u, r%u, [r%u]\n",
13709 nm, nCC(INSN_COND), rD, rT, rT+1, rN);
13710 } else {
13711 DIP("strex%s%s r%u, r%u, [r%u]\n",
13712 nm, nCC(INSN_COND), rD, rT, rN);
13713 }
sewardj6c299f32009-12-31 18:00:12 +000013714 goto decode_success;
13715 }
13716 /* fall through */
13717 }
13718
13719 /* --------------------- movw, movt --------------------- */
13720 if (0x03000000 == (insn & 0x0FF00000)
13721 || 0x03400000 == (insn & 0x0FF00000)) /* pray for CSE */ {
13722 UInt rD = INSN(15,12);
13723 UInt imm16 = (insn & 0xFFF) | ((insn >> 4) & 0x0000F000);
13724 UInt isT = (insn >> 22) & 1;
13725 if (rD == 15) {
13726 /* forget it */
13727 } else {
13728 if (isT) {
sewardjd2664472010-08-22 12:44:20 +000013729 putIRegA(rD,
13730 binop(Iop_Or32,
13731 binop(Iop_And32, getIRegA(rD), mkU32(0xFFFF)),
13732 mkU32(imm16 << 16)),
13733 condT, Ijk_Boring);
sewardj6c299f32009-12-31 18:00:12 +000013734 DIP("movt%s r%u, #0x%04x\n", nCC(INSN_COND), rD, imm16);
13735 goto decode_success;
13736 } else {
sewardjd2664472010-08-22 12:44:20 +000013737 putIRegA(rD, mkU32(imm16), condT, Ijk_Boring);
sewardj6c299f32009-12-31 18:00:12 +000013738 DIP("movw%s r%u, #0x%04x\n", nCC(INSN_COND), rD, imm16);
13739 goto decode_success;
13740 }
13741 }
13742 /* fall through */
13743 }
13744
sewardj1f139f52010-08-29 12:33:02 +000013745 /* ----------- uxtb, sxtb, uxth, sxth, uxtb16, sxtb16 ----------- */
13746 /* FIXME: this is an exact duplicate of the Thumb version. They
13747 should be commoned up. */
sewardj6c299f32009-12-31 18:00:12 +000013748 if (BITS8(0,1,1,0,1, 0,0,0) == (INSN(27,20) & BITS8(1,1,1,1,1,0,0,0))
13749 && BITS4(1,1,1,1) == INSN(19,16)
13750 && BITS4(0,1,1,1) == INSN(7,4)
13751 && BITS4(0,0, 0,0) == (INSN(11,8) & BITS4(0,0,1,1))) {
13752 UInt subopc = INSN(27,20) & BITS8(0,0,0,0,0, 1,1,1);
13753 if (subopc != BITS4(0,0,0,1) && subopc != BITS4(0,1,0,1)) {
13754 Int rot = (INSN(11,8) >> 2) & 3;
13755 UInt rM = INSN(3,0);
13756 UInt rD = INSN(15,12);
13757 IRTemp srcT = newTemp(Ity_I32);
13758 IRTemp rotT = newTemp(Ity_I32);
13759 IRTemp dstT = newTemp(Ity_I32);
13760 HChar* nm = "???";
sewardjd2664472010-08-22 12:44:20 +000013761 assign(srcT, getIRegA(rM));
sewardj6c299f32009-12-31 18:00:12 +000013762 assign(rotT, genROR32(srcT, 8 * rot)); /* 0, 8, 16 or 24 only */
13763 switch (subopc) {
13764 case BITS4(0,1,1,0): // UXTB
13765 assign(dstT, unop(Iop_8Uto32, unop(Iop_32to8, mkexpr(rotT))));
13766 nm = "uxtb";
13767 break;
13768 case BITS4(0,0,1,0): // SXTB
13769 assign(dstT, unop(Iop_8Sto32, unop(Iop_32to8, mkexpr(rotT))));
13770 nm = "sxtb";
13771 break;
13772 case BITS4(0,1,1,1): // UXTH
13773 assign(dstT, unop(Iop_16Uto32, unop(Iop_32to16, mkexpr(rotT))));
13774 nm = "uxth";
13775 break;
13776 case BITS4(0,0,1,1): // SXTH
13777 assign(dstT, unop(Iop_16Sto32, unop(Iop_32to16, mkexpr(rotT))));
13778 nm = "sxth";
13779 break;
13780 case BITS4(0,1,0,0): // UXTB16
13781 assign(dstT, binop(Iop_And32, mkexpr(rotT), mkU32(0x00FF00FF)));
13782 nm = "uxtb16";
13783 break;
13784 case BITS4(0,0,0,0): { // SXTB16
13785 IRTemp lo32 = newTemp(Ity_I32);
13786 IRTemp hi32 = newTemp(Ity_I32);
13787 assign(lo32, binop(Iop_And32, mkexpr(rotT), mkU32(0xFF)));
13788 assign(hi32, binop(Iop_Shr32, mkexpr(rotT), mkU8(16)));
13789 assign(
13790 dstT,
13791 binop(Iop_Or32,
13792 binop(Iop_And32,
13793 unop(Iop_8Sto32,
13794 unop(Iop_32to8, mkexpr(lo32))),
13795 mkU32(0xFFFF)),
13796 binop(Iop_Shl32,
13797 unop(Iop_8Sto32,
13798 unop(Iop_32to8, mkexpr(hi32))),
13799 mkU8(16))
13800 ));
sewardj1f139f52010-08-29 12:33:02 +000013801 nm = "sxtb16";
sewardj6c299f32009-12-31 18:00:12 +000013802 break;
13803 }
13804 default:
13805 vassert(0); // guarded by "if" above
13806 }
sewardjd2664472010-08-22 12:44:20 +000013807 putIRegA(rD, mkexpr(dstT), condT, Ijk_Boring);
sewardj6c299f32009-12-31 18:00:12 +000013808 DIP("%s%s r%u, r%u, ROR #%u\n", nm, nCC(INSN_COND), rD, rM, rot);
13809 goto decode_success;
13810 }
13811 /* fall through */
13812 }
13813
13814 /* ------------------- bfi, bfc ------------------- */
13815 if (BITS8(0,1,1,1,1,1,0, 0) == (INSN(27,20) & BITS8(1,1,1,1,1,1,1,0))
13816 && BITS4(0, 0,0,1) == (INSN(7,4) & BITS4(0,1,1,1))) {
13817 UInt rD = INSN(15,12);
13818 UInt rN = INSN(3,0);
13819 UInt msb = (insn >> 16) & 0x1F; /* 20:16 */
13820 UInt lsb = (insn >> 7) & 0x1F; /* 11:7 */
13821 if (rD == 15 || msb < lsb) {
13822 /* undecodable; fall through */
13823 } else {
13824 IRTemp src = newTemp(Ity_I32);
13825 IRTemp olddst = newTemp(Ity_I32);
13826 IRTemp newdst = newTemp(Ity_I32);
13827 UInt mask = 1 << (msb - lsb);
13828 mask = (mask - 1) + mask;
13829 vassert(mask != 0); // guaranteed by "msb < lsb" check above
13830 mask <<= lsb;
13831
sewardjd2664472010-08-22 12:44:20 +000013832 assign(src, rN == 15 ? mkU32(0) : getIRegA(rN));
13833 assign(olddst, getIRegA(rD));
sewardj6c299f32009-12-31 18:00:12 +000013834 assign(newdst,
13835 binop(Iop_Or32,
13836 binop(Iop_And32,
13837 binop(Iop_Shl32, mkexpr(src), mkU8(lsb)),
13838 mkU32(mask)),
13839 binop(Iop_And32,
13840 mkexpr(olddst),
13841 mkU32(~mask)))
13842 );
13843
sewardjd2664472010-08-22 12:44:20 +000013844 putIRegA(rD, mkexpr(newdst), condT, Ijk_Boring);
sewardj6c299f32009-12-31 18:00:12 +000013845
13846 if (rN == 15) {
13847 DIP("bfc%s r%u, #%u, #%u\n",
13848 nCC(INSN_COND), rD, lsb, msb-lsb+1);
13849 } else {
13850 DIP("bfi%s r%u, r%u, #%u, #%u\n",
13851 nCC(INSN_COND), rD, rN, lsb, msb-lsb+1);
13852 }
13853 goto decode_success;
13854 }
13855 /* fall through */
13856 }
13857
13858 /* ------------------- {u,s}bfx ------------------- */
13859 if (BITS8(0,1,1,1,1,0,1,0) == (INSN(27,20) & BITS8(1,1,1,1,1,0,1,0))
13860 && BITS4(0,1,0,1) == (INSN(7,4) & BITS4(0,1,1,1))) {
13861 UInt rD = INSN(15,12);
13862 UInt rN = INSN(3,0);
13863 UInt wm1 = (insn >> 16) & 0x1F; /* 20:16 */
13864 UInt lsb = (insn >> 7) & 0x1F; /* 11:7 */
13865 UInt msb = lsb + wm1;
13866 UInt isU = (insn >> 22) & 1; /* 22:22 */
13867 if (rD == 15 || rN == 15 || msb >= 32) {
13868 /* undecodable; fall through */
13869 } else {
13870 IRTemp src = newTemp(Ity_I32);
13871 IRTemp tmp = newTemp(Ity_I32);
13872 IRTemp res = newTemp(Ity_I32);
13873 UInt mask = ((1 << wm1) - 1) + (1 << wm1);
13874 vassert(msb >= 0 && msb <= 31);
13875 vassert(mask != 0); // guaranteed by msb being in 0 .. 31 inclusive
13876
sewardjd2664472010-08-22 12:44:20 +000013877 assign(src, getIRegA(rN));
sewardj6c299f32009-12-31 18:00:12 +000013878 assign(tmp, binop(Iop_And32,
13879 binop(Iop_Shr32, mkexpr(src), mkU8(lsb)),
13880 mkU32(mask)));
13881 assign(res, binop(isU ? Iop_Shr32 : Iop_Sar32,
13882 binop(Iop_Shl32, mkexpr(tmp), mkU8(31-wm1)),
13883 mkU8(31-wm1)));
13884
sewardjd2664472010-08-22 12:44:20 +000013885 putIRegA(rD, mkexpr(res), condT, Ijk_Boring);
sewardj6c299f32009-12-31 18:00:12 +000013886
13887 DIP("%s%s r%u, r%u, #%u, #%u\n",
13888 isU ? "ubfx" : "sbfx",
13889 nCC(INSN_COND), rD, rN, lsb, wm1 + 1);
13890 goto decode_success;
13891 }
13892 /* fall through */
13893 }
13894
sewardj6c299f32009-12-31 18:00:12 +000013895 /* --------------------- Load/store doubleword ------------- */
13896 // LDRD STRD
13897 /* 31 27 23 19 15 11 7 3 # highest bit
13898 28 24 20 16 12 8 4 0
13899 A5-36 1 | 16 cond 0001 U100 Rn Rd im4h 11S1 im4l
13900 A5-38 1 | 32 cond 0001 U000 Rn Rd 0000 11S1 Rm
13901 A5-40 2 | 16 cond 0001 U110 Rn Rd im4h 11S1 im4l
13902 A5-42 2 | 32 cond 0001 U010 Rn Rd 0000 11S1 Rm
13903 A5-44 3 | 16 cond 0000 U100 Rn Rd im4h 11S1 im4l
13904 A5-46 3 | 32 cond 0000 U000 Rn Rd 0000 11S1 Rm
13905 */
13906 /* case coding:
13907 1 at-ea (access at ea)
13908 2 at-ea-then-upd (access at ea, then Rn = ea)
13909 3 at-Rn-then-upd (access at Rn, then Rn = ea)
13910 ea coding
13911 16 Rn +/- imm8
13912 32 Rn +/- Rm
13913 */
13914 /* Quickly skip over all of this for hopefully most instructions */
13915 if ((INSN(27,24) & BITS4(1,1,1,0)) != BITS4(0,0,0,0))
13916 goto after_load_store_doubleword;
13917
13918 /* Check the "11S1" thing. */
13919 if ((INSN(7,4) & BITS4(1,1,0,1)) != BITS4(1,1,0,1))
13920 goto after_load_store_doubleword;
13921
13922 summary = 0;
13923
13924 /**/ if (INSN(27,24) == BITS4(0,0,0,1) && INSN(22,20) == BITS3(1,0,0)) {
13925 summary = 1 | 16;
13926 }
13927 else if (INSN(27,24) == BITS4(0,0,0,1) && INSN(22,20) == BITS3(0,0,0)) {
13928 summary = 1 | 32;
13929 }
13930 else if (INSN(27,24) == BITS4(0,0,0,1) && INSN(22,20) == BITS3(1,1,0)) {
13931 summary = 2 | 16;
13932 }
13933 else if (INSN(27,24) == BITS4(0,0,0,1) && INSN(22,20) == BITS3(0,1,0)) {
13934 summary = 2 | 32;
13935 }
13936 else if (INSN(27,24) == BITS4(0,0,0,0) && INSN(22,20) == BITS3(1,0,0)) {
13937 summary = 3 | 16;
13938 }
13939 else if (INSN(27,24) == BITS4(0,0,0,0) && INSN(22,20) == BITS3(0,0,0)) {
13940 summary = 3 | 32;
sewardj6c299f32009-12-31 18:00:12 +000013941 }
13942 else goto after_load_store_doubleword;
13943
13944 { UInt rN = (insn >> 16) & 0xF; /* 19:16 */
13945 UInt rD = (insn >> 12) & 0xF; /* 15:12 */
13946 UInt rM = (insn >> 0) & 0xF; /* 3:0 */
13947 UInt bU = (insn >> 23) & 1; /* 23 U=1 offset+, U=0 offset- */
13948 UInt bS = (insn >> 5) & 1; /* S=1 store, S=0 load */
13949 UInt imm8 = ((insn >> 4) & 0xF0) | (insn & 0xF); /* 11:8, 3:0 */
13950
13951 /* Require rD to be an even numbered register */
13952 if ((rD & 1) != 0)
13953 goto after_load_store_doubleword;
13954
13955 /* Require 11:8 == 0 for Rn +/- Rm cases */
13956 if ((summary & 32) != 0 && (imm8 & 0xF0) != 0)
13957 goto after_load_store_doubleword;
13958
13959 /* Skip some invalid cases, which would lead to two competing
13960 updates to the same register, or which are otherwise
13961 disallowed by the spec. */
13962 switch (summary) {
13963 case 1 | 16:
13964 break;
13965 case 1 | 32:
13966 if (rM == 15) goto after_load_store_doubleword;
13967 break;
13968 case 2 | 16: case 3 | 16:
13969 if (rN == 15) goto after_load_store_doubleword;
13970 if (bS == 0 && (rN == rD || rN == rD+1))
13971 goto after_load_store_doubleword;
13972 break;
13973 case 2 | 32: case 3 | 32:
13974 if (rM == 15) goto after_load_store_doubleword;
13975 if (rN == 15) goto after_load_store_doubleword;
13976 if (rN == rM) goto after_load_store_doubleword;
13977 if (bS == 0 && (rN == rD || rN == rD+1))
13978 goto after_load_store_doubleword;
13979 break;
13980 default:
13981 vassert(0);
13982 }
13983
13984 /* Now, we can't do a conditional load or store, since that very
13985 likely will generate an exception. So we have to take a side
13986 exit at this point if the condition is false. */
13987 if (condT != IRTemp_INVALID) {
sewardjd2664472010-08-22 12:44:20 +000013988 mk_skip_over_A32_if_cond_is_false( condT );
sewardj6c299f32009-12-31 18:00:12 +000013989 condT = IRTemp_INVALID;
13990 }
13991 /* Ok, now we're unconditional. Do the load or store. */
13992
13993 /* compute the effective address. Bind it to a tmp since we
13994 may need to use it twice. */
13995 IRExpr* eaE = NULL;
13996 switch (summary & 0xF0) {
13997 case 16:
13998 eaE = mk_EA_reg_plusminus_imm8( rN, bU, imm8, dis_buf );
13999 break;
14000 case 32:
14001 eaE = mk_EA_reg_plusminus_reg( rN, bU, rM, dis_buf );
14002 break;
14003 }
14004 vassert(eaE);
14005 IRTemp eaT = newTemp(Ity_I32);
14006 assign(eaT, eaE);
14007
14008 /* get the old Rn value */
14009 IRTemp rnT = newTemp(Ity_I32);
sewardjd2664472010-08-22 12:44:20 +000014010 assign(rnT, getIRegA(rN));
sewardj6c299f32009-12-31 18:00:12 +000014011
14012 /* decide on the transfer address */
14013 IRTemp taT = IRTemp_INVALID;
14014 switch (summary & 0x0F) {
14015 case 1: case 2: taT = eaT; break;
14016 case 3: taT = rnT; break;
14017 }
14018 vassert(taT != IRTemp_INVALID);
14019
14020 /* XXX deal with alignment constraints */
14021 /* XXX: but the A8 doesn't seem to trap for misaligned loads, so,
14022 ignore alignment issues for the time being. */
14023
14024 /* doubleword store S 1
14025 doubleword load S 0
14026 */
14027 HChar* name = NULL;
14028 /* generate the transfers */
14029 if (bS == 1) { // doubleword store
sewardjd2664472010-08-22 12:44:20 +000014030 storeLE( binop(Iop_Add32, mkexpr(taT), mkU32(0)), getIRegA(rD+0) );
14031 storeLE( binop(Iop_Add32, mkexpr(taT), mkU32(4)), getIRegA(rD+1) );
sewardj6c299f32009-12-31 18:00:12 +000014032 name = "strd";
14033 } else { // doubleword load
sewardjd2664472010-08-22 12:44:20 +000014034 putIRegA( rD+0,
14035 loadLE(Ity_I32, binop(Iop_Add32, mkexpr(taT), mkU32(0))),
14036 IRTemp_INVALID, Ijk_Boring );
14037 putIRegA( rD+1,
14038 loadLE(Ity_I32, binop(Iop_Add32, mkexpr(taT), mkU32(4))),
14039 IRTemp_INVALID, Ijk_Boring );
sewardj6c299f32009-12-31 18:00:12 +000014040 name = "ldrd";
14041 }
14042
14043 /* Update Rn if necessary. */
14044 switch (summary & 0x0F) {
14045 case 2: case 3:
14046 // should be assured by logic above:
14047 if (bS == 0) {
14048 vassert(rD+0 != rN); /* since we just wrote rD+0 */
14049 vassert(rD+1 != rN); /* since we just wrote rD+1 */
14050 }
sewardjd2664472010-08-22 12:44:20 +000014051 putIRegA( rN, mkexpr(eaT), IRTemp_INVALID, Ijk_Boring );
sewardj6c299f32009-12-31 18:00:12 +000014052 break;
14053 }
14054
14055 switch (summary & 0x0F) {
14056 case 1: DIP("%s%s r%u, %s\n", name, nCC(INSN_COND), rD, dis_buf);
14057 break;
14058 case 2: DIP("%s%s r%u, %s! (at-EA-then-Rn=EA)\n",
14059 name, nCC(INSN_COND), rD, dis_buf);
14060 break;
14061 case 3: DIP("%s%s r%u, %s! (at-Rn-then-Rn=EA)\n",
14062 name, nCC(INSN_COND), rD, dis_buf);
14063 break;
14064 default: vassert(0);
14065 }
14066
14067 goto decode_success;
14068 }
14069
14070 after_load_store_doubleword:
14071
sewardj04ac5de2010-03-08 14:49:03 +000014072 /* ------------------- {s,u}xtab ------------- */
14073 if (BITS8(0,1,1,0,1,0,1,0) == (INSN(27,20) & BITS8(1,1,1,1,1,0,1,1))
sewardj6c299f32009-12-31 18:00:12 +000014074 && BITS4(0,0,0,0) == (INSN(11,8) & BITS4(0,0,1,1))
14075 && BITS4(0,1,1,1) == INSN(7,4)) {
14076 UInt rN = INSN(19,16);
14077 UInt rD = INSN(15,12);
14078 UInt rM = INSN(3,0);
14079 UInt rot = (insn >> 10) & 3;
sewardj04ac5de2010-03-08 14:49:03 +000014080 UInt isU = INSN(22,22);
14081 if (rN == 15/*it's {S,U}XTB*/ || rD == 15 || rM == 15) {
sewardj6c299f32009-12-31 18:00:12 +000014082 /* undecodable; fall through */
14083 } else {
14084 IRTemp srcL = newTemp(Ity_I32);
14085 IRTemp srcR = newTemp(Ity_I32);
14086 IRTemp res = newTemp(Ity_I32);
sewardjd2664472010-08-22 12:44:20 +000014087 assign(srcR, getIRegA(rM));
14088 assign(srcL, getIRegA(rN));
sewardj6c299f32009-12-31 18:00:12 +000014089 assign(res, binop(Iop_Add32,
14090 mkexpr(srcL),
sewardj04ac5de2010-03-08 14:49:03 +000014091 unop(isU ? Iop_8Uto32 : Iop_8Sto32,
sewardj6c299f32009-12-31 18:00:12 +000014092 unop(Iop_32to8,
14093 genROR32(srcR, 8 * rot)))));
sewardjd2664472010-08-22 12:44:20 +000014094 putIRegA(rD, mkexpr(res), condT, Ijk_Boring);
sewardj04ac5de2010-03-08 14:49:03 +000014095 DIP("%cxtab%s r%u, r%u, r%u, ror #%u\n",
14096 isU ? 'u' : 's', nCC(INSN_COND), rD, rN, rM, rot);
sewardj6c299f32009-12-31 18:00:12 +000014097 goto decode_success;
14098 }
14099 /* fall through */
14100 }
14101
sewardj04ac5de2010-03-08 14:49:03 +000014102 /* ------------------- {s,u}xtah ------------- */
14103 if (BITS8(0,1,1,0,1,0,1,1) == (INSN(27,20) & BITS8(1,1,1,1,1,0,1,1))
sewardj6c299f32009-12-31 18:00:12 +000014104 && BITS4(0,0,0,0) == (INSN(11,8) & BITS4(0,0,1,1))
14105 && BITS4(0,1,1,1) == INSN(7,4)) {
14106 UInt rN = INSN(19,16);
14107 UInt rD = INSN(15,12);
14108 UInt rM = INSN(3,0);
14109 UInt rot = (insn >> 10) & 3;
sewardj04ac5de2010-03-08 14:49:03 +000014110 UInt isU = INSN(22,22);
14111 if (rN == 15/*it's {S,U}XTH*/ || rD == 15 || rM == 15) {
sewardj6c299f32009-12-31 18:00:12 +000014112 /* undecodable; fall through */
14113 } else {
14114 IRTemp srcL = newTemp(Ity_I32);
14115 IRTemp srcR = newTemp(Ity_I32);
14116 IRTemp res = newTemp(Ity_I32);
sewardjd2664472010-08-22 12:44:20 +000014117 assign(srcR, getIRegA(rM));
14118 assign(srcL, getIRegA(rN));
sewardj6c299f32009-12-31 18:00:12 +000014119 assign(res, binop(Iop_Add32,
14120 mkexpr(srcL),
sewardj04ac5de2010-03-08 14:49:03 +000014121 unop(isU ? Iop_16Uto32 : Iop_16Sto32,
sewardj6c299f32009-12-31 18:00:12 +000014122 unop(Iop_32to16,
14123 genROR32(srcR, 8 * rot)))));
sewardjd2664472010-08-22 12:44:20 +000014124 putIRegA(rD, mkexpr(res), condT, Ijk_Boring);
sewardj6c299f32009-12-31 18:00:12 +000014125
sewardj04ac5de2010-03-08 14:49:03 +000014126 DIP("%cxtah%s r%u, r%u, r%u, ror #%u\n",
14127 isU ? 'u' : 's', nCC(INSN_COND), rD, rN, rM, rot);
sewardj6c299f32009-12-31 18:00:12 +000014128 goto decode_success;
14129 }
14130 /* fall through */
14131 }
14132
sewardjdb1c20a2010-09-22 22:26:40 +000014133 /* ------------------- rev16, rev ------------------ */
14134 if (INSN(27,16) == 0x6BF
14135 && (INSN(11,4) == 0xFB/*rev16*/ || INSN(11,4) == 0xF3/*rev*/)) {
14136 Bool isREV = INSN(11,4) == 0xF3;
14137 UInt rM = INSN(3,0);
14138 UInt rD = INSN(15,12);
14139 if (rM != 15 && rD != 15) {
14140 IRTemp rMt = newTemp(Ity_I32);
14141 assign(rMt, getIRegA(rM));
sewardj27312d32010-09-26 00:48:41 +000014142 IRTemp res = isREV ? gen_REV(rMt) : gen_REV16(rMt);
14143 putIRegA(rD, mkexpr(res), condT, Ijk_Boring);
sewardjdb1c20a2010-09-22 22:26:40 +000014144 DIP("rev%s%s r%u, r%u\n", isREV ? "" : "16",
14145 nCC(INSN_COND), rD, rM);
14146 goto decode_success;
14147 }
14148 }
14149
sewardj389239a2010-09-24 21:59:55 +000014150 /* ------------------- rbit ------------------ */
14151 if (INSN(27,16) == 0x6FF && INSN(11,4) == 0xF3) {
14152 UInt rD = INSN(15,12);
14153 UInt rM = INSN(3,0);
14154 if (rD != 15 && rM != 15) {
14155 IRTemp arg = newTemp(Ity_I32);
14156 assign(arg, getIRegA(rM));
14157 IRTemp res = gen_BITREV(arg);
14158 putIRegA(rD, mkexpr(res), condT, Ijk_Boring);
14159 DIP("rbit r%u, r%u\n", rD, rM);
14160 goto decode_success;
14161 }
14162 }
14163
sewardjdb1c20a2010-09-22 22:26:40 +000014164 /* ------------------- smmul ------------------ */
14165 if (INSN(27,20) == BITS8(0,1,1,1,0,1,0,1)
14166 && INSN(15,12) == BITS4(1,1,1,1)
14167 && (INSN(7,4) & BITS4(1,1,0,1)) == BITS4(0,0,0,1)) {
14168 UInt bitR = INSN(5,5);
14169 UInt rD = INSN(19,16);
14170 UInt rM = INSN(11,8);
14171 UInt rN = INSN(3,0);
14172 if (rD != 15 && rM != 15 && rN != 15) {
14173 IRExpr* res
14174 = unop(Iop_64HIto32,
14175 binop(Iop_Add64,
14176 binop(Iop_MullS32, getIRegA(rN), getIRegA(rM)),
14177 mkU64(bitR ? 0x80000000ULL : 0ULL)));
14178 putIRegA(rD, res, condT, Ijk_Boring);
14179 DIP("smmul%s%s r%u, r%u, r%u\n",
14180 nCC(INSN_COND), bitR ? "r" : "", rD, rN, rM);
14181 goto decode_success;
14182 }
14183 }
14184
sewardj646bc002010-10-11 18:57:10 +000014185 /* ------------------- NOP ------------------ */
14186 if (0x0320F000 == (insn & 0x0FFFFFFF)) {
14187 DIP("nop%s\n", nCC(INSN_COND));
14188 goto decode_success;
14189 }
14190
sewardj6c299f32009-12-31 18:00:12 +000014191 /* ----------------------------------------------------------- */
14192 /* -- ARMv7 instructions -- */
14193 /* ----------------------------------------------------------- */
14194
14195 /* -------------- read CP15 TPIDRURO register ------------- */
14196 /* mrc p15, 0, r0, c13, c0, 3 up to
14197 mrc p15, 0, r14, c13, c0, 3
14198 */
14199 /* I don't know whether this is really v7-only. But anyway, we
14200 have to support it since arm-linux uses TPIDRURO as a thread
14201 state register. */
14202 if (0x0E1D0F70 == (insn & 0x0FFF0FFF)) {
14203 UInt rD = INSN(15,12);
14204 if (rD <= 14) {
14205 /* skip r15, that's too stupid to handle */
sewardjd2664472010-08-22 12:44:20 +000014206 putIRegA(rD, IRExpr_Get(OFFB_TPIDRURO, Ity_I32),
14207 condT, Ijk_Boring);
sewardj6c299f32009-12-31 18:00:12 +000014208 DIP("mrc%s p15,0, r%u, c13, c0, 3\n", nCC(INSN_COND), rD);
14209 goto decode_success;
14210 }
14211 /* fall through */
14212 }
14213
sewardj412098c2010-05-04 08:48:43 +000014214 /* Handle various kinds of barriers. This is rather indiscriminate
14215 in the sense that they are all turned into an IR Fence, which
14216 means we don't know which they are, so the back end has to
14217 re-emit them all when it comes acrosss an IR Fence.
14218 */
sewardj1331f4d2012-02-17 15:07:09 +000014219 /* v6 */ /* mcr 15, 0, rT, c7, c10, 5 */
14220 if (0xEE070FBA == (insn & 0xFFFF0FFF)) {
14221 UInt rT = INSN(15,12);
14222 if (rT <= 14) {
14223 /* mcr 15, 0, rT, c7, c10, 5 (v6) equiv to DMB (v7). Data
14224 Memory Barrier -- ensures ordering of memory accesses. */
14225 stmt( IRStmt_MBE(Imbe_Fence) );
14226 DIP("mcr 15, 0, r%u, c7, c10, 5 (data memory barrier)\n", rT);
14227 goto decode_success;
14228 }
14229 /* fall through */
14230 }
14231 /* other flavours of barrier */
sewardj412098c2010-05-04 08:48:43 +000014232 switch (insn) {
14233 case 0xEE070F9A: /* v6 */
14234 /* mcr 15, 0, r0, c7, c10, 4 (v6) equiv to DSB (v7). Data
14235 Synch Barrier -- ensures completion of memory accesses. */
14236 stmt( IRStmt_MBE(Imbe_Fence) );
14237 DIP("mcr 15, 0, r0, c7, c10, 4 (data synch barrier)\n");
14238 goto decode_success;
sewardj412098c2010-05-04 08:48:43 +000014239 case 0xEE070F95: /* v6 */
14240 /* mcr 15, 0, r0, c7, c5, 4 (v6) equiv to ISB (v7).
14241 Instruction Synchronisation Barrier (or Flush Prefetch
14242 Buffer) -- a pipe flush, I think. I suspect we could
14243 ignore those, but to be on the safe side emit a fence
14244 anyway. */
14245 stmt( IRStmt_MBE(Imbe_Fence) );
14246 DIP("mcr 15, 0, r0, c7, c5, 4 (insn synch barrier)\n");
14247 goto decode_success;
14248 default:
14249 break;
14250 }
14251
sewardj6c299f32009-12-31 18:00:12 +000014252 /* ----------------------------------------------------------- */
sewardjd2664472010-08-22 12:44:20 +000014253 /* -- VFP (CP 10, CP 11) instructions (in ARM mode) -- */
14254 /* ----------------------------------------------------------- */
14255
14256 if (INSN_COND != ARMCondNV) {
14257 Bool ok_vfp = decode_CP10_CP11_instruction (
14258 &dres, INSN(27,0), condT, INSN_COND,
14259 False/*!isT*/
14260 );
14261 if (ok_vfp)
14262 goto decode_success;
14263 }
14264
14265 /* ----------------------------------------------------------- */
14266 /* -- NEON instructions (in ARM mode) -- */
14267 /* ----------------------------------------------------------- */
14268
14269 /* These are all in NV space, and so are taken care of (far) above,
14270 by a call from this function to decode_NV_instruction(). */
14271
14272 /* ----------------------------------------------------------- */
sewardj1f139f52010-08-29 12:33:02 +000014273 /* -- v6 media instructions (in ARM mode) -- */
14274 /* ----------------------------------------------------------- */
14275
14276 { Bool ok_v6m = decode_V6MEDIA_instruction(
14277 &dres, INSN(27,0), condT, INSN_COND,
14278 False/*!isT*/
14279 );
14280 if (ok_v6m)
14281 goto decode_success;
14282 }
14283
14284 /* ----------------------------------------------------------- */
sewardj6c299f32009-12-31 18:00:12 +000014285 /* -- Undecodable -- */
14286 /* ----------------------------------------------------------- */
14287
14288 goto decode_failure;
14289 /*NOTREACHED*/
14290
14291 decode_failure:
sewardjc2c87162004-11-25 13:07:02 +000014292 /* All decode failures end up here. */
14293 vex_printf("disInstr(arm): unhandled instruction: "
sewardj6c299f32009-12-31 18:00:12 +000014294 "0x%x\n", insn);
14295 vex_printf(" cond=%d(0x%x) 27:20=%u(0x%02x) "
14296 "4:4=%d "
14297 "3:0=%u(0x%x)\n",
14298 (Int)INSN_COND, (UInt)INSN_COND,
14299 (Int)INSN(27,20), (UInt)INSN(27,20),
14300 (Int)INSN(4,4),
14301 (Int)INSN(3,0), (UInt)INSN(3,0) );
14302
14303 /* Tell the dispatcher that this insn cannot be decoded, and so has
14304 not been executed, and (is currently) the next to be executed.
14305 R15 should be up-to-date since it made so at the start of each
14306 insn, but nevertheless be paranoid and update it again right
14307 now. */
sewardjd2664472010-08-22 12:44:20 +000014308 vassert(0 == (guest_R15_curr_instr_notENC & 3));
14309 llPutIReg( 15, mkU32(guest_R15_curr_instr_notENC) );
sewardjc6f970f2012-04-02 21:54:49 +000014310 dres.whatNext = Dis_StopHere;
14311 dres.jk_StopHere = Ijk_NoDecode;
14312 dres.len = 0;
sewardj6c299f32009-12-31 18:00:12 +000014313 return dres;
14314
sewardjc2c87162004-11-25 13:07:02 +000014315 decode_success:
14316 /* All decode successes end up here. */
sewardjc2c87162004-11-25 13:07:02 +000014317 DIP("\n");
sewardj6c299f32009-12-31 18:00:12 +000014318
14319 vassert(dres.len == 4 || dres.len == 20);
14320
14321 /* Now then. Do we have an implicit jump to r15 to deal with? */
14322 if (r15written) {
14323 /* If we get jump to deal with, we assume that there's been no
14324 other competing branch stuff previously generated for this
14325 insn. That's reasonable, in the sense that the ARM insn set
14326 appears to declare as "Unpredictable" any instruction which
14327 generates more than one possible new value for r15. Hence
14328 just assert. The decoders themselves should check against
14329 all such instructions which are thusly Unpredictable, and
14330 decline to decode them. Hence we should never get here if we
14331 have competing new values for r15, and hence it is safe to
14332 assert here. */
14333 vassert(dres.whatNext == Dis_Continue);
14334 vassert(irsb->next == NULL);
sewardjf6d2cf92011-05-03 11:08:39 +000014335 vassert(irsb->jumpkind == Ijk_Boring);
sewardj6c299f32009-12-31 18:00:12 +000014336 /* If r15 is unconditionally written, terminate the block by
14337 jumping to it. If it's conditionally written, still
14338 terminate the block (a shame, but we can't do side exits to
14339 arbitrary destinations), but first jump to the next
14340 instruction if the condition doesn't hold. */
14341 /* We can't use getIReg(15) to get the destination, since that
14342 will produce r15+8, which isn't what we want. Must use
14343 llGetIReg(15) instead. */
14344 if (r15guard == IRTemp_INVALID) {
14345 /* unconditional */
14346 } else {
14347 /* conditional */
sewardjd2664472010-08-22 12:44:20 +000014348 stmt( IRStmt_Exit(
14349 unop(Iop_32to1,
14350 binop(Iop_Xor32,
14351 mkexpr(r15guard), mkU32(1))),
14352 r15kind,
sewardjc6f970f2012-04-02 21:54:49 +000014353 IRConst_U32(guest_R15_curr_instr_notENC + 4),
14354 OFFB_R15T
sewardj6c299f32009-12-31 18:00:12 +000014355 ));
14356 }
sewardjc6f970f2012-04-02 21:54:49 +000014357 /* This seems crazy, but we're required to finish the insn with
14358 a write to the guest PC. As usual we rely on ir_opt to tidy
14359 up later. */
14360 llPutIReg(15, llGetIReg(15));
14361 dres.whatNext = Dis_StopHere;
14362 dres.jk_StopHere = r15kind;
14363 } else {
14364 /* Set up the end-state in the normal way. */
14365 switch (dres.whatNext) {
14366 case Dis_Continue:
14367 llPutIReg(15, mkU32(dres.len + guest_R15_curr_instr_notENC));
14368 break;
14369 case Dis_ResteerU:
14370 case Dis_ResteerC:
14371 llPutIReg(15, mkU32(dres.continueAt));
14372 break;
14373 case Dis_StopHere:
14374 break;
14375 default:
14376 vassert(0);
14377 }
sewardj6c299f32009-12-31 18:00:12 +000014378 }
14379
14380 return dres;
14381
sewardj6c299f32009-12-31 18:00:12 +000014382# undef INSN_COND
sewardj80bea7b2010-01-09 11:43:21 +000014383# undef INSN
sewardjc2c87162004-11-25 13:07:02 +000014384}
14385
sewardjd2664472010-08-22 12:44:20 +000014386
14387/*------------------------------------------------------------*/
14388/*--- Disassemble a single Thumb2 instruction ---*/
14389/*------------------------------------------------------------*/
14390
sewardj66c8c9b2011-07-04 16:58:40 +000014391static const UChar it_length_table[256]; /* fwds */
14392
sewardjd2664472010-08-22 12:44:20 +000014393/* NB: in Thumb mode we do fetches of regs with getIRegT, which
14394 automagically adds 4 to fetches of r15. However, writes to regs
14395 are done with putIRegT, which disallows writes to r15. Hence any
14396 r15 writes and associated jumps have to be done "by hand". */
14397
14398/* Disassemble a single Thumb instruction into IR. The instruction is
14399 located in host memory at guest_instr, and has (decoded) guest IP
14400 of guest_R15_curr_instr_notENC, which will have been set before the
14401 call here. */
14402
14403static
14404DisResult disInstr_THUMB_WRK (
sewardjd2664472010-08-22 12:44:20 +000014405 Bool (*resteerOkFn) ( /*opaque*/void*, Addr64 ),
14406 Bool resteerCisOk,
14407 void* callback_opaque,
14408 UChar* guest_instr,
14409 VexArchInfo* archinfo,
14410 VexAbiInfo* abiinfo
14411 )
14412{
14413 /* A macro to fish bits out of insn0. There's also INSN1, to fish
14414 bits out of insn1, but that's defined only after the end of the
14415 16-bit insn decoder, so as to stop it mistakenly being used
14416 therein. */
14417# define INSN0(_bMax,_bMin) SLICE_UInt(((UInt)insn0), (_bMax), (_bMin))
14418
14419 DisResult dres;
14420 UShort insn0; /* first 16 bits of the insn */
14421 //Bool allow_VFP = False;
14422 //UInt hwcaps = archinfo->hwcaps;
14423 HChar dis_buf[128]; // big enough to hold LDMIA etc text
14424
sewardja002def2010-10-05 22:29:49 +000014425 /* Summary result of the ITxxx backwards analysis: False == safe
14426 but suboptimal. */
14427 Bool guaranteedUnconditional = False;
14428
sewardjd2664472010-08-22 12:44:20 +000014429 /* What insn variants are we supporting today? */
14430 //allow_VFP = (0 != (hwcaps & VEX_HWCAPS_ARM_VFP));
14431 // etc etc
14432
14433 /* Set result defaults. */
sewardjc6f970f2012-04-02 21:54:49 +000014434 dres.whatNext = Dis_Continue;
14435 dres.len = 2;
14436 dres.continueAt = 0;
14437 dres.jk_StopHere = Ijk_INVALID;
sewardjd2664472010-08-22 12:44:20 +000014438
14439 /* Set default actions for post-insn handling of writes to r15, if
14440 required. */
14441 r15written = False;
14442 r15guard = IRTemp_INVALID; /* unconditional */
14443 r15kind = Ijk_Boring;
14444
14445 /* Insns could be 2 or 4 bytes long. Just get the first 16 bits at
14446 this point. If we need the second 16, get them later. We can't
14447 get them both out immediately because it risks a fault (very
14448 unlikely, but ..) if the second 16 bits aren't actually
14449 necessary. */
14450 insn0 = getUShortLittleEndianly( guest_instr );
14451
14452 if (0) vex_printf("insn: 0x%x\n", insn0);
14453
14454 DIP("\t(thumb) 0x%x: ", (UInt)guest_R15_curr_instr_notENC);
14455
sewardjd2664472010-08-22 12:44:20 +000014456 vassert(0 == (guest_R15_curr_instr_notENC & 1));
sewardjd2664472010-08-22 12:44:20 +000014457
14458 /* ----------------------------------------------------------- */
14459 /* Spot "Special" instructions (see comment at top of file). */
14460 {
14461 UChar* code = (UChar*)guest_instr;
14462 /* Spot the 16-byte preamble:
14463
14464 ea4f 0cfc mov.w ip, ip, ror #3
14465 ea4f 3c7c mov.w ip, ip, ror #13
14466 ea4f 7c7c mov.w ip, ip, ror #29
14467 ea4f 4cfc mov.w ip, ip, ror #19
14468 */
14469 UInt word1 = 0x0CFCEA4F;
14470 UInt word2 = 0x3C7CEA4F;
14471 UInt word3 = 0x7C7CEA4F;
14472 UInt word4 = 0x4CFCEA4F;
14473 if (getUIntLittleEndianly(code+ 0) == word1 &&
14474 getUIntLittleEndianly(code+ 4) == word2 &&
14475 getUIntLittleEndianly(code+ 8) == word3 &&
14476 getUIntLittleEndianly(code+12) == word4) {
14477 /* Got a "Special" instruction preamble. Which one is it? */
14478 // 0x 0A 0A EA 4A
14479 if (getUIntLittleEndianly(code+16) == 0x0A0AEA4A
14480 /* orr.w r10,r10,r10 */) {
14481 /* R3 = client_request ( R4 ) */
14482 DIP("r3 = client_request ( %%r4 )\n");
sewardjc6f970f2012-04-02 21:54:49 +000014483 llPutIReg(15, mkU32( (guest_R15_curr_instr_notENC + 20) | 1 ));
14484 dres.jk_StopHere = Ijk_ClientReq;
14485 dres.whatNext = Dis_StopHere;
sewardjd2664472010-08-22 12:44:20 +000014486 goto decode_success;
14487 }
sewardjd2664472010-08-22 12:44:20 +000014488 else
14489 // 0x 0B 0B EA 4B
sewardjc0704052010-08-22 22:21:19 +000014490 if (getUIntLittleEndianly(code+16) == 0x0B0BEA4B
sewardjd2664472010-08-22 12:44:20 +000014491 /* orr r11,r11,r11 */) {
14492 /* R3 = guest_NRADDR */
14493 DIP("r3 = guest_NRADDR\n");
14494 dres.len = 20;
14495 llPutIReg(3, IRExpr_Get( OFFB_NRADDR, Ity_I32 ));
14496 goto decode_success;
14497 }
14498 else
14499 // 0x 0C 0C EA 4C
sewardjc0704052010-08-22 22:21:19 +000014500 if (getUIntLittleEndianly(code+16) == 0x0C0CEA4C
sewardjd2664472010-08-22 12:44:20 +000014501 /* orr r12,r12,r12 */) {
14502 /* branch-and-link-to-noredir R4 */
14503 DIP("branch-and-link-to-noredir r4\n");
sewardjc0704052010-08-22 22:21:19 +000014504 llPutIReg(14, mkU32( (guest_R15_curr_instr_notENC + 20) | 1 ));
sewardjc6f970f2012-04-02 21:54:49 +000014505 llPutIReg(15, getIRegT(4));
14506 dres.jk_StopHere = Ijk_NoRedir;
14507 dres.whatNext = Dis_StopHere;
sewardjd2664472010-08-22 12:44:20 +000014508 goto decode_success;
14509 }
sewardjd2664472010-08-22 12:44:20 +000014510 /* We don't know what it is. Set insn0 so decode_failure
14511 can print the insn following the Special-insn preamble. */
14512 insn0 = getUShortLittleEndianly(code+16);
14513 goto decode_failure;
14514 /*NOTREACHED*/
14515 }
14516
14517 }
14518
14519 /* ----------------------------------------------------------- */
14520
14521 /* Main Thumb instruction decoder starts here. It's a series of
14522 switches which examine ever longer bit sequences at the MSB of
14523 the instruction word, first for 16-bit insns, then for 32-bit
14524 insns. */
14525
sewardja002def2010-10-05 22:29:49 +000014526 /* --- BEGIN ITxxx optimisation analysis --- */
sewardjd2664472010-08-22 12:44:20 +000014527 /* This is a crucial optimisation for the ITState boilerplate that
14528 follows. Examine the 9 halfwords preceding this instruction,
14529 and if we are absolutely sure that none of them constitute an
14530 'it' instruction, then we can be sure that this instruction is
14531 not under the control of any 'it' instruction, and so
14532 guest_ITSTATE must be zero. So write zero into ITSTATE right
14533 now, so that iropt can fold out almost all of the resulting
14534 junk.
14535
14536 If we aren't sure, we can always safely skip this step. So be a
14537 bit conservative about it: only poke around in the same page as
14538 this instruction, lest we get a fault from the previous page
14539 that would not otherwise have happened. The saving grace is
14540 that such skipping is pretty rare -- it only happens,
14541 statistically, 18/4096ths of the time, so is judged unlikely to
14542 be a performance problems.
14543
14544 FIXME: do better. Take into account the number of insns covered
14545 by any IT insns we find, to rule out cases where an IT clearly
14546 cannot cover this instruction. This would improve behaviour for
14547 branch targets immediately following an IT-guarded group that is
14548 not of full length. Eg, (and completely ignoring issues of 16-
14549 vs 32-bit insn length):
14550
14551 ite cond
14552 insn1
14553 insn2
14554 label: insn3
14555 insn4
14556
14557 The 'it' only conditionalises insn1 and insn2. However, the
14558 current analysis is conservative and considers insn3 and insn4
14559 also possibly guarded. Hence if 'label:' is the start of a hot
14560 loop we will get a big performance hit.
14561 */
14562 {
14563 /* Summary result of this analysis: False == safe but
14564 suboptimal. */
sewardja002def2010-10-05 22:29:49 +000014565 vassert(guaranteedUnconditional == False);
sewardjd2664472010-08-22 12:44:20 +000014566
14567 UInt pc = guest_R15_curr_instr_notENC;
14568 vassert(0 == (pc & 1));
14569
14570 UInt pageoff = pc & 0xFFF;
14571 if (pageoff >= 18) {
14572 /* It's safe to poke about in the 9 halfwords preceding this
14573 insn. So, have a look at them. */
sewardj66c8c9b2011-07-04 16:58:40 +000014574 guaranteedUnconditional = True; /* assume no 'it' insn found,
14575 till we do */
sewardjdf86f162010-08-22 18:47:30 +000014576 UShort* hwp = (UShort*)(HWord)pc;
sewardjd2664472010-08-22 12:44:20 +000014577 Int i;
14578 for (i = -1; i >= -9; i--) {
14579 /* We're in the same page. (True, but commented out due
14580 to expense.) */
14581 /*
14582 vassert( ( ((UInt)(&hwp[i])) & 0xFFFFF000 )
14583 == ( pc & 0xFFFFF000 ) );
14584 */
14585 /* All valid IT instructions must have the form 0xBFxy,
sewardj66c8c9b2011-07-04 16:58:40 +000014586 where x can be anything, but y must be nonzero. Find
14587 the number of insns covered by it (1 .. 4) and check to
14588 see if it can possibly reach up to the instruction in
14589 question. Some (x,y) combinations mean UNPREDICTABLE,
14590 and the table is constructed to be conservative by
14591 returning 4 for those cases, so the analysis is safe
14592 even if the code uses unpredictable IT instructions (in
14593 which case its authors are nuts, but hey.) */
14594 UShort hwp_i = hwp[i];
14595 if (UNLIKELY((hwp_i & 0xFF00) == 0xBF00 && (hwp_i & 0xF) != 0)) {
14596 /* might be an 'it' insn. */
14597 /* # guarded insns */
14598 Int n_guarded = (Int)it_length_table[hwp_i & 0xFF];
14599 vassert(n_guarded >= 1 && n_guarded <= 4);
14600 if (n_guarded * 2 /* # guarded HWs, worst case */
14601 > (-(i+1))) /* -(i+1): # remaining HWs after the IT */
14602 /* -(i+0) also seems to work, even though I think
14603 it's wrong. I don't understand that. */
14604 guaranteedUnconditional = False;
sewardjd2664472010-08-22 12:44:20 +000014605 break;
14606 }
14607 }
14608 }
sewardjd2664472010-08-22 12:44:20 +000014609 }
sewardja002def2010-10-05 22:29:49 +000014610 /* --- END ITxxx optimisation analysis --- */
sewardjd2664472010-08-22 12:44:20 +000014611
14612 /* Generate the guarding condition for this insn, by examining
14613 ITSTATE. Assign it to condT. Also, generate new
14614 values for ITSTATE ready for stuffing back into the
14615 guest state, but don't actually do the Put yet, since it will
14616 need to stuffed back in only after the instruction gets to a
14617 point where it is sure to complete. Mostly we let the code at
14618 decode_success handle this, but in cases where the insn contains
14619 a side exit, we have to update them before the exit. */
14620
sewardja002def2010-10-05 22:29:49 +000014621 /* If the ITxxx optimisation analysis above could not prove that
14622 this instruction is guaranteed unconditional, we insert a
14623 lengthy IR preamble to compute the guarding condition at
14624 runtime. If it can prove it (which obviously we hope is the
14625 normal case) then we insert a minimal preamble, which is
14626 equivalent to setting guest_ITSTATE to zero and then folding
14627 that through the full preamble (which completely disappears). */
sewardjd2664472010-08-22 12:44:20 +000014628
sewardja002def2010-10-05 22:29:49 +000014629 IRTemp condT = IRTemp_INVALID;
14630 IRTemp old_itstate = IRTemp_INVALID;
14631 IRTemp new_itstate = IRTemp_INVALID;
14632 IRTemp cond_AND_notInIT_T = IRTemp_INVALID;
sewardjd2664472010-08-22 12:44:20 +000014633
sewardja002def2010-10-05 22:29:49 +000014634 if (guaranteedUnconditional) {
14635 /* BEGIN "partial eval { ITSTATE = 0; STANDARD_PREAMBLE; }" */
sewardjd2664472010-08-22 12:44:20 +000014636
sewardja002def2010-10-05 22:29:49 +000014637 // ITSTATE = 0 :: I32
14638 IRTemp z32 = newTemp(Ity_I32);
14639 assign(z32, mkU32(0));
14640 put_ITSTATE(z32);
14641
14642 // old_itstate = 0 :: I32
14643 //
14644 // old_itstate = get_ITSTATE();
14645 old_itstate = z32; /* 0 :: I32 */
14646
14647 // new_itstate = old_itstate >> 8
14648 // = 0 >> 8
14649 // = 0 :: I32
14650 //
14651 // new_itstate = newTemp(Ity_I32);
14652 // assign(new_itstate,
14653 // binop(Iop_Shr32, mkexpr(old_itstate), mkU8(8)));
14654 new_itstate = z32;
14655
14656 // ITSTATE = 0 :: I32(again)
14657 //
14658 // put_ITSTATE(new_itstate);
14659
14660 // condT1 = calc_cond_dyn( xor(and(old_istate,0xF0), 0xE0) )
14661 // = calc_cond_dyn( xor(0,0xE0) )
14662 // = calc_cond_dyn ( 0xE0 )
14663 // = 1 :: I32
14664 // Not that this matters, since the computed value is not used:
14665 // see condT folding below
14666 //
14667 // IRTemp condT1 = newTemp(Ity_I32);
14668 // assign(condT1,
14669 // mk_armg_calculate_condition_dyn(
14670 // binop(Iop_Xor32,
14671 // binop(Iop_And32, mkexpr(old_itstate), mkU32(0xF0)),
14672 // mkU32(0xE0))
14673 // )
14674 // );
14675
14676 // condT = 32to8(and32(old_itstate,0xF0)) == 0 ? 1 : condT1
14677 // = 32to8(and32(0,0xF0)) == 0 ? 1 : condT1
14678 // = 32to8(0) == 0 ? 1 : condT1
14679 // = 0 == 0 ? 1 : condT1
14680 // = 1
14681 //
14682 // condT = newTemp(Ity_I32);
14683 // assign(condT, IRExpr_Mux0X(
14684 // unop(Iop_32to8, binop(Iop_And32,
14685 // mkexpr(old_itstate),
14686 // mkU32(0xF0))),
14687 // mkU32(1),
14688 // mkexpr(condT1)
14689 // ));
14690 condT = newTemp(Ity_I32);
14691 assign(condT, mkU32(1));
14692
14693 // notInITt = xor32(and32(old_itstate, 1), 1)
14694 // = xor32(and32(0, 1), 1)
14695 // = xor32(0, 1)
14696 // = 1 :: I32
14697 //
14698 // IRTemp notInITt = newTemp(Ity_I32);
14699 // assign(notInITt,
14700 // binop(Iop_Xor32,
14701 // binop(Iop_And32, mkexpr(old_itstate), mkU32(1)),
14702 // mkU32(1)));
14703
14704 // cond_AND_notInIT_T = and32(notInITt, condT)
14705 // = and32(1, 1)
14706 // = 1
14707 //
14708 // cond_AND_notInIT_T = newTemp(Ity_I32);
14709 // assign(cond_AND_notInIT_T,
14710 // binop(Iop_And32, mkexpr(notInITt), mkexpr(condT)));
14711 cond_AND_notInIT_T = condT; /* 1 :: I32 */
14712
14713 /* END "partial eval { ITSTATE = 0; STANDARD_PREAMBLE; }" */
14714 } else {
14715 /* BEGIN { STANDARD PREAMBLE; } */
14716
14717 old_itstate = get_ITSTATE();
14718
14719 new_itstate = newTemp(Ity_I32);
14720 assign(new_itstate,
14721 binop(Iop_Shr32, mkexpr(old_itstate), mkU8(8)));
14722
14723 put_ITSTATE(new_itstate);
14724
14725 /* Same strategy as for ARM insns: generate a condition
14726 temporary at this point (or IRTemp_INVALID, meaning
14727 unconditional). We leave it to lower-level instruction
14728 decoders to decide whether they can generate straight-line
14729 code, or whether they must generate a side exit before the
14730 instruction. condT :: Ity_I32 and is always either zero or
14731 one. */
14732 IRTemp condT1 = newTemp(Ity_I32);
14733 assign(condT1,
14734 mk_armg_calculate_condition_dyn(
14735 binop(Iop_Xor32,
14736 binop(Iop_And32, mkexpr(old_itstate), mkU32(0xF0)),
14737 mkU32(0xE0))
14738 )
14739 );
14740
14741 /* This is a bit complex, but needed to make Memcheck understand
14742 that, if the condition in old_itstate[7:4] denotes AL (that
14743 is, if this instruction is to be executed unconditionally),
14744 then condT does not depend on the results of calling the
14745 helper.
14746
14747 We test explicitly for old_itstate[7:4] == AL ^ 0xE, and in
14748 that case set condT directly to 1. Else we use the results
14749 of the helper. Since old_itstate is always defined and
14750 because Memcheck does lazy V-bit propagation through Mux0X,
14751 this will cause condT to always be a defined 1 if the
14752 condition is 'AL'. From an execution semantics point of view
14753 this is irrelevant since we're merely duplicating part of the
14754 behaviour of the helper. But it makes it clear to Memcheck,
14755 in this case, that condT does not in fact depend on the
14756 contents of the condition code thunk. Without it, we get
14757 quite a lot of false errors.
14758
14759 So, just to clarify: from a straight semantics point of view,
14760 we can simply do "assign(condT, mkexpr(condT1))", and the
14761 simulator still runs fine. It's just that we get loads of
14762 false errors from Memcheck. */
14763 condT = newTemp(Ity_I32);
14764 assign(condT, IRExpr_Mux0X(
14765 unop(Iop_32to8, binop(Iop_And32,
14766 mkexpr(old_itstate),
14767 mkU32(0xF0))),
14768 mkU32(1),
14769 mkexpr(condT1)
14770 ));
14771
14772 /* Something we don't have in ARM: generate a 0 or 1 value
14773 indicating whether or not we are in an IT block (NB: 0 = in
14774 IT block, 1 = not in IT block). This is used to gate
14775 condition code updates in 16-bit Thumb instructions. */
14776 IRTemp notInITt = newTemp(Ity_I32);
14777 assign(notInITt,
sewardjd2664472010-08-22 12:44:20 +000014778 binop(Iop_Xor32,
sewardja002def2010-10-05 22:29:49 +000014779 binop(Iop_And32, mkexpr(old_itstate), mkU32(1)),
14780 mkU32(1)));
sewardjd2664472010-08-22 12:44:20 +000014781
sewardja002def2010-10-05 22:29:49 +000014782 /* Compute 'condT && notInITt' -- that is, the instruction is
14783 going to execute, and we're not in an IT block. This is the
14784 gating condition for updating condition codes in 16-bit Thumb
14785 instructions, except for CMP, CMN and TST. */
14786 cond_AND_notInIT_T = newTemp(Ity_I32);
14787 assign(cond_AND_notInIT_T,
14788 binop(Iop_And32, mkexpr(notInITt), mkexpr(condT)));
14789 /* END { STANDARD PREAMBLE; } */
14790 }
sewardjd2664472010-08-22 12:44:20 +000014791
sewardjd2664472010-08-22 12:44:20 +000014792
14793 /* At this point:
14794 * ITSTATE has been updated
14795 * condT holds the guarding condition for this instruction (0 or 1),
14796 * notInITt is 1 if we're in "normal" code, 0 if in an IT block
14797 * cond_AND_notInIT_T is the AND of the above two.
14798
14799 If the instruction proper can't trap, then there's nothing else
14800 to do w.r.t. ITSTATE -- just go and and generate IR for the
14801 insn, taking into account the guarding condition.
14802
14803 If, however, the instruction might trap, then we must back up
14804 ITSTATE to the old value, and re-update it after the potentially
14805 trapping IR section. A trap can happen either via a memory
14806 reference or because we need to throw SIGILL.
14807
14808 If an instruction has a side exit, we need to be sure that any
14809 ITSTATE backup is re-updated before the side exit.
14810 */
14811
14812 /* ----------------------------------------------------------- */
14813 /* -- -- */
14814 /* -- Thumb 16-bit integer instructions -- */
14815 /* -- -- */
14816 /* -- IMPORTANT: references to insn1 or INSN1 are -- */
14817 /* -- not allowed in this section -- */
14818 /* -- -- */
14819 /* ----------------------------------------------------------- */
14820
14821 /* 16-bit instructions inside an IT block, apart from CMP, CMN and
14822 TST, do not set the condition codes. Hence we must dynamically
14823 test for this case for every condition code update. */
14824
14825 IROp anOp = Iop_INVALID;
14826 HChar* anOpNm = NULL;
14827
14828 /* ================ 16-bit 15:6 cases ================ */
14829
14830 switch (INSN0(15,6)) {
14831
14832 case 0x10a: // CMP
14833 case 0x10b: { // CMN
14834 /* ---------------- CMP Rn, Rm ---------------- */
14835 Bool isCMN = INSN0(15,6) == 0x10b;
14836 UInt rN = INSN0(2,0);
14837 UInt rM = INSN0(5,3);
14838 IRTemp argL = newTemp(Ity_I32);
14839 IRTemp argR = newTemp(Ity_I32);
14840 assign( argL, getIRegT(rN) );
14841 assign( argR, getIRegT(rM) );
14842 /* Update flags regardless of whether in an IT block or not. */
14843 setFlags_D1_D2( isCMN ? ARMG_CC_OP_ADD : ARMG_CC_OP_SUB,
14844 argL, argR, condT );
14845 DIP("%s r%u, r%u\n", isCMN ? "cmn" : "cmp", rN, rM);
14846 goto decode_success;
14847 }
14848
14849 case 0x108: {
14850 /* ---------------- TST Rn, Rm ---------------- */
14851 UInt rN = INSN0(2,0);
14852 UInt rM = INSN0(5,3);
14853 IRTemp oldC = newTemp(Ity_I32);
14854 IRTemp oldV = newTemp(Ity_I32);
14855 IRTemp res = newTemp(Ity_I32);
14856 assign( oldC, mk_armg_calculate_flag_c() );
14857 assign( oldV, mk_armg_calculate_flag_v() );
14858 assign( res, binop(Iop_And32, getIRegT(rN), getIRegT(rM)) );
14859 /* Update flags regardless of whether in an IT block or not. */
14860 setFlags_D1_D2_ND( ARMG_CC_OP_LOGIC, res, oldC, oldV, condT );
14861 DIP("tst r%u, r%u\n", rN, rM);
14862 goto decode_success;
14863 }
14864
14865 case 0x109: {
14866 /* ---------------- NEGS Rd, Rm ---------------- */
14867 /* Rd = -Rm */
14868 UInt rM = INSN0(5,3);
14869 UInt rD = INSN0(2,0);
14870 IRTemp arg = newTemp(Ity_I32);
14871 IRTemp zero = newTemp(Ity_I32);
14872 assign(arg, getIRegT(rM));
14873 assign(zero, mkU32(0));
14874 // rD can never be r15
14875 putIRegT(rD, binop(Iop_Sub32, mkexpr(zero), mkexpr(arg)), condT);
14876 setFlags_D1_D2( ARMG_CC_OP_SUB, zero, arg, cond_AND_notInIT_T);
14877 DIP("negs r%u, r%u\n", rD, rM);
14878 goto decode_success;
14879 }
14880
14881 case 0x10F: {
14882 /* ---------------- MVNS Rd, Rm ---------------- */
14883 /* Rd = ~Rm */
14884 UInt rM = INSN0(5,3);
14885 UInt rD = INSN0(2,0);
14886 IRTemp oldV = newTemp(Ity_I32);
14887 IRTemp oldC = newTemp(Ity_I32);
14888 IRTemp res = newTemp(Ity_I32);
14889 assign( oldV, mk_armg_calculate_flag_v() );
14890 assign( oldC, mk_armg_calculate_flag_c() );
14891 assign(res, unop(Iop_Not32, getIRegT(rM)));
14892 // rD can never be r15
14893 putIRegT(rD, mkexpr(res), condT);
14894 setFlags_D1_D2_ND( ARMG_CC_OP_LOGIC, res, oldC, oldV,
14895 cond_AND_notInIT_T );
14896 DIP("mvns r%u, r%u\n", rD, rM);
14897 goto decode_success;
14898 }
14899
14900 case 0x10C:
14901 /* ---------------- ORRS Rd, Rm ---------------- */
14902 anOp = Iop_Or32; anOpNm = "orr"; goto and_orr_eor_mul;
14903 case 0x100:
14904 /* ---------------- ANDS Rd, Rm ---------------- */
14905 anOp = Iop_And32; anOpNm = "and"; goto and_orr_eor_mul;
14906 case 0x101:
14907 /* ---------------- EORS Rd, Rm ---------------- */
14908 anOp = Iop_Xor32; anOpNm = "eor"; goto and_orr_eor_mul;
14909 case 0x10d:
14910 /* ---------------- MULS Rd, Rm ---------------- */
14911 anOp = Iop_Mul32; anOpNm = "mul"; goto and_orr_eor_mul;
14912 and_orr_eor_mul: {
14913 /* Rd = Rd `op` Rm */
14914 UInt rM = INSN0(5,3);
14915 UInt rD = INSN0(2,0);
14916 IRTemp res = newTemp(Ity_I32);
14917 IRTemp oldV = newTemp(Ity_I32);
14918 IRTemp oldC = newTemp(Ity_I32);
14919 assign( oldV, mk_armg_calculate_flag_v() );
14920 assign( oldC, mk_armg_calculate_flag_c() );
14921 assign( res, binop(anOp, getIRegT(rD), getIRegT(rM) ));
14922 // not safe to read guest state after here
14923 // rD can never be r15
14924 putIRegT(rD, mkexpr(res), condT);
14925 setFlags_D1_D2_ND( ARMG_CC_OP_LOGIC, res, oldC, oldV,
14926 cond_AND_notInIT_T );
14927 DIP("%s r%u, r%u\n", anOpNm, rD, rM);
14928 goto decode_success;
14929 }
14930
14931 case 0x10E: {
14932 /* ---------------- BICS Rd, Rm ---------------- */
14933 /* Rd = Rd & ~Rm */
14934 UInt rM = INSN0(5,3);
14935 UInt rD = INSN0(2,0);
14936 IRTemp res = newTemp(Ity_I32);
14937 IRTemp oldV = newTemp(Ity_I32);
14938 IRTemp oldC = newTemp(Ity_I32);
14939 assign( oldV, mk_armg_calculate_flag_v() );
14940 assign( oldC, mk_armg_calculate_flag_c() );
14941 assign( res, binop(Iop_And32, getIRegT(rD),
14942 unop(Iop_Not32, getIRegT(rM) )));
14943 // not safe to read guest state after here
14944 // rD can never be r15
14945 putIRegT(rD, mkexpr(res), condT);
14946 setFlags_D1_D2_ND( ARMG_CC_OP_LOGIC, res, oldC, oldV,
14947 cond_AND_notInIT_T );
14948 DIP("bics r%u, r%u\n", rD, rM);
14949 goto decode_success;
14950 }
14951
14952 case 0x105: {
14953 /* ---------------- ADCS Rd, Rm ---------------- */
14954 /* Rd = Rd + Rm + oldC */
14955 UInt rM = INSN0(5,3);
14956 UInt rD = INSN0(2,0);
14957 IRTemp argL = newTemp(Ity_I32);
14958 IRTemp argR = newTemp(Ity_I32);
14959 IRTemp oldC = newTemp(Ity_I32);
14960 IRTemp res = newTemp(Ity_I32);
14961 assign(argL, getIRegT(rD));
14962 assign(argR, getIRegT(rM));
14963 assign(oldC, mk_armg_calculate_flag_c());
14964 assign(res, binop(Iop_Add32,
14965 binop(Iop_Add32, mkexpr(argL), mkexpr(argR)),
14966 mkexpr(oldC)));
14967 // rD can never be r15
14968 putIRegT(rD, mkexpr(res), condT);
14969 setFlags_D1_D2_ND( ARMG_CC_OP_ADC, argL, argR, oldC,
14970 cond_AND_notInIT_T );
14971 DIP("adcs r%u, r%u\n", rD, rM);
14972 goto decode_success;
14973 }
14974
14975 case 0x106: {
14976 /* ---------------- SBCS Rd, Rm ---------------- */
14977 /* Rd = Rd - Rm - (oldC ^ 1) */
14978 UInt rM = INSN0(5,3);
14979 UInt rD = INSN0(2,0);
14980 IRTemp argL = newTemp(Ity_I32);
14981 IRTemp argR = newTemp(Ity_I32);
14982 IRTemp oldC = newTemp(Ity_I32);
14983 IRTemp res = newTemp(Ity_I32);
14984 assign(argL, getIRegT(rD));
14985 assign(argR, getIRegT(rM));
14986 assign(oldC, mk_armg_calculate_flag_c());
14987 assign(res, binop(Iop_Sub32,
14988 binop(Iop_Sub32, mkexpr(argL), mkexpr(argR)),
14989 binop(Iop_Xor32, mkexpr(oldC), mkU32(1))));
14990 // rD can never be r15
14991 putIRegT(rD, mkexpr(res), condT);
14992 setFlags_D1_D2_ND( ARMG_CC_OP_SBB, argL, argR, oldC,
14993 cond_AND_notInIT_T );
14994 DIP("sbcs r%u, r%u\n", rD, rM);
14995 goto decode_success;
14996 }
14997
14998 case 0x2CB: {
14999 /* ---------------- UXTB Rd, Rm ---------------- */
15000 /* Rd = 8Uto32(Rm) */
15001 UInt rM = INSN0(5,3);
15002 UInt rD = INSN0(2,0);
15003 putIRegT(rD, binop(Iop_And32, getIRegT(rM), mkU32(0xFF)),
15004 condT);
15005 DIP("uxtb r%u, r%u\n", rD, rM);
15006 goto decode_success;
15007 }
15008
15009 case 0x2C9: {
15010 /* ---------------- SXTB Rd, Rm ---------------- */
15011 /* Rd = 8Sto32(Rm) */
15012 UInt rM = INSN0(5,3);
15013 UInt rD = INSN0(2,0);
15014 putIRegT(rD, binop(Iop_Sar32,
15015 binop(Iop_Shl32, getIRegT(rM), mkU8(24)),
15016 mkU8(24)),
15017 condT);
15018 DIP("sxtb r%u, r%u\n", rD, rM);
15019 goto decode_success;
15020 }
15021
15022 case 0x2CA: {
15023 /* ---------------- UXTH Rd, Rm ---------------- */
15024 /* Rd = 16Uto32(Rm) */
15025 UInt rM = INSN0(5,3);
15026 UInt rD = INSN0(2,0);
15027 putIRegT(rD, binop(Iop_And32, getIRegT(rM), mkU32(0xFFFF)),
15028 condT);
15029 DIP("uxth r%u, r%u\n", rD, rM);
15030 goto decode_success;
15031 }
15032
15033 case 0x2C8: {
15034 /* ---------------- SXTH Rd, Rm ---------------- */
15035 /* Rd = 16Sto32(Rm) */
15036 UInt rM = INSN0(5,3);
15037 UInt rD = INSN0(2,0);
15038 putIRegT(rD, binop(Iop_Sar32,
15039 binop(Iop_Shl32, getIRegT(rM), mkU8(16)),
15040 mkU8(16)),
15041 condT);
15042 DIP("sxth r%u, r%u\n", rD, rM);
15043 goto decode_success;
15044 }
15045
15046 case 0x102: // LSLS
15047 case 0x103: // LSRS
15048 case 0x104: // ASRS
15049 case 0x107: { // RORS
15050 /* ---------------- LSLS Rs, Rd ---------------- */
15051 /* ---------------- LSRS Rs, Rd ---------------- */
15052 /* ---------------- ASRS Rs, Rd ---------------- */
15053 /* ---------------- RORS Rs, Rd ---------------- */
15054 /* Rd = Rd `op` Rs, and set flags */
15055 UInt rS = INSN0(5,3);
15056 UInt rD = INSN0(2,0);
15057 IRTemp oldV = newTemp(Ity_I32);
15058 IRTemp rDt = newTemp(Ity_I32);
15059 IRTemp rSt = newTemp(Ity_I32);
15060 IRTemp res = newTemp(Ity_I32);
15061 IRTemp resC = newTemp(Ity_I32);
15062 HChar* wot = "???";
15063 assign(rSt, getIRegT(rS));
15064 assign(rDt, getIRegT(rD));
15065 assign(oldV, mk_armg_calculate_flag_v());
15066 /* Does not appear to be the standard 'how' encoding. */
15067 switch (INSN0(15,6)) {
15068 case 0x102:
15069 compute_result_and_C_after_LSL_by_reg(
15070 dis_buf, &res, &resC, rDt, rSt, rD, rS
15071 );
15072 wot = "lsl";
15073 break;
15074 case 0x103:
15075 compute_result_and_C_after_LSR_by_reg(
15076 dis_buf, &res, &resC, rDt, rSt, rD, rS
15077 );
15078 wot = "lsr";
15079 break;
15080 case 0x104:
15081 compute_result_and_C_after_ASR_by_reg(
15082 dis_buf, &res, &resC, rDt, rSt, rD, rS
15083 );
15084 wot = "asr";
15085 break;
15086 case 0x107:
15087 compute_result_and_C_after_ROR_by_reg(
15088 dis_buf, &res, &resC, rDt, rSt, rD, rS
15089 );
15090 wot = "ror";
15091 break;
15092 default:
15093 /*NOTREACHED*/vassert(0);
15094 }
15095 // not safe to read guest state after this point
15096 putIRegT(rD, mkexpr(res), condT);
15097 setFlags_D1_D2_ND( ARMG_CC_OP_LOGIC, res, resC, oldV,
15098 cond_AND_notInIT_T );
15099 DIP("%ss r%u, r%u\n", wot, rS, rD);
15100 goto decode_success;
15101 }
15102
sewardj27312d32010-09-26 00:48:41 +000015103 case 0x2E8: // REV
15104 case 0x2E9: { // REV16
15105 /* ---------------- REV Rd, Rm ---------------- */
15106 /* ---------------- REV16 Rd, Rm ---------------- */
15107 UInt rM = INSN0(5,3);
15108 UInt rD = INSN0(2,0);
15109 Bool isREV = INSN0(15,6) == 0x2E8;
15110 IRTemp arg = newTemp(Ity_I32);
15111 assign(arg, getIRegT(rM));
15112 IRTemp res = isREV ? gen_REV(arg) : gen_REV16(arg);
15113 putIRegT(rD, mkexpr(res), condT);
15114 DIP("rev%s r%u, r%u\n", isREV ? "" : "16", rD, rM);
15115 goto decode_success;
15116 }
15117
sewardjd2664472010-08-22 12:44:20 +000015118 default:
15119 break; /* examine the next shortest prefix */
15120
15121 }
15122
15123
15124 /* ================ 16-bit 15:7 cases ================ */
15125
15126 switch (INSN0(15,7)) {
15127
15128 case BITS9(1,0,1,1,0,0,0,0,0): {
15129 /* ------------ ADD SP, #imm7 * 4 ------------ */
15130 UInt uimm7 = INSN0(6,0);
15131 putIRegT(13, binop(Iop_Add32, getIRegT(13), mkU32(uimm7 * 4)),
15132 condT);
15133 DIP("add sp, #%u\n", uimm7 * 4);
15134 goto decode_success;
15135 }
15136
15137 case BITS9(1,0,1,1,0,0,0,0,1): {
15138 /* ------------ SUB SP, #imm7 * 4 ------------ */
15139 UInt uimm7 = INSN0(6,0);
15140 putIRegT(13, binop(Iop_Sub32, getIRegT(13), mkU32(uimm7 * 4)),
15141 condT);
15142 DIP("sub sp, #%u\n", uimm7 * 4);
15143 goto decode_success;
15144 }
15145
15146 case BITS9(0,1,0,0,0,1,1,1,0): {
15147 /* ---------------- BX rM ---------------- */
15148 /* Branch to reg, and optionally switch modes. Reg contains a
15149 suitably encoded address therefore (w CPSR.T at the bottom).
15150 Have to special-case r15, as usual. */
15151 UInt rM = (INSN0(6,6) << 3) | INSN0(5,3);
sewardj8e074cc2010-09-02 21:14:10 +000015152 if (BITS3(0,0,0) == INSN0(2,0)) {
sewardjd2664472010-08-22 12:44:20 +000015153 IRTemp dst = newTemp(Ity_I32);
15154 gen_SIGILL_T_if_in_but_NLI_ITBlock(old_itstate, new_itstate);
15155 mk_skip_over_T16_if_cond_is_false(condT);
15156 condT = IRTemp_INVALID;
15157 // now uncond
15158 if (rM <= 14) {
15159 assign( dst, getIRegT(rM) );
15160 } else {
sewardjd2664472010-08-22 12:44:20 +000015161 vassert(rM == 15);
15162 assign( dst, mkU32(guest_R15_curr_instr_notENC + 4) );
15163 }
sewardjc6f970f2012-04-02 21:54:49 +000015164 llPutIReg(15, mkexpr(dst));
15165 dres.jk_StopHere = rM == 14 ? Ijk_Ret : Ijk_Boring;
15166 dres.whatNext = Dis_StopHere;
sewardjd2664472010-08-22 12:44:20 +000015167 DIP("bx r%u (possibly switch to ARM mode)\n", rM);
15168 goto decode_success;
15169 }
15170 break;
15171 }
15172
15173 /* ---------------- BLX rM ---------------- */
15174 /* Branch and link to interworking address in rM. */
15175 case BITS9(0,1,0,0,0,1,1,1,1): {
15176 if (BITS3(0,0,0) == INSN0(2,0)) {
15177 UInt rM = (INSN0(6,6) << 3) | INSN0(5,3);
15178 IRTemp dst = newTemp(Ity_I32);
15179 if (rM <= 14) {
15180 gen_SIGILL_T_if_in_but_NLI_ITBlock(old_itstate, new_itstate);
15181 mk_skip_over_T16_if_cond_is_false(condT);
15182 condT = IRTemp_INVALID;
15183 // now uncond
15184 /* We're returning to Thumb code, hence "| 1" */
15185 assign( dst, getIRegT(rM) );
15186 putIRegT( 14, mkU32( (guest_R15_curr_instr_notENC + 2) | 1 ),
15187 IRTemp_INVALID );
sewardjc6f970f2012-04-02 21:54:49 +000015188 llPutIReg(15, mkexpr(dst));
15189 dres.jk_StopHere = Ijk_Call;
15190 dres.whatNext = Dis_StopHere;
sewardjd2664472010-08-22 12:44:20 +000015191 DIP("blx r%u (possibly switch to ARM mode)\n", rM);
15192 goto decode_success;
15193 }
15194 /* else unpredictable, fall through */
15195 }
15196 break;
15197 }
15198
15199 default:
15200 break; /* examine the next shortest prefix */
15201
15202 }
15203
15204
15205 /* ================ 16-bit 15:8 cases ================ */
15206
15207 switch (INSN0(15,8)) {
15208
15209 case BITS8(1,1,0,1,1,1,1,1): {
15210 /* ---------------- SVC ---------------- */
15211 UInt imm8 = INSN0(7,0);
15212 if (imm8 == 0) {
15213 /* A syscall. We can't do this conditionally, hence: */
15214 mk_skip_over_T16_if_cond_is_false( condT );
15215 // FIXME: what if we have to back up and restart this insn?
15216 // then ITSTATE will be wrong (we'll have it as "used")
15217 // when it isn't. Correct is to save ITSTATE in a
15218 // stash pseudo-reg, and back up from that if we have to
15219 // restart.
15220 // uncond after here
sewardjc6f970f2012-04-02 21:54:49 +000015221 llPutIReg(15, mkU32( (guest_R15_curr_instr_notENC + 2) | 1 ));
15222 dres.jk_StopHere = Ijk_Sys_syscall;
15223 dres.whatNext = Dis_StopHere;
sewardjd2664472010-08-22 12:44:20 +000015224 DIP("svc #0x%08x\n", imm8);
15225 goto decode_success;
15226 }
15227 /* else fall through */
15228 break;
15229 }
15230
15231 case BITS8(0,1,0,0,0,1,0,0): {
15232 /* ---------------- ADD(HI) Rd, Rm ---------------- */
15233 UInt h1 = INSN0(7,7);
15234 UInt h2 = INSN0(6,6);
15235 UInt rM = (h2 << 3) | INSN0(5,3);
15236 UInt rD = (h1 << 3) | INSN0(2,0);
15237 //if (h1 == 0 && h2 == 0) { // Original T1 was more restrictive
15238 if (rD == 15 && rM == 15) {
15239 // then it's invalid
15240 } else {
15241 IRTemp res = newTemp(Ity_I32);
15242 assign( res, binop(Iop_Add32, getIRegT(rD), getIRegT(rM) ));
15243 if (rD != 15) {
15244 putIRegT( rD, mkexpr(res), condT );
15245 } else {
15246 /* Only allowed outside or last-in IT block; SIGILL if not so. */
15247 gen_SIGILL_T_if_in_but_NLI_ITBlock(old_itstate, new_itstate);
15248 /* jump over insn if not selected */
15249 mk_skip_over_T16_if_cond_is_false(condT);
15250 condT = IRTemp_INVALID;
15251 // now uncond
15252 /* non-interworking branch */
15253 irsb->next = binop(Iop_Or32, mkexpr(res), mkU32(1));
15254 irsb->jumpkind = Ijk_Boring;
15255 dres.whatNext = Dis_StopHere;
15256 }
15257 DIP("add(hi) r%u, r%u\n", rD, rM);
15258 goto decode_success;
15259 }
15260 break;
15261 }
15262
15263 case BITS8(0,1,0,0,0,1,0,1): {
15264 /* ---------------- CMP(HI) Rd, Rm ---------------- */
15265 UInt h1 = INSN0(7,7);
15266 UInt h2 = INSN0(6,6);
15267 UInt rM = (h2 << 3) | INSN0(5,3);
15268 UInt rN = (h1 << 3) | INSN0(2,0);
15269 if (h1 != 0 || h2 != 0) {
15270 IRTemp argL = newTemp(Ity_I32);
15271 IRTemp argR = newTemp(Ity_I32);
15272 assign( argL, getIRegT(rN) );
15273 assign( argR, getIRegT(rM) );
15274 /* Update flags regardless of whether in an IT block or not. */
15275 setFlags_D1_D2( ARMG_CC_OP_SUB, argL, argR, condT );
15276 DIP("cmphi r%u, r%u\n", rN, rM);
15277 goto decode_success;
15278 }
15279 break;
15280 }
15281
15282 case BITS8(0,1,0,0,0,1,1,0): {
15283 /* ---------------- MOV(HI) Rd, Rm ---------------- */
15284 UInt h1 = INSN0(7,7);
15285 UInt h2 = INSN0(6,6);
15286 UInt rM = (h2 << 3) | INSN0(5,3);
15287 UInt rD = (h1 << 3) | INSN0(2,0);
15288 /* The old ARM ARM seems to disallow the case where both Rd and
15289 Rm are "low" registers, but newer versions allow it. */
15290 if (1 /*h1 != 0 || h2 != 0*/) {
15291 IRTemp val = newTemp(Ity_I32);
15292 assign( val, getIRegT(rM) );
15293 if (rD != 15) {
15294 putIRegT( rD, mkexpr(val), condT );
15295 } else {
15296 /* Only allowed outside or last-in IT block; SIGILL if not so. */
15297 gen_SIGILL_T_if_in_but_NLI_ITBlock(old_itstate, new_itstate);
15298 /* jump over insn if not selected */
15299 mk_skip_over_T16_if_cond_is_false(condT);
15300 condT = IRTemp_INVALID;
15301 // now uncond
15302 /* non-interworking branch */
sewardjc6f970f2012-04-02 21:54:49 +000015303 llPutIReg(15, binop(Iop_Or32, mkexpr(val), mkU32(1)));
15304 dres.jk_StopHere = rM == 14 ? Ijk_Ret : Ijk_Boring;
15305 dres.whatNext = Dis_StopHere;
sewardjd2664472010-08-22 12:44:20 +000015306 }
15307 DIP("mov r%u, r%u\n", rD, rM);
15308 goto decode_success;
15309 }
15310 break;
15311 }
15312
15313 case BITS8(1,0,1,1,1,1,1,1): {
15314 /* ---------------- IT (if-then) ---------------- */
15315 UInt firstcond = INSN0(7,4);
15316 UInt mask = INSN0(3,0);
15317 UInt newITSTATE = 0;
15318 /* This is the ITSTATE represented as described in
15319 libvex_guest_arm.h. It is not the ARM ARM representation. */
15320 UChar c1 = '.';
15321 UChar c2 = '.';
15322 UChar c3 = '.';
15323 Bool valid = compute_ITSTATE( &newITSTATE, &c1, &c2, &c3,
15324 firstcond, mask );
15325 if (valid && firstcond != 0xF/*NV*/) {
15326 /* Not allowed in an IT block; SIGILL if so. */
15327 gen_SIGILL_T_if_in_ITBlock(old_itstate, new_itstate);
15328
15329 IRTemp t = newTemp(Ity_I32);
15330 assign(t, mkU32(newITSTATE));
15331 put_ITSTATE(t);
15332
15333 DIP("it%c%c%c %s\n", c1, c2, c3, nCC(firstcond));
15334 goto decode_success;
15335 }
15336 break;
15337 }
15338
15339 case BITS8(1,0,1,1,0,0,0,1):
15340 case BITS8(1,0,1,1,0,0,1,1):
15341 case BITS8(1,0,1,1,1,0,0,1):
15342 case BITS8(1,0,1,1,1,0,1,1): {
15343 /* ---------------- CB{N}Z ---------------- */
15344 UInt rN = INSN0(2,0);
15345 UInt bOP = INSN0(11,11);
15346 UInt imm32 = (INSN0(9,9) << 6) | (INSN0(7,3) << 1);
15347 gen_SIGILL_T_if_in_ITBlock(old_itstate, new_itstate);
15348 /* It's a conditional branch forward. */
15349 IRTemp kond = newTemp(Ity_I1);
15350 assign( kond, binop(bOP ? Iop_CmpNE32 : Iop_CmpEQ32,
15351 getIRegT(rN), mkU32(0)) );
15352
15353 vassert(0 == (guest_R15_curr_instr_notENC & 1));
15354 /* Looks like the nearest insn we can branch to is the one after
15355 next. That makes sense, as there's no point in being able to
15356 encode a conditional branch to the next instruction. */
15357 UInt dst = (guest_R15_curr_instr_notENC + 4 + imm32) | 1;
15358 stmt(IRStmt_Exit( mkexpr(kond),
15359 Ijk_Boring,
sewardjc6f970f2012-04-02 21:54:49 +000015360 IRConst_U32(toUInt(dst)),
15361 OFFB_R15T ));
sewardjd2664472010-08-22 12:44:20 +000015362 DIP("cb%s r%u, 0x%x\n", bOP ? "nz" : "z", rN, dst - 1);
15363 goto decode_success;
15364 }
15365
15366 default:
15367 break; /* examine the next shortest prefix */
15368
15369 }
15370
15371
15372 /* ================ 16-bit 15:9 cases ================ */
15373
15374 switch (INSN0(15,9)) {
15375
15376 case BITS7(1,0,1,1,0,1,0): {
15377 /* ---------------- PUSH ---------------- */
15378 /* This is a bit like STMxx, but way simpler. Complications we
15379 don't have to deal with:
15380 * SP being one of the transferred registers
15381 * direction (increment vs decrement)
15382 * before-vs-after-ness
15383 */
15384 Int i, nRegs;
15385 UInt bitR = INSN0(8,8);
15386 UInt regList = INSN0(7,0);
15387 if (bitR) regList |= (1 << 14);
15388
sewardjb0f1df22012-06-11 21:54:58 +000015389 /* At least one register must be transferred, else result is
15390 UNPREDICTABLE. */
sewardjd2664472010-08-22 12:44:20 +000015391 if (regList != 0) {
15392 /* Since we can't generate a guaranteed non-trapping IR
15393 sequence, (1) jump over the insn if it is gated false, and
15394 (2) back out the ITSTATE update. */
15395 mk_skip_over_T16_if_cond_is_false(condT);
15396 condT = IRTemp_INVALID;
15397 put_ITSTATE(old_itstate);
15398 // now uncond
15399
15400 nRegs = 0;
15401 for (i = 0; i < 16; i++) {
15402 if ((regList & (1 << i)) != 0)
15403 nRegs++;
15404 }
sewardjb0f1df22012-06-11 21:54:58 +000015405 vassert(nRegs >= 1 && nRegs <= 9);
sewardjd2664472010-08-22 12:44:20 +000015406
15407 /* Move SP down first of all, so we're "covered". And don't
15408 mess with its alignment. */
15409 IRTemp newSP = newTemp(Ity_I32);
15410 assign(newSP, binop(Iop_Sub32, getIRegT(13), mkU32(4 * nRegs)));
15411 putIRegT(13, mkexpr(newSP), IRTemp_INVALID);
15412
15413 /* Generate a transfer base address as a forced-aligned
15414 version of the final SP value. */
15415 IRTemp base = newTemp(Ity_I32);
15416 assign(base, binop(Iop_And32, mkexpr(newSP), mkU32(~3)));
15417
15418 /* Now the transfers */
15419 nRegs = 0;
15420 for (i = 0; i < 16; i++) {
15421 if ((regList & (1 << i)) != 0) {
15422 storeLE( binop(Iop_Add32, mkexpr(base), mkU32(4 * nRegs)),
15423 getIRegT(i) );
15424 nRegs++;
15425 }
15426 }
15427
15428 /* Reinstate the ITSTATE update. */
15429 put_ITSTATE(new_itstate);
15430
15431 DIP("push {%s0x%04x}\n", bitR ? "lr," : "", regList & 0xFF);
15432 goto decode_success;
15433 }
15434 break;
15435 }
15436
15437 case BITS7(1,0,1,1,1,1,0): {
15438 /* ---------------- POP ---------------- */
15439 Int i, nRegs;
15440 UInt bitR = INSN0(8,8);
15441 UInt regList = INSN0(7,0);
15442
sewardjb0f1df22012-06-11 21:54:58 +000015443 /* At least one register must be transferred, else result is
15444 UNPREDICTABLE. */
sewardjd2664472010-08-22 12:44:20 +000015445 if (regList != 0 || bitR) {
15446 /* Since we can't generate a guaranteed non-trapping IR
15447 sequence, (1) jump over the insn if it is gated false, and
15448 (2) back out the ITSTATE update. */
15449 mk_skip_over_T16_if_cond_is_false(condT);
15450 condT = IRTemp_INVALID;
15451 put_ITSTATE(old_itstate);
15452 // now uncond
15453
15454 nRegs = 0;
15455 for (i = 0; i < 8; i++) {
15456 if ((regList & (1 << i)) != 0)
15457 nRegs++;
15458 }
sewardjb0f1df22012-06-11 21:54:58 +000015459 vassert(nRegs >= 0 && nRegs <= 8);
sewardjd2664472010-08-22 12:44:20 +000015460 vassert(bitR == 0 || bitR == 1);
15461
15462 IRTemp oldSP = newTemp(Ity_I32);
15463 assign(oldSP, getIRegT(13));
15464
15465 /* Generate a transfer base address as a forced-aligned
15466 version of the original SP value. */
15467 IRTemp base = newTemp(Ity_I32);
15468 assign(base, binop(Iop_And32, mkexpr(oldSP), mkU32(~3)));
15469
15470 /* Compute a new value for SP, but don't install it yet, so
15471 that we're "covered" until all the transfers are done.
15472 And don't mess with its alignment. */
15473 IRTemp newSP = newTemp(Ity_I32);
15474 assign(newSP, binop(Iop_Add32, mkexpr(oldSP),
15475 mkU32(4 * (nRegs + bitR))));
15476
15477 /* Now the transfers, not including PC */
15478 nRegs = 0;
15479 for (i = 0; i < 8; i++) {
15480 if ((regList & (1 << i)) != 0) {
15481 putIRegT(i, loadLE( Ity_I32,
15482 binop(Iop_Add32, mkexpr(base),
15483 mkU32(4 * nRegs))),
15484 IRTemp_INVALID );
15485 nRegs++;
15486 }
15487 }
15488
15489 IRTemp newPC = IRTemp_INVALID;
15490 if (bitR) {
15491 newPC = newTemp(Ity_I32);
15492 assign( newPC, loadLE( Ity_I32,
15493 binop(Iop_Add32, mkexpr(base),
15494 mkU32(4 * nRegs))));
15495 }
15496
15497 /* Now we can safely install the new SP value */
15498 putIRegT(13, mkexpr(newSP), IRTemp_INVALID);
15499
15500 /* Reinstate the ITSTATE update. */
15501 put_ITSTATE(new_itstate);
15502
15503 /* now, do we also have to do a branch? If so, it turns out
15504 that the new PC value is encoded exactly as we need it to
15505 be -- with CPSR.T in the bottom bit. So we can simply use
15506 it as is, no need to mess with it. Note, therefore, this
15507 is an interworking return. */
15508 if (bitR) {
sewardjc6f970f2012-04-02 21:54:49 +000015509 llPutIReg(15, mkexpr(newPC));
15510 dres.jk_StopHere = Ijk_Ret;
15511 dres.whatNext = Dis_StopHere;
sewardjd2664472010-08-22 12:44:20 +000015512 }
15513
15514 DIP("pop {%s0x%04x}\n", bitR ? "pc," : "", regList & 0xFF);
15515 goto decode_success;
15516 }
15517 break;
15518 }
15519
15520 case BITS7(0,0,0,1,1,1,0): /* ADDS */
15521 case BITS7(0,0,0,1,1,1,1): { /* SUBS */
15522 /* ---------------- ADDS Rd, Rn, #uimm3 ---------------- */
15523 /* ---------------- SUBS Rd, Rn, #uimm3 ---------------- */
15524 UInt uimm3 = INSN0(8,6);
15525 UInt rN = INSN0(5,3);
15526 UInt rD = INSN0(2,0);
15527 UInt isSub = INSN0(9,9);
15528 IRTemp argL = newTemp(Ity_I32);
15529 IRTemp argR = newTemp(Ity_I32);
15530 assign( argL, getIRegT(rN) );
15531 assign( argR, mkU32(uimm3) );
15532 putIRegT(rD, binop(isSub ? Iop_Sub32 : Iop_Add32,
15533 mkexpr(argL), mkexpr(argR)),
15534 condT);
15535 setFlags_D1_D2( isSub ? ARMG_CC_OP_SUB : ARMG_CC_OP_ADD,
15536 argL, argR, cond_AND_notInIT_T );
15537 DIP("%s r%u, r%u, #%u\n", isSub ? "subs" : "adds", rD, rN, uimm3);
15538 goto decode_success;
15539 }
15540
15541 case BITS7(0,0,0,1,1,0,0): /* ADDS */
15542 case BITS7(0,0,0,1,1,0,1): { /* SUBS */
15543 /* ---------------- ADDS Rd, Rn, Rm ---------------- */
15544 /* ---------------- SUBS Rd, Rn, Rm ---------------- */
15545 UInt rM = INSN0(8,6);
15546 UInt rN = INSN0(5,3);
15547 UInt rD = INSN0(2,0);
15548 UInt isSub = INSN0(9,9);
15549 IRTemp argL = newTemp(Ity_I32);
15550 IRTemp argR = newTemp(Ity_I32);
15551 assign( argL, getIRegT(rN) );
15552 assign( argR, getIRegT(rM) );
15553 putIRegT( rD, binop(isSub ? Iop_Sub32 : Iop_Add32,
15554 mkexpr(argL), mkexpr(argR)),
15555 condT );
15556 setFlags_D1_D2( isSub ? ARMG_CC_OP_SUB : ARMG_CC_OP_ADD,
15557 argL, argR, cond_AND_notInIT_T );
15558 DIP("%s r%u, r%u, r%u\n", isSub ? "subs" : "adds", rD, rN, rM);
15559 goto decode_success;
15560 }
15561
15562 case BITS7(0,1,0,1,0,0,0): /* STR */
15563 case BITS7(0,1,0,1,1,0,0): { /* LDR */
15564 /* ------------- LDR Rd, [Rn, Rm] ------------- */
15565 /* ------------- STR Rd, [Rn, Rm] ------------- */
15566 /* LDR/STR Rd, [Rn + Rm] */
15567 UInt rD = INSN0(2,0);
15568 UInt rN = INSN0(5,3);
15569 UInt rM = INSN0(8,6);
15570 UInt isLD = INSN0(11,11);
15571
15572 mk_skip_over_T16_if_cond_is_false(condT);
15573 condT = IRTemp_INVALID;
15574 // now uncond
15575
15576 IRExpr* ea = binop(Iop_Add32, getIRegT(rN), getIRegT(rM));
15577 put_ITSTATE(old_itstate); // backout
15578 if (isLD) {
15579 putIRegT(rD, loadLE(Ity_I32, ea), IRTemp_INVALID);
15580 } else {
15581 storeLE(ea, getIRegT(rD));
15582 }
15583 put_ITSTATE(new_itstate); // restore
15584
15585 DIP("%s r%u, [r%u, r%u]\n", isLD ? "ldr" : "str", rD, rN, rM);
15586 goto decode_success;
15587 }
15588
15589 case BITS7(0,1,0,1,0,0,1):
15590 case BITS7(0,1,0,1,1,0,1): {
15591 /* ------------- LDRH Rd, [Rn, Rm] ------------- */
15592 /* ------------- STRH Rd, [Rn, Rm] ------------- */
15593 /* LDRH/STRH Rd, [Rn + Rm] */
15594 UInt rD = INSN0(2,0);
15595 UInt rN = INSN0(5,3);
15596 UInt rM = INSN0(8,6);
15597 UInt isLD = INSN0(11,11);
15598
15599 mk_skip_over_T16_if_cond_is_false(condT);
15600 condT = IRTemp_INVALID;
15601 // now uncond
15602
15603 IRExpr* ea = binop(Iop_Add32, getIRegT(rN), getIRegT(rM));
15604 put_ITSTATE(old_itstate); // backout
15605 if (isLD) {
15606 putIRegT(rD, unop(Iop_16Uto32, loadLE(Ity_I16, ea)),
15607 IRTemp_INVALID);
15608 } else {
15609 storeLE( ea, unop(Iop_32to16, getIRegT(rD)) );
15610 }
15611 put_ITSTATE(new_itstate); // restore
15612
15613 DIP("%sh r%u, [r%u, r%u]\n", isLD ? "ldr" : "str", rD, rN, rM);
15614 goto decode_success;
15615 }
15616
15617 case BITS7(0,1,0,1,1,1,1): {
15618 /* ------------- LDRSH Rd, [Rn, Rm] ------------- */
15619 /* LDRSH Rd, [Rn + Rm] */
15620 UInt rD = INSN0(2,0);
15621 UInt rN = INSN0(5,3);
15622 UInt rM = INSN0(8,6);
15623
15624 mk_skip_over_T16_if_cond_is_false(condT);
15625 condT = IRTemp_INVALID;
15626 // now uncond
15627
15628 IRExpr* ea = binop(Iop_Add32, getIRegT(rN), getIRegT(rM));
15629 put_ITSTATE(old_itstate); // backout
15630 putIRegT(rD, unop(Iop_16Sto32, loadLE(Ity_I16, ea)),
15631 IRTemp_INVALID);
15632 put_ITSTATE(new_itstate); // restore
15633
15634 DIP("ldrsh r%u, [r%u, r%u]\n", rD, rN, rM);
15635 goto decode_success;
15636 }
15637
15638 case BITS7(0,1,0,1,0,1,1): {
15639 /* ------------- LDRSB Rd, [Rn, Rm] ------------- */
15640 /* LDRSB Rd, [Rn + Rm] */
15641 UInt rD = INSN0(2,0);
15642 UInt rN = INSN0(5,3);
15643 UInt rM = INSN0(8,6);
15644
15645 mk_skip_over_T16_if_cond_is_false(condT);
15646 condT = IRTemp_INVALID;
15647 // now uncond
15648
15649 IRExpr* ea = binop(Iop_Add32, getIRegT(rN), getIRegT(rM));
15650 put_ITSTATE(old_itstate); // backout
15651 putIRegT(rD, unop(Iop_8Sto32, loadLE(Ity_I8, ea)),
15652 IRTemp_INVALID);
15653 put_ITSTATE(new_itstate); // restore
15654
15655 DIP("ldrsb r%u, [r%u, r%u]\n", rD, rN, rM);
15656 goto decode_success;
15657 }
15658
15659 case BITS7(0,1,0,1,0,1,0):
15660 case BITS7(0,1,0,1,1,1,0): {
15661 /* ------------- LDRB Rd, [Rn, Rm] ------------- */
15662 /* ------------- STRB Rd, [Rn, Rm] ------------- */
15663 /* LDRB/STRB Rd, [Rn + Rm] */
15664 UInt rD = INSN0(2,0);
15665 UInt rN = INSN0(5,3);
15666 UInt rM = INSN0(8,6);
15667 UInt isLD = INSN0(11,11);
15668
15669 mk_skip_over_T16_if_cond_is_false(condT);
15670 condT = IRTemp_INVALID;
15671 // now uncond
15672
15673 IRExpr* ea = binop(Iop_Add32, getIRegT(rN), getIRegT(rM));
15674 put_ITSTATE(old_itstate); // backout
15675 if (isLD) {
15676 putIRegT(rD, unop(Iop_8Uto32, loadLE(Ity_I8, ea)),
15677 IRTemp_INVALID);
15678 } else {
15679 storeLE( ea, unop(Iop_32to8, getIRegT(rD)) );
15680 }
15681 put_ITSTATE(new_itstate); // restore
15682
15683 DIP("%sb r%u, [r%u, r%u]\n", isLD ? "ldr" : "str", rD, rN, rM);
15684 goto decode_success;
15685 }
15686
15687 default:
15688 break; /* examine the next shortest prefix */
15689
15690 }
15691
15692
15693 /* ================ 16-bit 15:11 cases ================ */
15694
15695 switch (INSN0(15,11)) {
15696
15697 case BITS5(0,0,1,1,0):
15698 case BITS5(0,0,1,1,1): {
15699 /* ---------------- ADDS Rn, #uimm8 ---------------- */
15700 /* ---------------- SUBS Rn, #uimm8 ---------------- */
15701 UInt isSub = INSN0(11,11);
15702 UInt rN = INSN0(10,8);
15703 UInt uimm8 = INSN0(7,0);
15704 IRTemp argL = newTemp(Ity_I32);
15705 IRTemp argR = newTemp(Ity_I32);
15706 assign( argL, getIRegT(rN) );
15707 assign( argR, mkU32(uimm8) );
15708 putIRegT( rN, binop(isSub ? Iop_Sub32 : Iop_Add32,
15709 mkexpr(argL), mkexpr(argR)), condT );
15710 setFlags_D1_D2( isSub ? ARMG_CC_OP_SUB : ARMG_CC_OP_ADD,
15711 argL, argR, cond_AND_notInIT_T );
15712 DIP("%s r%u, #%u\n", isSub ? "subs" : "adds", rN, uimm8);
15713 goto decode_success;
15714 }
15715
15716 case BITS5(1,0,1,0,0): {
15717 /* ---------------- ADD rD, PC, #imm8 * 4 ---------------- */
15718 /* a.k.a. ADR */
15719 /* rD = align4(PC) + imm8 * 4 */
15720 UInt rD = INSN0(10,8);
15721 UInt imm8 = INSN0(7,0);
15722 putIRegT(rD, binop(Iop_Add32,
sewardjdf86f162010-08-22 18:47:30 +000015723 binop(Iop_And32, getIRegT(15), mkU32(~3U)),
sewardjd2664472010-08-22 12:44:20 +000015724 mkU32(imm8 * 4)),
15725 condT);
15726 DIP("add r%u, pc, #%u\n", rD, imm8 * 4);
15727 goto decode_success;
15728 }
15729
15730 case BITS5(1,0,1,0,1): {
15731 /* ---------------- ADD rD, SP, #imm8 * 4 ---------------- */
15732 UInt rD = INSN0(10,8);
15733 UInt imm8 = INSN0(7,0);
15734 putIRegT(rD, binop(Iop_Add32, getIRegT(13), mkU32(imm8 * 4)),
15735 condT);
15736 DIP("add r%u, r13, #%u\n", rD, imm8 * 4);
15737 goto decode_success;
15738 }
15739
15740 case BITS5(0,0,1,0,1): {
15741 /* ---------------- CMP Rn, #uimm8 ---------------- */
15742 UInt rN = INSN0(10,8);
15743 UInt uimm8 = INSN0(7,0);
15744 IRTemp argL = newTemp(Ity_I32);
15745 IRTemp argR = newTemp(Ity_I32);
15746 assign( argL, getIRegT(rN) );
15747 assign( argR, mkU32(uimm8) );
15748 /* Update flags regardless of whether in an IT block or not. */
15749 setFlags_D1_D2( ARMG_CC_OP_SUB, argL, argR, condT );
15750 DIP("cmp r%u, #%u\n", rN, uimm8);
15751 goto decode_success;
15752 }
15753
15754 case BITS5(0,0,1,0,0): {
15755 /* -------------- (T1) MOVS Rn, #uimm8 -------------- */
15756 UInt rD = INSN0(10,8);
15757 UInt uimm8 = INSN0(7,0);
15758 IRTemp oldV = newTemp(Ity_I32);
15759 IRTemp oldC = newTemp(Ity_I32);
15760 IRTemp res = newTemp(Ity_I32);
15761 assign( oldV, mk_armg_calculate_flag_v() );
15762 assign( oldC, mk_armg_calculate_flag_c() );
15763 assign( res, mkU32(uimm8) );
15764 putIRegT(rD, mkexpr(res), condT);
15765 setFlags_D1_D2_ND( ARMG_CC_OP_LOGIC, res, oldC, oldV,
15766 cond_AND_notInIT_T );
15767 DIP("movs r%u, #%u\n", rD, uimm8);
15768 goto decode_success;
15769 }
15770
15771 case BITS5(0,1,0,0,1): {
15772 /* ------------- LDR Rd, [PC, #imm8 * 4] ------------- */
15773 /* LDR Rd, [align4(PC) + imm8 * 4] */
15774 UInt rD = INSN0(10,8);
15775 UInt imm8 = INSN0(7,0);
15776 IRTemp ea = newTemp(Ity_I32);
15777
15778 mk_skip_over_T16_if_cond_is_false(condT);
15779 condT = IRTemp_INVALID;
15780 // now uncond
15781
15782 assign(ea, binop(Iop_Add32,
sewardjdf86f162010-08-22 18:47:30 +000015783 binop(Iop_And32, getIRegT(15), mkU32(~3U)),
sewardjd2664472010-08-22 12:44:20 +000015784 mkU32(imm8 * 4)));
15785 put_ITSTATE(old_itstate); // backout
15786 putIRegT(rD, loadLE(Ity_I32, mkexpr(ea)),
15787 IRTemp_INVALID);
15788 put_ITSTATE(new_itstate); // restore
15789
15790 DIP("ldr r%u, [pc, #%u]\n", rD, imm8 * 4);
15791 goto decode_success;
15792 }
15793
15794 case BITS5(0,1,1,0,0): /* STR */
15795 case BITS5(0,1,1,0,1): { /* LDR */
15796 /* ------------- LDR Rd, [Rn, #imm5 * 4] ------------- */
15797 /* ------------- STR Rd, [Rn, #imm5 * 4] ------------- */
15798 /* LDR/STR Rd, [Rn + imm5 * 4] */
15799 UInt rD = INSN0(2,0);
15800 UInt rN = INSN0(5,3);
15801 UInt imm5 = INSN0(10,6);
15802 UInt isLD = INSN0(11,11);
15803
15804 mk_skip_over_T16_if_cond_is_false(condT);
15805 condT = IRTemp_INVALID;
15806 // now uncond
15807
15808 IRExpr* ea = binop(Iop_Add32, getIRegT(rN), mkU32(imm5 * 4));
15809 put_ITSTATE(old_itstate); // backout
15810 if (isLD) {
15811 putIRegT(rD, loadLE(Ity_I32, ea), IRTemp_INVALID);
15812 } else {
15813 storeLE( ea, getIRegT(rD) );
15814 }
15815 put_ITSTATE(new_itstate); // restore
15816
15817 DIP("%s r%u, [r%u, #%u]\n", isLD ? "ldr" : "str", rD, rN, imm5 * 4);
15818 goto decode_success;
15819 }
15820
15821 case BITS5(1,0,0,0,0): /* STRH */
15822 case BITS5(1,0,0,0,1): { /* LDRH */
15823 /* ------------- LDRH Rd, [Rn, #imm5 * 2] ------------- */
15824 /* ------------- STRH Rd, [Rn, #imm5 * 2] ------------- */
15825 /* LDRH/STRH Rd, [Rn + imm5 * 2] */
15826 UInt rD = INSN0(2,0);
15827 UInt rN = INSN0(5,3);
15828 UInt imm5 = INSN0(10,6);
15829 UInt isLD = INSN0(11,11);
15830
15831 mk_skip_over_T16_if_cond_is_false(condT);
15832 condT = IRTemp_INVALID;
15833 // now uncond
15834
15835 IRExpr* ea = binop(Iop_Add32, getIRegT(rN), mkU32(imm5 * 2));
15836 put_ITSTATE(old_itstate); // backout
15837 if (isLD) {
15838 putIRegT(rD, unop(Iop_16Uto32, loadLE(Ity_I16, ea)),
15839 IRTemp_INVALID);
15840 } else {
15841 storeLE( ea, unop(Iop_32to16, getIRegT(rD)) );
15842 }
15843 put_ITSTATE(new_itstate); // restore
15844
15845 DIP("%sh r%u, [r%u, #%u]\n", isLD ? "ldr" : "str", rD, rN, imm5 * 2);
15846 goto decode_success;
15847 }
15848
15849 case BITS5(0,1,1,1,0): /* STRB */
15850 case BITS5(0,1,1,1,1): { /* LDRB */
15851 /* ------------- LDRB Rd, [Rn, #imm5] ------------- */
15852 /* ------------- STRB Rd, [Rn, #imm5] ------------- */
15853 /* LDRB/STRB Rd, [Rn + imm5] */
15854 UInt rD = INSN0(2,0);
15855 UInt rN = INSN0(5,3);
15856 UInt imm5 = INSN0(10,6);
15857 UInt isLD = INSN0(11,11);
15858
15859 mk_skip_over_T16_if_cond_is_false(condT);
15860 condT = IRTemp_INVALID;
15861 // now uncond
15862
15863 IRExpr* ea = binop(Iop_Add32, getIRegT(rN), mkU32(imm5));
15864 put_ITSTATE(old_itstate); // backout
15865 if (isLD) {
15866 putIRegT(rD, unop(Iop_8Uto32, loadLE(Ity_I8, ea)),
15867 IRTemp_INVALID);
15868 } else {
15869 storeLE( ea, unop(Iop_32to8, getIRegT(rD)) );
15870 }
15871 put_ITSTATE(new_itstate); // restore
15872
15873 DIP("%sb r%u, [r%u, #%u]\n", isLD ? "ldr" : "str", rD, rN, imm5);
15874 goto decode_success;
15875 }
15876
15877 case BITS5(1,0,0,1,0): /* STR */
15878 case BITS5(1,0,0,1,1): { /* LDR */
15879 /* ------------- LDR Rd, [SP, #imm8 * 4] ------------- */
15880 /* ------------- STR Rd, [SP, #imm8 * 4] ------------- */
15881 /* LDR/STR Rd, [SP + imm8 * 4] */
15882 UInt rD = INSN0(10,8);
15883 UInt imm8 = INSN0(7,0);
15884 UInt isLD = INSN0(11,11);
15885
15886 mk_skip_over_T16_if_cond_is_false(condT);
15887 condT = IRTemp_INVALID;
15888 // now uncond
15889
15890 IRExpr* ea = binop(Iop_Add32, getIRegT(13), mkU32(imm8 * 4));
15891 put_ITSTATE(old_itstate); // backout
15892 if (isLD) {
15893 putIRegT(rD, loadLE(Ity_I32, ea), IRTemp_INVALID);
15894 } else {
15895 storeLE(ea, getIRegT(rD));
15896 }
15897 put_ITSTATE(new_itstate); // restore
15898
15899 DIP("%s r%u, [sp, #%u]\n", isLD ? "ldr" : "str", rD, imm8 * 4);
15900 goto decode_success;
15901 }
15902
15903 case BITS5(1,1,0,0,1): {
15904 /* ------------- LDMIA Rn!, {reglist} ------------- */
15905 Int i, nRegs = 0;
15906 UInt rN = INSN0(10,8);
15907 UInt list = INSN0(7,0);
15908 /* Empty lists aren't allowed. */
15909 if (list != 0) {
15910 mk_skip_over_T16_if_cond_is_false(condT);
15911 condT = IRTemp_INVALID;
15912 put_ITSTATE(old_itstate);
15913 // now uncond
15914
15915 IRTemp oldRn = newTemp(Ity_I32);
15916 IRTemp base = newTemp(Ity_I32);
15917 assign(oldRn, getIRegT(rN));
sewardjdf86f162010-08-22 18:47:30 +000015918 assign(base, binop(Iop_And32, mkexpr(oldRn), mkU32(~3U)));
sewardjd2664472010-08-22 12:44:20 +000015919 for (i = 0; i < 8; i++) {
15920 if (0 == (list & (1 << i)))
15921 continue;
15922 nRegs++;
15923 putIRegT(
15924 i, loadLE(Ity_I32,
15925 binop(Iop_Add32, mkexpr(base),
15926 mkU32(nRegs * 4 - 4))),
15927 IRTemp_INVALID
15928 );
15929 }
15930 /* Only do the writeback for rN if it isn't in the list of
15931 registers to be transferred. */
15932 if (0 == (list & (1 << rN))) {
15933 putIRegT(rN,
15934 binop(Iop_Add32, mkexpr(oldRn),
15935 mkU32(nRegs * 4)),
15936 IRTemp_INVALID
15937 );
15938 }
15939
15940 /* Reinstate the ITSTATE update. */
15941 put_ITSTATE(new_itstate);
15942
15943 DIP("ldmia r%u!, {0x%04x}\n", rN, list);
15944 goto decode_success;
15945 }
15946 break;
15947 }
15948
15949 case BITS5(1,1,0,0,0): {
15950 /* ------------- STMIA Rn!, {reglist} ------------- */
15951 Int i, nRegs = 0;
15952 UInt rN = INSN0(10,8);
15953 UInt list = INSN0(7,0);
15954 /* Empty lists aren't allowed. Also, if rN is in the list then
15955 it must be the lowest numbered register in the list. */
15956 Bool valid = list != 0;
15957 if (valid && 0 != (list & (1 << rN))) {
15958 for (i = 0; i < rN; i++) {
15959 if (0 != (list & (1 << i)))
15960 valid = False;
15961 }
15962 }
15963 if (valid) {
15964 mk_skip_over_T16_if_cond_is_false(condT);
15965 condT = IRTemp_INVALID;
15966 put_ITSTATE(old_itstate);
15967 // now uncond
15968
15969 IRTemp oldRn = newTemp(Ity_I32);
15970 IRTemp base = newTemp(Ity_I32);
15971 assign(oldRn, getIRegT(rN));
sewardjdf86f162010-08-22 18:47:30 +000015972 assign(base, binop(Iop_And32, mkexpr(oldRn), mkU32(~3U)));
sewardjd2664472010-08-22 12:44:20 +000015973 for (i = 0; i < 8; i++) {
15974 if (0 == (list & (1 << i)))
15975 continue;
15976 nRegs++;
15977 storeLE( binop(Iop_Add32, mkexpr(base), mkU32(nRegs * 4 - 4)),
15978 getIRegT(i) );
15979 }
15980 /* Always do the writeback. */
15981 putIRegT(rN,
15982 binop(Iop_Add32, mkexpr(oldRn),
15983 mkU32(nRegs * 4)),
15984 IRTemp_INVALID);
15985
15986 /* Reinstate the ITSTATE update. */
15987 put_ITSTATE(new_itstate);
15988
15989 DIP("stmia r%u!, {0x%04x}\n", rN, list);
15990 goto decode_success;
15991 }
15992 break;
15993 }
15994
15995 case BITS5(0,0,0,0,0): /* LSLS */
15996 case BITS5(0,0,0,0,1): /* LSRS */
15997 case BITS5(0,0,0,1,0): { /* ASRS */
15998 /* ---------------- LSLS Rd, Rm, #imm5 ---------------- */
15999 /* ---------------- LSRS Rd, Rm, #imm5 ---------------- */
16000 /* ---------------- ASRS Rd, Rm, #imm5 ---------------- */
16001 UInt rD = INSN0(2,0);
16002 UInt rM = INSN0(5,3);
16003 UInt imm5 = INSN0(10,6);
16004 IRTemp res = newTemp(Ity_I32);
16005 IRTemp resC = newTemp(Ity_I32);
16006 IRTemp rMt = newTemp(Ity_I32);
16007 IRTemp oldV = newTemp(Ity_I32);
16008 HChar* wot = "???";
16009 assign(rMt, getIRegT(rM));
16010 assign(oldV, mk_armg_calculate_flag_v());
16011 /* Looks like INSN0(12,11) are the standard 'how' encoding.
16012 Could compactify if the ROR case later appears. */
16013 switch (INSN0(15,11)) {
16014 case BITS5(0,0,0,0,0):
16015 compute_result_and_C_after_LSL_by_imm5(
16016 dis_buf, &res, &resC, rMt, imm5, rM
16017 );
16018 wot = "lsl";
16019 break;
16020 case BITS5(0,0,0,0,1):
16021 compute_result_and_C_after_LSR_by_imm5(
16022 dis_buf, &res, &resC, rMt, imm5, rM
16023 );
16024 wot = "lsr";
16025 break;
16026 case BITS5(0,0,0,1,0):
16027 compute_result_and_C_after_ASR_by_imm5(
16028 dis_buf, &res, &resC, rMt, imm5, rM
16029 );
16030 wot = "asr";
16031 break;
16032 default:
16033 /*NOTREACHED*/vassert(0);
16034 }
16035 // not safe to read guest state after this point
16036 putIRegT(rD, mkexpr(res), condT);
16037 setFlags_D1_D2_ND( ARMG_CC_OP_LOGIC, res, resC, oldV,
16038 cond_AND_notInIT_T );
16039 /* ignore buf and roll our own output */
16040 DIP("%ss r%u, r%u, #%u\n", wot, rD, rM, imm5);
16041 goto decode_success;
16042 }
16043
16044 case BITS5(1,1,1,0,0): {
16045 /* ---------------- B #simm11 ---------------- */
16046 Int simm11 = INSN0(10,0);
16047 simm11 = (simm11 << 21) >> 20;
16048 UInt dst = simm11 + guest_R15_curr_instr_notENC + 4;
16049 /* Only allowed outside or last-in IT block; SIGILL if not so. */
16050 gen_SIGILL_T_if_in_but_NLI_ITBlock(old_itstate, new_itstate);
16051 // and skip this insn if not selected; being cleverer is too
16052 // difficult
16053 mk_skip_over_T16_if_cond_is_false(condT);
16054 condT = IRTemp_INVALID;
16055 // now uncond
sewardjc6f970f2012-04-02 21:54:49 +000016056 llPutIReg(15, mkU32( dst | 1 /*CPSR.T*/ ));
16057 dres.jk_StopHere = Ijk_Boring;
16058 dres.whatNext = Dis_StopHere;
sewardjd2664472010-08-22 12:44:20 +000016059 DIP("b 0x%x\n", dst);
16060 goto decode_success;
16061 }
16062
16063 default:
16064 break; /* examine the next shortest prefix */
16065
16066 }
16067
16068
16069 /* ================ 16-bit 15:12 cases ================ */
16070
16071 switch (INSN0(15,12)) {
16072
16073 case BITS4(1,1,0,1): {
16074 /* ---------------- Bcond #simm8 ---------------- */
16075 UInt cond = INSN0(11,8);
16076 Int simm8 = INSN0(7,0);
16077 simm8 = (simm8 << 24) >> 23;
16078 UInt dst = simm8 + guest_R15_curr_instr_notENC + 4;
16079 if (cond != ARMCondAL && cond != ARMCondNV) {
16080 /* Not allowed in an IT block; SIGILL if so. */
16081 gen_SIGILL_T_if_in_ITBlock(old_itstate, new_itstate);
16082
16083 IRTemp kondT = newTemp(Ity_I32);
16084 assign( kondT, mk_armg_calculate_condition(cond) );
16085 stmt( IRStmt_Exit( unop(Iop_32to1, mkexpr(kondT)),
16086 Ijk_Boring,
sewardjc6f970f2012-04-02 21:54:49 +000016087 IRConst_U32(dst | 1/*CPSR.T*/),
16088 OFFB_R15T ));
16089 llPutIReg(15, mkU32( (guest_R15_curr_instr_notENC + 2)
16090 | 1 /*CPSR.T*/ ));
16091 dres.jk_StopHere = Ijk_Boring;
16092 dres.whatNext = Dis_StopHere;
sewardjd2664472010-08-22 12:44:20 +000016093 DIP("b%s 0x%x\n", nCC(cond), dst);
16094 goto decode_success;
16095 }
16096 break;
16097 }
16098
16099 default:
16100 break; /* hmm, nothing matched */
16101
16102 }
16103
16104 /* ================ 16-bit misc cases ================ */
16105
16106 /* ------ NOP ------ */
16107 if (INSN0(15,0) == 0xBF00) {
16108 DIP("nop");
16109 goto decode_success;
16110 }
16111
16112 /* ----------------------------------------------------------- */
16113 /* -- -- */
16114 /* -- Thumb 32-bit integer instructions -- */
16115 /* -- -- */
16116 /* ----------------------------------------------------------- */
16117
16118# define INSN1(_bMax,_bMin) SLICE_UInt(((UInt)insn1), (_bMax), (_bMin))
16119
16120 /* second 16 bits of the instruction, if any */
16121 UShort insn1 = getUShortLittleEndianly( guest_instr+2 );
16122
16123 anOp = Iop_INVALID; /* paranoia */
16124 anOpNm = NULL; /* paranoia */
16125
16126 /* Change result defaults to suit 32-bit insns. */
16127 vassert(dres.whatNext == Dis_Continue);
16128 vassert(dres.len == 2);
16129 vassert(dres.continueAt == 0);
16130 dres.len = 4;
16131
16132 /* ---------------- BL/BLX simm26 ---------------- */
16133 if (BITS5(1,1,1,1,0) == INSN0(15,11) && BITS2(1,1) == INSN1(15,14)) {
16134 UInt isBL = INSN1(12,12);
16135 UInt bS = INSN0(10,10);
16136 UInt bJ1 = INSN1(13,13);
16137 UInt bJ2 = INSN1(11,11);
16138 UInt bI1 = 1 ^ (bJ1 ^ bS);
16139 UInt bI2 = 1 ^ (bJ2 ^ bS);
16140 Int simm25
16141 = (bS << (1 + 1 + 10 + 11 + 1))
16142 | (bI1 << (1 + 10 + 11 + 1))
16143 | (bI2 << (10 + 11 + 1))
16144 | (INSN0(9,0) << (11 + 1))
16145 | (INSN1(10,0) << 1);
16146 simm25 = (simm25 << 7) >> 7;
16147
16148 vassert(0 == (guest_R15_curr_instr_notENC & 1));
16149 UInt dst = simm25 + guest_R15_curr_instr_notENC + 4;
16150
16151 /* One further validity case to check: in the case of BLX
16152 (not-BL), that insn1[0] must be zero. */
16153 Bool valid = True;
16154 if (isBL == 0 && INSN1(0,0) == 1) valid = False;
16155 if (valid) {
16156 /* Only allowed outside or last-in IT block; SIGILL if not so. */
16157 gen_SIGILL_T_if_in_but_NLI_ITBlock(old_itstate, new_itstate);
16158 // and skip this insn if not selected; being cleverer is too
16159 // difficult
16160 mk_skip_over_T32_if_cond_is_false(condT);
16161 condT = IRTemp_INVALID;
16162 // now uncond
16163
16164 /* We're returning to Thumb code, hence "| 1" */
16165 putIRegT( 14, mkU32( (guest_R15_curr_instr_notENC + 4) | 1 ),
16166 IRTemp_INVALID);
16167 if (isBL) {
16168 /* BL: unconditional T -> T call */
16169 /* we're calling Thumb code, hence "| 1" */
sewardjc6f970f2012-04-02 21:54:49 +000016170 llPutIReg(15, mkU32( dst | 1 ));
sewardjd2664472010-08-22 12:44:20 +000016171 DIP("bl 0x%x (stay in Thumb mode)\n", dst);
16172 } else {
16173 /* BLX: unconditional T -> A call */
16174 /* we're calling ARM code, hence "& 3" to align to a
16175 valid ARM insn address */
sewardjc6f970f2012-04-02 21:54:49 +000016176 llPutIReg(15, mkU32( dst & ~3 ));
sewardjd2664472010-08-22 12:44:20 +000016177 DIP("blx 0x%x (switch to ARM mode)\n", dst & ~3);
16178 }
sewardjc6f970f2012-04-02 21:54:49 +000016179 dres.whatNext = Dis_StopHere;
16180 dres.jk_StopHere = Ijk_Call;
sewardjd2664472010-08-22 12:44:20 +000016181 goto decode_success;
16182 }
16183 }
16184
16185 /* ---------------- {LD,ST}M{IA,DB} ---------------- */
16186 if (0x3a2 == INSN0(15,6) // {LD,ST}MIA
16187 || 0x3a4 == INSN0(15,6)) { // {LD,ST}MDB
16188 UInt bW = INSN0(5,5); /* writeback Rn ? */
16189 UInt bL = INSN0(4,4);
16190 UInt rN = INSN0(3,0);
16191 UInt bP = INSN1(15,15); /* reglist entry for r15 */
16192 UInt bM = INSN1(14,14); /* reglist entry for r14 */
16193 UInt rLmost = INSN1(12,0); /* reglist entry for r0 .. 12 */
16194 UInt rL13 = INSN1(13,13); /* must be zero */
16195 UInt regList = 0;
16196 Bool valid = True;
16197
16198 UInt bINC = 1;
16199 UInt bBEFORE = 0;
16200 if (INSN0(15,6) == 0x3a4) {
16201 bINC = 0;
16202 bBEFORE = 1;
16203 }
16204
16205 /* detect statically invalid cases, and construct the final
16206 reglist */
16207 if (rL13 == 1)
16208 valid = False;
16209
16210 if (bL == 1) {
16211 regList = (bP << 15) | (bM << 14) | rLmost;
16212 if (rN == 15) valid = False;
16213 if (popcount32(regList) < 2) valid = False;
16214 if (bP == 1 && bM == 1) valid = False;
16215 if (bW == 1 && (regList & (1<<rN))) valid = False;
16216 } else {
16217 regList = (bM << 14) | rLmost;
16218 if (bP == 1) valid = False;
16219 if (rN == 15) valid = False;
16220 if (popcount32(regList) < 2) valid = False;
16221 if (bW == 1 && (regList & (1<<rN))) valid = False;
16222 if (regList & (1<<rN)) {
16223 UInt i;
16224 /* if Rn is in the list, then it must be the
16225 lowest numbered entry */
16226 for (i = 0; i < rN; i++) {
16227 if (regList & (1<<i))
16228 valid = False;
16229 }
16230 }
16231 }
16232
16233 if (valid) {
16234 if (bL == 1 && bP == 1) {
16235 // We'll be writing the PC. Hence:
16236 /* Only allowed outside or last-in IT block; SIGILL if not so. */
16237 gen_SIGILL_T_if_in_but_NLI_ITBlock(old_itstate, new_itstate);
16238 }
16239
16240 /* Go uncond: */
16241 mk_skip_over_T32_if_cond_is_false(condT);
16242 condT = IRTemp_INVALID;
16243 // now uncond
16244
sewardjc6f970f2012-04-02 21:54:49 +000016245 /* Generate the IR. This might generate a write to R15. */
sewardjd2664472010-08-22 12:44:20 +000016246 mk_ldm_stm(False/*!arm*/, rN, bINC, bBEFORE, bW, bL, regList);
16247
16248 if (bL == 1 && (regList & (1<<15))) {
16249 // If we wrote to R15, we have an interworking return to
16250 // deal with.
sewardjc6f970f2012-04-02 21:54:49 +000016251 llPutIReg(15, llGetIReg(15));
16252 dres.jk_StopHere = Ijk_Ret;
16253 dres.whatNext = Dis_StopHere;
sewardjd2664472010-08-22 12:44:20 +000016254 }
16255
16256 DIP("%sm%c%c r%u%s, {0x%04x}\n",
16257 bL == 1 ? "ld" : "st", bINC ? 'i' : 'd', bBEFORE ? 'b' : 'a',
16258 rN, bW ? "!" : "", regList);
16259
16260 goto decode_success;
16261 }
16262 }
16263
16264 /* -------------- (T3) ADD{S}.W Rd, Rn, #constT -------------- */
16265 if (INSN0(15,11) == BITS5(1,1,1,1,0)
16266 && INSN0(9,5) == BITS5(0,1,0,0,0)
16267 && INSN1(15,15) == 0) {
16268 UInt bS = INSN0(4,4);
16269 UInt rN = INSN0(3,0);
16270 UInt rD = INSN1(11,8);
16271 Bool valid = !isBadRegT(rN) && !isBadRegT(rD);
sewardj51016d12011-10-26 15:06:25 +000016272 /* but allow "add.w reg, sp, #constT" for reg != PC */
16273 if (!valid && rD <= 14 && rN == 13)
sewardjd2664472010-08-22 12:44:20 +000016274 valid = True;
16275 if (valid) {
16276 IRTemp argL = newTemp(Ity_I32);
16277 IRTemp argR = newTemp(Ity_I32);
16278 IRTemp res = newTemp(Ity_I32);
16279 UInt imm32 = thumbExpandImm_from_I0_I1(NULL, insn0, insn1);
16280 assign(argL, getIRegT(rN));
16281 assign(argR, mkU32(imm32));
16282 assign(res, binop(Iop_Add32, mkexpr(argL), mkexpr(argR)));
16283 putIRegT(rD, mkexpr(res), condT);
16284 if (bS == 1)
16285 setFlags_D1_D2( ARMG_CC_OP_ADD, argL, argR, condT );
16286 DIP("add%s.w r%u, r%u, #%u\n",
16287 bS == 1 ? "s" : "", rD, rN, imm32);
16288 goto decode_success;
16289 }
16290 }
16291
sewardjdbf3d592011-07-08 15:36:59 +000016292 /* ---------------- (T4) ADDW Rd, Rn, #uimm12 -------------- */
16293 if (INSN0(15,11) == BITS5(1,1,1,1,0)
16294 && INSN0(9,4) == BITS6(1,0,0,0,0,0)
16295 && INSN1(15,15) == 0) {
16296 UInt rN = INSN0(3,0);
16297 UInt rD = INSN1(11,8);
16298 Bool valid = !isBadRegT(rN) && !isBadRegT(rD);
sewardj51016d12011-10-26 15:06:25 +000016299 /* but allow "addw reg, sp, #uimm12" for reg != PC */
16300 if (!valid && rD <= 14 && rN == 13)
sewardjdbf3d592011-07-08 15:36:59 +000016301 valid = True;
16302 if (valid) {
16303 IRTemp argL = newTemp(Ity_I32);
16304 IRTemp argR = newTemp(Ity_I32);
16305 IRTemp res = newTemp(Ity_I32);
16306 UInt imm12 = (INSN0(10,10) << 11) | (INSN1(14,12) << 8) | INSN1(7,0);
16307 assign(argL, getIRegT(rN));
16308 assign(argR, mkU32(imm12));
16309 assign(res, binop(Iop_Add32, mkexpr(argL), mkexpr(argR)));
16310 putIRegT(rD, mkexpr(res), condT);
16311 DIP("addw r%u, r%u, #%u\n", rD, rN, imm12);
16312 goto decode_success;
16313 }
16314 }
16315
sewardjd2664472010-08-22 12:44:20 +000016316 /* ---------------- (T2) CMP.W Rn, #constT ---------------- */
16317 /* ---------------- (T2) CMN.W Rn, #constT ---------------- */
16318 if (INSN0(15,11) == BITS5(1,1,1,1,0)
16319 && ( INSN0(9,4) == BITS6(0,1,1,0,1,1) // CMP
16320 || INSN0(9,4) == BITS6(0,1,0,0,0,1)) // CMN
16321 && INSN1(15,15) == 0
16322 && INSN1(11,8) == BITS4(1,1,1,1)) {
16323 UInt rN = INSN0(3,0);
16324 if (rN != 15) {
16325 IRTemp argL = newTemp(Ity_I32);
16326 IRTemp argR = newTemp(Ity_I32);
16327 Bool isCMN = INSN0(9,4) == BITS6(0,1,0,0,0,1);
16328 UInt imm32 = thumbExpandImm_from_I0_I1(NULL, insn0, insn1);
16329 assign(argL, getIRegT(rN));
16330 assign(argR, mkU32(imm32));
16331 setFlags_D1_D2( isCMN ? ARMG_CC_OP_ADD : ARMG_CC_OP_SUB,
16332 argL, argR, condT );
16333 DIP("%s.w r%u, #%u\n", isCMN ? "cmn" : "cmp", rN, imm32);
16334 goto decode_success;
16335 }
16336 }
16337
16338 /* -------------- (T1) TST.W Rn, #constT -------------- */
16339 /* -------------- (T1) TEQ.W Rn, #constT -------------- */
16340 if (INSN0(15,11) == BITS5(1,1,1,1,0)
16341 && ( INSN0(9,4) == BITS6(0,0,0,0,0,1) // TST
16342 || INSN0(9,4) == BITS6(0,0,1,0,0,1)) // TEQ
16343 && INSN1(15,15) == 0
16344 && INSN1(11,8) == BITS4(1,1,1,1)) {
16345 UInt rN = INSN0(3,0);
16346 if (!isBadRegT(rN)) { // yes, really, it's inconsistent with CMP.W
16347 Bool isTST = INSN0(9,4) == BITS6(0,0,0,0,0,1);
16348 IRTemp argL = newTemp(Ity_I32);
16349 IRTemp argR = newTemp(Ity_I32);
16350 IRTemp res = newTemp(Ity_I32);
16351 IRTemp oldV = newTemp(Ity_I32);
16352 IRTemp oldC = newTemp(Ity_I32);
16353 Bool updC = False;
16354 UInt imm32 = thumbExpandImm_from_I0_I1(&updC, insn0, insn1);
16355 assign(argL, getIRegT(rN));
16356 assign(argR, mkU32(imm32));
16357 assign(res, binop(isTST ? Iop_And32 : Iop_Xor32,
16358 mkexpr(argL), mkexpr(argR)));
16359 assign( oldV, mk_armg_calculate_flag_v() );
16360 assign( oldC, updC
16361 ? mkU32((imm32 >> 31) & 1)
16362 : mk_armg_calculate_flag_c() );
16363 setFlags_D1_D2_ND( ARMG_CC_OP_LOGIC, res, oldC, oldV, condT );
16364 DIP("%s.w r%u, #%u\n", isTST ? "tst" : "teq", rN, imm32);
16365 goto decode_success;
16366 }
16367 }
16368
16369 /* -------------- (T3) SUB{S}.W Rd, Rn, #constT -------------- */
16370 /* -------------- (T3) RSB{S}.W Rd, Rn, #constT -------------- */
16371 if (INSN0(15,11) == BITS5(1,1,1,1,0)
16372 && (INSN0(9,5) == BITS5(0,1,1,0,1) // SUB
16373 || INSN0(9,5) == BITS5(0,1,1,1,0)) // RSB
16374 && INSN1(15,15) == 0) {
16375 Bool isRSB = INSN0(9,5) == BITS5(0,1,1,1,0);
16376 UInt bS = INSN0(4,4);
16377 UInt rN = INSN0(3,0);
16378 UInt rD = INSN1(11,8);
16379 Bool valid = !isBadRegT(rN) && !isBadRegT(rD);
sewardj15c01042011-03-24 11:14:02 +000016380 /* but allow "sub{s}.w reg, sp, #constT
16381 this is (T2) of "SUB (SP minus immediate)" */
16382 if (!valid && !isRSB && rN == 13 && rD != 15)
sewardjd2664472010-08-22 12:44:20 +000016383 valid = True;
16384 if (valid) {
16385 IRTemp argL = newTemp(Ity_I32);
16386 IRTemp argR = newTemp(Ity_I32);
16387 IRTemp res = newTemp(Ity_I32);
16388 UInt imm32 = thumbExpandImm_from_I0_I1(NULL, insn0, insn1);
16389 assign(argL, getIRegT(rN));
16390 assign(argR, mkU32(imm32));
16391 assign(res, isRSB
16392 ? binop(Iop_Sub32, mkexpr(argR), mkexpr(argL))
16393 : binop(Iop_Sub32, mkexpr(argL), mkexpr(argR)));
16394 putIRegT(rD, mkexpr(res), condT);
16395 if (bS == 1) {
16396 if (isRSB)
16397 setFlags_D1_D2( ARMG_CC_OP_SUB, argR, argL, condT );
16398 else
16399 setFlags_D1_D2( ARMG_CC_OP_SUB, argL, argR, condT );
16400 }
16401 DIP("%s%s.w r%u, r%u, #%u\n",
16402 isRSB ? "rsb" : "sub", bS == 1 ? "s" : "", rD, rN, imm32);
16403 goto decode_success;
16404 }
16405 }
16406
sewardjdbf3d592011-07-08 15:36:59 +000016407 /* -------------- (T4) SUBW Rd, Rn, #uimm12 ------------------- */
16408 if (INSN0(15,11) == BITS5(1,1,1,1,0)
16409 && INSN0(9,4) == BITS6(1,0,1,0,1,0)
16410 && INSN1(15,15) == 0) {
16411 UInt rN = INSN0(3,0);
16412 UInt rD = INSN1(11,8);
16413 Bool valid = !isBadRegT(rN) && !isBadRegT(rD);
16414 /* but allow "subw sp, sp, #uimm12" */
16415 if (!valid && rD == 13 && rN == 13)
16416 valid = True;
16417 if (valid) {
16418 IRTemp argL = newTemp(Ity_I32);
16419 IRTemp argR = newTemp(Ity_I32);
16420 IRTemp res = newTemp(Ity_I32);
16421 UInt imm12 = (INSN0(10,10) << 11) | (INSN1(14,12) << 8) | INSN1(7,0);
16422 assign(argL, getIRegT(rN));
16423 assign(argR, mkU32(imm12));
16424 assign(res, binop(Iop_Sub32, mkexpr(argL), mkexpr(argR)));
16425 putIRegT(rD, mkexpr(res), condT);
16426 DIP("subw r%u, r%u, #%u\n", rD, rN, imm12);
16427 goto decode_success;
16428 }
16429 }
16430
sewardjd2664472010-08-22 12:44:20 +000016431 /* -------------- (T1) ADC{S}.W Rd, Rn, #constT -------------- */
16432 /* -------------- (T1) SBC{S}.W Rd, Rn, #constT -------------- */
16433 if (INSN0(15,11) == BITS5(1,1,1,1,0)
16434 && ( INSN0(9,5) == BITS5(0,1,0,1,0) // ADC
16435 || INSN0(9,5) == BITS5(0,1,0,1,1)) // SBC
16436 && INSN1(15,15) == 0) {
16437 /* ADC: Rd = Rn + constT + oldC */
16438 /* SBC: Rd = Rn - constT - (oldC ^ 1) */
16439 UInt bS = INSN0(4,4);
16440 UInt rN = INSN0(3,0);
16441 UInt rD = INSN1(11,8);
16442 if (!isBadRegT(rN) && !isBadRegT(rD)) {
16443 IRTemp argL = newTemp(Ity_I32);
16444 IRTemp argR = newTemp(Ity_I32);
16445 IRTemp res = newTemp(Ity_I32);
16446 IRTemp oldC = newTemp(Ity_I32);
16447 UInt imm32 = thumbExpandImm_from_I0_I1(NULL, insn0, insn1);
16448 assign(argL, getIRegT(rN));
16449 assign(argR, mkU32(imm32));
16450 assign(oldC, mk_armg_calculate_flag_c() );
16451 HChar* nm = "???";
16452 switch (INSN0(9,5)) {
16453 case BITS5(0,1,0,1,0): // ADC
16454 nm = "adc";
16455 assign(res,
16456 binop(Iop_Add32,
16457 binop(Iop_Add32, mkexpr(argL), mkexpr(argR)),
16458 mkexpr(oldC) ));
16459 putIRegT(rD, mkexpr(res), condT);
16460 if (bS)
16461 setFlags_D1_D2_ND( ARMG_CC_OP_ADC,
16462 argL, argR, oldC, condT );
16463 break;
16464 case BITS5(0,1,0,1,1): // SBC
16465 nm = "sbc";
16466 assign(res,
16467 binop(Iop_Sub32,
16468 binop(Iop_Sub32, mkexpr(argL), mkexpr(argR)),
16469 binop(Iop_Xor32, mkexpr(oldC), mkU32(1)) ));
16470 putIRegT(rD, mkexpr(res), condT);
16471 if (bS)
16472 setFlags_D1_D2_ND( ARMG_CC_OP_SBB,
16473 argL, argR, oldC, condT );
16474 break;
16475 default:
16476 vassert(0);
16477 }
16478 DIP("%s%s.w r%u, r%u, #%u\n",
16479 nm, bS == 1 ? "s" : "", rD, rN, imm32);
16480 goto decode_success;
16481 }
16482 }
16483
16484 /* -------------- (T1) ORR{S}.W Rd, Rn, #constT -------------- */
16485 /* -------------- (T1) AND{S}.W Rd, Rn, #constT -------------- */
16486 /* -------------- (T1) BIC{S}.W Rd, Rn, #constT -------------- */
16487 /* -------------- (T1) EOR{S}.W Rd, Rn, #constT -------------- */
16488 if (INSN0(15,11) == BITS5(1,1,1,1,0)
16489 && ( INSN0(9,5) == BITS5(0,0,0,1,0) // ORR
16490 || INSN0(9,5) == BITS5(0,0,0,0,0) // AND
16491 || INSN0(9,5) == BITS5(0,0,0,0,1) // BIC
sewardj04d6da32010-09-25 22:06:12 +000016492 || INSN0(9,5) == BITS5(0,0,1,0,0) // EOR
16493 || INSN0(9,5) == BITS5(0,0,0,1,1)) // ORN
sewardjd2664472010-08-22 12:44:20 +000016494 && INSN1(15,15) == 0) {
16495 UInt bS = INSN0(4,4);
16496 UInt rN = INSN0(3,0);
16497 UInt rD = INSN1(11,8);
16498 if (!isBadRegT(rN) && !isBadRegT(rD)) {
sewardj04d6da32010-09-25 22:06:12 +000016499 Bool notArgR = False;
16500 IROp op = Iop_INVALID;
16501 HChar* nm = "???";
sewardjd2664472010-08-22 12:44:20 +000016502 switch (INSN0(9,5)) {
16503 case BITS5(0,0,0,1,0): op = Iop_Or32; nm = "orr"; break;
16504 case BITS5(0,0,0,0,0): op = Iop_And32; nm = "and"; break;
16505 case BITS5(0,0,0,0,1): op = Iop_And32; nm = "bic";
sewardj04d6da32010-09-25 22:06:12 +000016506 notArgR = True; break;
16507 case BITS5(0,0,1,0,0): op = Iop_Xor32; nm = "eor"; break;
16508 case BITS5(0,0,0,1,1): op = Iop_Or32; nm = "orn";
16509 notArgR = True; break;
sewardjd2664472010-08-22 12:44:20 +000016510 default: vassert(0);
16511 }
16512 IRTemp argL = newTemp(Ity_I32);
16513 IRTemp argR = newTemp(Ity_I32);
16514 IRTemp res = newTemp(Ity_I32);
16515 Bool updC = False;
16516 UInt imm32 = thumbExpandImm_from_I0_I1(&updC, insn0, insn1);
16517 assign(argL, getIRegT(rN));
sewardj04d6da32010-09-25 22:06:12 +000016518 assign(argR, mkU32(notArgR ? ~imm32 : imm32));
sewardjd2664472010-08-22 12:44:20 +000016519 assign(res, binop(op, mkexpr(argL), mkexpr(argR)));
16520 putIRegT(rD, mkexpr(res), condT);
16521 if (bS) {
16522 IRTemp oldV = newTemp(Ity_I32);
16523 IRTemp oldC = newTemp(Ity_I32);
16524 assign( oldV, mk_armg_calculate_flag_v() );
16525 assign( oldC, updC
16526 ? mkU32((imm32 >> 31) & 1)
16527 : mk_armg_calculate_flag_c() );
16528 setFlags_D1_D2_ND( ARMG_CC_OP_LOGIC, res, oldC, oldV,
16529 condT );
16530 }
16531 DIP("%s%s.w r%u, r%u, #%u\n",
16532 nm, bS == 1 ? "s" : "", rD, rN, imm32);
16533 goto decode_success;
16534 }
16535 }
16536
16537 /* ---------- (T3) ADD{S}.W Rd, Rn, Rm, {shift} ---------- */
16538 /* ---------- (T3) SUB{S}.W Rd, Rn, Rm, {shift} ---------- */
16539 /* ---------- (T3) RSB{S}.W Rd, Rn, Rm, {shift} ---------- */
16540 if (INSN0(15,9) == BITS7(1,1,1,0,1,0,1)
16541 && ( INSN0(8,5) == BITS4(1,0,0,0) // add subopc
16542 || INSN0(8,5) == BITS4(1,1,0,1) // sub subopc
16543 || INSN0(8,5) == BITS4(1,1,1,0)) // rsb subopc
16544 && INSN1(15,15) == 0) {
16545 UInt rN = INSN0(3,0);
16546 UInt rD = INSN1(11,8);
16547 UInt rM = INSN1(3,0);
16548 UInt bS = INSN0(4,4);
16549 UInt imm5 = (INSN1(14,12) << 2) | INSN1(7,6);
16550 UInt how = INSN1(5,4);
16551
16552 Bool valid = !isBadRegT(rD) && !isBadRegT(rN) && !isBadRegT(rM);
sewardjfd5f4a42012-03-21 19:36:37 +000016553 /* but allow "add.w reg, sp, reg, lsl #N for N=0,1,2 or 3
sewardj15c01042011-03-24 11:14:02 +000016554 (T3) "ADD (SP plus register) */
sewardjd2664472010-08-22 12:44:20 +000016555 if (!valid && INSN0(8,5) == BITS4(1,0,0,0) // add
sewardjfd5f4a42012-03-21 19:36:37 +000016556 && rD != 15 && rN == 13 && imm5 <= 3 && how == 0) {
sewardjd2664472010-08-22 12:44:20 +000016557 valid = True;
16558 }
sewardj15c01042011-03-24 11:14:02 +000016559 /* also allow "sub.w reg, sp, reg w/ no shift
16560 (T1) "SUB (SP minus register) */
16561 if (!valid && INSN0(8,5) == BITS4(1,1,0,1) // sub
16562 && rD != 15 && rN == 13 && imm5 == 0 && how == 0) {
sewardjd2664472010-08-22 12:44:20 +000016563 valid = True;
16564 }
16565 if (valid) {
16566 Bool swap = False;
16567 IROp op = Iop_INVALID;
16568 HChar* nm = "???";
16569 switch (INSN0(8,5)) {
16570 case BITS4(1,0,0,0): op = Iop_Add32; nm = "add"; break;
16571 case BITS4(1,1,0,1): op = Iop_Sub32; nm = "sub"; break;
16572 case BITS4(1,1,1,0): op = Iop_Sub32; nm = "rsb";
16573 swap = True; break;
16574 default: vassert(0);
16575 }
16576
16577 IRTemp argL = newTemp(Ity_I32);
16578 assign(argL, getIRegT(rN));
16579
16580 IRTemp rMt = newTemp(Ity_I32);
16581 assign(rMt, getIRegT(rM));
16582
16583 IRTemp argR = newTemp(Ity_I32);
16584 compute_result_and_C_after_shift_by_imm5(
16585 dis_buf, &argR, NULL, rMt, how, imm5, rM
16586 );
16587
16588 IRTemp res = newTemp(Ity_I32);
16589 assign(res, swap
16590 ? binop(op, mkexpr(argR), mkexpr(argL))
16591 : binop(op, mkexpr(argL), mkexpr(argR)));
16592
16593 putIRegT(rD, mkexpr(res), condT);
16594 if (bS) {
16595 switch (op) {
16596 case Iop_Add32:
16597 setFlags_D1_D2( ARMG_CC_OP_ADD, argL, argR, condT );
16598 break;
16599 case Iop_Sub32:
16600 if (swap)
16601 setFlags_D1_D2( ARMG_CC_OP_SUB, argR, argL, condT );
16602 else
16603 setFlags_D1_D2( ARMG_CC_OP_SUB, argL, argR, condT );
16604 break;
16605 default:
16606 vassert(0);
16607 }
16608 }
16609
16610 DIP("%s%s.w r%u, r%u, %s\n",
16611 nm, bS ? "s" : "", rD, rN, dis_buf);
16612 goto decode_success;
16613 }
16614 }
16615
16616 /* ---------- (T3) ADC{S}.W Rd, Rn, Rm, {shift} ---------- */
16617 /* ---------- (T2) SBC{S}.W Rd, Rn, Rm, {shift} ---------- */
16618 if (INSN0(15,9) == BITS7(1,1,1,0,1,0,1)
16619 && ( INSN0(8,5) == BITS4(1,0,1,0) // adc subopc
16620 || INSN0(8,5) == BITS4(1,0,1,1)) // sbc subopc
16621 && INSN1(15,15) == 0) {
16622 /* ADC: Rd = Rn + shifter_operand + oldC */
16623 /* SBC: Rd = Rn - shifter_operand - (oldC ^ 1) */
16624 UInt rN = INSN0(3,0);
16625 UInt rD = INSN1(11,8);
16626 UInt rM = INSN1(3,0);
16627 if (!isBadRegT(rD) && !isBadRegT(rN) && !isBadRegT(rM)) {
16628 UInt bS = INSN0(4,4);
16629 UInt imm5 = (INSN1(14,12) << 2) | INSN1(7,6);
16630 UInt how = INSN1(5,4);
16631
16632 IRTemp argL = newTemp(Ity_I32);
16633 assign(argL, getIRegT(rN));
16634
16635 IRTemp rMt = newTemp(Ity_I32);
16636 assign(rMt, getIRegT(rM));
16637
16638 IRTemp oldC = newTemp(Ity_I32);
16639 assign(oldC, mk_armg_calculate_flag_c());
16640
16641 IRTemp argR = newTemp(Ity_I32);
16642 compute_result_and_C_after_shift_by_imm5(
16643 dis_buf, &argR, NULL, rMt, how, imm5, rM
16644 );
16645
16646 HChar* nm = "???";
16647 IRTemp res = newTemp(Ity_I32);
16648 switch (INSN0(8,5)) {
16649 case BITS4(1,0,1,0): // ADC
16650 nm = "adc";
16651 assign(res,
16652 binop(Iop_Add32,
16653 binop(Iop_Add32, mkexpr(argL), mkexpr(argR)),
16654 mkexpr(oldC) ));
16655 putIRegT(rD, mkexpr(res), condT);
16656 if (bS)
16657 setFlags_D1_D2_ND( ARMG_CC_OP_ADC,
16658 argL, argR, oldC, condT );
16659 break;
16660 case BITS4(1,0,1,1): // SBC
16661 nm = "sbc";
16662 assign(res,
16663 binop(Iop_Sub32,
16664 binop(Iop_Sub32, mkexpr(argL), mkexpr(argR)),
16665 binop(Iop_Xor32, mkexpr(oldC), mkU32(1)) ));
16666 putIRegT(rD, mkexpr(res), condT);
16667 if (bS)
16668 setFlags_D1_D2_ND( ARMG_CC_OP_SBB,
16669 argL, argR, oldC, condT );
16670 break;
16671 default:
16672 vassert(0);
16673 }
16674
16675 DIP("%s%s.w r%u, r%u, %s\n",
16676 nm, bS ? "s" : "", rD, rN, dis_buf);
16677 goto decode_success;
16678 }
16679 }
16680
16681 /* ---------- (T3) AND{S}.W Rd, Rn, Rm, {shift} ---------- */
16682 /* ---------- (T3) ORR{S}.W Rd, Rn, Rm, {shift} ---------- */
16683 /* ---------- (T3) EOR{S}.W Rd, Rn, Rm, {shift} ---------- */
16684 /* ---------- (T3) BIC{S}.W Rd, Rn, Rm, {shift} ---------- */
sewardj04d6da32010-09-25 22:06:12 +000016685 /* ---------- (T1) ORN{S}.W Rd, Rn, Rm, {shift} ---------- */
sewardjd2664472010-08-22 12:44:20 +000016686 if (INSN0(15,9) == BITS7(1,1,1,0,1,0,1)
16687 && ( INSN0(8,5) == BITS4(0,0,0,0) // and subopc
16688 || INSN0(8,5) == BITS4(0,0,1,0) // orr subopc
16689 || INSN0(8,5) == BITS4(0,1,0,0) // eor subopc
sewardj04d6da32010-09-25 22:06:12 +000016690 || INSN0(8,5) == BITS4(0,0,0,1) // bic subopc
16691 || INSN0(8,5) == BITS4(0,0,1,1)) // orn subopc
sewardjd2664472010-08-22 12:44:20 +000016692 && INSN1(15,15) == 0) {
16693 UInt rN = INSN0(3,0);
16694 UInt rD = INSN1(11,8);
16695 UInt rM = INSN1(3,0);
16696 if (!isBadRegT(rD) && !isBadRegT(rN) && !isBadRegT(rM)) {
sewardj04d6da32010-09-25 22:06:12 +000016697 Bool notArgR = False;
16698 IROp op = Iop_INVALID;
sewardjd2664472010-08-22 12:44:20 +000016699 HChar* nm = "???";
16700 switch (INSN0(8,5)) {
16701 case BITS4(0,0,0,0): op = Iop_And32; nm = "and"; break;
16702 case BITS4(0,0,1,0): op = Iop_Or32; nm = "orr"; break;
16703 case BITS4(0,1,0,0): op = Iop_Xor32; nm = "eor"; break;
16704 case BITS4(0,0,0,1): op = Iop_And32; nm = "bic";
sewardj04d6da32010-09-25 22:06:12 +000016705 notArgR = True; break;
16706 case BITS4(0,0,1,1): op = Iop_Or32; nm = "orn";
16707 notArgR = True; break;
sewardjd2664472010-08-22 12:44:20 +000016708 default: vassert(0);
16709 }
16710 UInt bS = INSN0(4,4);
16711 UInt imm5 = (INSN1(14,12) << 2) | INSN1(7,6);
16712 UInt how = INSN1(5,4);
16713
16714 IRTemp rNt = newTemp(Ity_I32);
16715 assign(rNt, getIRegT(rN));
16716
16717 IRTemp rMt = newTemp(Ity_I32);
16718 assign(rMt, getIRegT(rM));
16719
16720 IRTemp argR = newTemp(Ity_I32);
16721 IRTemp oldC = bS ? newTemp(Ity_I32) : IRTemp_INVALID;
16722
16723 compute_result_and_C_after_shift_by_imm5(
16724 dis_buf, &argR, bS ? &oldC : NULL, rMt, how, imm5, rM
16725 );
16726
16727 IRTemp res = newTemp(Ity_I32);
sewardj04d6da32010-09-25 22:06:12 +000016728 if (notArgR) {
16729 vassert(op == Iop_And32 || op == Iop_Or32);
sewardjd2664472010-08-22 12:44:20 +000016730 assign(res, binop(op, mkexpr(rNt),
16731 unop(Iop_Not32, mkexpr(argR))));
16732 } else {
16733 assign(res, binop(op, mkexpr(rNt), mkexpr(argR)));
16734 }
16735
16736 putIRegT(rD, mkexpr(res), condT);
16737 if (bS) {
16738 IRTemp oldV = newTemp(Ity_I32);
16739 assign( oldV, mk_armg_calculate_flag_v() );
16740 setFlags_D1_D2_ND( ARMG_CC_OP_LOGIC, res, oldC, oldV,
16741 condT );
16742 }
16743
16744 DIP("%s%s.w r%u, r%u, %s\n",
16745 nm, bS ? "s" : "", rD, rN, dis_buf);
16746 goto decode_success;
16747 }
16748 }
16749
16750 /* -------------- (T?) LSL{S}.W Rd, Rn, Rm -------------- */
16751 /* -------------- (T?) LSR{S}.W Rd, Rn, Rm -------------- */
16752 /* -------------- (T?) ASR{S}.W Rd, Rn, Rm -------------- */
16753 /* -------------- (T?) ROR{S}.W Rd, Rn, Rm -------------- */
16754 if (INSN0(15,7) == BITS9(1,1,1,1,1,0,1,0,0)
16755 && INSN1(15,12) == BITS4(1,1,1,1)
16756 && INSN1(7,4) == BITS4(0,0,0,0)) {
16757 UInt how = INSN0(6,5); // standard encoding
16758 UInt rN = INSN0(3,0);
16759 UInt rD = INSN1(11,8);
16760 UInt rM = INSN1(3,0);
16761 UInt bS = INSN0(4,4);
16762 Bool valid = !isBadRegT(rN) && !isBadRegT(rM) && !isBadRegT(rD);
sewardjd2664472010-08-22 12:44:20 +000016763 if (valid) {
16764 IRTemp rNt = newTemp(Ity_I32);
16765 IRTemp rMt = newTemp(Ity_I32);
16766 IRTemp res = newTemp(Ity_I32);
16767 IRTemp oldC = bS ? newTemp(Ity_I32) : IRTemp_INVALID;
16768 IRTemp oldV = bS ? newTemp(Ity_I32) : IRTemp_INVALID;
16769 HChar* nms[4] = { "lsl", "lsr", "asr", "ror" };
16770 HChar* nm = nms[how];
16771 assign(rNt, getIRegT(rN));
16772 assign(rMt, getIRegT(rM));
16773 compute_result_and_C_after_shift_by_reg(
16774 dis_buf, &res, bS ? &oldC : NULL,
16775 rNt, how, rMt, rN, rM
16776 );
16777 if (bS)
16778 assign(oldV, mk_armg_calculate_flag_v());
16779 putIRegT(rD, mkexpr(res), condT);
16780 if (bS) {
16781 setFlags_D1_D2_ND( ARMG_CC_OP_LOGIC, res, oldC, oldV,
16782 condT );
16783 }
16784 DIP("%s%s.w r%u, r%u, r%u\n",
16785 nm, bS ? "s" : "", rD, rN, rM);
16786 goto decode_success;
16787 }
16788 }
16789
16790 /* ------------ (T?) MOV{S}.W Rd, Rn, {shift} ------------ */
16791 /* ------------ (T?) MVN{S}.W Rd, Rn, {shift} ------------ */
16792 if ((INSN0(15,0) & 0xFFCF) == 0xEA4F
16793 && INSN1(15,15) == 0) {
16794 UInt rD = INSN1(11,8);
16795 UInt rN = INSN1(3,0);
16796 if (!isBadRegT(rD) && !isBadRegT(rN)) {
16797 UInt bS = INSN0(4,4);
16798 UInt isMVN = INSN0(5,5);
16799 UInt imm5 = (INSN1(14,12) << 2) | INSN1(7,6);
16800 UInt how = INSN1(5,4);
16801
16802 IRTemp rNt = newTemp(Ity_I32);
16803 assign(rNt, getIRegT(rN));
16804
16805 IRTemp oldRn = newTemp(Ity_I32);
16806 IRTemp oldC = bS ? newTemp(Ity_I32) : IRTemp_INVALID;
16807 compute_result_and_C_after_shift_by_imm5(
16808 dis_buf, &oldRn, bS ? &oldC : NULL, rNt, how, imm5, rN
16809 );
16810
16811 IRTemp res = newTemp(Ity_I32);
16812 assign(res, isMVN ? unop(Iop_Not32, mkexpr(oldRn))
16813 : mkexpr(oldRn));
16814
16815 putIRegT(rD, mkexpr(res), condT);
16816 if (bS) {
16817 IRTemp oldV = newTemp(Ity_I32);
16818 assign( oldV, mk_armg_calculate_flag_v() );
16819 setFlags_D1_D2_ND( ARMG_CC_OP_LOGIC, res, oldC, oldV, condT);
16820 }
16821 DIP("%s%s.w r%u, %s\n",
16822 isMVN ? "mvn" : "mov", bS ? "s" : "", rD, dis_buf);
16823 goto decode_success;
16824 }
16825 }
16826
16827 /* -------------- (T?) TST.W Rn, Rm, {shift} -------------- */
16828 /* -------------- (T?) TEQ.W Rn, Rm, {shift} -------------- */
16829 if (INSN0(15,9) == BITS7(1,1,1,0,1,0,1)
16830 && ( INSN0(8,4) == BITS5(0,0,0,0,1) // TST
16831 || INSN0(8,4) == BITS5(0,1,0,0,1)) // TEQ
16832 && INSN1(15,15) == 0
16833 && INSN1(11,8) == BITS4(1,1,1,1)) {
16834 UInt rN = INSN0(3,0);
16835 UInt rM = INSN1(3,0);
16836 if (!isBadRegT(rN) && !isBadRegT(rM)) {
16837 Bool isTST = INSN0(8,4) == BITS5(0,0,0,0,1);
16838
16839 UInt how = INSN1(5,4);
16840 UInt imm5 = (INSN1(14,12) << 2) | INSN1(7,6);
16841
16842 IRTemp argL = newTemp(Ity_I32);
16843 assign(argL, getIRegT(rN));
16844
16845 IRTemp rMt = newTemp(Ity_I32);
16846 assign(rMt, getIRegT(rM));
16847
16848 IRTemp argR = newTemp(Ity_I32);
16849 IRTemp oldC = newTemp(Ity_I32);
16850 compute_result_and_C_after_shift_by_imm5(
16851 dis_buf, &argR, &oldC, rMt, how, imm5, rM
16852 );
16853
16854 IRTemp oldV = newTemp(Ity_I32);
16855 assign( oldV, mk_armg_calculate_flag_v() );
16856
16857 IRTemp res = newTemp(Ity_I32);
16858 assign(res, binop(isTST ? Iop_And32 : Iop_Xor32,
16859 mkexpr(argL), mkexpr(argR)));
16860
16861 setFlags_D1_D2_ND( ARMG_CC_OP_LOGIC, res, oldC, oldV,
16862 condT );
16863 DIP("%s.w r%u, %s\n", isTST ? "tst" : "teq", rN, dis_buf);
16864 goto decode_success;
16865 }
16866 }
16867
16868 /* -------------- (T3) CMP.W Rn, Rm, {shift} -------------- */
16869 /* -------------- (T2) CMN.W Rn, Rm, {shift} -------------- */
16870 if (INSN0(15,9) == BITS7(1,1,1,0,1,0,1)
16871 && ( INSN0(8,4) == BITS5(1,1,0,1,1) // CMP
16872 || INSN0(8,4) == BITS5(1,0,0,0,1)) // CMN
16873 && INSN1(15,15) == 0
16874 && INSN1(11,8) == BITS4(1,1,1,1)) {
16875 UInt rN = INSN0(3,0);
16876 UInt rM = INSN1(3,0);
16877 if (!isBadRegT(rN) && !isBadRegT(rM)) {
16878 Bool isCMN = INSN0(8,4) == BITS5(1,0,0,0,1);
16879 UInt how = INSN1(5,4);
16880 UInt imm5 = (INSN1(14,12) << 2) | INSN1(7,6);
16881
16882 IRTemp argL = newTemp(Ity_I32);
16883 assign(argL, getIRegT(rN));
16884
16885 IRTemp rMt = newTemp(Ity_I32);
16886 assign(rMt, getIRegT(rM));
16887
16888 IRTemp argR = newTemp(Ity_I32);
16889 compute_result_and_C_after_shift_by_imm5(
16890 dis_buf, &argR, NULL, rMt, how, imm5, rM
16891 );
16892
16893 setFlags_D1_D2( isCMN ? ARMG_CC_OP_ADD : ARMG_CC_OP_SUB,
16894 argL, argR, condT );
16895
16896 DIP("%s.w r%u, %s\n", isCMN ? "cmn" : "cmp", rN, dis_buf);
16897 goto decode_success;
16898 }
16899 }
16900
16901 /* -------------- (T2) MOV{S}.W Rd, #constT -------------- */
16902 /* -------------- (T2) MVN{S}.W Rd, #constT -------------- */
16903 if (INSN0(15,11) == BITS5(1,1,1,1,0)
16904 && ( INSN0(9,5) == BITS5(0,0,0,1,0) // MOV
16905 || INSN0(9,5) == BITS5(0,0,0,1,1)) // MVN
16906 && INSN0(3,0) == BITS4(1,1,1,1)
16907 && INSN1(15,15) == 0) {
16908 UInt rD = INSN1(11,8);
16909 if (!isBadRegT(rD)) {
16910 Bool updC = False;
16911 UInt bS = INSN0(4,4);
16912 Bool isMVN = INSN0(5,5) == 1;
16913 UInt imm32 = thumbExpandImm_from_I0_I1(&updC, insn0, insn1);
16914 IRTemp res = newTemp(Ity_I32);
16915 assign(res, mkU32(isMVN ? ~imm32 : imm32));
16916 putIRegT(rD, mkexpr(res), condT);
16917 if (bS) {
16918 IRTemp oldV = newTemp(Ity_I32);
16919 IRTemp oldC = newTemp(Ity_I32);
16920 assign( oldV, mk_armg_calculate_flag_v() );
16921 assign( oldC, updC
16922 ? mkU32((imm32 >> 31) & 1)
16923 : mk_armg_calculate_flag_c() );
16924 setFlags_D1_D2_ND( ARMG_CC_OP_LOGIC, res, oldC, oldV,
16925 condT );
16926 }
16927 DIP("%s%s.w r%u, #%u\n",
16928 isMVN ? "mvn" : "mov", bS ? "s" : "", rD, imm32);
16929 goto decode_success;
16930 }
16931 }
16932
16933 /* -------------- (T3) MOVW Rd, #imm16 -------------- */
16934 if (INSN0(15,11) == BITS5(1,1,1,1,0)
16935 && INSN0(9,4) == BITS6(1,0,0,1,0,0)
16936 && INSN1(15,15) == 0) {
16937 UInt rD = INSN1(11,8);
16938 if (!isBadRegT(rD)) {
16939 UInt imm16 = (INSN0(3,0) << 12) | (INSN0(10,10) << 11)
16940 | (INSN1(14,12) << 8) | INSN1(7,0);
16941 putIRegT(rD, mkU32(imm16), condT);
16942 DIP("movw r%u, #%u\n", rD, imm16);
16943 goto decode_success;
16944 }
16945 }
16946
16947 /* ---------------- MOVT Rd, #imm16 ---------------- */
16948 if (INSN0(15,11) == BITS5(1,1,1,1,0)
16949 && INSN0(9,4) == BITS6(1,0,1,1,0,0)
16950 && INSN1(15,15) == 0) {
16951 UInt rD = INSN1(11,8);
16952 if (!isBadRegT(rD)) {
16953 UInt imm16 = (INSN0(3,0) << 12) | (INSN0(10,10) << 11)
16954 | (INSN1(14,12) << 8) | INSN1(7,0);
16955 IRTemp res = newTemp(Ity_I32);
16956 assign(res,
16957 binop(Iop_Or32,
16958 binop(Iop_And32, getIRegT(rD), mkU32(0xFFFF)),
16959 mkU32(imm16 << 16)));
16960 putIRegT(rD, mkexpr(res), condT);
16961 DIP("movt r%u, #%u\n", rD, imm16);
16962 goto decode_success;
16963 }
16964 }
16965
16966 /* ---------------- LD/ST reg+/-#imm8 ---------------- */
16967 /* Loads and stores of the form:
16968 op Rt, [Rn, #-imm8] or
16969 op Rt, [Rn], #+/-imm8 or
16970 op Rt, [Rn, #+/-imm8]!
16971 where op is one of
16972 ldrb ldrh ldr ldrsb ldrsh
16973 strb strh str
16974 */
16975 if (INSN0(15,9) == BITS7(1,1,1,1,1,0,0) && INSN1(11,11) == 1) {
16976 Bool valid = True;
16977 Bool syned = False;
16978 Bool isST = False;
16979 IRType ty = Ity_I8;
16980 HChar* nm = "???";
16981
16982 switch (INSN0(8,4)) {
16983 case BITS5(0,0,0,0,0): // strb
16984 nm = "strb"; isST = True; break;
16985 case BITS5(0,0,0,0,1): // ldrb
16986 nm = "ldrb"; break;
16987 case BITS5(1,0,0,0,1): // ldrsb
16988 nm = "ldrsb"; syned = True; break;
16989 case BITS5(0,0,0,1,0): // strh
16990 nm = "strh"; ty = Ity_I16; isST = True; break;
16991 case BITS5(0,0,0,1,1): // ldrh
16992 nm = "ldrh"; ty = Ity_I16; break;
16993 case BITS5(1,0,0,1,1): // ldrsh
16994 nm = "ldrsh"; ty = Ity_I16; syned = True; break;
16995 case BITS5(0,0,1,0,0): // str
16996 nm = "str"; ty = Ity_I32; isST = True; break;
16997 case BITS5(0,0,1,0,1):
16998 nm = "ldr"; ty = Ity_I32; break; // ldr
16999 default:
17000 valid = False; break;
17001 }
17002
17003 UInt rN = INSN0(3,0);
17004 UInt rT = INSN1(15,12);
17005 UInt bP = INSN1(10,10);
17006 UInt bU = INSN1(9,9);
17007 UInt bW = INSN1(8,8);
17008 UInt imm8 = INSN1(7,0);
17009 Bool loadsPC = False;
17010
17011 if (valid) {
17012 if (bP == 1 && bU == 1 && bW == 0)
17013 valid = False;
17014 if (bP == 0 && bW == 0)
17015 valid = False;
17016 if (rN == 15)
17017 valid = False;
17018 if (bW == 1 && rN == rT)
17019 valid = False;
17020 if (ty == Ity_I8 || ty == Ity_I16) {
17021 if (isBadRegT(rT))
17022 valid = False;
17023 } else {
17024 /* ty == Ity_I32 */
17025 if (isST && rT == 15)
17026 valid = False;
17027 if (!isST && rT == 15)
17028 loadsPC = True;
17029 }
17030 }
17031
17032 if (valid) {
17033 // if it's a branch, it can't happen in the middle of an IT block
17034 if (loadsPC)
17035 gen_SIGILL_T_if_in_but_NLI_ITBlock(old_itstate, new_itstate);
17036 // go uncond
17037 mk_skip_over_T32_if_cond_is_false(condT);
17038 condT = IRTemp_INVALID;
17039 // now uncond
17040
17041 IRTemp preAddr = newTemp(Ity_I32);
17042 assign(preAddr, getIRegT(rN));
17043
17044 IRTemp postAddr = newTemp(Ity_I32);
17045 assign(postAddr, binop(bU == 1 ? Iop_Add32 : Iop_Sub32,
17046 mkexpr(preAddr), mkU32(imm8)));
17047
17048 IRTemp transAddr = bP == 1 ? postAddr : preAddr;
17049
17050 if (isST) {
17051
17052 /* Store. If necessary, update the base register before
17053 the store itself, so that the common idiom of "str rX,
17054 [sp, #-4]!" (store rX at sp-4, then do new sp = sp-4,
17055 a.k.a "push rX") doesn't cause Memcheck to complain
17056 that the access is below the stack pointer. Also, not
17057 updating sp before the store confuses Valgrind's
17058 dynamic stack-extending logic. So do it before the
17059 store. Hence we need to snarf the store data before
17060 doing the basereg update. */
17061
17062 /* get hold of the data to be stored */
17063 IRTemp oldRt = newTemp(Ity_I32);
17064 assign(oldRt, getIRegT(rT));
17065
17066 /* Update Rn if necessary. */
17067 if (bW == 1) {
17068 vassert(rN != rT); // assured by validity check above
17069 putIRegT(rN, mkexpr(postAddr), IRTemp_INVALID);
17070 }
17071
17072 /* generate the transfer */
17073 switch (ty) {
17074 case Ity_I8:
17075 storeLE(mkexpr(transAddr),
17076 unop(Iop_32to8, mkexpr(oldRt)));
17077 break;
17078 case Ity_I16:
17079 storeLE(mkexpr(transAddr),
17080 unop(Iop_32to16, mkexpr(oldRt)));
17081 break;
17082 case Ity_I32:
17083 storeLE(mkexpr(transAddr), mkexpr(oldRt));
17084 break;
17085 default:
17086 vassert(0);
17087 }
17088
17089 } else {
17090
17091 /* Load. */
17092
17093 /* generate the transfer */
17094 IRTemp newRt = newTemp(Ity_I32);
17095 IROp widen = Iop_INVALID;
17096 switch (ty) {
17097 case Ity_I8:
17098 widen = syned ? Iop_8Sto32 : Iop_8Uto32; break;
17099 case Ity_I16:
17100 widen = syned ? Iop_16Sto32 : Iop_16Uto32; break;
17101 case Ity_I32:
17102 break;
17103 default:
17104 vassert(0);
17105 }
17106 if (widen == Iop_INVALID) {
17107 assign(newRt, loadLE(ty, mkexpr(transAddr)));
17108 } else {
17109 assign(newRt, unop(widen, loadLE(ty, mkexpr(transAddr))));
17110 }
17111 if (loadsPC) {
17112 vassert(rT == 15);
17113 llPutIReg(rT, mkexpr(newRt));
17114 } else {
17115 putIRegT(rT, mkexpr(newRt), IRTemp_INVALID);
17116 }
17117
sewardjd2664472010-08-22 12:44:20 +000017118 /* Update Rn if necessary. */
17119 if (bW == 1) {
17120 vassert(rN != rT); // assured by validity check above
17121 putIRegT(rN, mkexpr(postAddr), IRTemp_INVALID);
17122 }
sewardjc6f970f2012-04-02 21:54:49 +000017123
17124 if (loadsPC) {
17125 /* Presumably this is an interworking branch. */
17126 vassert(rN != 15); // assured by validity check above
17127 llPutIReg(15, mkexpr(newRt));
17128 dres.jk_StopHere = Ijk_Boring; /* or _Ret ? */
17129 dres.whatNext = Dis_StopHere;
17130 }
sewardjd2664472010-08-22 12:44:20 +000017131 }
17132
17133 if (bP == 1 && bW == 0) {
17134 DIP("%s.w r%u, [r%u, #%c%u]\n",
17135 nm, rT, rN, bU ? '+' : '-', imm8);
17136 }
17137 else if (bP == 1 && bW == 1) {
17138 DIP("%s.w r%u, [r%u, #%c%u]!\n",
17139 nm, rT, rN, bU ? '+' : '-', imm8);
17140 }
17141 else {
17142 vassert(bP == 0 && bW == 1);
17143 DIP("%s.w r%u, [r%u], #%c%u\n",
17144 nm, rT, rN, bU ? '+' : '-', imm8);
17145 }
17146
17147 goto decode_success;
17148 }
17149 }
17150
17151 /* ------------- LD/ST reg+(reg<<imm2) ------------- */
17152 /* Loads and stores of the form:
17153 op Rt, [Rn, Rm, LSL #imm8]
17154 where op is one of
17155 ldrb ldrh ldr ldrsb ldrsh
17156 strb strh str
17157 */
17158 if (INSN0(15,9) == BITS7(1,1,1,1,1,0,0)
17159 && INSN1(11,6) == BITS6(0,0,0,0,0,0)) {
17160 Bool valid = True;
17161 Bool syned = False;
17162 Bool isST = False;
17163 IRType ty = Ity_I8;
17164 HChar* nm = "???";
17165
17166 switch (INSN0(8,4)) {
17167 case BITS5(0,0,0,0,0): // strb
17168 nm = "strb"; isST = True; break;
17169 case BITS5(0,0,0,0,1): // ldrb
17170 nm = "ldrb"; break;
17171 case BITS5(1,0,0,0,1): // ldrsb
17172 nm = "ldrsb"; syned = True; break;
17173 case BITS5(0,0,0,1,0): // strh
17174 nm = "strh"; ty = Ity_I16; isST = True; break;
17175 case BITS5(0,0,0,1,1): // ldrh
17176 nm = "ldrh"; ty = Ity_I16; break;
17177 case BITS5(1,0,0,1,1): // ldrsh
17178 nm = "ldrsh"; ty = Ity_I16; syned = True; break;
17179 case BITS5(0,0,1,0,0): // str
17180 nm = "str"; ty = Ity_I32; isST = True; break;
17181 case BITS5(0,0,1,0,1):
17182 nm = "ldr"; ty = Ity_I32; break; // ldr
17183 default:
17184 valid = False; break;
17185 }
17186
17187 UInt rN = INSN0(3,0);
17188 UInt rM = INSN1(3,0);
17189 UInt rT = INSN1(15,12);
17190 UInt imm2 = INSN1(5,4);
17191 Bool loadsPC = False;
17192
17193 if (ty == Ity_I8 || ty == Ity_I16) {
17194 /* all 8- and 16-bit load and store cases have the
17195 same exclusion set. */
17196 if (rN == 15 || isBadRegT(rT) || isBadRegT(rM))
17197 valid = False;
17198 } else {
17199 vassert(ty == Ity_I32);
17200 if (rN == 15 || isBadRegT(rM))
17201 valid = False;
17202 if (isST && rT == 15)
17203 valid = False;
17204 /* If it is a load and rT is 15, that's only allowable if we
17205 not in an IT block, or are the last in it. Need to insert
17206 a dynamic check for that. */
17207 if (!isST && rT == 15)
17208 loadsPC = True;
17209 }
17210
17211 if (valid) {
17212 // if it's a branch, it can't happen in the middle of an IT block
17213 if (loadsPC)
17214 gen_SIGILL_T_if_in_but_NLI_ITBlock(old_itstate, new_itstate);
17215 // go uncond
17216 mk_skip_over_T32_if_cond_is_false(condT);
17217 condT = IRTemp_INVALID;
17218 // now uncond
17219
17220 IRTemp transAddr = newTemp(Ity_I32);
17221 assign(transAddr,
17222 binop( Iop_Add32,
17223 getIRegT(rN),
17224 binop(Iop_Shl32, getIRegT(rM), mkU8(imm2)) ));
17225
17226 if (isST) {
17227 IRTemp oldRt = newTemp(Ity_I32);
17228 assign(oldRt, getIRegT(rT));
17229 switch (ty) {
17230 case Ity_I8:
17231 storeLE(mkexpr(transAddr),
17232 unop(Iop_32to8, mkexpr(oldRt)));
17233 break;
17234 case Ity_I16:
17235 storeLE(mkexpr(transAddr),
17236 unop(Iop_32to16, mkexpr(oldRt)));
17237 break;
17238 case Ity_I32:
17239 storeLE(mkexpr(transAddr), mkexpr(oldRt));
17240 break;
17241 default:
17242 vassert(0);
17243 }
17244 } else {
17245 IRTemp newRt = newTemp(Ity_I32);
17246 IROp widen = Iop_INVALID;
17247 switch (ty) {
17248 case Ity_I8:
17249 widen = syned ? Iop_8Sto32 : Iop_8Uto32; break;
17250 case Ity_I16:
17251 widen = syned ? Iop_16Sto32 : Iop_16Uto32; break;
17252 case Ity_I32:
17253 break;
17254 default:
17255 vassert(0);
17256 }
17257 if (widen == Iop_INVALID) {
17258 assign(newRt, loadLE(ty, mkexpr(transAddr)));
17259 } else {
17260 assign(newRt, unop(widen, loadLE(ty, mkexpr(transAddr))));
17261 }
17262
17263 /* If we're loading the PC, putIRegT will assert. So go
17264 direct via llPutIReg. In all other cases use putIRegT
17265 as it is safer (although could simply use llPutIReg for
17266 _all_ cases here.) */
17267 if (loadsPC) {
17268 vassert(rT == 15);
17269 llPutIReg(rT, mkexpr(newRt));
17270 } else {
17271 putIRegT(rT, mkexpr(newRt), IRTemp_INVALID);
17272 }
17273
17274 if (loadsPC) {
17275 /* Presumably this is an interworking branch. */
sewardjc6f970f2012-04-02 21:54:49 +000017276 llPutIReg(15, mkexpr(newRt));
17277 dres.jk_StopHere = Ijk_Boring; /* or _Ret ? */
17278 dres.whatNext = Dis_StopHere;
sewardjd2664472010-08-22 12:44:20 +000017279 }
17280 }
17281
17282 DIP("%s.w r%u, [r%u, r%u, LSL #%u]\n",
17283 nm, rT, rN, rM, imm2);
17284
17285 goto decode_success;
17286 }
17287 }
17288
17289 /* --------------- LD/ST reg+imm12 --------------- */
17290 /* Loads and stores of the form:
17291 op Rt, [Rn, +#imm12]
17292 where op is one of
17293 ldrb ldrh ldr ldrsb ldrsh
17294 strb strh str
17295 */
17296 if (INSN0(15,9) == BITS7(1,1,1,1,1,0,0)) {
17297 Bool valid = True;
17298 Bool syned = False;
17299 Bool isST = False;
17300 IRType ty = Ity_I8;
17301 HChar* nm = "???";
17302
17303 switch (INSN0(8,4)) {
17304 case BITS5(0,1,0,0,0): // strb
17305 nm = "strb"; isST = True; break;
17306 case BITS5(0,1,0,0,1): // ldrb
17307 nm = "ldrb"; break;
17308 case BITS5(1,1,0,0,1): // ldrsb
17309 nm = "ldrsb"; syned = True; break;
17310 case BITS5(0,1,0,1,0): // strh
17311 nm = "strh"; ty = Ity_I16; isST = True; break;
17312 case BITS5(0,1,0,1,1): // ldrh
17313 nm = "ldrh"; ty = Ity_I16; break;
17314 case BITS5(1,1,0,1,1): // ldrsh
17315 nm = "ldrsh"; ty = Ity_I16; syned = True; break;
17316 case BITS5(0,1,1,0,0): // str
17317 nm = "str"; ty = Ity_I32; isST = True; break;
17318 case BITS5(0,1,1,0,1):
17319 nm = "ldr"; ty = Ity_I32; break; // ldr
17320 default:
17321 valid = False; break;
17322 }
17323
17324 UInt rN = INSN0(3,0);
17325 UInt rT = INSN1(15,12);
17326 UInt imm12 = INSN1(11,0);
17327 Bool loadsPC = False;
17328
17329 if (ty == Ity_I8 || ty == Ity_I16) {
17330 /* all 8- and 16-bit load and store cases have the
17331 same exclusion set. */
17332 if (rN == 15 || isBadRegT(rT))
17333 valid = False;
17334 } else {
17335 vassert(ty == Ity_I32);
17336 if (isST) {
17337 if (rN == 15 || rT == 15)
17338 valid = False;
17339 } else {
17340 /* For a 32-bit load, rT == 15 is only allowable if we not
17341 in an IT block, or are the last in it. Need to insert
17342 a dynamic check for that. Also, in this particular
17343 case, rN == 15 is allowable. In this case however, the
17344 value obtained for rN is (apparently)
17345 "word-align(address of current insn + 4)". */
17346 if (rT == 15)
17347 loadsPC = True;
17348 }
17349 }
17350
17351 if (valid) {
17352 // if it's a branch, it can't happen in the middle of an IT block
17353 if (loadsPC)
17354 gen_SIGILL_T_if_in_but_NLI_ITBlock(old_itstate, new_itstate);
17355 // go uncond
17356 mk_skip_over_T32_if_cond_is_false(condT);
17357 condT = IRTemp_INVALID;
17358 // now uncond
17359
17360 IRTemp rNt = newTemp(Ity_I32);
17361 if (rN == 15) {
17362 vassert(ty == Ity_I32 && !isST);
17363 assign(rNt, binop(Iop_And32, getIRegT(rN), mkU32(~3)));
17364 } else {
17365 assign(rNt, getIRegT(rN));
17366 }
17367
17368 IRTemp transAddr = newTemp(Ity_I32);
17369 assign(transAddr,
17370 binop( Iop_Add32, mkexpr(rNt), mkU32(imm12) ));
17371
17372 if (isST) {
17373 IRTemp oldRt = newTemp(Ity_I32);
17374 assign(oldRt, getIRegT(rT));
17375 switch (ty) {
17376 case Ity_I8:
17377 storeLE(mkexpr(transAddr),
17378 unop(Iop_32to8, mkexpr(oldRt)));
17379 break;
17380 case Ity_I16:
17381 storeLE(mkexpr(transAddr),
17382 unop(Iop_32to16, mkexpr(oldRt)));
17383 break;
17384 case Ity_I32:
17385 storeLE(mkexpr(transAddr), mkexpr(oldRt));
17386 break;
17387 default:
17388 vassert(0);
17389 }
17390 } else {
17391 IRTemp newRt = newTemp(Ity_I32);
17392 IROp widen = Iop_INVALID;
17393 switch (ty) {
17394 case Ity_I8:
17395 widen = syned ? Iop_8Sto32 : Iop_8Uto32; break;
17396 case Ity_I16:
17397 widen = syned ? Iop_16Sto32 : Iop_16Uto32; break;
17398 case Ity_I32:
17399 break;
17400 default:
17401 vassert(0);
17402 }
17403 if (widen == Iop_INVALID) {
17404 assign(newRt, loadLE(ty, mkexpr(transAddr)));
17405 } else {
17406 assign(newRt, unop(widen, loadLE(ty, mkexpr(transAddr))));
17407 }
17408 putIRegT(rT, mkexpr(newRt), IRTemp_INVALID);
17409
17410 if (loadsPC) {
17411 /* Presumably this is an interworking branch. */
17412 irsb->next = mkexpr(newRt);
17413 irsb->jumpkind = Ijk_Boring; /* or _Ret ? */
17414 dres.whatNext = Dis_StopHere;
17415 }
17416 }
17417
17418 DIP("%s.w r%u, [r%u, +#%u]\n", nm, rT, rN, imm12);
17419
17420 goto decode_success;
17421 }
17422 }
17423
17424 /* -------------- LDRD/STRD reg+/-#imm8 -------------- */
17425 /* Doubleword loads and stores of the form:
17426 ldrd/strd Rt, Rt2, [Rn, #-imm8] or
17427 ldrd/strd Rt, Rt2, [Rn], #+/-imm8 or
17428 ldrd/strd Rt, Rt2, [Rn, #+/-imm8]!
17429 */
17430 if (INSN0(15,9) == BITS7(1,1,1,0,1,0,0) && INSN0(6,6) == 1) {
17431 UInt bP = INSN0(8,8);
17432 UInt bU = INSN0(7,7);
17433 UInt bW = INSN0(5,5);
17434 UInt bL = INSN0(4,4); // 1: load 0: store
17435 UInt rN = INSN0(3,0);
17436 UInt rT = INSN1(15,12);
17437 UInt rT2 = INSN1(11,8);
17438 UInt imm8 = INSN1(7,0);
17439
17440 Bool valid = True;
17441 if (bP == 0 && bW == 0) valid = False;
17442 if (bW == 1 && (rN == rT || rN == rT2)) valid = False;
17443 if (isBadRegT(rT) || isBadRegT(rT2)) valid = False;
17444 if (rN == 15) valid = False;
17445 if (bL == 1 && rT == rT2) valid = False;
17446
17447 if (valid) {
17448 // go uncond
17449 mk_skip_over_T32_if_cond_is_false(condT);
17450 condT = IRTemp_INVALID;
17451 // now uncond
17452
17453 IRTemp preAddr = newTemp(Ity_I32);
17454 assign(preAddr, getIRegT(rN));
17455
17456 IRTemp postAddr = newTemp(Ity_I32);
17457 assign(postAddr, binop(bU == 1 ? Iop_Add32 : Iop_Sub32,
17458 mkexpr(preAddr), mkU32(imm8 << 2)));
17459
17460 IRTemp transAddr = bP == 1 ? postAddr : preAddr;
17461
17462 if (bL == 0) {
17463 IRTemp oldRt = newTemp(Ity_I32);
17464 IRTemp oldRt2 = newTemp(Ity_I32);
17465 assign(oldRt, getIRegT(rT));
17466 assign(oldRt2, getIRegT(rT2));
17467 storeLE(mkexpr(transAddr),
17468 mkexpr(oldRt));
17469 storeLE(binop(Iop_Add32, mkexpr(transAddr), mkU32(4)),
17470 mkexpr(oldRt2));
17471 } else {
17472 IRTemp newRt = newTemp(Ity_I32);
17473 IRTemp newRt2 = newTemp(Ity_I32);
17474 assign(newRt,
17475 loadLE(Ity_I32,
17476 mkexpr(transAddr)));
17477 assign(newRt2,
17478 loadLE(Ity_I32,
17479 binop(Iop_Add32, mkexpr(transAddr), mkU32(4))));
17480 putIRegT(rT, mkexpr(newRt), IRTemp_INVALID);
17481 putIRegT(rT2, mkexpr(newRt2), IRTemp_INVALID);
17482 }
17483
17484 if (bW == 1) {
17485 putIRegT(rN, mkexpr(postAddr), IRTemp_INVALID);
17486 }
17487
17488 HChar* nm = bL ? "ldrd" : "strd";
17489
17490 if (bP == 1 && bW == 0) {
17491 DIP("%s.w r%u, r%u, [r%u, #%c%u]\n",
17492 nm, rT, rT2, rN, bU ? '+' : '-', imm8 << 2);
17493 }
17494 else if (bP == 1 && bW == 1) {
17495 DIP("%s.w r%u, r%u, [r%u, #%c%u]!\n",
17496 nm, rT, rT2, rN, bU ? '+' : '-', imm8 << 2);
17497 }
17498 else {
17499 vassert(bP == 0 && bW == 1);
17500 DIP("%s.w r%u, r%u, [r%u], #%c%u\n",
17501 nm, rT, rT2, rN, bU ? '+' : '-', imm8 << 2);
17502 }
17503
17504 goto decode_success;
17505 }
17506 }
17507
17508 /* -------------- (T3) Bcond.W label -------------- */
17509 /* This variant carries its own condition, so can't be part of an
17510 IT block ... */
17511 if (INSN0(15,11) == BITS5(1,1,1,1,0)
17512 && INSN1(15,14) == BITS2(1,0)
17513 && INSN1(12,12) == 0) {
17514 UInt cond = INSN0(9,6);
17515 if (cond != ARMCondAL && cond != ARMCondNV) {
17516 Int simm21
17517 = (INSN0(10,10) << (1 + 1 + 6 + 11 + 1))
17518 | (INSN1(11,11) << (1 + 6 + 11 + 1))
17519 | (INSN1(13,13) << (6 + 11 + 1))
17520 | (INSN0(5,0) << (11 + 1))
17521 | (INSN1(10,0) << 1);
17522 simm21 = (simm21 << 11) >> 11;
17523
17524 vassert(0 == (guest_R15_curr_instr_notENC & 1));
17525 UInt dst = simm21 + guest_R15_curr_instr_notENC + 4;
17526
17527 /* Not allowed in an IT block; SIGILL if so. */
17528 gen_SIGILL_T_if_in_ITBlock(old_itstate, new_itstate);
17529
17530 IRTemp kondT = newTemp(Ity_I32);
17531 assign( kondT, mk_armg_calculate_condition(cond) );
17532 stmt( IRStmt_Exit( unop(Iop_32to1, mkexpr(kondT)),
17533 Ijk_Boring,
sewardjc6f970f2012-04-02 21:54:49 +000017534 IRConst_U32(dst | 1/*CPSR.T*/),
17535 OFFB_R15T ));
17536 llPutIReg(15, mkU32( (guest_R15_curr_instr_notENC + 4)
17537 | 1 /*CPSR.T*/ ));
17538 dres.jk_StopHere = Ijk_Boring;
17539 dres.whatNext = Dis_StopHere;
sewardjd2664472010-08-22 12:44:20 +000017540 DIP("b%s.w 0x%x\n", nCC(cond), dst);
17541 goto decode_success;
17542 }
17543 }
17544
17545 /* ---------------- (T4) B.W label ---------------- */
17546 /* ... whereas this variant doesn't carry its own condition, so it
17547 has to be either unconditional or the conditional by virtue of
17548 being the last in an IT block. The upside is that there's 4
17549 more bits available for the jump offset, so it has a 16-times
17550 greater branch range than the T3 variant. */
17551 if (INSN0(15,11) == BITS5(1,1,1,1,0)
17552 && INSN1(15,14) == BITS2(1,0)
17553 && INSN1(12,12) == 1) {
17554 if (1) {
17555 UInt bS = INSN0(10,10);
17556 UInt bJ1 = INSN1(13,13);
17557 UInt bJ2 = INSN1(11,11);
17558 UInt bI1 = 1 ^ (bJ1 ^ bS);
17559 UInt bI2 = 1 ^ (bJ2 ^ bS);
17560 Int simm25
17561 = (bS << (1 + 1 + 10 + 11 + 1))
17562 | (bI1 << (1 + 10 + 11 + 1))
17563 | (bI2 << (10 + 11 + 1))
17564 | (INSN0(9,0) << (11 + 1))
17565 | (INSN1(10,0) << 1);
17566 simm25 = (simm25 << 7) >> 7;
17567
17568 vassert(0 == (guest_R15_curr_instr_notENC & 1));
17569 UInt dst = simm25 + guest_R15_curr_instr_notENC + 4;
17570
17571 /* If in an IT block, must be the last insn. */
17572 gen_SIGILL_T_if_in_but_NLI_ITBlock(old_itstate, new_itstate);
17573
17574 // go uncond
17575 mk_skip_over_T32_if_cond_is_false(condT);
17576 condT = IRTemp_INVALID;
17577 // now uncond
17578
17579 // branch to dst
sewardjc6f970f2012-04-02 21:54:49 +000017580 llPutIReg(15, mkU32( dst | 1 /*CPSR.T*/ ));
17581 dres.jk_StopHere = Ijk_Boring;
17582 dres.whatNext = Dis_StopHere;
sewardjd2664472010-08-22 12:44:20 +000017583 DIP("b.w 0x%x\n", dst);
17584 goto decode_success;
17585 }
17586 }
17587
17588 /* ------------------ TBB, TBH ------------------ */
17589 if (INSN0(15,4) == 0xE8D && INSN1(15,5) == 0x780) {
17590 UInt rN = INSN0(3,0);
17591 UInt rM = INSN1(3,0);
17592 UInt bH = INSN1(4,4);
17593 if (bH/*ATC*/ || (rN != 13 && !isBadRegT(rM))) {
17594 /* Must be last or not-in IT block */
17595 gen_SIGILL_T_if_in_but_NLI_ITBlock(old_itstate, new_itstate);
17596 /* Go uncond */
17597 mk_skip_over_T32_if_cond_is_false(condT);
17598 condT = IRTemp_INVALID;
17599
17600 IRExpr* ea
17601 = binop(Iop_Add32,
17602 getIRegT(rN),
17603 bH ? binop(Iop_Shl32, getIRegT(rM), mkU8(1))
17604 : getIRegT(rM));
17605
17606 IRTemp delta = newTemp(Ity_I32);
17607 if (bH) {
17608 assign(delta, unop(Iop_16Uto32, loadLE(Ity_I16, ea)));
17609 } else {
17610 assign(delta, unop(Iop_8Uto32, loadLE(Ity_I8, ea)));
17611 }
17612
sewardjc6f970f2012-04-02 21:54:49 +000017613 llPutIReg(
17614 15,
17615 binop(Iop_Or32,
17616 binop(Iop_Add32,
17617 getIRegT(15),
17618 binop(Iop_Shl32, mkexpr(delta), mkU8(1))
17619 ),
17620 mkU32(1)
17621 ));
17622 dres.jk_StopHere = Ijk_Boring;
17623 dres.whatNext = Dis_StopHere;
sewardjd2664472010-08-22 12:44:20 +000017624 DIP("tb%c [r%u, r%u%s]\n",
17625 bH ? 'h' : 'b', rN, rM, bH ? ", LSL #1" : "");
17626 goto decode_success;
17627 }
17628 }
17629
17630 /* ------------------ UBFX ------------------ */
17631 /* ------------------ SBFX ------------------ */
17632 /* There's also ARM versions of same, but it doesn't seem worth the
17633 hassle to common up the handling (it's only a couple of C
17634 statements). */
17635 if ((INSN0(15,4) == 0xF3C // UBFX
17636 || INSN0(15,4) == 0xF34) // SBFX
17637 && INSN1(15,15) == 0 && INSN1(5,5) == 0) {
17638 UInt rN = INSN0(3,0);
17639 UInt rD = INSN1(11,8);
17640 UInt lsb = (INSN1(14,12) << 2) | INSN1(7,6);
17641 UInt wm1 = INSN1(4,0);
17642 UInt msb = lsb + wm1;
17643 if (!isBadRegT(rD) && !isBadRegT(rN) && msb <= 31) {
17644 Bool isU = INSN0(15,4) == 0xF3C;
17645 IRTemp src = newTemp(Ity_I32);
17646 IRTemp tmp = newTemp(Ity_I32);
17647 IRTemp res = newTemp(Ity_I32);
17648 UInt mask = ((1 << wm1) - 1) + (1 << wm1);
17649 vassert(msb >= 0 && msb <= 31);
17650 vassert(mask != 0); // guaranteed by msb being in 0 .. 31 inclusive
17651
17652 assign(src, getIRegT(rN));
17653 assign(tmp, binop(Iop_And32,
17654 binop(Iop_Shr32, mkexpr(src), mkU8(lsb)),
17655 mkU32(mask)));
17656 assign(res, binop(isU ? Iop_Shr32 : Iop_Sar32,
17657 binop(Iop_Shl32, mkexpr(tmp), mkU8(31-wm1)),
17658 mkU8(31-wm1)));
17659
17660 putIRegT(rD, mkexpr(res), condT);
17661
17662 DIP("%s r%u, r%u, #%u, #%u\n",
17663 isU ? "ubfx" : "sbfx", rD, rN, lsb, wm1 + 1);
17664 goto decode_success;
17665 }
17666 }
17667
17668 /* ------------------ UXTB ------------------ */
17669 /* ------------------ UXTH ------------------ */
17670 /* ------------------ SXTB ------------------ */
17671 /* ------------------ SXTH ------------------ */
sewardj1f139f52010-08-29 12:33:02 +000017672 /* ----------------- UXTB16 ----------------- */
17673 /* ----------------- SXTB16 ----------------- */
17674 /* FIXME: this is an exact duplicate of the ARM version. They
17675 should be commoned up. */
sewardjd2664472010-08-22 12:44:20 +000017676 if ((INSN0(15,0) == 0xFA5F // UXTB
17677 || INSN0(15,0) == 0xFA1F // UXTH
17678 || INSN0(15,0) == 0xFA4F // SXTB
sewardj1f139f52010-08-29 12:33:02 +000017679 || INSN0(15,0) == 0xFA0F // SXTH
17680 || INSN0(15,0) == 0xFA3F // UXTB16
17681 || INSN0(15,0) == 0xFA2F) // SXTB16
sewardjd2664472010-08-22 12:44:20 +000017682 && INSN1(15,12) == BITS4(1,1,1,1)
17683 && INSN1(7,6) == BITS2(1,0)) {
17684 UInt rD = INSN1(11,8);
17685 UInt rM = INSN1(3,0);
17686 UInt rot = INSN1(5,4);
17687 if (!isBadRegT(rD) && !isBadRegT(rM)) {
17688 HChar* nm = "???";
17689 IRTemp srcT = newTemp(Ity_I32);
17690 IRTemp rotT = newTemp(Ity_I32);
17691 IRTemp dstT = newTemp(Ity_I32);
17692 assign(srcT, getIRegT(rM));
17693 assign(rotT, genROR32(srcT, 8 * rot));
17694 switch (INSN0(15,0)) {
17695 case 0xFA5F: // UXTB
17696 nm = "uxtb";
17697 assign(dstT, unop(Iop_8Uto32,
17698 unop(Iop_32to8, mkexpr(rotT))));
17699 break;
17700 case 0xFA1F: // UXTH
17701 nm = "uxth";
17702 assign(dstT, unop(Iop_16Uto32,
17703 unop(Iop_32to16, mkexpr(rotT))));
17704 break;
17705 case 0xFA4F: // SXTB
17706 nm = "sxtb";
17707 assign(dstT, unop(Iop_8Sto32,
17708 unop(Iop_32to8, mkexpr(rotT))));
17709 break;
17710 case 0xFA0F: // SXTH
17711 nm = "sxth";
17712 assign(dstT, unop(Iop_16Sto32,
17713 unop(Iop_32to16, mkexpr(rotT))));
17714 break;
sewardj1f139f52010-08-29 12:33:02 +000017715 case 0xFA3F: // UXTB16
17716 nm = "uxtb16";
17717 assign(dstT, binop(Iop_And32, mkexpr(rotT),
17718 mkU32(0x00FF00FF)));
17719 break;
17720 case 0xFA2F: { // SXTB16
17721 nm = "sxtb16";
17722 IRTemp lo32 = newTemp(Ity_I32);
17723 IRTemp hi32 = newTemp(Ity_I32);
17724 assign(lo32, binop(Iop_And32, mkexpr(rotT), mkU32(0xFF)));
17725 assign(hi32, binop(Iop_Shr32, mkexpr(rotT), mkU8(16)));
17726 assign(
17727 dstT,
17728 binop(Iop_Or32,
17729 binop(Iop_And32,
17730 unop(Iop_8Sto32,
17731 unop(Iop_32to8, mkexpr(lo32))),
17732 mkU32(0xFFFF)),
17733 binop(Iop_Shl32,
17734 unop(Iop_8Sto32,
17735 unop(Iop_32to8, mkexpr(hi32))),
17736 mkU8(16))
17737 ));
17738 break;
17739 }
sewardjd2664472010-08-22 12:44:20 +000017740 default:
17741 vassert(0);
17742 }
17743 putIRegT(rD, mkexpr(dstT), condT);
17744 DIP("%s r%u, r%u, ror #%u\n", nm, rD, rM, 8 * rot);
17745 goto decode_success;
17746 }
17747 }
17748
17749 /* -------------- MUL.W Rd, Rn, Rm -------------- */
17750 if (INSN0(15,4) == 0xFB0
17751 && (INSN1(15,0) & 0xF0F0) == 0xF000) {
17752 UInt rN = INSN0(3,0);
17753 UInt rD = INSN1(11,8);
17754 UInt rM = INSN1(3,0);
17755 if (!isBadRegT(rD) && !isBadRegT(rN) && !isBadRegT(rM)) {
17756 IRTemp res = newTemp(Ity_I32);
17757 assign(res, binop(Iop_Mul32, getIRegT(rN), getIRegT(rM)));
17758 putIRegT(rD, mkexpr(res), condT);
17759 DIP("mul.w r%u, r%u, r%u\n", rD, rN, rM);
17760 goto decode_success;
17761 }
17762 }
17763
17764 /* ------------------ {U,S}MULL ------------------ */
17765 if ((INSN0(15,4) == 0xFB8 || INSN0(15,4) == 0xFBA)
17766 && INSN1(7,4) == BITS4(0,0,0,0)) {
17767 UInt isU = INSN0(5,5);
17768 UInt rN = INSN0(3,0);
17769 UInt rDlo = INSN1(15,12);
17770 UInt rDhi = INSN1(11,8);
17771 UInt rM = INSN1(3,0);
17772 if (!isBadRegT(rDhi) && !isBadRegT(rDlo)
17773 && !isBadRegT(rN) && !isBadRegT(rM) && rDlo != rDhi) {
17774 IRTemp res = newTemp(Ity_I64);
17775 assign(res, binop(isU ? Iop_MullU32 : Iop_MullS32,
17776 getIRegT(rN), getIRegT(rM)));
17777 putIRegT( rDhi, unop(Iop_64HIto32, mkexpr(res)), condT );
17778 putIRegT( rDlo, unop(Iop_64to32, mkexpr(res)), condT );
17779 DIP("%cmull r%u, r%u, r%u, r%u\n",
17780 isU ? 'u' : 's', rDlo, rDhi, rN, rM);
17781 goto decode_success;
17782 }
17783 }
17784
17785 /* ------------------ ML{A,S} ------------------ */
17786 if (INSN0(15,4) == 0xFB0
17787 && ( INSN1(7,4) == BITS4(0,0,0,0) // MLA
17788 || INSN1(7,4) == BITS4(0,0,0,1))) { // MLS
17789 UInt rN = INSN0(3,0);
17790 UInt rA = INSN1(15,12);
17791 UInt rD = INSN1(11,8);
17792 UInt rM = INSN1(3,0);
17793 if (!isBadRegT(rD) && !isBadRegT(rN)
17794 && !isBadRegT(rM) && !isBadRegT(rA)) {
17795 Bool isMLA = INSN1(7,4) == BITS4(0,0,0,0);
17796 IRTemp res = newTemp(Ity_I32);
17797 assign(res,
17798 binop(isMLA ? Iop_Add32 : Iop_Sub32,
17799 getIRegT(rA),
17800 binop(Iop_Mul32, getIRegT(rN), getIRegT(rM))));
17801 putIRegT(rD, mkexpr(res), condT);
17802 DIP("%s r%u, r%u, r%u, r%u\n",
17803 isMLA ? "mla" : "mls", rD, rN, rM, rA);
17804 goto decode_success;
17805 }
17806 }
17807
17808 /* ------------------ (T3) ADR ------------------ */
17809 if ((INSN0(15,0) == 0xF20F || INSN0(15,0) == 0xF60F)
17810 && INSN1(15,15) == 0) {
17811 /* rD = align4(PC) + imm32 */
17812 UInt rD = INSN1(11,8);
17813 if (!isBadRegT(rD)) {
17814 UInt imm32 = (INSN0(10,10) << 11)
17815 | (INSN1(14,12) << 8) | INSN1(7,0);
17816 putIRegT(rD, binop(Iop_Add32,
sewardjdf86f162010-08-22 18:47:30 +000017817 binop(Iop_And32, getIRegT(15), mkU32(~3U)),
sewardjd2664472010-08-22 12:44:20 +000017818 mkU32(imm32)),
17819 condT);
17820 DIP("add r%u, pc, #%u\n", rD, imm32);
17821 goto decode_success;
17822 }
17823 }
17824
17825 /* ----------------- (T1) UMLAL ----------------- */
17826 /* ----------------- (T1) SMLAL ----------------- */
17827 if ((INSN0(15,4) == 0xFBE // UMLAL
17828 || INSN0(15,4) == 0xFBC) // SMLAL
17829 && INSN1(7,4) == BITS4(0,0,0,0)) {
17830 UInt rN = INSN0(3,0);
17831 UInt rDlo = INSN1(15,12);
17832 UInt rDhi = INSN1(11,8);
17833 UInt rM = INSN1(3,0);
17834 if (!isBadRegT(rDlo) && !isBadRegT(rDhi) && !isBadRegT(rN)
17835 && !isBadRegT(rM) && rDhi != rDlo) {
17836 Bool isS = INSN0(15,4) == 0xFBC;
17837 IRTemp argL = newTemp(Ity_I32);
17838 IRTemp argR = newTemp(Ity_I32);
17839 IRTemp old = newTemp(Ity_I64);
17840 IRTemp res = newTemp(Ity_I64);
17841 IRTemp resHi = newTemp(Ity_I32);
17842 IRTemp resLo = newTemp(Ity_I32);
17843 IROp mulOp = isS ? Iop_MullS32 : Iop_MullU32;
17844 assign( argL, getIRegT(rM));
17845 assign( argR, getIRegT(rN));
17846 assign( old, binop(Iop_32HLto64, getIRegT(rDhi), getIRegT(rDlo)) );
17847 assign( res, binop(Iop_Add64,
17848 mkexpr(old),
17849 binop(mulOp, mkexpr(argL), mkexpr(argR))) );
17850 assign( resHi, unop(Iop_64HIto32, mkexpr(res)) );
17851 assign( resLo, unop(Iop_64to32, mkexpr(res)) );
17852 putIRegT( rDhi, mkexpr(resHi), condT );
17853 putIRegT( rDlo, mkexpr(resLo), condT );
17854 DIP("%cmlal r%u, r%u, r%u, r%u\n",
17855 isS ? 's' : 'u', rDlo, rDhi, rN, rM);
17856 goto decode_success;
17857 }
17858 }
17859
17860 /* ------------------ (T2) ADR ------------------ */
17861 if ((INSN0(15,0) == 0xF2AF || INSN0(15,0) == 0xF6AF)
17862 && INSN1(15,15) == 0) {
17863 /* rD = align4(PC) - imm32 */
17864 UInt rD = INSN1(11,8);
17865 if (!isBadRegT(rD)) {
17866 UInt imm32 = (INSN0(10,10) << 11)
17867 | (INSN1(14,12) << 8) | INSN1(7,0);
17868 putIRegT(rD, binop(Iop_Sub32,
sewardjdf86f162010-08-22 18:47:30 +000017869 binop(Iop_And32, getIRegT(15), mkU32(~3U)),
sewardjd2664472010-08-22 12:44:20 +000017870 mkU32(imm32)),
17871 condT);
17872 DIP("sub r%u, pc, #%u\n", rD, imm32);
17873 goto decode_success;
17874 }
17875 }
17876
17877 /* ------------------- (T1) BFI ------------------- */
17878 /* ------------------- (T1) BFC ------------------- */
17879 if (INSN0(15,4) == 0xF36 && INSN1(15,15) == 0 && INSN1(5,5) == 0) {
17880 UInt rD = INSN1(11,8);
17881 UInt rN = INSN0(3,0);
17882 UInt msb = INSN1(4,0);
17883 UInt lsb = (INSN1(14,12) << 2) | INSN1(7,6);
17884 if (isBadRegT(rD) || rN == 13 || msb < lsb) {
17885 /* undecodable; fall through */
17886 } else {
17887 IRTemp src = newTemp(Ity_I32);
17888 IRTemp olddst = newTemp(Ity_I32);
17889 IRTemp newdst = newTemp(Ity_I32);
17890 UInt mask = 1 << (msb - lsb);
17891 mask = (mask - 1) + mask;
17892 vassert(mask != 0); // guaranteed by "msb < lsb" check above
17893 mask <<= lsb;
17894
17895 assign(src, rN == 15 ? mkU32(0) : getIRegT(rN));
17896 assign(olddst, getIRegT(rD));
17897 assign(newdst,
17898 binop(Iop_Or32,
17899 binop(Iop_And32,
17900 binop(Iop_Shl32, mkexpr(src), mkU8(lsb)),
17901 mkU32(mask)),
17902 binop(Iop_And32,
17903 mkexpr(olddst),
17904 mkU32(~mask)))
17905 );
17906
17907 putIRegT(rD, mkexpr(newdst), condT);
17908
17909 if (rN == 15) {
17910 DIP("bfc r%u, #%u, #%u\n",
17911 rD, lsb, msb-lsb+1);
17912 } else {
17913 DIP("bfi r%u, r%u, #%u, #%u\n",
17914 rD, rN, lsb, msb-lsb+1);
17915 }
17916 goto decode_success;
17917 }
17918 }
17919
sewardjd2664472010-08-22 12:44:20 +000017920 /* ------------------- (T1) SXTAH ------------------- */
17921 /* ------------------- (T1) UXTAH ------------------- */
17922 if ((INSN0(15,4) == 0xFA1 // UXTAH
17923 || INSN0(15,4) == 0xFA0) // SXTAH
17924 && INSN1(15,12) == BITS4(1,1,1,1)
17925 && INSN1(7,6) == BITS2(1,0)) {
17926 Bool isU = INSN0(15,4) == 0xFA1;
17927 UInt rN = INSN0(3,0);
17928 UInt rD = INSN1(11,8);
17929 UInt rM = INSN1(3,0);
17930 UInt rot = INSN1(5,4);
17931 if (!isBadRegT(rD) && !isBadRegT(rN) && !isBadRegT(rM)) {
17932 IRTemp srcL = newTemp(Ity_I32);
17933 IRTemp srcR = newTemp(Ity_I32);
17934 IRTemp res = newTemp(Ity_I32);
17935 assign(srcR, getIRegT(rM));
17936 assign(srcL, getIRegT(rN));
17937 assign(res, binop(Iop_Add32,
17938 mkexpr(srcL),
17939 unop(isU ? Iop_16Uto32 : Iop_16Sto32,
17940 unop(Iop_32to16,
17941 genROR32(srcR, 8 * rot)))));
17942 putIRegT(rD, mkexpr(res), condT);
17943 DIP("%cxtah r%u, r%u, r%u, ror #%u\n",
17944 isU ? 'u' : 's', rD, rN, rM, rot);
17945 goto decode_success;
17946 }
17947 }
17948
17949 /* ------------------- (T1) SXTAB ------------------- */
17950 /* ------------------- (T1) UXTAB ------------------- */
17951 if ((INSN0(15,4) == 0xFA5 // UXTAB
17952 || INSN0(15,4) == 0xFA4) // SXTAB
17953 && INSN1(15,12) == BITS4(1,1,1,1)
17954 && INSN1(7,6) == BITS2(1,0)) {
17955 Bool isU = INSN0(15,4) == 0xFA5;
17956 UInt rN = INSN0(3,0);
17957 UInt rD = INSN1(11,8);
17958 UInt rM = INSN1(3,0);
17959 UInt rot = INSN1(5,4);
17960 if (!isBadRegT(rD) && !isBadRegT(rN) && !isBadRegT(rM)) {
17961 IRTemp srcL = newTemp(Ity_I32);
17962 IRTemp srcR = newTemp(Ity_I32);
17963 IRTemp res = newTemp(Ity_I32);
17964 assign(srcR, getIRegT(rM));
17965 assign(srcL, getIRegT(rN));
17966 assign(res, binop(Iop_Add32,
17967 mkexpr(srcL),
17968 unop(isU ? Iop_8Uto32 : Iop_8Sto32,
17969 unop(Iop_32to8,
17970 genROR32(srcR, 8 * rot)))));
17971 putIRegT(rD, mkexpr(res), condT);
17972 DIP("%cxtab r%u, r%u, r%u, ror #%u\n",
17973 isU ? 'u' : 's', rD, rN, rM, rot);
17974 goto decode_success;
17975 }
17976 }
17977
17978 /* ------------------- (T1) CLZ ------------------- */
17979 if (INSN0(15,4) == 0xFAB
17980 && INSN1(15,12) == BITS4(1,1,1,1)
17981 && INSN1(7,4) == BITS4(1,0,0,0)) {
17982 UInt rM1 = INSN0(3,0);
sewardj677e5af2010-09-02 21:02:47 +000017983 UInt rD = INSN1(11,8);
sewardjd2664472010-08-22 12:44:20 +000017984 UInt rM2 = INSN1(3,0);
17985 if (!isBadRegT(rD) && !isBadRegT(rM1) && rM1 == rM2) {
17986 IRTemp arg = newTemp(Ity_I32);
17987 IRTemp res = newTemp(Ity_I32);
17988 assign(arg, getIRegT(rM1));
17989 assign(res, IRExpr_Mux0X(
17990 unop(Iop_1Uto8,binop(Iop_CmpEQ32,
17991 mkexpr(arg),
17992 mkU32(0))),
17993 unop(Iop_Clz32, mkexpr(arg)),
17994 mkU32(32)
17995 ));
17996 putIRegT(rD, mkexpr(res), condT);
17997 DIP("clz r%u, r%u\n", rD, rM1);
17998 goto decode_success;
17999 }
18000 }
18001
sewardj677e5af2010-09-02 21:02:47 +000018002 /* ------------------- (T1) RBIT ------------------- */
18003 if (INSN0(15,4) == 0xFA9
18004 && INSN1(15,12) == BITS4(1,1,1,1)
18005 && INSN1(7,4) == BITS4(1,0,1,0)) {
18006 UInt rM1 = INSN0(3,0);
18007 UInt rD = INSN1(11,8);
18008 UInt rM2 = INSN1(3,0);
18009 if (!isBadRegT(rD) && !isBadRegT(rM1) && rM1 == rM2) {
18010 IRTemp arg = newTemp(Ity_I32);
18011 assign(arg, getIRegT(rM1));
18012 IRTemp res = gen_BITREV(arg);
18013 putIRegT(rD, mkexpr(res), condT);
18014 DIP("rbit r%u, r%u\n", rD, rM1);
18015 goto decode_success;
18016 }
18017 }
18018
sewardj27312d32010-09-26 00:48:41 +000018019 /* ------------------- (T2) REV ------------------- */
18020 /* ------------------- (T2) REV16 ------------------- */
18021 if (INSN0(15,4) == 0xFA9
18022 && INSN1(15,12) == BITS4(1,1,1,1)
18023 && ( INSN1(7,4) == BITS4(1,0,0,0) // REV
18024 || INSN1(7,4) == BITS4(1,0,0,1))) { // REV16
18025 UInt rM1 = INSN0(3,0);
18026 UInt rD = INSN1(11,8);
18027 UInt rM2 = INSN1(3,0);
18028 Bool isREV = INSN1(7,4) == BITS4(1,0,0,0);
18029 if (!isBadRegT(rD) && !isBadRegT(rM1) && rM1 == rM2) {
18030 IRTemp arg = newTemp(Ity_I32);
18031 assign(arg, getIRegT(rM1));
18032 IRTemp res = isREV ? gen_REV(arg) : gen_REV16(arg);
18033 putIRegT(rD, mkexpr(res), condT);
18034 DIP("rev%s r%u, r%u\n", isREV ? "" : "16", rD, rM1);
18035 goto decode_success;
18036 }
18037 }
18038
sewardjd2664472010-08-22 12:44:20 +000018039 /* -------------- (T1) MSR apsr, reg -------------- */
18040 if (INSN0(15,4) == 0xF38
18041 && INSN1(15,12) == BITS4(1,0,0,0) && INSN1(9,0) == 0x000) {
18042 UInt rN = INSN0(3,0);
18043 UInt write_ge = INSN1(10,10);
18044 UInt write_nzcvq = INSN1(11,11);
sewardj1f139f52010-08-29 12:33:02 +000018045 if (!isBadRegT(rN) && (write_nzcvq || write_ge)) {
sewardjd2664472010-08-22 12:44:20 +000018046 IRTemp rNt = newTemp(Ity_I32);
18047 assign(rNt, getIRegT(rN));
sewardj1f139f52010-08-29 12:33:02 +000018048 desynthesise_APSR( write_nzcvq, write_ge, rNt, condT );
18049 DIP("msr cpsr_%s%s, r%u\n",
18050 write_nzcvq ? "f" : "", write_ge ? "g" : "", rN);
sewardjd2664472010-08-22 12:44:20 +000018051 goto decode_success;
18052 }
18053 }
18054
18055 /* -------------- (T1) MRS reg, apsr -------------- */
18056 if (INSN0(15,0) == 0xF3EF
18057 && INSN1(15,12) == BITS4(1,0,0,0) && INSN1(7,0) == 0x00) {
18058 UInt rD = INSN1(11,8);
18059 if (!isBadRegT(rD)) {
sewardj1f139f52010-08-29 12:33:02 +000018060 IRTemp apsr = synthesise_APSR();
18061 putIRegT( rD, mkexpr(apsr), condT );
sewardjd2664472010-08-22 12:44:20 +000018062 DIP("mrs r%u, cpsr\n", rD);
18063 goto decode_success;
18064 }
18065 }
18066
sewardje1a93962010-09-24 23:35:59 +000018067 /* ----------------- (T1) LDREX ----------------- */
18068 if (INSN0(15,4) == 0xE85 && INSN1(11,8) == BITS4(1,1,1,1)) {
18069 UInt rN = INSN0(3,0);
18070 UInt rT = INSN1(15,12);
18071 UInt imm8 = INSN1(7,0);
18072 if (!isBadRegT(rT) && rN != 15) {
18073 IRTemp res;
18074 // go uncond
18075 mk_skip_over_T32_if_cond_is_false( condT );
18076 // now uncond
18077 res = newTemp(Ity_I32);
18078 stmt( IRStmt_LLSC(Iend_LE,
18079 res,
18080 binop(Iop_Add32, getIRegT(rN), mkU32(imm8 * 4)),
18081 NULL/*this is a load*/ ));
18082 putIRegT(rT, mkexpr(res), IRTemp_INVALID);
18083 DIP("ldrex r%u, [r%u, #+%u]\n", rT, rN, imm8 * 4);
18084 goto decode_success;
18085 }
18086 }
18087
sewardjff7f5b72011-07-11 11:43:38 +000018088 /* --------------- (T1) LDREX{B,H} --------------- */
18089 if (INSN0(15,4) == 0xE8D
18090 && (INSN1(11,0) == 0xF4F || INSN1(11,0) == 0xF5F)) {
18091 UInt rN = INSN0(3,0);
18092 UInt rT = INSN1(15,12);
18093 Bool isH = INSN1(11,0) == 0xF5F;
18094 if (!isBadRegT(rT) && rN != 15) {
18095 IRTemp res;
18096 // go uncond
18097 mk_skip_over_T32_if_cond_is_false( condT );
18098 // now uncond
18099 res = newTemp(isH ? Ity_I16 : Ity_I8);
18100 stmt( IRStmt_LLSC(Iend_LE, res, getIRegT(rN),
18101 NULL/*this is a load*/ ));
18102 putIRegT(rT, unop(isH ? Iop_16Uto32 : Iop_8Uto32, mkexpr(res)),
18103 IRTemp_INVALID);
18104 DIP("ldrex%c r%u, [r%u]\n", isH ? 'h' : 'b', rT, rN);
18105 goto decode_success;
18106 }
18107 }
18108
18109 /* --------------- (T1) LDREXD --------------- */
18110 if (INSN0(15,4) == 0xE8D && INSN1(7,0) == 0x7F) {
18111 UInt rN = INSN0(3,0);
18112 UInt rT = INSN1(15,12);
18113 UInt rT2 = INSN1(11,8);
18114 if (!isBadRegT(rT) && !isBadRegT(rT2) && rT != rT2 && rN != 15) {
18115 IRTemp res;
18116 // go uncond
18117 mk_skip_over_T32_if_cond_is_false( condT );
18118 // now uncond
18119 res = newTemp(Ity_I64);
18120 // FIXME: assumes little-endian guest
18121 stmt( IRStmt_LLSC(Iend_LE, res, getIRegT(rN),
18122 NULL/*this is a load*/ ));
18123 // FIXME: assumes little-endian guest
18124 putIRegT(rT, unop(Iop_64to32, mkexpr(res)), IRTemp_INVALID);
18125 putIRegT(rT2, unop(Iop_64HIto32, mkexpr(res)), IRTemp_INVALID);
18126 DIP("ldrexd r%u, r%u, [r%u]\n", rT, rT2, rN);
18127 goto decode_success;
18128 }
18129 }
18130
sewardje1a93962010-09-24 23:35:59 +000018131 /* ----------------- (T1) STREX ----------------- */
18132 if (INSN0(15,4) == 0xE84) {
18133 UInt rN = INSN0(3,0);
18134 UInt rT = INSN1(15,12);
18135 UInt rD = INSN1(11,8);
18136 UInt imm8 = INSN1(7,0);
18137 if (!isBadRegT(rD) && !isBadRegT(rT) && rN != 15
18138 && rD != rN && rD != rT) {
18139 IRTemp resSC1, resSC32;
sewardje1a93962010-09-24 23:35:59 +000018140 // go uncond
18141 mk_skip_over_T32_if_cond_is_false( condT );
18142 // now uncond
sewardje1a93962010-09-24 23:35:59 +000018143 /* Ok, now we're unconditional. Do the store. */
18144 resSC1 = newTemp(Ity_I1);
18145 stmt( IRStmt_LLSC(Iend_LE,
18146 resSC1,
18147 binop(Iop_Add32, getIRegT(rN), mkU32(imm8 * 4)),
18148 getIRegT(rT)) );
sewardje1a93962010-09-24 23:35:59 +000018149 /* Set rD to 1 on failure, 0 on success. Currently we have
18150 resSC1 == 0 on failure, 1 on success. */
18151 resSC32 = newTemp(Ity_I32);
18152 assign(resSC32,
18153 unop(Iop_1Uto32, unop(Iop_Not1, mkexpr(resSC1))));
sewardje1a93962010-09-24 23:35:59 +000018154 putIRegT(rD, mkexpr(resSC32), IRTemp_INVALID);
18155 DIP("strex r%u, r%u, [r%u, #+%u]\n", rD, rT, rN, imm8 * 4);
18156 goto decode_success;
18157 }
18158 }
18159
sewardjff7f5b72011-07-11 11:43:38 +000018160 /* --------------- (T1) STREX{B,H} --------------- */
18161 if (INSN0(15,4) == 0xE8C
18162 && (INSN1(11,4) == 0xF4 || INSN1(11,4) == 0xF5)) {
18163 UInt rN = INSN0(3,0);
18164 UInt rT = INSN1(15,12);
18165 UInt rD = INSN1(3,0);
18166 Bool isH = INSN1(11,4) == 0xF5;
18167 if (!isBadRegT(rD) && !isBadRegT(rT) && rN != 15
18168 && rD != rN && rD != rT) {
18169 IRTemp resSC1, resSC32;
18170 // go uncond
18171 mk_skip_over_T32_if_cond_is_false( condT );
18172 // now uncond
18173 /* Ok, now we're unconditional. Do the store. */
18174 resSC1 = newTemp(Ity_I1);
18175 stmt( IRStmt_LLSC(Iend_LE, resSC1, getIRegT(rN),
18176 unop(isH ? Iop_32to16 : Iop_32to8,
18177 getIRegT(rT))) );
18178 /* Set rD to 1 on failure, 0 on success. Currently we have
18179 resSC1 == 0 on failure, 1 on success. */
18180 resSC32 = newTemp(Ity_I32);
18181 assign(resSC32,
18182 unop(Iop_1Uto32, unop(Iop_Not1, mkexpr(resSC1))));
18183 putIRegT(rD, mkexpr(resSC32), IRTemp_INVALID);
18184 DIP("strex%c r%u, r%u, [r%u]\n", isH ? 'h' : 'b', rD, rT, rN);
18185 goto decode_success;
18186 }
18187 }
18188
18189 /* ---------------- (T1) STREXD ---------------- */
18190 if (INSN0(15,4) == 0xE8C && INSN1(7,4) == BITS4(0,1,1,1)) {
18191 UInt rN = INSN0(3,0);
18192 UInt rT = INSN1(15,12);
18193 UInt rT2 = INSN1(11,8);
18194 UInt rD = INSN1(3,0);
18195 if (!isBadRegT(rD) && !isBadRegT(rT) && !isBadRegT(rT2)
18196 && rN != 15 && rD != rN && rD != rT && rD != rT) {
18197 IRTemp resSC1, resSC32, data;
18198 // go uncond
18199 mk_skip_over_T32_if_cond_is_false( condT );
18200 // now uncond
18201 /* Ok, now we're unconditional. Do the store. */
18202 resSC1 = newTemp(Ity_I1);
18203 data = newTemp(Ity_I64);
18204 // FIXME: assumes little-endian guest
18205 assign(data, binop(Iop_32HLto64, getIRegT(rT2), getIRegT(rT)));
18206 // FIXME: assumes little-endian guest
18207 stmt( IRStmt_LLSC(Iend_LE, resSC1, getIRegT(rN), mkexpr(data)));
18208 /* Set rD to 1 on failure, 0 on success. Currently we have
18209 resSC1 == 0 on failure, 1 on success. */
18210 resSC32 = newTemp(Ity_I32);
18211 assign(resSC32,
18212 unop(Iop_1Uto32, unop(Iop_Not1, mkexpr(resSC1))));
18213 putIRegT(rD, mkexpr(resSC32), IRTemp_INVALID);
18214 DIP("strexd r%u, r%u, r%u, [r%u]\n", rD, rT, rT2, rN);
18215 goto decode_success;
18216 }
18217 }
sewardj4aec3762010-09-24 23:48:29 +000018218 /* -------------- v7 barrier insns -------------- */
sewardj5bb6ca22011-05-08 09:09:12 +000018219 if (INSN0(15,0) == 0xF3BF && (INSN1(15,0) & 0xFF00) == 0x8F00) {
sewardj6d615ba2011-09-26 16:19:43 +000018220 /* FIXME: should this be unconditional? */
sewardj646bc002010-10-11 18:57:10 +000018221 /* XXX this isn't really right, is it? The generated IR does
18222 them unconditionally. I guess it doesn't matter since it
18223 doesn't do any harm to do them even when the guarding
18224 condition is false -- it's just a performance loss. */
sewardj5bb6ca22011-05-08 09:09:12 +000018225 switch (INSN1(7,0)) {
18226 case 0x4F: /* DSB sy */
18227 case 0x4E: /* DSB st */
18228 case 0x4B: /* DSB ish */
18229 case 0x4A: /* DSB ishst */
18230 case 0x47: /* DSB nsh */
18231 case 0x46: /* DSB nshst */
18232 case 0x43: /* DSB osh */
18233 case 0x42: /* DSB oshst */
sewardj4aec3762010-09-24 23:48:29 +000018234 stmt( IRStmt_MBE(Imbe_Fence) );
18235 DIP("DSB\n");
18236 goto decode_success;
sewardj5bb6ca22011-05-08 09:09:12 +000018237 case 0x5F: /* DMB sy */
18238 case 0x5E: /* DMB st */
18239 case 0x5B: /* DMB ish */
18240 case 0x5A: /* DMB ishst */
18241 case 0x57: /* DMB nsh */
18242 case 0x56: /* DMB nshst */
18243 case 0x53: /* DMB osh */
18244 case 0x52: /* DMB oshst */
sewardj4aec3762010-09-24 23:48:29 +000018245 stmt( IRStmt_MBE(Imbe_Fence) );
18246 DIP("DMB\n");
18247 goto decode_success;
sewardj5bb6ca22011-05-08 09:09:12 +000018248 case 0x6F: /* ISB */
sewardj4aec3762010-09-24 23:48:29 +000018249 stmt( IRStmt_MBE(Imbe_Fence) );
18250 DIP("ISB\n");
18251 goto decode_success;
18252 default:
18253 break;
18254 }
18255 }
18256
sewardj7f5a8412011-07-21 06:17:21 +000018257 /* ---------------------- PLD{,W} ---------------------- */
18258 if ((INSN0(15,4) & 0xFFD) == 0xF89 && INSN1(15,12) == 0xF) {
sewardj6d615ba2011-09-26 16:19:43 +000018259 /* FIXME: should this be unconditional? */
sewardj7f5a8412011-07-21 06:17:21 +000018260 /* PLD/PLDW immediate, encoding T1 */
18261 UInt rN = INSN0(3,0);
18262 UInt bW = INSN0(5,5);
18263 UInt imm12 = INSN1(11,0);
18264 DIP("pld%s [r%u, #%u]\n", bW ? "w" : "", rN, imm12);
18265 goto decode_success;
18266 }
18267
18268 if ((INSN0(15,4) & 0xFFD) == 0xF81 && INSN1(15,8) == 0xFC) {
sewardj6d615ba2011-09-26 16:19:43 +000018269 /* FIXME: should this be unconditional? */
sewardj7f5a8412011-07-21 06:17:21 +000018270 /* PLD/PLDW immediate, encoding T2 */
18271 UInt rN = INSN0(3,0);
18272 UInt bW = INSN0(5,5);
18273 UInt imm8 = INSN1(7,0);
18274 DIP("pld%s [r%u, #-%u]\n", bW ? "w" : "", rN, imm8);
18275 goto decode_success;
18276 }
18277
18278 if ((INSN0(15,4) & 0xFFD) == 0xF81 && INSN1(15,6) == 0x3C0) {
sewardj6d615ba2011-09-26 16:19:43 +000018279 /* FIXME: should this be unconditional? */
sewardj7f5a8412011-07-21 06:17:21 +000018280 /* PLD/PLDW register, encoding T1 */
18281 UInt rN = INSN0(3,0);
18282 UInt rM = INSN1(3,0);
18283 UInt bW = INSN0(5,5);
18284 UInt imm2 = INSN1(5,4);
18285 if (!isBadRegT(rM)) {
18286 DIP("pld%s [r%u, r%u, lsl %d]\n", bW ? "w" : "", rN, rM, imm2);
18287 goto decode_success;
18288 }
18289 /* fall through */
18290 }
18291
sewardjed75a682011-02-09 14:21:45 +000018292 /* -------------- read CP15 TPIDRURO register ------------- */
18293 /* mrc p15, 0, r0, c13, c0, 3 up to
18294 mrc p15, 0, r14, c13, c0, 3
18295 */
18296 /* I don't know whether this is really v7-only. But anyway, we
18297 have to support it since arm-linux uses TPIDRURO as a thread
18298 state register. */
sewardjed75a682011-02-09 14:21:45 +000018299 if ((INSN0(15,0) == 0xEE1D) && (INSN1(11,0) == 0x0F70)) {
sewardj6d615ba2011-09-26 16:19:43 +000018300 /* FIXME: should this be unconditional? */
sewardjed75a682011-02-09 14:21:45 +000018301 UInt rD = INSN1(15,12);
18302 if (!isBadRegT(rD)) {
18303 putIRegT(rD, IRExpr_Get(OFFB_TPIDRURO, Ity_I32), IRTemp_INVALID);
18304 DIP("mrc p15,0, r%u, c13, c0, 3\n", rD);
18305 goto decode_success;
18306 }
18307 /* fall through */
18308 }
18309
sewardj6d615ba2011-09-26 16:19:43 +000018310 /* ------------------- CLREX ------------------ */
18311 if (INSN0(15,0) == 0xF3BF && INSN1(15,0) == 0x8F2F) {
18312 /* AFAICS, this simply cancels a (all?) reservations made by a
18313 (any?) preceding LDREX(es). Arrange to hand it through to
18314 the back end. */
18315 mk_skip_over_T32_if_cond_is_false( condT );
18316 stmt( IRStmt_MBE(Imbe_CancelReservation) );
18317 DIP("clrex\n");
18318 goto decode_success;
18319 }
18320
sewardj646bc002010-10-11 18:57:10 +000018321 /* ------------------- NOP ------------------ */
18322 if (INSN0(15,0) == 0xF3AF && INSN1(15,0) == 0x8000) {
18323 DIP("nop\n");
18324 goto decode_success;
18325 }
18326
sewardjd2664472010-08-22 12:44:20 +000018327 /* ----------------------------------------------------------- */
18328 /* -- VFP (CP 10, CP 11) instructions (in Thumb mode) -- */
18329 /* ----------------------------------------------------------- */
18330
18331 if (INSN0(15,12) == BITS4(1,1,1,0)) {
18332 UInt insn28 = (INSN0(11,0) << 16) | INSN1(15,0);
18333 Bool ok_vfp = decode_CP10_CP11_instruction (
18334 &dres, insn28, condT, ARMCondAL/*bogus*/,
18335 True/*isT*/
18336 );
18337 if (ok_vfp)
18338 goto decode_success;
18339 }
18340
18341 /* ----------------------------------------------------------- */
18342 /* -- NEON instructions (in Thumb mode) -- */
18343 /* ----------------------------------------------------------- */
18344
sewardj1fce8de2010-09-09 07:27:24 +000018345 if (archinfo->hwcaps & VEX_HWCAPS_ARM_NEON) {
18346 UInt insn32 = (INSN0(15,0) << 16) | INSN1(15,0);
18347 Bool ok_neon = decode_NEON_instruction(
18348 &dres, insn32, condT, True/*isT*/
18349 );
18350 if (ok_neon)
18351 goto decode_success;
sewardjd2664472010-08-22 12:44:20 +000018352 }
18353
18354 /* ----------------------------------------------------------- */
sewardj1f139f52010-08-29 12:33:02 +000018355 /* -- v6 media instructions (in Thumb mode) -- */
18356 /* ----------------------------------------------------------- */
18357
18358 { UInt insn32 = (INSN0(15,0) << 16) | INSN1(15,0);
18359 Bool ok_v6m = decode_V6MEDIA_instruction(
18360 &dres, insn32, condT, ARMCondAL/*bogus*/,
18361 True/*isT*/
18362 );
18363 if (ok_v6m)
18364 goto decode_success;
18365 }
18366
18367 /* ----------------------------------------------------------- */
sewardjd2664472010-08-22 12:44:20 +000018368 /* -- Undecodable -- */
18369 /* ----------------------------------------------------------- */
18370
18371 goto decode_failure;
18372 /*NOTREACHED*/
18373
18374 decode_failure:
18375 /* All decode failures end up here. */
18376 vex_printf("disInstr(thumb): unhandled instruction: "
18377 "0x%04x 0x%04x\n", (UInt)insn0, (UInt)insn1);
18378
18379 /* Back up ITSTATE to the initial value for this instruction.
18380 If we don't do that, any subsequent restart of the instruction
18381 will restart with the wrong value. */
18382 put_ITSTATE(old_itstate);
18383 /* Tell the dispatcher that this insn cannot be decoded, and so has
18384 not been executed, and (is currently) the next to be executed.
18385 R15 should be up-to-date since it made so at the start of each
18386 insn, but nevertheless be paranoid and update it again right
18387 now. */
18388 vassert(0 == (guest_R15_curr_instr_notENC & 1));
18389 llPutIReg( 15, mkU32(guest_R15_curr_instr_notENC | 1) );
sewardjc6f970f2012-04-02 21:54:49 +000018390 dres.whatNext = Dis_StopHere;
18391 dres.jk_StopHere = Ijk_NoDecode;
18392 dres.len = 0;
sewardjd2664472010-08-22 12:44:20 +000018393 return dres;
18394
18395 decode_success:
18396 /* All decode successes end up here. */
sewardjc6f970f2012-04-02 21:54:49 +000018397 vassert(dres.len == 4 || dres.len == 2 || dres.len == 20);
18398 switch (dres.whatNext) {
18399 case Dis_Continue:
18400 llPutIReg(15, mkU32(dres.len + (guest_R15_curr_instr_notENC | 1)));
18401 break;
18402 case Dis_ResteerU:
18403 case Dis_ResteerC:
18404 llPutIReg(15, mkU32(dres.continueAt));
18405 break;
18406 case Dis_StopHere:
18407 break;
18408 default:
18409 vassert(0);
sewardjd2664472010-08-22 12:44:20 +000018410 }
sewardjc6f970f2012-04-02 21:54:49 +000018411
18412 DIP("\n");
sewardjd2664472010-08-22 12:44:20 +000018413
18414 return dres;
18415
18416# undef INSN0
18417# undef INSN1
18418}
18419
sewardjc2c87162004-11-25 13:07:02 +000018420#undef DIP
18421#undef DIS
18422
sewardj6c299f32009-12-31 18:00:12 +000018423
sewardj66c8c9b2011-07-04 16:58:40 +000018424/* Helper table for figuring out how many insns an IT insn
18425 conditionalises.
18426
18427 An ITxyz instruction of the format "1011 1111 firstcond mask"
18428 conditionalises some number of instructions, as indicated by the
18429 following table. A value of zero indicates the instruction is
18430 invalid in some way.
18431
18432 mask = 0 means this isn't an IT instruction
18433 fc = 15 (NV) means unpredictable
18434
18435 The line fc = 14 (AL) is different from the others; there are
18436 additional constraints in this case.
18437
18438 mask(0 .. 15)
18439 +--------------------------------
18440 fc(0 | 0 4 3 4 2 4 3 4 1 4 3 4 2 4 3 4
18441 .. | 0 4 3 4 2 4 3 4 1 4 3 4 2 4 3 4
18442 | 0 4 3 4 2 4 3 4 1 4 3 4 2 4 3 4
18443 | 0 4 3 4 2 4 3 4 1 4 3 4 2 4 3 4
18444 | 0 4 3 4 2 4 3 4 1 4 3 4 2 4 3 4
18445 | 0 4 3 4 2 4 3 4 1 4 3 4 2 4 3 4
18446 | 0 4 3 4 2 4 3 4 1 4 3 4 2 4 3 4
18447 | 0 4 3 4 2 4 3 4 1 4 3 4 2 4 3 4
18448 | 0 4 3 4 2 4 3 4 1 4 3 4 2 4 3 4
18449 | 0 4 3 4 2 4 3 4 1 4 3 4 2 4 3 4
18450 | 0 4 3 4 2 4 3 4 1 4 3 4 2 4 3 4
18451 | 0 4 3 4 2 4 3 4 1 4 3 4 2 4 3 4
18452 | 0 4 3 4 2 4 3 4 1 4 3 4 2 4 3 4
18453 | 0 4 3 4 2 4 3 4 1 4 3 4 2 4 3 4
18454 | 0 4 3 0 2 0 0 0 1 0 0 0 0 0 0 0
18455 15) | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
18456
18457 To be conservative with the analysis, let's rule out the mask = 0
18458 case, since that isn't an IT insn at all. But for all the other
18459 cases where the table contains zero, that means unpredictable, so
18460 let's say 4 to be conservative. Hence we have a safe value for any
18461 IT (mask,fc) pair that the CPU would actually identify as an IT
18462 instruction. The final table is
18463
18464 mask(0 .. 15)
18465 +--------------------------------
18466 fc(0 | 0 4 3 4 2 4 3 4 1 4 3 4 2 4 3 4
18467 .. | 0 4 3 4 2 4 3 4 1 4 3 4 2 4 3 4
18468 | 0 4 3 4 2 4 3 4 1 4 3 4 2 4 3 4
18469 | 0 4 3 4 2 4 3 4 1 4 3 4 2 4 3 4
18470 | 0 4 3 4 2 4 3 4 1 4 3 4 2 4 3 4
18471 | 0 4 3 4 2 4 3 4 1 4 3 4 2 4 3 4
18472 | 0 4 3 4 2 4 3 4 1 4 3 4 2 4 3 4
18473 | 0 4 3 4 2 4 3 4 1 4 3 4 2 4 3 4
18474 | 0 4 3 4 2 4 3 4 1 4 3 4 2 4 3 4
18475 | 0 4 3 4 2 4 3 4 1 4 3 4 2 4 3 4
18476 | 0 4 3 4 2 4 3 4 1 4 3 4 2 4 3 4
18477 | 0 4 3 4 2 4 3 4 1 4 3 4 2 4 3 4
18478 | 0 4 3 4 2 4 3 4 1 4 3 4 2 4 3 4
18479 | 0 4 3 4 2 4 3 4 1 4 3 4 2 4 3 4
18480 | 0 4 3 4 2 4 4 4 1 4 4 4 4 4 4 4
18481 15) | 0 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4
18482*/
18483static const UChar it_length_table[256]
18484 = { 0, 4, 3, 4, 2, 4, 3, 4, 1, 4, 3, 4, 2, 4, 3, 4,
18485 0, 4, 3, 4, 2, 4, 3, 4, 1, 4, 3, 4, 2, 4, 3, 4,
18486 0, 4, 3, 4, 2, 4, 3, 4, 1, 4, 3, 4, 2, 4, 3, 4,
18487 0, 4, 3, 4, 2, 4, 3, 4, 1, 4, 3, 4, 2, 4, 3, 4,
18488 0, 4, 3, 4, 2, 4, 3, 4, 1, 4, 3, 4, 2, 4, 3, 4,
18489 0, 4, 3, 4, 2, 4, 3, 4, 1, 4, 3, 4, 2, 4, 3, 4,
18490 0, 4, 3, 4, 2, 4, 3, 4, 1, 4, 3, 4, 2, 4, 3, 4,
18491 0, 4, 3, 4, 2, 4, 3, 4, 1, 4, 3, 4, 2, 4, 3, 4,
18492 0, 4, 3, 4, 2, 4, 3, 4, 1, 4, 3, 4, 2, 4, 3, 4,
18493 0, 4, 3, 4, 2, 4, 3, 4, 1, 4, 3, 4, 2, 4, 3, 4,
18494 0, 4, 3, 4, 2, 4, 3, 4, 1, 4, 3, 4, 2, 4, 3, 4,
18495 0, 4, 3, 4, 2, 4, 3, 4, 1, 4, 3, 4, 2, 4, 3, 4,
18496 0, 4, 3, 4, 2, 4, 3, 4, 1, 4, 3, 4, 2, 4, 3, 4,
18497 0, 4, 3, 4, 2, 4, 3, 4, 1, 4, 3, 4, 2, 4, 3, 4,
18498 0, 4, 3, 4, 2, 4, 4, 4, 1, 4, 4, 4, 4, 4, 4, 4,
18499 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4
18500 };
18501
18502
sewardj6c299f32009-12-31 18:00:12 +000018503/*------------------------------------------------------------*/
18504/*--- Top-level fn ---*/
18505/*------------------------------------------------------------*/
18506
18507/* Disassemble a single instruction into IR. The instruction
18508 is located in host memory at &guest_code[delta]. */
18509
18510DisResult disInstr_ARM ( IRSB* irsb_IN,
sewardj6c299f32009-12-31 18:00:12 +000018511 Bool (*resteerOkFn) ( void*, Addr64 ),
sewardj984d9b12010-01-15 10:53:21 +000018512 Bool resteerCisOk,
sewardj6c299f32009-12-31 18:00:12 +000018513 void* callback_opaque,
18514 UChar* guest_code_IN,
sewardjd2664472010-08-22 12:44:20 +000018515 Long delta_ENCODED,
18516 Addr64 guest_IP_ENCODED,
sewardj6c299f32009-12-31 18:00:12 +000018517 VexArch guest_arch,
18518 VexArchInfo* archinfo,
18519 VexAbiInfo* abiinfo,
18520 Bool host_bigendian_IN )
18521{
18522 DisResult dres;
sewardjd2664472010-08-22 12:44:20 +000018523 Bool isThumb = (Bool)(guest_IP_ENCODED & 1);
sewardj6c299f32009-12-31 18:00:12 +000018524
18525 /* Set globals (see top of this file) */
18526 vassert(guest_arch == VexArchARM);
sewardj6c299f32009-12-31 18:00:12 +000018527
sewardjd2664472010-08-22 12:44:20 +000018528 irsb = irsb_IN;
18529 host_is_bigendian = host_bigendian_IN;
18530 __curr_is_Thumb = isThumb;
18531
18532 if (isThumb) {
18533 guest_R15_curr_instr_notENC = (Addr32)guest_IP_ENCODED - 1;
18534 } else {
18535 guest_R15_curr_instr_notENC = (Addr32)guest_IP_ENCODED;
18536 }
18537
18538 if (isThumb) {
sewardjc6f970f2012-04-02 21:54:49 +000018539 dres = disInstr_THUMB_WRK ( resteerOkFn,
sewardjd2664472010-08-22 12:44:20 +000018540 resteerCisOk, callback_opaque,
18541 &guest_code_IN[delta_ENCODED - 1],
18542 archinfo, abiinfo );
18543 } else {
sewardjc6f970f2012-04-02 21:54:49 +000018544 dres = disInstr_ARM_WRK ( resteerOkFn,
sewardjd2664472010-08-22 12:44:20 +000018545 resteerCisOk, callback_opaque,
18546 &guest_code_IN[delta_ENCODED],
18547 archinfo, abiinfo );
18548 }
sewardj6c299f32009-12-31 18:00:12 +000018549
18550 return dres;
18551}
18552
18553/* Test program for the conversion of IRCmpF64Result values to VFP
18554 nzcv values. See handling of FCMPD et al above. */
18555/*
18556UInt foo ( UInt x )
18557{
18558 UInt ix = ((x >> 5) & 3) | (x & 1);
18559 UInt termL = (((((ix ^ 1) << 30) - 1) >> 29) + 1);
18560 UInt termR = (ix & (ix >> 1) & 1);
18561 return termL - termR;
18562}
18563
18564void try ( char* s, UInt ir, UInt req )
18565{
18566 UInt act = foo(ir);
18567 printf("%s 0x%02x -> req %d%d%d%d act %d%d%d%d (0x%x)\n",
18568 s, ir, (req >> 3) & 1, (req >> 2) & 1,
18569 (req >> 1) & 1, (req >> 0) & 1,
18570 (act >> 3) & 1, (act >> 2) & 1,
18571 (act >> 1) & 1, (act >> 0) & 1, act);
18572
18573}
18574
18575int main ( void )
18576{
18577 printf("\n");
18578 try("UN", 0x45, 0b0011);
18579 try("LT", 0x01, 0b1000);
18580 try("GT", 0x00, 0b0010);
18581 try("EQ", 0x40, 0b0110);
18582 printf("\n");
18583 return 0;
18584}
18585*/
18586
sewardjc2c87162004-11-25 13:07:02 +000018587/*--------------------------------------------------------------------*/
sewardjcef7d3e2009-07-02 12:21:59 +000018588/*--- end guest_arm_toIR.c ---*/
sewardjc2c87162004-11-25 13:07:02 +000018589/*--------------------------------------------------------------------*/