blob: edf42ba9d326377226787111c7f3054b6f15e3d0 [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
sewardj25e54732012-08-05 15:36:51 +000010 Copyright (C) 2004-2012 OpenWorks LLP
sewardj752f9062010-05-03 21:38:49 +000011 info@open-works.net
sewardj64733c42010-10-12 10:10:46 +000012
13 NEON support is
sewardj25e54732012-08-05 15:36:51 +000014 Copyright (C) 2010-2012 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
sewardj92001d42013-04-26 10:24:31 +000070 - pretty dodgy exception semantics for {LD,ST}Mxx and {LD,ST}RD.
71 These instructions are non-restartable in the case where the
72 transfer(s) fault.
sewardj6c299f32009-12-31 18:00:12 +000073
74 - SWP: the restart jump back is Ijk_Boring; it should be
75 Ijk_NoRedir but that's expensive. See comments on casLE() in
76 guest_x86_toIR.c.
sewardj6c299f32009-12-31 18:00:12 +000077*/
78
79/* "Special" instructions.
80
81 This instruction decoder can decode four special instructions
82 which mean nothing natively (are no-ops as far as regs/mem are
83 concerned) but have meaning for supporting Valgrind. A special
84 instruction is flagged by a 16-byte preamble:
85
86 E1A0C1EC E1A0C6EC E1A0CEEC E1A0C9EC
87 (mov r12, r12, ROR #3; mov r12, r12, ROR #13;
88 mov r12, r12, ROR #29; mov r12, r12, ROR #19)
89
90 Following that, one of the following 3 are allowed
91 (standard interpretation in parentheses):
92
93 E18AA00A (orr r10,r10,r10) R3 = client_request ( R4 )
94 E18BB00B (orr r11,r11,r11) R3 = guest_NRADDR
95 E18CC00C (orr r12,r12,r12) branch-and-link-to-noredir R4
sewardja0d8eb82012-09-03 21:48:42 +000096 E1899009 (orr r9,r9,r9) IR injection
sewardj6c299f32009-12-31 18:00:12 +000097
98 Any other bytes following the 16-byte preamble are illegal and
99 constitute a failure in instruction decoding. This all assumes
100 that the preamble will never occur except in specific code
101 fragments designed for Valgrind to catch.
102*/
103
104/* Translates ARM(v5) code to IR. */
sewardjc2c87162004-11-25 13:07:02 +0000105
106#include "libvex_basictypes.h"
107#include "libvex_ir.h"
108#include "libvex.h"
109#include "libvex_guest_arm.h"
110
sewardjcef7d3e2009-07-02 12:21:59 +0000111#include "main_util.h"
112#include "main_globals.h"
sewardj6c299f32009-12-31 18:00:12 +0000113#include "guest_generic_bb_to_IR.h"
sewardjcef7d3e2009-07-02 12:21:59 +0000114#include "guest_arm_defs.h"
sewardjc2c87162004-11-25 13:07:02 +0000115
116
117/*------------------------------------------------------------*/
118/*--- Globals ---*/
119/*------------------------------------------------------------*/
120
sewardj6c299f32009-12-31 18:00:12 +0000121/* These are set at the start of the translation of a instruction, so
122 that we don't have to pass them around endlessly. CONST means does
123 not change during translation of the instruction.
sewardjc2c87162004-11-25 13:07:02 +0000124*/
125
sewardj6c299f32009-12-31 18:00:12 +0000126/* CONST: is the host bigendian? This has to do with float vs double
127 register accesses on VFP, but it's complex and not properly thought
128 out. */
sewardjc2c87162004-11-25 13:07:02 +0000129static Bool host_is_bigendian;
130
sewardj6c299f32009-12-31 18:00:12 +0000131/* CONST: The guest address for the instruction currently being
sewardjd2664472010-08-22 12:44:20 +0000132 translated. This is the real, "decoded" address (not subject
133 to the CPSR.T kludge). */
134static Addr32 guest_R15_curr_instr_notENC;
135
136/* CONST, FOR ASSERTIONS ONLY. Indicates whether currently processed
137 insn is Thumb (True) or ARM (False). */
138static Bool __curr_is_Thumb;
sewardjc2c87162004-11-25 13:07:02 +0000139
sewardj6c299f32009-12-31 18:00:12 +0000140/* MOD: The IRSB* into which we're generating code. */
sewardjdd40fdf2006-12-24 02:20:24 +0000141static IRSB* irsb;
sewardjc2c87162004-11-25 13:07:02 +0000142
sewardj6c299f32009-12-31 18:00:12 +0000143/* These are to do with handling writes to r15. They are initially
144 set at the start of disInstr_ARM_WRK to indicate no update,
145 possibly updated during the routine, and examined again at the end.
146 If they have been set to indicate a r15 update then a jump is
147 generated. Note, "explicit" jumps (b, bx, etc) are generated
148 directly, not using this mechanism -- this is intended to handle
149 the implicit-style jumps resulting from (eg) assigning to r15 as
150 the result of insns we wouldn't normally consider branchy. */
151
152/* MOD. Initially False; set to True iff abovementioned handling is
153 required. */
154static Bool r15written;
155
156/* MOD. Initially IRTemp_INVALID. If the r15 branch to be generated
157 is conditional, this holds the gating IRTemp :: Ity_I32. If the
158 branch to be generated is unconditional, this remains
159 IRTemp_INVALID. */
160static IRTemp r15guard; /* :: Ity_I32, 0 or 1 */
161
162/* MOD. Initially Ijk_Boring. If an r15 branch is to be generated,
163 this holds the jump kind. */
164static IRTemp r15kind;
165
sewardjc2c87162004-11-25 13:07:02 +0000166
167/*------------------------------------------------------------*/
168/*--- Debugging output ---*/
169/*------------------------------------------------------------*/
170
171#define DIP(format, args...) \
172 if (vex_traceflags & VEX_TRACE_FE) \
173 vex_printf(format, ## args)
174
175#define DIS(buf, format, args...) \
176 if (vex_traceflags & VEX_TRACE_FE) \
177 vex_sprintf(buf, format, ## args)
178
sewardjd2664472010-08-22 12:44:20 +0000179#define ASSERT_IS_THUMB \
180 do { vassert(__curr_is_Thumb); } while (0)
181
182#define ASSERT_IS_ARM \
183 do { vassert(! __curr_is_Thumb); } while (0)
184
sewardjc2c87162004-11-25 13:07:02 +0000185
sewardj6c299f32009-12-31 18:00:12 +0000186/*------------------------------------------------------------*/
187/*--- Helper bits and pieces for deconstructing the ---*/
188/*--- arm insn stream. ---*/
189/*------------------------------------------------------------*/
190
191/* Do a little-endian load of a 32-bit word, regardless of the
192 endianness of the underlying host. */
sewardj80bea7b2010-01-09 11:43:21 +0000193static inline UInt getUIntLittleEndianly ( UChar* p )
sewardj6c299f32009-12-31 18:00:12 +0000194{
195 UInt w = 0;
196 w = (w << 8) | p[3];
197 w = (w << 8) | p[2];
198 w = (w << 8) | p[1];
199 w = (w << 8) | p[0];
200 return w;
201}
202
sewardjd2664472010-08-22 12:44:20 +0000203/* Do a little-endian load of a 16-bit word, regardless of the
204 endianness of the underlying host. */
205static inline UShort getUShortLittleEndianly ( UChar* p )
206{
207 UShort w = 0;
208 w = (w << 8) | p[1];
209 w = (w << 8) | p[0];
210 return w;
211}
212
sewardj6c299f32009-12-31 18:00:12 +0000213static UInt ROR32 ( UInt x, UInt sh ) {
214 vassert(sh >= 0 && sh < 32);
215 if (sh == 0)
216 return x;
217 else
218 return (x << (32-sh)) | (x >> sh);
219}
220
sewardjd2664472010-08-22 12:44:20 +0000221static Int popcount32 ( UInt x )
222{
223 Int res = 0, i;
224 for (i = 0; i < 32; i++) {
225 res += (x & 1);
226 x >>= 1;
227 }
228 return res;
229}
230
231static UInt setbit32 ( UInt x, Int ix, UInt b )
232{
233 UInt mask = 1 << ix;
234 x &= ~mask;
235 x |= ((b << ix) & mask);
236 return x;
237}
238
sewardj6c299f32009-12-31 18:00:12 +0000239#define BITS2(_b1,_b0) \
240 (((_b1) << 1) | (_b0))
241
242#define BITS3(_b2,_b1,_b0) \
243 (((_b2) << 2) | ((_b1) << 1) | (_b0))
244
245#define BITS4(_b3,_b2,_b1,_b0) \
246 (((_b3) << 3) | ((_b2) << 2) | ((_b1) << 1) | (_b0))
247
248#define BITS8(_b7,_b6,_b5,_b4,_b3,_b2,_b1,_b0) \
249 ((BITS4((_b7),(_b6),(_b5),(_b4)) << 4) \
250 | BITS4((_b3),(_b2),(_b1),(_b0)))
ceriona70a37b2004-12-03 18:54:08 +0000251
sewardjd2664472010-08-22 12:44:20 +0000252#define BITS5(_b4,_b3,_b2,_b1,_b0) \
253 (BITS8(0,0,0,(_b4),(_b3),(_b2),(_b1),(_b0)))
254#define BITS6(_b5,_b4,_b3,_b2,_b1,_b0) \
255 (BITS8(0,0,(_b5),(_b4),(_b3),(_b2),(_b1),(_b0)))
256#define BITS7(_b6,_b5,_b4,_b3,_b2,_b1,_b0) \
257 (BITS8(0,(_b6),(_b5),(_b4),(_b3),(_b2),(_b1),(_b0)))
258
259#define BITS9(_b8,_b7,_b6,_b5,_b4,_b3,_b2,_b1,_b0) \
260 (((_b8) << 8) \
261 | BITS8((_b7),(_b6),(_b5),(_b4),(_b3),(_b2),(_b1),(_b0)))
262
sewardj1f139f52010-08-29 12:33:02 +0000263#define BITS10(_b9,_b8,_b7,_b6,_b5,_b4,_b3,_b2,_b1,_b0) \
264 (((_b9) << 9) | ((_b8) << 8) \
265 | BITS8((_b7),(_b6),(_b5),(_b4),(_b3),(_b2),(_b1),(_b0)))
266
sewardj80bea7b2010-01-09 11:43:21 +0000267/* produces _uint[_bMax:_bMin] */
268#define SLICE_UInt(_uint,_bMax,_bMin) \
269 (( ((UInt)(_uint)) >> (_bMin)) \
sewardjd2664472010-08-22 12:44:20 +0000270 & (UInt)((1ULL << ((_bMax) - (_bMin) + 1)) - 1ULL))
sewardj80bea7b2010-01-09 11:43:21 +0000271
ceriona70a37b2004-12-03 18:54:08 +0000272
sewardjc2c87162004-11-25 13:07:02 +0000273/*------------------------------------------------------------*/
sewardj6c299f32009-12-31 18:00:12 +0000274/*--- Helper bits and pieces for creating IR fragments. ---*/
275/*------------------------------------------------------------*/
276
sewardjd2664472010-08-22 12:44:20 +0000277static IRExpr* mkU64 ( ULong i )
278{
279 return IRExpr_Const(IRConst_U64(i));
280}
281
sewardj6c299f32009-12-31 18:00:12 +0000282static IRExpr* mkU32 ( UInt i )
283{
284 return IRExpr_Const(IRConst_U32(i));
285}
286
287static IRExpr* mkU8 ( UInt i )
288{
289 vassert(i < 256);
290 return IRExpr_Const(IRConst_U8( (UChar)i ));
291}
292
293static IRExpr* mkexpr ( IRTemp tmp )
294{
295 return IRExpr_RdTmp(tmp);
296}
297
298static IRExpr* unop ( IROp op, IRExpr* a )
299{
300 return IRExpr_Unop(op, a);
301}
302
303static IRExpr* binop ( IROp op, IRExpr* a1, IRExpr* a2 )
304{
305 return IRExpr_Binop(op, a1, a2);
306}
307
308static IRExpr* triop ( IROp op, IRExpr* a1, IRExpr* a2, IRExpr* a3 )
309{
310 return IRExpr_Triop(op, a1, a2, a3);
311}
312
313static IRExpr* loadLE ( IRType ty, IRExpr* addr )
314{
315 return IRExpr_Load(Iend_LE, ty, addr);
316}
317
318/* Add a statement to the list held by "irbb". */
319static void stmt ( IRStmt* st )
320{
321 addStmtToIRSB( irsb, st );
322}
323
324static void assign ( IRTemp dst, IRExpr* e )
325{
326 stmt( IRStmt_WrTmp(dst, e) );
327}
328
329static void storeLE ( IRExpr* addr, IRExpr* data )
330{
331 stmt( IRStmt_Store(Iend_LE, addr, data) );
332}
333
sewardjcfe046e2013-01-17 14:23:53 +0000334static void storeGuardedLE ( IRExpr* addr, IRExpr* data, IRTemp guardT )
335{
336 if (guardT == IRTemp_INVALID) {
337 /* unconditional */
338 storeLE(addr, data);
339 } else {
340 stmt( IRStmt_StoreG(Iend_LE, addr, data,
341 binop(Iop_CmpNE32, mkexpr(guardT), mkU32(0))) );
342 }
343}
344
345static void loadGuardedLE ( IRTemp dst, IRLoadGOp cvt,
346 IRExpr* addr, IRExpr* alt,
347 IRTemp guardT /* :: Ity_I32, 0 or 1 */ )
348{
349 if (guardT == IRTemp_INVALID) {
350 /* unconditional */
351 IRExpr* loaded = NULL;
352 switch (cvt) {
353 case ILGop_Ident32:
354 loaded = loadLE(Ity_I32, addr); break;
355 case ILGop_8Uto32:
356 loaded = unop(Iop_8Uto32, loadLE(Ity_I8, addr)); break;
357 case ILGop_8Sto32:
358 loaded = unop(Iop_8Sto32, loadLE(Ity_I8, addr)); break;
359 case ILGop_16Uto32:
360 loaded = unop(Iop_16Uto32, loadLE(Ity_I16, addr)); break;
361 case ILGop_16Sto32:
362 loaded = unop(Iop_16Sto32, loadLE(Ity_I16, addr)); break;
363 default:
364 vassert(0);
365 }
366 vassert(loaded != NULL);
367 assign(dst, loaded);
368 } else {
369 /* Generate a guarded load into 'dst', but apply 'cvt' to the
370 loaded data before putting the data in 'dst'. If the load
371 does not take place, 'alt' is placed directly in 'dst'. */
372 stmt( IRStmt_LoadG(Iend_LE, cvt, dst, addr, alt,
373 binop(Iop_CmpNE32, mkexpr(guardT), mkU32(0))) );
374 }
375}
376
sewardj6c299f32009-12-31 18:00:12 +0000377/* Generate a new temporary of the given type. */
378static IRTemp newTemp ( IRType ty )
379{
380 vassert(isPlausibleIRType(ty));
381 return newIRTemp( irsb->tyenv, ty );
382}
383
384/* Produces a value in 0 .. 3, which is encoded as per the type
385 IRRoundingMode. */
386static IRExpr* /* :: Ity_I32 */ get_FAKE_roundingmode ( void )
387{
388 return mkU32(Irrm_NEAREST);
389}
390
391/* Generate an expression for SRC rotated right by ROT. */
392static IRExpr* genROR32( IRTemp src, Int rot )
393{
394 vassert(rot >= 0 && rot < 32);
395 if (rot == 0)
396 return mkexpr(src);
397 return
398 binop(Iop_Or32,
399 binop(Iop_Shl32, mkexpr(src), mkU8(32 - rot)),
400 binop(Iop_Shr32, mkexpr(src), mkU8(rot)));
401}
402
sewardjd2664472010-08-22 12:44:20 +0000403static IRExpr* mkU128 ( ULong i )
404{
405 return binop(Iop_64HLtoV128, mkU64(i), mkU64(i));
406}
407
408/* Generate a 4-aligned version of the given expression if
409 the given condition is true. Else return it unchanged. */
410static IRExpr* align4if ( IRExpr* e, Bool b )
411{
412 if (b)
413 return binop(Iop_And32, e, mkU32(~3));
414 else
415 return e;
416}
417
sewardj6c299f32009-12-31 18:00:12 +0000418
419/*------------------------------------------------------------*/
420/*--- Helpers for accessing guest registers. ---*/
sewardjc2c87162004-11-25 13:07:02 +0000421/*------------------------------------------------------------*/
422
423#define OFFB_R0 offsetof(VexGuestARMState,guest_R0)
cerionc60c01e2004-12-02 20:19:22 +0000424#define OFFB_R1 offsetof(VexGuestARMState,guest_R1)
425#define OFFB_R2 offsetof(VexGuestARMState,guest_R2)
426#define OFFB_R3 offsetof(VexGuestARMState,guest_R3)
427#define OFFB_R4 offsetof(VexGuestARMState,guest_R4)
428#define OFFB_R5 offsetof(VexGuestARMState,guest_R5)
429#define OFFB_R6 offsetof(VexGuestARMState,guest_R6)
430#define OFFB_R7 offsetof(VexGuestARMState,guest_R7)
431#define OFFB_R8 offsetof(VexGuestARMState,guest_R8)
432#define OFFB_R9 offsetof(VexGuestARMState,guest_R9)
433#define OFFB_R10 offsetof(VexGuestARMState,guest_R10)
434#define OFFB_R11 offsetof(VexGuestARMState,guest_R11)
435#define OFFB_R12 offsetof(VexGuestARMState,guest_R12)
436#define OFFB_R13 offsetof(VexGuestARMState,guest_R13)
437#define OFFB_R14 offsetof(VexGuestARMState,guest_R14)
sewardjd2664472010-08-22 12:44:20 +0000438#define OFFB_R15T offsetof(VexGuestARMState,guest_R15T)
sewardjc2c87162004-11-25 13:07:02 +0000439
cerionc60c01e2004-12-02 20:19:22 +0000440#define OFFB_CC_OP offsetof(VexGuestARMState,guest_CC_OP)
441#define OFFB_CC_DEP1 offsetof(VexGuestARMState,guest_CC_DEP1)
442#define OFFB_CC_DEP2 offsetof(VexGuestARMState,guest_CC_DEP2)
sewardj6c299f32009-12-31 18:00:12 +0000443#define OFFB_CC_NDEP offsetof(VexGuestARMState,guest_CC_NDEP)
444#define OFFB_NRADDR offsetof(VexGuestARMState,guest_NRADDR)
cerionc60c01e2004-12-02 20:19:22 +0000445
sewardj6c299f32009-12-31 18:00:12 +0000446#define OFFB_D0 offsetof(VexGuestARMState,guest_D0)
447#define OFFB_D1 offsetof(VexGuestARMState,guest_D1)
448#define OFFB_D2 offsetof(VexGuestARMState,guest_D2)
449#define OFFB_D3 offsetof(VexGuestARMState,guest_D3)
450#define OFFB_D4 offsetof(VexGuestARMState,guest_D4)
451#define OFFB_D5 offsetof(VexGuestARMState,guest_D5)
452#define OFFB_D6 offsetof(VexGuestARMState,guest_D6)
453#define OFFB_D7 offsetof(VexGuestARMState,guest_D7)
454#define OFFB_D8 offsetof(VexGuestARMState,guest_D8)
455#define OFFB_D9 offsetof(VexGuestARMState,guest_D9)
456#define OFFB_D10 offsetof(VexGuestARMState,guest_D10)
457#define OFFB_D11 offsetof(VexGuestARMState,guest_D11)
458#define OFFB_D12 offsetof(VexGuestARMState,guest_D12)
459#define OFFB_D13 offsetof(VexGuestARMState,guest_D13)
460#define OFFB_D14 offsetof(VexGuestARMState,guest_D14)
461#define OFFB_D15 offsetof(VexGuestARMState,guest_D15)
sewardjd2664472010-08-22 12:44:20 +0000462#define OFFB_D16 offsetof(VexGuestARMState,guest_D16)
463#define OFFB_D17 offsetof(VexGuestARMState,guest_D17)
464#define OFFB_D18 offsetof(VexGuestARMState,guest_D18)
465#define OFFB_D19 offsetof(VexGuestARMState,guest_D19)
466#define OFFB_D20 offsetof(VexGuestARMState,guest_D20)
467#define OFFB_D21 offsetof(VexGuestARMState,guest_D21)
468#define OFFB_D22 offsetof(VexGuestARMState,guest_D22)
469#define OFFB_D23 offsetof(VexGuestARMState,guest_D23)
470#define OFFB_D24 offsetof(VexGuestARMState,guest_D24)
471#define OFFB_D25 offsetof(VexGuestARMState,guest_D25)
472#define OFFB_D26 offsetof(VexGuestARMState,guest_D26)
473#define OFFB_D27 offsetof(VexGuestARMState,guest_D27)
474#define OFFB_D28 offsetof(VexGuestARMState,guest_D28)
475#define OFFB_D29 offsetof(VexGuestARMState,guest_D29)
476#define OFFB_D30 offsetof(VexGuestARMState,guest_D30)
477#define OFFB_D31 offsetof(VexGuestARMState,guest_D31)
sewardj6c299f32009-12-31 18:00:12 +0000478
479#define OFFB_FPSCR offsetof(VexGuestARMState,guest_FPSCR)
480#define OFFB_TPIDRURO offsetof(VexGuestARMState,guest_TPIDRURO)
sewardjd2664472010-08-22 12:44:20 +0000481#define OFFB_ITSTATE offsetof(VexGuestARMState,guest_ITSTATE)
482#define OFFB_QFLAG32 offsetof(VexGuestARMState,guest_QFLAG32)
sewardj1f139f52010-08-29 12:33:02 +0000483#define OFFB_GEFLAG0 offsetof(VexGuestARMState,guest_GEFLAG0)
484#define OFFB_GEFLAG1 offsetof(VexGuestARMState,guest_GEFLAG1)
485#define OFFB_GEFLAG2 offsetof(VexGuestARMState,guest_GEFLAG2)
486#define OFFB_GEFLAG3 offsetof(VexGuestARMState,guest_GEFLAG3)
cerionc60c01e2004-12-02 20:19:22 +0000487
sewardja0d8eb82012-09-03 21:48:42 +0000488#define OFFB_TISTART offsetof(VexGuestARMState,guest_TISTART)
489#define OFFB_TILEN offsetof(VexGuestARMState,guest_TILEN)
490
sewardjc2c87162004-11-25 13:07:02 +0000491
sewardj6c299f32009-12-31 18:00:12 +0000492/* ---------------- Integer registers ---------------- */
sewardjc2c87162004-11-25 13:07:02 +0000493
sewardj6c299f32009-12-31 18:00:12 +0000494static Int integerGuestRegOffset ( UInt iregNo )
sewardjc2c87162004-11-25 13:07:02 +0000495{
sewardj6c299f32009-12-31 18:00:12 +0000496 /* Do we care about endianness here? We do if sub-parts of integer
497 registers are accessed, but I don't think that ever happens on
498 ARM. */
499 switch (iregNo) {
500 case 0: return OFFB_R0;
501 case 1: return OFFB_R1;
502 case 2: return OFFB_R2;
503 case 3: return OFFB_R3;
504 case 4: return OFFB_R4;
505 case 5: return OFFB_R5;
506 case 6: return OFFB_R6;
507 case 7: return OFFB_R7;
508 case 8: return OFFB_R8;
509 case 9: return OFFB_R9;
510 case 10: return OFFB_R10;
511 case 11: return OFFB_R11;
512 case 12: return OFFB_R12;
513 case 13: return OFFB_R13;
514 case 14: return OFFB_R14;
sewardjd2664472010-08-22 12:44:20 +0000515 case 15: return OFFB_R15T;
sewardj6c299f32009-12-31 18:00:12 +0000516 default: vassert(0);
sewardjc2c87162004-11-25 13:07:02 +0000517 }
518}
519
sewardj6c299f32009-12-31 18:00:12 +0000520/* Plain ("low level") read from a reg; no +8 offset magic for r15. */
521static IRExpr* llGetIReg ( UInt iregNo )
522{
523 vassert(iregNo < 16);
524 return IRExpr_Get( integerGuestRegOffset(iregNo), Ity_I32 );
525}
526
sewardjd2664472010-08-22 12:44:20 +0000527/* Architected read from a reg in ARM mode. This automagically adds 8
528 to all reads of r15. */
529static IRExpr* getIRegA ( UInt iregNo )
sewardj6c299f32009-12-31 18:00:12 +0000530{
531 IRExpr* e;
sewardjd2664472010-08-22 12:44:20 +0000532 ASSERT_IS_ARM;
sewardj6c299f32009-12-31 18:00:12 +0000533 vassert(iregNo < 16);
534 if (iregNo == 15) {
535 /* If asked for r15, don't read the guest state value, as that
536 may not be up to date in the case where loop unrolling has
537 happened, because the first insn's write to the block is
538 omitted; hence in the 2nd and subsequent unrollings we don't
539 have a correct value in guest r15. Instead produce the
540 constant that we know would be produced at this point. */
sewardjd2664472010-08-22 12:44:20 +0000541 vassert(0 == (guest_R15_curr_instr_notENC & 3));
542 e = mkU32(guest_R15_curr_instr_notENC + 8);
543 } else {
544 e = IRExpr_Get( integerGuestRegOffset(iregNo), Ity_I32 );
545 }
546 return e;
547}
548
549/* Architected read from a reg in Thumb mode. This automagically adds
550 4 to all reads of r15. */
551static IRExpr* getIRegT ( UInt iregNo )
552{
553 IRExpr* e;
554 ASSERT_IS_THUMB;
555 vassert(iregNo < 16);
556 if (iregNo == 15) {
557 /* Ditto comment in getIReg. */
558 vassert(0 == (guest_R15_curr_instr_notENC & 1));
559 e = mkU32(guest_R15_curr_instr_notENC + 4);
sewardj6c299f32009-12-31 18:00:12 +0000560 } else {
561 e = IRExpr_Get( integerGuestRegOffset(iregNo), Ity_I32 );
562 }
563 return e;
564}
565
566/* Plain ("low level") write to a reg; no jump or alignment magic for
567 r15. */
568static void llPutIReg ( UInt iregNo, IRExpr* e )
569{
570 vassert(iregNo < 16);
571 vassert(typeOfIRExpr(irsb->tyenv, e) == Ity_I32);
572 stmt( IRStmt_Put(integerGuestRegOffset(iregNo), e) );
573}
574
sewardjd2664472010-08-22 12:44:20 +0000575/* Architected write to an integer register in ARM mode. If it is to
576 r15, record info so at the end of this insn's translation, a branch
577 to it can be made. Also handles conditional writes to the
578 register: if guardT == IRTemp_INVALID then the write is
579 unconditional. If writing r15, also 4-align it. */
580static void putIRegA ( UInt iregNo,
581 IRExpr* e,
582 IRTemp guardT /* :: Ity_I32, 0 or 1 */,
583 IRJumpKind jk /* if a jump is generated */ )
sewardj6c299f32009-12-31 18:00:12 +0000584{
585 /* if writing r15, force e to be 4-aligned. */
sewardjd2664472010-08-22 12:44:20 +0000586 // INTERWORKING FIXME. this needs to be relaxed so that
587 // puts caused by LDMxx which load r15 interwork right.
588 // but is no aligned too relaxed?
589 //if (iregNo == 15)
590 // e = binop(Iop_And32, e, mkU32(~3));
591 ASSERT_IS_ARM;
sewardj6c299f32009-12-31 18:00:12 +0000592 /* So, generate either an unconditional or a conditional write to
593 the reg. */
594 if (guardT == IRTemp_INVALID) {
595 /* unconditional write */
596 llPutIReg( iregNo, e );
597 } else {
598 llPutIReg( iregNo,
florian99dd03e2013-01-29 03:56:06 +0000599 IRExpr_ITE( binop(Iop_CmpNE32, mkexpr(guardT), mkU32(0)),
600 e, llGetIReg(iregNo) ));
sewardj6c299f32009-12-31 18:00:12 +0000601 }
602 if (iregNo == 15) {
603 // assert against competing r15 updates. Shouldn't
604 // happen; should be ruled out by the instr matching
605 // logic.
606 vassert(r15written == False);
607 vassert(r15guard == IRTemp_INVALID);
608 vassert(r15kind == Ijk_Boring);
609 r15written = True;
610 r15guard = guardT;
611 r15kind = jk;
612 }
613}
614
615
sewardjd2664472010-08-22 12:44:20 +0000616/* Architected write to an integer register in Thumb mode. Writes to
617 r15 are not allowed. Handles conditional writes to the register:
618 if guardT == IRTemp_INVALID then the write is unconditional. */
619static void putIRegT ( UInt iregNo,
620 IRExpr* e,
621 IRTemp guardT /* :: Ity_I32, 0 or 1 */ )
622{
623 /* So, generate either an unconditional or a conditional write to
624 the reg. */
625 ASSERT_IS_THUMB;
626 vassert(iregNo >= 0 && iregNo <= 14);
627 if (guardT == IRTemp_INVALID) {
628 /* unconditional write */
629 llPutIReg( iregNo, e );
630 } else {
631 llPutIReg( iregNo,
florian99dd03e2013-01-29 03:56:06 +0000632 IRExpr_ITE( binop(Iop_CmpNE32, mkexpr(guardT), mkU32(0)),
633 e, llGetIReg(iregNo) ));
sewardjd2664472010-08-22 12:44:20 +0000634 }
635}
636
637
638/* Thumb16 and Thumb32 only.
639 Returns true if reg is 13 or 15. Implements the BadReg
640 predicate in the ARM ARM. */
641static Bool isBadRegT ( UInt r )
642{
643 vassert(r <= 15);
644 ASSERT_IS_THUMB;
645 return r == 13 || r == 15;
646}
647
648
sewardj6c299f32009-12-31 18:00:12 +0000649/* ---------------- Double registers ---------------- */
650
651static Int doubleGuestRegOffset ( UInt dregNo )
652{
653 /* Do we care about endianness here? Probably do if we ever get
654 into the situation of dealing with the single-precision VFP
655 registers. */
656 switch (dregNo) {
657 case 0: return OFFB_D0;
658 case 1: return OFFB_D1;
659 case 2: return OFFB_D2;
660 case 3: return OFFB_D3;
661 case 4: return OFFB_D4;
662 case 5: return OFFB_D5;
663 case 6: return OFFB_D6;
664 case 7: return OFFB_D7;
665 case 8: return OFFB_D8;
666 case 9: return OFFB_D9;
667 case 10: return OFFB_D10;
668 case 11: return OFFB_D11;
669 case 12: return OFFB_D12;
670 case 13: return OFFB_D13;
671 case 14: return OFFB_D14;
672 case 15: return OFFB_D15;
sewardjd2664472010-08-22 12:44:20 +0000673 case 16: return OFFB_D16;
674 case 17: return OFFB_D17;
675 case 18: return OFFB_D18;
676 case 19: return OFFB_D19;
677 case 20: return OFFB_D20;
678 case 21: return OFFB_D21;
679 case 22: return OFFB_D22;
680 case 23: return OFFB_D23;
681 case 24: return OFFB_D24;
682 case 25: return OFFB_D25;
683 case 26: return OFFB_D26;
684 case 27: return OFFB_D27;
685 case 28: return OFFB_D28;
686 case 29: return OFFB_D29;
687 case 30: return OFFB_D30;
688 case 31: return OFFB_D31;
sewardj6c299f32009-12-31 18:00:12 +0000689 default: vassert(0);
690 }
691}
692
693/* Plain ("low level") read from a VFP Dreg. */
694static IRExpr* llGetDReg ( UInt dregNo )
695{
sewardjd2664472010-08-22 12:44:20 +0000696 vassert(dregNo < 32);
sewardj6c299f32009-12-31 18:00:12 +0000697 return IRExpr_Get( doubleGuestRegOffset(dregNo), Ity_F64 );
698}
699
700/* Architected read from a VFP Dreg. */
701static IRExpr* getDReg ( UInt dregNo ) {
702 return llGetDReg( dregNo );
703}
704
705/* Plain ("low level") write to a VFP Dreg. */
706static void llPutDReg ( UInt dregNo, IRExpr* e )
707{
sewardjd2664472010-08-22 12:44:20 +0000708 vassert(dregNo < 32);
sewardj6c299f32009-12-31 18:00:12 +0000709 vassert(typeOfIRExpr(irsb->tyenv, e) == Ity_F64);
710 stmt( IRStmt_Put(doubleGuestRegOffset(dregNo), e) );
711}
712
713/* Architected write to a VFP Dreg. Handles conditional writes to the
714 register: if guardT == IRTemp_INVALID then the write is
715 unconditional. */
716static void putDReg ( UInt dregNo,
717 IRExpr* e,
718 IRTemp guardT /* :: Ity_I32, 0 or 1 */)
719{
720 /* So, generate either an unconditional or a conditional write to
721 the reg. */
722 if (guardT == IRTemp_INVALID) {
723 /* unconditional write */
724 llPutDReg( dregNo, e );
725 } else {
726 llPutDReg( dregNo,
florian99dd03e2013-01-29 03:56:06 +0000727 IRExpr_ITE( binop(Iop_CmpNE32, mkexpr(guardT), mkU32(0)),
728 e, llGetDReg(dregNo) ));
sewardj6c299f32009-12-31 18:00:12 +0000729 }
730}
731
sewardjd2664472010-08-22 12:44:20 +0000732/* And now exactly the same stuff all over again, but this time
733 taking/returning I64 rather than F64, to support 64-bit Neon
734 ops. */
735
736/* Plain ("low level") read from a Neon Integer Dreg. */
737static IRExpr* llGetDRegI64 ( UInt dregNo )
738{
739 vassert(dregNo < 32);
740 return IRExpr_Get( doubleGuestRegOffset(dregNo), Ity_I64 );
741}
742
743/* Architected read from a Neon Integer Dreg. */
744static IRExpr* getDRegI64 ( UInt dregNo ) {
745 return llGetDRegI64( dregNo );
746}
747
748/* Plain ("low level") write to a Neon Integer Dreg. */
749static void llPutDRegI64 ( UInt dregNo, IRExpr* e )
750{
751 vassert(dregNo < 32);
752 vassert(typeOfIRExpr(irsb->tyenv, e) == Ity_I64);
753 stmt( IRStmt_Put(doubleGuestRegOffset(dregNo), e) );
754}
755
756/* Architected write to a Neon Integer Dreg. Handles conditional
757 writes to the register: if guardT == IRTemp_INVALID then the write
758 is unconditional. */
759static void putDRegI64 ( UInt dregNo,
760 IRExpr* e,
761 IRTemp guardT /* :: Ity_I32, 0 or 1 */)
762{
763 /* So, generate either an unconditional or a conditional write to
764 the reg. */
765 if (guardT == IRTemp_INVALID) {
766 /* unconditional write */
767 llPutDRegI64( dregNo, e );
768 } else {
769 llPutDRegI64( dregNo,
florian99dd03e2013-01-29 03:56:06 +0000770 IRExpr_ITE( binop(Iop_CmpNE32, mkexpr(guardT), mkU32(0)),
771 e, llGetDRegI64(dregNo) ));
sewardjd2664472010-08-22 12:44:20 +0000772 }
773}
774
775/* ---------------- Quad registers ---------------- */
776
777static Int quadGuestRegOffset ( UInt qregNo )
778{
779 /* Do we care about endianness here? Probably do if we ever get
780 into the situation of dealing with the 64 bit Neon registers. */
781 switch (qregNo) {
782 case 0: return OFFB_D0;
783 case 1: return OFFB_D2;
784 case 2: return OFFB_D4;
785 case 3: return OFFB_D6;
786 case 4: return OFFB_D8;
787 case 5: return OFFB_D10;
788 case 6: return OFFB_D12;
789 case 7: return OFFB_D14;
790 case 8: return OFFB_D16;
791 case 9: return OFFB_D18;
792 case 10: return OFFB_D20;
793 case 11: return OFFB_D22;
794 case 12: return OFFB_D24;
795 case 13: return OFFB_D26;
796 case 14: return OFFB_D28;
797 case 15: return OFFB_D30;
798 default: vassert(0);
799 }
800}
801
802/* Plain ("low level") read from a Neon Qreg. */
803static IRExpr* llGetQReg ( UInt qregNo )
804{
805 vassert(qregNo < 16);
806 return IRExpr_Get( quadGuestRegOffset(qregNo), Ity_V128 );
807}
808
809/* Architected read from a Neon Qreg. */
810static IRExpr* getQReg ( UInt qregNo ) {
811 return llGetQReg( qregNo );
812}
813
814/* Plain ("low level") write to a Neon Qreg. */
815static void llPutQReg ( UInt qregNo, IRExpr* e )
816{
817 vassert(qregNo < 16);
818 vassert(typeOfIRExpr(irsb->tyenv, e) == Ity_V128);
819 stmt( IRStmt_Put(quadGuestRegOffset(qregNo), e) );
820}
821
822/* Architected write to a Neon Qreg. Handles conditional writes to the
823 register: if guardT == IRTemp_INVALID then the write is
824 unconditional. */
825static void putQReg ( UInt qregNo,
826 IRExpr* e,
827 IRTemp guardT /* :: Ity_I32, 0 or 1 */)
828{
829 /* So, generate either an unconditional or a conditional write to
830 the reg. */
831 if (guardT == IRTemp_INVALID) {
832 /* unconditional write */
833 llPutQReg( qregNo, e );
834 } else {
835 llPutQReg( qregNo,
florian99dd03e2013-01-29 03:56:06 +0000836 IRExpr_ITE( binop(Iop_CmpNE32, mkexpr(guardT), mkU32(0)),
837 e, llGetQReg(qregNo) ));
sewardjd2664472010-08-22 12:44:20 +0000838 }
839}
840
sewardj6c299f32009-12-31 18:00:12 +0000841
842/* ---------------- Float registers ---------------- */
843
844static Int floatGuestRegOffset ( UInt fregNo )
845{
sewardjd2664472010-08-22 12:44:20 +0000846 /* Start with the offset of the containing double, and then correct
sewardj6c299f32009-12-31 18:00:12 +0000847 for endianness. Actually this is completely bogus and needs
848 careful thought. */
849 Int off;
850 vassert(fregNo < 32);
851 off = doubleGuestRegOffset(fregNo >> 1);
852 if (host_is_bigendian) {
853 vassert(0);
854 } else {
855 if (fregNo & 1)
856 off += 4;
857 }
858 return off;
859}
860
861/* Plain ("low level") read from a VFP Freg. */
862static IRExpr* llGetFReg ( UInt fregNo )
863{
864 vassert(fregNo < 32);
865 return IRExpr_Get( floatGuestRegOffset(fregNo), Ity_F32 );
866}
867
868/* Architected read from a VFP Freg. */
869static IRExpr* getFReg ( UInt fregNo ) {
870 return llGetFReg( fregNo );
871}
872
873/* Plain ("low level") write to a VFP Freg. */
874static void llPutFReg ( UInt fregNo, IRExpr* e )
875{
876 vassert(fregNo < 32);
877 vassert(typeOfIRExpr(irsb->tyenv, e) == Ity_F32);
878 stmt( IRStmt_Put(floatGuestRegOffset(fregNo), e) );
879}
880
881/* Architected write to a VFP Freg. Handles conditional writes to the
882 register: if guardT == IRTemp_INVALID then the write is
883 unconditional. */
884static void putFReg ( UInt fregNo,
885 IRExpr* e,
886 IRTemp guardT /* :: Ity_I32, 0 or 1 */)
887{
888 /* So, generate either an unconditional or a conditional write to
889 the reg. */
890 if (guardT == IRTemp_INVALID) {
891 /* unconditional write */
892 llPutFReg( fregNo, e );
893 } else {
894 llPutFReg( fregNo,
florian99dd03e2013-01-29 03:56:06 +0000895 IRExpr_ITE( binop(Iop_CmpNE32, mkexpr(guardT), mkU32(0)),
896 e, llGetFReg(fregNo) ));
sewardj6c299f32009-12-31 18:00:12 +0000897 }
898}
899
900
901/* ---------------- Misc registers ---------------- */
902
903static void putMiscReg32 ( UInt gsoffset,
904 IRExpr* e, /* :: Ity_I32 */
905 IRTemp guardT /* :: Ity_I32, 0 or 1 */)
906{
907 switch (gsoffset) {
sewardjd2664472010-08-22 12:44:20 +0000908 case OFFB_FPSCR: break;
909 case OFFB_QFLAG32: break;
sewardj1f139f52010-08-29 12:33:02 +0000910 case OFFB_GEFLAG0: break;
911 case OFFB_GEFLAG1: break;
912 case OFFB_GEFLAG2: break;
913 case OFFB_GEFLAG3: break;
sewardj6c299f32009-12-31 18:00:12 +0000914 default: vassert(0); /* awaiting more cases */
915 }
916 vassert(typeOfIRExpr(irsb->tyenv, e) == Ity_I32);
917
918 if (guardT == IRTemp_INVALID) {
919 /* unconditional write */
920 stmt(IRStmt_Put(gsoffset, e));
921 } else {
sewardjd2664472010-08-22 12:44:20 +0000922 stmt(IRStmt_Put(
923 gsoffset,
florian99dd03e2013-01-29 03:56:06 +0000924 IRExpr_ITE( binop(Iop_CmpNE32, mkexpr(guardT), mkU32(0)),
925 e, IRExpr_Get(gsoffset, Ity_I32) )
sewardjd2664472010-08-22 12:44:20 +0000926 ));
sewardj6c299f32009-12-31 18:00:12 +0000927 }
928}
929
sewardjd2664472010-08-22 12:44:20 +0000930static IRTemp get_ITSTATE ( void )
931{
932 ASSERT_IS_THUMB;
933 IRTemp t = newTemp(Ity_I32);
934 assign(t, IRExpr_Get( OFFB_ITSTATE, Ity_I32));
935 return t;
936}
937
938static void put_ITSTATE ( IRTemp t )
939{
940 ASSERT_IS_THUMB;
941 stmt( IRStmt_Put( OFFB_ITSTATE, mkexpr(t)) );
942}
943
944static IRTemp get_QFLAG32 ( void )
945{
946 IRTemp t = newTemp(Ity_I32);
947 assign(t, IRExpr_Get( OFFB_QFLAG32, Ity_I32));
948 return t;
949}
950
951static void put_QFLAG32 ( IRTemp t, IRTemp condT )
952{
953 putMiscReg32( OFFB_QFLAG32, mkexpr(t), condT );
954}
955
sewardj1f139f52010-08-29 12:33:02 +0000956/* Stickily set the 'Q' flag (APSR bit 27) of the APSR (Application Program
957 Status Register) to indicate that overflow or saturation occurred.
958 Nb: t must be zero to denote no saturation, and any nonzero
959 value to indicate saturation. */
960static void or_into_QFLAG32 ( IRExpr* e, IRTemp condT )
sewardjd2664472010-08-22 12:44:20 +0000961{
962 IRTemp old = get_QFLAG32();
963 IRTemp nyu = newTemp(Ity_I32);
sewardj1f139f52010-08-29 12:33:02 +0000964 assign(nyu, binop(Iop_Or32, mkexpr(old), e) );
sewardjd2664472010-08-22 12:44:20 +0000965 put_QFLAG32(nyu, condT);
966}
967
sewardj1f139f52010-08-29 12:33:02 +0000968/* Generate code to set APSR.GE[flagNo]. Each fn call sets 1 bit.
969 flagNo: which flag bit to set [3...0]
970 lowbits_to_ignore: 0 = look at all 32 bits
971 8 = look at top 24 bits only
972 16 = look at top 16 bits only
973 31 = look at the top bit only
974 e: input value to be evaluated.
975 The new value is taken from 'e' with the lowest 'lowbits_to_ignore'
976 masked out. If the resulting value is zero then the GE flag is
977 set to 0; any other value sets the flag to 1. */
978static void put_GEFLAG32 ( Int flagNo, /* 0, 1, 2 or 3 */
979 Int lowbits_to_ignore, /* 0, 8, 16 or 31 */
980 IRExpr* e, /* Ity_I32 */
981 IRTemp condT )
982{
983 vassert( flagNo >= 0 && flagNo <= 3 );
984 vassert( lowbits_to_ignore == 0 ||
985 lowbits_to_ignore == 8 ||
986 lowbits_to_ignore == 16 ||
987 lowbits_to_ignore == 31 );
988 IRTemp masked = newTemp(Ity_I32);
989 assign(masked, binop(Iop_Shr32, e, mkU8(lowbits_to_ignore)));
990
991 switch (flagNo) {
992 case 0: putMiscReg32(OFFB_GEFLAG0, mkexpr(masked), condT); break;
993 case 1: putMiscReg32(OFFB_GEFLAG1, mkexpr(masked), condT); break;
994 case 2: putMiscReg32(OFFB_GEFLAG2, mkexpr(masked), condT); break;
995 case 3: putMiscReg32(OFFB_GEFLAG3, mkexpr(masked), condT); break;
996 default: vassert(0);
997 }
998}
999
1000/* Return the (32-bit, zero-or-nonzero representation scheme) of
1001 the specified GE flag. */
1002static IRExpr* get_GEFLAG32( Int flagNo /* 0, 1, 2, 3 */ )
1003{
1004 switch (flagNo) {
1005 case 0: return IRExpr_Get( OFFB_GEFLAG0, Ity_I32 );
1006 case 1: return IRExpr_Get( OFFB_GEFLAG1, Ity_I32 );
1007 case 2: return IRExpr_Get( OFFB_GEFLAG2, Ity_I32 );
1008 case 3: return IRExpr_Get( OFFB_GEFLAG3, Ity_I32 );
1009 default: vassert(0);
1010 }
1011}
1012
sewardje2ea1762010-09-22 00:56:37 +00001013/* Set all 4 GE flags from the given 32-bit value as follows: GE 3 and
1014 2 are set from bit 31 of the value, and GE 1 and 0 are set from bit
1015 15 of the value. All other bits are ignored. */
1016static void set_GE_32_10_from_bits_31_15 ( IRTemp t32, IRTemp condT )
1017{
1018 IRTemp ge10 = newTemp(Ity_I32);
1019 IRTemp ge32 = newTemp(Ity_I32);
1020 assign(ge10, binop(Iop_And32, mkexpr(t32), mkU32(0x00008000)));
1021 assign(ge32, binop(Iop_And32, mkexpr(t32), mkU32(0x80000000)));
1022 put_GEFLAG32( 0, 0, mkexpr(ge10), condT );
1023 put_GEFLAG32( 1, 0, mkexpr(ge10), condT );
1024 put_GEFLAG32( 2, 0, mkexpr(ge32), condT );
1025 put_GEFLAG32( 3, 0, mkexpr(ge32), condT );
1026}
1027
1028
1029/* Set all 4 GE flags from the given 32-bit value as follows: GE 3
1030 from bit 31, GE 2 from bit 23, GE 1 from bit 15, and GE0 from
1031 bit 7. All other bits are ignored. */
1032static void set_GE_3_2_1_0_from_bits_31_23_15_7 ( IRTemp t32, IRTemp condT )
1033{
1034 IRTemp ge0 = newTemp(Ity_I32);
1035 IRTemp ge1 = newTemp(Ity_I32);
1036 IRTemp ge2 = newTemp(Ity_I32);
1037 IRTemp ge3 = newTemp(Ity_I32);
1038 assign(ge0, binop(Iop_And32, mkexpr(t32), mkU32(0x00000080)));
1039 assign(ge1, binop(Iop_And32, mkexpr(t32), mkU32(0x00008000)));
1040 assign(ge2, binop(Iop_And32, mkexpr(t32), mkU32(0x00800000)));
1041 assign(ge3, binop(Iop_And32, mkexpr(t32), mkU32(0x80000000)));
1042 put_GEFLAG32( 0, 0, mkexpr(ge0), condT );
1043 put_GEFLAG32( 1, 0, mkexpr(ge1), condT );
1044 put_GEFLAG32( 2, 0, mkexpr(ge2), condT );
1045 put_GEFLAG32( 3, 0, mkexpr(ge3), condT );
1046}
1047
sewardj6c299f32009-12-31 18:00:12 +00001048
1049/* ---------------- FPSCR stuff ---------------- */
1050
1051/* Generate IR to get hold of the rounding mode bits in FPSCR, and
1052 convert them to IR format. Bind the final result to the
1053 returned temp. */
1054static IRTemp /* :: Ity_I32 */ mk_get_IR_rounding_mode ( void )
1055{
1056 /* The ARMvfp encoding for rounding mode bits is:
1057 00 to nearest
1058 01 to +infinity
1059 10 to -infinity
1060 11 to zero
1061 We need to convert that to the IR encoding:
1062 00 to nearest (the default)
1063 10 to +infinity
1064 01 to -infinity
1065 11 to zero
1066 Which can be done by swapping bits 0 and 1.
1067 The rmode bits are at 23:22 in FPSCR.
1068 */
1069 IRTemp armEncd = newTemp(Ity_I32);
1070 IRTemp swapped = newTemp(Ity_I32);
1071 /* Fish FPSCR[23:22] out, and slide to bottom. Doesn't matter that
1072 we don't zero out bits 24 and above, since the assignment to
1073 'swapped' will mask them out anyway. */
1074 assign(armEncd,
1075 binop(Iop_Shr32, IRExpr_Get(OFFB_FPSCR, Ity_I32), mkU8(22)));
1076 /* Now swap them. */
1077 assign(swapped,
1078 binop(Iop_Or32,
1079 binop(Iop_And32,
1080 binop(Iop_Shl32, mkexpr(armEncd), mkU8(1)),
1081 mkU32(2)),
1082 binop(Iop_And32,
1083 binop(Iop_Shr32, mkexpr(armEncd), mkU8(1)),
1084 mkU32(1))
1085 ));
1086 return swapped;
1087}
1088
sewardjc2c87162004-11-25 13:07:02 +00001089
1090/*------------------------------------------------------------*/
sewardj6c299f32009-12-31 18:00:12 +00001091/*--- Helpers for flag handling and conditional insns ---*/
sewardjc2c87162004-11-25 13:07:02 +00001092/*------------------------------------------------------------*/
1093
florian55085f82012-11-21 00:36:55 +00001094static const HChar* name_ARMCondcode ( ARMCondcode cond )
sewardjc2c87162004-11-25 13:07:02 +00001095{
sewardj6c299f32009-12-31 18:00:12 +00001096 switch (cond) {
1097 case ARMCondEQ: return "{eq}";
1098 case ARMCondNE: return "{ne}";
1099 case ARMCondHS: return "{hs}"; // or 'cs'
1100 case ARMCondLO: return "{lo}"; // or 'cc'
1101 case ARMCondMI: return "{mi}";
1102 case ARMCondPL: return "{pl}";
1103 case ARMCondVS: return "{vs}";
1104 case ARMCondVC: return "{vc}";
1105 case ARMCondHI: return "{hi}";
1106 case ARMCondLS: return "{ls}";
1107 case ARMCondGE: return "{ge}";
1108 case ARMCondLT: return "{lt}";
1109 case ARMCondGT: return "{gt}";
1110 case ARMCondLE: return "{le}";
1111 case ARMCondAL: return ""; // {al}: is the default
1112 case ARMCondNV: return "{nv}";
1113 default: vpanic("name_ARMCondcode");
sewardjc2c87162004-11-25 13:07:02 +00001114 }
1115}
sewardj6c299f32009-12-31 18:00:12 +00001116/* and a handy shorthand for it */
florian55085f82012-11-21 00:36:55 +00001117static const HChar* nCC ( ARMCondcode cond ) {
sewardj6c299f32009-12-31 18:00:12 +00001118 return name_ARMCondcode(cond);
cerionf7da63d2004-12-09 19:04:57 +00001119}
1120
cerionc60c01e2004-12-02 20:19:22 +00001121
sewardjc2c87162004-11-25 13:07:02 +00001122/* Build IR to calculate some particular condition from stored
sewardj6c299f32009-12-31 18:00:12 +00001123 CC_OP/CC_DEP1/CC_DEP2/CC_NDEP. Returns an expression of type
1124 Ity_I32, suitable for narrowing. Although the return type is
sewardjd2664472010-08-22 12:44:20 +00001125 Ity_I32, the returned value is either 0 or 1. 'cond' must be
1126 :: Ity_I32 and must denote the condition to compute in
1127 bits 7:4, and be zero everywhere else.
cerionc60c01e2004-12-02 20:19:22 +00001128*/
sewardjd2664472010-08-22 12:44:20 +00001129static IRExpr* mk_armg_calculate_condition_dyn ( IRExpr* cond )
sewardjc2c87162004-11-25 13:07:02 +00001130{
sewardjd2664472010-08-22 12:44:20 +00001131 vassert(typeOfIRExpr(irsb->tyenv, cond) == Ity_I32);
sewardjbb8b3942011-05-01 18:47:10 +00001132 /* And 'cond' had better produce a value in which only bits 7:4 are
1133 nonzero. However, obviously we can't assert for that. */
sewardjd2664472010-08-22 12:44:20 +00001134
1135 /* So what we're constructing for the first argument is
sewardjbb8b3942011-05-01 18:47:10 +00001136 "(cond << 4) | stored-operation".
1137 However, as per comments above, 'cond' must be supplied
1138 pre-shifted to this function.
sewardjd2664472010-08-22 12:44:20 +00001139
1140 This pairing scheme requires that the ARM_CC_OP_ values all fit
1141 in 4 bits. Hence we are passing a (COND, OP) pair in the lowest
1142 8 bits of the first argument. */
sewardjc2c87162004-11-25 13:07:02 +00001143 IRExpr** args
sewardj6c299f32009-12-31 18:00:12 +00001144 = mkIRExprVec_4(
sewardjd2664472010-08-22 12:44:20 +00001145 binop(Iop_Or32, IRExpr_Get(OFFB_CC_OP, Ity_I32), cond),
sewardj6c299f32009-12-31 18:00:12 +00001146 IRExpr_Get(OFFB_CC_DEP1, Ity_I32),
1147 IRExpr_Get(OFFB_CC_DEP2, Ity_I32),
1148 IRExpr_Get(OFFB_CC_NDEP, Ity_I32)
1149 );
sewardjc2c87162004-11-25 13:07:02 +00001150 IRExpr* call
1151 = mkIRExprCCall(
1152 Ity_I32,
1153 0/*regparm*/,
cerionc60c01e2004-12-02 20:19:22 +00001154 "armg_calculate_condition", &armg_calculate_condition,
sewardjc2c87162004-11-25 13:07:02 +00001155 args
1156 );
cerionc60c01e2004-12-02 20:19:22 +00001157
sewardj6c299f32009-12-31 18:00:12 +00001158 /* Exclude the requested condition, OP and NDEP from definedness
sewardjc2c87162004-11-25 13:07:02 +00001159 checking. We're only interested in DEP1 and DEP2. */
sewardj6c299f32009-12-31 18:00:12 +00001160 call->Iex.CCall.cee->mcx_mask = (1<<0) | (1<<3);
1161 return call;
sewardjc2c87162004-11-25 13:07:02 +00001162}
1163
cerionc60c01e2004-12-02 20:19:22 +00001164
sewardjd2664472010-08-22 12:44:20 +00001165/* Build IR to calculate some particular condition from stored
1166 CC_OP/CC_DEP1/CC_DEP2/CC_NDEP. Returns an expression of type
1167 Ity_I32, suitable for narrowing. Although the return type is
1168 Ity_I32, the returned value is either 0 or 1.
1169*/
1170static IRExpr* mk_armg_calculate_condition ( ARMCondcode cond )
1171{
1172 /* First arg is "(cond << 4) | condition". This requires that the
1173 ARM_CC_OP_ values all fit in 4 bits. Hence we are passing a
1174 (COND, OP) pair in the lowest 8 bits of the first argument. */
1175 vassert(cond >= 0 && cond <= 15);
1176 return mk_armg_calculate_condition_dyn( mkU32(cond << 4) );
1177}
1178
1179
sewardj6c299f32009-12-31 18:00:12 +00001180/* Build IR to calculate just the carry flag from stored
1181 CC_OP/CC_DEP1/CC_DEP2/CC_NDEP. Returns an expression ::
1182 Ity_I32. */
1183static IRExpr* mk_armg_calculate_flag_c ( void )
sewardjc2c87162004-11-25 13:07:02 +00001184{
sewardj6c299f32009-12-31 18:00:12 +00001185 IRExpr** args
1186 = mkIRExprVec_4( IRExpr_Get(OFFB_CC_OP, Ity_I32),
1187 IRExpr_Get(OFFB_CC_DEP1, Ity_I32),
1188 IRExpr_Get(OFFB_CC_DEP2, Ity_I32),
1189 IRExpr_Get(OFFB_CC_NDEP, Ity_I32) );
1190 IRExpr* call
1191 = mkIRExprCCall(
1192 Ity_I32,
1193 0/*regparm*/,
1194 "armg_calculate_flag_c", &armg_calculate_flag_c,
1195 args
1196 );
1197 /* Exclude OP and NDEP from definedness checking. We're only
1198 interested in DEP1 and DEP2. */
1199 call->Iex.CCall.cee->mcx_mask = (1<<0) | (1<<3);
1200 return call;
sewardjc2c87162004-11-25 13:07:02 +00001201}
1202
sewardj6c299f32009-12-31 18:00:12 +00001203
1204/* Build IR to calculate just the overflow flag from stored
1205 CC_OP/CC_DEP1/CC_DEP2/CC_NDEP. Returns an expression ::
1206 Ity_I32. */
1207static IRExpr* mk_armg_calculate_flag_v ( void )
sewardjc2c87162004-11-25 13:07:02 +00001208{
sewardj6c299f32009-12-31 18:00:12 +00001209 IRExpr** args
1210 = mkIRExprVec_4( IRExpr_Get(OFFB_CC_OP, Ity_I32),
1211 IRExpr_Get(OFFB_CC_DEP1, Ity_I32),
1212 IRExpr_Get(OFFB_CC_DEP2, Ity_I32),
1213 IRExpr_Get(OFFB_CC_NDEP, Ity_I32) );
1214 IRExpr* call
1215 = mkIRExprCCall(
1216 Ity_I32,
1217 0/*regparm*/,
1218 "armg_calculate_flag_v", &armg_calculate_flag_v,
1219 args
1220 );
1221 /* Exclude OP and NDEP from definedness checking. We're only
1222 interested in DEP1 and DEP2. */
1223 call->Iex.CCall.cee->mcx_mask = (1<<0) | (1<<3);
1224 return call;
sewardjc2c87162004-11-25 13:07:02 +00001225}
1226
sewardj6c299f32009-12-31 18:00:12 +00001227
1228/* Build IR to calculate N Z C V in bits 31:28 of the
1229 returned word. */
1230static IRExpr* mk_armg_calculate_flags_nzcv ( void )
sewardjc2c87162004-11-25 13:07:02 +00001231{
sewardj6c299f32009-12-31 18:00:12 +00001232 IRExpr** args
1233 = mkIRExprVec_4( IRExpr_Get(OFFB_CC_OP, Ity_I32),
1234 IRExpr_Get(OFFB_CC_DEP1, Ity_I32),
1235 IRExpr_Get(OFFB_CC_DEP2, Ity_I32),
1236 IRExpr_Get(OFFB_CC_NDEP, Ity_I32) );
1237 IRExpr* call
1238 = mkIRExprCCall(
1239 Ity_I32,
1240 0/*regparm*/,
1241 "armg_calculate_flags_nzcv", &armg_calculate_flags_nzcv,
1242 args
1243 );
1244 /* Exclude OP and NDEP from definedness checking. We're only
1245 interested in DEP1 and DEP2. */
1246 call->Iex.CCall.cee->mcx_mask = (1<<0) | (1<<3);
1247 return call;
sewardjc2c87162004-11-25 13:07:02 +00001248}
1249
sewardjd2664472010-08-22 12:44:20 +00001250static IRExpr* mk_armg_calculate_flag_qc ( IRExpr* resL, IRExpr* resR, Bool Q )
1251{
1252 IRExpr** args1;
1253 IRExpr** args2;
1254 IRExpr *call1, *call2, *res;
1255
1256 if (Q) {
1257 args1 = mkIRExprVec_4 ( binop(Iop_GetElem32x4, resL, mkU8(0)),
1258 binop(Iop_GetElem32x4, resL, mkU8(1)),
1259 binop(Iop_GetElem32x4, resR, mkU8(0)),
1260 binop(Iop_GetElem32x4, resR, mkU8(1)) );
1261 args2 = mkIRExprVec_4 ( binop(Iop_GetElem32x4, resL, mkU8(2)),
1262 binop(Iop_GetElem32x4, resL, mkU8(3)),
1263 binop(Iop_GetElem32x4, resR, mkU8(2)),
1264 binop(Iop_GetElem32x4, resR, mkU8(3)) );
1265 } else {
1266 args1 = mkIRExprVec_4 ( binop(Iop_GetElem32x2, resL, mkU8(0)),
1267 binop(Iop_GetElem32x2, resL, mkU8(1)),
1268 binop(Iop_GetElem32x2, resR, mkU8(0)),
1269 binop(Iop_GetElem32x2, resR, mkU8(1)) );
1270 }
1271
sewardjd2664472010-08-22 12:44:20 +00001272 call1 = mkIRExprCCall(
1273 Ity_I32,
1274 0/*regparm*/,
1275 "armg_calculate_flag_qc", &armg_calculate_flag_qc,
1276 args1
1277 );
1278 if (Q) {
1279 call2 = mkIRExprCCall(
1280 Ity_I32,
1281 0/*regparm*/,
1282 "armg_calculate_flag_qc", &armg_calculate_flag_qc,
1283 args2
1284 );
1285 }
1286 if (Q) {
1287 res = binop(Iop_Or32, call1, call2);
1288 } else {
1289 res = call1;
1290 }
sewardjd2664472010-08-22 12:44:20 +00001291 return res;
1292}
1293
sewardj9dbbd7b2010-08-22 18:24:51 +00001294// FIXME: this is named wrongly .. looks like a sticky set of
1295// QC, not a write to it.
sewardjd2664472010-08-22 12:44:20 +00001296static void setFlag_QC ( IRExpr* resL, IRExpr* resR, Bool Q,
1297 IRTemp condT )
1298{
1299 putMiscReg32 (OFFB_FPSCR,
1300 binop(Iop_Or32,
1301 IRExpr_Get(OFFB_FPSCR, Ity_I32),
1302 binop(Iop_Shl32,
1303 mk_armg_calculate_flag_qc(resL, resR, Q),
1304 mkU8(27))),
1305 condT);
1306}
sewardjc2c87162004-11-25 13:07:02 +00001307
sewardj6c299f32009-12-31 18:00:12 +00001308/* Build IR to conditionally set the flags thunk. As with putIReg, if
1309 guard is IRTemp_INVALID then it's unconditional, else it holds a
1310 condition :: Ity_I32. */
sewardjc2c87162004-11-25 13:07:02 +00001311static
sewardj6c299f32009-12-31 18:00:12 +00001312void setFlags_D1_D2_ND ( UInt cc_op, IRTemp t_dep1,
1313 IRTemp t_dep2, IRTemp t_ndep,
1314 IRTemp guardT /* :: Ity_I32, 0 or 1 */ )
sewardjc2c87162004-11-25 13:07:02 +00001315{
sewardj6c299f32009-12-31 18:00:12 +00001316 vassert(typeOfIRTemp(irsb->tyenv, t_dep1 == Ity_I32));
1317 vassert(typeOfIRTemp(irsb->tyenv, t_dep2 == Ity_I32));
1318 vassert(typeOfIRTemp(irsb->tyenv, t_ndep == Ity_I32));
1319 vassert(cc_op >= ARMG_CC_OP_COPY && cc_op < ARMG_CC_OP_NUMBER);
1320 if (guardT == IRTemp_INVALID) {
1321 /* unconditional */
1322 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(cc_op) ));
1323 stmt( IRStmt_Put( OFFB_CC_DEP1, mkexpr(t_dep1) ));
1324 stmt( IRStmt_Put( OFFB_CC_DEP2, mkexpr(t_dep2) ));
1325 stmt( IRStmt_Put( OFFB_CC_NDEP, mkexpr(t_ndep) ));
sewardjc2c87162004-11-25 13:07:02 +00001326 } else {
sewardj6c299f32009-12-31 18:00:12 +00001327 /* conditional */
sewardj009230b2013-01-26 11:47:55 +00001328 IRTemp c1 = newTemp(Ity_I1);
1329 assign( c1, binop(Iop_CmpNE32, mkexpr(guardT), mkU32(0)) );
sewardj6c299f32009-12-31 18:00:12 +00001330 stmt( IRStmt_Put(
1331 OFFB_CC_OP,
florian99dd03e2013-01-29 03:56:06 +00001332 IRExpr_ITE( mkexpr(c1),
1333 mkU32(cc_op),
1334 IRExpr_Get(OFFB_CC_OP, Ity_I32) ) ));
sewardj6c299f32009-12-31 18:00:12 +00001335 stmt( IRStmt_Put(
1336 OFFB_CC_DEP1,
florian99dd03e2013-01-29 03:56:06 +00001337 IRExpr_ITE( mkexpr(c1),
1338 mkexpr(t_dep1),
1339 IRExpr_Get(OFFB_CC_DEP1, Ity_I32) ) ));
sewardj6c299f32009-12-31 18:00:12 +00001340 stmt( IRStmt_Put(
1341 OFFB_CC_DEP2,
florian99dd03e2013-01-29 03:56:06 +00001342 IRExpr_ITE( mkexpr(c1),
1343 mkexpr(t_dep2),
1344 IRExpr_Get(OFFB_CC_DEP2, Ity_I32) ) ));
sewardj6c299f32009-12-31 18:00:12 +00001345 stmt( IRStmt_Put(
1346 OFFB_CC_NDEP,
florian99dd03e2013-01-29 03:56:06 +00001347 IRExpr_ITE( mkexpr(c1),
1348 mkexpr(t_ndep),
1349 IRExpr_Get(OFFB_CC_NDEP, Ity_I32) ) ));
sewardjc2c87162004-11-25 13:07:02 +00001350 }
1351}
cerionc60c01e2004-12-02 20:19:22 +00001352
1353
sewardj6c299f32009-12-31 18:00:12 +00001354/* Minor variant of the above that sets NDEP to zero (if it
1355 sets it at all) */
1356static void setFlags_D1_D2 ( UInt cc_op, IRTemp t_dep1,
1357 IRTemp t_dep2,
1358 IRTemp guardT /* :: Ity_I32, 0 or 1 */ )
cerion397f9e52004-12-15 13:04:06 +00001359{
sewardj6c299f32009-12-31 18:00:12 +00001360 IRTemp z32 = newTemp(Ity_I32);
1361 assign( z32, mkU32(0) );
1362 setFlags_D1_D2_ND( cc_op, t_dep1, t_dep2, z32, guardT );
cerion397f9e52004-12-15 13:04:06 +00001363}
1364
1365
sewardj6c299f32009-12-31 18:00:12 +00001366/* Minor variant of the above that sets DEP2 to zero (if it
1367 sets it at all) */
1368static void setFlags_D1_ND ( UInt cc_op, IRTemp t_dep1,
1369 IRTemp t_ndep,
1370 IRTemp guardT /* :: Ity_I32, 0 or 1 */ )
cerion397f9e52004-12-15 13:04:06 +00001371{
sewardj6c299f32009-12-31 18:00:12 +00001372 IRTemp z32 = newTemp(Ity_I32);
1373 assign( z32, mkU32(0) );
1374 setFlags_D1_D2_ND( cc_op, t_dep1, z32, t_ndep, guardT );
cerion397f9e52004-12-15 13:04:06 +00001375}
1376
sewardj6c299f32009-12-31 18:00:12 +00001377
1378/* Minor variant of the above that sets DEP2 and NDEP to zero (if it
1379 sets them at all) */
1380static void setFlags_D1 ( UInt cc_op, IRTemp t_dep1,
1381 IRTemp guardT /* :: Ity_I32, 0 or 1 */ )
cerion397f9e52004-12-15 13:04:06 +00001382{
sewardj6c299f32009-12-31 18:00:12 +00001383 IRTemp z32 = newTemp(Ity_I32);
1384 assign( z32, mkU32(0) );
1385 setFlags_D1_D2_ND( cc_op, t_dep1, z32, z32, guardT );
cerion397f9e52004-12-15 13:04:06 +00001386}
cerionc60c01e2004-12-02 20:19:22 +00001387
1388
sewardjd2664472010-08-22 12:44:20 +00001389/* ARM only */
sewardj6c299f32009-12-31 18:00:12 +00001390/* Generate a side-exit to the next instruction, if the given guard
1391 expression :: Ity_I32 is 0 (note! the side exit is taken if the
1392 condition is false!) This is used to skip over conditional
1393 instructions which we can't generate straight-line code for, either
1394 because they are too complex or (more likely) they potentially
1395 generate exceptions.
cerionf7da63d2004-12-09 19:04:57 +00001396*/
sewardjd2664472010-08-22 12:44:20 +00001397static void mk_skip_over_A32_if_cond_is_false (
sewardj6c299f32009-12-31 18:00:12 +00001398 IRTemp guardT /* :: Ity_I32, 0 or 1 */
1399 )
cerionf7da63d2004-12-09 19:04:57 +00001400{
sewardjd2664472010-08-22 12:44:20 +00001401 ASSERT_IS_ARM;
sewardj6c299f32009-12-31 18:00:12 +00001402 vassert(guardT != IRTemp_INVALID);
sewardjd2664472010-08-22 12:44:20 +00001403 vassert(0 == (guest_R15_curr_instr_notENC & 3));
sewardj6c299f32009-12-31 18:00:12 +00001404 stmt( IRStmt_Exit(
1405 unop(Iop_Not1, unop(Iop_32to1, mkexpr(guardT))),
1406 Ijk_Boring,
sewardjc6f970f2012-04-02 21:54:49 +00001407 IRConst_U32(toUInt(guest_R15_curr_instr_notENC + 4)),
1408 OFFB_R15T
sewardj6c299f32009-12-31 18:00:12 +00001409 ));
1410}
1411
sewardjd2664472010-08-22 12:44:20 +00001412/* Thumb16 only */
1413/* ditto, but jump over a 16-bit thumb insn */
1414static void mk_skip_over_T16_if_cond_is_false (
1415 IRTemp guardT /* :: Ity_I32, 0 or 1 */
1416 )
1417{
1418 ASSERT_IS_THUMB;
1419 vassert(guardT != IRTemp_INVALID);
1420 vassert(0 == (guest_R15_curr_instr_notENC & 1));
1421 stmt( IRStmt_Exit(
1422 unop(Iop_Not1, unop(Iop_32to1, mkexpr(guardT))),
1423 Ijk_Boring,
sewardjc6f970f2012-04-02 21:54:49 +00001424 IRConst_U32(toUInt((guest_R15_curr_instr_notENC + 2) | 1)),
1425 OFFB_R15T
sewardjd2664472010-08-22 12:44:20 +00001426 ));
1427}
1428
1429
1430/* Thumb32 only */
1431/* ditto, but jump over a 32-bit thumb insn */
1432static void mk_skip_over_T32_if_cond_is_false (
1433 IRTemp guardT /* :: Ity_I32, 0 or 1 */
1434 )
1435{
1436 ASSERT_IS_THUMB;
1437 vassert(guardT != IRTemp_INVALID);
1438 vassert(0 == (guest_R15_curr_instr_notENC & 1));
1439 stmt( IRStmt_Exit(
1440 unop(Iop_Not1, unop(Iop_32to1, mkexpr(guardT))),
1441 Ijk_Boring,
sewardjc6f970f2012-04-02 21:54:49 +00001442 IRConst_U32(toUInt((guest_R15_curr_instr_notENC + 4) | 1)),
1443 OFFB_R15T
sewardjd2664472010-08-22 12:44:20 +00001444 ));
1445}
1446
1447
1448/* Thumb16 and Thumb32 only
1449 Generate a SIGILL followed by a restart of the current instruction
1450 if the given temp is nonzero. */
1451static void gen_SIGILL_T_if_nonzero ( IRTemp t /* :: Ity_I32 */ )
1452{
1453 ASSERT_IS_THUMB;
1454 vassert(t != IRTemp_INVALID);
1455 vassert(0 == (guest_R15_curr_instr_notENC & 1));
1456 stmt(
1457 IRStmt_Exit(
1458 binop(Iop_CmpNE32, mkexpr(t), mkU32(0)),
1459 Ijk_NoDecode,
sewardjc6f970f2012-04-02 21:54:49 +00001460 IRConst_U32(toUInt(guest_R15_curr_instr_notENC | 1)),
1461 OFFB_R15T
sewardjd2664472010-08-22 12:44:20 +00001462 )
1463 );
1464}
1465
1466
1467/* Inspect the old_itstate, and generate a SIGILL if it indicates that
1468 we are currently in an IT block and are not the last in the block.
1469 This also rolls back guest_ITSTATE to its old value before the exit
1470 and restores it to its new value afterwards. This is so that if
1471 the exit is taken, we have an up to date version of ITSTATE
1472 available. Without doing that, we have no hope of making precise
1473 exceptions work. */
1474static void gen_SIGILL_T_if_in_but_NLI_ITBlock (
1475 IRTemp old_itstate /* :: Ity_I32 */,
1476 IRTemp new_itstate /* :: Ity_I32 */
1477 )
1478{
1479 ASSERT_IS_THUMB;
1480 put_ITSTATE(old_itstate); // backout
1481 IRTemp guards_for_next3 = newTemp(Ity_I32);
1482 assign(guards_for_next3,
1483 binop(Iop_Shr32, mkexpr(old_itstate), mkU8(8)));
1484 gen_SIGILL_T_if_nonzero(guards_for_next3);
1485 put_ITSTATE(new_itstate); //restore
1486}
1487
1488
1489/* Simpler version of the above, which generates a SIGILL if
1490 we're anywhere within an IT block. */
1491static void gen_SIGILL_T_if_in_ITBlock (
1492 IRTemp old_itstate /* :: Ity_I32 */,
1493 IRTemp new_itstate /* :: Ity_I32 */
1494 )
1495{
1496 put_ITSTATE(old_itstate); // backout
1497 gen_SIGILL_T_if_nonzero(old_itstate);
1498 put_ITSTATE(new_itstate); //restore
1499}
1500
1501
sewardj1f139f52010-08-29 12:33:02 +00001502/* Generate an APSR value, from the NZCV thunk, and
1503 from QFLAG32 and GEFLAG0 .. GEFLAG3. */
1504static IRTemp synthesise_APSR ( void )
1505{
1506 IRTemp res1 = newTemp(Ity_I32);
1507 // Get NZCV
1508 assign( res1, mk_armg_calculate_flags_nzcv() );
1509 // OR in the Q value
1510 IRTemp res2 = newTemp(Ity_I32);
1511 assign(
1512 res2,
1513 binop(Iop_Or32,
1514 mkexpr(res1),
1515 binop(Iop_Shl32,
1516 unop(Iop_1Uto32,
1517 binop(Iop_CmpNE32,
1518 mkexpr(get_QFLAG32()),
1519 mkU32(0))),
1520 mkU8(ARMG_CC_SHIFT_Q)))
1521 );
1522 // OR in GE0 .. GE3
1523 IRExpr* ge0
1524 = unop(Iop_1Uto32, binop(Iop_CmpNE32, get_GEFLAG32(0), mkU32(0)));
1525 IRExpr* ge1
1526 = unop(Iop_1Uto32, binop(Iop_CmpNE32, get_GEFLAG32(1), mkU32(0)));
1527 IRExpr* ge2
1528 = unop(Iop_1Uto32, binop(Iop_CmpNE32, get_GEFLAG32(2), mkU32(0)));
1529 IRExpr* ge3
1530 = unop(Iop_1Uto32, binop(Iop_CmpNE32, get_GEFLAG32(3), mkU32(0)));
1531 IRTemp res3 = newTemp(Ity_I32);
1532 assign(res3,
1533 binop(Iop_Or32,
1534 mkexpr(res2),
1535 binop(Iop_Or32,
1536 binop(Iop_Or32,
1537 binop(Iop_Shl32, ge0, mkU8(16)),
1538 binop(Iop_Shl32, ge1, mkU8(17))),
1539 binop(Iop_Or32,
1540 binop(Iop_Shl32, ge2, mkU8(18)),
1541 binop(Iop_Shl32, ge3, mkU8(19))) )));
1542 return res3;
1543}
1544
1545
1546/* and the inverse transformation: given an APSR value,
1547 set the NZCV thunk, the Q flag, and the GE flags. */
1548static void desynthesise_APSR ( Bool write_nzcvq, Bool write_ge,
1549 IRTemp apsrT, IRTemp condT )
1550{
1551 vassert(write_nzcvq || write_ge);
1552 if (write_nzcvq) {
1553 // Do NZCV
1554 IRTemp immT = newTemp(Ity_I32);
1555 assign(immT, binop(Iop_And32, mkexpr(apsrT), mkU32(0xF0000000)) );
1556 setFlags_D1(ARMG_CC_OP_COPY, immT, condT);
1557 // Do Q
1558 IRTemp qnewT = newTemp(Ity_I32);
1559 assign(qnewT, binop(Iop_And32, mkexpr(apsrT), mkU32(ARMG_CC_MASK_Q)));
1560 put_QFLAG32(qnewT, condT);
1561 }
1562 if (write_ge) {
1563 // Do GE3..0
1564 put_GEFLAG32(0, 0, binop(Iop_And32, mkexpr(apsrT), mkU32(1<<16)),
1565 condT);
1566 put_GEFLAG32(1, 0, binop(Iop_And32, mkexpr(apsrT), mkU32(1<<17)),
1567 condT);
1568 put_GEFLAG32(2, 0, binop(Iop_And32, mkexpr(apsrT), mkU32(1<<18)),
1569 condT);
1570 put_GEFLAG32(3, 0, binop(Iop_And32, mkexpr(apsrT), mkU32(1<<19)),
1571 condT);
1572 }
1573}
1574
1575
1576/*------------------------------------------------------------*/
1577/*--- Helpers for saturation ---*/
1578/*------------------------------------------------------------*/
1579
1580/* FIXME: absolutely the only diff. between (a) armUnsignedSatQ and
1581 (b) armSignedSatQ is that in (a) the floor is set to 0, whereas in
1582 (b) the floor is computed from the value of imm5. these two fnsn
1583 should be commoned up. */
1584
1585/* UnsignedSatQ(): 'clamp' each value so it lies between 0 <= x <= (2^N)-1
1586 Optionally return flag resQ saying whether saturation occurred.
1587 See definition in manual, section A2.2.1, page 41
1588 (bits(N), boolean) UnsignedSatQ( integer i, integer N )
1589 {
1590 if ( i > (2^N)-1 ) { result = (2^N)-1; saturated = TRUE; }
1591 elsif ( i < 0 ) { result = 0; saturated = TRUE; }
1592 else { result = i; saturated = FALSE; }
1593 return ( result<N-1:0>, saturated );
1594 }
1595*/
1596static void armUnsignedSatQ( IRTemp* res, /* OUT - Ity_I32 */
1597 IRTemp* resQ, /* OUT - Ity_I32 */
1598 IRTemp regT, /* value to clamp - Ity_I32 */
1599 UInt imm5 ) /* saturation ceiling */
1600{
1601 UInt ceil = (1 << imm5) - 1; // (2^imm5)-1
1602 UInt floor = 0;
1603
sewardj009230b2013-01-26 11:47:55 +00001604 IRTemp nd0 = newTemp(Ity_I32);
1605 IRTemp nd1 = newTemp(Ity_I32);
1606 IRTemp nd2 = newTemp(Ity_I1);
1607 IRTemp nd3 = newTemp(Ity_I32);
1608 IRTemp nd4 = newTemp(Ity_I32);
1609 IRTemp nd5 = newTemp(Ity_I1);
1610 IRTemp nd6 = newTemp(Ity_I32);
sewardj1f139f52010-08-29 12:33:02 +00001611
sewardj009230b2013-01-26 11:47:55 +00001612 assign( nd0, mkexpr(regT) );
1613 assign( nd1, mkU32(ceil) );
1614 assign( nd2, binop( Iop_CmpLT32S, mkexpr(nd1), mkexpr(nd0) ) );
florian99dd03e2013-01-29 03:56:06 +00001615 assign( nd3, IRExpr_ITE(mkexpr(nd2), mkexpr(nd1), mkexpr(nd0)) );
sewardj009230b2013-01-26 11:47:55 +00001616 assign( nd4, mkU32(floor) );
1617 assign( nd5, binop( Iop_CmpLT32S, mkexpr(nd3), mkexpr(nd4) ) );
florian99dd03e2013-01-29 03:56:06 +00001618 assign( nd6, IRExpr_ITE(mkexpr(nd5), mkexpr(nd4), mkexpr(nd3)) );
sewardj009230b2013-01-26 11:47:55 +00001619 assign( *res, mkexpr(nd6) );
sewardj1f139f52010-08-29 12:33:02 +00001620
1621 /* if saturation occurred, then resQ is set to some nonzero value
1622 if sat did not occur, resQ is guaranteed to be zero. */
1623 if (resQ) {
1624 assign( *resQ, binop(Iop_Xor32, mkexpr(*res), mkexpr(regT)) );
1625 }
1626}
1627
1628
1629/* SignedSatQ(): 'clamp' each value so it lies between -2^N <= x <= (2^N) - 1
1630 Optionally return flag resQ saying whether saturation occurred.
1631 - see definition in manual, section A2.2.1, page 41
1632 (bits(N), boolean ) SignedSatQ( integer i, integer N )
1633 {
1634 if ( i > 2^(N-1) - 1 ) { result = 2^(N-1) - 1; saturated = TRUE; }
1635 elsif ( i < -(2^(N-1)) ) { result = -(2^(N-1)); saturated = FALSE; }
1636 else { result = i; saturated = FALSE; }
1637 return ( result[N-1:0], saturated );
1638 }
1639*/
1640static void armSignedSatQ( IRTemp regT, /* value to clamp - Ity_I32 */
1641 UInt imm5, /* saturation ceiling */
1642 IRTemp* res, /* OUT - Ity_I32 */
1643 IRTemp* resQ ) /* OUT - Ity_I32 */
1644{
1645 Int ceil = (1 << (imm5-1)) - 1; // (2^(imm5-1))-1
1646 Int floor = -(1 << (imm5-1)); // -(2^(imm5-1))
1647
sewardj009230b2013-01-26 11:47:55 +00001648 IRTemp nd0 = newTemp(Ity_I32);
1649 IRTemp nd1 = newTemp(Ity_I32);
1650 IRTemp nd2 = newTemp(Ity_I1);
1651 IRTemp nd3 = newTemp(Ity_I32);
1652 IRTemp nd4 = newTemp(Ity_I32);
1653 IRTemp nd5 = newTemp(Ity_I1);
1654 IRTemp nd6 = newTemp(Ity_I32);
sewardj1f139f52010-08-29 12:33:02 +00001655
sewardj009230b2013-01-26 11:47:55 +00001656 assign( nd0, mkexpr(regT) );
1657 assign( nd1, mkU32(ceil) );
1658 assign( nd2, binop( Iop_CmpLT32S, mkexpr(nd1), mkexpr(nd0) ) );
florian99dd03e2013-01-29 03:56:06 +00001659 assign( nd3, IRExpr_ITE( mkexpr(nd2), mkexpr(nd1), mkexpr(nd0) ) );
sewardj009230b2013-01-26 11:47:55 +00001660 assign( nd4, mkU32(floor) );
1661 assign( nd5, binop( Iop_CmpLT32S, mkexpr(nd3), mkexpr(nd4) ) );
florian99dd03e2013-01-29 03:56:06 +00001662 assign( nd6, IRExpr_ITE( mkexpr(nd5), mkexpr(nd4), mkexpr(nd3) ) );
sewardj009230b2013-01-26 11:47:55 +00001663 assign( *res, mkexpr(nd6) );
sewardj1f139f52010-08-29 12:33:02 +00001664
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,
florian99dd03e2013-01-29 03:56:06 +00001787 IRExpr_ITE(
sewardj009230b2013-01-26 11:47:55 +00001788 binop(Iop_CmpEQ32, mkexpr(amtT), mkU32(0)),
florian99dd03e2013-01-29 03:56:06 +00001789 mkexpr(oldC),
1790 IRExpr_ITE(
sewardj009230b2013-01-26 11:47:55 +00001791 binop(Iop_CmpLE32U, mkexpr(amtT), mkU32(32)),
sewardjbb8b3942011-05-01 18:47:10 +00001792 binop(Iop_And32,
1793 binop(Iop_Shr32,
1794 mkexpr(rMt),
1795 unop(Iop_32to8,
1796 binop(Iop_And32,
1797 binop(Iop_Sub32,
1798 mkU32(32),
1799 mkexpr(amtT)),
1800 mkU32(31)
1801 )
1802 )
1803 ),
1804 mkU32(1)
florian99dd03e2013-01-29 03:56:06 +00001805 ),
1806 mkU32(0)
1807 )
sewardjd2664472010-08-22 12:44:20 +00001808 )
1809 );
1810 }
1811 // (Rm << (Rs & 31)) & (((Rs & 255) - 32) >>s 31)
1812 // Lhs of the & limits the shift to 31 bits, so as to
1813 // give known IR semantics. Rhs of the & is all 1s for
1814 // Rs <= 31 and all 0s for Rs >= 32.
1815 assign(
1816 *res,
1817 binop(
1818 Iop_And32,
1819 binop(Iop_Shl32,
1820 mkexpr(rMt),
1821 unop(Iop_32to8,
1822 binop(Iop_And32, mkexpr(rSt), mkU32(31)))),
1823 binop(Iop_Sar32,
1824 binop(Iop_Sub32,
1825 mkexpr(amtT),
1826 mkU32(32)),
1827 mkU8(31))));
1828 DIS(buf, "r%u, LSL r%u", rM, rS);
1829}
1830
1831
1832static void compute_result_and_C_after_LSR_by_imm5 (
1833 /*OUT*/HChar* buf,
1834 IRTemp* res,
1835 IRTemp* newC,
1836 IRTemp rMt, UInt shift_amt, /* operands */
1837 UInt rM /* only for debug printing */
1838 )
1839{
1840 if (shift_amt == 0) {
1841 // conceptually a 32-bit shift, however:
1842 // res = 0
1843 // newC = Rm[31]
1844 if (newC) {
1845 assign( *newC,
1846 binop(Iop_And32,
1847 binop(Iop_Shr32, mkexpr(rMt), mkU8(31)),
1848 mkU32(1)));
1849 }
1850 assign( *res, mkU32(0) );
1851 DIS(buf, "r%u, LSR #0(a.k.a. 32)", rM);
1852 } else {
1853 // shift in range 1..31
1854 // res = Rm >>u shift_amt
1855 // newC = Rm[shift_amt - 1]
1856 vassert(shift_amt >= 1 && shift_amt <= 31);
1857 if (newC) {
1858 assign( *newC,
1859 binop(Iop_And32,
1860 binop(Iop_Shr32, mkexpr(rMt),
1861 mkU8(shift_amt - 1)),
1862 mkU32(1)));
1863 }
1864 assign( *res,
1865 binop(Iop_Shr32, mkexpr(rMt), mkU8(shift_amt)) );
1866 DIS(buf, "r%u, LSR #%u", rM, shift_amt);
1867 }
1868}
1869
1870
1871static void compute_result_and_C_after_LSR_by_reg (
1872 /*OUT*/HChar* buf,
1873 IRTemp* res,
1874 IRTemp* newC,
1875 IRTemp rMt, IRTemp rSt, /* operands */
1876 UInt rM, UInt rS /* only for debug printing */
1877 )
1878{
1879 // shift right in range 0 .. 255
1880 // amt = rS & 255
1881 // res = amt < 32 ? Rm >>u amt : 0
1882 // newC = amt == 0 ? oldC :
1883 // amt in 1..32 ? Rm[amt-1] : 0
1884 IRTemp amtT = newTemp(Ity_I32);
1885 assign( amtT, binop(Iop_And32, mkexpr(rSt), mkU32(255)) );
1886 if (newC) {
1887 /* mux0X(amt == 0,
1888 mux0X(amt < 32,
1889 0,
sewardjbb8b3942011-05-01 18:47:10 +00001890 Rm[(amt-1) & 31]),
sewardjd2664472010-08-22 12:44:20 +00001891 oldC)
1892 */
1893 IRTemp oldC = newTemp(Ity_I32);
1894 assign(oldC, mk_armg_calculate_flag_c() );
1895 assign(
1896 *newC,
florian99dd03e2013-01-29 03:56:06 +00001897 IRExpr_ITE(
1898 binop(Iop_CmpEQ32, mkexpr(amtT), mkU32(0)),
1899 mkexpr(oldC),
1900 IRExpr_ITE(
sewardj009230b2013-01-26 11:47:55 +00001901 binop(Iop_CmpLE32U, mkexpr(amtT), mkU32(32)),
sewardjbb8b3942011-05-01 18:47:10 +00001902 binop(Iop_And32,
1903 binop(Iop_Shr32,
1904 mkexpr(rMt),
1905 unop(Iop_32to8,
1906 binop(Iop_And32,
1907 binop(Iop_Sub32,
1908 mkexpr(amtT),
1909 mkU32(1)),
1910 mkU32(31)
1911 )
1912 )
1913 ),
1914 mkU32(1)
florian99dd03e2013-01-29 03:56:06 +00001915 ),
1916 mkU32(0)
1917 )
sewardjd2664472010-08-22 12:44:20 +00001918 )
1919 );
1920 }
1921 // (Rm >>u (Rs & 31)) & (((Rs & 255) - 32) >>s 31)
1922 // Lhs of the & limits the shift to 31 bits, so as to
1923 // give known IR semantics. Rhs of the & is all 1s for
1924 // Rs <= 31 and all 0s for Rs >= 32.
1925 assign(
1926 *res,
1927 binop(
1928 Iop_And32,
1929 binop(Iop_Shr32,
1930 mkexpr(rMt),
1931 unop(Iop_32to8,
1932 binop(Iop_And32, mkexpr(rSt), mkU32(31)))),
1933 binop(Iop_Sar32,
1934 binop(Iop_Sub32,
1935 mkexpr(amtT),
1936 mkU32(32)),
1937 mkU8(31))));
1938 DIS(buf, "r%u, LSR r%u", rM, rS);
1939}
1940
1941
1942static void compute_result_and_C_after_ASR_by_imm5 (
1943 /*OUT*/HChar* buf,
1944 IRTemp* res,
1945 IRTemp* newC,
1946 IRTemp rMt, UInt shift_amt, /* operands */
1947 UInt rM /* only for debug printing */
1948 )
1949{
1950 if (shift_amt == 0) {
1951 // conceptually a 32-bit shift, however:
1952 // res = Rm >>s 31
1953 // newC = Rm[31]
1954 if (newC) {
1955 assign( *newC,
1956 binop(Iop_And32,
1957 binop(Iop_Shr32, mkexpr(rMt), mkU8(31)),
1958 mkU32(1)));
1959 }
1960 assign( *res, binop(Iop_Sar32, mkexpr(rMt), mkU8(31)) );
1961 DIS(buf, "r%u, ASR #0(a.k.a. 32)", rM);
1962 } else {
1963 // shift in range 1..31
1964 // res = Rm >>s shift_amt
1965 // newC = Rm[shift_amt - 1]
1966 vassert(shift_amt >= 1 && shift_amt <= 31);
1967 if (newC) {
1968 assign( *newC,
1969 binop(Iop_And32,
1970 binop(Iop_Shr32, mkexpr(rMt),
1971 mkU8(shift_amt - 1)),
1972 mkU32(1)));
1973 }
1974 assign( *res,
1975 binop(Iop_Sar32, mkexpr(rMt), mkU8(shift_amt)) );
1976 DIS(buf, "r%u, ASR #%u", rM, shift_amt);
1977 }
1978}
1979
1980
1981static void compute_result_and_C_after_ASR_by_reg (
1982 /*OUT*/HChar* buf,
1983 IRTemp* res,
1984 IRTemp* newC,
1985 IRTemp rMt, IRTemp rSt, /* operands */
1986 UInt rM, UInt rS /* only for debug printing */
1987 )
1988{
1989 // arithmetic shift right in range 0 .. 255
1990 // amt = rS & 255
1991 // res = amt < 32 ? Rm >>s amt : Rm >>s 31
1992 // newC = amt == 0 ? oldC :
1993 // amt in 1..32 ? Rm[amt-1] : Rm[31]
1994 IRTemp amtT = newTemp(Ity_I32);
1995 assign( amtT, binop(Iop_And32, mkexpr(rSt), mkU32(255)) );
1996 if (newC) {
1997 /* mux0X(amt == 0,
1998 mux0X(amt < 32,
1999 Rm[31],
2000 Rm[(amt-1) & 31])
2001 oldC)
2002 */
2003 IRTemp oldC = newTemp(Ity_I32);
2004 assign(oldC, mk_armg_calculate_flag_c() );
2005 assign(
2006 *newC,
florian99dd03e2013-01-29 03:56:06 +00002007 IRExpr_ITE(
sewardj009230b2013-01-26 11:47:55 +00002008 binop(Iop_CmpEQ32, mkexpr(amtT), mkU32(0)),
florian99dd03e2013-01-29 03:56:06 +00002009 mkexpr(oldC),
2010 IRExpr_ITE(
sewardj009230b2013-01-26 11:47:55 +00002011 binop(Iop_CmpLE32U, mkexpr(amtT), mkU32(32)),
sewardjbb8b3942011-05-01 18:47:10 +00002012 binop(Iop_And32,
2013 binop(Iop_Shr32,
2014 mkexpr(rMt),
sewardjbb8b3942011-05-01 18:47:10 +00002015 unop(Iop_32to8,
2016 binop(Iop_And32,
2017 binop(Iop_Sub32,
2018 mkexpr(amtT),
2019 mkU32(1)),
2020 mkU32(31)
2021 )
2022 )
2023 ),
2024 mkU32(1)
florian99dd03e2013-01-29 03:56:06 +00002025 ),
2026 binop(Iop_And32,
2027 binop(Iop_Shr32,
2028 mkexpr(rMt),
2029 mkU8(31)
2030 ),
2031 mkU32(1)
sewardjd2664472010-08-22 12:44:20 +00002032 )
florian99dd03e2013-01-29 03:56:06 +00002033 )
sewardjd2664472010-08-22 12:44:20 +00002034 )
2035 );
2036 }
2037 // (Rm >>s (amt <u 32 ? amt : 31))
2038 assign(
2039 *res,
2040 binop(
2041 Iop_Sar32,
2042 mkexpr(rMt),
2043 unop(
2044 Iop_32to8,
florian99dd03e2013-01-29 03:56:06 +00002045 IRExpr_ITE(
sewardj009230b2013-01-26 11:47:55 +00002046 binop(Iop_CmpLT32U, mkexpr(amtT), mkU32(32)),
florian99dd03e2013-01-29 03:56:06 +00002047 mkexpr(amtT),
2048 mkU32(31)))));
sewardjd2664472010-08-22 12:44:20 +00002049 DIS(buf, "r%u, ASR r%u", rM, rS);
2050}
2051
2052
2053static void compute_result_and_C_after_ROR_by_reg (
2054 /*OUT*/HChar* buf,
2055 IRTemp* res,
2056 IRTemp* newC,
2057 IRTemp rMt, IRTemp rSt, /* operands */
2058 UInt rM, UInt rS /* only for debug printing */
2059 )
2060{
2061 // rotate right in range 0 .. 255
2062 // amt = rS & 255
2063 // shop = Rm `ror` (amt & 31)
2064 // shco = amt == 0 ? oldC : Rm[(amt-1) & 31]
2065 IRTemp amtT = newTemp(Ity_I32);
2066 assign( amtT, binop(Iop_And32, mkexpr(rSt), mkU32(255)) );
2067 IRTemp amt5T = newTemp(Ity_I32);
2068 assign( amt5T, binop(Iop_And32, mkexpr(rSt), mkU32(31)) );
2069 IRTemp oldC = newTemp(Ity_I32);
2070 assign(oldC, mk_armg_calculate_flag_c() );
2071 if (newC) {
2072 assign(
2073 *newC,
florian99dd03e2013-01-29 03:56:06 +00002074 IRExpr_ITE(
sewardj009230b2013-01-26 11:47:55 +00002075 binop(Iop_CmpNE32, mkexpr(amtT), mkU32(0)),
sewardjd2664472010-08-22 12:44:20 +00002076 binop(Iop_And32,
2077 binop(Iop_Shr32,
2078 mkexpr(rMt),
2079 unop(Iop_32to8,
2080 binop(Iop_And32,
2081 binop(Iop_Sub32,
2082 mkexpr(amtT),
2083 mkU32(1)
2084 ),
2085 mkU32(31)
2086 )
2087 )
2088 ),
2089 mkU32(1)
florian99dd03e2013-01-29 03:56:06 +00002090 ),
2091 mkexpr(oldC)
sewardjd2664472010-08-22 12:44:20 +00002092 )
2093 );
2094 }
2095 assign(
2096 *res,
florian99dd03e2013-01-29 03:56:06 +00002097 IRExpr_ITE(
sewardj009230b2013-01-26 11:47:55 +00002098 binop(Iop_CmpNE32, mkexpr(amt5T), mkU32(0)),
sewardjd2664472010-08-22 12:44:20 +00002099 binop(Iop_Or32,
2100 binop(Iop_Shr32,
2101 mkexpr(rMt),
2102 unop(Iop_32to8, mkexpr(amt5T))
2103 ),
2104 binop(Iop_Shl32,
2105 mkexpr(rMt),
2106 unop(Iop_32to8,
2107 binop(Iop_Sub32, mkU32(32), mkexpr(amt5T))
2108 )
2109 )
florian99dd03e2013-01-29 03:56:06 +00002110 ),
2111 mkexpr(rMt)
sewardjd2664472010-08-22 12:44:20 +00002112 )
2113 );
2114 DIS(buf, "r%u, ROR r#%u", rM, rS);
2115}
2116
2117
2118/* Generate an expression corresponding to the immediate-shift case of
2119 a shifter operand. This is used both for ARM and Thumb2.
2120
2121 Bind it to a temporary, and return that via *res. If newC is
2122 non-NULL, also compute a value for the shifter's carry out (in the
2123 LSB of a word), bind it to a temporary, and return that via *shco.
2124
2125 Generates GETs from the guest state and is therefore not safe to
2126 use once we start doing PUTs to it, for any given instruction.
2127
2128 'how' is encoded thusly:
2129 00b LSL, 01b LSR, 10b ASR, 11b ROR
2130 Most but not all ARM and Thumb integer insns use this encoding.
2131 Be careful to ensure the right value is passed here.
2132*/
2133static void compute_result_and_C_after_shift_by_imm5 (
2134 /*OUT*/HChar* buf,
2135 /*OUT*/IRTemp* res,
2136 /*OUT*/IRTemp* newC,
2137 IRTemp rMt, /* reg to shift */
2138 UInt how, /* what kind of shift */
2139 UInt shift_amt, /* shift amount (0..31) */
2140 UInt rM /* only for debug printing */
2141 )
2142{
2143 vassert(shift_amt < 32);
2144 vassert(how < 4);
2145
2146 switch (how) {
2147
2148 case 0:
2149 compute_result_and_C_after_LSL_by_imm5(
2150 buf, res, newC, rMt, shift_amt, rM
2151 );
2152 break;
2153
2154 case 1:
2155 compute_result_and_C_after_LSR_by_imm5(
2156 buf, res, newC, rMt, shift_amt, rM
2157 );
2158 break;
2159
2160 case 2:
2161 compute_result_and_C_after_ASR_by_imm5(
2162 buf, res, newC, rMt, shift_amt, rM
2163 );
2164 break;
2165
2166 case 3:
2167 if (shift_amt == 0) {
2168 IRTemp oldcT = newTemp(Ity_I32);
2169 // rotate right 1 bit through carry (?)
2170 // RRX -- described at ARM ARM A5-17
2171 // res = (oldC << 31) | (Rm >>u 1)
2172 // newC = Rm[0]
2173 if (newC) {
2174 assign( *newC,
2175 binop(Iop_And32, mkexpr(rMt), mkU32(1)));
2176 }
2177 assign( oldcT, mk_armg_calculate_flag_c() );
2178 assign( *res,
2179 binop(Iop_Or32,
2180 binop(Iop_Shl32, mkexpr(oldcT), mkU8(31)),
2181 binop(Iop_Shr32, mkexpr(rMt), mkU8(1))) );
2182 DIS(buf, "r%u, RRX", rM);
2183 } else {
2184 // rotate right in range 1..31
2185 // res = Rm `ror` shift_amt
2186 // newC = Rm[shift_amt - 1]
2187 vassert(shift_amt >= 1 && shift_amt <= 31);
2188 if (newC) {
2189 assign( *newC,
2190 binop(Iop_And32,
2191 binop(Iop_Shr32, mkexpr(rMt),
2192 mkU8(shift_amt - 1)),
2193 mkU32(1)));
2194 }
2195 assign( *res,
2196 binop(Iop_Or32,
2197 binop(Iop_Shr32, mkexpr(rMt), mkU8(shift_amt)),
2198 binop(Iop_Shl32, mkexpr(rMt),
2199 mkU8(32-shift_amt))));
2200 DIS(buf, "r%u, ROR #%u", rM, shift_amt);
2201 }
2202 break;
2203
2204 default:
2205 /*NOTREACHED*/
2206 vassert(0);
2207 }
2208}
2209
2210
2211/* Generate an expression corresponding to the register-shift case of
2212 a shifter operand. This is used both for ARM and Thumb2.
2213
2214 Bind it to a temporary, and return that via *res. If newC is
2215 non-NULL, also compute a value for the shifter's carry out (in the
2216 LSB of a word), bind it to a temporary, and return that via *shco.
2217
2218 Generates GETs from the guest state and is therefore not safe to
2219 use once we start doing PUTs to it, for any given instruction.
2220
2221 'how' is encoded thusly:
2222 00b LSL, 01b LSR, 10b ASR, 11b ROR
2223 Most but not all ARM and Thumb integer insns use this encoding.
2224 Be careful to ensure the right value is passed here.
2225*/
2226static void compute_result_and_C_after_shift_by_reg (
2227 /*OUT*/HChar* buf,
2228 /*OUT*/IRTemp* res,
2229 /*OUT*/IRTemp* newC,
2230 IRTemp rMt, /* reg to shift */
2231 UInt how, /* what kind of shift */
2232 IRTemp rSt, /* shift amount */
2233 UInt rM, /* only for debug printing */
2234 UInt rS /* only for debug printing */
2235 )
2236{
2237 vassert(how < 4);
2238 switch (how) {
2239 case 0: { /* LSL */
2240 compute_result_and_C_after_LSL_by_reg(
2241 buf, res, newC, rMt, rSt, rM, rS
2242 );
2243 break;
2244 }
2245 case 1: { /* LSR */
2246 compute_result_and_C_after_LSR_by_reg(
2247 buf, res, newC, rMt, rSt, rM, rS
2248 );
2249 break;
2250 }
2251 case 2: { /* ASR */
2252 compute_result_and_C_after_ASR_by_reg(
2253 buf, res, newC, rMt, rSt, rM, rS
2254 );
2255 break;
2256 }
2257 case 3: { /* ROR */
2258 compute_result_and_C_after_ROR_by_reg(
2259 buf, res, newC, rMt, rSt, rM, rS
2260 );
2261 break;
2262 }
2263 default:
2264 /*NOTREACHED*/
2265 vassert(0);
2266 }
2267}
2268
2269
sewardj6c299f32009-12-31 18:00:12 +00002270/* Generate an expression corresponding to a shifter_operand, bind it
2271 to a temporary, and return that via *shop. If shco is non-NULL,
2272 also compute a value for the shifter's carry out (in the LSB of a
2273 word), bind it to a temporary, and return that via *shco.
2274
2275 If for some reason we can't come up with a shifter operand (missing
2276 case? not really a shifter operand?) return False.
sewardjd2664472010-08-22 12:44:20 +00002277
2278 Generates GETs from the guest state and is therefore not safe to
2279 use once we start doing PUTs to it, for any given instruction.
2280
2281 For ARM insns only; not for Thumb.
sewardj6c299f32009-12-31 18:00:12 +00002282*/
2283static Bool mk_shifter_operand ( UInt insn_25, UInt insn_11_0,
2284 /*OUT*/IRTemp* shop,
2285 /*OUT*/IRTemp* shco,
2286 /*OUT*/HChar* buf )
2287{
2288 UInt insn_4 = (insn_11_0 >> 4) & 1;
2289 UInt insn_7 = (insn_11_0 >> 7) & 1;
2290 vassert(insn_25 <= 0x1);
2291 vassert(insn_11_0 <= 0xFFF);
2292
2293 vassert(shop && *shop == IRTemp_INVALID);
2294 *shop = newTemp(Ity_I32);
2295
2296 if (shco) {
2297 vassert(*shco == IRTemp_INVALID);
2298 *shco = newTemp(Ity_I32);
cerionb85e8bb2005-02-16 08:54:33 +00002299 }
cerion060c5422004-12-10 15:28:43 +00002300
sewardj6c299f32009-12-31 18:00:12 +00002301 /* 32-bit immediate */
2302
2303 if (insn_25 == 1) {
2304 /* immediate: (7:0) rotated right by 2 * (11:8) */
2305 UInt imm = (insn_11_0 >> 0) & 0xFF;
2306 UInt rot = 2 * ((insn_11_0 >> 8) & 0xF);
2307 vassert(rot <= 30);
2308 imm = ROR32(imm, rot);
2309 if (shco) {
2310 if (rot == 0) {
2311 assign( *shco, mk_armg_calculate_flag_c() );
2312 } else {
2313 assign( *shco, mkU32( (imm >> 31) & 1 ) );
2314 }
cerionb85e8bb2005-02-16 08:54:33 +00002315 }
sewardj6c299f32009-12-31 18:00:12 +00002316 DIS(buf, "#0x%x", imm);
2317 assign( *shop, mkU32(imm) );
2318 return True;
cerionb85e8bb2005-02-16 08:54:33 +00002319 }
sewardj6c299f32009-12-31 18:00:12 +00002320
2321 /* Shift/rotate by immediate */
2322
2323 if (insn_25 == 0 && insn_4 == 0) {
2324 /* Rm (3:0) shifted (6:5) by immediate (11:7) */
2325 UInt shift_amt = (insn_11_0 >> 7) & 0x1F;
2326 UInt rM = (insn_11_0 >> 0) & 0xF;
2327 UInt how = (insn_11_0 >> 5) & 3;
2328 /* how: 00 = Shl, 01 = Shr, 10 = Sar, 11 = Ror */
2329 IRTemp rMt = newTemp(Ity_I32);
sewardjd2664472010-08-22 12:44:20 +00002330 assign(rMt, getIRegA(rM));
sewardj6c299f32009-12-31 18:00:12 +00002331
2332 vassert(shift_amt <= 31);
2333
sewardjd2664472010-08-22 12:44:20 +00002334 compute_result_and_C_after_shift_by_imm5(
2335 buf, shop, shco, rMt, how, shift_amt, rM
2336 );
2337 return True;
cerionb85e8bb2005-02-16 08:54:33 +00002338 }
sewardj6c299f32009-12-31 18:00:12 +00002339
2340 /* Shift/rotate by register */
2341 if (insn_25 == 0 && insn_4 == 1) {
2342 /* Rm (3:0) shifted (6:5) by Rs (11:8) */
2343 UInt rM = (insn_11_0 >> 0) & 0xF;
2344 UInt rS = (insn_11_0 >> 8) & 0xF;
2345 UInt how = (insn_11_0 >> 5) & 3;
2346 /* how: 00 = Shl, 01 = Shr, 10 = Sar, 11 = Ror */
2347 IRTemp rMt = newTemp(Ity_I32);
2348 IRTemp rSt = newTemp(Ity_I32);
2349
2350 if (insn_7 == 1)
2351 return False; /* not really a shifter operand */
2352
sewardjd2664472010-08-22 12:44:20 +00002353 assign(rMt, getIRegA(rM));
2354 assign(rSt, getIRegA(rS));
sewardj6c299f32009-12-31 18:00:12 +00002355
sewardjd2664472010-08-22 12:44:20 +00002356 compute_result_and_C_after_shift_by_reg(
2357 buf, shop, shco, rMt, how, rSt, rM, rS
2358 );
2359 return True;
sewardj6c299f32009-12-31 18:00:12 +00002360 }
2361
2362 vex_printf("mk_shifter_operand(0x%x,0x%x)\n", insn_25, insn_11_0 );
2363 return False;
cerion060c5422004-12-10 15:28:43 +00002364}
cerionf7da63d2004-12-09 19:04:57 +00002365
2366
sewardjd2664472010-08-22 12:44:20 +00002367/* ARM only */
sewardj6c299f32009-12-31 18:00:12 +00002368static
2369IRExpr* mk_EA_reg_plusminus_imm12 ( UInt rN, UInt bU, UInt imm12,
2370 /*OUT*/HChar* buf )
cerion060c5422004-12-10 15:28:43 +00002371{
sewardj6c299f32009-12-31 18:00:12 +00002372 vassert(rN < 16);
2373 vassert(bU < 2);
2374 vassert(imm12 < 0x1000);
florian5df8ab02012-10-13 19:34:19 +00002375 HChar opChar = bU == 1 ? '+' : '-';
sewardj6c299f32009-12-31 18:00:12 +00002376 DIS(buf, "[r%u, #%c%u]", rN, opChar, imm12);
2377 return
2378 binop( (bU == 1 ? Iop_Add32 : Iop_Sub32),
sewardjd2664472010-08-22 12:44:20 +00002379 getIRegA(rN),
sewardj6c299f32009-12-31 18:00:12 +00002380 mkU32(imm12) );
cerionf7da63d2004-12-09 19:04:57 +00002381}
cerionc60c01e2004-12-02 20:19:22 +00002382
cerionc60c01e2004-12-02 20:19:22 +00002383
sewardjd2664472010-08-22 12:44:20 +00002384/* ARM only.
2385 NB: This is "DecodeImmShift" in newer versions of the the ARM ARM.
sewardj80bea7b2010-01-09 11:43:21 +00002386*/
ceriona70a37b2004-12-03 18:54:08 +00002387static
sewardj6c299f32009-12-31 18:00:12 +00002388IRExpr* mk_EA_reg_plusminus_shifted_reg ( UInt rN, UInt bU, UInt rM,
2389 UInt sh2, UInt imm5,
2390 /*OUT*/HChar* buf )
ceriona70a37b2004-12-03 18:54:08 +00002391{
sewardj6c299f32009-12-31 18:00:12 +00002392 vassert(rN < 16);
2393 vassert(bU < 2);
2394 vassert(rM < 16);
2395 vassert(sh2 < 4);
2396 vassert(imm5 < 32);
florian5df8ab02012-10-13 19:34:19 +00002397 HChar opChar = bU == 1 ? '+' : '-';
sewardj6c299f32009-12-31 18:00:12 +00002398 IRExpr* index = NULL;
2399 switch (sh2) {
2400 case 0: /* LSL */
2401 /* imm5 can be in the range 0 .. 31 inclusive. */
sewardjd2664472010-08-22 12:44:20 +00002402 index = binop(Iop_Shl32, getIRegA(rM), mkU8(imm5));
sewardj6c299f32009-12-31 18:00:12 +00002403 DIS(buf, "[r%u, %c r%u LSL #%u]", rN, opChar, rM, imm5);
cerionb85e8bb2005-02-16 08:54:33 +00002404 break;
sewardj6c299f32009-12-31 18:00:12 +00002405 case 1: /* LSR */
2406 if (imm5 == 0) {
2407 index = mkU32(0);
2408 vassert(0); // ATC
2409 } else {
sewardjd2664472010-08-22 12:44:20 +00002410 index = binop(Iop_Shr32, getIRegA(rM), mkU8(imm5));
sewardj6c299f32009-12-31 18:00:12 +00002411 }
2412 DIS(buf, "[r%u, %cr%u, LSR #%u]",
2413 rN, opChar, rM, imm5 == 0 ? 32 : imm5);
cerionb85e8bb2005-02-16 08:54:33 +00002414 break;
sewardj6c299f32009-12-31 18:00:12 +00002415 case 2: /* ASR */
2416 /* Doesn't this just mean that the behaviour with imm5 == 0
2417 is the same as if it had been 31 ? */
2418 if (imm5 == 0) {
sewardjd2664472010-08-22 12:44:20 +00002419 index = binop(Iop_Sar32, getIRegA(rM), mkU8(31));
sewardj6c299f32009-12-31 18:00:12 +00002420 vassert(0); // ATC
2421 } else {
sewardjd2664472010-08-22 12:44:20 +00002422 index = binop(Iop_Sar32, getIRegA(rM), mkU8(imm5));
sewardj6c299f32009-12-31 18:00:12 +00002423 }
2424 DIS(buf, "[r%u, %cr%u, ASR #%u]",
2425 rN, opChar, rM, imm5 == 0 ? 32 : imm5);
cerionb85e8bb2005-02-16 08:54:33 +00002426 break;
sewardj6c299f32009-12-31 18:00:12 +00002427 case 3: /* ROR or RRX */
2428 if (imm5 == 0) {
2429 IRTemp rmT = newTemp(Ity_I32);
2430 IRTemp cflagT = newTemp(Ity_I32);
sewardjd2664472010-08-22 12:44:20 +00002431 assign(rmT, getIRegA(rM));
sewardj80bea7b2010-01-09 11:43:21 +00002432 assign(cflagT, mk_armg_calculate_flag_c());
sewardj6c299f32009-12-31 18:00:12 +00002433 index = binop(Iop_Or32,
2434 binop(Iop_Shl32, mkexpr(cflagT), mkU8(31)),
2435 binop(Iop_Shr32, mkexpr(rmT), mkU8(1)));
sewardj6c299f32009-12-31 18:00:12 +00002436 DIS(buf, "[r%u, %cr%u, RRX]", rN, opChar, rM);
2437 } else {
2438 IRTemp rmT = newTemp(Ity_I32);
sewardjd2664472010-08-22 12:44:20 +00002439 assign(rmT, getIRegA(rM));
sewardj6c299f32009-12-31 18:00:12 +00002440 vassert(imm5 >= 1 && imm5 <= 31);
2441 index = binop(Iop_Or32,
2442 binop(Iop_Shl32, mkexpr(rmT), mkU8(32-imm5)),
2443 binop(Iop_Shr32, mkexpr(rmT), mkU8(imm5)));
sewardj6c299f32009-12-31 18:00:12 +00002444 DIS(buf, "[r%u, %cr%u, ROR #%u]", rN, opChar, rM, imm5);
2445 }
2446 break;
cerionb85e8bb2005-02-16 08:54:33 +00002447 default:
sewardj6c299f32009-12-31 18:00:12 +00002448 vassert(0);
cerionb85e8bb2005-02-16 08:54:33 +00002449 }
sewardj6c299f32009-12-31 18:00:12 +00002450 vassert(index);
2451 return binop(bU == 1 ? Iop_Add32 : Iop_Sub32,
sewardjd2664472010-08-22 12:44:20 +00002452 getIRegA(rN), index);
cerionc60c01e2004-12-02 20:19:22 +00002453}
2454
2455
sewardjd2664472010-08-22 12:44:20 +00002456/* ARM only */
sewardj6c299f32009-12-31 18:00:12 +00002457static
2458IRExpr* mk_EA_reg_plusminus_imm8 ( UInt rN, UInt bU, UInt imm8,
2459 /*OUT*/HChar* buf )
cerionf7da63d2004-12-09 19:04:57 +00002460{
sewardj6c299f32009-12-31 18:00:12 +00002461 vassert(rN < 16);
2462 vassert(bU < 2);
2463 vassert(imm8 < 0x100);
florian5df8ab02012-10-13 19:34:19 +00002464 HChar opChar = bU == 1 ? '+' : '-';
sewardj6c299f32009-12-31 18:00:12 +00002465 DIS(buf, "[r%u, #%c%u]", rN, opChar, imm8);
2466 return
2467 binop( (bU == 1 ? Iop_Add32 : Iop_Sub32),
sewardjd2664472010-08-22 12:44:20 +00002468 getIRegA(rN),
sewardj6c299f32009-12-31 18:00:12 +00002469 mkU32(imm8) );
cerionc60c01e2004-12-02 20:19:22 +00002470}
2471
2472
sewardjd2664472010-08-22 12:44:20 +00002473/* ARM only */
cerionc60c01e2004-12-02 20:19:22 +00002474static
sewardj6c299f32009-12-31 18:00:12 +00002475IRExpr* mk_EA_reg_plusminus_reg ( UInt rN, UInt bU, UInt rM,
2476 /*OUT*/HChar* buf )
cerionc60c01e2004-12-02 20:19:22 +00002477{
sewardj6c299f32009-12-31 18:00:12 +00002478 vassert(rN < 16);
2479 vassert(bU < 2);
2480 vassert(rM < 16);
florian5df8ab02012-10-13 19:34:19 +00002481 HChar opChar = bU == 1 ? '+' : '-';
sewardjd2664472010-08-22 12:44:20 +00002482 IRExpr* index = getIRegA(rM);
sewardj6c299f32009-12-31 18:00:12 +00002483 DIS(buf, "[r%u, %c r%u]", rN, opChar, rM);
2484 return binop(bU == 1 ? Iop_Add32 : Iop_Sub32,
sewardjd2664472010-08-22 12:44:20 +00002485 getIRegA(rN), index);
cerionc60c01e2004-12-02 20:19:22 +00002486}
2487
2488
sewardj6c299f32009-12-31 18:00:12 +00002489/* irRes :: Ity_I32 holds a floating point comparison result encoded
2490 as an IRCmpF64Result. Generate code to convert it to an
2491 ARM-encoded (N,Z,C,V) group in the lowest 4 bits of an I32 value.
2492 Assign a new temp to hold that value, and return the temp. */
ceriona70a37b2004-12-03 18:54:08 +00002493static
sewardj6c299f32009-12-31 18:00:12 +00002494IRTemp mk_convert_IRCmpF64Result_to_NZCV ( IRTemp irRes )
ceriona70a37b2004-12-03 18:54:08 +00002495{
sewardj6c299f32009-12-31 18:00:12 +00002496 IRTemp ix = newTemp(Ity_I32);
2497 IRTemp termL = newTemp(Ity_I32);
2498 IRTemp termR = newTemp(Ity_I32);
2499 IRTemp nzcv = newTemp(Ity_I32);
ceriona70a37b2004-12-03 18:54:08 +00002500
sewardj6c299f32009-12-31 18:00:12 +00002501 /* This is where the fun starts. We have to convert 'irRes' from
2502 an IR-convention return result (IRCmpF64Result) to an
2503 ARM-encoded (N,Z,C,V) group. The final result is in the bottom
2504 4 bits of 'nzcv'. */
2505 /* Map compare result from IR to ARM(nzcv) */
2506 /*
2507 FP cmp result | IR | ARM(nzcv)
2508 --------------------------------
2509 UN 0x45 0011
2510 LT 0x01 1000
2511 GT 0x00 0010
2512 EQ 0x40 0110
2513 */
2514 /* Now since you're probably wondering WTF ..
cerion397f9e52004-12-15 13:04:06 +00002515
sewardj6c299f32009-12-31 18:00:12 +00002516 ix fishes the useful bits out of the IR value, bits 6 and 0, and
2517 places them side by side, giving a number which is 0, 1, 2 or 3.
cerion397f9e52004-12-15 13:04:06 +00002518
sewardj6c299f32009-12-31 18:00:12 +00002519 termL is a sequence cooked up by GNU superopt. It converts ix
2520 into an almost correct value NZCV value (incredibly), except
2521 for the case of UN, where it produces 0100 instead of the
2522 required 0011.
cerion397f9e52004-12-15 13:04:06 +00002523
sewardj6c299f32009-12-31 18:00:12 +00002524 termR is therefore a correction term, also computed from ix. It
2525 is 1 in the UN case and 0 for LT, GT and UN. Hence, to get
2526 the final correct value, we subtract termR from termL.
ceriona70a37b2004-12-03 18:54:08 +00002527
sewardj6c299f32009-12-31 18:00:12 +00002528 Don't take my word for it. There's a test program at the bottom
2529 of this file, to try this out with.
2530 */
2531 assign(
2532 ix,
2533 binop(Iop_Or32,
2534 binop(Iop_And32,
2535 binop(Iop_Shr32, mkexpr(irRes), mkU8(5)),
2536 mkU32(3)),
2537 binop(Iop_And32, mkexpr(irRes), mkU32(1))));
ceriona70a37b2004-12-03 18:54:08 +00002538
sewardj6c299f32009-12-31 18:00:12 +00002539 assign(
2540 termL,
2541 binop(Iop_Add32,
2542 binop(Iop_Shr32,
2543 binop(Iop_Sub32,
2544 binop(Iop_Shl32,
2545 binop(Iop_Xor32, mkexpr(ix), mkU32(1)),
2546 mkU8(30)),
2547 mkU32(1)),
2548 mkU8(29)),
2549 mkU32(1)));
ceriona70a37b2004-12-03 18:54:08 +00002550
sewardj6c299f32009-12-31 18:00:12 +00002551 assign(
2552 termR,
2553 binop(Iop_And32,
2554 binop(Iop_And32,
2555 mkexpr(ix),
2556 binop(Iop_Shr32, mkexpr(ix), mkU8(1))),
2557 mkU32(1)));
cerionf7da63d2004-12-09 19:04:57 +00002558
sewardj6c299f32009-12-31 18:00:12 +00002559 assign(nzcv, binop(Iop_Sub32, mkexpr(termL), mkexpr(termR)));
2560 return nzcv;
ceriona70a37b2004-12-03 18:54:08 +00002561}
2562
2563
sewardjd2664472010-08-22 12:44:20 +00002564/* Thumb32 only. This is "ThumbExpandImm" in the ARM ARM. If
2565 updatesC is non-NULL, a boolean is written to it indicating whether
2566 or not the C flag is updated, as per ARM ARM "ThumbExpandImm_C".
2567*/
2568static UInt thumbExpandImm ( Bool* updatesC,
2569 UInt imm1, UInt imm3, UInt imm8 )
2570{
2571 vassert(imm1 < (1<<1));
2572 vassert(imm3 < (1<<3));
2573 vassert(imm8 < (1<<8));
2574 UInt i_imm3_a = (imm1 << 4) | (imm3 << 1) | ((imm8 >> 7) & 1);
2575 UInt abcdefgh = imm8;
2576 UInt lbcdefgh = imm8 | 0x80;
2577 if (updatesC) {
2578 *updatesC = i_imm3_a >= 8;
2579 }
2580 switch (i_imm3_a) {
2581 case 0: case 1:
2582 return abcdefgh;
2583 case 2: case 3:
2584 return (abcdefgh << 16) | abcdefgh;
2585 case 4: case 5:
2586 return (abcdefgh << 24) | (abcdefgh << 8);
2587 case 6: case 7:
2588 return (abcdefgh << 24) | (abcdefgh << 16)
2589 | (abcdefgh << 8) | abcdefgh;
2590 case 8 ... 31:
2591 return lbcdefgh << (32 - i_imm3_a);
2592 default:
2593 break;
2594 }
2595 /*NOTREACHED*/vassert(0);
2596}
2597
2598
2599/* Version of thumbExpandImm where we simply feed it the
2600 instruction halfwords (the lowest addressed one is I0). */
2601static UInt thumbExpandImm_from_I0_I1 ( Bool* updatesC,
2602 UShort i0s, UShort i1s )
2603{
2604 UInt i0 = (UInt)i0s;
2605 UInt i1 = (UInt)i1s;
2606 UInt imm1 = SLICE_UInt(i0,10,10);
2607 UInt imm3 = SLICE_UInt(i1,14,12);
2608 UInt imm8 = SLICE_UInt(i1,7,0);
2609 return thumbExpandImm(updatesC, imm1, imm3, imm8);
2610}
2611
2612
2613/* Thumb16 only. Given the firstcond and mask fields from an IT
2614 instruction, compute the 32-bit ITSTATE value implied, as described
2615 in libvex_guest_arm.h. This is not the ARM ARM representation.
2616 Also produce the t/e chars for the 2nd, 3rd, 4th insns, for
2617 disassembly printing. Returns False if firstcond or mask
2618 denote something invalid.
2619
2620 The number and conditions for the instructions to be
2621 conditionalised depend on firstcond and mask:
2622
2623 mask cond 1 cond 2 cond 3 cond 4
2624
2625 1000 fc[3:0]
2626 x100 fc[3:0] fc[3:1]:x
2627 xy10 fc[3:0] fc[3:1]:x fc[3:1]:y
2628 xyz1 fc[3:0] fc[3:1]:x fc[3:1]:y fc[3:1]:z
2629
2630 The condition fields are assembled in *itstate backwards (cond 4 at
2631 the top, cond 1 at the bottom). Conditions are << 4'd and then
2632 ^0xE'd, and those fields that correspond to instructions in the IT
2633 block are tagged with a 1 bit.
2634*/
2635static Bool compute_ITSTATE ( /*OUT*/UInt* itstate,
florian5df8ab02012-10-13 19:34:19 +00002636 /*OUT*/HChar* ch1,
2637 /*OUT*/HChar* ch2,
2638 /*OUT*/HChar* ch3,
sewardjd2664472010-08-22 12:44:20 +00002639 UInt firstcond, UInt mask )
2640{
2641 vassert(firstcond <= 0xF);
2642 vassert(mask <= 0xF);
2643 *itstate = 0;
2644 *ch1 = *ch2 = *ch3 = '.';
2645 if (mask == 0)
2646 return False; /* the logic below actually ensures this anyway,
2647 but clearer to make it explicit. */
2648 if (firstcond == 0xF)
2649 return False; /* NV is not allowed */
2650 if (firstcond == 0xE && popcount32(mask) != 1)
2651 return False; /* if firstcond is AL then all the rest must be too */
2652
2653 UInt m3 = (mask >> 3) & 1;
2654 UInt m2 = (mask >> 2) & 1;
2655 UInt m1 = (mask >> 1) & 1;
2656 UInt m0 = (mask >> 0) & 1;
2657
2658 UInt fc = (firstcond << 4) | 1/*in-IT-block*/;
2659 UInt ni = (0xE/*AL*/ << 4) | 0/*not-in-IT-block*/;
2660
2661 if (m3 == 1 && (m2|m1|m0) == 0) {
2662 *itstate = (ni << 24) | (ni << 16) | (ni << 8) | fc;
2663 *itstate ^= 0xE0E0E0E0;
2664 return True;
2665 }
2666
2667 if (m2 == 1 && (m1|m0) == 0) {
2668 *itstate = (ni << 24) | (ni << 16) | (setbit32(fc, 4, m3) << 8) | fc;
2669 *itstate ^= 0xE0E0E0E0;
2670 *ch1 = m3 == (firstcond & 1) ? 't' : 'e';
2671 return True;
2672 }
2673
2674 if (m1 == 1 && m0 == 0) {
2675 *itstate = (ni << 24)
2676 | (setbit32(fc, 4, m2) << 16)
2677 | (setbit32(fc, 4, m3) << 8) | fc;
2678 *itstate ^= 0xE0E0E0E0;
2679 *ch1 = m3 == (firstcond & 1) ? 't' : 'e';
2680 *ch2 = m2 == (firstcond & 1) ? 't' : 'e';
2681 return True;
2682 }
2683
2684 if (m0 == 1) {
2685 *itstate = (setbit32(fc, 4, m1) << 24)
2686 | (setbit32(fc, 4, m2) << 16)
2687 | (setbit32(fc, 4, m3) << 8) | fc;
2688 *itstate ^= 0xE0E0E0E0;
2689 *ch1 = m3 == (firstcond & 1) ? 't' : 'e';
2690 *ch2 = m2 == (firstcond & 1) ? 't' : 'e';
2691 *ch3 = m1 == (firstcond & 1) ? 't' : 'e';
2692 return True;
2693 }
2694
2695 return False;
2696}
2697
sewardj677e5af2010-09-02 21:02:47 +00002698
2699/* Generate IR to do 32-bit bit reversal, a la Hacker's Delight
2700 Chapter 7 Section 1. */
2701static IRTemp gen_BITREV ( IRTemp x0 )
2702{
2703 IRTemp x1 = newTemp(Ity_I32);
2704 IRTemp x2 = newTemp(Ity_I32);
2705 IRTemp x3 = newTemp(Ity_I32);
2706 IRTemp x4 = newTemp(Ity_I32);
2707 IRTemp x5 = newTemp(Ity_I32);
2708 UInt c1 = 0x55555555;
2709 UInt c2 = 0x33333333;
2710 UInt c3 = 0x0F0F0F0F;
2711 UInt c4 = 0x00FF00FF;
2712 UInt c5 = 0x0000FFFF;
2713 assign(x1,
2714 binop(Iop_Or32,
2715 binop(Iop_Shl32,
2716 binop(Iop_And32, mkexpr(x0), mkU32(c1)),
2717 mkU8(1)),
2718 binop(Iop_Shr32,
2719 binop(Iop_And32, mkexpr(x0), mkU32(~c1)),
2720 mkU8(1))
2721 ));
2722 assign(x2,
2723 binop(Iop_Or32,
2724 binop(Iop_Shl32,
2725 binop(Iop_And32, mkexpr(x1), mkU32(c2)),
2726 mkU8(2)),
2727 binop(Iop_Shr32,
2728 binop(Iop_And32, mkexpr(x1), mkU32(~c2)),
2729 mkU8(2))
2730 ));
2731 assign(x3,
2732 binop(Iop_Or32,
2733 binop(Iop_Shl32,
2734 binop(Iop_And32, mkexpr(x2), mkU32(c3)),
2735 mkU8(4)),
2736 binop(Iop_Shr32,
2737 binop(Iop_And32, mkexpr(x2), mkU32(~c3)),
2738 mkU8(4))
2739 ));
2740 assign(x4,
2741 binop(Iop_Or32,
2742 binop(Iop_Shl32,
2743 binop(Iop_And32, mkexpr(x3), mkU32(c4)),
2744 mkU8(8)),
2745 binop(Iop_Shr32,
2746 binop(Iop_And32, mkexpr(x3), mkU32(~c4)),
2747 mkU8(8))
2748 ));
2749 assign(x5,
2750 binop(Iop_Or32,
2751 binop(Iop_Shl32,
2752 binop(Iop_And32, mkexpr(x4), mkU32(c5)),
2753 mkU8(16)),
2754 binop(Iop_Shr32,
2755 binop(Iop_And32, mkexpr(x4), mkU32(~c5)),
2756 mkU8(16))
2757 ));
2758 return x5;
2759}
2760
2761
sewardj27312d32010-09-26 00:48:41 +00002762/* Generate IR to do rearrange bytes 3:2:1:0 in a word in to the order
2763 0:1:2:3 (aka byte-swap). */
2764static IRTemp gen_REV ( IRTemp arg )
2765{
2766 IRTemp res = newTemp(Ity_I32);
2767 assign(res,
2768 binop(Iop_Or32,
2769 binop(Iop_Shl32, mkexpr(arg), mkU8(24)),
2770 binop(Iop_Or32,
2771 binop(Iop_And32, binop(Iop_Shl32, mkexpr(arg), mkU8(8)),
2772 mkU32(0x00FF0000)),
2773 binop(Iop_Or32,
2774 binop(Iop_And32, binop(Iop_Shr32, mkexpr(arg), mkU8(8)),
2775 mkU32(0x0000FF00)),
2776 binop(Iop_And32, binop(Iop_Shr32, mkexpr(arg), mkU8(24)),
2777 mkU32(0x000000FF) )
2778 ))));
2779 return res;
2780}
2781
2782
2783/* Generate IR to do rearrange bytes 3:2:1:0 in a word in to the order
2784 2:3:0:1 (swap within lo and hi halves). */
2785static IRTemp gen_REV16 ( IRTemp arg )
2786{
2787 IRTemp res = newTemp(Ity_I32);
2788 assign(res,
2789 binop(Iop_Or32,
2790 binop(Iop_And32,
2791 binop(Iop_Shl32, mkexpr(arg), mkU8(8)),
2792 mkU32(0xFF00FF00)),
2793 binop(Iop_And32,
2794 binop(Iop_Shr32, mkexpr(arg), mkU8(8)),
2795 mkU32(0x00FF00FF))));
2796 return res;
2797}
2798
2799
sewardjd2664472010-08-22 12:44:20 +00002800/*------------------------------------------------------------*/
2801/*--- Advanced SIMD (NEON) instructions ---*/
2802/*------------------------------------------------------------*/
2803
2804/*------------------------------------------------------------*/
2805/*--- NEON data processing ---*/
2806/*------------------------------------------------------------*/
2807
2808/* For all NEON DP ops, we use the normal scheme to handle conditional
2809 writes to registers -- pass in condT and hand that on to the
2810 put*Reg functions. In ARM mode condT is always IRTemp_INVALID
2811 since NEON is unconditional for ARM. In Thumb mode condT is
2812 derived from the ITSTATE shift register in the normal way. */
2813
2814static
2815UInt get_neon_d_regno(UInt theInstr)
2816{
2817 UInt x = ((theInstr >> 18) & 0x10) | ((theInstr >> 12) & 0xF);
2818 if (theInstr & 0x40) {
2819 if (x & 1) {
2820 x = x + 0x100;
2821 } else {
2822 x = x >> 1;
2823 }
2824 }
2825 return x;
2826}
2827
2828static
2829UInt get_neon_n_regno(UInt theInstr)
2830{
2831 UInt x = ((theInstr >> 3) & 0x10) | ((theInstr >> 16) & 0xF);
2832 if (theInstr & 0x40) {
2833 if (x & 1) {
2834 x = x + 0x100;
2835 } else {
2836 x = x >> 1;
2837 }
2838 }
2839 return x;
2840}
2841
2842static
2843UInt get_neon_m_regno(UInt theInstr)
2844{
2845 UInt x = ((theInstr >> 1) & 0x10) | (theInstr & 0xF);
2846 if (theInstr & 0x40) {
2847 if (x & 1) {
2848 x = x + 0x100;
2849 } else {
2850 x = x >> 1;
2851 }
2852 }
2853 return x;
2854}
2855
2856static
2857Bool dis_neon_vext ( UInt theInstr, IRTemp condT )
2858{
2859 UInt dreg = get_neon_d_regno(theInstr);
2860 UInt mreg = get_neon_m_regno(theInstr);
2861 UInt nreg = get_neon_n_regno(theInstr);
2862 UInt imm4 = (theInstr >> 8) & 0xf;
2863 UInt Q = (theInstr >> 6) & 1;
2864 HChar reg_t = Q ? 'q' : 'd';
2865
2866 if (Q) {
2867 putQReg(dreg, triop(Iop_ExtractV128, getQReg(nreg),
2868 getQReg(mreg), mkU8(imm4)), condT);
2869 } else {
2870 putDRegI64(dreg, triop(Iop_Extract64, getDRegI64(nreg),
2871 getDRegI64(mreg), mkU8(imm4)), condT);
2872 }
2873 DIP("vext.8 %c%d, %c%d, %c%d, #%d\n", reg_t, dreg, reg_t, nreg,
2874 reg_t, mreg, imm4);
2875 return True;
2876}
2877
2878/* VTBL, VTBX */
2879static
2880Bool dis_neon_vtb ( UInt theInstr, IRTemp condT )
2881{
2882 UInt op = (theInstr >> 6) & 1;
2883 UInt dreg = get_neon_d_regno(theInstr & ~(1 << 6));
2884 UInt nreg = get_neon_n_regno(theInstr & ~(1 << 6));
2885 UInt mreg = get_neon_m_regno(theInstr & ~(1 << 6));
2886 UInt len = (theInstr >> 8) & 3;
2887 Int i;
2888 IROp cmp;
2889 ULong imm;
2890 IRTemp arg_l;
2891 IRTemp old_mask, new_mask, cur_mask;
2892 IRTemp old_res, new_res;
2893 IRTemp old_arg, new_arg;
2894
2895 if (dreg >= 0x100 || mreg >= 0x100 || nreg >= 0x100)
2896 return False;
2897 if (nreg + len > 31)
2898 return False;
2899
2900 cmp = Iop_CmpGT8Ux8;
2901
2902 old_mask = newTemp(Ity_I64);
2903 old_res = newTemp(Ity_I64);
2904 old_arg = newTemp(Ity_I64);
2905 assign(old_mask, mkU64(0));
2906 assign(old_res, mkU64(0));
2907 assign(old_arg, getDRegI64(mreg));
2908 imm = 8;
2909 imm = (imm << 8) | imm;
2910 imm = (imm << 16) | imm;
2911 imm = (imm << 32) | imm;
2912
2913 for (i = 0; i <= len; i++) {
2914 arg_l = newTemp(Ity_I64);
2915 new_mask = newTemp(Ity_I64);
2916 cur_mask = newTemp(Ity_I64);
2917 new_res = newTemp(Ity_I64);
2918 new_arg = newTemp(Ity_I64);
2919 assign(arg_l, getDRegI64(nreg+i));
2920 assign(new_arg, binop(Iop_Sub8x8, mkexpr(old_arg), mkU64(imm)));
2921 assign(cur_mask, binop(cmp, mkU64(imm), mkexpr(old_arg)));
2922 assign(new_mask, binop(Iop_Or64, mkexpr(old_mask), mkexpr(cur_mask)));
2923 assign(new_res, binop(Iop_Or64,
2924 mkexpr(old_res),
2925 binop(Iop_And64,
2926 binop(Iop_Perm8x8,
2927 mkexpr(arg_l),
2928 binop(Iop_And64,
2929 mkexpr(old_arg),
2930 mkexpr(cur_mask))),
2931 mkexpr(cur_mask))));
2932
2933 old_arg = new_arg;
2934 old_mask = new_mask;
2935 old_res = new_res;
2936 }
2937 if (op) {
2938 new_res = newTemp(Ity_I64);
2939 assign(new_res, binop(Iop_Or64,
2940 binop(Iop_And64,
2941 getDRegI64(dreg),
2942 unop(Iop_Not64, mkexpr(old_mask))),
2943 mkexpr(old_res)));
2944 old_res = new_res;
2945 }
2946
2947 putDRegI64(dreg, mkexpr(old_res), condT);
2948 DIP("vtb%c.8 d%u, {", op ? 'x' : 'l', dreg);
2949 if (len > 0) {
2950 DIP("d%u-d%u", nreg, nreg + len);
2951 } else {
2952 DIP("d%u", nreg);
2953 }
2954 DIP("}, d%u\n", mreg);
2955 return True;
2956}
2957
2958/* VDUP (scalar) */
2959static
2960Bool dis_neon_vdup ( UInt theInstr, IRTemp condT )
2961{
2962 UInt Q = (theInstr >> 6) & 1;
2963 UInt dreg = ((theInstr >> 18) & 0x10) | ((theInstr >> 12) & 0xF);
2964 UInt mreg = ((theInstr >> 1) & 0x10) | (theInstr & 0xF);
2965 UInt imm4 = (theInstr >> 16) & 0xF;
2966 UInt index;
2967 UInt size;
2968 IRTemp arg_m;
2969 IRTemp res;
2970 IROp op, op2;
2971
2972 if ((imm4 == 0) || (imm4 == 8))
2973 return False;
2974 if ((Q == 1) && ((dreg & 1) == 1))
2975 return False;
2976 if (Q)
2977 dreg >>= 1;
2978 arg_m = newTemp(Ity_I64);
2979 assign(arg_m, getDRegI64(mreg));
2980 if (Q)
2981 res = newTemp(Ity_V128);
2982 else
2983 res = newTemp(Ity_I64);
2984 if ((imm4 & 1) == 1) {
2985 op = Q ? Iop_Dup8x16 : Iop_Dup8x8;
2986 op2 = Iop_GetElem8x8;
2987 index = imm4 >> 1;
2988 size = 8;
2989 } else if ((imm4 & 3) == 2) {
2990 op = Q ? Iop_Dup16x8 : Iop_Dup16x4;
2991 op2 = Iop_GetElem16x4;
2992 index = imm4 >> 2;
2993 size = 16;
2994 } else if ((imm4 & 7) == 4) {
2995 op = Q ? Iop_Dup32x4 : Iop_Dup32x2;
2996 op2 = Iop_GetElem32x2;
2997 index = imm4 >> 3;
2998 size = 32;
sewardj9dbbd7b2010-08-22 18:24:51 +00002999 } else {
3000 return False; // can this ever happen?
sewardjd2664472010-08-22 12:44:20 +00003001 }
3002 assign(res, unop(op, binop(op2, mkexpr(arg_m), mkU8(index))));
3003 if (Q) {
3004 putQReg(dreg, mkexpr(res), condT);
3005 } else {
3006 putDRegI64(dreg, mkexpr(res), condT);
3007 }
3008 DIP("vdup.%d %c%d, d%d[%d]\n", size, Q ? 'q' : 'd', dreg, mreg, index);
3009 return True;
3010}
3011
3012/* A7.4.1 Three registers of the same length */
3013static
3014Bool dis_neon_data_3same ( UInt theInstr, IRTemp condT )
3015{
3016 UInt Q = (theInstr >> 6) & 1;
3017 UInt dreg = get_neon_d_regno(theInstr);
3018 UInt nreg = get_neon_n_regno(theInstr);
3019 UInt mreg = get_neon_m_regno(theInstr);
3020 UInt A = (theInstr >> 8) & 0xF;
3021 UInt B = (theInstr >> 4) & 1;
3022 UInt C = (theInstr >> 20) & 0x3;
3023 UInt U = (theInstr >> 24) & 1;
3024 UInt size = C;
3025
3026 IRTemp arg_n;
3027 IRTemp arg_m;
3028 IRTemp res;
3029
3030 if (Q) {
3031 arg_n = newTemp(Ity_V128);
3032 arg_m = newTemp(Ity_V128);
3033 res = newTemp(Ity_V128);
3034 assign(arg_n, getQReg(nreg));
3035 assign(arg_m, getQReg(mreg));
3036 } else {
3037 arg_n = newTemp(Ity_I64);
3038 arg_m = newTemp(Ity_I64);
3039 res = newTemp(Ity_I64);
3040 assign(arg_n, getDRegI64(nreg));
3041 assign(arg_m, getDRegI64(mreg));
3042 }
3043
3044 switch(A) {
3045 case 0:
3046 if (B == 0) {
3047 /* VHADD */
3048 ULong imm = 0;
3049 IRExpr *imm_val;
3050 IROp addOp;
3051 IROp andOp;
3052 IROp shOp;
florian5df8ab02012-10-13 19:34:19 +00003053 HChar regType = Q ? 'q' : 'd';
sewardjd2664472010-08-22 12:44:20 +00003054
3055 if (size == 3)
3056 return False;
3057 switch(size) {
3058 case 0: imm = 0x101010101010101LL; break;
3059 case 1: imm = 0x1000100010001LL; break;
3060 case 2: imm = 0x100000001LL; break;
3061 default: vassert(0);
3062 }
3063 if (Q) {
3064 imm_val = binop(Iop_64HLtoV128, mkU64(imm), mkU64(imm));
3065 andOp = Iop_AndV128;
3066 } else {
3067 imm_val = mkU64(imm);
3068 andOp = Iop_And64;
3069 }
3070 if (U) {
3071 switch(size) {
3072 case 0:
3073 addOp = Q ? Iop_Add8x16 : Iop_Add8x8;
3074 shOp = Q ? Iop_ShrN8x16 : Iop_ShrN8x8;
3075 break;
3076 case 1:
3077 addOp = Q ? Iop_Add16x8 : Iop_Add16x4;
3078 shOp = Q ? Iop_ShrN16x8 : Iop_ShrN16x4;
3079 break;
3080 case 2:
3081 addOp = Q ? Iop_Add32x4 : Iop_Add32x2;
3082 shOp = Q ? Iop_ShrN32x4 : Iop_ShrN32x2;
3083 break;
3084 default:
3085 vassert(0);
3086 }
3087 } else {
3088 switch(size) {
3089 case 0:
3090 addOp = Q ? Iop_Add8x16 : Iop_Add8x8;
3091 shOp = Q ? Iop_SarN8x16 : Iop_SarN8x8;
3092 break;
3093 case 1:
3094 addOp = Q ? Iop_Add16x8 : Iop_Add16x4;
3095 shOp = Q ? Iop_SarN16x8 : Iop_SarN16x4;
3096 break;
3097 case 2:
3098 addOp = Q ? Iop_Add32x4 : Iop_Add32x2;
3099 shOp = Q ? Iop_SarN32x4 : Iop_SarN32x2;
3100 break;
3101 default:
3102 vassert(0);
3103 }
3104 }
3105 assign(res,
3106 binop(addOp,
3107 binop(addOp,
3108 binop(shOp, mkexpr(arg_m), mkU8(1)),
3109 binop(shOp, mkexpr(arg_n), mkU8(1))),
3110 binop(shOp,
3111 binop(addOp,
3112 binop(andOp, mkexpr(arg_m), imm_val),
3113 binop(andOp, mkexpr(arg_n), imm_val)),
3114 mkU8(1))));
3115 DIP("vhadd.%c%d %c%d, %c%d, %c%d\n",
3116 U ? 'u' : 's', 8 << size, regType,
3117 dreg, regType, nreg, regType, mreg);
3118 } else {
3119 /* VQADD */
3120 IROp op, op2;
3121 IRTemp tmp;
florian5df8ab02012-10-13 19:34:19 +00003122 HChar reg_t = Q ? 'q' : 'd';
sewardjd2664472010-08-22 12:44:20 +00003123 if (Q) {
3124 switch (size) {
3125 case 0:
3126 op = U ? Iop_QAdd8Ux16 : Iop_QAdd8Sx16;
3127 op2 = Iop_Add8x16;
3128 break;
3129 case 1:
3130 op = U ? Iop_QAdd16Ux8 : Iop_QAdd16Sx8;
3131 op2 = Iop_Add16x8;
3132 break;
3133 case 2:
3134 op = U ? Iop_QAdd32Ux4 : Iop_QAdd32Sx4;
3135 op2 = Iop_Add32x4;
3136 break;
3137 case 3:
3138 op = U ? Iop_QAdd64Ux2 : Iop_QAdd64Sx2;
3139 op2 = Iop_Add64x2;
3140 break;
3141 default:
3142 vassert(0);
3143 }
3144 } else {
3145 switch (size) {
3146 case 0:
3147 op = U ? Iop_QAdd8Ux8 : Iop_QAdd8Sx8;
3148 op2 = Iop_Add8x8;
3149 break;
3150 case 1:
3151 op = U ? Iop_QAdd16Ux4 : Iop_QAdd16Sx4;
3152 op2 = Iop_Add16x4;
3153 break;
3154 case 2:
3155 op = U ? Iop_QAdd32Ux2 : Iop_QAdd32Sx2;
3156 op2 = Iop_Add32x2;
3157 break;
3158 case 3:
3159 op = U ? Iop_QAdd64Ux1 : Iop_QAdd64Sx1;
3160 op2 = Iop_Add64;
3161 break;
3162 default:
3163 vassert(0);
3164 }
3165 }
3166 if (Q) {
3167 tmp = newTemp(Ity_V128);
3168 } else {
3169 tmp = newTemp(Ity_I64);
3170 }
3171 assign(res, binop(op, mkexpr(arg_n), mkexpr(arg_m)));
sewardjd2664472010-08-22 12:44:20 +00003172 assign(tmp, binop(op2, mkexpr(arg_n), mkexpr(arg_m)));
3173 setFlag_QC(mkexpr(res), mkexpr(tmp), Q, condT);
sewardjd2664472010-08-22 12:44:20 +00003174 DIP("vqadd.%c%d %c%d, %c%d, %c%d\n",
3175 U ? 'u' : 's',
3176 8 << size, reg_t, dreg, reg_t, nreg, reg_t, mreg);
3177 }
3178 break;
3179 case 1:
3180 if (B == 0) {
3181 /* VRHADD */
3182 /* VRHADD C, A, B ::=
3183 C = (A >> 1) + (B >> 1) + (((A & 1) + (B & 1) + 1) >> 1) */
3184 IROp shift_op, add_op;
3185 IRTemp cc;
3186 ULong one = 1;
3187 HChar reg_t = Q ? 'q' : 'd';
3188 switch (size) {
3189 case 0: one = (one << 8) | one; /* fall through */
3190 case 1: one = (one << 16) | one; /* fall through */
3191 case 2: one = (one << 32) | one; break;
3192 case 3: return False;
3193 default: vassert(0);
3194 }
3195 if (Q) {
3196 switch (size) {
3197 case 0:
3198 shift_op = U ? Iop_ShrN8x16 : Iop_SarN8x16;
3199 add_op = Iop_Add8x16;
3200 break;
3201 case 1:
3202 shift_op = U ? Iop_ShrN16x8 : Iop_SarN16x8;
3203 add_op = Iop_Add16x8;
3204 break;
3205 case 2:
3206 shift_op = U ? Iop_ShrN32x4 : Iop_SarN32x4;
3207 add_op = Iop_Add32x4;
3208 break;
3209 case 3:
3210 return False;
3211 default:
3212 vassert(0);
3213 }
3214 } else {
3215 switch (size) {
3216 case 0:
3217 shift_op = U ? Iop_ShrN8x8 : Iop_SarN8x8;
3218 add_op = Iop_Add8x8;
3219 break;
3220 case 1:
3221 shift_op = U ? Iop_ShrN16x4 : Iop_SarN16x4;
3222 add_op = Iop_Add16x4;
3223 break;
3224 case 2:
3225 shift_op = U ? Iop_ShrN32x2 : Iop_SarN32x2;
3226 add_op = Iop_Add32x2;
3227 break;
3228 case 3:
3229 return False;
3230 default:
3231 vassert(0);
3232 }
3233 }
3234 if (Q) {
3235 cc = newTemp(Ity_V128);
3236 assign(cc, binop(shift_op,
3237 binop(add_op,
3238 binop(add_op,
3239 binop(Iop_AndV128,
3240 mkexpr(arg_n),
3241 binop(Iop_64HLtoV128,
3242 mkU64(one),
3243 mkU64(one))),
3244 binop(Iop_AndV128,
3245 mkexpr(arg_m),
3246 binop(Iop_64HLtoV128,
3247 mkU64(one),
3248 mkU64(one)))),
3249 binop(Iop_64HLtoV128,
3250 mkU64(one),
3251 mkU64(one))),
3252 mkU8(1)));
3253 assign(res, binop(add_op,
3254 binop(add_op,
3255 binop(shift_op,
3256 mkexpr(arg_n),
3257 mkU8(1)),
3258 binop(shift_op,
3259 mkexpr(arg_m),
3260 mkU8(1))),
3261 mkexpr(cc)));
3262 } else {
3263 cc = newTemp(Ity_I64);
3264 assign(cc, binop(shift_op,
3265 binop(add_op,
3266 binop(add_op,
3267 binop(Iop_And64,
3268 mkexpr(arg_n),
3269 mkU64(one)),
3270 binop(Iop_And64,
3271 mkexpr(arg_m),
3272 mkU64(one))),
3273 mkU64(one)),
3274 mkU8(1)));
3275 assign(res, binop(add_op,
3276 binop(add_op,
3277 binop(shift_op,
3278 mkexpr(arg_n),
3279 mkU8(1)),
3280 binop(shift_op,
3281 mkexpr(arg_m),
3282 mkU8(1))),
3283 mkexpr(cc)));
3284 }
3285 DIP("vrhadd.%c%d %c%d, %c%d, %c%d\n",
3286 U ? 'u' : 's',
3287 8 << size, reg_t, dreg, reg_t, nreg, reg_t, mreg);
3288 } else {
3289 if (U == 0) {
3290 switch(C) {
3291 case 0: {
3292 /* VAND */
3293 HChar reg_t = Q ? 'q' : 'd';
3294 if (Q) {
3295 assign(res, binop(Iop_AndV128, mkexpr(arg_n),
3296 mkexpr(arg_m)));
3297 } else {
3298 assign(res, binop(Iop_And64, mkexpr(arg_n),
3299 mkexpr(arg_m)));
3300 }
3301 DIP("vand %c%d, %c%d, %c%d\n",
3302 reg_t, dreg, reg_t, nreg, reg_t, mreg);
3303 break;
3304 }
3305 case 1: {
3306 /* VBIC */
3307 HChar reg_t = Q ? 'q' : 'd';
3308 if (Q) {
3309 assign(res, binop(Iop_AndV128,mkexpr(arg_n),
3310 unop(Iop_NotV128, mkexpr(arg_m))));
3311 } else {
3312 assign(res, binop(Iop_And64, mkexpr(arg_n),
3313 unop(Iop_Not64, mkexpr(arg_m))));
3314 }
3315 DIP("vbic %c%d, %c%d, %c%d\n",
3316 reg_t, dreg, reg_t, nreg, reg_t, mreg);
3317 break;
3318 }
3319 case 2:
3320 if ( nreg != mreg) {
3321 /* VORR */
3322 HChar reg_t = Q ? 'q' : 'd';
3323 if (Q) {
3324 assign(res, binop(Iop_OrV128, mkexpr(arg_n),
3325 mkexpr(arg_m)));
3326 } else {
3327 assign(res, binop(Iop_Or64, mkexpr(arg_n),
3328 mkexpr(arg_m)));
3329 }
3330 DIP("vorr %c%d, %c%d, %c%d\n",
3331 reg_t, dreg, reg_t, nreg, reg_t, mreg);
3332 } else {
3333 /* VMOV */
3334 HChar reg_t = Q ? 'q' : 'd';
3335 assign(res, mkexpr(arg_m));
3336 DIP("vmov %c%d, %c%d\n", reg_t, dreg, reg_t, mreg);
3337 }
3338 break;
3339 case 3:{
3340 /* VORN */
3341 HChar reg_t = Q ? 'q' : 'd';
3342 if (Q) {
3343 assign(res, binop(Iop_OrV128,mkexpr(arg_n),
3344 unop(Iop_NotV128, mkexpr(arg_m))));
3345 } else {
3346 assign(res, binop(Iop_Or64, mkexpr(arg_n),
3347 unop(Iop_Not64, mkexpr(arg_m))));
3348 }
3349 DIP("vorn %c%d, %c%d, %c%d\n",
3350 reg_t, dreg, reg_t, nreg, reg_t, mreg);
3351 break;
3352 }
3353 }
3354 } else {
3355 switch(C) {
3356 case 0:
3357 /* VEOR (XOR) */
3358 if (Q) {
3359 assign(res, binop(Iop_XorV128, mkexpr(arg_n),
3360 mkexpr(arg_m)));
3361 } else {
3362 assign(res, binop(Iop_Xor64, mkexpr(arg_n),
3363 mkexpr(arg_m)));
3364 }
3365 DIP("veor %c%u, %c%u, %c%u\n", Q ? 'q' : 'd', dreg,
3366 Q ? 'q' : 'd', nreg, Q ? 'q' : 'd', mreg);
3367 break;
3368 case 1:
3369 /* VBSL */
3370 if (Q) {
3371 IRTemp reg_d = newTemp(Ity_V128);
3372 assign(reg_d, getQReg(dreg));
3373 assign(res,
3374 binop(Iop_OrV128,
3375 binop(Iop_AndV128, mkexpr(arg_n),
3376 mkexpr(reg_d)),
3377 binop(Iop_AndV128,
3378 mkexpr(arg_m),
3379 unop(Iop_NotV128,
3380 mkexpr(reg_d)) ) ) );
3381 } else {
3382 IRTemp reg_d = newTemp(Ity_I64);
3383 assign(reg_d, getDRegI64(dreg));
3384 assign(res,
3385 binop(Iop_Or64,
3386 binop(Iop_And64, mkexpr(arg_n),
3387 mkexpr(reg_d)),
3388 binop(Iop_And64,
3389 mkexpr(arg_m),
3390 unop(Iop_Not64, mkexpr(reg_d)))));
3391 }
3392 DIP("vbsl %c%u, %c%u, %c%u\n",
3393 Q ? 'q' : 'd', dreg,
3394 Q ? 'q' : 'd', nreg, Q ? 'q' : 'd', mreg);
3395 break;
3396 case 2:
3397 /* VBIT */
3398 if (Q) {
3399 IRTemp reg_d = newTemp(Ity_V128);
3400 assign(reg_d, getQReg(dreg));
3401 assign(res,
3402 binop(Iop_OrV128,
3403 binop(Iop_AndV128, mkexpr(arg_n),
3404 mkexpr(arg_m)),
3405 binop(Iop_AndV128,
3406 mkexpr(reg_d),
3407 unop(Iop_NotV128, mkexpr(arg_m)))));
3408 } else {
3409 IRTemp reg_d = newTemp(Ity_I64);
3410 assign(reg_d, getDRegI64(dreg));
3411 assign(res,
3412 binop(Iop_Or64,
3413 binop(Iop_And64, mkexpr(arg_n),
3414 mkexpr(arg_m)),
3415 binop(Iop_And64,
3416 mkexpr(reg_d),
3417 unop(Iop_Not64, mkexpr(arg_m)))));
3418 }
3419 DIP("vbit %c%u, %c%u, %c%u\n",
3420 Q ? 'q' : 'd', dreg,
3421 Q ? 'q' : 'd', nreg, Q ? 'q' : 'd', mreg);
3422 break;
3423 case 3:
3424 /* VBIF */
3425 if (Q) {
3426 IRTemp reg_d = newTemp(Ity_V128);
3427 assign(reg_d, getQReg(dreg));
3428 assign(res,
3429 binop(Iop_OrV128,
3430 binop(Iop_AndV128, mkexpr(reg_d),
3431 mkexpr(arg_m)),
3432 binop(Iop_AndV128,
3433 mkexpr(arg_n),
3434 unop(Iop_NotV128, mkexpr(arg_m)))));
3435 } else {
3436 IRTemp reg_d = newTemp(Ity_I64);
3437 assign(reg_d, getDRegI64(dreg));
3438 assign(res,
3439 binop(Iop_Or64,
3440 binop(Iop_And64, mkexpr(reg_d),
3441 mkexpr(arg_m)),
3442 binop(Iop_And64,
3443 mkexpr(arg_n),
3444 unop(Iop_Not64, mkexpr(arg_m)))));
3445 }
3446 DIP("vbif %c%u, %c%u, %c%u\n",
3447 Q ? 'q' : 'd', dreg,
3448 Q ? 'q' : 'd', nreg, Q ? 'q' : 'd', mreg);
3449 break;
3450 }
3451 }
3452 }
3453 break;
3454 case 2:
3455 if (B == 0) {
3456 /* VHSUB */
3457 /* (A >> 1) - (B >> 1) - (NOT (A) & B & 1) */
3458 ULong imm = 0;
3459 IRExpr *imm_val;
3460 IROp subOp;
3461 IROp notOp;
3462 IROp andOp;
3463 IROp shOp;
3464 if (size == 3)
3465 return False;
3466 switch(size) {
3467 case 0: imm = 0x101010101010101LL; break;
3468 case 1: imm = 0x1000100010001LL; break;
3469 case 2: imm = 0x100000001LL; break;
3470 default: vassert(0);
3471 }
3472 if (Q) {
3473 imm_val = binop(Iop_64HLtoV128, mkU64(imm), mkU64(imm));
3474 andOp = Iop_AndV128;
3475 notOp = Iop_NotV128;
3476 } else {
3477 imm_val = mkU64(imm);
3478 andOp = Iop_And64;
3479 notOp = Iop_Not64;
3480 }
3481 if (U) {
3482 switch(size) {
3483 case 0:
3484 subOp = Q ? Iop_Sub8x16 : Iop_Sub8x8;
3485 shOp = Q ? Iop_ShrN8x16 : Iop_ShrN8x8;
3486 break;
3487 case 1:
3488 subOp = Q ? Iop_Sub16x8 : Iop_Sub16x4;
3489 shOp = Q ? Iop_ShrN16x8 : Iop_ShrN16x4;
3490 break;
3491 case 2:
3492 subOp = Q ? Iop_Sub32x4 : Iop_Sub32x2;
3493 shOp = Q ? Iop_ShrN32x4 : Iop_ShrN32x2;
3494 break;
3495 default:
3496 vassert(0);
3497 }
3498 } else {
3499 switch(size) {
3500 case 0:
3501 subOp = Q ? Iop_Sub8x16 : Iop_Sub8x8;
3502 shOp = Q ? Iop_SarN8x16 : Iop_SarN8x8;
3503 break;
3504 case 1:
3505 subOp = Q ? Iop_Sub16x8 : Iop_Sub16x4;
3506 shOp = Q ? Iop_SarN16x8 : Iop_SarN16x4;
3507 break;
3508 case 2:
3509 subOp = Q ? Iop_Sub32x4 : Iop_Sub32x2;
3510 shOp = Q ? Iop_SarN32x4 : Iop_SarN32x2;
3511 break;
3512 default:
3513 vassert(0);
3514 }
3515 }
3516 assign(res,
3517 binop(subOp,
3518 binop(subOp,
3519 binop(shOp, mkexpr(arg_n), mkU8(1)),
3520 binop(shOp, mkexpr(arg_m), mkU8(1))),
3521 binop(andOp,
3522 binop(andOp,
3523 unop(notOp, mkexpr(arg_n)),
3524 mkexpr(arg_m)),
3525 imm_val)));
3526 DIP("vhsub.%c%u %c%u, %c%u, %c%u\n",
3527 U ? 'u' : 's', 8 << size,
3528 Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', nreg, Q ? 'q' : 'd',
3529 mreg);
3530 } else {
3531 /* VQSUB */
3532 IROp op, op2;
3533 IRTemp tmp;
3534 if (Q) {
3535 switch (size) {
3536 case 0:
3537 op = U ? Iop_QSub8Ux16 : Iop_QSub8Sx16;
3538 op2 = Iop_Sub8x16;
3539 break;
3540 case 1:
3541 op = U ? Iop_QSub16Ux8 : Iop_QSub16Sx8;
3542 op2 = Iop_Sub16x8;
3543 break;
3544 case 2:
3545 op = U ? Iop_QSub32Ux4 : Iop_QSub32Sx4;
3546 op2 = Iop_Sub32x4;
3547 break;
3548 case 3:
3549 op = U ? Iop_QSub64Ux2 : Iop_QSub64Sx2;
3550 op2 = Iop_Sub64x2;
3551 break;
3552 default:
3553 vassert(0);
3554 }
3555 } else {
3556 switch (size) {
3557 case 0:
3558 op = U ? Iop_QSub8Ux8 : Iop_QSub8Sx8;
3559 op2 = Iop_Sub8x8;
3560 break;
3561 case 1:
3562 op = U ? Iop_QSub16Ux4 : Iop_QSub16Sx4;
3563 op2 = Iop_Sub16x4;
3564 break;
3565 case 2:
3566 op = U ? Iop_QSub32Ux2 : Iop_QSub32Sx2;
3567 op2 = Iop_Sub32x2;
3568 break;
3569 case 3:
3570 op = U ? Iop_QSub64Ux1 : Iop_QSub64Sx1;
3571 op2 = Iop_Sub64;
3572 break;
3573 default:
3574 vassert(0);
3575 }
3576 }
3577 if (Q)
3578 tmp = newTemp(Ity_V128);
3579 else
3580 tmp = newTemp(Ity_I64);
3581 assign(res, binop(op, mkexpr(arg_n), mkexpr(arg_m)));
sewardjd2664472010-08-22 12:44:20 +00003582 assign(tmp, binop(op2, mkexpr(arg_n), mkexpr(arg_m)));
3583 setFlag_QC(mkexpr(res), mkexpr(tmp), Q, condT);
sewardjd2664472010-08-22 12:44:20 +00003584 DIP("vqsub.%c%u %c%u, %c%u, %c%u\n",
3585 U ? 'u' : 's', 8 << size,
3586 Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', nreg, Q ? 'q' : 'd',
3587 mreg);
3588 }
3589 break;
3590 case 3: {
3591 IROp op;
3592 if (Q) {
3593 switch (size) {
3594 case 0: op = U ? Iop_CmpGT8Ux16 : Iop_CmpGT8Sx16; break;
3595 case 1: op = U ? Iop_CmpGT16Ux8 : Iop_CmpGT16Sx8; break;
3596 case 2: op = U ? Iop_CmpGT32Ux4 : Iop_CmpGT32Sx4; break;
3597 case 3: return False;
3598 default: vassert(0);
3599 }
3600 } else {
3601 switch (size) {
3602 case 0: op = U ? Iop_CmpGT8Ux8 : Iop_CmpGT8Sx8; break;
3603 case 1: op = U ? Iop_CmpGT16Ux4 : Iop_CmpGT16Sx4; break;
3604 case 2: op = U ? Iop_CmpGT32Ux2: Iop_CmpGT32Sx2; break;
3605 case 3: return False;
3606 default: vassert(0);
3607 }
3608 }
3609 if (B == 0) {
3610 /* VCGT */
3611 assign(res, binop(op, mkexpr(arg_n), mkexpr(arg_m)));
3612 DIP("vcgt.%c%u %c%u, %c%u, %c%u\n",
3613 U ? 'u' : 's', 8 << size,
3614 Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', nreg, Q ? 'q' : 'd',
3615 mreg);
3616 } else {
3617 /* VCGE */
3618 /* VCGE res, argn, argm
3619 is equal to
3620 VCGT tmp, argm, argn
3621 VNOT res, tmp */
3622 assign(res,
3623 unop(Q ? Iop_NotV128 : Iop_Not64,
3624 binop(op, mkexpr(arg_m), mkexpr(arg_n))));
3625 DIP("vcge.%c%u %c%u, %c%u, %c%u\n",
3626 U ? 'u' : 's', 8 << size,
3627 Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', nreg, Q ? 'q' : 'd',
3628 mreg);
3629 }
3630 }
3631 break;
3632 case 4:
3633 if (B == 0) {
3634 /* VSHL */
3635 IROp op, sub_op;
3636 IRTemp tmp;
3637 if (U) {
3638 switch (size) {
3639 case 0: op = Q ? Iop_Shl8x16 : Iop_Shl8x8; break;
3640 case 1: op = Q ? Iop_Shl16x8 : Iop_Shl16x4; break;
3641 case 2: op = Q ? Iop_Shl32x4 : Iop_Shl32x2; break;
3642 case 3: op = Q ? Iop_Shl64x2 : Iop_Shl64; break;
3643 default: vassert(0);
3644 }
3645 } else {
3646 tmp = newTemp(Q ? Ity_V128 : Ity_I64);
3647 switch (size) {
3648 case 0:
3649 op = Q ? Iop_Sar8x16 : Iop_Sar8x8;
3650 sub_op = Q ? Iop_Sub8x16 : Iop_Sub8x8;
3651 break;
3652 case 1:
3653 op = Q ? Iop_Sar16x8 : Iop_Sar16x4;
3654 sub_op = Q ? Iop_Sub16x8 : Iop_Sub16x4;
3655 break;
3656 case 2:
3657 op = Q ? Iop_Sar32x4 : Iop_Sar32x2;
3658 sub_op = Q ? Iop_Sub32x4 : Iop_Sub32x2;
3659 break;
3660 case 3:
3661 op = Q ? Iop_Sar64x2 : Iop_Sar64;
3662 sub_op = Q ? Iop_Sub64x2 : Iop_Sub64;
3663 break;
3664 default:
3665 vassert(0);
3666 }
3667 }
3668 if (U) {
3669 if (!Q && (size == 3))
3670 assign(res, binop(op, mkexpr(arg_m),
3671 unop(Iop_64to8, mkexpr(arg_n))));
3672 else
3673 assign(res, binop(op, mkexpr(arg_m), mkexpr(arg_n)));
3674 } else {
3675 if (Q)
3676 assign(tmp, binop(sub_op,
3677 binop(Iop_64HLtoV128, mkU64(0), mkU64(0)),
3678 mkexpr(arg_n)));
3679 else
3680 assign(tmp, binop(sub_op, mkU64(0), mkexpr(arg_n)));
3681 if (!Q && (size == 3))
3682 assign(res, binop(op, mkexpr(arg_m),
3683 unop(Iop_64to8, mkexpr(tmp))));
3684 else
3685 assign(res, binop(op, mkexpr(arg_m), mkexpr(tmp)));
3686 }
3687 DIP("vshl.%c%u %c%u, %c%u, %c%u\n",
3688 U ? 'u' : 's', 8 << size,
3689 Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', mreg, Q ? 'q' : 'd',
3690 nreg);
3691 } else {
3692 /* VQSHL */
3693 IROp op, op_rev, op_shrn, op_shln, cmp_neq, cmp_gt;
3694 IRTemp tmp, shval, mask, old_shval;
3695 UInt i;
3696 ULong esize;
3697 cmp_neq = Q ? Iop_CmpNEZ8x16 : Iop_CmpNEZ8x8;
3698 cmp_gt = Q ? Iop_CmpGT8Sx16 : Iop_CmpGT8Sx8;
3699 if (U) {
3700 switch (size) {
3701 case 0:
3702 op = Q ? Iop_QShl8x16 : Iop_QShl8x8;
3703 op_rev = Q ? Iop_Shr8x16 : Iop_Shr8x8;
3704 op_shrn = Q ? Iop_ShrN8x16 : Iop_ShrN8x8;
3705 op_shln = Q ? Iop_ShlN8x16 : Iop_ShlN8x8;
3706 break;
3707 case 1:
3708 op = Q ? Iop_QShl16x8 : Iop_QShl16x4;
3709 op_rev = Q ? Iop_Shr16x8 : Iop_Shr16x4;
3710 op_shrn = Q ? Iop_ShrN16x8 : Iop_ShrN16x4;
3711 op_shln = Q ? Iop_ShlN16x8 : Iop_ShlN16x4;
3712 break;
3713 case 2:
3714 op = Q ? Iop_QShl32x4 : Iop_QShl32x2;
3715 op_rev = Q ? Iop_Shr32x4 : Iop_Shr32x2;
3716 op_shrn = Q ? Iop_ShrN32x4 : Iop_ShrN32x2;
3717 op_shln = Q ? Iop_ShlN32x4 : Iop_ShlN32x2;
3718 break;
3719 case 3:
3720 op = Q ? Iop_QShl64x2 : Iop_QShl64x1;
3721 op_rev = Q ? Iop_Shr64x2 : Iop_Shr64;
3722 op_shrn = Q ? Iop_ShrN64x2 : Iop_Shr64;
3723 op_shln = Q ? Iop_ShlN64x2 : Iop_Shl64;
3724 break;
3725 default:
3726 vassert(0);
3727 }
3728 } else {
3729 switch (size) {
3730 case 0:
3731 op = Q ? Iop_QSal8x16 : Iop_QSal8x8;
3732 op_rev = Q ? Iop_Sar8x16 : Iop_Sar8x8;
3733 op_shrn = Q ? Iop_ShrN8x16 : Iop_ShrN8x8;
3734 op_shln = Q ? Iop_ShlN8x16 : Iop_ShlN8x8;
3735 break;
3736 case 1:
3737 op = Q ? Iop_QSal16x8 : Iop_QSal16x4;
3738 op_rev = Q ? Iop_Sar16x8 : Iop_Sar16x4;
3739 op_shrn = Q ? Iop_ShrN16x8 : Iop_ShrN16x4;
3740 op_shln = Q ? Iop_ShlN16x8 : Iop_ShlN16x4;
3741 break;
3742 case 2:
3743 op = Q ? Iop_QSal32x4 : Iop_QSal32x2;
3744 op_rev = Q ? Iop_Sar32x4 : Iop_Sar32x2;
3745 op_shrn = Q ? Iop_ShrN32x4 : Iop_ShrN32x2;
3746 op_shln = Q ? Iop_ShlN32x4 : Iop_ShlN32x2;
3747 break;
3748 case 3:
3749 op = Q ? Iop_QSal64x2 : Iop_QSal64x1;
3750 op_rev = Q ? Iop_Sar64x2 : Iop_Sar64;
3751 op_shrn = Q ? Iop_ShrN64x2 : Iop_Shr64;
3752 op_shln = Q ? Iop_ShlN64x2 : Iop_Shl64;
3753 break;
3754 default:
3755 vassert(0);
3756 }
3757 }
3758 if (Q) {
3759 tmp = newTemp(Ity_V128);
3760 shval = newTemp(Ity_V128);
3761 mask = newTemp(Ity_V128);
3762 } else {
3763 tmp = newTemp(Ity_I64);
3764 shval = newTemp(Ity_I64);
3765 mask = newTemp(Ity_I64);
3766 }
3767 assign(res, binop(op, mkexpr(arg_m), mkexpr(arg_n)));
sewardjd2664472010-08-22 12:44:20 +00003768 /* Only least significant byte from second argument is used.
3769 Copy this byte to the whole vector element. */
3770 assign(shval, binop(op_shrn,
3771 binop(op_shln,
3772 mkexpr(arg_n),
3773 mkU8((8 << size) - 8)),
3774 mkU8((8 << size) - 8)));
3775 for(i = 0; i < size; i++) {
3776 old_shval = shval;
3777 shval = newTemp(Q ? Ity_V128 : Ity_I64);
3778 assign(shval, binop(Q ? Iop_OrV128 : Iop_Or64,
3779 mkexpr(old_shval),
3780 binop(op_shln,
3781 mkexpr(old_shval),
3782 mkU8(8 << i))));
3783 }
3784 /* If shift is greater or equal to the element size and
3785 element is non-zero, then QC flag should be set. */
3786 esize = (8 << size) - 1;
3787 esize = (esize << 8) | esize;
3788 esize = (esize << 16) | esize;
3789 esize = (esize << 32) | esize;
3790 setFlag_QC(binop(Q ? Iop_AndV128 : Iop_And64,
3791 binop(cmp_gt, mkexpr(shval),
3792 Q ? mkU128(esize) : mkU64(esize)),
3793 unop(cmp_neq, mkexpr(arg_m))),
3794 Q ? mkU128(0) : mkU64(0),
3795 Q, condT);
3796 /* Othervise QC flag should be set if shift value is positive and
3797 result beign rightshifted the same value is not equal to left
3798 argument. */
3799 assign(mask, binop(cmp_gt, mkexpr(shval),
3800 Q ? mkU128(0) : mkU64(0)));
3801 if (!Q && size == 3)
3802 assign(tmp, binop(op_rev, mkexpr(res),
3803 unop(Iop_64to8, mkexpr(arg_n))));
3804 else
3805 assign(tmp, binop(op_rev, mkexpr(res), mkexpr(arg_n)));
3806 setFlag_QC(binop(Q ? Iop_AndV128 : Iop_And64,
3807 mkexpr(tmp), mkexpr(mask)),
3808 binop(Q ? Iop_AndV128 : Iop_And64,
3809 mkexpr(arg_m), mkexpr(mask)),
3810 Q, condT);
sewardjd2664472010-08-22 12:44:20 +00003811 DIP("vqshl.%c%u %c%u, %c%u, %c%u\n",
3812 U ? 'u' : 's', 8 << size,
3813 Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', mreg, Q ? 'q' : 'd',
3814 nreg);
3815 }
3816 break;
3817 case 5:
3818 if (B == 0) {
3819 /* VRSHL */
sewardj06122e72011-03-28 12:14:48 +00003820 IROp op, op_shrn, op_shln, cmp_gt, op_add;
sewardjd2664472010-08-22 12:44:20 +00003821 IRTemp shval, old_shval, imm_val, round;
3822 UInt i;
3823 ULong imm;
3824 cmp_gt = Q ? Iop_CmpGT8Sx16 : Iop_CmpGT8Sx8;
3825 imm = 1L;
3826 switch (size) {
3827 case 0: imm = (imm << 8) | imm; /* fall through */
3828 case 1: imm = (imm << 16) | imm; /* fall through */
3829 case 2: imm = (imm << 32) | imm; /* fall through */
3830 case 3: break;
3831 default: vassert(0);
3832 }
3833 imm_val = newTemp(Q ? Ity_V128 : Ity_I64);
3834 round = newTemp(Q ? Ity_V128 : Ity_I64);
3835 assign(imm_val, Q ? mkU128(imm) : mkU64(imm));
3836 if (U) {
3837 switch (size) {
3838 case 0:
3839 op = Q ? Iop_Shl8x16 : Iop_Shl8x8;
sewardjd2664472010-08-22 12:44:20 +00003840 op_add = Q ? Iop_Add8x16 : Iop_Add8x8;
3841 op_shrn = Q ? Iop_ShrN8x16 : Iop_ShrN8x8;
3842 op_shln = Q ? Iop_ShlN8x16 : Iop_ShlN8x8;
3843 break;
3844 case 1:
3845 op = Q ? Iop_Shl16x8 : Iop_Shl16x4;
sewardjd2664472010-08-22 12:44:20 +00003846 op_add = Q ? Iop_Add16x8 : Iop_Add16x4;
3847 op_shrn = Q ? Iop_ShrN16x8 : Iop_ShrN16x4;
3848 op_shln = Q ? Iop_ShlN16x8 : Iop_ShlN16x4;
3849 break;
3850 case 2:
3851 op = Q ? Iop_Shl32x4 : Iop_Shl32x2;
sewardjd2664472010-08-22 12:44:20 +00003852 op_add = Q ? Iop_Add32x4 : Iop_Add32x2;
3853 op_shrn = Q ? Iop_ShrN32x4 : Iop_ShrN32x2;
3854 op_shln = Q ? Iop_ShlN32x4 : Iop_ShlN32x2;
3855 break;
3856 case 3:
3857 op = Q ? Iop_Shl64x2 : Iop_Shl64;
sewardjd2664472010-08-22 12:44:20 +00003858 op_add = Q ? Iop_Add64x2 : Iop_Add64;
3859 op_shrn = Q ? Iop_ShrN64x2 : Iop_Shr64;
3860 op_shln = Q ? Iop_ShlN64x2 : Iop_Shl64;
3861 break;
3862 default:
3863 vassert(0);
3864 }
3865 } else {
3866 switch (size) {
3867 case 0:
3868 op = Q ? Iop_Sal8x16 : Iop_Sal8x8;
sewardjd2664472010-08-22 12:44:20 +00003869 op_add = Q ? Iop_Add8x16 : Iop_Add8x8;
3870 op_shrn = Q ? Iop_ShrN8x16 : Iop_ShrN8x8;
3871 op_shln = Q ? Iop_ShlN8x16 : Iop_ShlN8x8;
3872 break;
3873 case 1:
3874 op = Q ? Iop_Sal16x8 : Iop_Sal16x4;
sewardjd2664472010-08-22 12:44:20 +00003875 op_add = Q ? Iop_Add16x8 : Iop_Add16x4;
3876 op_shrn = Q ? Iop_ShrN16x8 : Iop_ShrN16x4;
3877 op_shln = Q ? Iop_ShlN16x8 : Iop_ShlN16x4;
3878 break;
3879 case 2:
3880 op = Q ? Iop_Sal32x4 : Iop_Sal32x2;
sewardjd2664472010-08-22 12:44:20 +00003881 op_add = Q ? Iop_Add32x4 : Iop_Add32x2;
3882 op_shrn = Q ? Iop_ShrN32x4 : Iop_ShrN32x2;
3883 op_shln = Q ? Iop_ShlN32x4 : Iop_ShlN32x2;
3884 break;
3885 case 3:
3886 op = Q ? Iop_Sal64x2 : Iop_Sal64x1;
sewardjd2664472010-08-22 12:44:20 +00003887 op_add = Q ? Iop_Add64x2 : Iop_Add64;
3888 op_shrn = Q ? Iop_ShrN64x2 : Iop_Shr64;
3889 op_shln = Q ? Iop_ShlN64x2 : Iop_Shl64;
3890 break;
3891 default:
3892 vassert(0);
3893 }
3894 }
3895 if (Q) {
3896 shval = newTemp(Ity_V128);
3897 } else {
3898 shval = newTemp(Ity_I64);
3899 }
3900 /* Only least significant byte from second argument is used.
3901 Copy this byte to the whole vector element. */
3902 assign(shval, binop(op_shrn,
3903 binop(op_shln,
3904 mkexpr(arg_n),
3905 mkU8((8 << size) - 8)),
3906 mkU8((8 << size) - 8)));
3907 for (i = 0; i < size; i++) {
3908 old_shval = shval;
3909 shval = newTemp(Q ? Ity_V128 : Ity_I64);
3910 assign(shval, binop(Q ? Iop_OrV128 : Iop_Or64,
3911 mkexpr(old_shval),
3912 binop(op_shln,
3913 mkexpr(old_shval),
3914 mkU8(8 << i))));
3915 }
3916 /* Compute the result */
3917 if (!Q && size == 3 && U) {
3918 assign(round, binop(Q ? Iop_AndV128 : Iop_And64,
3919 binop(op,
3920 mkexpr(arg_m),
3921 unop(Iop_64to8,
sewardjb0d80ea2010-10-06 20:47:22 +00003922 binop(op_add,
sewardjd2664472010-08-22 12:44:20 +00003923 mkexpr(arg_n),
3924 mkexpr(imm_val)))),
3925 binop(Q ? Iop_AndV128 : Iop_And64,
3926 mkexpr(imm_val),
3927 binop(cmp_gt,
3928 Q ? mkU128(0) : mkU64(0),
3929 mkexpr(arg_n)))));
3930 assign(res, binop(op_add,
3931 binop(op,
3932 mkexpr(arg_m),
3933 unop(Iop_64to8, mkexpr(arg_n))),
3934 mkexpr(round)));
3935 } else {
3936 assign(round, binop(Q ? Iop_AndV128 : Iop_And64,
3937 binop(op,
3938 mkexpr(arg_m),
3939 binop(op_add,
3940 mkexpr(arg_n),
3941 mkexpr(imm_val))),
3942 binop(Q ? Iop_AndV128 : Iop_And64,
3943 mkexpr(imm_val),
3944 binop(cmp_gt,
3945 Q ? mkU128(0) : mkU64(0),
3946 mkexpr(arg_n)))));
3947 assign(res, binop(op_add,
3948 binop(op, mkexpr(arg_m), mkexpr(arg_n)),
3949 mkexpr(round)));
3950 }
3951 DIP("vrshl.%c%u %c%u, %c%u, %c%u\n",
3952 U ? 'u' : 's', 8 << size,
3953 Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', mreg, Q ? 'q' : 'd',
3954 nreg);
3955 } else {
3956 /* VQRSHL */
sewardj06122e72011-03-28 12:14:48 +00003957 IROp op, op_rev, op_shrn, op_shln, cmp_neq, cmp_gt, op_add;
sewardjd2664472010-08-22 12:44:20 +00003958 IRTemp tmp, shval, mask, old_shval, imm_val, round;
3959 UInt i;
3960 ULong esize, imm;
3961 cmp_neq = Q ? Iop_CmpNEZ8x16 : Iop_CmpNEZ8x8;
3962 cmp_gt = Q ? Iop_CmpGT8Sx16 : Iop_CmpGT8Sx8;
3963 imm = 1L;
3964 switch (size) {
3965 case 0: imm = (imm << 8) | imm; /* fall through */
3966 case 1: imm = (imm << 16) | imm; /* fall through */
3967 case 2: imm = (imm << 32) | imm; /* fall through */
3968 case 3: break;
3969 default: vassert(0);
3970 }
3971 imm_val = newTemp(Q ? Ity_V128 : Ity_I64);
3972 round = newTemp(Q ? Ity_V128 : Ity_I64);
3973 assign(imm_val, Q ? mkU128(imm) : mkU64(imm));
3974 if (U) {
3975 switch (size) {
3976 case 0:
3977 op = Q ? Iop_QShl8x16 : Iop_QShl8x8;
sewardjd2664472010-08-22 12:44:20 +00003978 op_add = Q ? Iop_Add8x16 : Iop_Add8x8;
3979 op_rev = Q ? Iop_Shr8x16 : Iop_Shr8x8;
3980 op_shrn = Q ? Iop_ShrN8x16 : Iop_ShrN8x8;
3981 op_shln = Q ? Iop_ShlN8x16 : Iop_ShlN8x8;
3982 break;
3983 case 1:
3984 op = Q ? Iop_QShl16x8 : Iop_QShl16x4;
sewardjd2664472010-08-22 12:44:20 +00003985 op_add = Q ? Iop_Add16x8 : Iop_Add16x4;
3986 op_rev = Q ? Iop_Shr16x8 : Iop_Shr16x4;
3987 op_shrn = Q ? Iop_ShrN16x8 : Iop_ShrN16x4;
3988 op_shln = Q ? Iop_ShlN16x8 : Iop_ShlN16x4;
3989 break;
3990 case 2:
3991 op = Q ? Iop_QShl32x4 : Iop_QShl32x2;
sewardjd2664472010-08-22 12:44:20 +00003992 op_add = Q ? Iop_Add32x4 : Iop_Add32x2;
3993 op_rev = Q ? Iop_Shr32x4 : Iop_Shr32x2;
3994 op_shrn = Q ? Iop_ShrN32x4 : Iop_ShrN32x2;
3995 op_shln = Q ? Iop_ShlN32x4 : Iop_ShlN32x2;
3996 break;
3997 case 3:
3998 op = Q ? Iop_QShl64x2 : Iop_QShl64x1;
sewardjd2664472010-08-22 12:44:20 +00003999 op_add = Q ? Iop_Add64x2 : Iop_Add64;
4000 op_rev = Q ? Iop_Shr64x2 : Iop_Shr64;
4001 op_shrn = Q ? Iop_ShrN64x2 : Iop_Shr64;
4002 op_shln = Q ? Iop_ShlN64x2 : Iop_Shl64;
4003 break;
4004 default:
4005 vassert(0);
4006 }
4007 } else {
4008 switch (size) {
4009 case 0:
4010 op = Q ? Iop_QSal8x16 : Iop_QSal8x8;
sewardjd2664472010-08-22 12:44:20 +00004011 op_add = Q ? Iop_Add8x16 : Iop_Add8x8;
4012 op_rev = Q ? Iop_Sar8x16 : Iop_Sar8x8;
4013 op_shrn = Q ? Iop_ShrN8x16 : Iop_ShrN8x8;
4014 op_shln = Q ? Iop_ShlN8x16 : Iop_ShlN8x8;
4015 break;
4016 case 1:
4017 op = Q ? Iop_QSal16x8 : Iop_QSal16x4;
sewardjd2664472010-08-22 12:44:20 +00004018 op_add = Q ? Iop_Add16x8 : Iop_Add16x4;
4019 op_rev = Q ? Iop_Sar16x8 : Iop_Sar16x4;
4020 op_shrn = Q ? Iop_ShrN16x8 : Iop_ShrN16x4;
4021 op_shln = Q ? Iop_ShlN16x8 : Iop_ShlN16x4;
4022 break;
4023 case 2:
4024 op = Q ? Iop_QSal32x4 : Iop_QSal32x2;
sewardjd2664472010-08-22 12:44:20 +00004025 op_add = Q ? Iop_Add32x4 : Iop_Add32x2;
4026 op_rev = Q ? Iop_Sar32x4 : Iop_Sar32x2;
4027 op_shrn = Q ? Iop_ShrN32x4 : Iop_ShrN32x2;
4028 op_shln = Q ? Iop_ShlN32x4 : Iop_ShlN32x2;
4029 break;
4030 case 3:
4031 op = Q ? Iop_QSal64x2 : Iop_QSal64x1;
sewardjd2664472010-08-22 12:44:20 +00004032 op_add = Q ? Iop_Add64x2 : Iop_Add64;
4033 op_rev = Q ? Iop_Sar64x2 : Iop_Sar64;
4034 op_shrn = Q ? Iop_ShrN64x2 : Iop_Shr64;
4035 op_shln = Q ? Iop_ShlN64x2 : Iop_Shl64;
4036 break;
4037 default:
4038 vassert(0);
4039 }
4040 }
4041 if (Q) {
4042 tmp = newTemp(Ity_V128);
4043 shval = newTemp(Ity_V128);
4044 mask = newTemp(Ity_V128);
4045 } else {
4046 tmp = newTemp(Ity_I64);
4047 shval = newTemp(Ity_I64);
4048 mask = newTemp(Ity_I64);
4049 }
4050 /* Only least significant byte from second argument is used.
4051 Copy this byte to the whole vector element. */
4052 assign(shval, binop(op_shrn,
4053 binop(op_shln,
4054 mkexpr(arg_n),
4055 mkU8((8 << size) - 8)),
4056 mkU8((8 << size) - 8)));
4057 for (i = 0; i < size; i++) {
4058 old_shval = shval;
4059 shval = newTemp(Q ? Ity_V128 : Ity_I64);
4060 assign(shval, binop(Q ? Iop_OrV128 : Iop_Or64,
4061 mkexpr(old_shval),
4062 binop(op_shln,
4063 mkexpr(old_shval),
4064 mkU8(8 << i))));
4065 }
4066 /* Compute the result */
4067 assign(round, binop(Q ? Iop_AndV128 : Iop_And64,
4068 binop(op,
4069 mkexpr(arg_m),
4070 binop(op_add,
4071 mkexpr(arg_n),
4072 mkexpr(imm_val))),
4073 binop(Q ? Iop_AndV128 : Iop_And64,
4074 mkexpr(imm_val),
4075 binop(cmp_gt,
4076 Q ? mkU128(0) : mkU64(0),
4077 mkexpr(arg_n)))));
4078 assign(res, binop(op_add,
4079 binop(op, mkexpr(arg_m), mkexpr(arg_n)),
4080 mkexpr(round)));
sewardjd2664472010-08-22 12:44:20 +00004081 /* If shift is greater or equal to the element size and element is
4082 non-zero, then QC flag should be set. */
4083 esize = (8 << size) - 1;
4084 esize = (esize << 8) | esize;
4085 esize = (esize << 16) | esize;
4086 esize = (esize << 32) | esize;
4087 setFlag_QC(binop(Q ? Iop_AndV128 : Iop_And64,
4088 binop(cmp_gt, mkexpr(shval),
4089 Q ? mkU128(esize) : mkU64(esize)),
4090 unop(cmp_neq, mkexpr(arg_m))),
4091 Q ? mkU128(0) : mkU64(0),
4092 Q, condT);
4093 /* Othervise QC flag should be set if shift value is positive and
4094 result beign rightshifted the same value is not equal to left
4095 argument. */
4096 assign(mask, binop(cmp_gt, mkexpr(shval),
4097 Q ? mkU128(0) : mkU64(0)));
4098 if (!Q && size == 3)
4099 assign(tmp, binop(op_rev, mkexpr(res),
4100 unop(Iop_64to8, mkexpr(arg_n))));
4101 else
4102 assign(tmp, binop(op_rev, mkexpr(res), mkexpr(arg_n)));
4103 setFlag_QC(binop(Q ? Iop_AndV128 : Iop_And64,
4104 mkexpr(tmp), mkexpr(mask)),
4105 binop(Q ? Iop_AndV128 : Iop_And64,
4106 mkexpr(arg_m), mkexpr(mask)),
4107 Q, condT);
sewardjd2664472010-08-22 12:44:20 +00004108 DIP("vqrshl.%c%u %c%u, %c%u, %c%u\n",
4109 U ? 'u' : 's', 8 << size,
4110 Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', mreg, Q ? 'q' : 'd',
4111 nreg);
4112 }
4113 break;
4114 case 6:
4115 /* VMAX, VMIN */
4116 if (B == 0) {
4117 /* VMAX */
4118 IROp op;
4119 if (U == 0) {
4120 switch (size) {
4121 case 0: op = Q ? Iop_Max8Sx16 : Iop_Max8Sx8; break;
4122 case 1: op = Q ? Iop_Max16Sx8 : Iop_Max16Sx4; break;
4123 case 2: op = Q ? Iop_Max32Sx4 : Iop_Max32Sx2; break;
4124 case 3: return False;
4125 default: vassert(0);
4126 }
4127 } else {
4128 switch (size) {
4129 case 0: op = Q ? Iop_Max8Ux16 : Iop_Max8Ux8; break;
4130 case 1: op = Q ? Iop_Max16Ux8 : Iop_Max16Ux4; break;
4131 case 2: op = Q ? Iop_Max32Ux4 : Iop_Max32Ux2; break;
4132 case 3: return False;
4133 default: vassert(0);
4134 }
4135 }
4136 assign(res, binop(op, mkexpr(arg_n), mkexpr(arg_m)));
4137 DIP("vmax.%c%u %c%u, %c%u, %c%u\n",
4138 U ? 'u' : 's', 8 << size,
4139 Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', nreg, Q ? 'q' : 'd',
4140 mreg);
4141 } else {
4142 /* VMIN */
4143 IROp op;
4144 if (U == 0) {
4145 switch (size) {
4146 case 0: op = Q ? Iop_Min8Sx16 : Iop_Min8Sx8; break;
4147 case 1: op = Q ? Iop_Min16Sx8 : Iop_Min16Sx4; break;
4148 case 2: op = Q ? Iop_Min32Sx4 : Iop_Min32Sx2; break;
4149 case 3: return False;
4150 default: vassert(0);
4151 }
4152 } else {
4153 switch (size) {
sewardjb0d80ea2010-10-06 20:47:22 +00004154 case 0: op = Q ? Iop_Min8Ux16 : Iop_Min8Ux8; break;
4155 case 1: op = Q ? Iop_Min16Ux8 : Iop_Min16Ux4; break;
4156 case 2: op = Q ? Iop_Min32Ux4 : Iop_Min32Ux2; break;
sewardjd2664472010-08-22 12:44:20 +00004157 case 3: return False;
4158 default: vassert(0);
4159 }
4160 }
4161 assign(res, binop(op, mkexpr(arg_n), mkexpr(arg_m)));
4162 DIP("vmin.%c%u %c%u, %c%u, %c%u\n",
4163 U ? 'u' : 's', 8 << size,
4164 Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', nreg, Q ? 'q' : 'd',
4165 mreg);
4166 }
4167 break;
4168 case 7:
4169 if (B == 0) {
4170 /* VABD */
4171 IROp op_cmp, op_sub;
4172 IRTemp cond;
4173 if ((theInstr >> 23) & 1) {
4174 vpanic("VABDL should not be in dis_neon_data_3same\n");
4175 }
4176 if (Q) {
4177 switch (size) {
4178 case 0:
4179 op_cmp = U ? Iop_CmpGT8Ux16 : Iop_CmpGT8Sx16;
4180 op_sub = Iop_Sub8x16;
4181 break;
4182 case 1:
4183 op_cmp = U ? Iop_CmpGT16Ux8 : Iop_CmpGT16Sx8;
4184 op_sub = Iop_Sub16x8;
4185 break;
4186 case 2:
4187 op_cmp = U ? Iop_CmpGT32Ux4 : Iop_CmpGT32Sx4;
4188 op_sub = Iop_Sub32x4;
4189 break;
4190 case 3:
4191 return False;
4192 default:
4193 vassert(0);
4194 }
4195 } else {
4196 switch (size) {
4197 case 0:
4198 op_cmp = U ? Iop_CmpGT8Ux8 : Iop_CmpGT8Sx8;
4199 op_sub = Iop_Sub8x8;
4200 break;
4201 case 1:
4202 op_cmp = U ? Iop_CmpGT16Ux4 : Iop_CmpGT16Sx4;
4203 op_sub = Iop_Sub16x4;
4204 break;
4205 case 2:
4206 op_cmp = U ? Iop_CmpGT32Ux2 : Iop_CmpGT32Sx2;
4207 op_sub = Iop_Sub32x2;
4208 break;
4209 case 3:
4210 return False;
4211 default:
4212 vassert(0);
4213 }
4214 }
4215 if (Q) {
4216 cond = newTemp(Ity_V128);
4217 } else {
4218 cond = newTemp(Ity_I64);
4219 }
4220 assign(cond, binop(op_cmp, mkexpr(arg_n), mkexpr(arg_m)));
4221 assign(res, binop(Q ? Iop_OrV128 : Iop_Or64,
4222 binop(Q ? Iop_AndV128 : Iop_And64,
4223 binop(op_sub, mkexpr(arg_n),
4224 mkexpr(arg_m)),
4225 mkexpr(cond)),
4226 binop(Q ? Iop_AndV128 : Iop_And64,
4227 binop(op_sub, mkexpr(arg_m),
4228 mkexpr(arg_n)),
4229 unop(Q ? Iop_NotV128 : Iop_Not64,
4230 mkexpr(cond)))));
4231 DIP("vabd.%c%u %c%u, %c%u, %c%u\n",
4232 U ? 'u' : 's', 8 << size,
4233 Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', nreg, Q ? 'q' : 'd',
4234 mreg);
4235 } else {
4236 /* VABA */
4237 IROp op_cmp, op_sub, op_add;
4238 IRTemp cond, acc, tmp;
4239 if ((theInstr >> 23) & 1) {
4240 vpanic("VABAL should not be in dis_neon_data_3same");
4241 }
4242 if (Q) {
4243 switch (size) {
4244 case 0:
4245 op_cmp = U ? Iop_CmpGT8Ux16 : Iop_CmpGT8Sx16;
4246 op_sub = Iop_Sub8x16;
4247 op_add = Iop_Add8x16;
4248 break;
4249 case 1:
4250 op_cmp = U ? Iop_CmpGT16Ux8 : Iop_CmpGT16Sx8;
4251 op_sub = Iop_Sub16x8;
4252 op_add = Iop_Add16x8;
4253 break;
4254 case 2:
4255 op_cmp = U ? Iop_CmpGT32Ux4 : Iop_CmpGT32Sx4;
4256 op_sub = Iop_Sub32x4;
4257 op_add = Iop_Add32x4;
4258 break;
4259 case 3:
4260 return False;
4261 default:
4262 vassert(0);
4263 }
4264 } else {
4265 switch (size) {
4266 case 0:
4267 op_cmp = U ? Iop_CmpGT8Ux8 : Iop_CmpGT8Sx8;
4268 op_sub = Iop_Sub8x8;
4269 op_add = Iop_Add8x8;
4270 break;
4271 case 1:
4272 op_cmp = U ? Iop_CmpGT16Ux4 : Iop_CmpGT16Sx4;
4273 op_sub = Iop_Sub16x4;
4274 op_add = Iop_Add16x4;
4275 break;
4276 case 2:
4277 op_cmp = U ? Iop_CmpGT32Ux2 : Iop_CmpGT32Sx2;
4278 op_sub = Iop_Sub32x2;
4279 op_add = Iop_Add32x2;
4280 break;
4281 case 3:
4282 return False;
4283 default:
4284 vassert(0);
4285 }
4286 }
4287 if (Q) {
4288 cond = newTemp(Ity_V128);
4289 acc = newTemp(Ity_V128);
4290 tmp = newTemp(Ity_V128);
4291 assign(acc, getQReg(dreg));
4292 } else {
4293 cond = newTemp(Ity_I64);
4294 acc = newTemp(Ity_I64);
4295 tmp = newTemp(Ity_I64);
4296 assign(acc, getDRegI64(dreg));
4297 }
4298 assign(cond, binop(op_cmp, mkexpr(arg_n), mkexpr(arg_m)));
4299 assign(tmp, binop(Q ? Iop_OrV128 : Iop_Or64,
4300 binop(Q ? Iop_AndV128 : Iop_And64,
4301 binop(op_sub, mkexpr(arg_n),
4302 mkexpr(arg_m)),
4303 mkexpr(cond)),
4304 binop(Q ? Iop_AndV128 : Iop_And64,
4305 binop(op_sub, mkexpr(arg_m),
4306 mkexpr(arg_n)),
4307 unop(Q ? Iop_NotV128 : Iop_Not64,
4308 mkexpr(cond)))));
4309 assign(res, binop(op_add, mkexpr(acc), mkexpr(tmp)));
4310 DIP("vaba.%c%u %c%u, %c%u, %c%u\n",
4311 U ? 'u' : 's', 8 << size,
4312 Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', nreg, Q ? 'q' : 'd',
4313 mreg);
4314 }
4315 break;
4316 case 8:
4317 if (B == 0) {
4318 IROp op;
4319 if (U == 0) {
4320 /* VADD */
4321 switch (size) {
4322 case 0: op = Q ? Iop_Add8x16 : Iop_Add8x8; break;
4323 case 1: op = Q ? Iop_Add16x8 : Iop_Add16x4; break;
4324 case 2: op = Q ? Iop_Add32x4 : Iop_Add32x2; break;
4325 case 3: op = Q ? Iop_Add64x2 : Iop_Add64; break;
4326 default: vassert(0);
4327 }
4328 DIP("vadd.i%u %c%u, %c%u, %c%u\n",
4329 8 << size, Q ? 'q' : 'd',
4330 dreg, Q ? 'q' : 'd', nreg, Q ? 'q' : 'd', mreg);
4331 } else {
4332 /* VSUB */
4333 switch (size) {
4334 case 0: op = Q ? Iop_Sub8x16 : Iop_Sub8x8; break;
4335 case 1: op = Q ? Iop_Sub16x8 : Iop_Sub16x4; break;
4336 case 2: op = Q ? Iop_Sub32x4 : Iop_Sub32x2; break;
4337 case 3: op = Q ? Iop_Sub64x2 : Iop_Sub64; break;
4338 default: vassert(0);
4339 }
4340 DIP("vsub.i%u %c%u, %c%u, %c%u\n",
4341 8 << size, Q ? 'q' : 'd',
4342 dreg, Q ? 'q' : 'd', nreg, Q ? 'q' : 'd', mreg);
4343 }
4344 assign(res, binop(op, mkexpr(arg_n), mkexpr(arg_m)));
4345 } else {
4346 IROp op;
4347 switch (size) {
4348 case 0: op = Q ? Iop_CmpNEZ8x16 : Iop_CmpNEZ8x8; break;
4349 case 1: op = Q ? Iop_CmpNEZ16x8 : Iop_CmpNEZ16x4; break;
4350 case 2: op = Q ? Iop_CmpNEZ32x4 : Iop_CmpNEZ32x2; break;
4351 case 3: op = Q ? Iop_CmpNEZ64x2 : Iop_CmpwNEZ64; break;
4352 default: vassert(0);
4353 }
4354 if (U == 0) {
4355 /* VTST */
4356 assign(res, unop(op, binop(Q ? Iop_AndV128 : Iop_And64,
4357 mkexpr(arg_n),
4358 mkexpr(arg_m))));
4359 DIP("vtst.%u %c%u, %c%u, %c%u\n",
4360 8 << size, Q ? 'q' : 'd',
4361 dreg, Q ? 'q' : 'd', nreg, Q ? 'q' : 'd', mreg);
4362 } else {
4363 /* VCEQ */
4364 assign(res, unop(Q ? Iop_NotV128 : Iop_Not64,
4365 unop(op,
4366 binop(Q ? Iop_XorV128 : Iop_Xor64,
4367 mkexpr(arg_n),
4368 mkexpr(arg_m)))));
4369 DIP("vceq.i%u %c%u, %c%u, %c%u\n",
4370 8 << size, Q ? 'q' : 'd',
4371 dreg, Q ? 'q' : 'd', nreg, Q ? 'q' : 'd', mreg);
4372 }
4373 }
4374 break;
4375 case 9:
4376 if (B == 0) {
4377 /* VMLA, VMLS (integer) */
4378 IROp op, op2;
4379 UInt P = (theInstr >> 24) & 1;
4380 if (P) {
4381 switch (size) {
4382 case 0:
4383 op = Q ? Iop_Mul8x16 : Iop_Mul8x8;
4384 op2 = Q ? Iop_Sub8x16 : Iop_Sub8x8;
4385 break;
4386 case 1:
4387 op = Q ? Iop_Mul16x8 : Iop_Mul16x4;
4388 op2 = Q ? Iop_Sub16x8 : Iop_Sub16x4;
4389 break;
4390 case 2:
4391 op = Q ? Iop_Mul32x4 : Iop_Mul32x2;
4392 op2 = Q ? Iop_Sub32x4 : Iop_Sub32x2;
4393 break;
4394 case 3:
4395 return False;
4396 default:
4397 vassert(0);
4398 }
4399 } else {
4400 switch (size) {
4401 case 0:
4402 op = Q ? Iop_Mul8x16 : Iop_Mul8x8;
4403 op2 = Q ? Iop_Add8x16 : Iop_Add8x8;
4404 break;
4405 case 1:
4406 op = Q ? Iop_Mul16x8 : Iop_Mul16x4;
4407 op2 = Q ? Iop_Add16x8 : Iop_Add16x4;
4408 break;
4409 case 2:
4410 op = Q ? Iop_Mul32x4 : Iop_Mul32x2;
4411 op2 = Q ? Iop_Add32x4 : Iop_Add32x2;
4412 break;
4413 case 3:
4414 return False;
4415 default:
4416 vassert(0);
4417 }
4418 }
4419 assign(res, binop(op2,
4420 Q ? getQReg(dreg) : getDRegI64(dreg),
4421 binop(op, mkexpr(arg_n), mkexpr(arg_m))));
4422 DIP("vml%c.i%u %c%u, %c%u, %c%u\n",
4423 P ? 's' : 'a', 8 << size,
4424 Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', nreg, Q ? 'q' : 'd',
4425 mreg);
4426 } else {
4427 /* VMUL */
4428 IROp op;
4429 UInt P = (theInstr >> 24) & 1;
4430 if (P) {
4431 switch (size) {
4432 case 0:
4433 op = Q ? Iop_PolynomialMul8x16 : Iop_PolynomialMul8x8;
4434 break;
4435 case 1: case 2: case 3: return False;
4436 default: vassert(0);
4437 }
4438 } else {
4439 switch (size) {
4440 case 0: op = Q ? Iop_Mul8x16 : Iop_Mul8x8; break;
4441 case 1: op = Q ? Iop_Mul16x8 : Iop_Mul16x4; break;
4442 case 2: op = Q ? Iop_Mul32x4 : Iop_Mul32x2; break;
4443 case 3: return False;
4444 default: vassert(0);
4445 }
4446 }
4447 assign(res, binop(op, mkexpr(arg_n), mkexpr(arg_m)));
4448 DIP("vmul.%c%u %c%u, %c%u, %c%u\n",
4449 P ? 'p' : 'i', 8 << size,
4450 Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', nreg, Q ? 'q' : 'd',
4451 mreg);
4452 }
4453 break;
4454 case 10: {
4455 /* VPMAX, VPMIN */
4456 UInt P = (theInstr >> 4) & 1;
4457 IROp op;
4458 if (Q)
4459 return False;
4460 if (P) {
4461 switch (size) {
4462 case 0: op = U ? Iop_PwMin8Ux8 : Iop_PwMin8Sx8; break;
4463 case 1: op = U ? Iop_PwMin16Ux4 : Iop_PwMin16Sx4; break;
4464 case 2: op = U ? Iop_PwMin32Ux2 : Iop_PwMin32Sx2; break;
4465 case 3: return False;
4466 default: vassert(0);
4467 }
4468 } else {
4469 switch (size) {
4470 case 0: op = U ? Iop_PwMax8Ux8 : Iop_PwMax8Sx8; break;
4471 case 1: op = U ? Iop_PwMax16Ux4 : Iop_PwMax16Sx4; break;
4472 case 2: op = U ? Iop_PwMax32Ux2 : Iop_PwMax32Sx2; break;
4473 case 3: return False;
4474 default: vassert(0);
4475 }
4476 }
4477 assign(res, binop(op, mkexpr(arg_n), mkexpr(arg_m)));
4478 DIP("vp%s.%c%u %c%u, %c%u, %c%u\n",
4479 P ? "min" : "max", U ? 'u' : 's',
4480 8 << size, Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', nreg,
4481 Q ? 'q' : 'd', mreg);
4482 break;
4483 }
4484 case 11:
4485 if (B == 0) {
4486 if (U == 0) {
4487 /* VQDMULH */
4488 IROp op ,op2;
4489 ULong imm;
4490 switch (size) {
4491 case 0: case 3:
4492 return False;
4493 case 1:
4494 op = Q ? Iop_QDMulHi16Sx8 : Iop_QDMulHi16Sx4;
4495 op2 = Q ? Iop_CmpEQ16x8 : Iop_CmpEQ16x4;
4496 imm = 1LL << 15;
4497 imm = (imm << 16) | imm;
4498 imm = (imm << 32) | imm;
4499 break;
4500 case 2:
4501 op = Q ? Iop_QDMulHi32Sx4 : Iop_QDMulHi32Sx2;
4502 op2 = Q ? Iop_CmpEQ32x4 : Iop_CmpEQ32x2;
4503 imm = 1LL << 31;
4504 imm = (imm << 32) | imm;
4505 break;
4506 default:
4507 vassert(0);
4508 }
4509 assign(res, binop(op, mkexpr(arg_n), mkexpr(arg_m)));
sewardjd2664472010-08-22 12:44:20 +00004510 setFlag_QC(binop(Q ? Iop_AndV128 : Iop_And64,
4511 binop(op2, mkexpr(arg_n),
4512 Q ? mkU128(imm) : mkU64(imm)),
4513 binop(op2, mkexpr(arg_m),
4514 Q ? mkU128(imm) : mkU64(imm))),
4515 Q ? mkU128(0) : mkU64(0),
4516 Q, condT);
sewardjd2664472010-08-22 12:44:20 +00004517 DIP("vqdmulh.s%u %c%u, %c%u, %c%u\n",
4518 8 << size, Q ? 'q' : 'd',
4519 dreg, Q ? 'q' : 'd', nreg, Q ? 'q' : 'd', mreg);
4520 } else {
4521 /* VQRDMULH */
4522 IROp op ,op2;
4523 ULong imm;
4524 switch(size) {
4525 case 0: case 3:
4526 return False;
4527 case 1:
4528 imm = 1LL << 15;
4529 imm = (imm << 16) | imm;
4530 imm = (imm << 32) | imm;
4531 op = Q ? Iop_QRDMulHi16Sx8 : Iop_QRDMulHi16Sx4;
4532 op2 = Q ? Iop_CmpEQ16x8 : Iop_CmpEQ16x4;
4533 break;
4534 case 2:
4535 imm = 1LL << 31;
4536 imm = (imm << 32) | imm;
4537 op = Q ? Iop_QRDMulHi32Sx4 : Iop_QRDMulHi32Sx2;
4538 op2 = Q ? Iop_CmpEQ32x4 : Iop_CmpEQ32x2;
4539 break;
4540 default:
4541 vassert(0);
4542 }
4543 assign(res, binop(op, mkexpr(arg_n), mkexpr(arg_m)));
sewardjd2664472010-08-22 12:44:20 +00004544 setFlag_QC(binop(Q ? Iop_AndV128 : Iop_And64,
4545 binop(op2, mkexpr(arg_n),
4546 Q ? mkU128(imm) : mkU64(imm)),
4547 binop(op2, mkexpr(arg_m),
4548 Q ? mkU128(imm) : mkU64(imm))),
4549 Q ? mkU128(0) : mkU64(0),
4550 Q, condT);
sewardjd2664472010-08-22 12:44:20 +00004551 DIP("vqrdmulh.s%u %c%u, %c%u, %c%u\n",
4552 8 << size, Q ? 'q' : 'd',
4553 dreg, Q ? 'q' : 'd', nreg, Q ? 'q' : 'd', mreg);
4554 }
4555 } else {
4556 if (U == 0) {
4557 /* VPADD */
4558 IROp op;
4559 if (Q)
4560 return False;
4561 switch (size) {
4562 case 0: op = Q ? Iop_PwAdd8x16 : Iop_PwAdd8x8; break;
4563 case 1: op = Q ? Iop_PwAdd16x8 : Iop_PwAdd16x4; break;
4564 case 2: op = Q ? Iop_PwAdd32x4 : Iop_PwAdd32x2; break;
4565 case 3: return False;
4566 default: vassert(0);
4567 }
4568 assign(res, binop(op, mkexpr(arg_n), mkexpr(arg_m)));
4569 DIP("vpadd.i%d %c%u, %c%u, %c%u\n",
4570 8 << size, Q ? 'q' : 'd',
4571 dreg, Q ? 'q' : 'd', nreg, Q ? 'q' : 'd', mreg);
4572 }
4573 }
4574 break;
4575 /* Starting from here these are FP SIMD cases */
4576 case 13:
4577 if (B == 0) {
4578 IROp op;
4579 if (U == 0) {
4580 if ((C >> 1) == 0) {
4581 /* VADD */
4582 op = Q ? Iop_Add32Fx4 : Iop_Add32Fx2 ;
4583 DIP("vadd.f32 %c%u, %c%u, %c%u\n",
4584 Q ? 'q' : 'd', dreg,
4585 Q ? 'q' : 'd', nreg, Q ? 'q' : 'd', mreg);
4586 } else {
4587 /* VSUB */
4588 op = Q ? Iop_Sub32Fx4 : Iop_Sub32Fx2 ;
4589 DIP("vsub.f32 %c%u, %c%u, %c%u\n",
4590 Q ? 'q' : 'd', dreg,
4591 Q ? 'q' : 'd', nreg, Q ? 'q' : 'd', mreg);
4592 }
4593 } else {
4594 if ((C >> 1) == 0) {
4595 /* VPADD */
4596 if (Q)
4597 return False;
4598 op = Iop_PwAdd32Fx2;
4599 DIP("vpadd.f32 d%u, d%u, d%u\n", dreg, nreg, mreg);
4600 } else {
4601 /* VABD */
4602 if (Q) {
4603 assign(res, unop(Iop_Abs32Fx4,
4604 binop(Iop_Sub32Fx4,
4605 mkexpr(arg_n),
4606 mkexpr(arg_m))));
4607 } else {
4608 assign(res, unop(Iop_Abs32Fx2,
4609 binop(Iop_Sub32Fx2,
4610 mkexpr(arg_n),
4611 mkexpr(arg_m))));
4612 }
4613 DIP("vabd.f32 %c%u, %c%u, %c%u\n",
4614 Q ? 'q' : 'd', dreg,
4615 Q ? 'q' : 'd', nreg, Q ? 'q' : 'd', mreg);
4616 break;
4617 }
4618 }
4619 assign(res, binop(op, mkexpr(arg_n), mkexpr(arg_m)));
4620 } else {
4621 if (U == 0) {
4622 /* VMLA, VMLS */
4623 IROp op, op2;
4624 UInt P = (theInstr >> 21) & 1;
4625 if (P) {
4626 switch (size & 1) {
4627 case 0:
4628 op = Q ? Iop_Mul32Fx4 : Iop_Mul32Fx2;
4629 op2 = Q ? Iop_Sub32Fx4 : Iop_Sub32Fx2;
4630 break;
4631 case 1: return False;
4632 default: vassert(0);
4633 }
4634 } else {
4635 switch (size & 1) {
4636 case 0:
4637 op = Q ? Iop_Mul32Fx4 : Iop_Mul32Fx2;
4638 op2 = Q ? Iop_Add32Fx4 : Iop_Add32Fx2;
4639 break;
4640 case 1: return False;
4641 default: vassert(0);
4642 }
4643 }
4644 assign(res, binop(op2,
4645 Q ? getQReg(dreg) : getDRegI64(dreg),
4646 binop(op, mkexpr(arg_n), mkexpr(arg_m))));
4647
4648 DIP("vml%c.f32 %c%u, %c%u, %c%u\n",
4649 P ? 's' : 'a', Q ? 'q' : 'd',
4650 dreg, Q ? 'q' : 'd', nreg, Q ? 'q' : 'd', mreg);
4651 } else {
4652 /* VMUL */
4653 IROp op;
4654 if ((C >> 1) != 0)
4655 return False;
4656 op = Q ? Iop_Mul32Fx4 : Iop_Mul32Fx2 ;
4657 assign(res, binop(op, mkexpr(arg_n), mkexpr(arg_m)));
4658 DIP("vmul.f32 %c%u, %c%u, %c%u\n",
4659 Q ? 'q' : 'd', dreg,
4660 Q ? 'q' : 'd', nreg, Q ? 'q' : 'd', mreg);
4661 }
4662 }
4663 break;
4664 case 14:
4665 if (B == 0) {
4666 if (U == 0) {
4667 if ((C >> 1) == 0) {
4668 /* VCEQ */
4669 IROp op;
4670 if ((theInstr >> 20) & 1)
4671 return False;
4672 op = Q ? Iop_CmpEQ32Fx4 : Iop_CmpEQ32Fx2;
4673 assign(res, binop(op, mkexpr(arg_n), mkexpr(arg_m)));
4674 DIP("vceq.f32 %c%u, %c%u, %c%u\n",
4675 Q ? 'q' : 'd', dreg,
4676 Q ? 'q' : 'd', nreg, Q ? 'q' : 'd', mreg);
4677 } else {
4678 return False;
4679 }
4680 } else {
4681 if ((C >> 1) == 0) {
4682 /* VCGE */
4683 IROp op;
4684 if ((theInstr >> 20) & 1)
4685 return False;
4686 op = Q ? Iop_CmpGE32Fx4 : Iop_CmpGE32Fx2;
4687 assign(res, binop(op, mkexpr(arg_n), mkexpr(arg_m)));
4688 DIP("vcge.f32 %c%u, %c%u, %c%u\n",
4689 Q ? 'q' : 'd', dreg,
4690 Q ? 'q' : 'd', nreg, Q ? 'q' : 'd', mreg);
4691 } else {
4692 /* VCGT */
4693 IROp op;
4694 if ((theInstr >> 20) & 1)
4695 return False;
4696 op = Q ? Iop_CmpGT32Fx4 : Iop_CmpGT32Fx2;
4697 assign(res, binop(op, mkexpr(arg_n), mkexpr(arg_m)));
4698 DIP("vcgt.f32 %c%u, %c%u, %c%u\n",
4699 Q ? 'q' : 'd', dreg,
4700 Q ? 'q' : 'd', nreg, Q ? 'q' : 'd', mreg);
4701 }
4702 }
4703 } else {
4704 if (U == 1) {
4705 /* VACGE, VACGT */
4706 UInt op_bit = (theInstr >> 21) & 1;
4707 IROp op, op2;
4708 op2 = Q ? Iop_Abs32Fx4 : Iop_Abs32Fx2;
4709 if (op_bit) {
4710 op = Q ? Iop_CmpGT32Fx4 : Iop_CmpGT32Fx2;
4711 assign(res, binop(op,
4712 unop(op2, mkexpr(arg_n)),
4713 unop(op2, mkexpr(arg_m))));
4714 } else {
4715 op = Q ? Iop_CmpGE32Fx4 : Iop_CmpGE32Fx2;
4716 assign(res, binop(op,
4717 unop(op2, mkexpr(arg_n)),
4718 unop(op2, mkexpr(arg_m))));
4719 }
4720 DIP("vacg%c.f32 %c%u, %c%u, %c%u\n", op_bit ? 't' : 'e',
4721 Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', nreg,
4722 Q ? 'q' : 'd', mreg);
4723 }
4724 }
4725 break;
4726 case 15:
4727 if (B == 0) {
4728 if (U == 0) {
4729 /* VMAX, VMIN */
4730 IROp op;
4731 if ((theInstr >> 20) & 1)
4732 return False;
4733 if ((theInstr >> 21) & 1) {
4734 op = Q ? Iop_Min32Fx4 : Iop_Min32Fx2;
4735 DIP("vmin.f32 %c%u, %c%u, %c%u\n", Q ? 'q' : 'd', dreg,
4736 Q ? 'q' : 'd', nreg, Q ? 'q' : 'd', mreg);
4737 } else {
4738 op = Q ? Iop_Max32Fx4 : Iop_Max32Fx2;
4739 DIP("vmax.f32 %c%u, %c%u, %c%u\n", Q ? 'q' : 'd', dreg,
4740 Q ? 'q' : 'd', nreg, Q ? 'q' : 'd', mreg);
4741 }
4742 assign(res, binop(op, mkexpr(arg_n), mkexpr(arg_m)));
4743 } else {
4744 /* VPMAX, VPMIN */
4745 IROp op;
4746 if (Q)
4747 return False;
4748 if ((theInstr >> 20) & 1)
4749 return False;
4750 if ((theInstr >> 21) & 1) {
4751 op = Iop_PwMin32Fx2;
4752 DIP("vpmin.f32 d%u, d%u, d%u\n", dreg, nreg, mreg);
4753 } else {
4754 op = Iop_PwMax32Fx2;
4755 DIP("vpmax.f32 d%u, d%u, d%u\n", dreg, nreg, mreg);
4756 }
4757 assign(res, binop(op, mkexpr(arg_n), mkexpr(arg_m)));
4758 }
4759 } else {
4760 if (U == 0) {
4761 if ((C >> 1) == 0) {
4762 /* VRECPS */
4763 if ((theInstr >> 20) & 1)
4764 return False;
4765 assign(res, binop(Q ? Iop_Recps32Fx4 : Iop_Recps32Fx2,
4766 mkexpr(arg_n),
4767 mkexpr(arg_m)));
4768 DIP("vrecps.f32 %c%u, %c%u, %c%u\n", Q ? 'q' : 'd', dreg,
4769 Q ? 'q' : 'd', nreg, Q ? 'q' : 'd', mreg);
4770 } else {
4771 /* VRSQRTS */
4772 if ((theInstr >> 20) & 1)
4773 return False;
4774 assign(res, binop(Q ? Iop_Rsqrts32Fx4 : Iop_Rsqrts32Fx2,
4775 mkexpr(arg_n),
4776 mkexpr(arg_m)));
4777 DIP("vrsqrts.f32 %c%u, %c%u, %c%u\n", Q ? 'q' : 'd', dreg,
4778 Q ? 'q' : 'd', nreg, Q ? 'q' : 'd', mreg);
4779 }
4780 }
4781 }
4782 break;
4783 }
4784
4785 if (Q) {
4786 putQReg(dreg, mkexpr(res), condT);
4787 } else {
4788 putDRegI64(dreg, mkexpr(res), condT);
4789 }
4790
4791 return True;
4792}
4793
4794/* A7.4.2 Three registers of different length */
4795static
4796Bool dis_neon_data_3diff ( UInt theInstr, IRTemp condT )
4797{
4798 UInt A = (theInstr >> 8) & 0xf;
4799 UInt B = (theInstr >> 20) & 3;
4800 UInt U = (theInstr >> 24) & 1;
4801 UInt P = (theInstr >> 9) & 1;
4802 UInt mreg = get_neon_m_regno(theInstr);
4803 UInt nreg = get_neon_n_regno(theInstr);
4804 UInt dreg = get_neon_d_regno(theInstr);
4805 UInt size = B;
4806 ULong imm;
4807 IRTemp res, arg_m, arg_n, cond, tmp;
4808 IROp cvt, cvt2, cmp, op, op2, sh, add;
4809 switch (A) {
4810 case 0: case 1: case 2: case 3:
4811 /* VADDL, VADDW, VSUBL, VSUBW */
4812 if (dreg & 1)
4813 return False;
4814 dreg >>= 1;
4815 size = B;
4816 switch (size) {
4817 case 0:
sewardj5f438dd2011-06-16 11:36:23 +00004818 cvt = U ? Iop_Widen8Uto16x8 : Iop_Widen8Sto16x8;
sewardjd2664472010-08-22 12:44:20 +00004819 op = (A & 2) ? Iop_Sub16x8 : Iop_Add16x8;
4820 break;
4821 case 1:
sewardj5f438dd2011-06-16 11:36:23 +00004822 cvt = U ? Iop_Widen16Uto32x4 : Iop_Widen16Sto32x4;
sewardjd2664472010-08-22 12:44:20 +00004823 op = (A & 2) ? Iop_Sub32x4 : Iop_Add32x4;
4824 break;
4825 case 2:
sewardj5f438dd2011-06-16 11:36:23 +00004826 cvt = U ? Iop_Widen32Uto64x2 : Iop_Widen32Sto64x2;
sewardjd2664472010-08-22 12:44:20 +00004827 op = (A & 2) ? Iop_Sub64x2 : Iop_Add64x2;
4828 break;
4829 case 3:
4830 return False;
4831 default:
4832 vassert(0);
4833 }
4834 arg_n = newTemp(Ity_V128);
4835 arg_m = newTemp(Ity_V128);
4836 if (A & 1) {
4837 if (nreg & 1)
4838 return False;
4839 nreg >>= 1;
4840 assign(arg_n, getQReg(nreg));
4841 } else {
4842 assign(arg_n, unop(cvt, getDRegI64(nreg)));
4843 }
4844 assign(arg_m, unop(cvt, getDRegI64(mreg)));
4845 putQReg(dreg, binop(op, mkexpr(arg_n), mkexpr(arg_m)),
4846 condT);
4847 DIP("v%s%c.%c%u q%u, %c%u, d%u\n", (A & 2) ? "sub" : "add",
4848 (A & 1) ? 'w' : 'l', U ? 'u' : 's', 8 << size, dreg,
4849 (A & 1) ? 'q' : 'd', nreg, mreg);
4850 return True;
4851 case 4:
4852 /* VADDHN, VRADDHN */
4853 if (mreg & 1)
4854 return False;
4855 mreg >>= 1;
4856 if (nreg & 1)
4857 return False;
4858 nreg >>= 1;
4859 size = B;
4860 switch (size) {
4861 case 0:
4862 op = Iop_Add16x8;
sewardj5f438dd2011-06-16 11:36:23 +00004863 cvt = Iop_NarrowUn16to8x8;
sewardjd2664472010-08-22 12:44:20 +00004864 sh = Iop_ShrN16x8;
4865 imm = 1U << 7;
4866 imm = (imm << 16) | imm;
4867 imm = (imm << 32) | imm;
4868 break;
4869 case 1:
4870 op = Iop_Add32x4;
sewardj5f438dd2011-06-16 11:36:23 +00004871 cvt = Iop_NarrowUn32to16x4;
sewardjd2664472010-08-22 12:44:20 +00004872 sh = Iop_ShrN32x4;
4873 imm = 1U << 15;
4874 imm = (imm << 32) | imm;
4875 break;
4876 case 2:
4877 op = Iop_Add64x2;
sewardj5f438dd2011-06-16 11:36:23 +00004878 cvt = Iop_NarrowUn64to32x2;
sewardjd2664472010-08-22 12:44:20 +00004879 sh = Iop_ShrN64x2;
4880 imm = 1U << 31;
4881 break;
4882 case 3:
4883 return False;
4884 default:
4885 vassert(0);
4886 }
4887 tmp = newTemp(Ity_V128);
4888 res = newTemp(Ity_V128);
4889 assign(tmp, binop(op, getQReg(nreg), getQReg(mreg)));
4890 if (U) {
4891 /* VRADDHN */
4892 assign(res, binop(op, mkexpr(tmp),
4893 binop(Iop_64HLtoV128, mkU64(imm), mkU64(imm))));
4894 } else {
4895 assign(res, mkexpr(tmp));
4896 }
4897 putDRegI64(dreg, unop(cvt, binop(sh, mkexpr(res), mkU8(8 << size))),
4898 condT);
4899 DIP("v%saddhn.i%u d%u, q%u, q%u\n", U ? "r" : "", 16 << size, dreg,
4900 nreg, mreg);
4901 return True;
4902 case 5:
4903 /* VABAL */
4904 if (!((theInstr >> 23) & 1)) {
4905 vpanic("VABA should not be in dis_neon_data_3diff\n");
4906 }
4907 if (dreg & 1)
4908 return False;
4909 dreg >>= 1;
4910 switch (size) {
4911 case 0:
4912 cmp = U ? Iop_CmpGT8Ux8 : Iop_CmpGT8Sx8;
sewardj5f438dd2011-06-16 11:36:23 +00004913 cvt = U ? Iop_Widen8Uto16x8 : Iop_Widen8Sto16x8;
4914 cvt2 = Iop_Widen8Sto16x8;
sewardjd2664472010-08-22 12:44:20 +00004915 op = Iop_Sub16x8;
4916 op2 = Iop_Add16x8;
4917 break;
4918 case 1:
4919 cmp = U ? Iop_CmpGT16Ux4 : Iop_CmpGT16Sx4;
sewardj5f438dd2011-06-16 11:36:23 +00004920 cvt = U ? Iop_Widen16Uto32x4 : Iop_Widen16Sto32x4;
4921 cvt2 = Iop_Widen16Sto32x4;
sewardjd2664472010-08-22 12:44:20 +00004922 op = Iop_Sub32x4;
4923 op2 = Iop_Add32x4;
4924 break;
4925 case 2:
4926 cmp = U ? Iop_CmpGT32Ux2 : Iop_CmpGT32Sx2;
sewardj5f438dd2011-06-16 11:36:23 +00004927 cvt = U ? Iop_Widen32Uto64x2 : Iop_Widen32Sto64x2;
4928 cvt2 = Iop_Widen32Sto64x2;
sewardjd2664472010-08-22 12:44:20 +00004929 op = Iop_Sub64x2;
4930 op2 = Iop_Add64x2;
4931 break;
4932 case 3:
4933 return False;
4934 default:
4935 vassert(0);
4936 }
4937 arg_n = newTemp(Ity_V128);
4938 arg_m = newTemp(Ity_V128);
4939 cond = newTemp(Ity_V128);
4940 res = newTemp(Ity_V128);
4941 assign(arg_n, unop(cvt, getDRegI64(nreg)));
4942 assign(arg_m, unop(cvt, getDRegI64(mreg)));
4943 assign(cond, unop(cvt2, binop(cmp, getDRegI64(nreg),
4944 getDRegI64(mreg))));
4945 assign(res, binop(op2,
4946 binop(Iop_OrV128,
4947 binop(Iop_AndV128,
4948 binop(op, mkexpr(arg_n), mkexpr(arg_m)),
4949 mkexpr(cond)),
4950 binop(Iop_AndV128,
4951 binop(op, mkexpr(arg_m), mkexpr(arg_n)),
4952 unop(Iop_NotV128, mkexpr(cond)))),
4953 getQReg(dreg)));
4954 putQReg(dreg, mkexpr(res), condT);
4955 DIP("vabal.%c%u q%u, d%u, d%u\n", U ? 'u' : 's', 8 << size, dreg,
4956 nreg, mreg);
4957 return True;
4958 case 6:
4959 /* VSUBHN, VRSUBHN */
4960 if (mreg & 1)
4961 return False;
4962 mreg >>= 1;
4963 if (nreg & 1)
4964 return False;
4965 nreg >>= 1;
4966 size = B;
4967 switch (size) {
4968 case 0:
4969 op = Iop_Sub16x8;
4970 op2 = Iop_Add16x8;
sewardj5f438dd2011-06-16 11:36:23 +00004971 cvt = Iop_NarrowUn16to8x8;
sewardjd2664472010-08-22 12:44:20 +00004972 sh = Iop_ShrN16x8;
4973 imm = 1U << 7;
4974 imm = (imm << 16) | imm;
4975 imm = (imm << 32) | imm;
4976 break;
4977 case 1:
4978 op = Iop_Sub32x4;
4979 op2 = Iop_Add32x4;
sewardj5f438dd2011-06-16 11:36:23 +00004980 cvt = Iop_NarrowUn32to16x4;
sewardjd2664472010-08-22 12:44:20 +00004981 sh = Iop_ShrN32x4;
4982 imm = 1U << 15;
4983 imm = (imm << 32) | imm;
4984 break;
4985 case 2:
4986 op = Iop_Sub64x2;
4987 op2 = Iop_Add64x2;
sewardj5f438dd2011-06-16 11:36:23 +00004988 cvt = Iop_NarrowUn64to32x2;
sewardjd2664472010-08-22 12:44:20 +00004989 sh = Iop_ShrN64x2;
4990 imm = 1U << 31;
4991 break;
4992 case 3:
4993 return False;
4994 default:
4995 vassert(0);
4996 }
4997 tmp = newTemp(Ity_V128);
4998 res = newTemp(Ity_V128);
4999 assign(tmp, binop(op, getQReg(nreg), getQReg(mreg)));
5000 if (U) {
5001 /* VRSUBHN */
5002 assign(res, binop(op2, mkexpr(tmp),
5003 binop(Iop_64HLtoV128, mkU64(imm), mkU64(imm))));
5004 } else {
5005 assign(res, mkexpr(tmp));
5006 }
5007 putDRegI64(dreg, unop(cvt, binop(sh, mkexpr(res), mkU8(8 << size))),
5008 condT);
5009 DIP("v%ssubhn.i%u d%u, q%u, q%u\n", U ? "r" : "", 16 << size, dreg,
5010 nreg, mreg);
5011 return True;
5012 case 7:
5013 /* VABDL */
5014 if (!((theInstr >> 23) & 1)) {
5015 vpanic("VABL should not be in dis_neon_data_3diff\n");
5016 }
5017 if (dreg & 1)
5018 return False;
5019 dreg >>= 1;
5020 switch (size) {
5021 case 0:
5022 cmp = U ? Iop_CmpGT8Ux8 : Iop_CmpGT8Sx8;
sewardj5f438dd2011-06-16 11:36:23 +00005023 cvt = U ? Iop_Widen8Uto16x8 : Iop_Widen8Sto16x8;
5024 cvt2 = Iop_Widen8Sto16x8;
sewardjd2664472010-08-22 12:44:20 +00005025 op = Iop_Sub16x8;
5026 break;
5027 case 1:
5028 cmp = U ? Iop_CmpGT16Ux4 : Iop_CmpGT16Sx4;
sewardj5f438dd2011-06-16 11:36:23 +00005029 cvt = U ? Iop_Widen16Uto32x4 : Iop_Widen16Sto32x4;
5030 cvt2 = Iop_Widen16Sto32x4;
sewardjd2664472010-08-22 12:44:20 +00005031 op = Iop_Sub32x4;
5032 break;
5033 case 2:
5034 cmp = U ? Iop_CmpGT32Ux2 : Iop_CmpGT32Sx2;
sewardj5f438dd2011-06-16 11:36:23 +00005035 cvt = U ? Iop_Widen32Uto64x2 : Iop_Widen32Sto64x2;
5036 cvt2 = Iop_Widen32Sto64x2;
sewardjd2664472010-08-22 12:44:20 +00005037 op = Iop_Sub64x2;
5038 break;
5039 case 3:
5040 return False;
5041 default:
5042 vassert(0);
5043 }
5044 arg_n = newTemp(Ity_V128);
5045 arg_m = newTemp(Ity_V128);
5046 cond = newTemp(Ity_V128);
5047 res = newTemp(Ity_V128);
5048 assign(arg_n, unop(cvt, getDRegI64(nreg)));
5049 assign(arg_m, unop(cvt, getDRegI64(mreg)));
5050 assign(cond, unop(cvt2, binop(cmp, getDRegI64(nreg),
5051 getDRegI64(mreg))));
5052 assign(res, binop(Iop_OrV128,
5053 binop(Iop_AndV128,
5054 binop(op, mkexpr(arg_n), mkexpr(arg_m)),
5055 mkexpr(cond)),
5056 binop(Iop_AndV128,
5057 binop(op, mkexpr(arg_m), mkexpr(arg_n)),
5058 unop(Iop_NotV128, mkexpr(cond)))));
5059 putQReg(dreg, mkexpr(res), condT);
5060 DIP("vabdl.%c%u q%u, d%u, d%u\n", U ? 'u' : 's', 8 << size, dreg,
5061 nreg, mreg);
5062 return True;
5063 case 8:
5064 case 10:
5065 /* VMLAL, VMLSL (integer) */
5066 if (dreg & 1)
5067 return False;
5068 dreg >>= 1;
5069 size = B;
5070 switch (size) {
5071 case 0:
5072 op = U ? Iop_Mull8Ux8 : Iop_Mull8Sx8;
5073 op2 = P ? Iop_Sub16x8 : Iop_Add16x8;
5074 break;
5075 case 1:
5076 op = U ? Iop_Mull16Ux4 : Iop_Mull16Sx4;
5077 op2 = P ? Iop_Sub32x4 : Iop_Add32x4;
5078 break;
5079 case 2:
5080 op = U ? Iop_Mull32Ux2 : Iop_Mull32Sx2;
5081 op2 = P ? Iop_Sub64x2 : Iop_Add64x2;
5082 break;
5083 case 3:
5084 return False;
5085 default:
5086 vassert(0);
5087 }
5088 res = newTemp(Ity_V128);
5089 assign(res, binop(op, getDRegI64(nreg),getDRegI64(mreg)));
5090 putQReg(dreg, binop(op2, getQReg(dreg), mkexpr(res)), condT);
5091 DIP("vml%cl.%c%u q%u, d%u, d%u\n", P ? 's' : 'a', U ? 'u' : 's',
5092 8 << size, dreg, nreg, mreg);
5093 return True;
5094 case 9:
5095 case 11:
5096 /* VQDMLAL, VQDMLSL */
5097 if (U)
5098 return False;
5099 if (dreg & 1)
5100 return False;
5101 dreg >>= 1;
5102 size = B;
5103 switch (size) {
5104 case 0: case 3:
5105 return False;
5106 case 1:
5107 op = Iop_QDMulLong16Sx4;
5108 cmp = Iop_CmpEQ16x4;
5109 add = P ? Iop_QSub32Sx4 : Iop_QAdd32Sx4;
5110 op2 = P ? Iop_Sub32x4 : Iop_Add32x4;
5111 imm = 1LL << 15;
5112 imm = (imm << 16) | imm;
5113 imm = (imm << 32) | imm;
5114 break;
5115 case 2:
5116 op = Iop_QDMulLong32Sx2;
5117 cmp = Iop_CmpEQ32x2;
5118 add = P ? Iop_QSub64Sx2 : Iop_QAdd64Sx2;
5119 op2 = P ? Iop_Sub64x2 : Iop_Add64x2;
5120 imm = 1LL << 31;
5121 imm = (imm << 32) | imm;
5122 break;
5123 default:
5124 vassert(0);
5125 }
5126 res = newTemp(Ity_V128);
5127 tmp = newTemp(Ity_V128);
5128 assign(res, binop(op, getDRegI64(nreg), getDRegI64(mreg)));
sewardjd2664472010-08-22 12:44:20 +00005129 assign(tmp, binop(op2, getQReg(dreg), mkexpr(res)));
5130 setFlag_QC(mkexpr(tmp), binop(add, getQReg(dreg), mkexpr(res)),
5131 True, condT);
5132 setFlag_QC(binop(Iop_And64,
5133 binop(cmp, getDRegI64(nreg), mkU64(imm)),
5134 binop(cmp, getDRegI64(mreg), mkU64(imm))),
5135 mkU64(0),
5136 False, condT);
sewardjd2664472010-08-22 12:44:20 +00005137 putQReg(dreg, binop(add, getQReg(dreg), mkexpr(res)), condT);
5138 DIP("vqdml%cl.s%u q%u, d%u, d%u\n", P ? 's' : 'a', 8 << size, dreg,
5139 nreg, mreg);
5140 return True;
5141 case 12:
5142 case 14:
5143 /* VMULL (integer or polynomial) */
5144 if (dreg & 1)
5145 return False;
5146 dreg >>= 1;
5147 size = B;
5148 switch (size) {
5149 case 0:
5150 op = (U) ? Iop_Mull8Ux8 : Iop_Mull8Sx8;
5151 if (P)
5152 op = Iop_PolynomialMull8x8;
5153 break;
5154 case 1:
5155 op = (U) ? Iop_Mull16Ux4 : Iop_Mull16Sx4;
5156 break;
5157 case 2:
5158 op = (U) ? Iop_Mull32Ux2 : Iop_Mull32Sx2;
5159 break;
5160 default:
5161 vassert(0);
5162 }
5163 putQReg(dreg, binop(op, getDRegI64(nreg),
5164 getDRegI64(mreg)), condT);
5165 DIP("vmull.%c%u q%u, d%u, d%u\n", P ? 'p' : (U ? 'u' : 's'),
5166 8 << size, dreg, nreg, mreg);
5167 return True;
5168 case 13:
5169 /* VQDMULL */
5170 if (U)
5171 return False;
5172 if (dreg & 1)
5173 return False;
5174 dreg >>= 1;
5175 size = B;
5176 switch (size) {
5177 case 0:
5178 case 3:
5179 return False;
5180 case 1:
5181 op = Iop_QDMulLong16Sx4;
5182 op2 = Iop_CmpEQ16x4;
5183 imm = 1LL << 15;
5184 imm = (imm << 16) | imm;
5185 imm = (imm << 32) | imm;
5186 break;
5187 case 2:
5188 op = Iop_QDMulLong32Sx2;
5189 op2 = Iop_CmpEQ32x2;
5190 imm = 1LL << 31;
5191 imm = (imm << 32) | imm;
5192 break;
5193 default:
5194 vassert(0);
5195 }
5196 putQReg(dreg, binop(op, getDRegI64(nreg), getDRegI64(mreg)),
5197 condT);
sewardjd2664472010-08-22 12:44:20 +00005198 setFlag_QC(binop(Iop_And64,
5199 binop(op2, getDRegI64(nreg), mkU64(imm)),
5200 binop(op2, getDRegI64(mreg), mkU64(imm))),
5201 mkU64(0),
5202 False, condT);
sewardjd2664472010-08-22 12:44:20 +00005203 DIP("vqdmull.s%u q%u, d%u, d%u\n", 8 << size, dreg, nreg, mreg);
5204 return True;
5205 default:
5206 return False;
5207 }
5208 return False;
5209}
5210
5211/* A7.4.3 Two registers and a scalar */
5212static
5213Bool dis_neon_data_2reg_and_scalar ( UInt theInstr, IRTemp condT )
5214{
5215# define INSN(_bMax,_bMin) SLICE_UInt(theInstr, (_bMax), (_bMin))
5216 UInt U = INSN(24,24);
5217 UInt dreg = get_neon_d_regno(theInstr & ~(1 << 6));
5218 UInt nreg = get_neon_n_regno(theInstr & ~(1 << 6));
5219 UInt mreg = get_neon_m_regno(theInstr & ~(1 << 6));
5220 UInt size = INSN(21,20);
5221 UInt index;
5222 UInt Q = INSN(24,24);
5223
5224 if (INSN(27,25) != 1 || INSN(23,23) != 1
5225 || INSN(6,6) != 1 || INSN(4,4) != 0)
5226 return False;
5227
5228 /* VMLA, VMLS (scalar) */
5229 if ((INSN(11,8) & BITS4(1,0,1,0)) == BITS4(0,0,0,0)) {
5230 IRTemp res, arg_m, arg_n;
5231 IROp dup, get, op, op2, add, sub;
5232 if (Q) {
5233 if ((dreg & 1) || (nreg & 1))
5234 return False;
5235 dreg >>= 1;
5236 nreg >>= 1;
5237 res = newTemp(Ity_V128);
5238 arg_m = newTemp(Ity_V128);
5239 arg_n = newTemp(Ity_V128);
5240 assign(arg_n, getQReg(nreg));
5241 switch(size) {
5242 case 1:
5243 dup = Iop_Dup16x8;
5244 get = Iop_GetElem16x4;
5245 index = mreg >> 3;
5246 mreg &= 7;
5247 break;
5248 case 2:
5249 dup = Iop_Dup32x4;
5250 get = Iop_GetElem32x2;
5251 index = mreg >> 4;
5252 mreg &= 0xf;
5253 break;
5254 case 0:
5255 case 3:
5256 return False;
5257 default:
5258 vassert(0);
5259 }
5260 assign(arg_m, unop(dup, binop(get, getDRegI64(mreg), mkU8(index))));
5261 } else {
5262 res = newTemp(Ity_I64);
5263 arg_m = newTemp(Ity_I64);
5264 arg_n = newTemp(Ity_I64);
5265 assign(arg_n, getDRegI64(nreg));
5266 switch(size) {
5267 case 1:
5268 dup = Iop_Dup16x4;
5269 get = Iop_GetElem16x4;
5270 index = mreg >> 3;
5271 mreg &= 7;
5272 break;
5273 case 2:
5274 dup = Iop_Dup32x2;
5275 get = Iop_GetElem32x2;
5276 index = mreg >> 4;
5277 mreg &= 0xf;
5278 break;
5279 case 0:
5280 case 3:
5281 return False;
5282 default:
5283 vassert(0);
5284 }
5285 assign(arg_m, unop(dup, binop(get, getDRegI64(mreg), mkU8(index))));
5286 }
5287 if (INSN(8,8)) {
5288 switch (size) {
5289 case 2:
5290 op = Q ? Iop_Mul32Fx4 : Iop_Mul32Fx2;
5291 add = Q ? Iop_Add32Fx4 : Iop_Add32Fx2;
5292 sub = Q ? Iop_Sub32Fx4 : Iop_Sub32Fx2;
5293 break;
5294 case 0:
5295 case 1:
5296 case 3:
5297 return False;
5298 default:
5299 vassert(0);
5300 }
5301 } else {
5302 switch (size) {
5303 case 1:
5304 op = Q ? Iop_Mul16x8 : Iop_Mul16x4;
5305 add = Q ? Iop_Add16x8 : Iop_Add16x4;
5306 sub = Q ? Iop_Sub16x8 : Iop_Sub16x4;
5307 break;
5308 case 2:
5309 op = Q ? Iop_Mul32x4 : Iop_Mul32x2;
5310 add = Q ? Iop_Add32x4 : Iop_Add32x2;
5311 sub = Q ? Iop_Sub32x4 : Iop_Sub32x2;
5312 break;
5313 case 0:
5314 case 3:
5315 return False;
5316 default:
5317 vassert(0);
5318 }
5319 }
5320 op2 = INSN(10,10) ? sub : add;
5321 assign(res, binop(op, mkexpr(arg_n), mkexpr(arg_m)));
5322 if (Q)
5323 putQReg(dreg, binop(op2, getQReg(dreg), mkexpr(res)),
5324 condT);
5325 else
5326 putDRegI64(dreg, binop(op2, getDRegI64(dreg), mkexpr(res)),
5327 condT);
5328 DIP("vml%c.%c%u %c%u, %c%u, d%u[%u]\n", INSN(10,10) ? 's' : 'a',
5329 INSN(8,8) ? 'f' : 'i', 8 << size,
5330 Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', nreg, mreg, index);
5331 return True;
5332 }
5333
5334 /* VMLAL, VMLSL (scalar) */
5335 if ((INSN(11,8) & BITS4(1,0,1,1)) == BITS4(0,0,1,0)) {
5336 IRTemp res, arg_m, arg_n;
5337 IROp dup, get, op, op2, add, sub;
5338 if (dreg & 1)
5339 return False;
5340 dreg >>= 1;
5341 res = newTemp(Ity_V128);
5342 arg_m = newTemp(Ity_I64);
5343 arg_n = newTemp(Ity_I64);
5344 assign(arg_n, getDRegI64(nreg));
5345 switch(size) {
5346 case 1:
5347 dup = Iop_Dup16x4;
5348 get = Iop_GetElem16x4;
5349 index = mreg >> 3;
5350 mreg &= 7;
5351 break;
5352 case 2:
5353 dup = Iop_Dup32x2;
5354 get = Iop_GetElem32x2;
5355 index = mreg >> 4;
5356 mreg &= 0xf;
5357 break;
5358 case 0:
5359 case 3:
5360 return False;
5361 default:
5362 vassert(0);
5363 }
5364 assign(arg_m, unop(dup, binop(get, getDRegI64(mreg), mkU8(index))));
5365 switch (size) {
5366 case 1:
5367 op = U ? Iop_Mull16Ux4 : Iop_Mull16Sx4;
5368 add = Iop_Add32x4;
5369 sub = Iop_Sub32x4;
5370 break;
5371 case 2:
5372 op = U ? Iop_Mull32Ux2 : Iop_Mull32Sx2;
5373 add = Iop_Add64x2;
5374 sub = Iop_Sub64x2;
5375 break;
5376 case 0:
5377 case 3:
5378 return False;
5379 default:
5380 vassert(0);
5381 }
5382 op2 = INSN(10,10) ? sub : add;
5383 assign(res, binop(op, mkexpr(arg_n), mkexpr(arg_m)));
5384 putQReg(dreg, binop(op2, getQReg(dreg), mkexpr(res)), condT);
5385 DIP("vml%cl.%c%u q%u, d%u, d%u[%u]\n",
5386 INSN(10,10) ? 's' : 'a', U ? 'u' : 's',
5387 8 << size, dreg, nreg, mreg, index);
5388 return True;
5389 }
5390
5391 /* VQDMLAL, VQDMLSL (scalar) */
5392 if ((INSN(11,8) & BITS4(1,0,1,1)) == BITS4(0,0,1,1) && !U) {
5393 IRTemp res, arg_m, arg_n, tmp;
5394 IROp dup, get, op, op2, add, cmp;
5395 UInt P = INSN(10,10);
5396 ULong imm;
5397 if (dreg & 1)
5398 return False;
5399 dreg >>= 1;
5400 res = newTemp(Ity_V128);
5401 arg_m = newTemp(Ity_I64);
5402 arg_n = newTemp(Ity_I64);
5403 assign(arg_n, getDRegI64(nreg));
5404 switch(size) {
5405 case 1:
5406 dup = Iop_Dup16x4;
5407 get = Iop_GetElem16x4;
5408 index = mreg >> 3;
5409 mreg &= 7;
5410 break;
5411 case 2:
5412 dup = Iop_Dup32x2;
5413 get = Iop_GetElem32x2;
5414 index = mreg >> 4;
5415 mreg &= 0xf;
5416 break;
5417 case 0:
5418 case 3:
5419 return False;
5420 default:
5421 vassert(0);
5422 }
5423 assign(arg_m, unop(dup, binop(get, getDRegI64(mreg), mkU8(index))));
5424 switch (size) {
5425 case 0:
5426 case 3:
5427 return False;
5428 case 1:
5429 op = Iop_QDMulLong16Sx4;
5430 cmp = Iop_CmpEQ16x4;
5431 add = P ? Iop_QSub32Sx4 : Iop_QAdd32Sx4;
5432 op2 = P ? Iop_Sub32x4 : Iop_Add32x4;
5433 imm = 1LL << 15;
5434 imm = (imm << 16) | imm;
5435 imm = (imm << 32) | imm;
5436 break;
5437 case 2:
5438 op = Iop_QDMulLong32Sx2;
5439 cmp = Iop_CmpEQ32x2;
5440 add = P ? Iop_QSub64Sx2 : Iop_QAdd64Sx2;
5441 op2 = P ? Iop_Sub64x2 : Iop_Add64x2;
5442 imm = 1LL << 31;
5443 imm = (imm << 32) | imm;
5444 break;
5445 default:
5446 vassert(0);
5447 }
5448 res = newTemp(Ity_V128);
5449 tmp = newTemp(Ity_V128);
5450 assign(res, binop(op, mkexpr(arg_n), mkexpr(arg_m)));
sewardjd2664472010-08-22 12:44:20 +00005451 assign(tmp, binop(op2, getQReg(dreg), mkexpr(res)));
5452 setFlag_QC(binop(Iop_And64,
5453 binop(cmp, mkexpr(arg_n), mkU64(imm)),
5454 binop(cmp, mkexpr(arg_m), mkU64(imm))),
5455 mkU64(0),
5456 False, condT);
5457 setFlag_QC(mkexpr(tmp), binop(add, getQReg(dreg), mkexpr(res)),
5458 True, condT);
sewardjd2664472010-08-22 12:44:20 +00005459 putQReg(dreg, binop(add, getQReg(dreg), mkexpr(res)), condT);
5460 DIP("vqdml%cl.s%u q%u, d%u, d%u[%u]\n", P ? 's' : 'a', 8 << size,
5461 dreg, nreg, mreg, index);
5462 return True;
5463 }
5464
5465 /* VMUL (by scalar) */
5466 if ((INSN(11,8) & BITS4(1,1,1,0)) == BITS4(1,0,0,0)) {
5467 IRTemp res, arg_m, arg_n;
5468 IROp dup, get, op;
5469 if (Q) {
5470 if ((dreg & 1) || (nreg & 1))
5471 return False;
5472 dreg >>= 1;
5473 nreg >>= 1;
5474 res = newTemp(Ity_V128);
5475 arg_m = newTemp(Ity_V128);
5476 arg_n = newTemp(Ity_V128);
5477 assign(arg_n, getQReg(nreg));
5478 switch(size) {
5479 case 1:
5480 dup = Iop_Dup16x8;
5481 get = Iop_GetElem16x4;
5482 index = mreg >> 3;
5483 mreg &= 7;
5484 break;
5485 case 2:
5486 dup = Iop_Dup32x4;
5487 get = Iop_GetElem32x2;
5488 index = mreg >> 4;
5489 mreg &= 0xf;
5490 break;
5491 case 0:
5492 case 3:
5493 return False;
5494 default:
5495 vassert(0);
5496 }
5497 assign(arg_m, unop(dup, binop(get, getDRegI64(mreg), mkU8(index))));
5498 } else {
5499 res = newTemp(Ity_I64);
5500 arg_m = newTemp(Ity_I64);
5501 arg_n = newTemp(Ity_I64);
5502 assign(arg_n, getDRegI64(nreg));
5503 switch(size) {
5504 case 1:
5505 dup = Iop_Dup16x4;
5506 get = Iop_GetElem16x4;
5507 index = mreg >> 3;
5508 mreg &= 7;
5509 break;
5510 case 2:
5511 dup = Iop_Dup32x2;
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 }
sewardja561f892011-07-19 07:37:03 +00005524 if (INSN(8,8)) {
5525 switch (size) {
5526 case 2:
5527 op = Q ? Iop_Mul32Fx4 : Iop_Mul32Fx2;
5528 break;
5529 case 0:
5530 case 1:
5531 case 3:
5532 return False;
5533 default:
5534 vassert(0);
5535 }
5536 } else {
5537 switch (size) {
5538 case 1:
5539 op = Q ? Iop_Mul16x8 : Iop_Mul16x4;
5540 break;
5541 case 2:
5542 op = Q ? Iop_Mul32x4 : Iop_Mul32x2;
5543 break;
5544 case 0:
5545 case 3:
5546 return False;
5547 default:
5548 vassert(0);
5549 }
sewardjd2664472010-08-22 12:44:20 +00005550 }
5551 assign(res, binop(op, mkexpr(arg_n), mkexpr(arg_m)));
5552 if (Q)
5553 putQReg(dreg, mkexpr(res), condT);
5554 else
5555 putDRegI64(dreg, mkexpr(res), condT);
sewardja561f892011-07-19 07:37:03 +00005556 DIP("vmul.%c%u %c%u, %c%u, d%u[%u]\n", INSN(8,8) ? 'f' : 'i',
5557 8 << size, Q ? 'q' : 'd', dreg,
sewardjd2664472010-08-22 12:44:20 +00005558 Q ? 'q' : 'd', nreg, mreg, index);
5559 return True;
5560 }
5561
5562 /* VMULL (scalar) */
5563 if (INSN(11,8) == BITS4(1,0,1,0)) {
5564 IRTemp res, arg_m, arg_n;
5565 IROp dup, get, op;
5566 if (dreg & 1)
5567 return False;
5568 dreg >>= 1;
5569 res = newTemp(Ity_V128);
5570 arg_m = newTemp(Ity_I64);
5571 arg_n = newTemp(Ity_I64);
5572 assign(arg_n, getDRegI64(nreg));
5573 switch(size) {
5574 case 1:
5575 dup = Iop_Dup16x4;
5576 get = Iop_GetElem16x4;
5577 index = mreg >> 3;
5578 mreg &= 7;
5579 break;
5580 case 2:
5581 dup = Iop_Dup32x2;
5582 get = Iop_GetElem32x2;
5583 index = mreg >> 4;
5584 mreg &= 0xf;
5585 break;
5586 case 0:
5587 case 3:
5588 return False;
5589 default:
5590 vassert(0);
5591 }
5592 assign(arg_m, unop(dup, binop(get, getDRegI64(mreg), mkU8(index))));
5593 switch (size) {
5594 case 1: op = U ? Iop_Mull16Ux4 : Iop_Mull16Sx4; break;
5595 case 2: op = U ? Iop_Mull32Ux2 : Iop_Mull32Sx2; break;
5596 case 0: case 3: return False;
5597 default: vassert(0);
5598 }
5599 assign(res, binop(op, mkexpr(arg_n), mkexpr(arg_m)));
5600 putQReg(dreg, mkexpr(res), condT);
5601 DIP("vmull.%c%u q%u, d%u, d%u[%u]\n", U ? 'u' : 's', 8 << size, dreg,
5602 nreg, mreg, index);
5603 return True;
5604 }
5605
5606 /* VQDMULL */
5607 if (INSN(11,8) == BITS4(1,0,1,1) && !U) {
5608 IROp op ,op2, dup, get;
5609 ULong imm;
sewardj06122e72011-03-28 12:14:48 +00005610 IRTemp arg_m, arg_n;
sewardjd2664472010-08-22 12:44:20 +00005611 if (dreg & 1)
5612 return False;
5613 dreg >>= 1;
sewardjd2664472010-08-22 12:44:20 +00005614 arg_m = newTemp(Ity_I64);
5615 arg_n = newTemp(Ity_I64);
5616 assign(arg_n, getDRegI64(nreg));
5617 switch(size) {
5618 case 1:
5619 dup = Iop_Dup16x4;
5620 get = Iop_GetElem16x4;
5621 index = mreg >> 3;
5622 mreg &= 7;
5623 break;
5624 case 2:
5625 dup = Iop_Dup32x2;
5626 get = Iop_GetElem32x2;
5627 index = mreg >> 4;
5628 mreg &= 0xf;
5629 break;
5630 case 0:
5631 case 3:
5632 return False;
5633 default:
5634 vassert(0);
5635 }
5636 assign(arg_m, unop(dup, binop(get, getDRegI64(mreg), mkU8(index))));
5637 switch (size) {
5638 case 0:
5639 case 3:
5640 return False;
5641 case 1:
5642 op = Iop_QDMulLong16Sx4;
5643 op2 = Iop_CmpEQ16x4;
5644 imm = 1LL << 15;
5645 imm = (imm << 16) | imm;
5646 imm = (imm << 32) | imm;
5647 break;
5648 case 2:
5649 op = Iop_QDMulLong32Sx2;
5650 op2 = Iop_CmpEQ32x2;
5651 imm = 1LL << 31;
5652 imm = (imm << 32) | imm;
5653 break;
5654 default:
5655 vassert(0);
5656 }
5657 putQReg(dreg, binop(op, mkexpr(arg_n), mkexpr(arg_m)),
5658 condT);
sewardjd2664472010-08-22 12:44:20 +00005659 setFlag_QC(binop(Iop_And64,
5660 binop(op2, mkexpr(arg_n), mkU64(imm)),
5661 binop(op2, mkexpr(arg_m), mkU64(imm))),
5662 mkU64(0),
5663 False, condT);
sewardjd2664472010-08-22 12:44:20 +00005664 DIP("vqdmull.s%u q%u, d%u, d%u[%u]\n", 8 << size, dreg, nreg, mreg,
5665 index);
5666 return True;
5667 }
5668
5669 /* VQDMULH */
5670 if (INSN(11,8) == BITS4(1,1,0,0)) {
5671 IROp op ,op2, dup, get;
5672 ULong imm;
5673 IRTemp res, arg_m, arg_n;
5674 if (Q) {
5675 if ((dreg & 1) || (nreg & 1))
5676 return False;
5677 dreg >>= 1;
5678 nreg >>= 1;
5679 res = newTemp(Ity_V128);
5680 arg_m = newTemp(Ity_V128);
5681 arg_n = newTemp(Ity_V128);
5682 assign(arg_n, getQReg(nreg));
5683 switch(size) {
5684 case 1:
5685 dup = Iop_Dup16x8;
5686 get = Iop_GetElem16x4;
5687 index = mreg >> 3;
5688 mreg &= 7;
5689 break;
5690 case 2:
5691 dup = Iop_Dup32x4;
5692 get = Iop_GetElem32x2;
5693 index = mreg >> 4;
5694 mreg &= 0xf;
5695 break;
5696 case 0:
5697 case 3:
5698 return False;
5699 default:
5700 vassert(0);
5701 }
5702 assign(arg_m, unop(dup, binop(get, getDRegI64(mreg), mkU8(index))));
5703 } else {
5704 res = newTemp(Ity_I64);
5705 arg_m = newTemp(Ity_I64);
5706 arg_n = newTemp(Ity_I64);
5707 assign(arg_n, getDRegI64(nreg));
5708 switch(size) {
5709 case 1:
5710 dup = Iop_Dup16x4;
5711 get = Iop_GetElem16x4;
5712 index = mreg >> 3;
5713 mreg &= 7;
5714 break;
5715 case 2:
5716 dup = Iop_Dup32x2;
5717 get = Iop_GetElem32x2;
5718 index = mreg >> 4;
5719 mreg &= 0xf;
5720 break;
5721 case 0:
5722 case 3:
5723 return False;
5724 default:
5725 vassert(0);
5726 }
5727 assign(arg_m, unop(dup, binop(get, getDRegI64(mreg), mkU8(index))));
5728 }
5729 switch (size) {
5730 case 0:
5731 case 3:
5732 return False;
5733 case 1:
5734 op = Q ? Iop_QDMulHi16Sx8 : Iop_QDMulHi16Sx4;
5735 op2 = Q ? Iop_CmpEQ16x8 : Iop_CmpEQ16x4;
5736 imm = 1LL << 15;
5737 imm = (imm << 16) | imm;
5738 imm = (imm << 32) | imm;
5739 break;
5740 case 2:
5741 op = Q ? Iop_QDMulHi32Sx4 : Iop_QDMulHi32Sx2;
5742 op2 = Q ? Iop_CmpEQ32x4 : Iop_CmpEQ32x2;
5743 imm = 1LL << 31;
5744 imm = (imm << 32) | imm;
5745 break;
5746 default:
5747 vassert(0);
5748 }
5749 assign(res, binop(op, mkexpr(arg_n), mkexpr(arg_m)));
sewardjd2664472010-08-22 12:44:20 +00005750 setFlag_QC(binop(Q ? Iop_AndV128 : Iop_And64,
5751 binop(op2, mkexpr(arg_n),
5752 Q ? mkU128(imm) : mkU64(imm)),
5753 binop(op2, mkexpr(arg_m),
5754 Q ? mkU128(imm) : mkU64(imm))),
5755 Q ? mkU128(0) : mkU64(0),
5756 Q, condT);
sewardjd2664472010-08-22 12:44:20 +00005757 if (Q)
5758 putQReg(dreg, mkexpr(res), condT);
5759 else
5760 putDRegI64(dreg, mkexpr(res), condT);
5761 DIP("vqdmulh.s%u %c%u, %c%u, d%u[%u]\n",
5762 8 << size, Q ? 'q' : 'd', dreg,
5763 Q ? 'q' : 'd', nreg, mreg, index);
5764 return True;
5765 }
5766
5767 /* VQRDMULH (scalar) */
5768 if (INSN(11,8) == BITS4(1,1,0,1)) {
5769 IROp op ,op2, dup, get;
5770 ULong imm;
5771 IRTemp res, arg_m, arg_n;
5772 if (Q) {
5773 if ((dreg & 1) || (nreg & 1))
5774 return False;
5775 dreg >>= 1;
5776 nreg >>= 1;
5777 res = newTemp(Ity_V128);
5778 arg_m = newTemp(Ity_V128);
5779 arg_n = newTemp(Ity_V128);
5780 assign(arg_n, getQReg(nreg));
5781 switch(size) {
5782 case 1:
5783 dup = Iop_Dup16x8;
5784 get = Iop_GetElem16x4;
5785 index = mreg >> 3;
5786 mreg &= 7;
5787 break;
5788 case 2:
5789 dup = Iop_Dup32x4;
5790 get = Iop_GetElem32x2;
5791 index = mreg >> 4;
5792 mreg &= 0xf;
5793 break;
5794 case 0:
5795 case 3:
5796 return False;
5797 default:
5798 vassert(0);
5799 }
5800 assign(arg_m, unop(dup, binop(get, getDRegI64(mreg), mkU8(index))));
5801 } else {
5802 res = newTemp(Ity_I64);
5803 arg_m = newTemp(Ity_I64);
5804 arg_n = newTemp(Ity_I64);
5805 assign(arg_n, getDRegI64(nreg));
5806 switch(size) {
5807 case 1:
5808 dup = Iop_Dup16x4;
5809 get = Iop_GetElem16x4;
5810 index = mreg >> 3;
5811 mreg &= 7;
5812 break;
5813 case 2:
5814 dup = Iop_Dup32x2;
5815 get = Iop_GetElem32x2;
5816 index = mreg >> 4;
5817 mreg &= 0xf;
5818 break;
5819 case 0:
5820 case 3:
5821 return False;
5822 default:
5823 vassert(0);
5824 }
5825 assign(arg_m, unop(dup, binop(get, getDRegI64(mreg), mkU8(index))));
5826 }
5827 switch (size) {
5828 case 0:
5829 case 3:
5830 return False;
5831 case 1:
5832 op = Q ? Iop_QRDMulHi16Sx8 : Iop_QRDMulHi16Sx4;
5833 op2 = Q ? Iop_CmpEQ16x8 : Iop_CmpEQ16x4;
5834 imm = 1LL << 15;
5835 imm = (imm << 16) | imm;
5836 imm = (imm << 32) | imm;
5837 break;
5838 case 2:
5839 op = Q ? Iop_QRDMulHi32Sx4 : Iop_QRDMulHi32Sx2;
5840 op2 = Q ? Iop_CmpEQ32x4 : Iop_CmpEQ32x2;
5841 imm = 1LL << 31;
5842 imm = (imm << 32) | imm;
5843 break;
5844 default:
5845 vassert(0);
5846 }
5847 assign(res, binop(op, mkexpr(arg_n), mkexpr(arg_m)));
sewardjd2664472010-08-22 12:44:20 +00005848 setFlag_QC(binop(Q ? Iop_AndV128 : Iop_And64,
5849 binop(op2, mkexpr(arg_n),
5850 Q ? mkU128(imm) : mkU64(imm)),
5851 binop(op2, mkexpr(arg_m),
5852 Q ? mkU128(imm) : mkU64(imm))),
5853 Q ? mkU128(0) : mkU64(0),
5854 Q, condT);
sewardjd2664472010-08-22 12:44:20 +00005855 if (Q)
5856 putQReg(dreg, mkexpr(res), condT);
5857 else
5858 putDRegI64(dreg, mkexpr(res), condT);
5859 DIP("vqrdmulh.s%u %c%u, %c%u, d%u[%u]\n",
5860 8 << size, Q ? 'q' : 'd', dreg,
5861 Q ? 'q' : 'd', nreg, mreg, index);
5862 return True;
5863 }
5864
5865 return False;
5866# undef INSN
5867}
5868
5869/* A7.4.4 Two registers and a shift amount */
5870static
5871Bool dis_neon_data_2reg_and_shift ( UInt theInstr, IRTemp condT )
5872{
5873 UInt A = (theInstr >> 8) & 0xf;
5874 UInt B = (theInstr >> 6) & 1;
5875 UInt L = (theInstr >> 7) & 1;
5876 UInt U = (theInstr >> 24) & 1;
5877 UInt Q = B;
5878 UInt imm6 = (theInstr >> 16) & 0x3f;
5879 UInt shift_imm;
5880 UInt size = 4;
5881 UInt tmp;
5882 UInt mreg = get_neon_m_regno(theInstr);
5883 UInt dreg = get_neon_d_regno(theInstr);
5884 ULong imm = 0;
5885 IROp op, cvt, add = Iop_INVALID, cvt2, op_rev;
5886 IRTemp reg_m, res, mask;
5887
5888 if (L == 0 && ((theInstr >> 19) & 7) == 0)
5889 /* It is one reg and immediate */
5890 return False;
5891
5892 tmp = (L << 6) | imm6;
5893 if (tmp & 0x40) {
5894 size = 3;
5895 shift_imm = 64 - imm6;
5896 } else if (tmp & 0x20) {
5897 size = 2;
5898 shift_imm = 64 - imm6;
5899 } else if (tmp & 0x10) {
5900 size = 1;
5901 shift_imm = 32 - imm6;
5902 } else if (tmp & 0x8) {
5903 size = 0;
5904 shift_imm = 16 - imm6;
5905 } else {
5906 return False;
5907 }
5908
5909 switch (A) {
5910 case 3:
5911 case 2:
5912 /* VRSHR, VRSRA */
5913 if (shift_imm > 0) {
5914 IRExpr *imm_val;
5915 imm = 1L;
5916 switch (size) {
5917 case 0:
5918 imm = (imm << 8) | imm;
5919 /* fall through */
5920 case 1:
5921 imm = (imm << 16) | imm;
5922 /* fall through */
5923 case 2:
5924 imm = (imm << 32) | imm;
5925 /* fall through */
5926 case 3:
5927 break;
5928 default:
5929 vassert(0);
5930 }
5931 if (Q) {
5932 reg_m = newTemp(Ity_V128);
5933 res = newTemp(Ity_V128);
5934 imm_val = binop(Iop_64HLtoV128, mkU64(imm), mkU64(imm));
5935 assign(reg_m, getQReg(mreg));
5936 switch (size) {
5937 case 0:
5938 add = Iop_Add8x16;
5939 op = U ? Iop_ShrN8x16 : Iop_SarN8x16;
5940 break;
5941 case 1:
5942 add = Iop_Add16x8;
5943 op = U ? Iop_ShrN16x8 : Iop_SarN16x8;
5944 break;
5945 case 2:
5946 add = Iop_Add32x4;
5947 op = U ? Iop_ShrN32x4 : Iop_SarN32x4;
5948 break;
5949 case 3:
5950 add = Iop_Add64x2;
5951 op = U ? Iop_ShrN64x2 : Iop_SarN64x2;
5952 break;
5953 default:
5954 vassert(0);
5955 }
5956 } else {
5957 reg_m = newTemp(Ity_I64);
5958 res = newTemp(Ity_I64);
5959 imm_val = mkU64(imm);
5960 assign(reg_m, getDRegI64(mreg));
5961 switch (size) {
5962 case 0:
5963 add = Iop_Add8x8;
5964 op = U ? Iop_ShrN8x8 : Iop_SarN8x8;
5965 break;
5966 case 1:
5967 add = Iop_Add16x4;
5968 op = U ? Iop_ShrN16x4 : Iop_SarN16x4;
5969 break;
5970 case 2:
5971 add = Iop_Add32x2;
5972 op = U ? Iop_ShrN32x2 : Iop_SarN32x2;
5973 break;
5974 case 3:
5975 add = Iop_Add64;
5976 op = U ? Iop_Shr64 : Iop_Sar64;
5977 break;
5978 default:
5979 vassert(0);
5980 }
5981 }
5982 assign(res,
5983 binop(add,
5984 binop(op,
5985 mkexpr(reg_m),
5986 mkU8(shift_imm)),
5987 binop(Q ? Iop_AndV128 : Iop_And64,
5988 binop(op,
5989 mkexpr(reg_m),
5990 mkU8(shift_imm - 1)),
5991 imm_val)));
5992 } else {
5993 if (Q) {
5994 res = newTemp(Ity_V128);
5995 assign(res, getQReg(mreg));
5996 } else {
5997 res = newTemp(Ity_I64);
5998 assign(res, getDRegI64(mreg));
5999 }
6000 }
6001 if (A == 3) {
6002 if (Q) {
6003 putQReg(dreg, binop(add, mkexpr(res), getQReg(dreg)),
6004 condT);
6005 } else {
6006 putDRegI64(dreg, binop(add, mkexpr(res), getDRegI64(dreg)),
6007 condT);
6008 }
6009 DIP("vrsra.%c%u %c%u, %c%u, #%u\n",
6010 U ? 'u' : 's', 8 << size,
6011 Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', mreg, shift_imm);
6012 } else {
6013 if (Q) {
6014 putQReg(dreg, mkexpr(res), condT);
6015 } else {
6016 putDRegI64(dreg, mkexpr(res), condT);
6017 }
6018 DIP("vrshr.%c%u %c%u, %c%u, #%u\n", U ? 'u' : 's', 8 << size,
6019 Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', mreg, shift_imm);
6020 }
6021 return True;
6022 case 1:
6023 case 0:
6024 /* VSHR, VSRA */
6025 if (Q) {
6026 reg_m = newTemp(Ity_V128);
6027 assign(reg_m, getQReg(mreg));
6028 res = newTemp(Ity_V128);
6029 } else {
6030 reg_m = newTemp(Ity_I64);
6031 assign(reg_m, getDRegI64(mreg));
6032 res = newTemp(Ity_I64);
6033 }
6034 if (Q) {
6035 switch (size) {
6036 case 0:
6037 op = U ? Iop_ShrN8x16 : Iop_SarN8x16;
6038 add = Iop_Add8x16;
6039 break;
6040 case 1:
6041 op = U ? Iop_ShrN16x8 : Iop_SarN16x8;
6042 add = Iop_Add16x8;
6043 break;
6044 case 2:
6045 op = U ? Iop_ShrN32x4 : Iop_SarN32x4;
6046 add = Iop_Add32x4;
6047 break;
6048 case 3:
6049 op = U ? Iop_ShrN64x2 : Iop_SarN64x2;
6050 add = Iop_Add64x2;
6051 break;
6052 default:
6053 vassert(0);
6054 }
6055 } else {
6056 switch (size) {
6057 case 0:
6058 op = U ? Iop_ShrN8x8 : Iop_SarN8x8;
6059 add = Iop_Add8x8;
6060 break;
6061 case 1:
6062 op = U ? Iop_ShrN16x4 : Iop_SarN16x4;
6063 add = Iop_Add16x4;
6064 break;
6065 case 2:
6066 op = U ? Iop_ShrN32x2 : Iop_SarN32x2;
6067 add = Iop_Add32x2;
6068 break;
6069 case 3:
6070 op = U ? Iop_Shr64 : Iop_Sar64;
6071 add = Iop_Add64;
6072 break;
6073 default:
6074 vassert(0);
6075 }
6076 }
6077 assign(res, binop(op, mkexpr(reg_m), mkU8(shift_imm)));
6078 if (A == 1) {
6079 if (Q) {
6080 putQReg(dreg, binop(add, mkexpr(res), getQReg(dreg)),
6081 condT);
6082 } else {
6083 putDRegI64(dreg, binop(add, mkexpr(res), getDRegI64(dreg)),
6084 condT);
6085 }
6086 DIP("vsra.%c%u %c%u, %c%u, #%u\n", U ? 'u' : 's', 8 << size,
6087 Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', mreg, shift_imm);
6088 } else {
6089 if (Q) {
6090 putQReg(dreg, mkexpr(res), condT);
6091 } else {
6092 putDRegI64(dreg, mkexpr(res), condT);
6093 }
6094 DIP("vshr.%c%u %c%u, %c%u, #%u\n", U ? 'u' : 's', 8 << size,
6095 Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', mreg, shift_imm);
6096 }
6097 return True;
6098 case 4:
6099 /* VSRI */
6100 if (!U)
6101 return False;
6102 if (Q) {
6103 res = newTemp(Ity_V128);
6104 mask = newTemp(Ity_V128);
6105 } else {
6106 res = newTemp(Ity_I64);
6107 mask = newTemp(Ity_I64);
6108 }
6109 switch (size) {
6110 case 0: op = Q ? Iop_ShrN8x16 : Iop_ShrN8x8; break;
6111 case 1: op = Q ? Iop_ShrN16x8 : Iop_ShrN16x4; break;
6112 case 2: op = Q ? Iop_ShrN32x4 : Iop_ShrN32x2; break;
6113 case 3: op = Q ? Iop_ShrN64x2 : Iop_Shr64; break;
6114 default: vassert(0);
6115 }
6116 if (Q) {
6117 assign(mask, binop(op, binop(Iop_64HLtoV128,
6118 mkU64(0xFFFFFFFFFFFFFFFFLL),
6119 mkU64(0xFFFFFFFFFFFFFFFFLL)),
6120 mkU8(shift_imm)));
6121 assign(res, binop(Iop_OrV128,
6122 binop(Iop_AndV128,
6123 getQReg(dreg),
6124 unop(Iop_NotV128,
6125 mkexpr(mask))),
6126 binop(op,
6127 getQReg(mreg),
6128 mkU8(shift_imm))));
6129 putQReg(dreg, mkexpr(res), condT);
6130 } else {
6131 assign(mask, binop(op, mkU64(0xFFFFFFFFFFFFFFFFLL),
6132 mkU8(shift_imm)));
6133 assign(res, binop(Iop_Or64,
6134 binop(Iop_And64,
6135 getDRegI64(dreg),
6136 unop(Iop_Not64,
6137 mkexpr(mask))),
6138 binop(op,
6139 getDRegI64(mreg),
6140 mkU8(shift_imm))));
6141 putDRegI64(dreg, mkexpr(res), condT);
6142 }
6143 DIP("vsri.%u %c%u, %c%u, #%u\n",
6144 8 << size, Q ? 'q' : 'd', dreg,
6145 Q ? 'q' : 'd', mreg, shift_imm);
6146 return True;
6147 case 5:
6148 if (U) {
6149 /* VSLI */
6150 shift_imm = 8 * (1 << size) - shift_imm;
6151 if (Q) {
6152 res = newTemp(Ity_V128);
6153 mask = newTemp(Ity_V128);
6154 } else {
6155 res = newTemp(Ity_I64);
6156 mask = newTemp(Ity_I64);
6157 }
6158 switch (size) {
6159 case 0: op = Q ? Iop_ShlN8x16 : Iop_ShlN8x8; break;
6160 case 1: op = Q ? Iop_ShlN16x8 : Iop_ShlN16x4; break;
6161 case 2: op = Q ? Iop_ShlN32x4 : Iop_ShlN32x2; break;
6162 case 3: op = Q ? Iop_ShlN64x2 : Iop_Shl64; break;
6163 default: vassert(0);
6164 }
6165 if (Q) {
6166 assign(mask, binop(op, binop(Iop_64HLtoV128,
6167 mkU64(0xFFFFFFFFFFFFFFFFLL),
6168 mkU64(0xFFFFFFFFFFFFFFFFLL)),
6169 mkU8(shift_imm)));
6170 assign(res, binop(Iop_OrV128,
6171 binop(Iop_AndV128,
6172 getQReg(dreg),
6173 unop(Iop_NotV128,
6174 mkexpr(mask))),
6175 binop(op,
6176 getQReg(mreg),
6177 mkU8(shift_imm))));
6178 putQReg(dreg, mkexpr(res), condT);
6179 } else {
6180 assign(mask, binop(op, mkU64(0xFFFFFFFFFFFFFFFFLL),
6181 mkU8(shift_imm)));
6182 assign(res, binop(Iop_Or64,
6183 binop(Iop_And64,
6184 getDRegI64(dreg),
6185 unop(Iop_Not64,
6186 mkexpr(mask))),
6187 binop(op,
6188 getDRegI64(mreg),
6189 mkU8(shift_imm))));
6190 putDRegI64(dreg, mkexpr(res), condT);
6191 }
6192 DIP("vsli.%u %c%u, %c%u, #%u\n",
6193 8 << size, Q ? 'q' : 'd', dreg,
6194 Q ? 'q' : 'd', mreg, shift_imm);
6195 return True;
6196 } else {
6197 /* VSHL #imm */
6198 shift_imm = 8 * (1 << size) - shift_imm;
6199 if (Q) {
6200 res = newTemp(Ity_V128);
6201 } else {
6202 res = newTemp(Ity_I64);
6203 }
6204 switch (size) {
6205 case 0: op = Q ? Iop_ShlN8x16 : Iop_ShlN8x8; break;
6206 case 1: op = Q ? Iop_ShlN16x8 : Iop_ShlN16x4; break;
6207 case 2: op = Q ? Iop_ShlN32x4 : Iop_ShlN32x2; break;
6208 case 3: op = Q ? Iop_ShlN64x2 : Iop_Shl64; break;
6209 default: vassert(0);
6210 }
6211 assign(res, binop(op, Q ? getQReg(mreg) : getDRegI64(mreg),
6212 mkU8(shift_imm)));
6213 if (Q) {
6214 putQReg(dreg, mkexpr(res), condT);
6215 } else {
6216 putDRegI64(dreg, mkexpr(res), condT);
6217 }
6218 DIP("vshl.i%u %c%u, %c%u, #%u\n",
6219 8 << size, Q ? 'q' : 'd', dreg,
6220 Q ? 'q' : 'd', mreg, shift_imm);
6221 return True;
6222 }
6223 break;
6224 case 6:
6225 case 7:
6226 /* VQSHL, VQSHLU */
6227 shift_imm = 8 * (1 << size) - shift_imm;
6228 if (U) {
6229 if (A & 1) {
6230 switch (size) {
6231 case 0:
6232 op = Q ? Iop_QShlN8x16 : Iop_QShlN8x8;
6233 op_rev = Q ? Iop_ShrN8x16 : Iop_ShrN8x8;
6234 break;
6235 case 1:
6236 op = Q ? Iop_QShlN16x8 : Iop_QShlN16x4;
6237 op_rev = Q ? Iop_ShrN16x8 : Iop_ShrN16x4;
6238 break;
6239 case 2:
6240 op = Q ? Iop_QShlN32x4 : Iop_QShlN32x2;
6241 op_rev = Q ? Iop_ShrN32x4 : Iop_ShrN32x2;
6242 break;
6243 case 3:
6244 op = Q ? Iop_QShlN64x2 : Iop_QShlN64x1;
6245 op_rev = Q ? Iop_ShrN64x2 : Iop_Shr64;
6246 break;
6247 default:
6248 vassert(0);
6249 }
6250 DIP("vqshl.u%u %c%u, %c%u, #%u\n",
6251 8 << size,
6252 Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', mreg, shift_imm);
6253 } else {
6254 switch (size) {
6255 case 0:
6256 op = Q ? Iop_QShlN8Sx16 : Iop_QShlN8Sx8;
6257 op_rev = Q ? Iop_ShrN8x16 : Iop_ShrN8x8;
6258 break;
6259 case 1:
6260 op = Q ? Iop_QShlN16Sx8 : Iop_QShlN16Sx4;
6261 op_rev = Q ? Iop_ShrN16x8 : Iop_ShrN16x4;
6262 break;
6263 case 2:
6264 op = Q ? Iop_QShlN32Sx4 : Iop_QShlN32Sx2;
6265 op_rev = Q ? Iop_ShrN32x4 : Iop_ShrN32x2;
6266 break;
6267 case 3:
6268 op = Q ? Iop_QShlN64Sx2 : Iop_QShlN64Sx1;
6269 op_rev = Q ? Iop_ShrN64x2 : Iop_Shr64;
6270 break;
6271 default:
6272 vassert(0);
6273 }
6274 DIP("vqshlu.s%u %c%u, %c%u, #%u\n",
6275 8 << size,
6276 Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', mreg, shift_imm);
6277 }
6278 } else {
6279 if (!(A & 1))
6280 return False;
6281 switch (size) {
6282 case 0:
6283 op = Q ? Iop_QSalN8x16 : Iop_QSalN8x8;
6284 op_rev = Q ? Iop_SarN8x16 : Iop_SarN8x8;
6285 break;
6286 case 1:
6287 op = Q ? Iop_QSalN16x8 : Iop_QSalN16x4;
6288 op_rev = Q ? Iop_SarN16x8 : Iop_SarN16x4;
6289 break;
6290 case 2:
6291 op = Q ? Iop_QSalN32x4 : Iop_QSalN32x2;
6292 op_rev = Q ? Iop_SarN32x4 : Iop_SarN32x2;
6293 break;
6294 case 3:
6295 op = Q ? Iop_QSalN64x2 : Iop_QSalN64x1;
6296 op_rev = Q ? Iop_SarN64x2 : Iop_Sar64;
6297 break;
6298 default:
6299 vassert(0);
6300 }
6301 DIP("vqshl.s%u %c%u, %c%u, #%u\n",
6302 8 << size,
6303 Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', mreg, shift_imm);
6304 }
6305 if (Q) {
6306 tmp = newTemp(Ity_V128);
6307 res = newTemp(Ity_V128);
6308 reg_m = newTemp(Ity_V128);
6309 assign(reg_m, getQReg(mreg));
6310 } else {
6311 tmp = newTemp(Ity_I64);
6312 res = newTemp(Ity_I64);
6313 reg_m = newTemp(Ity_I64);
6314 assign(reg_m, getDRegI64(mreg));
6315 }
6316 assign(res, binop(op, mkexpr(reg_m), mkU8(shift_imm)));
sewardjd2664472010-08-22 12:44:20 +00006317 assign(tmp, binop(op_rev, mkexpr(res), mkU8(shift_imm)));
6318 setFlag_QC(mkexpr(tmp), mkexpr(reg_m), Q, condT);
sewardjd2664472010-08-22 12:44:20 +00006319 if (Q)
6320 putQReg(dreg, mkexpr(res), condT);
6321 else
6322 putDRegI64(dreg, mkexpr(res), condT);
6323 return True;
6324 case 8:
6325 if (!U) {
6326 if (L == 1)
6327 return False;
6328 size++;
6329 dreg = ((theInstr >> 18) & 0x10) | ((theInstr >> 12) & 0xF);
6330 mreg = ((theInstr >> 1) & 0x10) | (theInstr & 0xF);
6331 if (mreg & 1)
6332 return False;
6333 mreg >>= 1;
6334 if (!B) {
6335 /* VSHRN*/
6336 IROp narOp;
6337 reg_m = newTemp(Ity_V128);
6338 assign(reg_m, getQReg(mreg));
6339 res = newTemp(Ity_I64);
6340 switch (size) {
6341 case 1:
6342 op = Iop_ShrN16x8;
sewardj5f438dd2011-06-16 11:36:23 +00006343 narOp = Iop_NarrowUn16to8x8;
sewardjd2664472010-08-22 12:44:20 +00006344 break;
6345 case 2:
6346 op = Iop_ShrN32x4;
sewardj5f438dd2011-06-16 11:36:23 +00006347 narOp = Iop_NarrowUn32to16x4;
sewardjd2664472010-08-22 12:44:20 +00006348 break;
6349 case 3:
6350 op = Iop_ShrN64x2;
sewardj5f438dd2011-06-16 11:36:23 +00006351 narOp = Iop_NarrowUn64to32x2;
sewardjd2664472010-08-22 12:44:20 +00006352 break;
6353 default:
6354 vassert(0);
6355 }
6356 assign(res, unop(narOp,
6357 binop(op,
6358 mkexpr(reg_m),
6359 mkU8(shift_imm))));
6360 putDRegI64(dreg, mkexpr(res), condT);
6361 DIP("vshrn.i%u d%u, q%u, #%u\n", 8 << size, dreg, mreg,
6362 shift_imm);
6363 return True;
6364 } else {
6365 /* VRSHRN */
6366 IROp addOp, shOp, narOp;
6367 IRExpr *imm_val;
6368 reg_m = newTemp(Ity_V128);
6369 assign(reg_m, getQReg(mreg));
6370 res = newTemp(Ity_I64);
6371 imm = 1L;
6372 switch (size) {
6373 case 0: imm = (imm << 8) | imm; /* fall through */
6374 case 1: imm = (imm << 16) | imm; /* fall through */
6375 case 2: imm = (imm << 32) | imm; /* fall through */
6376 case 3: break;
6377 default: vassert(0);
6378 }
6379 imm_val = binop(Iop_64HLtoV128, mkU64(imm), mkU64(imm));
6380 switch (size) {
6381 case 1:
6382 addOp = Iop_Add16x8;
6383 shOp = Iop_ShrN16x8;
sewardj5f438dd2011-06-16 11:36:23 +00006384 narOp = Iop_NarrowUn16to8x8;
sewardjd2664472010-08-22 12:44:20 +00006385 break;
6386 case 2:
6387 addOp = Iop_Add32x4;
6388 shOp = Iop_ShrN32x4;
sewardj5f438dd2011-06-16 11:36:23 +00006389 narOp = Iop_NarrowUn32to16x4;
sewardjd2664472010-08-22 12:44:20 +00006390 break;
6391 case 3:
6392 addOp = Iop_Add64x2;
6393 shOp = Iop_ShrN64x2;
sewardj5f438dd2011-06-16 11:36:23 +00006394 narOp = Iop_NarrowUn64to32x2;
sewardjd2664472010-08-22 12:44:20 +00006395 break;
6396 default:
6397 vassert(0);
6398 }
6399 assign(res, unop(narOp,
6400 binop(addOp,
6401 binop(shOp,
6402 mkexpr(reg_m),
6403 mkU8(shift_imm)),
6404 binop(Iop_AndV128,
6405 binop(shOp,
6406 mkexpr(reg_m),
6407 mkU8(shift_imm - 1)),
6408 imm_val))));
6409 putDRegI64(dreg, mkexpr(res), condT);
6410 if (shift_imm == 0) {
6411 DIP("vmov%u d%u, q%u, #%u\n", 8 << size, dreg, mreg,
6412 shift_imm);
6413 } else {
6414 DIP("vrshrn.i%u d%u, q%u, #%u\n", 8 << size, dreg, mreg,
6415 shift_imm);
6416 }
6417 return True;
6418 }
6419 } else {
6420 /* fall through */
6421 }
6422 case 9:
6423 dreg = ((theInstr >> 18) & 0x10) | ((theInstr >> 12) & 0xF);
6424 mreg = ((theInstr >> 1) & 0x10) | (theInstr & 0xF);
6425 if (mreg & 1)
6426 return False;
6427 mreg >>= 1;
6428 size++;
6429 if ((theInstr >> 8) & 1) {
6430 switch (size) {
6431 case 1:
6432 op = U ? Iop_ShrN16x8 : Iop_SarN16x8;
sewardj5f438dd2011-06-16 11:36:23 +00006433 cvt = U ? Iop_QNarrowUn16Uto8Ux8 : Iop_QNarrowUn16Sto8Sx8;
6434 cvt2 = U ? Iop_Widen8Uto16x8 : Iop_Widen8Sto16x8;
sewardjd2664472010-08-22 12:44:20 +00006435 break;
6436 case 2:
6437 op = U ? Iop_ShrN32x4 : Iop_SarN32x4;
sewardj5f438dd2011-06-16 11:36:23 +00006438 cvt = U ? Iop_QNarrowUn32Uto16Ux4 : Iop_QNarrowUn32Sto16Sx4;
6439 cvt2 = U ? Iop_Widen16Uto32x4 : Iop_Widen16Sto32x4;
sewardjd2664472010-08-22 12:44:20 +00006440 break;
6441 case 3:
6442 op = U ? Iop_ShrN64x2 : Iop_SarN64x2;
sewardj5f438dd2011-06-16 11:36:23 +00006443 cvt = U ? Iop_QNarrowUn64Uto32Ux2 : Iop_QNarrowUn64Sto32Sx2;
6444 cvt2 = U ? Iop_Widen32Uto64x2 : Iop_Widen32Sto64x2;
sewardjd2664472010-08-22 12:44:20 +00006445 break;
6446 default:
6447 vassert(0);
6448 }
6449 DIP("vq%sshrn.%c%u d%u, q%u, #%u\n", B ? "r" : "",
6450 U ? 'u' : 's', 8 << size, dreg, mreg, shift_imm);
6451 } else {
6452 vassert(U);
6453 switch (size) {
6454 case 1:
6455 op = Iop_SarN16x8;
sewardj5f438dd2011-06-16 11:36:23 +00006456 cvt = Iop_QNarrowUn16Sto8Ux8;
6457 cvt2 = Iop_Widen8Uto16x8;
sewardjd2664472010-08-22 12:44:20 +00006458 break;
6459 case 2:
6460 op = Iop_SarN32x4;
sewardj5f438dd2011-06-16 11:36:23 +00006461 cvt = Iop_QNarrowUn32Sto16Ux4;
6462 cvt2 = Iop_Widen16Uto32x4;
sewardjd2664472010-08-22 12:44:20 +00006463 break;
6464 case 3:
6465 op = Iop_SarN64x2;
sewardj5f438dd2011-06-16 11:36:23 +00006466 cvt = Iop_QNarrowUn64Sto32Ux2;
6467 cvt2 = Iop_Widen32Uto64x2;
sewardjd2664472010-08-22 12:44:20 +00006468 break;
6469 default:
6470 vassert(0);
6471 }
6472 DIP("vq%sshrun.s%u d%u, q%u, #%u\n", B ? "r" : "",
6473 8 << size, dreg, mreg, shift_imm);
6474 }
6475 if (B) {
6476 if (shift_imm > 0) {
6477 imm = 1;
6478 switch (size) {
6479 case 1: imm = (imm << 16) | imm; /* fall through */
6480 case 2: imm = (imm << 32) | imm; /* fall through */
6481 case 3: break;
6482 case 0: default: vassert(0);
6483 }
6484 switch (size) {
6485 case 1: add = Iop_Add16x8; break;
6486 case 2: add = Iop_Add32x4; break;
6487 case 3: add = Iop_Add64x2; break;
6488 case 0: default: vassert(0);
6489 }
6490 }
6491 }
6492 reg_m = newTemp(Ity_V128);
6493 res = newTemp(Ity_V128);
6494 assign(reg_m, getQReg(mreg));
6495 if (B) {
6496 /* VQRSHRN, VQRSHRUN */
6497 assign(res, binop(add,
6498 binop(op, mkexpr(reg_m), mkU8(shift_imm)),
6499 binop(Iop_AndV128,
6500 binop(op,
6501 mkexpr(reg_m),
6502 mkU8(shift_imm - 1)),
6503 mkU128(imm))));
6504 } else {
6505 /* VQSHRN, VQSHRUN */
6506 assign(res, binop(op, mkexpr(reg_m), mkU8(shift_imm)));
6507 }
sewardjd2664472010-08-22 12:44:20 +00006508 setFlag_QC(unop(cvt2, unop(cvt, mkexpr(res))), mkexpr(res),
6509 True, condT);
sewardjd2664472010-08-22 12:44:20 +00006510 putDRegI64(dreg, unop(cvt, mkexpr(res)), condT);
6511 return True;
6512 case 10:
6513 /* VSHLL
6514 VMOVL ::= VSHLL #0 */
6515 if (B)
6516 return False;
6517 if (dreg & 1)
6518 return False;
6519 dreg >>= 1;
6520 shift_imm = (8 << size) - shift_imm;
6521 res = newTemp(Ity_V128);
6522 switch (size) {
6523 case 0:
6524 op = Iop_ShlN16x8;
sewardj5f438dd2011-06-16 11:36:23 +00006525 cvt = U ? Iop_Widen8Uto16x8 : Iop_Widen8Sto16x8;
sewardjd2664472010-08-22 12:44:20 +00006526 break;
6527 case 1:
6528 op = Iop_ShlN32x4;
sewardj5f438dd2011-06-16 11:36:23 +00006529 cvt = U ? Iop_Widen16Uto32x4 : Iop_Widen16Sto32x4;
sewardjd2664472010-08-22 12:44:20 +00006530 break;
6531 case 2:
6532 op = Iop_ShlN64x2;
sewardj5f438dd2011-06-16 11:36:23 +00006533 cvt = U ? Iop_Widen32Uto64x2 : Iop_Widen32Sto64x2;
sewardjd2664472010-08-22 12:44:20 +00006534 break;
6535 case 3:
6536 return False;
6537 default:
6538 vassert(0);
6539 }
6540 assign(res, binop(op, unop(cvt, getDRegI64(mreg)), mkU8(shift_imm)));
6541 putQReg(dreg, mkexpr(res), condT);
6542 if (shift_imm == 0) {
6543 DIP("vmovl.%c%u q%u, d%u\n", U ? 'u' : 's', 8 << size,
6544 dreg, mreg);
6545 } else {
6546 DIP("vshll.%c%u q%u, d%u, #%u\n", U ? 'u' : 's', 8 << size,
6547 dreg, mreg, shift_imm);
6548 }
6549 return True;
6550 case 14:
6551 case 15:
6552 /* VCVT floating-point <-> fixed-point */
6553 if ((theInstr >> 8) & 1) {
6554 if (U) {
6555 op = Q ? Iop_F32ToFixed32Ux4_RZ : Iop_F32ToFixed32Ux2_RZ;
6556 } else {
6557 op = Q ? Iop_F32ToFixed32Sx4_RZ : Iop_F32ToFixed32Sx2_RZ;
6558 }
6559 DIP("vcvt.%c32.f32 %c%u, %c%u, #%u\n", U ? 'u' : 's',
6560 Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', mreg,
6561 64 - ((theInstr >> 16) & 0x3f));
6562 } else {
6563 if (U) {
6564 op = Q ? Iop_Fixed32UToF32x4_RN : Iop_Fixed32UToF32x2_RN;
6565 } else {
6566 op = Q ? Iop_Fixed32SToF32x4_RN : Iop_Fixed32SToF32x2_RN;
6567 }
6568 DIP("vcvt.f32.%c32 %c%u, %c%u, #%u\n", U ? 'u' : 's',
6569 Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', mreg,
6570 64 - ((theInstr >> 16) & 0x3f));
6571 }
6572 if (((theInstr >> 21) & 1) == 0)
6573 return False;
6574 if (Q) {
6575 putQReg(dreg, binop(op, getQReg(mreg),
6576 mkU8(64 - ((theInstr >> 16) & 0x3f))), condT);
6577 } else {
6578 putDRegI64(dreg, binop(op, getDRegI64(mreg),
6579 mkU8(64 - ((theInstr >> 16) & 0x3f))), condT);
6580 }
6581 return True;
6582 default:
6583 return False;
6584
6585 }
6586 return False;
6587}
6588
6589/* A7.4.5 Two registers, miscellaneous */
6590static
6591Bool dis_neon_data_2reg_misc ( UInt theInstr, IRTemp condT )
6592{
6593 UInt A = (theInstr >> 16) & 3;
6594 UInt B = (theInstr >> 6) & 0x1f;
6595 UInt Q = (theInstr >> 6) & 1;
6596 UInt U = (theInstr >> 24) & 1;
6597 UInt size = (theInstr >> 18) & 3;
6598 UInt dreg = get_neon_d_regno(theInstr);
6599 UInt mreg = get_neon_m_regno(theInstr);
6600 UInt F = (theInstr >> 10) & 1;
sewardj1df80962013-04-18 11:50:58 +00006601 IRTemp arg_d = IRTemp_INVALID;
6602 IRTemp arg_m = IRTemp_INVALID;
6603 IRTemp res = IRTemp_INVALID;
sewardjd2664472010-08-22 12:44:20 +00006604 switch (A) {
6605 case 0:
6606 if (Q) {
6607 arg_m = newTemp(Ity_V128);
6608 res = newTemp(Ity_V128);
6609 assign(arg_m, getQReg(mreg));
6610 } else {
6611 arg_m = newTemp(Ity_I64);
6612 res = newTemp(Ity_I64);
6613 assign(arg_m, getDRegI64(mreg));
6614 }
6615 switch (B >> 1) {
6616 case 0: {
6617 /* VREV64 */
6618 IROp op;
6619 switch (size) {
6620 case 0:
6621 op = Q ? Iop_Reverse64_8x16 : Iop_Reverse64_8x8;
6622 break;
6623 case 1:
6624 op = Q ? Iop_Reverse64_16x8 : Iop_Reverse64_16x4;
6625 break;
6626 case 2:
6627 op = Q ? Iop_Reverse64_32x4 : Iop_Reverse64_32x2;
6628 break;
6629 case 3:
6630 return False;
6631 default:
6632 vassert(0);
6633 }
6634 assign(res, unop(op, mkexpr(arg_m)));
6635 DIP("vrev64.%u %c%u, %c%u\n", 8 << size,
6636 Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', mreg);
6637 break;
6638 }
6639 case 1: {
6640 /* VREV32 */
6641 IROp op;
6642 switch (size) {
6643 case 0:
6644 op = Q ? Iop_Reverse32_8x16 : Iop_Reverse32_8x8;
6645 break;
6646 case 1:
6647 op = Q ? Iop_Reverse32_16x8 : Iop_Reverse32_16x4;
6648 break;
6649 case 2:
6650 case 3:
6651 return False;
6652 default:
6653 vassert(0);
6654 }
6655 assign(res, unop(op, mkexpr(arg_m)));
6656 DIP("vrev32.%u %c%u, %c%u\n", 8 << size,
6657 Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', mreg);
6658 break;
6659 }
6660 case 2: {
6661 /* VREV16 */
6662 IROp op;
6663 switch (size) {
6664 case 0:
6665 op = Q ? Iop_Reverse16_8x16 : Iop_Reverse16_8x8;
6666 break;
6667 case 1:
6668 case 2:
6669 case 3:
6670 return False;
6671 default:
6672 vassert(0);
6673 }
6674 assign(res, unop(op, mkexpr(arg_m)));
6675 DIP("vrev16.%u %c%u, %c%u\n", 8 << size,
6676 Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', mreg);
6677 break;
6678 }
6679 case 3:
6680 return False;
6681 case 4:
6682 case 5: {
6683 /* VPADDL */
6684 IROp op;
6685 U = (theInstr >> 7) & 1;
6686 if (Q) {
6687 switch (size) {
6688 case 0: op = U ? Iop_PwAddL8Ux16 : Iop_PwAddL8Sx16; break;
6689 case 1: op = U ? Iop_PwAddL16Ux8 : Iop_PwAddL16Sx8; break;
6690 case 2: op = U ? Iop_PwAddL32Ux4 : Iop_PwAddL32Sx4; break;
6691 case 3: return False;
6692 default: vassert(0);
6693 }
6694 } else {
6695 switch (size) {
6696 case 0: op = U ? Iop_PwAddL8Ux8 : Iop_PwAddL8Sx8; break;
6697 case 1: op = U ? Iop_PwAddL16Ux4 : Iop_PwAddL16Sx4; break;
6698 case 2: op = U ? Iop_PwAddL32Ux2 : Iop_PwAddL32Sx2; break;
6699 case 3: return False;
6700 default: vassert(0);
6701 }
6702 }
6703 assign(res, unop(op, mkexpr(arg_m)));
6704 DIP("vpaddl.%c%u %c%u, %c%u\n", U ? 'u' : 's', 8 << size,
6705 Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', mreg);
6706 break;
6707 }
6708 case 6:
6709 case 7:
6710 return False;
6711 case 8: {
6712 /* VCLS */
6713 IROp op;
6714 switch (size) {
6715 case 0: op = Q ? Iop_Cls8Sx16 : Iop_Cls8Sx8; break;
6716 case 1: op = Q ? Iop_Cls16Sx8 : Iop_Cls16Sx4; break;
6717 case 2: op = Q ? Iop_Cls32Sx4 : Iop_Cls32Sx2; break;
6718 case 3: return False;
6719 default: vassert(0);
6720 }
6721 assign(res, unop(op, mkexpr(arg_m)));
6722 DIP("vcls.s%u %c%u, %c%u\n", 8 << size, Q ? 'q' : 'd', dreg,
6723 Q ? 'q' : 'd', mreg);
6724 break;
6725 }
6726 case 9: {
6727 /* VCLZ */
6728 IROp op;
6729 switch (size) {
6730 case 0: op = Q ? Iop_Clz8Sx16 : Iop_Clz8Sx8; break;
6731 case 1: op = Q ? Iop_Clz16Sx8 : Iop_Clz16Sx4; break;
6732 case 2: op = Q ? Iop_Clz32Sx4 : Iop_Clz32Sx2; break;
6733 case 3: return False;
6734 default: vassert(0);
6735 }
6736 assign(res, unop(op, mkexpr(arg_m)));
6737 DIP("vclz.i%u %c%u, %c%u\n", 8 << size, Q ? 'q' : 'd', dreg,
6738 Q ? 'q' : 'd', mreg);
6739 break;
6740 }
6741 case 10:
6742 /* VCNT */
6743 assign(res, unop(Q ? Iop_Cnt8x16 : Iop_Cnt8x8, mkexpr(arg_m)));
6744 DIP("vcnt.8 %c%u, %c%u\n", Q ? 'q' : 'd', dreg, Q ? 'q' : 'd',
6745 mreg);
6746 break;
6747 case 11:
6748 /* VMVN */
6749 if (Q)
6750 assign(res, unop(Iop_NotV128, mkexpr(arg_m)));
6751 else
6752 assign(res, unop(Iop_Not64, mkexpr(arg_m)));
6753 DIP("vmvn %c%u, %c%u\n", Q ? 'q' : 'd', dreg, Q ? 'q' : 'd',
6754 mreg);
6755 break;
6756 case 12:
6757 case 13: {
6758 /* VPADAL */
6759 IROp op, add_op;
6760 U = (theInstr >> 7) & 1;
6761 if (Q) {
6762 switch (size) {
6763 case 0:
6764 op = U ? Iop_PwAddL8Ux16 : Iop_PwAddL8Sx16;
6765 add_op = Iop_Add16x8;
6766 break;
6767 case 1:
6768 op = U ? Iop_PwAddL16Ux8 : Iop_PwAddL16Sx8;
6769 add_op = Iop_Add32x4;
6770 break;
6771 case 2:
6772 op = U ? Iop_PwAddL32Ux4 : Iop_PwAddL32Sx4;
6773 add_op = Iop_Add64x2;
6774 break;
6775 case 3:
6776 return False;
6777 default:
6778 vassert(0);
6779 }
6780 } else {
6781 switch (size) {
6782 case 0:
6783 op = U ? Iop_PwAddL8Ux8 : Iop_PwAddL8Sx8;
6784 add_op = Iop_Add16x4;
6785 break;
6786 case 1:
6787 op = U ? Iop_PwAddL16Ux4 : Iop_PwAddL16Sx4;
6788 add_op = Iop_Add32x2;
6789 break;
6790 case 2:
6791 op = U ? Iop_PwAddL32Ux2 : Iop_PwAddL32Sx2;
6792 add_op = Iop_Add64;
6793 break;
6794 case 3:
6795 return False;
6796 default:
6797 vassert(0);
6798 }
6799 }
6800 if (Q) {
6801 arg_d = newTemp(Ity_V128);
6802 assign(arg_d, getQReg(dreg));
6803 } else {
6804 arg_d = newTemp(Ity_I64);
6805 assign(arg_d, getDRegI64(dreg));
6806 }
6807 assign(res, binop(add_op, unop(op, mkexpr(arg_m)),
6808 mkexpr(arg_d)));
6809 DIP("vpadal.%c%u %c%u, %c%u\n", U ? 'u' : 's', 8 << size,
6810 Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', mreg);
6811 break;
6812 }
6813 case 14: {
6814 /* VQABS */
6815 IROp op_sub, op_qsub, op_cmp;
6816 IRTemp mask, tmp;
6817 IRExpr *zero1, *zero2;
6818 IRExpr *neg, *neg2;
6819 if (Q) {
6820 zero1 = binop(Iop_64HLtoV128, mkU64(0), mkU64(0));
6821 zero2 = binop(Iop_64HLtoV128, mkU64(0), mkU64(0));
6822 mask = newTemp(Ity_V128);
6823 tmp = newTemp(Ity_V128);
6824 } else {
6825 zero1 = mkU64(0);
6826 zero2 = mkU64(0);
6827 mask = newTemp(Ity_I64);
6828 tmp = newTemp(Ity_I64);
6829 }
6830 switch (size) {
6831 case 0:
6832 op_sub = Q ? Iop_Sub8x16 : Iop_Sub8x8;
6833 op_qsub = Q ? Iop_QSub8Sx16 : Iop_QSub8Sx8;
6834 op_cmp = Q ? Iop_CmpGT8Sx16 : Iop_CmpGT8Sx8;
6835 break;
6836 case 1:
6837 op_sub = Q ? Iop_Sub16x8 : Iop_Sub16x4;
6838 op_qsub = Q ? Iop_QSub16Sx8 : Iop_QSub16Sx4;
6839 op_cmp = Q ? Iop_CmpGT16Sx8 : Iop_CmpGT16Sx4;
6840 break;
6841 case 2:
6842 op_sub = Q ? Iop_Sub32x4 : Iop_Sub32x2;
6843 op_qsub = Q ? Iop_QSub32Sx4 : Iop_QSub32Sx2;
6844 op_cmp = Q ? Iop_CmpGT32Sx4 : Iop_CmpGT32Sx2;
6845 break;
6846 case 3:
6847 return False;
6848 default:
6849 vassert(0);
6850 }
6851 assign(mask, binop(op_cmp, mkexpr(arg_m), zero1));
6852 neg = binop(op_qsub, zero2, mkexpr(arg_m));
6853 neg2 = binop(op_sub, zero2, mkexpr(arg_m));
6854 assign(res, binop(Q ? Iop_OrV128 : Iop_Or64,
6855 binop(Q ? Iop_AndV128 : Iop_And64,
6856 mkexpr(mask),
6857 mkexpr(arg_m)),
6858 binop(Q ? Iop_AndV128 : Iop_And64,
6859 unop(Q ? Iop_NotV128 : Iop_Not64,
6860 mkexpr(mask)),
6861 neg)));
sewardjd2664472010-08-22 12:44:20 +00006862 assign(tmp, binop(Q ? Iop_OrV128 : Iop_Or64,
6863 binop(Q ? Iop_AndV128 : Iop_And64,
6864 mkexpr(mask),
6865 mkexpr(arg_m)),
6866 binop(Q ? Iop_AndV128 : Iop_And64,
6867 unop(Q ? Iop_NotV128 : Iop_Not64,
6868 mkexpr(mask)),
6869 neg2)));
6870 setFlag_QC(mkexpr(res), mkexpr(tmp), Q, condT);
sewardjd2664472010-08-22 12:44:20 +00006871 DIP("vqabs.s%u %c%u, %c%u\n", 8 << size, Q ? 'q' : 'd', dreg,
6872 Q ? 'q' : 'd', mreg);
6873 break;
6874 }
6875 case 15: {
6876 /* VQNEG */
6877 IROp op, op2;
6878 IRExpr *zero;
6879 if (Q) {
6880 zero = binop(Iop_64HLtoV128, mkU64(0), mkU64(0));
6881 } else {
6882 zero = mkU64(0);
6883 }
6884 switch (size) {
6885 case 0:
6886 op = Q ? Iop_QSub8Sx16 : Iop_QSub8Sx8;
6887 op2 = Q ? Iop_Sub8x16 : Iop_Sub8x8;
6888 break;
6889 case 1:
6890 op = Q ? Iop_QSub16Sx8 : Iop_QSub16Sx4;
6891 op2 = Q ? Iop_Sub16x8 : Iop_Sub16x4;
6892 break;
6893 case 2:
6894 op = Q ? Iop_QSub32Sx4 : Iop_QSub32Sx2;
6895 op2 = Q ? Iop_Sub32x4 : Iop_Sub32x2;
6896 break;
6897 case 3:
6898 return False;
6899 default:
6900 vassert(0);
6901 }
6902 assign(res, binop(op, zero, mkexpr(arg_m)));
sewardjd2664472010-08-22 12:44:20 +00006903 setFlag_QC(mkexpr(res), binop(op2, zero, mkexpr(arg_m)),
6904 Q, condT);
sewardjd2664472010-08-22 12:44:20 +00006905 DIP("vqneg.s%u %c%u, %c%u\n", 8 << size, Q ? 'q' : 'd', dreg,
6906 Q ? 'q' : 'd', mreg);
6907 break;
6908 }
6909 default:
6910 vassert(0);
6911 }
6912 if (Q) {
6913 putQReg(dreg, mkexpr(res), condT);
6914 } else {
6915 putDRegI64(dreg, mkexpr(res), condT);
6916 }
6917 return True;
6918 case 1:
6919 if (Q) {
6920 arg_m = newTemp(Ity_V128);
6921 res = newTemp(Ity_V128);
6922 assign(arg_m, getQReg(mreg));
6923 } else {
6924 arg_m = newTemp(Ity_I64);
6925 res = newTemp(Ity_I64);
6926 assign(arg_m, getDRegI64(mreg));
6927 }
6928 switch ((B >> 1) & 0x7) {
6929 case 0: {
6930 /* VCGT #0 */
6931 IRExpr *zero;
6932 IROp op;
6933 if (Q) {
6934 zero = binop(Iop_64HLtoV128, mkU64(0), mkU64(0));
6935 } else {
6936 zero = mkU64(0);
6937 }
6938 if (F) {
6939 switch (size) {
6940 case 0: case 1: case 3: return False;
6941 case 2: op = Q ? Iop_CmpGT32Fx4 : Iop_CmpGT32Fx2; break;
6942 default: vassert(0);
6943 }
6944 } else {
6945 switch (size) {
6946 case 0: op = Q ? Iop_CmpGT8Sx16 : Iop_CmpGT8Sx8; break;
6947 case 1: op = Q ? Iop_CmpGT16Sx8 : Iop_CmpGT16Sx4; break;
6948 case 2: op = Q ? Iop_CmpGT32Sx4 : Iop_CmpGT32Sx2; break;
6949 case 3: return False;
6950 default: vassert(0);
6951 }
6952 }
6953 assign(res, binop(op, mkexpr(arg_m), zero));
6954 DIP("vcgt.%c%u %c%u, %c%u, #0\n", F ? 'f' : 's', 8 << size,
6955 Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', mreg);
6956 break;
6957 }
6958 case 1: {
6959 /* VCGE #0 */
6960 IROp op;
6961 IRExpr *zero;
6962 if (Q) {
6963 zero = binop(Iop_64HLtoV128, mkU64(0), mkU64(0));
6964 } else {
6965 zero = mkU64(0);
6966 }
6967 if (F) {
6968 switch (size) {
6969 case 0: case 1: case 3: return False;
6970 case 2: op = Q ? Iop_CmpGE32Fx4 : Iop_CmpGE32Fx2; break;
6971 default: vassert(0);
6972 }
6973 assign(res, binop(op, mkexpr(arg_m), zero));
6974 } else {
6975 switch (size) {
6976 case 0: op = Q ? Iop_CmpGT8Sx16 : Iop_CmpGT8Sx8; break;
6977 case 1: op = Q ? Iop_CmpGT16Sx8 : Iop_CmpGT16Sx4; break;
6978 case 2: op = Q ? Iop_CmpGT32Sx4 : Iop_CmpGT32Sx2; break;
6979 case 3: return False;
6980 default: vassert(0);
6981 }
6982 assign(res, unop(Q ? Iop_NotV128 : Iop_Not64,
6983 binop(op, zero, mkexpr(arg_m))));
6984 }
6985 DIP("vcge.%c%u %c%u, %c%u, #0\n", F ? 'f' : 's', 8 << size,
6986 Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', mreg);
6987 break;
6988 }
6989 case 2: {
6990 /* VCEQ #0 */
6991 IROp op;
6992 IRExpr *zero;
6993 if (F) {
6994 if (Q) {
6995 zero = binop(Iop_64HLtoV128, mkU64(0), mkU64(0));
6996 } else {
6997 zero = mkU64(0);
6998 }
6999 switch (size) {
7000 case 0: case 1: case 3: return False;
7001 case 2: op = Q ? Iop_CmpEQ32Fx4 : Iop_CmpEQ32Fx2; break;
7002 default: vassert(0);
7003 }
7004 assign(res, binop(op, zero, mkexpr(arg_m)));
7005 } else {
7006 switch (size) {
7007 case 0: op = Q ? Iop_CmpNEZ8x16 : Iop_CmpNEZ8x8; break;
7008 case 1: op = Q ? Iop_CmpNEZ16x8 : Iop_CmpNEZ16x4; break;
7009 case 2: op = Q ? Iop_CmpNEZ32x4 : Iop_CmpNEZ32x2; break;
7010 case 3: return False;
7011 default: vassert(0);
7012 }
7013 assign(res, unop(Q ? Iop_NotV128 : Iop_Not64,
7014 unop(op, mkexpr(arg_m))));
7015 }
7016 DIP("vceq.%c%u %c%u, %c%u, #0\n", F ? 'f' : 'i', 8 << size,
7017 Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', mreg);
7018 break;
7019 }
7020 case 3: {
7021 /* VCLE #0 */
7022 IRExpr *zero;
7023 IROp op;
7024 if (Q) {
7025 zero = binop(Iop_64HLtoV128, mkU64(0), mkU64(0));
7026 } else {
7027 zero = mkU64(0);
7028 }
7029 if (F) {
7030 switch (size) {
7031 case 0: case 1: case 3: return False;
7032 case 2: op = Q ? Iop_CmpGE32Fx4 : Iop_CmpGE32Fx2; break;
7033 default: vassert(0);
7034 }
7035 assign(res, binop(op, zero, mkexpr(arg_m)));
7036 } else {
7037 switch (size) {
7038 case 0: op = Q ? Iop_CmpGT8Sx16 : Iop_CmpGT8Sx8; break;
7039 case 1: op = Q ? Iop_CmpGT16Sx8 : Iop_CmpGT16Sx4; break;
7040 case 2: op = Q ? Iop_CmpGT32Sx4 : Iop_CmpGT32Sx2; break;
7041 case 3: return False;
7042 default: vassert(0);
7043 }
7044 assign(res, unop(Q ? Iop_NotV128 : Iop_Not64,
7045 binop(op, mkexpr(arg_m), zero)));
7046 }
7047 DIP("vcle.%c%u %c%u, %c%u, #0\n", F ? 'f' : 's', 8 << size,
7048 Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', mreg);
7049 break;
7050 }
7051 case 4: {
7052 /* VCLT #0 */
7053 IROp op;
7054 IRExpr *zero;
7055 if (Q) {
7056 zero = binop(Iop_64HLtoV128, mkU64(0), mkU64(0));
7057 } else {
7058 zero = mkU64(0);
7059 }
7060 if (F) {
7061 switch (size) {
7062 case 0: case 1: case 3: return False;
7063 case 2: op = Q ? Iop_CmpGT32Fx4 : Iop_CmpGT32Fx2; break;
7064 default: vassert(0);
7065 }
7066 assign(res, binop(op, zero, mkexpr(arg_m)));
7067 } else {
7068 switch (size) {
7069 case 0: op = Q ? Iop_CmpGT8Sx16 : Iop_CmpGT8Sx8; break;
7070 case 1: op = Q ? Iop_CmpGT16Sx8 : Iop_CmpGT16Sx4; break;
7071 case 2: op = Q ? Iop_CmpGT32Sx4 : Iop_CmpGT32Sx2; break;
7072 case 3: return False;
7073 default: vassert(0);
7074 }
7075 assign(res, binop(op, zero, mkexpr(arg_m)));
7076 }
7077 DIP("vclt.%c%u %c%u, %c%u, #0\n", F ? 'f' : 's', 8 << size,
7078 Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', mreg);
7079 break;
7080 }
7081 case 5:
7082 return False;
7083 case 6: {
7084 /* VABS */
7085 if (!F) {
7086 IROp op;
7087 switch(size) {
7088 case 0: op = Q ? Iop_Abs8x16 : Iop_Abs8x8; break;
7089 case 1: op = Q ? Iop_Abs16x8 : Iop_Abs16x4; break;
7090 case 2: op = Q ? Iop_Abs32x4 : Iop_Abs32x2; break;
7091 case 3: return False;
7092 default: vassert(0);
7093 }
7094 assign(res, unop(op, mkexpr(arg_m)));
7095 } else {
7096 assign(res, unop(Q ? Iop_Abs32Fx4 : Iop_Abs32Fx2,
7097 mkexpr(arg_m)));
7098 }
7099 DIP("vabs.%c%u %c%u, %c%u\n",
7100 F ? 'f' : 's', 8 << size, Q ? 'q' : 'd', dreg,
7101 Q ? 'q' : 'd', mreg);
7102 break;
7103 }
7104 case 7: {
7105 /* VNEG */
7106 IROp op;
7107 IRExpr *zero;
7108 if (F) {
7109 switch (size) {
7110 case 0: case 1: case 3: return False;
7111 case 2: op = Q ? Iop_Neg32Fx4 : Iop_Neg32Fx2; break;
7112 default: vassert(0);
7113 }
7114 assign(res, unop(op, mkexpr(arg_m)));
7115 } else {
7116 if (Q) {
7117 zero = binop(Iop_64HLtoV128, mkU64(0), mkU64(0));
7118 } else {
7119 zero = mkU64(0);
7120 }
7121 switch (size) {
7122 case 0: op = Q ? Iop_Sub8x16 : Iop_Sub8x8; break;
7123 case 1: op = Q ? Iop_Sub16x8 : Iop_Sub16x4; break;
7124 case 2: op = Q ? Iop_Sub32x4 : Iop_Sub32x2; break;
7125 case 3: return False;
7126 default: vassert(0);
7127 }
7128 assign(res, binop(op, zero, mkexpr(arg_m)));
7129 }
7130 DIP("vneg.%c%u %c%u, %c%u\n",
7131 F ? 'f' : 's', 8 << size, Q ? 'q' : 'd', dreg,
7132 Q ? 'q' : 'd', mreg);
7133 break;
7134 }
7135 default:
7136 vassert(0);
7137 }
7138 if (Q) {
7139 putQReg(dreg, mkexpr(res), condT);
7140 } else {
7141 putDRegI64(dreg, mkexpr(res), condT);
7142 }
7143 return True;
7144 case 2:
7145 if ((B >> 1) == 0) {
7146 /* VSWP */
7147 if (Q) {
7148 arg_m = newTemp(Ity_V128);
7149 assign(arg_m, getQReg(mreg));
7150 putQReg(mreg, getQReg(dreg), condT);
7151 putQReg(dreg, mkexpr(arg_m), condT);
7152 } else {
7153 arg_m = newTemp(Ity_I64);
7154 assign(arg_m, getDRegI64(mreg));
7155 putDRegI64(mreg, getDRegI64(dreg), condT);
7156 putDRegI64(dreg, mkexpr(arg_m), condT);
7157 }
7158 DIP("vswp %c%u, %c%u\n",
7159 Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', mreg);
7160 return True;
7161 } else if ((B >> 1) == 1) {
7162 /* VTRN */
sewardj1df80962013-04-18 11:50:58 +00007163 IROp op_odd = Iop_INVALID, op_even = Iop_INVALID;
7164 IRTemp old_m, old_d, new_d, new_m;
sewardjd2664472010-08-22 12:44:20 +00007165 if (Q) {
sewardj1df80962013-04-18 11:50:58 +00007166 old_m = newTemp(Ity_V128);
7167 old_d = newTemp(Ity_V128);
7168 new_m = newTemp(Ity_V128);
7169 new_d = newTemp(Ity_V128);
7170 assign(old_m, getQReg(mreg));
7171 assign(old_d, getQReg(dreg));
sewardjd2664472010-08-22 12:44:20 +00007172 } else {
sewardj1df80962013-04-18 11:50:58 +00007173 old_m = newTemp(Ity_I64);
7174 old_d = newTemp(Ity_I64);
7175 new_m = newTemp(Ity_I64);
7176 new_d = newTemp(Ity_I64);
7177 assign(old_m, getDRegI64(mreg));
7178 assign(old_d, getDRegI64(dreg));
sewardjd2664472010-08-22 12:44:20 +00007179 }
7180 if (Q) {
7181 switch (size) {
7182 case 0:
sewardj1df80962013-04-18 11:50:58 +00007183 op_odd = Iop_InterleaveOddLanes8x16;
7184 op_even = Iop_InterleaveEvenLanes8x16;
sewardjd2664472010-08-22 12:44:20 +00007185 break;
7186 case 1:
sewardj1df80962013-04-18 11:50:58 +00007187 op_odd = Iop_InterleaveOddLanes16x8;
7188 op_even = Iop_InterleaveEvenLanes16x8;
sewardjd2664472010-08-22 12:44:20 +00007189 break;
7190 case 2:
sewardj1df80962013-04-18 11:50:58 +00007191 op_odd = Iop_InterleaveOddLanes32x4;
7192 op_even = Iop_InterleaveEvenLanes32x4;
sewardjd2664472010-08-22 12:44:20 +00007193 break;
7194 case 3:
7195 return False;
7196 default:
7197 vassert(0);
7198 }
7199 } else {
7200 switch (size) {
7201 case 0:
sewardj1df80962013-04-18 11:50:58 +00007202 op_odd = Iop_InterleaveOddLanes8x8;
7203 op_even = Iop_InterleaveEvenLanes8x8;
sewardjd2664472010-08-22 12:44:20 +00007204 break;
7205 case 1:
sewardj1df80962013-04-18 11:50:58 +00007206 op_odd = Iop_InterleaveOddLanes16x4;
7207 op_even = Iop_InterleaveEvenLanes16x4;
sewardjd2664472010-08-22 12:44:20 +00007208 break;
7209 case 2:
sewardj1df80962013-04-18 11:50:58 +00007210 op_odd = Iop_InterleaveHI32x2;
7211 op_even = Iop_InterleaveLO32x2;
sewardjd2664472010-08-22 12:44:20 +00007212 break;
7213 case 3:
7214 return False;
7215 default:
7216 vassert(0);
7217 }
7218 }
sewardj1df80962013-04-18 11:50:58 +00007219 assign(new_d, binop(op_even, mkexpr(old_m), mkexpr(old_d)));
7220 assign(new_m, binop(op_odd, mkexpr(old_m), mkexpr(old_d)));
sewardjd2664472010-08-22 12:44:20 +00007221 if (Q) {
sewardj1df80962013-04-18 11:50:58 +00007222 putQReg(dreg, mkexpr(new_d), condT);
7223 putQReg(mreg, mkexpr(new_m), condT);
sewardjd2664472010-08-22 12:44:20 +00007224 } else {
sewardj1df80962013-04-18 11:50:58 +00007225 putDRegI64(dreg, mkexpr(new_d), condT);
7226 putDRegI64(mreg, mkexpr(new_m), condT);
sewardjd2664472010-08-22 12:44:20 +00007227 }
7228 DIP("vtrn.%u %c%u, %c%u\n",
7229 8 << size, Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', mreg);
7230 return True;
7231 } else if ((B >> 1) == 2) {
7232 /* VUZP */
sewardj1df80962013-04-18 11:50:58 +00007233 IROp op_even, op_odd;
7234 IRTemp old_m, old_d, new_m, new_d;
sewardjd2664472010-08-22 12:44:20 +00007235 if (!Q && size == 2)
7236 return False;
7237 if (Q) {
sewardj1df80962013-04-18 11:50:58 +00007238 old_m = newTemp(Ity_V128);
7239 old_d = newTemp(Ity_V128);
7240 new_m = newTemp(Ity_V128);
7241 new_d = newTemp(Ity_V128);
7242 assign(old_m, getQReg(mreg));
7243 assign(old_d, getQReg(dreg));
sewardjd2664472010-08-22 12:44:20 +00007244 } else {
sewardj1df80962013-04-18 11:50:58 +00007245 old_m = newTemp(Ity_I64);
7246 old_d = newTemp(Ity_I64);
7247 new_m = newTemp(Ity_I64);
7248 new_d = newTemp(Ity_I64);
7249 assign(old_m, getDRegI64(mreg));
7250 assign(old_d, getDRegI64(dreg));
sewardjd2664472010-08-22 12:44:20 +00007251 }
7252 switch (size) {
7253 case 0:
sewardj1df80962013-04-18 11:50:58 +00007254 op_odd = Q ? Iop_CatOddLanes8x16 : Iop_CatOddLanes8x8;
7255 op_even = Q ? Iop_CatEvenLanes8x16 : Iop_CatEvenLanes8x8;
sewardjd2664472010-08-22 12:44:20 +00007256 break;
7257 case 1:
sewardj1df80962013-04-18 11:50:58 +00007258 op_odd = Q ? Iop_CatOddLanes16x8 : Iop_CatOddLanes16x4;
7259 op_even = Q ? Iop_CatEvenLanes16x8 : Iop_CatEvenLanes16x4;
sewardjd2664472010-08-22 12:44:20 +00007260 break;
7261 case 2:
sewardj1df80962013-04-18 11:50:58 +00007262 op_odd = Iop_CatOddLanes32x4;
7263 op_even = Iop_CatEvenLanes32x4;
sewardjd2664472010-08-22 12:44:20 +00007264 break;
7265 case 3:
7266 return False;
7267 default:
7268 vassert(0);
7269 }
sewardj1df80962013-04-18 11:50:58 +00007270 assign(new_d, binop(op_even, mkexpr(old_m), mkexpr(old_d)));
7271 assign(new_m, binop(op_odd, mkexpr(old_m), mkexpr(old_d)));
sewardjd2664472010-08-22 12:44:20 +00007272 if (Q) {
sewardj1df80962013-04-18 11:50:58 +00007273 putQReg(dreg, mkexpr(new_d), condT);
7274 putQReg(mreg, mkexpr(new_m), condT);
sewardjd2664472010-08-22 12:44:20 +00007275 } else {
sewardj1df80962013-04-18 11:50:58 +00007276 putDRegI64(dreg, mkexpr(new_d), condT);
7277 putDRegI64(mreg, mkexpr(new_m), condT);
sewardjd2664472010-08-22 12:44:20 +00007278 }
7279 DIP("vuzp.%u %c%u, %c%u\n",
7280 8 << size, Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', mreg);
7281 return True;
7282 } else if ((B >> 1) == 3) {
7283 /* VZIP */
7284 IROp op_lo, op_hi;
sewardj1df80962013-04-18 11:50:58 +00007285 IRTemp old_m, old_d, new_m, new_d;
sewardjd2664472010-08-22 12:44:20 +00007286 if (!Q && size == 2)
7287 return False;
7288 if (Q) {
sewardj1df80962013-04-18 11:50:58 +00007289 old_m = newTemp(Ity_V128);
7290 old_d = newTemp(Ity_V128);
7291 new_m = newTemp(Ity_V128);
7292 new_d = newTemp(Ity_V128);
7293 assign(old_m, getQReg(mreg));
7294 assign(old_d, getQReg(dreg));
sewardjd2664472010-08-22 12:44:20 +00007295 } else {
sewardj1df80962013-04-18 11:50:58 +00007296 old_m = newTemp(Ity_I64);
7297 old_d = newTemp(Ity_I64);
7298 new_m = newTemp(Ity_I64);
7299 new_d = newTemp(Ity_I64);
7300 assign(old_m, getDRegI64(mreg));
7301 assign(old_d, getDRegI64(dreg));
sewardjd2664472010-08-22 12:44:20 +00007302 }
7303 switch (size) {
7304 case 0:
sewardj1df80962013-04-18 11:50:58 +00007305 op_hi = Q ? Iop_InterleaveHI8x16 : Iop_InterleaveHI8x8;
7306 op_lo = Q ? Iop_InterleaveLO8x16 : Iop_InterleaveLO8x8;
sewardjd2664472010-08-22 12:44:20 +00007307 break;
7308 case 1:
sewardj1df80962013-04-18 11:50:58 +00007309 op_hi = Q ? Iop_InterleaveHI16x8 : Iop_InterleaveHI16x4;
7310 op_lo = Q ? Iop_InterleaveLO16x8 : Iop_InterleaveLO16x4;
sewardjd2664472010-08-22 12:44:20 +00007311 break;
7312 case 2:
sewardj1df80962013-04-18 11:50:58 +00007313 op_hi = Iop_InterleaveHI32x4;
7314 op_lo = Iop_InterleaveLO32x4;
sewardjd2664472010-08-22 12:44:20 +00007315 break;
7316 case 3:
7317 return False;
7318 default:
7319 vassert(0);
7320 }
sewardj1df80962013-04-18 11:50:58 +00007321 assign(new_d, binop(op_lo, mkexpr(old_m), mkexpr(old_d)));
7322 assign(new_m, binop(op_hi, mkexpr(old_m), mkexpr(old_d)));
sewardjd2664472010-08-22 12:44:20 +00007323 if (Q) {
sewardj1df80962013-04-18 11:50:58 +00007324 putQReg(dreg, mkexpr(new_d), condT);
7325 putQReg(mreg, mkexpr(new_m), condT);
sewardjd2664472010-08-22 12:44:20 +00007326 } else {
sewardj1df80962013-04-18 11:50:58 +00007327 putDRegI64(dreg, mkexpr(new_d), condT);
7328 putDRegI64(mreg, mkexpr(new_m), condT);
sewardjd2664472010-08-22 12:44:20 +00007329 }
7330 DIP("vzip.%u %c%u, %c%u\n",
7331 8 << size, Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', mreg);
7332 return True;
7333 } else if (B == 8) {
7334 /* VMOVN */
7335 IROp op;
7336 mreg >>= 1;
7337 switch (size) {
sewardj5f438dd2011-06-16 11:36:23 +00007338 case 0: op = Iop_NarrowUn16to8x8; break;
7339 case 1: op = Iop_NarrowUn32to16x4; break;
7340 case 2: op = Iop_NarrowUn64to32x2; break;
sewardjd2664472010-08-22 12:44:20 +00007341 case 3: return False;
7342 default: vassert(0);
7343 }
7344 putDRegI64(dreg, unop(op, getQReg(mreg)), condT);
7345 DIP("vmovn.i%u d%u, q%u\n", 16 << size, dreg, mreg);
7346 return True;
7347 } else if (B == 9 || (B >> 1) == 5) {
7348 /* VQMOVN, VQMOVUN */
7349 IROp op, op2;
7350 IRTemp tmp;
7351 dreg = ((theInstr >> 18) & 0x10) | ((theInstr >> 12) & 0xF);
7352 mreg = ((theInstr >> 1) & 0x10) | (theInstr & 0xF);
7353 if (mreg & 1)
7354 return False;
7355 mreg >>= 1;
7356 switch (size) {
sewardj5f438dd2011-06-16 11:36:23 +00007357 case 0: op2 = Iop_NarrowUn16to8x8; break;
7358 case 1: op2 = Iop_NarrowUn32to16x4; break;
7359 case 2: op2 = Iop_NarrowUn64to32x2; break;
sewardjd2664472010-08-22 12:44:20 +00007360 case 3: return False;
7361 default: vassert(0);
7362 }
7363 switch (B & 3) {
7364 case 0:
7365 vassert(0);
7366 case 1:
7367 switch (size) {
sewardj5f438dd2011-06-16 11:36:23 +00007368 case 0: op = Iop_QNarrowUn16Sto8Ux8; break;
7369 case 1: op = Iop_QNarrowUn32Sto16Ux4; break;
7370 case 2: op = Iop_QNarrowUn64Sto32Ux2; break;
sewardjd2664472010-08-22 12:44:20 +00007371 case 3: return False;
7372 default: vassert(0);
7373 }
7374 DIP("vqmovun.s%u d%u, q%u\n", 16 << size, dreg, mreg);
7375 break;
7376 case 2:
7377 switch (size) {
sewardj5f438dd2011-06-16 11:36:23 +00007378 case 0: op = Iop_QNarrowUn16Sto8Sx8; break;
7379 case 1: op = Iop_QNarrowUn32Sto16Sx4; break;
7380 case 2: op = Iop_QNarrowUn64Sto32Sx2; break;
sewardjd2664472010-08-22 12:44:20 +00007381 case 3: return False;
7382 default: vassert(0);
7383 }
7384 DIP("vqmovn.s%u d%u, q%u\n", 16 << size, dreg, mreg);
7385 break;
7386 case 3:
7387 switch (size) {
sewardj5f438dd2011-06-16 11:36:23 +00007388 case 0: op = Iop_QNarrowUn16Uto8Ux8; break;
7389 case 1: op = Iop_QNarrowUn32Uto16Ux4; break;
7390 case 2: op = Iop_QNarrowUn64Uto32Ux2; break;
sewardjd2664472010-08-22 12:44:20 +00007391 case 3: return False;
7392 default: vassert(0);
7393 }
7394 DIP("vqmovn.u%u d%u, q%u\n", 16 << size, dreg, mreg);
7395 break;
7396 default:
7397 vassert(0);
7398 }
7399 res = newTemp(Ity_I64);
7400 tmp = newTemp(Ity_I64);
7401 assign(res, unop(op, getQReg(mreg)));
sewardjd2664472010-08-22 12:44:20 +00007402 assign(tmp, unop(op2, getQReg(mreg)));
7403 setFlag_QC(mkexpr(res), mkexpr(tmp), False, condT);
sewardjd2664472010-08-22 12:44:20 +00007404 putDRegI64(dreg, mkexpr(res), condT);
7405 return True;
7406 } else if (B == 12) {
7407 /* VSHLL (maximum shift) */
7408 IROp op, cvt;
7409 UInt shift_imm;
7410 if (Q)
7411 return False;
7412 if (dreg & 1)
7413 return False;
7414 dreg >>= 1;
7415 shift_imm = 8 << size;
7416 res = newTemp(Ity_V128);
7417 switch (size) {
sewardj5f438dd2011-06-16 11:36:23 +00007418 case 0: op = Iop_ShlN16x8; cvt = Iop_Widen8Uto16x8; break;
7419 case 1: op = Iop_ShlN32x4; cvt = Iop_Widen16Uto32x4; break;
7420 case 2: op = Iop_ShlN64x2; cvt = Iop_Widen32Uto64x2; break;
sewardjd2664472010-08-22 12:44:20 +00007421 case 3: return False;
7422 default: vassert(0);
7423 }
7424 assign(res, binop(op, unop(cvt, getDRegI64(mreg)),
7425 mkU8(shift_imm)));
7426 putQReg(dreg, mkexpr(res), condT);
7427 DIP("vshll.i%u q%u, d%u, #%u\n", 8 << size, dreg, mreg, 8 << size);
7428 return True;
7429 } else if ((B >> 3) == 3 && (B & 3) == 0) {
7430 /* VCVT (half<->single) */
7431 /* Half-precision extensions are needed to run this */
7432 vassert(0); // ATC
7433 if (((theInstr >> 18) & 3) != 1)
7434 return False;
7435 if ((theInstr >> 8) & 1) {
7436 if (dreg & 1)
7437 return False;
7438 dreg >>= 1;
7439 putQReg(dreg, unop(Iop_F16toF32x4, getDRegI64(mreg)),
7440 condT);
7441 DIP("vcvt.f32.f16 q%u, d%u\n", dreg, mreg);
7442 } else {
7443 if (mreg & 1)
7444 return False;
7445 mreg >>= 1;
7446 putDRegI64(dreg, unop(Iop_F32toF16x4, getQReg(mreg)),
7447 condT);
7448 DIP("vcvt.f16.f32 d%u, q%u\n", dreg, mreg);
7449 }
7450 return True;
7451 } else {
7452 return False;
7453 }
7454 vassert(0);
7455 return True;
7456 case 3:
7457 if (((B >> 1) & BITS4(1,1,0,1)) == BITS4(1,0,0,0)) {
7458 /* VRECPE */
7459 IROp op;
7460 F = (theInstr >> 8) & 1;
7461 if (size != 2)
7462 return False;
7463 if (Q) {
7464 op = F ? Iop_Recip32Fx4 : Iop_Recip32x4;
7465 putQReg(dreg, unop(op, getQReg(mreg)), condT);
7466 DIP("vrecpe.%c32 q%u, q%u\n", F ? 'f' : 'u', dreg, mreg);
7467 } else {
7468 op = F ? Iop_Recip32Fx2 : Iop_Recip32x2;
7469 putDRegI64(dreg, unop(op, getDRegI64(mreg)), condT);
7470 DIP("vrecpe.%c32 d%u, d%u\n", F ? 'f' : 'u', dreg, mreg);
7471 }
7472 return True;
7473 } else if (((B >> 1) & BITS4(1,1,0,1)) == BITS4(1,0,0,1)) {
7474 /* VRSQRTE */
7475 IROp op;
7476 F = (B >> 2) & 1;
7477 if (size != 2)
7478 return False;
7479 if (F) {
7480 /* fp */
7481 op = Q ? Iop_Rsqrte32Fx4 : Iop_Rsqrte32Fx2;
7482 } else {
7483 /* unsigned int */
7484 op = Q ? Iop_Rsqrte32x4 : Iop_Rsqrte32x2;
7485 }
7486 if (Q) {
7487 putQReg(dreg, unop(op, getQReg(mreg)), condT);
7488 DIP("vrsqrte.%c32 q%u, q%u\n", F ? 'f' : 'u', dreg, mreg);
7489 } else {
7490 putDRegI64(dreg, unop(op, getDRegI64(mreg)), condT);
7491 DIP("vrsqrte.%c32 d%u, d%u\n", F ? 'f' : 'u', dreg, mreg);
7492 }
7493 return True;
7494 } else if ((B >> 3) == 3) {
7495 /* VCVT (fp<->integer) */
7496 IROp op;
7497 if (size != 2)
7498 return False;
7499 switch ((B >> 1) & 3) {
7500 case 0:
7501 op = Q ? Iop_I32StoFx4 : Iop_I32StoFx2;
7502 DIP("vcvt.f32.s32 %c%u, %c%u\n",
7503 Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', mreg);
7504 break;
7505 case 1:
7506 op = Q ? Iop_I32UtoFx4 : Iop_I32UtoFx2;
7507 DIP("vcvt.f32.u32 %c%u, %c%u\n",
7508 Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', mreg);
7509 break;
7510 case 2:
7511 op = Q ? Iop_FtoI32Sx4_RZ : Iop_FtoI32Sx2_RZ;
7512 DIP("vcvt.s32.f32 %c%u, %c%u\n",
7513 Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', mreg);
7514 break;
7515 case 3:
7516 op = Q ? Iop_FtoI32Ux4_RZ : Iop_FtoI32Ux2_RZ;
7517 DIP("vcvt.u32.f32 %c%u, %c%u\n",
7518 Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', mreg);
7519 break;
7520 default:
7521 vassert(0);
7522 }
7523 if (Q) {
7524 putQReg(dreg, unop(op, getQReg(mreg)), condT);
7525 } else {
7526 putDRegI64(dreg, unop(op, getDRegI64(mreg)), condT);
7527 }
7528 return True;
7529 } else {
7530 return False;
7531 }
7532 vassert(0);
7533 return True;
7534 default:
7535 vassert(0);
7536 }
7537 return False;
7538}
7539
7540/* A7.4.6 One register and a modified immediate value */
7541static
7542void ppNeonImm(UInt imm, UInt cmode, UInt op)
7543{
7544 int i;
7545 switch (cmode) {
7546 case 0: case 1: case 8: case 9:
7547 vex_printf("0x%x", imm);
7548 break;
7549 case 2: case 3: case 10: case 11:
7550 vex_printf("0x%x00", imm);
7551 break;
7552 case 4: case 5:
7553 vex_printf("0x%x0000", imm);
7554 break;
7555 case 6: case 7:
7556 vex_printf("0x%x000000", imm);
7557 break;
7558 case 12:
7559 vex_printf("0x%xff", imm);
7560 break;
7561 case 13:
7562 vex_printf("0x%xffff", imm);
7563 break;
7564 case 14:
7565 if (op) {
7566 vex_printf("0x");
7567 for (i = 7; i >= 0; i--)
7568 vex_printf("%s", (imm & (1 << i)) ? "ff" : "00");
7569 } else {
7570 vex_printf("0x%x", imm);
7571 }
7572 break;
7573 case 15:
7574 vex_printf("0x%x", imm);
7575 break;
7576 }
7577}
7578
7579static
7580const char *ppNeonImmType(UInt cmode, UInt op)
7581{
7582 switch (cmode) {
7583 case 0 ... 7:
7584 case 12: case 13:
7585 return "i32";
7586 case 8 ... 11:
7587 return "i16";
7588 case 14:
7589 if (op)
7590 return "i64";
7591 else
7592 return "i8";
7593 case 15:
7594 if (op)
7595 vassert(0);
7596 else
7597 return "f32";
7598 default:
7599 vassert(0);
7600 }
7601}
7602
7603static
7604void DIPimm(UInt imm, UInt cmode, UInt op,
7605 const char *instr, UInt Q, UInt dreg)
7606{
7607 if (vex_traceflags & VEX_TRACE_FE) {
7608 vex_printf("%s.%s %c%u, #", instr,
7609 ppNeonImmType(cmode, op), Q ? 'q' : 'd', dreg);
7610 ppNeonImm(imm, cmode, op);
7611 vex_printf("\n");
7612 }
7613}
7614
7615static
7616Bool dis_neon_data_1reg_and_imm ( UInt theInstr, IRTemp condT )
7617{
7618 UInt dreg = get_neon_d_regno(theInstr);
7619 ULong imm_raw = ((theInstr >> 17) & 0x80) | ((theInstr >> 12) & 0x70) |
7620 (theInstr & 0xf);
7621 ULong imm_raw_pp = imm_raw;
7622 UInt cmode = (theInstr >> 8) & 0xf;
7623 UInt op_bit = (theInstr >> 5) & 1;
7624 ULong imm = 0;
7625 UInt Q = (theInstr >> 6) & 1;
7626 int i, j;
7627 UInt tmp;
7628 IRExpr *imm_val;
7629 IRExpr *expr;
7630 IRTemp tmp_var;
7631 switch(cmode) {
7632 case 7: case 6:
7633 imm_raw = imm_raw << 8;
7634 /* fallthrough */
7635 case 5: case 4:
7636 imm_raw = imm_raw << 8;
7637 /* fallthrough */
7638 case 3: case 2:
7639 imm_raw = imm_raw << 8;
7640 /* fallthrough */
7641 case 0: case 1:
7642 imm = (imm_raw << 32) | imm_raw;
7643 break;
7644 case 11: case 10:
7645 imm_raw = imm_raw << 8;
7646 /* fallthrough */
7647 case 9: case 8:
7648 imm_raw = (imm_raw << 16) | imm_raw;
7649 imm = (imm_raw << 32) | imm_raw;
7650 break;
7651 case 13:
7652 imm_raw = (imm_raw << 8) | 0xff;
7653 /* fallthrough */
7654 case 12:
7655 imm_raw = (imm_raw << 8) | 0xff;
7656 imm = (imm_raw << 32) | imm_raw;
7657 break;
7658 case 14:
7659 if (! op_bit) {
7660 for(i = 0; i < 8; i++) {
7661 imm = (imm << 8) | imm_raw;
7662 }
7663 } else {
7664 for(i = 7; i >= 0; i--) {
7665 tmp = 0;
7666 for(j = 0; j < 8; j++) {
7667 tmp = (tmp << 1) | ((imm_raw >> i) & 1);
7668 }
7669 imm = (imm << 8) | tmp;
7670 }
7671 }
7672 break;
7673 case 15:
7674 imm = (imm_raw & 0x80) << 5;
sewardjf7558392011-07-19 15:48:29 +00007675 imm |= ((~imm_raw & 0x40) << 5);
sewardjd2664472010-08-22 12:44:20 +00007676 for(i = 1; i <= 4; i++)
7677 imm |= (imm_raw & 0x40) << i;
7678 imm |= (imm_raw & 0x7f);
7679 imm = imm << 19;
7680 imm = (imm << 32) | imm;
7681 break;
7682 default:
7683 return False;
7684 }
7685 if (Q) {
7686 imm_val = binop(Iop_64HLtoV128, mkU64(imm), mkU64(imm));
7687 } else {
7688 imm_val = mkU64(imm);
7689 }
7690 if (((op_bit == 0) &&
7691 (((cmode & 9) == 0) || ((cmode & 13) == 8) || ((cmode & 12) == 12))) ||
7692 ((op_bit == 1) && (cmode == 14))) {
7693 /* VMOV (immediate) */
7694 if (Q) {
7695 putQReg(dreg, imm_val, condT);
7696 } else {
7697 putDRegI64(dreg, imm_val, condT);
7698 }
7699 DIPimm(imm_raw_pp, cmode, op_bit, "vmov", Q, dreg);
7700 return True;
7701 }
7702 if ((op_bit == 1) &&
7703 (((cmode & 9) == 0) || ((cmode & 13) == 8) || ((cmode & 14) == 12))) {
7704 /* VMVN (immediate) */
7705 if (Q) {
7706 putQReg(dreg, unop(Iop_NotV128, imm_val), condT);
7707 } else {
7708 putDRegI64(dreg, unop(Iop_Not64, imm_val), condT);
7709 }
7710 DIPimm(imm_raw_pp, cmode, op_bit, "vmvn", Q, dreg);
7711 return True;
7712 }
7713 if (Q) {
7714 tmp_var = newTemp(Ity_V128);
7715 assign(tmp_var, getQReg(dreg));
7716 } else {
7717 tmp_var = newTemp(Ity_I64);
7718 assign(tmp_var, getDRegI64(dreg));
7719 }
7720 if ((op_bit == 0) && (((cmode & 9) == 1) || ((cmode & 13) == 9))) {
7721 /* VORR (immediate) */
7722 if (Q)
7723 expr = binop(Iop_OrV128, mkexpr(tmp_var), imm_val);
7724 else
7725 expr = binop(Iop_Or64, mkexpr(tmp_var), imm_val);
7726 DIPimm(imm_raw_pp, cmode, op_bit, "vorr", Q, dreg);
7727 } else if ((op_bit == 1) && (((cmode & 9) == 1) || ((cmode & 13) == 9))) {
7728 /* VBIC (immediate) */
7729 if (Q)
7730 expr = binop(Iop_AndV128, mkexpr(tmp_var),
7731 unop(Iop_NotV128, imm_val));
7732 else
7733 expr = binop(Iop_And64, mkexpr(tmp_var), unop(Iop_Not64, imm_val));
7734 DIPimm(imm_raw_pp, cmode, op_bit, "vbic", Q, dreg);
7735 } else {
7736 return False;
7737 }
7738 if (Q)
7739 putQReg(dreg, expr, condT);
7740 else
7741 putDRegI64(dreg, expr, condT);
7742 return True;
7743}
7744
7745/* A7.4 Advanced SIMD data-processing instructions */
7746static
7747Bool dis_neon_data_processing ( UInt theInstr, IRTemp condT )
7748{
7749 UInt A = (theInstr >> 19) & 0x1F;
7750 UInt B = (theInstr >> 8) & 0xF;
7751 UInt C = (theInstr >> 4) & 0xF;
7752 UInt U = (theInstr >> 24) & 0x1;
7753
7754 if (! (A & 0x10)) {
7755 return dis_neon_data_3same(theInstr, condT);
7756 }
7757 if (((A & 0x17) == 0x10) && ((C & 0x9) == 0x1)) {
7758 return dis_neon_data_1reg_and_imm(theInstr, condT);
7759 }
7760 if ((C & 1) == 1) {
7761 return dis_neon_data_2reg_and_shift(theInstr, condT);
7762 }
7763 if (((C & 5) == 0) && (((A & 0x14) == 0x10) || ((A & 0x16) == 0x14))) {
7764 return dis_neon_data_3diff(theInstr, condT);
7765 }
7766 if (((C & 5) == 4) && (((A & 0x14) == 0x10) || ((A & 0x16) == 0x14))) {
7767 return dis_neon_data_2reg_and_scalar(theInstr, condT);
7768 }
7769 if ((A & 0x16) == 0x16) {
7770 if ((U == 0) && ((C & 1) == 0)) {
7771 return dis_neon_vext(theInstr, condT);
7772 }
7773 if ((U != 1) || ((C & 1) == 1))
7774 return False;
7775 if ((B & 8) == 0) {
7776 return dis_neon_data_2reg_misc(theInstr, condT);
7777 }
7778 if ((B & 12) == 8) {
7779 return dis_neon_vtb(theInstr, condT);
7780 }
7781 if ((B == 12) && ((C & 9) == 0)) {
7782 return dis_neon_vdup(theInstr, condT);
7783 }
7784 }
7785 return False;
7786}
7787
7788
7789/*------------------------------------------------------------*/
7790/*--- NEON loads and stores ---*/
7791/*------------------------------------------------------------*/
7792
7793/* For NEON memory operations, we use the standard scheme to handle
7794 conditionalisation: generate a jump around the instruction if the
7795 condition is false. That's only necessary in Thumb mode, however,
7796 since in ARM mode NEON instructions are unconditional. */
7797
7798/* A helper function for what follows. It assumes we already went
7799 uncond as per comments at the top of this section. */
7800static
7801void mk_neon_elem_load_to_one_lane( UInt rD, UInt inc, UInt index,
7802 UInt N, UInt size, IRTemp addr )
7803{
7804 UInt i;
7805 switch (size) {
7806 case 0:
7807 putDRegI64(rD, triop(Iop_SetElem8x8, getDRegI64(rD), mkU8(index),
7808 loadLE(Ity_I8, mkexpr(addr))), IRTemp_INVALID);
7809 break;
7810 case 1:
7811 putDRegI64(rD, triop(Iop_SetElem16x4, getDRegI64(rD), mkU8(index),
7812 loadLE(Ity_I16, mkexpr(addr))), IRTemp_INVALID);
7813 break;
7814 case 2:
7815 putDRegI64(rD, triop(Iop_SetElem32x2, getDRegI64(rD), mkU8(index),
7816 loadLE(Ity_I32, mkexpr(addr))), IRTemp_INVALID);
7817 break;
7818 default:
7819 vassert(0);
7820 }
7821 for (i = 1; i <= N; i++) {
7822 switch (size) {
7823 case 0:
7824 putDRegI64(rD + i * inc,
7825 triop(Iop_SetElem8x8,
7826 getDRegI64(rD + i * inc),
7827 mkU8(index),
7828 loadLE(Ity_I8, binop(Iop_Add32,
7829 mkexpr(addr),
7830 mkU32(i * 1)))),
7831 IRTemp_INVALID);
7832 break;
7833 case 1:
7834 putDRegI64(rD + i * inc,
7835 triop(Iop_SetElem16x4,
7836 getDRegI64(rD + i * inc),
7837 mkU8(index),
7838 loadLE(Ity_I16, binop(Iop_Add32,
7839 mkexpr(addr),
7840 mkU32(i * 2)))),
7841 IRTemp_INVALID);
7842 break;
7843 case 2:
7844 putDRegI64(rD + i * inc,
7845 triop(Iop_SetElem32x2,
7846 getDRegI64(rD + i * inc),
7847 mkU8(index),
7848 loadLE(Ity_I32, binop(Iop_Add32,
7849 mkexpr(addr),
7850 mkU32(i * 4)))),
7851 IRTemp_INVALID);
7852 break;
7853 default:
7854 vassert(0);
7855 }
7856 }
7857}
7858
7859/* A(nother) helper function for what follows. It assumes we already
7860 went uncond as per comments at the top of this section. */
7861static
7862void mk_neon_elem_store_from_one_lane( UInt rD, UInt inc, UInt index,
7863 UInt N, UInt size, IRTemp addr )
7864{
7865 UInt i;
7866 switch (size) {
7867 case 0:
7868 storeLE(mkexpr(addr),
7869 binop(Iop_GetElem8x8, getDRegI64(rD), mkU8(index)));
7870 break;
7871 case 1:
7872 storeLE(mkexpr(addr),
7873 binop(Iop_GetElem16x4, getDRegI64(rD), mkU8(index)));
7874 break;
7875 case 2:
7876 storeLE(mkexpr(addr),
7877 binop(Iop_GetElem32x2, getDRegI64(rD), mkU8(index)));
7878 break;
7879 default:
7880 vassert(0);
7881 }
7882 for (i = 1; i <= N; i++) {
7883 switch (size) {
7884 case 0:
7885 storeLE(binop(Iop_Add32, mkexpr(addr), mkU32(i * 1)),
7886 binop(Iop_GetElem8x8, getDRegI64(rD + i * inc),
7887 mkU8(index)));
7888 break;
7889 case 1:
7890 storeLE(binop(Iop_Add32, mkexpr(addr), mkU32(i * 2)),
7891 binop(Iop_GetElem16x4, getDRegI64(rD + i * inc),
7892 mkU8(index)));
7893 break;
7894 case 2:
7895 storeLE(binop(Iop_Add32, mkexpr(addr), mkU32(i * 4)),
7896 binop(Iop_GetElem32x2, getDRegI64(rD + i * inc),
7897 mkU8(index)));
7898 break;
7899 default:
7900 vassert(0);
7901 }
7902 }
7903}
7904
sewardj1df80962013-04-18 11:50:58 +00007905/* Generate 2x64 -> 2x64 deinterleave code, for VLD2. Caller must
7906 make *u0 and *u1 be valid IRTemps before the call. */
7907static void math_DEINTERLEAVE_2 (/*OUT*/IRTemp* u0, /*OUT*/IRTemp* u1,
7908 IRTemp i0, IRTemp i1, Int laneszB)
7909{
7910 /* The following assumes that the guest is little endian, and hence
7911 that the memory-side (interleaved) data is stored
7912 little-endianly. */
7913 vassert(u0 && u1);
7914 /* This is pretty easy, since we have primitives directly to
7915 hand. */
7916 if (laneszB == 4) {
7917 // memLE(128 bits) == A0 B0 A1 B1
7918 // i0 == B0 A0, i1 == B1 A1
7919 // u0 == A1 A0, u1 == B1 B0
7920 assign(*u0, binop(Iop_InterleaveLO32x2, mkexpr(i1), mkexpr(i0)));
7921 assign(*u1, binop(Iop_InterleaveHI32x2, mkexpr(i1), mkexpr(i0)));
7922 } else if (laneszB == 2) {
7923 // memLE(128 bits) == A0 B0 A1 B1 A2 B2 A3 B3
7924 // i0 == B1 A1 B0 A0, i1 == B3 A3 B2 A2
7925 // u0 == A3 A2 A1 A0, u1 == B3 B2 B1 B0
7926 assign(*u0, binop(Iop_CatEvenLanes16x4, mkexpr(i1), mkexpr(i0)));
7927 assign(*u1, binop(Iop_CatOddLanes16x4, mkexpr(i1), mkexpr(i0)));
7928 } else if (laneszB == 1) {
7929 // memLE(128 bits) == A0 B0 A1 B1 A2 B2 A3 B3 A4 B4 A5 B5 A6 B6 A7 B7
7930 // i0 == B3 A3 B2 A2 B1 A1 B0 A0, i1 == B7 A7 B6 A6 B5 A5 B4 A4
7931 // u0 == A7 A6 A5 A4 A3 A2 A1 A0, u1 == B7 B6 B5 B4 B3 B2 B1 B0
7932 assign(*u0, binop(Iop_CatEvenLanes8x8, mkexpr(i1), mkexpr(i0)));
7933 assign(*u1, binop(Iop_CatOddLanes8x8, mkexpr(i1), mkexpr(i0)));
7934 } else {
7935 // Can never happen, since VLD2 only has valid lane widths of 32,
7936 // 16 or 8 bits.
7937 vpanic("math_DEINTERLEAVE_2");
7938 }
7939}
7940
7941/* Generate 2x64 -> 2x64 interleave code, for VST2. Caller must make
7942 *u0 and *u1 be valid IRTemps before the call. */
7943static void math_INTERLEAVE_2 (/*OUT*/IRTemp* i0, /*OUT*/IRTemp* i1,
7944 IRTemp u0, IRTemp u1, Int laneszB)
7945{
7946 /* The following assumes that the guest is little endian, and hence
7947 that the memory-side (interleaved) data is stored
7948 little-endianly. */
7949 vassert(i0 && *i1);
7950 /* This is pretty easy, since we have primitives directly to
7951 hand. */
7952 if (laneszB == 4) {
7953 // memLE(128 bits) == A0 B0 A1 B1
7954 // i0 == B0 A0, i1 == B1 A1
7955 // u0 == A1 A0, u1 == B1 B0
7956 assign(*i0, binop(Iop_InterleaveLO32x2, mkexpr(u1), mkexpr(u0)));
7957 assign(*i1, binop(Iop_InterleaveHI32x2, mkexpr(u1), mkexpr(u0)));
7958 } else if (laneszB == 2) {
7959 // memLE(128 bits) == A0 B0 A1 B1 A2 B2 A3 B3
7960 // i0 == B1 A1 B0 A0, i1 == B3 A3 B2 A2
7961 // u0 == A3 A2 A1 A0, u1 == B3 B2 B1 B0
7962 assign(*i0, binop(Iop_InterleaveLO16x4, mkexpr(u1), mkexpr(u0)));
7963 assign(*i1, binop(Iop_InterleaveHI16x4, mkexpr(u1), mkexpr(u0)));
7964 } else if (laneszB == 1) {
7965 // memLE(128 bits) == A0 B0 A1 B1 A2 B2 A3 B3 A4 B4 A5 B5 A6 B6 A7 B7
7966 // i0 == B3 A3 B2 A2 B1 A1 B0 A0, i1 == B7 A7 B6 A6 B5 A5 B4 A4
7967 // u0 == A7 A6 A5 A4 A3 A2 A1 A0, u1 == B7 B6 B5 B4 B3 B2 B1 B0
7968 assign(*i0, binop(Iop_InterleaveLO8x8, mkexpr(u1), mkexpr(u0)));
7969 assign(*i1, binop(Iop_InterleaveHI8x8, mkexpr(u1), mkexpr(u0)));
7970 } else {
7971 // Can never happen, since VST2 only has valid lane widths of 32,
7972 // 16 or 8 bits.
7973 vpanic("math_INTERLEAVE_2");
7974 }
7975}
7976
sewardjc1e23c42013-04-20 21:19:44 +00007977// Helper function for generating arbitrary slicing 'n' dicing of
7978// 3 8x8 vectors, as needed for VLD3.8 and VST3.8.
7979static IRExpr* math_PERM_8x8x3(const UChar* desc,
7980 IRTemp s0, IRTemp s1, IRTemp s2)
7981{
7982 // desc is an array of 8 pairs, encoded as 16 bytes,
7983 // that describe how to assemble the result lanes, starting with
7984 // lane 7. Each pair is: first component (0..2) says which of
7985 // s0/s1/s2 to use. Second component (0..7) is the lane number
7986 // in the source to use.
7987 UInt si;
7988 for (si = 0; si < 7; si++) {
7989 vassert(desc[2 * si + 0] <= 2);
7990 vassert(desc[2 * si + 1] <= 7);
7991 }
7992 IRTemp h3 = newTemp(Ity_I64);
7993 IRTemp h2 = newTemp(Ity_I64);
7994 IRTemp h1 = newTemp(Ity_I64);
7995 IRTemp h0 = newTemp(Ity_I64);
7996 IRTemp srcs[3] = {s0, s1, s2};
7997# define SRC_VEC(_lane) mkexpr(srcs[desc[2 * (7-(_lane)) + 0]])
7998# define SRC_SHIFT(_lane) mkU8(56-8*(desc[2 * (7-(_lane)) + 1]))
7999 assign(h3, binop(Iop_InterleaveHI8x8,
8000 binop(Iop_Shl64, SRC_VEC(7), SRC_SHIFT(7)),
8001 binop(Iop_Shl64, SRC_VEC(6), SRC_SHIFT(6))));
8002 assign(h2, binop(Iop_InterleaveHI8x8,
8003 binop(Iop_Shl64, SRC_VEC(5), SRC_SHIFT(5)),
8004 binop(Iop_Shl64, SRC_VEC(4), SRC_SHIFT(4))));
8005 assign(h1, binop(Iop_InterleaveHI8x8,
8006 binop(Iop_Shl64, SRC_VEC(3), SRC_SHIFT(3)),
8007 binop(Iop_Shl64, SRC_VEC(2), SRC_SHIFT(2))));
8008 assign(h0, binop(Iop_InterleaveHI8x8,
8009 binop(Iop_Shl64, SRC_VEC(1), SRC_SHIFT(1)),
8010 binop(Iop_Shl64, SRC_VEC(0), SRC_SHIFT(0))));
8011# undef SRC_VEC
8012# undef SRC_SHIFT
8013 // Now h3..h0 are 64 bit vectors with useful information only
8014 // in the top 16 bits. We now concatentate those four 16-bit
8015 // groups so as to produce the final result.
8016 IRTemp w1 = newTemp(Ity_I64);
8017 IRTemp w0 = newTemp(Ity_I64);
8018 assign(w1, binop(Iop_InterleaveHI16x4, mkexpr(h3), mkexpr(h2)));
8019 assign(w0, binop(Iop_InterleaveHI16x4, mkexpr(h1), mkexpr(h0)));
8020 return binop(Iop_InterleaveHI32x2, mkexpr(w1), mkexpr(w0));
8021}
8022
8023/* Generate 3x64 -> 3x64 deinterleave code, for VLD3. Caller must
8024 make *u0, *u1 and *u2 be valid IRTemps before the call. */
8025static void math_DEINTERLEAVE_3 (
8026 /*OUT*/IRTemp* u0, /*OUT*/IRTemp* u1, /*OUT*/IRTemp* u2,
8027 IRTemp i0, IRTemp i1, IRTemp i2, Int laneszB
8028 )
8029{
8030# define IHI32x2(_e1, _e2) binop(Iop_InterleaveHI32x2, (_e1), (_e2))
8031# define IHI16x4(_e1, _e2) binop(Iop_InterleaveHI16x4, (_e1), (_e2))
8032# define SHL64(_tmp, _amt) binop(Iop_Shl64, mkexpr(_tmp), mkU8(_amt))
8033 /* The following assumes that the guest is little endian, and hence
8034 that the memory-side (interleaved) data is stored
8035 little-endianly. */
8036 vassert(u0 && u1 && u2);
8037 if (laneszB == 4) {
8038 // memLE(192 bits) == A0 B0 C0 A1 B1 C1
8039 // i0 == B0 A0, i1 == A1 C0, i2 == C1 B1
8040 // u0 == A1 A0, u1 == B1 B0, u2 == C1 C0
8041 assign(*u0, IHI32x2(SHL64(i1, 0), SHL64(i0, 32)));
8042 assign(*u1, IHI32x2(SHL64(i2, 32), SHL64(i0, 0)));
8043 assign(*u2, IHI32x2(SHL64(i2, 0), SHL64(i1, 32)));
8044 } else if (laneszB == 2) {
8045 // memLE(192 bits) == A0 B0 C0 A1, B1 C1 A2 B2, C2 A3 B3 C3
8046 // i0 == A1 C0 B0 A0, i1 == B2 A2 C1 B1, i2 == C3 B3 A3 C2
8047 // u0 == A3 A2 A1 A0, u1 == B3 B2 B1 B0, u2 == C3 C2 C1 C0
8048# define XXX(_tmp3,_la3,_tmp2,_la2,_tmp1,_la1,_tmp0,_la0) \
8049 IHI32x2( \
8050 IHI16x4(SHL64((_tmp3),48-16*(_la3)), \
8051 SHL64((_tmp2),48-16*(_la2))), \
8052 IHI16x4(SHL64((_tmp1),48-16*(_la1)), \
8053 SHL64((_tmp0),48-16*(_la0))))
8054 assign(*u0, XXX(i2,1, i1,2, i0,3, i0,0));
8055 assign(*u1, XXX(i2,2, i1,3, i1,0, i0,1));
8056 assign(*u2, XXX(i2,3, i2,0, i1,1, i0,2));
8057# undef XXX
8058 } else if (laneszB == 1) {
8059 // These describe how the result vectors [7..0] are
8060 // assembled from the source vectors. Each pair is
8061 // (source vector number, lane number).
8062 static const UChar de0[16] = {2,5, 2,2, 1,7, 1,4, 1,1, 0,6, 0,3, 0,0};
8063 static const UChar de1[16] = {2,6, 2,3, 2,0, 1,5, 1,2, 0,7, 0,4, 0,1};
8064 static const UChar de2[16] = {2,7, 2,4, 2,1, 1,6, 1,3, 1,0, 0,5, 0,2};
8065 assign(*u0, math_PERM_8x8x3(de0, i0, i1, i2));
8066 assign(*u1, math_PERM_8x8x3(de1, i0, i1, i2));
8067 assign(*u2, math_PERM_8x8x3(de2, i0, i1, i2));
8068 } else {
8069 // Can never happen, since VLD3 only has valid lane widths of 32,
8070 // 16 or 8 bits.
8071 vpanic("math_DEINTERLEAVE_3");
8072 }
8073# undef SHL64
8074# undef IHI16x4
8075# undef IHI32x2
8076}
8077
8078/* Generate 3x64 -> 3x64 interleave code, for VST3. Caller must
8079 make *i0, *i1 and *i2 be valid IRTemps before the call. */
8080static void math_INTERLEAVE_3 (
8081 /*OUT*/IRTemp* i0, /*OUT*/IRTemp* i1, /*OUT*/IRTemp* i2,
8082 IRTemp u0, IRTemp u1, IRTemp u2, Int laneszB
8083 )
8084{
8085# define IHI32x2(_e1, _e2) binop(Iop_InterleaveHI32x2, (_e1), (_e2))
8086# define IHI16x4(_e1, _e2) binop(Iop_InterleaveHI16x4, (_e1), (_e2))
8087# define SHL64(_tmp, _amt) binop(Iop_Shl64, mkexpr(_tmp), mkU8(_amt))
8088 /* The following assumes that the guest is little endian, and hence
8089 that the memory-side (interleaved) data is stored
8090 little-endianly. */
8091 vassert(i0 && i1 && i2);
8092 if (laneszB == 4) {
8093 // memLE(192 bits) == A0 B0 C0 A1 B1 C1
8094 // i0 == B0 A0, i1 == A1 C0, i2 == C1 B1
8095 // u0 == A1 A0, u1 == B1 B0, u2 == C1 C0
8096 assign(*i0, IHI32x2(SHL64(u1, 32), SHL64(u0, 32)));
8097 assign(*i1, IHI32x2(SHL64(u0, 0), SHL64(u2, 32)));
8098 assign(*i2, IHI32x2(SHL64(u2, 0), SHL64(u1, 0)));
8099 } else if (laneszB == 2) {
8100 // memLE(192 bits) == A0 B0 C0 A1, B1 C1 A2 B2, C2 A3 B3 C3
8101 // i0 == A1 C0 B0 A0, i1 == B2 A2 C1 B1, i2 == C3 B3 A3 C2
8102 // u0 == A3 A2 A1 A0, u1 == B3 B2 B1 B0, u2 == C3 C2 C1 C0
8103# define XXX(_tmp3,_la3,_tmp2,_la2,_tmp1,_la1,_tmp0,_la0) \
8104 IHI32x2( \
8105 IHI16x4(SHL64((_tmp3),48-16*(_la3)), \
8106 SHL64((_tmp2),48-16*(_la2))), \
8107 IHI16x4(SHL64((_tmp1),48-16*(_la1)), \
8108 SHL64((_tmp0),48-16*(_la0))))
8109 assign(*i0, XXX(u0,1, u2,0, u1,0, u0,0));
8110 assign(*i1, XXX(u1,2, u0,2, u2,1, u1,1));
8111 assign(*i2, XXX(u2,3, u1,3, u0,3, u2,2));
8112# undef XXX
8113 } else if (laneszB == 1) {
8114 // These describe how the result vectors [7..0] are
8115 // assembled from the source vectors. Each pair is
8116 // (source vector number, lane number).
8117 static const UChar in0[16] = {1,2, 0,2, 2,1, 1,1, 0,1, 2,0, 1,0, 0,0};
8118 static const UChar in1[16] = {0,5, 2,4, 1,4, 0,4, 2,3, 1,3, 0,3, 2,2};
8119 static const UChar in2[16] = {2,7, 1,7, 0,7, 2,6, 1,6, 0,6, 2,5, 1,5};
8120 assign(*i0, math_PERM_8x8x3(in0, u0, u1, u2));
8121 assign(*i1, math_PERM_8x8x3(in1, u0, u1, u2));
8122 assign(*i2, math_PERM_8x8x3(in2, u0, u1, u2));
8123 } else {
8124 // Can never happen, since VST3 only has valid lane widths of 32,
8125 // 16 or 8 bits.
8126 vpanic("math_INTERLEAVE_3");
8127 }
8128# undef SHL64
8129# undef IHI16x4
8130# undef IHI32x2
8131}
8132
sewardj0adc2f22013-04-20 23:27:36 +00008133/* Generate 4x64 -> 4x64 deinterleave code, for VLD4. Caller must
8134 make *u0, *u1, *u2 and *u3 be valid IRTemps before the call. */
8135static void math_DEINTERLEAVE_4 (
8136 /*OUT*/IRTemp* u0, /*OUT*/IRTemp* u1,
8137 /*OUT*/IRTemp* u2, /*OUT*/IRTemp* u3,
8138 IRTemp i0, IRTemp i1, IRTemp i2, IRTemp i3, Int laneszB
8139 )
8140{
8141# define IHI32x2(_t1, _t2) \
8142 binop(Iop_InterleaveHI32x2, mkexpr(_t1), mkexpr(_t2))
8143# define ILO32x2(_t1, _t2) \
8144 binop(Iop_InterleaveLO32x2, mkexpr(_t1), mkexpr(_t2))
8145# define IHI16x4(_t1, _t2) \
8146 binop(Iop_InterleaveHI16x4, mkexpr(_t1), mkexpr(_t2))
8147# define ILO16x4(_t1, _t2) \
8148 binop(Iop_InterleaveLO16x4, mkexpr(_t1), mkexpr(_t2))
8149# define IHI8x8(_t1, _e2) \
8150 binop(Iop_InterleaveHI8x8, mkexpr(_t1), _e2)
8151# define SHL64(_tmp, _amt) \
8152 binop(Iop_Shl64, mkexpr(_tmp), mkU8(_amt))
8153 /* The following assumes that the guest is little endian, and hence
8154 that the memory-side (interleaved) data is stored
8155 little-endianly. */
8156 vassert(u0 && u1 && u2 && u3);
8157 if (laneszB == 4) {
8158 assign(*u0, ILO32x2(i2, i0));
8159 assign(*u1, IHI32x2(i2, i0));
8160 assign(*u2, ILO32x2(i3, i1));
8161 assign(*u3, IHI32x2(i3, i1));
8162 } else if (laneszB == 2) {
8163 IRTemp b1b0a1a0 = newTemp(Ity_I64);
8164 IRTemp b3b2a3a2 = newTemp(Ity_I64);
8165 IRTemp d1d0c1c0 = newTemp(Ity_I64);
8166 IRTemp d3d2c3c2 = newTemp(Ity_I64);
8167 assign(b1b0a1a0, ILO16x4(i1, i0));
8168 assign(b3b2a3a2, ILO16x4(i3, i2));
8169 assign(d1d0c1c0, IHI16x4(i1, i0));
8170 assign(d3d2c3c2, IHI16x4(i3, i2));
8171 // And now do what we did for the 32-bit case.
8172 assign(*u0, ILO32x2(b3b2a3a2, b1b0a1a0));
8173 assign(*u1, IHI32x2(b3b2a3a2, b1b0a1a0));
8174 assign(*u2, ILO32x2(d3d2c3c2, d1d0c1c0));
8175 assign(*u3, IHI32x2(d3d2c3c2, d1d0c1c0));
8176 } else if (laneszB == 1) {
8177 // Deinterleave into 16-bit chunks, then do as the 16-bit case.
8178 IRTemp i0x = newTemp(Ity_I64);
8179 IRTemp i1x = newTemp(Ity_I64);
8180 IRTemp i2x = newTemp(Ity_I64);
8181 IRTemp i3x = newTemp(Ity_I64);
8182 assign(i0x, IHI8x8(i0, SHL64(i0, 32)));
8183 assign(i1x, IHI8x8(i1, SHL64(i1, 32)));
8184 assign(i2x, IHI8x8(i2, SHL64(i2, 32)));
8185 assign(i3x, IHI8x8(i3, SHL64(i3, 32)));
8186 // From here on is like the 16 bit case.
8187 IRTemp b1b0a1a0 = newTemp(Ity_I64);
8188 IRTemp b3b2a3a2 = newTemp(Ity_I64);
8189 IRTemp d1d0c1c0 = newTemp(Ity_I64);
8190 IRTemp d3d2c3c2 = newTemp(Ity_I64);
8191 assign(b1b0a1a0, ILO16x4(i1x, i0x));
8192 assign(b3b2a3a2, ILO16x4(i3x, i2x));
8193 assign(d1d0c1c0, IHI16x4(i1x, i0x));
8194 assign(d3d2c3c2, IHI16x4(i3x, i2x));
8195 // And now do what we did for the 32-bit case.
8196 assign(*u0, ILO32x2(b3b2a3a2, b1b0a1a0));
8197 assign(*u1, IHI32x2(b3b2a3a2, b1b0a1a0));
8198 assign(*u2, ILO32x2(d3d2c3c2, d1d0c1c0));
8199 assign(*u3, IHI32x2(d3d2c3c2, d1d0c1c0));
8200 } else {
8201 // Can never happen, since VLD4 only has valid lane widths of 32,
8202 // 16 or 8 bits.
8203 vpanic("math_DEINTERLEAVE_4");
8204 }
8205# undef SHL64
8206# undef IHI8x8
8207# undef ILO16x4
8208# undef IHI16x4
8209# undef ILO32x2
8210# undef IHI32x2
8211}
8212
8213/* Generate 4x64 -> 4x64 interleave code, for VST4. Caller must
8214 make *i0, *i1, *i2 and *i3 be valid IRTemps before the call. */
8215static void math_INTERLEAVE_4 (
8216 /*OUT*/IRTemp* i0, /*OUT*/IRTemp* i1,
8217 /*OUT*/IRTemp* i2, /*OUT*/IRTemp* i3,
8218 IRTemp u0, IRTemp u1, IRTemp u2, IRTemp u3, Int laneszB
8219 )
8220{
8221# define IHI32x2(_t1, _t2) \
8222 binop(Iop_InterleaveHI32x2, mkexpr(_t1), mkexpr(_t2))
8223# define ILO32x2(_t1, _t2) \
8224 binop(Iop_InterleaveLO32x2, mkexpr(_t1), mkexpr(_t2))
8225# define CEV16x4(_t1, _t2) \
8226 binop(Iop_CatEvenLanes16x4, mkexpr(_t1), mkexpr(_t2))
8227# define COD16x4(_t1, _t2) \
8228 binop(Iop_CatOddLanes16x4, mkexpr(_t1), mkexpr(_t2))
8229# define COD8x8(_t1, _e2) \
8230 binop(Iop_CatOddLanes8x8, mkexpr(_t1), _e2)
8231# define SHL64(_tmp, _amt) \
8232 binop(Iop_Shl64, mkexpr(_tmp), mkU8(_amt))
8233 /* The following assumes that the guest is little endian, and hence
8234 that the memory-side (interleaved) data is stored
8235 little-endianly. */
8236 vassert(u0 && u1 && u2 && u3);
8237 if (laneszB == 4) {
8238 assign(*i0, ILO32x2(u1, u0));
8239 assign(*i1, ILO32x2(u3, u2));
8240 assign(*i2, IHI32x2(u1, u0));
8241 assign(*i3, IHI32x2(u3, u2));
8242 } else if (laneszB == 2) {
8243 // First, interleave at the 32-bit lane size.
8244 IRTemp b1b0a1a0 = newTemp(Ity_I64);
8245 IRTemp b3b2a3a2 = newTemp(Ity_I64);
8246 IRTemp d1d0c1c0 = newTemp(Ity_I64);
8247 IRTemp d3d2c3c2 = newTemp(Ity_I64);
8248 assign(b1b0a1a0, ILO32x2(u1, u0));
8249 assign(b3b2a3a2, IHI32x2(u1, u0));
8250 assign(d1d0c1c0, ILO32x2(u3, u2));
8251 assign(d3d2c3c2, IHI32x2(u3, u2));
8252 // And interleave (cat) at the 16 bit size.
8253 assign(*i0, CEV16x4(d1d0c1c0, b1b0a1a0));
8254 assign(*i1, COD16x4(d1d0c1c0, b1b0a1a0));
8255 assign(*i2, CEV16x4(d3d2c3c2, b3b2a3a2));
8256 assign(*i3, COD16x4(d3d2c3c2, b3b2a3a2));
8257 } else if (laneszB == 1) {
8258 // First, interleave at the 32-bit lane size.
8259 IRTemp b1b0a1a0 = newTemp(Ity_I64);
8260 IRTemp b3b2a3a2 = newTemp(Ity_I64);
8261 IRTemp d1d0c1c0 = newTemp(Ity_I64);
8262 IRTemp d3d2c3c2 = newTemp(Ity_I64);
8263 assign(b1b0a1a0, ILO32x2(u1, u0));
8264 assign(b3b2a3a2, IHI32x2(u1, u0));
8265 assign(d1d0c1c0, ILO32x2(u3, u2));
8266 assign(d3d2c3c2, IHI32x2(u3, u2));
8267 // And interleave (cat) at the 16 bit size.
8268 IRTemp i0x = newTemp(Ity_I64);
8269 IRTemp i1x = newTemp(Ity_I64);
8270 IRTemp i2x = newTemp(Ity_I64);
8271 IRTemp i3x = newTemp(Ity_I64);
8272 assign(i0x, CEV16x4(d1d0c1c0, b1b0a1a0));
8273 assign(i1x, COD16x4(d1d0c1c0, b1b0a1a0));
8274 assign(i2x, CEV16x4(d3d2c3c2, b3b2a3a2));
8275 assign(i3x, COD16x4(d3d2c3c2, b3b2a3a2));
8276 // And rearrange within each word, to get the right 8 bit lanes.
8277 assign(*i0, COD8x8(i0x, SHL64(i0x, 8)));
8278 assign(*i1, COD8x8(i1x, SHL64(i1x, 8)));
8279 assign(*i2, COD8x8(i2x, SHL64(i2x, 8)));
8280 assign(*i3, COD8x8(i3x, SHL64(i3x, 8)));
8281 } else {
8282 // Can never happen, since VLD4 only has valid lane widths of 32,
8283 // 16 or 8 bits.
8284 vpanic("math_DEINTERLEAVE_4");
8285 }
8286# undef SHL64
8287# undef COD8x8
8288# undef COD16x4
8289# undef CEV16x4
8290# undef ILO32x2
8291# undef IHI32x2
8292}
sewardjc1e23c42013-04-20 21:19:44 +00008293
sewardjd2664472010-08-22 12:44:20 +00008294/* A7.7 Advanced SIMD element or structure load/store instructions */
8295static
sewardj28958322011-07-21 22:45:42 +00008296Bool dis_neon_load_or_store ( UInt theInstr,
8297 Bool isT, IRTemp condT )
sewardjd2664472010-08-22 12:44:20 +00008298{
8299# define INSN(_bMax,_bMin) SLICE_UInt(theInstr, (_bMax), (_bMin))
sewardj28958322011-07-21 22:45:42 +00008300 UInt bA = INSN(23,23);
8301 UInt fB = INSN(11,8);
8302 UInt bL = INSN(21,21);
sewardjd2664472010-08-22 12:44:20 +00008303 UInt rD = (INSN(22,22) << 4) | INSN(15,12);
8304 UInt rN = INSN(19,16);
8305 UInt rM = INSN(3,0);
8306 UInt N, size, i, j;
8307 UInt inc;
8308 UInt regs = 1;
sewardjd2664472010-08-22 12:44:20 +00008309
8310 if (isT) {
8311 vassert(condT != IRTemp_INVALID);
8312 } else {
8313 vassert(condT == IRTemp_INVALID);
8314 }
8315 /* So now, if condT is not IRTemp_INVALID, we know we're
8316 dealing with Thumb code. */
8317
8318 if (INSN(20,20) != 0)
8319 return False;
8320
sewardj21eaf242010-08-31 09:18:22 +00008321 IRTemp initialRn = newTemp(Ity_I32);
8322 assign(initialRn, isT ? getIRegT(rN) : getIRegA(rN));
8323
8324 IRTemp initialRm = newTemp(Ity_I32);
8325 assign(initialRm, isT ? getIRegT(rM) : getIRegA(rM));
8326
sewardj28958322011-07-21 22:45:42 +00008327 /* There are 3 cases:
8328 (1) VSTn / VLDn (n-element structure from/to one lane)
8329 (2) VLDn (single element to all lanes)
8330 (3) VSTn / VLDn (multiple n-element structures)
8331 */
8332 if (bA) {
8333 N = fB & 3;
8334 if ((fB >> 2) < 3) {
8335 /* ------------ Case (1) ------------
8336 VSTn / VLDn (n-element structure from/to one lane) */
sewardjd2664472010-08-22 12:44:20 +00008337
sewardj28958322011-07-21 22:45:42 +00008338 size = fB >> 2;
sewardjd2664472010-08-22 12:44:20 +00008339
8340 switch (size) {
8341 case 0: i = INSN(7,5); inc = 1; break;
8342 case 1: i = INSN(7,6); inc = INSN(5,5) ? 2 : 1; break;
8343 case 2: i = INSN(7,7); inc = INSN(6,6) ? 2 : 1; break;
8344 case 3: return False;
8345 default: vassert(0);
8346 }
8347
sewardj21eaf242010-08-31 09:18:22 +00008348 IRTemp addr = newTemp(Ity_I32);
8349 assign(addr, mkexpr(initialRn));
sewardjd2664472010-08-22 12:44:20 +00008350
8351 // go uncond
8352 if (condT != IRTemp_INVALID)
8353 mk_skip_over_T32_if_cond_is_false(condT);
8354 // now uncond
8355
sewardj28958322011-07-21 22:45:42 +00008356 if (bL)
sewardjd2664472010-08-22 12:44:20 +00008357 mk_neon_elem_load_to_one_lane(rD, inc, i, N, size, addr);
8358 else
8359 mk_neon_elem_store_from_one_lane(rD, inc, i, N, size, addr);
sewardj28958322011-07-21 22:45:42 +00008360 DIP("v%s%u.%u {", bL ? "ld" : "st", N + 1, 8 << size);
sewardjd2664472010-08-22 12:44:20 +00008361 for (j = 0; j <= N; j++) {
8362 if (j)
8363 DIP(", ");
8364 DIP("d%u[%u]", rD + j * inc, i);
8365 }
sewardj17bf0aa2010-08-31 09:29:51 +00008366 DIP("}, [r%u]", rN);
8367 if (rM != 13 && rM != 15) {
8368 DIP(", r%u\n", rM);
8369 } else {
8370 DIP("%s\n", (rM != 15) ? "!" : "");
8371 }
sewardjd2664472010-08-22 12:44:20 +00008372 } else {
sewardj28958322011-07-21 22:45:42 +00008373 /* ------------ Case (2) ------------
8374 VLDn (single element to all lanes) */
sewardjd2664472010-08-22 12:44:20 +00008375 UInt r;
sewardj28958322011-07-21 22:45:42 +00008376 if (bL == 0)
sewardjd2664472010-08-22 12:44:20 +00008377 return False;
8378
8379 inc = INSN(5,5) + 1;
8380 size = INSN(7,6);
8381
8382 /* size == 3 and size == 2 cases differ in alignment constraints */
8383 if (size == 3 && N == 3 && INSN(4,4) == 1)
8384 size = 2;
8385
8386 if (size == 0 && N == 0 && INSN(4,4) == 1)
8387 return False;
8388 if (N == 2 && INSN(4,4) == 1)
8389 return False;
8390 if (size == 3)
8391 return False;
8392
8393 // go uncond
8394 if (condT != IRTemp_INVALID)
8395 mk_skip_over_T32_if_cond_is_false(condT);
8396 // now uncond
8397
sewardj21eaf242010-08-31 09:18:22 +00008398 IRTemp addr = newTemp(Ity_I32);
8399 assign(addr, mkexpr(initialRn));
sewardjd2664472010-08-22 12:44:20 +00008400
8401 if (N == 0 && INSN(5,5))
8402 regs = 2;
8403
8404 for (r = 0; r < regs; r++) {
8405 switch (size) {
8406 case 0:
8407 putDRegI64(rD + r, unop(Iop_Dup8x8,
8408 loadLE(Ity_I8, mkexpr(addr))),
8409 IRTemp_INVALID);
8410 break;
8411 case 1:
8412 putDRegI64(rD + r, unop(Iop_Dup16x4,
8413 loadLE(Ity_I16, mkexpr(addr))),
8414 IRTemp_INVALID);
8415 break;
8416 case 2:
8417 putDRegI64(rD + r, unop(Iop_Dup32x2,
8418 loadLE(Ity_I32, mkexpr(addr))),
8419 IRTemp_INVALID);
8420 break;
8421 default:
8422 vassert(0);
8423 }
8424 for (i = 1; i <= N; i++) {
8425 switch (size) {
8426 case 0:
8427 putDRegI64(rD + r + i * inc,
8428 unop(Iop_Dup8x8,
8429 loadLE(Ity_I8, binop(Iop_Add32,
8430 mkexpr(addr),
8431 mkU32(i * 1)))),
8432 IRTemp_INVALID);
8433 break;
8434 case 1:
8435 putDRegI64(rD + r + i * inc,
8436 unop(Iop_Dup16x4,
8437 loadLE(Ity_I16, binop(Iop_Add32,
8438 mkexpr(addr),
8439 mkU32(i * 2)))),
8440 IRTemp_INVALID);
8441 break;
8442 case 2:
8443 putDRegI64(rD + r + i * inc,
8444 unop(Iop_Dup32x2,
8445 loadLE(Ity_I32, binop(Iop_Add32,
8446 mkexpr(addr),
8447 mkU32(i * 4)))),
8448 IRTemp_INVALID);
8449 break;
8450 default:
8451 vassert(0);
8452 }
8453 }
8454 }
8455 DIP("vld%u.%u {", N + 1, 8 << size);
8456 for (r = 0; r < regs; r++) {
8457 for (i = 0; i <= N; i++) {
8458 if (i || r)
8459 DIP(", ");
8460 DIP("d%u[]", rD + r + i * inc);
8461 }
8462 }
sewardj17bf0aa2010-08-31 09:29:51 +00008463 DIP("}, [r%u]", rN);
8464 if (rM != 13 && rM != 15) {
8465 DIP(", r%u\n", rM);
8466 } else {
8467 DIP("%s\n", (rM != 15) ? "!" : "");
8468 }
sewardjd2664472010-08-22 12:44:20 +00008469 }
8470 /* Writeback. We're uncond here, so no condT-ing. */
8471 if (rM != 15) {
8472 if (rM == 13) {
8473 IRExpr* e = binop(Iop_Add32,
sewardj21eaf242010-08-31 09:18:22 +00008474 mkexpr(initialRn),
sewardjd2664472010-08-22 12:44:20 +00008475 mkU32((1 << size) * (N + 1)));
8476 if (isT)
8477 putIRegT(rN, e, IRTemp_INVALID);
8478 else
8479 putIRegA(rN, e, IRTemp_INVALID, Ijk_Boring);
8480 } else {
sewardj21eaf242010-08-31 09:18:22 +00008481 IRExpr* e = binop(Iop_Add32,
8482 mkexpr(initialRn),
8483 mkexpr(initialRm));
sewardjd2664472010-08-22 12:44:20 +00008484 if (isT)
8485 putIRegT(rN, e, IRTemp_INVALID);
8486 else
8487 putIRegA(rN, e, IRTemp_INVALID, Ijk_Boring);
8488 }
8489 }
8490 return True;
8491 } else {
sewardj28958322011-07-21 22:45:42 +00008492 /* ------------ Case (3) ------------
8493 VSTn / VLDn (multiple n-element structures) */
sewardj0adc2f22013-04-20 23:27:36 +00008494 inc = (fB & 1) + 1;
8495
sewardj1df80962013-04-18 11:50:58 +00008496 if (fB == BITS4(0,0,1,0) // Dd, Dd+1, Dd+2, Dd+3 inc = 1 regs = 4
8497 || fB == BITS4(0,1,1,0) // Dd, Dd+1, Dd+2 inc = 1 regs = 3
8498 || fB == BITS4(0,1,1,1) // Dd inc = 2 regs = 1
8499 || fB == BITS4(1,0,1,0)) { // Dd, Dd+1 inc = 1 regs = 2
8500 N = 0; // VLD1/VST1. 'inc' does not appear to have any
8501 // meaning for the VLD1/VST1 cases. 'regs' is the number of
8502 // registers involved.
sewardj0adc2f22013-04-20 23:27:36 +00008503 if (rD + regs > 32) return False;
sewardj1df80962013-04-18 11:50:58 +00008504 }
8505 else
8506 if (fB == BITS4(0,0,1,1) // Dd, Dd+1, Dd+2, Dd+3 inc=2 regs = 2
8507 || fB == BITS4(1,0,0,0) // Dd, Dd+1 inc=1 regs = 1
8508 || fB == BITS4(1,0,0,1)) { // Dd, Dd+2 inc=2 regs = 1
8509 N = 1; // VLD2/VST2. 'regs' is the number of register-pairs involved
sewardj0adc2f22013-04-20 23:27:36 +00008510 if (regs == 1 && inc == 1 && rD + 1 >= 32) return False;
8511 if (regs == 1 && inc == 2 && rD + 2 >= 32) return False;
8512 if (regs == 2 && inc == 2 && rD + 3 >= 32) return False;
sewardj28958322011-07-21 22:45:42 +00008513 } else if (fB == BITS4(0,1,0,0) || fB == BITS4(0,1,0,1)) {
sewardj0adc2f22013-04-20 23:27:36 +00008514 N = 2; // VLD3/VST3
8515 if (inc == 1 && rD + 2 >= 32) return False;
8516 if (inc == 2 && rD + 4 >= 32) return False;
sewardj28958322011-07-21 22:45:42 +00008517 } else if (fB == BITS4(0,0,0,0) || fB == BITS4(0,0,0,1)) {
sewardj0adc2f22013-04-20 23:27:36 +00008518 N = 3; // VLD4/VST4
8519 if (inc == 1 && rD + 3 >= 32) return False;
8520 if (inc == 2 && rD + 6 >= 32) return False;
sewardjd2664472010-08-22 12:44:20 +00008521 } else {
8522 return False;
8523 }
sewardj0adc2f22013-04-20 23:27:36 +00008524
sewardj28958322011-07-21 22:45:42 +00008525 if (N == 1 && fB == BITS4(0,0,1,1)) {
sewardjd2664472010-08-22 12:44:20 +00008526 regs = 2;
8527 } else if (N == 0) {
sewardj28958322011-07-21 22:45:42 +00008528 if (fB == BITS4(1,0,1,0)) {
sewardjd2664472010-08-22 12:44:20 +00008529 regs = 2;
sewardj28958322011-07-21 22:45:42 +00008530 } else if (fB == BITS4(0,1,1,0)) {
sewardjd2664472010-08-22 12:44:20 +00008531 regs = 3;
sewardj28958322011-07-21 22:45:42 +00008532 } else if (fB == BITS4(0,0,1,0)) {
sewardjd2664472010-08-22 12:44:20 +00008533 regs = 4;
8534 }
8535 }
8536
8537 size = INSN(7,6);
8538 if (N == 0 && size == 3)
8539 size = 2;
8540 if (size == 3)
8541 return False;
8542
sewardjd2664472010-08-22 12:44:20 +00008543 // go uncond
8544 if (condT != IRTemp_INVALID)
8545 mk_skip_over_T32_if_cond_is_false(condT);
8546 // now uncond
8547
sewardj21eaf242010-08-31 09:18:22 +00008548 IRTemp addr = newTemp(Ity_I32);
8549 assign(addr, mkexpr(initialRn));
sewardjd2664472010-08-22 12:44:20 +00008550
sewardj1df80962013-04-18 11:50:58 +00008551 if (N == 0 /* No interleaving -- VLD1/VST1 */) {
sewardj0adc2f22013-04-20 23:27:36 +00008552 UInt r;
sewardj1df80962013-04-18 11:50:58 +00008553 vassert(regs == 1 || regs == 2 || regs == 3 || regs == 4);
8554 /* inc has no relevance here */
8555 for (r = 0; r < regs; r++) {
sewardj28958322011-07-21 22:45:42 +00008556 if (bL)
sewardj1df80962013-04-18 11:50:58 +00008557 putDRegI64(rD+r, loadLE(Ity_I64, mkexpr(addr)), IRTemp_INVALID);
sewardjd2664472010-08-22 12:44:20 +00008558 else
sewardj1df80962013-04-18 11:50:58 +00008559 storeLE(mkexpr(addr), getDRegI64(rD+r));
8560 IRTemp tmp = newTemp(Ity_I32);
8561 assign(tmp, binop(Iop_Add32, mkexpr(addr), mkU32(8)));
sewardjd2664472010-08-22 12:44:20 +00008562 addr = tmp;
8563 }
8564 }
sewardjc1e23c42013-04-20 21:19:44 +00008565 else
8566 if (N == 1 /* 2-interleaving -- VLD2/VST2 */) {
sewardj1df80962013-04-18 11:50:58 +00008567 vassert( (regs == 1 && (inc == 1 || inc == 2))
8568 || (regs == 2 && inc == 2) );
8569 // Make 'nregs' be the number of registers and 'regstep'
8570 // equal the actual register-step. The ARM encoding, using 'regs'
8571 // and 'inc', is bizarre. After this, we have:
8572 // Dd, Dd+1 regs = 1, inc = 1, nregs = 2, regstep = 1
8573 // Dd, Dd+2 regs = 1, inc = 2, nregs = 2, regstep = 2
8574 // Dd, Dd+1, Dd+2, Dd+3 regs = 2, inc = 2, nregs = 4, regstep = 1
8575 UInt nregs = 2;
8576 UInt regstep = 1;
8577 if (regs == 1 && inc == 1) {
8578 /* nothing */
8579 } else if (regs == 1 && inc == 2) {
8580 regstep = 2;
8581 } else if (regs == 2 && inc == 2) {
8582 nregs = 4;
sewardjd2664472010-08-22 12:44:20 +00008583 } else {
sewardj1df80962013-04-18 11:50:58 +00008584 vassert(0);
8585 }
8586 // 'a' is address,
8587 // 'di' is interleaved data, 'du' is uninterleaved data
8588 if (nregs == 2) {
8589 IRExpr* a0 = binop(Iop_Add32, mkexpr(addr), mkU32(0));
8590 IRExpr* a1 = binop(Iop_Add32, mkexpr(addr), mkU32(8));
8591 IRTemp di0 = newTemp(Ity_I64);
8592 IRTemp di1 = newTemp(Ity_I64);
8593 IRTemp du0 = newTemp(Ity_I64);
8594 IRTemp du1 = newTemp(Ity_I64);
8595 if (bL) {
8596 assign(di0, loadLE(Ity_I64, a0));
8597 assign(di1, loadLE(Ity_I64, a1));
8598 math_DEINTERLEAVE_2(&du0, &du1, di0, di1, 1 << size);
8599 putDRegI64(rD + 0 * regstep, mkexpr(du0), IRTemp_INVALID);
8600 putDRegI64(rD + 1 * regstep, mkexpr(du1), IRTemp_INVALID);
8601 } else {
8602 assign(du0, getDRegI64(rD + 0 * regstep));
8603 assign(du1, getDRegI64(rD + 1 * regstep));
8604 math_INTERLEAVE_2(&di0, &di1, du0, du1, 1 << size);
8605 storeLE(a0, mkexpr(di0));
8606 storeLE(a1, mkexpr(di1));
8607 }
8608 IRTemp tmp = newTemp(Ity_I32);
8609 assign(tmp, binop(Iop_Add32, mkexpr(addr), mkU32(16)));
8610 addr = tmp;
8611 } else {
8612 vassert(nregs == 4);
8613 vassert(regstep == 1);
8614 IRExpr* a0 = binop(Iop_Add32, mkexpr(addr), mkU32(0));
8615 IRExpr* a1 = binop(Iop_Add32, mkexpr(addr), mkU32(8));
8616 IRExpr* a2 = binop(Iop_Add32, mkexpr(addr), mkU32(16));
8617 IRExpr* a3 = binop(Iop_Add32, mkexpr(addr), mkU32(24));
8618 IRTemp di0 = newTemp(Ity_I64);
8619 IRTemp di1 = newTemp(Ity_I64);
8620 IRTemp di2 = newTemp(Ity_I64);
8621 IRTemp di3 = newTemp(Ity_I64);
8622 IRTemp du0 = newTemp(Ity_I64);
8623 IRTemp du1 = newTemp(Ity_I64);
8624 IRTemp du2 = newTemp(Ity_I64);
8625 IRTemp du3 = newTemp(Ity_I64);
8626 if (bL) {
8627 assign(di0, loadLE(Ity_I64, a0));
8628 assign(di1, loadLE(Ity_I64, a1));
8629 assign(di2, loadLE(Ity_I64, a2));
8630 assign(di3, loadLE(Ity_I64, a3));
sewardjc1e23c42013-04-20 21:19:44 +00008631 // Note spooky interleaving: du0, du2, di0, di1 etc
sewardj1df80962013-04-18 11:50:58 +00008632 math_DEINTERLEAVE_2(&du0, &du2, di0, di1, 1 << size);
8633 math_DEINTERLEAVE_2(&du1, &du3, di2, di3, 1 << size);
8634 putDRegI64(rD + 0 * regstep, mkexpr(du0), IRTemp_INVALID);
8635 putDRegI64(rD + 1 * regstep, mkexpr(du1), IRTemp_INVALID);
8636 putDRegI64(rD + 2 * regstep, mkexpr(du2), IRTemp_INVALID);
8637 putDRegI64(rD + 3 * regstep, mkexpr(du3), IRTemp_INVALID);
8638 } else {
8639 assign(du0, getDRegI64(rD + 0 * regstep));
8640 assign(du1, getDRegI64(rD + 1 * regstep));
8641 assign(du2, getDRegI64(rD + 2 * regstep));
8642 assign(du3, getDRegI64(rD + 3 * regstep));
sewardjc1e23c42013-04-20 21:19:44 +00008643 // Note spooky interleaving: du0, du2, di0, di1 etc
sewardj1df80962013-04-18 11:50:58 +00008644 math_INTERLEAVE_2(&di0, &di1, du0, du2, 1 << size);
8645 math_INTERLEAVE_2(&di2, &di3, du1, du3, 1 << size);
8646 storeLE(a0, mkexpr(di0));
8647 storeLE(a1, mkexpr(di1));
8648 storeLE(a2, mkexpr(di2));
8649 storeLE(a3, mkexpr(di3));
8650 }
8651
8652 IRTemp tmp = newTemp(Ity_I32);
8653 assign(tmp, binop(Iop_Add32, mkexpr(addr), mkU32(32)));
8654 addr = tmp;
8655 }
sewardjc1e23c42013-04-20 21:19:44 +00008656 }
sewardj0adc2f22013-04-20 23:27:36 +00008657 else
8658 if (N == 2 /* 3-interleaving -- VLD3/VST3 */) {
sewardjc1e23c42013-04-20 21:19:44 +00008659 // Dd, Dd+1, Dd+2 regs = 1, inc = 1
8660 // Dd, Dd+2, Dd+4 regs = 1, inc = 2
8661 vassert(regs == 1 && (inc == 1 || inc == 2));
8662 IRExpr* a0 = binop(Iop_Add32, mkexpr(addr), mkU32(0));
8663 IRExpr* a1 = binop(Iop_Add32, mkexpr(addr), mkU32(8));
8664 IRExpr* a2 = binop(Iop_Add32, mkexpr(addr), mkU32(16));
8665 IRTemp di0 = newTemp(Ity_I64);
8666 IRTemp di1 = newTemp(Ity_I64);
8667 IRTemp di2 = newTemp(Ity_I64);
8668 IRTemp du0 = newTemp(Ity_I64);
8669 IRTemp du1 = newTemp(Ity_I64);
8670 IRTemp du2 = newTemp(Ity_I64);
8671 if (bL) {
8672 assign(di0, loadLE(Ity_I64, a0));
8673 assign(di1, loadLE(Ity_I64, a1));
8674 assign(di2, loadLE(Ity_I64, a2));
8675 math_DEINTERLEAVE_3(&du0, &du1, &du2, di0, di1, di2, 1 << size);
8676 putDRegI64(rD + 0 * inc, mkexpr(du0), IRTemp_INVALID);
8677 putDRegI64(rD + 1 * inc, mkexpr(du1), IRTemp_INVALID);
8678 putDRegI64(rD + 2 * inc, mkexpr(du2), IRTemp_INVALID);
8679 } else {
8680 assign(du0, getDRegI64(rD + 0 * inc));
8681 assign(du1, getDRegI64(rD + 1 * inc));
8682 assign(du2, getDRegI64(rD + 2 * inc));
8683 math_INTERLEAVE_3(&di0, &di1, &di2, du0, du1, du2, 1 << size);
8684 storeLE(a0, mkexpr(di0));
8685 storeLE(a1, mkexpr(di1));
8686 storeLE(a2, mkexpr(di2));
8687 }
8688 IRTemp tmp = newTemp(Ity_I32);
8689 assign(tmp, binop(Iop_Add32, mkexpr(addr), mkU32(24)));
8690 addr = tmp;
sewardj1df80962013-04-18 11:50:58 +00008691 }
sewardj0adc2f22013-04-20 23:27:36 +00008692 else
8693 if (N == 3 /* 4-interleaving -- VLD4/VST4 */) {
8694 // Dd, Dd+1, Dd+2, Dd+3 regs = 1, inc = 1
8695 // Dd, Dd+2, Dd+4, Dd+6 regs = 1, inc = 2
8696 vassert(regs == 1 && (inc == 1 || inc == 2));
8697 IRExpr* a0 = binop(Iop_Add32, mkexpr(addr), mkU32(0));
8698 IRExpr* a1 = binop(Iop_Add32, mkexpr(addr), mkU32(8));
8699 IRExpr* a2 = binop(Iop_Add32, mkexpr(addr), mkU32(16));
8700 IRExpr* a3 = binop(Iop_Add32, mkexpr(addr), mkU32(24));
8701 IRTemp di0 = newTemp(Ity_I64);
8702 IRTemp di1 = newTemp(Ity_I64);
8703 IRTemp di2 = newTemp(Ity_I64);
8704 IRTemp di3 = newTemp(Ity_I64);
8705 IRTemp du0 = newTemp(Ity_I64);
8706 IRTemp du1 = newTemp(Ity_I64);
8707 IRTemp du2 = newTemp(Ity_I64);
8708 IRTemp du3 = newTemp(Ity_I64);
8709 if (bL) {
8710 assign(di0, loadLE(Ity_I64, a0));
8711 assign(di1, loadLE(Ity_I64, a1));
8712 assign(di2, loadLE(Ity_I64, a2));
8713 assign(di3, loadLE(Ity_I64, a3));
8714 math_DEINTERLEAVE_4(&du0, &du1, &du2, &du3,
8715 di0, di1, di2, di3, 1 << size);
8716 putDRegI64(rD + 0 * inc, mkexpr(du0), IRTemp_INVALID);
8717 putDRegI64(rD + 1 * inc, mkexpr(du1), IRTemp_INVALID);
8718 putDRegI64(rD + 2 * inc, mkexpr(du2), IRTemp_INVALID);
8719 putDRegI64(rD + 3 * inc, mkexpr(du3), IRTemp_INVALID);
8720 } else {
8721 assign(du0, getDRegI64(rD + 0 * inc));
8722 assign(du1, getDRegI64(rD + 1 * inc));
8723 assign(du2, getDRegI64(rD + 2 * inc));
8724 assign(du3, getDRegI64(rD + 3 * inc));
8725 math_INTERLEAVE_4(&di0, &di1, &di2, &di3,
8726 du0, du1, du2, du3, 1 << size);
8727 storeLE(a0, mkexpr(di0));
8728 storeLE(a1, mkexpr(di1));
8729 storeLE(a2, mkexpr(di2));
8730 storeLE(a3, mkexpr(di3));
sewardjd2664472010-08-22 12:44:20 +00008731 }
sewardj0adc2f22013-04-20 23:27:36 +00008732 IRTemp tmp = newTemp(Ity_I32);
8733 assign(tmp, binop(Iop_Add32, mkexpr(addr), mkU32(32)));
8734 addr = tmp;
8735 }
8736 else {
8737 vassert(0);
sewardjd2664472010-08-22 12:44:20 +00008738 }
sewardj1df80962013-04-18 11:50:58 +00008739
8740 /* Writeback */
8741 if (rM != 15) {
8742 IRExpr* e;
8743 if (rM == 13) {
8744 e = binop(Iop_Add32, mkexpr(initialRn),
8745 mkU32(8 * (N + 1) * regs));
8746 } else {
8747 e = binop(Iop_Add32, mkexpr(initialRn),
8748 mkexpr(initialRm));
8749 }
8750 if (isT)
8751 putIRegT(rN, e, IRTemp_INVALID);
8752 else
8753 putIRegA(rN, e, IRTemp_INVALID, Ijk_Boring);
8754 }
8755
sewardj28958322011-07-21 22:45:42 +00008756 DIP("v%s%u.%u {", bL ? "ld" : "st", N + 1, 8 << INSN(7,6));
sewardjd2664472010-08-22 12:44:20 +00008757 if ((inc == 1 && regs * (N + 1) > 1)
8758 || (inc == 2 && regs > 1 && N > 0)) {
8759 DIP("d%u-d%u", rD, rD + regs * (N + 1) - 1);
8760 } else {
sewardj0adc2f22013-04-20 23:27:36 +00008761 UInt r;
sewardjd2664472010-08-22 12:44:20 +00008762 for (r = 0; r < regs; r++) {
8763 for (i = 0; i <= N; i++) {
8764 if (i || r)
8765 DIP(", ");
8766 DIP("d%u", rD + r + i * inc);
8767 }
8768 }
8769 }
sewardj17bf0aa2010-08-31 09:29:51 +00008770 DIP("}, [r%u]", rN);
8771 if (rM != 13 && rM != 15) {
8772 DIP(", r%u\n", rM);
8773 } else {
8774 DIP("%s\n", (rM != 15) ? "!" : "");
8775 }
sewardjd2664472010-08-22 12:44:20 +00008776 return True;
8777 }
8778# undef INSN
8779}
8780
8781
8782/*------------------------------------------------------------*/
8783/*--- NEON, top level control ---*/
8784/*------------------------------------------------------------*/
8785
8786/* Both ARM and Thumb */
8787
8788/* Translate a NEON instruction. If successful, returns
8789 True and *dres may or may not be updated. If failure, returns
8790 False and doesn't change *dres nor create any IR.
8791
8792 The Thumb and ARM encodings are similar for the 24 bottom bits, but
8793 the top 8 bits are slightly different. In both cases, the caller
8794 must pass the entire 32 bits. Callers may pass any instruction;
8795 this ignores non-NEON ones.
8796
8797 Caller must supply an IRTemp 'condT' holding the gating condition,
8798 or IRTemp_INVALID indicating the insn is always executed. In ARM
8799 code, this must always be IRTemp_INVALID because NEON insns are
8800 unconditional for ARM.
8801
8802 Finally, the caller must indicate whether this occurs in ARM or in
8803 Thumb code.
8804*/
8805static Bool decode_NEON_instruction (
8806 /*MOD*/DisResult* dres,
8807 UInt insn32,
8808 IRTemp condT,
8809 Bool isT
8810 )
8811{
8812# define INSN(_bMax,_bMin) SLICE_UInt(insn32, (_bMax), (_bMin))
8813
8814 /* There are two kinds of instruction to deal with: load/store and
8815 data processing. In each case, in ARM mode we merely identify
8816 the kind, and pass it on to the relevant sub-handler. In Thumb
8817 mode we identify the kind, swizzle the bits around to make it
8818 have the same encoding as in ARM, and hand it on to the
8819 sub-handler.
8820 */
8821
8822 /* In ARM mode, NEON instructions can't be conditional. */
8823 if (!isT)
8824 vassert(condT == IRTemp_INVALID);
8825
8826 /* Data processing:
8827 Thumb: 111U 1111 AAAA Axxx xxxx BBBB CCCC xxxx
8828 ARM: 1111 001U AAAA Axxx xxxx BBBB CCCC xxxx
8829 */
8830 if (!isT && INSN(31,25) == BITS7(1,1,1,1,0,0,1)) {
8831 // ARM, DP
8832 return dis_neon_data_processing(INSN(31,0), condT);
8833 }
8834 if (isT && INSN(31,29) == BITS3(1,1,1)
8835 && INSN(27,24) == BITS4(1,1,1,1)) {
8836 // Thumb, DP
8837 UInt reformatted = INSN(23,0);
8838 reformatted |= (INSN(28,28) << 24); // U bit
8839 reformatted |= (BITS7(1,1,1,1,0,0,1) << 25);
8840 return dis_neon_data_processing(reformatted, condT);
8841 }
8842
8843 /* Load/store:
8844 Thumb: 1111 1001 AxL0 xxxx xxxx BBBB xxxx xxxx
8845 ARM: 1111 0100 AxL0 xxxx xxxx BBBB xxxx xxxx
8846 */
8847 if (!isT && INSN(31,24) == BITS8(1,1,1,1,0,1,0,0)) {
8848 // ARM, memory
sewardj28958322011-07-21 22:45:42 +00008849 return dis_neon_load_or_store(INSN(31,0), isT, condT);
sewardjd2664472010-08-22 12:44:20 +00008850 }
8851 if (isT && INSN(31,24) == BITS8(1,1,1,1,1,0,0,1)) {
8852 UInt reformatted = INSN(23,0);
8853 reformatted |= (BITS8(1,1,1,1,0,1,0,0) << 24);
sewardj28958322011-07-21 22:45:42 +00008854 return dis_neon_load_or_store(reformatted, isT, condT);
sewardjd2664472010-08-22 12:44:20 +00008855 }
8856
8857 /* Doesn't match. */
8858 return False;
8859
8860# undef INSN
8861}
8862
8863
8864/*------------------------------------------------------------*/
sewardj1f139f52010-08-29 12:33:02 +00008865/*--- V6 MEDIA instructions ---*/
8866/*------------------------------------------------------------*/
8867
8868/* Both ARM and Thumb */
8869
8870/* Translate a V6 media instruction. If successful, returns
8871 True and *dres may or may not be updated. If failure, returns
8872 False and doesn't change *dres nor create any IR.
8873
8874 The Thumb and ARM encodings are completely different. In Thumb
8875 mode, the caller must pass the entire 32 bits. In ARM mode it must
8876 pass the lower 28 bits. Apart from that, callers may pass any
8877 instruction; this function ignores anything it doesn't recognise.
8878
8879 Caller must supply an IRTemp 'condT' holding the gating condition,
8880 or IRTemp_INVALID indicating the insn is always executed.
8881
8882 Caller must also supply an ARMCondcode 'cond'. This is only used
8883 for debug printing, no other purpose. For ARM, this is simply the
8884 top 4 bits of the original instruction. For Thumb, the condition
8885 is not (really) known until run time, and so ARMCondAL should be
8886 passed, only so that printing of these instructions does not show
8887 any condition.
8888
8889 Finally, the caller must indicate whether this occurs in ARM or in
8890 Thumb code.
8891*/
8892static Bool decode_V6MEDIA_instruction (
8893 /*MOD*/DisResult* dres,
8894 UInt insnv6m,
8895 IRTemp condT,
8896 ARMCondcode conq,
8897 Bool isT
8898 )
8899{
8900# define INSNA(_bMax,_bMin) SLICE_UInt(insnv6m, (_bMax), (_bMin))
8901# define INSNT0(_bMax,_bMin) SLICE_UInt( ((insnv6m >> 16) & 0xFFFF), \
8902 (_bMax), (_bMin) )
8903# define INSNT1(_bMax,_bMin) SLICE_UInt( ((insnv6m >> 0) & 0xFFFF), \
8904 (_bMax), (_bMin) )
8905 HChar dis_buf[128];
8906 dis_buf[0] = 0;
8907
8908 if (isT) {
8909 vassert(conq == ARMCondAL);
8910 } else {
8911 vassert(INSNA(31,28) == BITS4(0,0,0,0)); // caller's obligation
8912 vassert(conq >= ARMCondEQ && conq <= ARMCondAL);
8913 }
8914
8915 /* ----------- smulbb, smulbt, smultb, smultt ----------- */
8916 {
8917 UInt regD = 99, regM = 99, regN = 99, bitM = 0, bitN = 0;
8918 Bool gate = False;
8919
8920 if (isT) {
8921 if (INSNT0(15,4) == 0xFB1 && INSNT1(15,12) == BITS4(1,1,1,1)
8922 && INSNT1(7,6) == BITS2(0,0)) {
8923 regD = INSNT1(11,8);
8924 regM = INSNT1(3,0);
8925 regN = INSNT0(3,0);
8926 bitM = INSNT1(4,4);
8927 bitN = INSNT1(5,5);
8928 if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
8929 gate = True;
8930 }
8931 } else {
8932 if (BITS8(0,0,0,1,0,1,1,0) == INSNA(27,20) &&
8933 BITS4(0,0,0,0) == INSNA(15,12) &&
8934 BITS4(1,0,0,0) == (INSNA(7,4) & BITS4(1,0,0,1)) ) {
8935 regD = INSNA(19,16);
8936 regM = INSNA(11,8);
8937 regN = INSNA(3,0);
8938 bitM = INSNA(6,6);
8939 bitN = INSNA(5,5);
8940 if (regD != 15 && regN != 15 && regM != 15)
8941 gate = True;
8942 }
8943 }
8944
8945 if (gate) {
8946 IRTemp srcN = newTemp(Ity_I32);
8947 IRTemp srcM = newTemp(Ity_I32);
8948 IRTemp res = newTemp(Ity_I32);
8949
8950 assign( srcN, binop(Iop_Sar32,
8951 binop(Iop_Shl32,
8952 isT ? getIRegT(regN) : getIRegA(regN),
8953 mkU8(bitN ? 0 : 16)), mkU8(16)) );
8954 assign( srcM, binop(Iop_Sar32,
8955 binop(Iop_Shl32,
8956 isT ? getIRegT(regM) : getIRegA(regM),
8957 mkU8(bitM ? 0 : 16)), mkU8(16)) );
8958 assign( res, binop(Iop_Mul32, mkexpr(srcN), mkexpr(srcM)) );
8959
8960 if (isT)
8961 putIRegT( regD, mkexpr(res), condT );
8962 else
8963 putIRegA( regD, mkexpr(res), condT, Ijk_Boring );
8964
8965 DIP( "smul%c%c%s r%u, r%u, r%u\n", bitN ? 't' : 'b', bitM ? 't' : 'b',
8966 nCC(conq), regD, regN, regM );
8967 return True;
8968 }
8969 /* fall through */
8970 }
8971
8972 /* ------------ smulwb<y><c> <Rd>,<Rn>,<Rm> ------------- */
8973 /* ------------ smulwt<y><c> <Rd>,<Rn>,<Rm> ------------- */
8974 {
8975 UInt regD = 99, regN = 99, regM = 99, bitM = 0;
8976 Bool gate = False;
8977
8978 if (isT) {
8979 if (INSNT0(15,4) == 0xFB3 && INSNT1(15,12) == BITS4(1,1,1,1)
8980 && INSNT1(7,5) == BITS3(0,0,0)) {
8981 regN = INSNT0(3,0);
8982 regD = INSNT1(11,8);
8983 regM = INSNT1(3,0);
8984 bitM = INSNT1(4,4);
8985 if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
8986 gate = True;
8987 }
8988 } else {
8989 if (INSNA(27,20) == BITS8(0,0,0,1,0,0,1,0) &&
8990 INSNA(15,12) == BITS4(0,0,0,0) &&
8991 (INSNA(7,4) & BITS4(1,0,1,1)) == BITS4(1,0,1,0)) {
8992 regD = INSNA(19,16);
8993 regN = INSNA(3,0);
8994 regM = INSNA(11,8);
8995 bitM = INSNA(6,6);
8996 if (regD != 15 && regN != 15 && regM != 15)
8997 gate = True;
8998 }
8999 }
9000
9001 if (gate) {
9002 IRTemp irt_prod = newTemp(Ity_I64);
9003
9004 assign( irt_prod,
9005 binop(Iop_MullS32,
9006 isT ? getIRegT(regN) : getIRegA(regN),
9007 binop(Iop_Sar32,
9008 binop(Iop_Shl32,
9009 isT ? getIRegT(regM) : getIRegA(regM),
9010 mkU8(bitM ? 0 : 16)),
9011 mkU8(16))) );
9012
9013 IRExpr* ire_result = binop(Iop_Or32,
9014 binop( Iop_Shl32,
9015 unop(Iop_64HIto32, mkexpr(irt_prod)),
9016 mkU8(16) ),
9017 binop( Iop_Shr32,
9018 unop(Iop_64to32, mkexpr(irt_prod)),
9019 mkU8(16) ) );
9020
9021 if (isT)
9022 putIRegT( regD, ire_result, condT );
9023 else
9024 putIRegA( regD, ire_result, condT, Ijk_Boring );
9025
9026 DIP("smulw%c%s r%u, r%u, r%u\n",
9027 bitM ? 't' : 'b', nCC(conq),regD,regN,regM);
9028 return True;
9029 }
9030 /* fall through */
9031 }
9032
9033 /* ------------ pkhbt<c> Rd, Rn, Rm {,LSL #imm} ------------- */
9034 /* ------------ pkhtb<c> Rd, Rn, Rm {,ASR #imm} ------------- */
9035 {
9036 UInt regD = 99, regN = 99, regM = 99, imm5 = 99, shift_type = 99;
9037 Bool tbform = False;
9038 Bool gate = False;
9039
9040 if (isT) {
9041 if (INSNT0(15,4) == 0xEAC
9042 && INSNT1(15,15) == 0 && INSNT1(4,4) == 0) {
9043 regN = INSNT0(3,0);
9044 regD = INSNT1(11,8);
9045 regM = INSNT1(3,0);
9046 imm5 = (INSNT1(14,12) << 2) | INSNT1(7,6);
9047 shift_type = (INSNT1(5,5) << 1) | 0;
9048 tbform = (INSNT1(5,5) == 0) ? False : True;
9049 if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
9050 gate = True;
9051 }
9052 } else {
9053 if (INSNA(27,20) == BITS8(0,1,1,0,1,0,0,0) &&
9054 INSNA(5,4) == BITS2(0,1) &&
9055 (INSNA(6,6) == 0 || INSNA(6,6) == 1) ) {
9056 regD = INSNA(15,12);
9057 regN = INSNA(19,16);
9058 regM = INSNA(3,0);
9059 imm5 = INSNA(11,7);
9060 shift_type = (INSNA(6,6) << 1) | 0;
9061 tbform = (INSNA(6,6) == 0) ? False : True;
9062 if (regD != 15 && regN != 15 && regM != 15)
9063 gate = True;
9064 }
9065 }
9066
9067 if (gate) {
9068 IRTemp irt_regM = newTemp(Ity_I32);
9069 IRTemp irt_regM_shift = newTemp(Ity_I32);
9070 assign( irt_regM, isT ? getIRegT(regM) : getIRegA(regM) );
9071 compute_result_and_C_after_shift_by_imm5(
9072 dis_buf, &irt_regM_shift, NULL, irt_regM, shift_type, imm5, regM );
9073
9074 UInt mask = (tbform == True) ? 0x0000FFFF : 0xFFFF0000;
9075 IRExpr* ire_result
9076 = binop( Iop_Or32,
9077 binop(Iop_And32, mkexpr(irt_regM_shift), mkU32(mask)),
9078 binop(Iop_And32, isT ? getIRegT(regN) : getIRegA(regN),
9079 unop(Iop_Not32, mkU32(mask))) );
9080
9081 if (isT)
9082 putIRegT( regD, ire_result, condT );
9083 else
9084 putIRegA( regD, ire_result, condT, Ijk_Boring );
9085
9086 DIP( "pkh%s%s r%u, r%u, r%u %s\n", tbform ? "tb" : "bt",
9087 nCC(conq), regD, regN, regM, dis_buf );
9088
9089 return True;
9090 }
9091 /* fall through */
9092 }
9093
9094 /* ---------- usat<c> <Rd>,#<imm5>,<Rn>{,<shift>} ----------- */
9095 {
9096 UInt regD = 99, regN = 99, shift_type = 99, imm5 = 99, sat_imm = 99;
9097 Bool gate = False;
9098
9099 if (isT) {
9100 if (INSNT0(15,6) == BITS10(1,1,1,1,0,0,1,1,1,0)
9101 && INSNT0(4,4) == 0
9102 && INSNT1(15,15) == 0 && INSNT1(5,5) == 0) {
9103 regD = INSNT1(11,8);
9104 regN = INSNT0(3,0);
9105 shift_type = (INSNT0(5,5) << 1) | 0;
9106 imm5 = (INSNT1(14,12) << 2) | INSNT1(7,6);
9107 sat_imm = INSNT1(4,0);
9108 if (!isBadRegT(regD) && !isBadRegT(regN))
9109 gate = True;
9110 if (shift_type == BITS2(1,0) && imm5 == 0)
9111 gate = False;
9112 }
9113 } else {
9114 if (INSNA(27,21) == BITS7(0,1,1,0,1,1,1) &&
9115 INSNA(5,4) == BITS2(0,1)) {
9116 regD = INSNA(15,12);
9117 regN = INSNA(3,0);
9118 shift_type = (INSNA(6,6) << 1) | 0;
9119 imm5 = INSNA(11,7);
9120 sat_imm = INSNA(20,16);
9121 if (regD != 15 && regN != 15)
9122 gate = True;
9123 }
9124 }
9125
9126 if (gate) {
9127 IRTemp irt_regN = newTemp(Ity_I32);
9128 IRTemp irt_regN_shift = newTemp(Ity_I32);
9129 IRTemp irt_sat_Q = newTemp(Ity_I32);
9130 IRTemp irt_result = newTemp(Ity_I32);
9131
9132 assign( irt_regN, isT ? getIRegT(regN) : getIRegA(regN) );
9133 compute_result_and_C_after_shift_by_imm5(
9134 dis_buf, &irt_regN_shift, NULL,
9135 irt_regN, shift_type, imm5, regN );
9136
9137 armUnsignedSatQ( &irt_result, &irt_sat_Q, irt_regN_shift, sat_imm );
9138 or_into_QFLAG32( mkexpr(irt_sat_Q), condT );
9139
9140 if (isT)
9141 putIRegT( regD, mkexpr(irt_result), condT );
9142 else
9143 putIRegA( regD, mkexpr(irt_result), condT, Ijk_Boring );
9144
9145 DIP("usat%s r%u, #0x%04x, %s\n",
9146 nCC(conq), regD, imm5, dis_buf);
9147 return True;
9148 }
9149 /* fall through */
9150 }
9151
9152 /* ----------- ssat<c> <Rd>,#<imm5>,<Rn>{,<shift>} ----------- */
9153 {
9154 UInt regD = 99, regN = 99, shift_type = 99, imm5 = 99, sat_imm = 99;
9155 Bool gate = False;
9156
9157 if (isT) {
9158 if (INSNT0(15,6) == BITS10(1,1,1,1,0,0,1,1,0,0)
9159 && INSNT0(4,4) == 0
9160 && INSNT1(15,15) == 0 && INSNT1(5,5) == 0) {
9161 regD = INSNT1(11,8);
9162 regN = INSNT0(3,0);
9163 shift_type = (INSNT0(5,5) << 1) | 0;
9164 imm5 = (INSNT1(14,12) << 2) | INSNT1(7,6);
9165 sat_imm = INSNT1(4,0) + 1;
9166 if (!isBadRegT(regD) && !isBadRegT(regN))
9167 gate = True;
9168 if (shift_type == BITS2(1,0) && imm5 == 0)
9169 gate = False;
9170 }
9171 } else {
9172 if (INSNA(27,21) == BITS7(0,1,1,0,1,0,1) &&
9173 INSNA(5,4) == BITS2(0,1)) {
9174 regD = INSNA(15,12);
9175 regN = INSNA(3,0);
9176 shift_type = (INSNA(6,6) << 1) | 0;
9177 imm5 = INSNA(11,7);
9178 sat_imm = INSNA(20,16) + 1;
9179 if (regD != 15 && regN != 15)
9180 gate = True;
9181 }
9182 }
9183
9184 if (gate) {
9185 IRTemp irt_regN = newTemp(Ity_I32);
9186 IRTemp irt_regN_shift = newTemp(Ity_I32);
9187 IRTemp irt_sat_Q = newTemp(Ity_I32);
9188 IRTemp irt_result = newTemp(Ity_I32);
9189
9190 assign( irt_regN, isT ? getIRegT(regN) : getIRegA(regN) );
9191 compute_result_and_C_after_shift_by_imm5(
9192 dis_buf, &irt_regN_shift, NULL,
9193 irt_regN, shift_type, imm5, regN );
9194
9195 armSignedSatQ( irt_regN_shift, sat_imm, &irt_result, &irt_sat_Q );
9196 or_into_QFLAG32( mkexpr(irt_sat_Q), condT );
9197
9198 if (isT)
9199 putIRegT( regD, mkexpr(irt_result), condT );
9200 else
9201 putIRegA( regD, mkexpr(irt_result), condT, Ijk_Boring );
9202
9203 DIP( "ssat%s r%u, #0x%04x, %s\n",
9204 nCC(conq), regD, imm5, dis_buf);
9205 return True;
9206 }
9207 /* fall through */
9208 }
9209
sewardje6601582013-05-13 10:02:33 +00009210 /* ----------- ssat16<c> <Rd>,#<imm>,<Rn> ----------- */
9211 {
9212 UInt regD = 99, regN = 99, sat_imm = 99;
9213 Bool gate = False;
9214
9215 if (isT) {
9216 if (INSNT0(15,6) == BITS10(1,1,1,1,0,0,1,1,0,0)
9217 && INSNT0(5,4) == BITS2(1,0)
9218 && INSNT1(15,12) == BITS4(0,0,0,0)
9219 && INSNT1(7,4) == BITS4(0,0,0,0)) {
9220 regD = INSNT1(11,8);
9221 regN = INSNT0(3,0);
9222 sat_imm = INSNT1(3,0) + 1;
9223 if (!isBadRegT(regD) && !isBadRegT(regN))
9224 gate = True;
9225 }
9226 } else {
9227 if (INSNA(27,20) == BITS8(0,1,1,0,1,0,1,0) &&
9228 INSNA(11,4) == BITS8(1,1,1,1,0,0,1,1)) {
9229 regD = INSNA(15,12);
9230 regN = INSNA(3,0);
9231 sat_imm = INSNA(19,16) + 1;
9232 if (regD != 15 && regN != 15)
9233 gate = True;
9234 }
9235 }
9236
9237 if (gate) {
9238 IRTemp irt_regN = newTemp(Ity_I32);
9239 IRTemp irt_regN_lo = newTemp(Ity_I32);
9240 IRTemp irt_regN_hi = newTemp(Ity_I32);
9241 IRTemp irt_Q_lo = newTemp(Ity_I32);
9242 IRTemp irt_Q_hi = newTemp(Ity_I32);
9243 IRTemp irt_res_lo = newTemp(Ity_I32);
9244 IRTemp irt_res_hi = newTemp(Ity_I32);
9245
9246 assign( irt_regN, isT ? getIRegT(regN) : getIRegA(regN) );
9247 assign( irt_regN_lo,
9248 binop( Iop_Sar32,
9249 binop(Iop_Shl32, mkexpr(irt_regN), mkU8(16)),
9250 mkU8(16)) );
9251 assign( irt_regN_hi, binop(Iop_Sar32, mkexpr(irt_regN), mkU8(16)) );
9252
9253 armSignedSatQ( irt_regN_lo, sat_imm, &irt_res_lo, &irt_Q_lo );
9254 or_into_QFLAG32( mkexpr(irt_Q_lo), condT );
9255
9256 armSignedSatQ( irt_regN_hi, sat_imm, &irt_res_hi, &irt_Q_hi );
9257 or_into_QFLAG32( mkexpr(irt_Q_hi), condT );
9258
9259 IRExpr* ire_result
9260 = binop(Iop_Or32,
9261 binop(Iop_And32, mkexpr(irt_res_lo), mkU32(0xFFFF)),
9262 binop(Iop_Shl32, mkexpr(irt_res_hi), mkU8(16)));
9263 if (isT)
9264 putIRegT( regD, ire_result, condT );
9265 else
9266 putIRegA( regD, ire_result, condT, Ijk_Boring );
9267
9268 DIP( "ssat16%s r%u, #0x%04x, r%u\n", nCC(conq), regD, sat_imm, regN );
9269 return True;
9270 }
9271 /* fall through */
9272 }
9273
sewardj1f139f52010-08-29 12:33:02 +00009274 /* -------------- usat16<c> <Rd>,#<imm4>,<Rn> --------------- */
9275 {
9276 UInt regD = 99, regN = 99, sat_imm = 99;
9277 Bool gate = False;
9278
9279 if (isT) {
9280 if (INSNT0(15,4) == 0xF3A && (INSNT1(15,0) & 0xF0F0) == 0x0000) {
9281 regN = INSNT0(3,0);
9282 regD = INSNT1(11,8);
9283 sat_imm = INSNT1(3,0);
9284 if (!isBadRegT(regD) && !isBadRegT(regN))
9285 gate = True;
9286 }
9287 } else {
9288 if (INSNA(27,20) == BITS8(0,1,1,0,1,1,1,0) &&
9289 INSNA(11,8) == BITS4(1,1,1,1) &&
9290 INSNA(7,4) == BITS4(0,0,1,1)) {
9291 regD = INSNA(15,12);
9292 regN = INSNA(3,0);
9293 sat_imm = INSNA(19,16);
9294 if (regD != 15 && regN != 15)
9295 gate = True;
9296 }
9297 }
9298
9299 if (gate) {
9300 IRTemp irt_regN = newTemp(Ity_I32);
9301 IRTemp irt_regN_lo = newTemp(Ity_I32);
9302 IRTemp irt_regN_hi = newTemp(Ity_I32);
9303 IRTemp irt_Q_lo = newTemp(Ity_I32);
9304 IRTemp irt_Q_hi = newTemp(Ity_I32);
9305 IRTemp irt_res_lo = newTemp(Ity_I32);
9306 IRTemp irt_res_hi = newTemp(Ity_I32);
9307
9308 assign( irt_regN, isT ? getIRegT(regN) : getIRegA(regN) );
9309 assign( irt_regN_lo, binop( Iop_Sar32,
9310 binop(Iop_Shl32, mkexpr(irt_regN), mkU8(16)),
9311 mkU8(16)) );
9312 assign( irt_regN_hi, binop(Iop_Sar32, mkexpr(irt_regN), mkU8(16)) );
9313
9314 armUnsignedSatQ( &irt_res_lo, &irt_Q_lo, irt_regN_lo, sat_imm );
9315 or_into_QFLAG32( mkexpr(irt_Q_lo), condT );
9316
9317 armUnsignedSatQ( &irt_res_hi, &irt_Q_hi, irt_regN_hi, sat_imm );
9318 or_into_QFLAG32( mkexpr(irt_Q_hi), condT );
9319
9320 IRExpr* ire_result = binop( Iop_Or32,
9321 binop(Iop_Shl32, mkexpr(irt_res_hi), mkU8(16)),
9322 mkexpr(irt_res_lo) );
9323
9324 if (isT)
9325 putIRegT( regD, ire_result, condT );
9326 else
9327 putIRegA( regD, ire_result, condT, Ijk_Boring );
9328
9329 DIP( "usat16%s r%u, #0x%04x, r%u\n", nCC(conq), regD, sat_imm, regN );
9330 return True;
9331 }
9332 /* fall through */
9333 }
9334
9335 /* -------------- uadd16<c> <Rd>,<Rn>,<Rm> -------------- */
9336 {
9337 UInt regD = 99, regN = 99, regM = 99;
9338 Bool gate = False;
9339
9340 if (isT) {
9341 if (INSNT0(15,4) == 0xFA9 && (INSNT1(15,0) & 0xF0F0) == 0xF040) {
9342 regN = INSNT0(3,0);
9343 regD = INSNT1(11,8);
9344 regM = INSNT1(3,0);
9345 if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
9346 gate = True;
9347 }
9348 } else {
9349 if (INSNA(27,20) == BITS8(0,1,1,0,0,1,0,1) &&
9350 INSNA(11,8) == BITS4(1,1,1,1) &&
9351 INSNA(7,4) == BITS4(0,0,0,1)) {
9352 regD = INSNA(15,12);
9353 regN = INSNA(19,16);
9354 regM = INSNA(3,0);
9355 if (regD != 15 && regN != 15 && regM != 15)
9356 gate = True;
9357 }
9358 }
9359
9360 if (gate) {
sewardje2ea1762010-09-22 00:56:37 +00009361 IRTemp rNt = newTemp(Ity_I32);
9362 IRTemp rMt = newTemp(Ity_I32);
9363 IRTemp res = newTemp(Ity_I32);
9364 IRTemp reso = newTemp(Ity_I32);
sewardj1f139f52010-08-29 12:33:02 +00009365
sewardje2ea1762010-09-22 00:56:37 +00009366 assign( rNt, isT ? getIRegT(regN) : getIRegA(regN) );
9367 assign( rMt, isT ? getIRegT(regM) : getIRegA(regM) );
sewardj1f139f52010-08-29 12:33:02 +00009368
sewardje2ea1762010-09-22 00:56:37 +00009369 assign(res, binop(Iop_Add16x2, mkexpr(rNt), mkexpr(rMt)));
sewardj1f139f52010-08-29 12:33:02 +00009370 if (isT)
sewardje2ea1762010-09-22 00:56:37 +00009371 putIRegT( regD, mkexpr(res), condT );
sewardj1f139f52010-08-29 12:33:02 +00009372 else
sewardje2ea1762010-09-22 00:56:37 +00009373 putIRegA( regD, mkexpr(res), condT, Ijk_Boring );
9374
9375 assign(reso, binop(Iop_HAdd16Ux2, mkexpr(rNt), mkexpr(rMt)));
9376 set_GE_32_10_from_bits_31_15(reso, condT);
sewardj1f139f52010-08-29 12:33:02 +00009377
9378 DIP("uadd16%s r%u, r%u, r%u\n", nCC(conq),regD,regN,regM);
9379 return True;
9380 }
9381 /* fall through */
9382 }
9383
sewardj22ac5962010-09-20 22:35:35 +00009384 /* -------------- sadd16<c> <Rd>,<Rn>,<Rm> -------------- */
9385 {
9386 UInt regD = 99, regN = 99, regM = 99;
9387 Bool gate = False;
9388
9389 if (isT) {
9390 if (INSNT0(15,4) == 0xFA9 && (INSNT1(15,0) & 0xF0F0) == 0xF000) {
9391 regN = INSNT0(3,0);
9392 regD = INSNT1(11,8);
9393 regM = INSNT1(3,0);
9394 if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
9395 gate = True;
9396 }
9397 } else {
9398 if (INSNA(27,20) == BITS8(0,1,1,0,0,0,0,1) &&
9399 INSNA(11,8) == BITS4(1,1,1,1) &&
9400 INSNA(7,4) == BITS4(0,0,0,1)) {
9401 regD = INSNA(15,12);
9402 regN = INSNA(19,16);
9403 regM = INSNA(3,0);
9404 if (regD != 15 && regN != 15 && regM != 15)
9405 gate = True;
9406 }
9407 }
9408
9409 if (gate) {
sewardje2ea1762010-09-22 00:56:37 +00009410 IRTemp rNt = newTemp(Ity_I32);
9411 IRTemp rMt = newTemp(Ity_I32);
9412 IRTemp res = newTemp(Ity_I32);
9413 IRTemp reso = newTemp(Ity_I32);
sewardj22ac5962010-09-20 22:35:35 +00009414
sewardje2ea1762010-09-22 00:56:37 +00009415 assign( rNt, isT ? getIRegT(regN) : getIRegA(regN) );
9416 assign( rMt, isT ? getIRegT(regM) : getIRegA(regM) );
sewardj22ac5962010-09-20 22:35:35 +00009417
sewardje2ea1762010-09-22 00:56:37 +00009418 assign(res, binop(Iop_Add16x2, mkexpr(rNt), mkexpr(rMt)));
sewardj22ac5962010-09-20 22:35:35 +00009419 if (isT)
sewardje2ea1762010-09-22 00:56:37 +00009420 putIRegT( regD, mkexpr(res), condT );
sewardj22ac5962010-09-20 22:35:35 +00009421 else
sewardje2ea1762010-09-22 00:56:37 +00009422 putIRegA( regD, mkexpr(res), condT, Ijk_Boring );
9423
9424 assign(reso, unop(Iop_Not32,
9425 binop(Iop_HAdd16Sx2, mkexpr(rNt), mkexpr(rMt))));
9426 set_GE_32_10_from_bits_31_15(reso, condT);
sewardj22ac5962010-09-20 22:35:35 +00009427
9428 DIP("sadd16%s r%u, r%u, r%u\n", nCC(conq),regD,regN,regM);
9429 return True;
9430 }
9431 /* fall through */
9432 }
9433
sewardj1f139f52010-08-29 12:33:02 +00009434 /* ---------------- usub16<c> <Rd>,<Rn>,<Rm> ---------------- */
9435 {
9436 UInt regD = 99, regN = 99, regM = 99;
9437 Bool gate = False;
9438
9439 if (isT) {
9440 if (INSNT0(15,4) == 0xFAD && (INSNT1(15,0) & 0xF0F0) == 0xF040) {
9441 regN = INSNT0(3,0);
9442 regD = INSNT1(11,8);
9443 regM = INSNT1(3,0);
9444 if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
9445 gate = True;
9446 }
9447 } else {
9448 if (INSNA(27,20) == BITS8(0,1,1,0,0,1,0,1) &&
9449 INSNA(11,8) == BITS4(1,1,1,1) &&
9450 INSNA(7,4) == BITS4(0,1,1,1)) {
9451 regD = INSNA(15,12);
9452 regN = INSNA(19,16);
9453 regM = INSNA(3,0);
9454 if (regD != 15 && regN != 15 && regM != 15)
9455 gate = True;
9456 }
9457 }
9458
9459 if (gate) {
sewardje2ea1762010-09-22 00:56:37 +00009460 IRTemp rNt = newTemp(Ity_I32);
9461 IRTemp rMt = newTemp(Ity_I32);
9462 IRTemp res = newTemp(Ity_I32);
9463 IRTemp reso = newTemp(Ity_I32);
sewardj1f139f52010-08-29 12:33:02 +00009464
sewardje2ea1762010-09-22 00:56:37 +00009465 assign( rNt, isT ? getIRegT(regN) : getIRegA(regN) );
9466 assign( rMt, isT ? getIRegT(regM) : getIRegA(regM) );
sewardj1f139f52010-08-29 12:33:02 +00009467
sewardje2ea1762010-09-22 00:56:37 +00009468 assign(res, binop(Iop_Sub16x2, mkexpr(rNt), mkexpr(rMt)));
sewardj1f139f52010-08-29 12:33:02 +00009469 if (isT)
sewardje2ea1762010-09-22 00:56:37 +00009470 putIRegT( regD, mkexpr(res), condT );
sewardj1f139f52010-08-29 12:33:02 +00009471 else
sewardje2ea1762010-09-22 00:56:37 +00009472 putIRegA( regD, mkexpr(res), condT, Ijk_Boring );
sewardj1f139f52010-08-29 12:33:02 +00009473
sewardje2ea1762010-09-22 00:56:37 +00009474 assign(reso, unop(Iop_Not32,
9475 binop(Iop_HSub16Ux2, mkexpr(rNt), mkexpr(rMt))));
9476 set_GE_32_10_from_bits_31_15(reso, condT);
9477
9478 DIP("usub16%s r%u, r%u, r%u\n", nCC(conq),regD,regN,regM);
sewardj1f139f52010-08-29 12:33:02 +00009479 return True;
9480 }
9481 /* fall through */
9482 }
9483
sewardj22ac5962010-09-20 22:35:35 +00009484 /* -------------- ssub16<c> <Rd>,<Rn>,<Rm> -------------- */
9485 {
9486 UInt regD = 99, regN = 99, regM = 99;
9487 Bool gate = False;
9488
9489 if (isT) {
9490 if (INSNT0(15,4) == 0xFAD && (INSNT1(15,0) & 0xF0F0) == 0xF000) {
9491 regN = INSNT0(3,0);
9492 regD = INSNT1(11,8);
9493 regM = INSNT1(3,0);
9494 if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
9495 gate = True;
9496 }
9497 } else {
9498 if (INSNA(27,20) == BITS8(0,1,1,0,0,0,0,1) &&
9499 INSNA(11,8) == BITS4(1,1,1,1) &&
9500 INSNA(7,4) == BITS4(0,1,1,1)) {
9501 regD = INSNA(15,12);
9502 regN = INSNA(19,16);
9503 regM = INSNA(3,0);
9504 if (regD != 15 && regN != 15 && regM != 15)
9505 gate = True;
9506 }
9507 }
9508
9509 if (gate) {
sewardje2ea1762010-09-22 00:56:37 +00009510 IRTemp rNt = newTemp(Ity_I32);
9511 IRTemp rMt = newTemp(Ity_I32);
9512 IRTemp res = newTemp(Ity_I32);
9513 IRTemp reso = newTemp(Ity_I32);
sewardj22ac5962010-09-20 22:35:35 +00009514
sewardje2ea1762010-09-22 00:56:37 +00009515 assign( rNt, isT ? getIRegT(regN) : getIRegA(regN) );
9516 assign( rMt, isT ? getIRegT(regM) : getIRegA(regM) );
sewardj22ac5962010-09-20 22:35:35 +00009517
sewardje2ea1762010-09-22 00:56:37 +00009518 assign(res, binop(Iop_Sub16x2, mkexpr(rNt), mkexpr(rMt)));
sewardj22ac5962010-09-20 22:35:35 +00009519 if (isT)
sewardje2ea1762010-09-22 00:56:37 +00009520 putIRegT( regD, mkexpr(res), condT );
sewardj22ac5962010-09-20 22:35:35 +00009521 else
sewardje2ea1762010-09-22 00:56:37 +00009522 putIRegA( regD, mkexpr(res), condT, Ijk_Boring );
9523
9524 assign(reso, unop(Iop_Not32,
9525 binop(Iop_HSub16Sx2, mkexpr(rNt), mkexpr(rMt))));
9526 set_GE_32_10_from_bits_31_15(reso, condT);
sewardj22ac5962010-09-20 22:35:35 +00009527
9528 DIP("ssub16%s r%u, r%u, r%u\n", nCC(conq),regD,regN,regM);
9529 return True;
9530 }
9531 /* fall through */
9532 }
9533
sewardj1f139f52010-08-29 12:33:02 +00009534 /* ----------------- uadd8<c> <Rd>,<Rn>,<Rm> ---------------- */
9535 {
9536 UInt regD = 99, regN = 99, regM = 99;
9537 Bool gate = False;
9538
9539 if (isT) {
9540 if (INSNT0(15,4) == 0xFA8 && (INSNT1(15,0) & 0xF0F0) == 0xF040) {
9541 regN = INSNT0(3,0);
9542 regD = INSNT1(11,8);
9543 regM = INSNT1(3,0);
9544 if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
9545 gate = True;
9546 }
9547 } else {
9548 if (INSNA(27,20) == BITS8(0,1,1,0,0,1,0,1) &&
9549 INSNA(11,8) == BITS4(1,1,1,1) &&
9550 (INSNA(7,4) == BITS4(1,0,0,1))) {
9551 regD = INSNA(15,12);
9552 regN = INSNA(19,16);
9553 regM = INSNA(3,0);
9554 if (regD != 15 && regN != 15 && regM != 15)
9555 gate = True;
9556 }
9557 }
9558
9559 if (gate) {
sewardje2ea1762010-09-22 00:56:37 +00009560 IRTemp rNt = newTemp(Ity_I32);
9561 IRTemp rMt = newTemp(Ity_I32);
9562 IRTemp res = newTemp(Ity_I32);
9563 IRTemp reso = newTemp(Ity_I32);
sewardj1f139f52010-08-29 12:33:02 +00009564
sewardje2ea1762010-09-22 00:56:37 +00009565 assign( rNt, isT ? getIRegT(regN) : getIRegA(regN) );
9566 assign( rMt, isT ? getIRegT(regM) : getIRegA(regM) );
sewardj1f139f52010-08-29 12:33:02 +00009567
sewardje2ea1762010-09-22 00:56:37 +00009568 assign(res, binop(Iop_Add8x4, mkexpr(rNt), mkexpr(rMt)));
sewardj1f139f52010-08-29 12:33:02 +00009569 if (isT)
sewardje2ea1762010-09-22 00:56:37 +00009570 putIRegT( regD, mkexpr(res), condT );
sewardj1f139f52010-08-29 12:33:02 +00009571 else
sewardje2ea1762010-09-22 00:56:37 +00009572 putIRegA( regD, mkexpr(res), condT, Ijk_Boring );
sewardj1f139f52010-08-29 12:33:02 +00009573
sewardje2ea1762010-09-22 00:56:37 +00009574 assign(reso, binop(Iop_HAdd8Ux4, mkexpr(rNt), mkexpr(rMt)));
9575 set_GE_3_2_1_0_from_bits_31_23_15_7(reso, condT);
9576
9577 DIP("uadd8%s r%u, r%u, r%u\n", nCC(conq),regD,regN,regM);
9578 return True;
9579 }
9580 /* fall through */
9581 }
9582
9583 /* ------------------- sadd8<c> <Rd>,<Rn>,<Rm> ------------------ */
9584 {
9585 UInt regD = 99, regN = 99, regM = 99;
9586 Bool gate = False;
9587
9588 if (isT) {
9589 if (INSNT0(15,4) == 0xFA8 && (INSNT1(15,0) & 0xF0F0) == 0xF000) {
9590 regN = INSNT0(3,0);
9591 regD = INSNT1(11,8);
9592 regM = INSNT1(3,0);
9593 if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
9594 gate = True;
9595 }
9596 } else {
9597 if (INSNA(27,20) == BITS8(0,1,1,0,0,0,0,1) &&
9598 INSNA(11,8) == BITS4(1,1,1,1) &&
9599 (INSNA(7,4) == BITS4(1,0,0,1))) {
9600 regD = INSNA(15,12);
9601 regN = INSNA(19,16);
9602 regM = INSNA(3,0);
9603 if (regD != 15 && regN != 15 && regM != 15)
9604 gate = True;
9605 }
9606 }
9607
9608 if (gate) {
9609 IRTemp rNt = newTemp(Ity_I32);
9610 IRTemp rMt = newTemp(Ity_I32);
9611 IRTemp res = newTemp(Ity_I32);
9612 IRTemp reso = newTemp(Ity_I32);
9613
9614 assign( rNt, isT ? getIRegT(regN) : getIRegA(regN) );
9615 assign( rMt, isT ? getIRegT(regM) : getIRegA(regM) );
9616
9617 assign(res, binop(Iop_Add8x4, mkexpr(rNt), mkexpr(rMt)));
9618 if (isT)
9619 putIRegT( regD, mkexpr(res), condT );
9620 else
9621 putIRegA( regD, mkexpr(res), condT, Ijk_Boring );
9622
9623 assign(reso, unop(Iop_Not32,
9624 binop(Iop_HAdd8Sx4, mkexpr(rNt), mkexpr(rMt))));
9625 set_GE_3_2_1_0_from_bits_31_23_15_7(reso, condT);
9626
9627 DIP("sadd8%s r%u, r%u, r%u\n", nCC(conq),regD,regN,regM);
sewardj1f139f52010-08-29 12:33:02 +00009628 return True;
9629 }
9630 /* fall through */
9631 }
9632
9633 /* ------------------- usub8<c> <Rd>,<Rn>,<Rm> ------------------ */
9634 {
9635 UInt regD = 99, regN = 99, regM = 99;
9636 Bool gate = False;
9637
9638 if (isT) {
9639 if (INSNT0(15,4) == 0xFAC && (INSNT1(15,0) & 0xF0F0) == 0xF040) {
9640 regN = INSNT0(3,0);
9641 regD = INSNT1(11,8);
9642 regM = INSNT1(3,0);
9643 if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
9644 gate = True;
9645 }
9646 } else {
9647 if (INSNA(27,20) == BITS8(0,1,1,0,0,1,0,1) &&
9648 INSNA(11,8) == BITS4(1,1,1,1) &&
9649 (INSNA(7,4) == BITS4(1,1,1,1))) {
9650 regD = INSNA(15,12);
9651 regN = INSNA(19,16);
9652 regM = INSNA(3,0);
9653 if (regD != 15 && regN != 15 && regM != 15)
9654 gate = True;
9655 }
9656 }
9657
9658 if (gate) {
sewardje2ea1762010-09-22 00:56:37 +00009659 IRTemp rNt = newTemp(Ity_I32);
9660 IRTemp rMt = newTemp(Ity_I32);
9661 IRTemp res = newTemp(Ity_I32);
9662 IRTemp reso = newTemp(Ity_I32);
sewardj1f139f52010-08-29 12:33:02 +00009663
sewardje2ea1762010-09-22 00:56:37 +00009664 assign( rNt, isT ? getIRegT(regN) : getIRegA(regN) );
9665 assign( rMt, isT ? getIRegT(regM) : getIRegA(regM) );
sewardj1f139f52010-08-29 12:33:02 +00009666
sewardje2ea1762010-09-22 00:56:37 +00009667 assign(res, binop(Iop_Sub8x4, mkexpr(rNt), mkexpr(rMt)));
sewardj1f139f52010-08-29 12:33:02 +00009668 if (isT)
sewardje2ea1762010-09-22 00:56:37 +00009669 putIRegT( regD, mkexpr(res), condT );
sewardj1f139f52010-08-29 12:33:02 +00009670 else
sewardje2ea1762010-09-22 00:56:37 +00009671 putIRegA( regD, mkexpr(res), condT, Ijk_Boring );
sewardj1f139f52010-08-29 12:33:02 +00009672
sewardje2ea1762010-09-22 00:56:37 +00009673 assign(reso, unop(Iop_Not32,
9674 binop(Iop_HSub8Ux4, mkexpr(rNt), mkexpr(rMt))));
9675 set_GE_3_2_1_0_from_bits_31_23_15_7(reso, condT);
9676
9677 DIP("usub8%s r%u, r%u, r%u\n", nCC(conq),regD,regN,regM);
9678 return True;
9679 }
9680 /* fall through */
9681 }
9682
9683 /* ------------------- ssub8<c> <Rd>,<Rn>,<Rm> ------------------ */
9684 {
9685 UInt regD = 99, regN = 99, regM = 99;
9686 Bool gate = False;
9687
9688 if (isT) {
9689 if (INSNT0(15,4) == 0xFAC && (INSNT1(15,0) & 0xF0F0) == 0xF000) {
9690 regN = INSNT0(3,0);
9691 regD = INSNT1(11,8);
9692 regM = INSNT1(3,0);
9693 if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
9694 gate = True;
9695 }
9696 } else {
9697 if (INSNA(27,20) == BITS8(0,1,1,0,0,0,0,1) &&
9698 INSNA(11,8) == BITS4(1,1,1,1) &&
9699 INSNA(7,4) == BITS4(1,1,1,1)) {
9700 regD = INSNA(15,12);
9701 regN = INSNA(19,16);
9702 regM = INSNA(3,0);
9703 if (regD != 15 && regN != 15 && regM != 15)
9704 gate = True;
9705 }
9706 }
9707
9708 if (gate) {
9709 IRTemp rNt = newTemp(Ity_I32);
9710 IRTemp rMt = newTemp(Ity_I32);
9711 IRTemp res = newTemp(Ity_I32);
9712 IRTemp reso = newTemp(Ity_I32);
9713
9714 assign( rNt, isT ? getIRegT(regN) : getIRegA(regN) );
9715 assign( rMt, isT ? getIRegT(regM) : getIRegA(regM) );
9716
9717 assign(res, binop(Iop_Sub8x4, mkexpr(rNt), mkexpr(rMt)));
9718 if (isT)
9719 putIRegT( regD, mkexpr(res), condT );
9720 else
9721 putIRegA( regD, mkexpr(res), condT, Ijk_Boring );
9722
9723 assign(reso, unop(Iop_Not32,
9724 binop(Iop_HSub8Sx4, mkexpr(rNt), mkexpr(rMt))));
9725 set_GE_3_2_1_0_from_bits_31_23_15_7(reso, condT);
9726
9727 DIP("ssub8%s r%u, r%u, r%u\n", nCC(conq),regD,regN,regM);
9728 return True;
9729 }
9730 /* fall through */
9731 }
9732
9733 /* ------------------ qadd8<c> <Rd>,<Rn>,<Rm> ------------------- */
9734 {
9735 UInt regD = 99, regN = 99, regM = 99;
9736 Bool gate = False;
9737
9738 if (isT) {
9739 if (INSNT0(15,4) == 0xFA8 && (INSNT1(15,0) & 0xF0F0) == 0xF010) {
9740 regN = INSNT0(3,0);
9741 regD = INSNT1(11,8);
9742 regM = INSNT1(3,0);
9743 if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
9744 gate = True;
9745 }
9746 } else {
9747 if (INSNA(27,20) == BITS8(0,1,1,0,0,0,1,0) &&
9748 INSNA(11,8) == BITS4(1,1,1,1) &&
9749 INSNA(7,4) == BITS4(1,0,0,1)) {
9750 regD = INSNA(15,12);
9751 regN = INSNA(19,16);
9752 regM = INSNA(3,0);
9753 if (regD != 15 && regN != 15 && regM != 15)
9754 gate = True;
9755 }
9756 }
9757
9758 if (gate) {
9759 IRTemp rNt = newTemp(Ity_I32);
9760 IRTemp rMt = newTemp(Ity_I32);
9761 IRTemp res_q = newTemp(Ity_I32);
9762
9763 assign( rNt, isT ? getIRegT(regN) : getIRegA(regN) );
9764 assign( rMt, isT ? getIRegT(regM) : getIRegA(regM) );
9765
9766 assign(res_q, binop(Iop_QAdd8Sx4, mkexpr(rNt), mkexpr(rMt)));
9767 if (isT)
9768 putIRegT( regD, mkexpr(res_q), condT );
9769 else
9770 putIRegA( regD, mkexpr(res_q), condT, Ijk_Boring );
9771
9772 DIP("qadd8%s r%u, r%u, r%u\n", nCC(conq),regD,regN,regM);
9773 return True;
9774 }
9775 /* fall through */
9776 }
9777
9778 /* ------------------ qsub8<c> <Rd>,<Rn>,<Rm> ------------------- */
9779 {
9780 UInt regD = 99, regN = 99, regM = 99;
9781 Bool gate = False;
9782
9783 if (isT) {
9784 if (INSNT0(15,4) == 0xFAC && (INSNT1(15,0) & 0xF0F0) == 0xF010) {
9785 regN = INSNT0(3,0);
9786 regD = INSNT1(11,8);
9787 regM = INSNT1(3,0);
9788 if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
9789 gate = True;
9790 }
9791 } else {
9792 if (INSNA(27,20) == BITS8(0,1,1,0,0,0,1,0) &&
9793 INSNA(11,8) == BITS4(1,1,1,1) &&
9794 INSNA(7,4) == BITS4(1,1,1,1)) {
9795 regD = INSNA(15,12);
9796 regN = INSNA(19,16);
9797 regM = INSNA(3,0);
9798 if (regD != 15 && regN != 15 && regM != 15)
9799 gate = True;
9800 }
9801 }
9802
9803 if (gate) {
9804 IRTemp rNt = newTemp(Ity_I32);
9805 IRTemp rMt = newTemp(Ity_I32);
9806 IRTemp res_q = newTemp(Ity_I32);
9807
9808 assign( rNt, isT ? getIRegT(regN) : getIRegA(regN) );
9809 assign( rMt, isT ? getIRegT(regM) : getIRegA(regM) );
9810
9811 assign(res_q, binop(Iop_QSub8Sx4, mkexpr(rNt), mkexpr(rMt)));
9812 if (isT)
9813 putIRegT( regD, mkexpr(res_q), condT );
9814 else
9815 putIRegA( regD, mkexpr(res_q), condT, Ijk_Boring );
9816
9817 DIP("qsub8%s r%u, r%u, r%u\n", nCC(conq),regD,regN,regM);
9818 return True;
9819 }
9820 /* fall through */
9821 }
9822
9823 /* ------------------ uqadd8<c> <Rd>,<Rn>,<Rm> ------------------ */
9824 {
9825 UInt regD = 99, regN = 99, regM = 99;
9826 Bool gate = False;
9827
9828 if (isT) {
9829 if (INSNT0(15,4) == 0xFA8 && (INSNT1(15,0) & 0xF0F0) == 0xF050) {
9830 regN = INSNT0(3,0);
9831 regD = INSNT1(11,8);
9832 regM = INSNT1(3,0);
9833 if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
9834 gate = True;
9835 }
9836 } else {
9837 if (INSNA(27,20) == BITS8(0,1,1,0,0,1,1,0) &&
9838 INSNA(11,8) == BITS4(1,1,1,1) &&
9839 (INSNA(7,4) == BITS4(1,0,0,1))) {
9840 regD = INSNA(15,12);
9841 regN = INSNA(19,16);
9842 regM = INSNA(3,0);
9843 if (regD != 15 && regN != 15 && regM != 15)
9844 gate = True;
9845 }
9846 }
9847
9848 if (gate) {
9849 IRTemp rNt = newTemp(Ity_I32);
9850 IRTemp rMt = newTemp(Ity_I32);
9851 IRTemp res_q = newTemp(Ity_I32);
9852
9853 assign( rNt, isT ? getIRegT(regN) : getIRegA(regN) );
9854 assign( rMt, isT ? getIRegT(regM) : getIRegA(regM) );
9855
9856 assign(res_q, binop(Iop_QAdd8Ux4, mkexpr(rNt), mkexpr(rMt)));
9857 if (isT)
9858 putIRegT( regD, mkexpr(res_q), condT );
9859 else
9860 putIRegA( regD, mkexpr(res_q), condT, Ijk_Boring );
9861
9862 DIP("uqadd8%s r%u, r%u, r%u\n", nCC(conq),regD,regN,regM);
9863 return True;
9864 }
9865 /* fall through */
9866 }
9867
9868 /* ------------------ uqsub8<c> <Rd>,<Rn>,<Rm> ------------------ */
9869 {
9870 UInt regD = 99, regN = 99, regM = 99;
9871 Bool gate = False;
9872
9873 if (isT) {
9874 if (INSNT0(15,4) == 0xFAC && (INSNT1(15,0) & 0xF0F0) == 0xF050) {
9875 regN = INSNT0(3,0);
9876 regD = INSNT1(11,8);
9877 regM = INSNT1(3,0);
9878 if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
9879 gate = True;
9880 }
9881 } else {
9882 if (INSNA(27,20) == BITS8(0,1,1,0,0,1,1,0) &&
9883 INSNA(11,8) == BITS4(1,1,1,1) &&
9884 (INSNA(7,4) == BITS4(1,1,1,1))) {
9885 regD = INSNA(15,12);
9886 regN = INSNA(19,16);
9887 regM = INSNA(3,0);
9888 if (regD != 15 && regN != 15 && regM != 15)
9889 gate = True;
9890 }
9891 }
9892
9893 if (gate) {
9894 IRTemp rNt = newTemp(Ity_I32);
9895 IRTemp rMt = newTemp(Ity_I32);
9896 IRTemp res_q = newTemp(Ity_I32);
9897
9898 assign( rNt, isT ? getIRegT(regN) : getIRegA(regN) );
9899 assign( rMt, isT ? getIRegT(regM) : getIRegA(regM) );
9900
9901 assign(res_q, binop(Iop_QSub8Ux4, mkexpr(rNt), mkexpr(rMt)));
9902 if (isT)
9903 putIRegT( regD, mkexpr(res_q), condT );
9904 else
9905 putIRegA( regD, mkexpr(res_q), condT, Ijk_Boring );
9906
9907 DIP("uqsub8%s r%u, r%u, r%u\n", nCC(conq),regD,regN,regM);
9908 return True;
9909 }
9910 /* fall through */
9911 }
9912
9913 /* ----------------- uhadd8<c> <Rd>,<Rn>,<Rm> ------------------- */
9914 {
9915 UInt regD = 99, regN = 99, regM = 99;
9916 Bool gate = False;
9917
9918 if (isT) {
9919 if (INSNT0(15,4) == 0xFA8 && (INSNT1(15,0) & 0xF0F0) == 0xF060) {
9920 regN = INSNT0(3,0);
9921 regD = INSNT1(11,8);
9922 regM = INSNT1(3,0);
9923 if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
9924 gate = True;
9925 }
9926 } else {
9927 if (INSNA(27,20) == BITS8(0,1,1,0,0,1,1,1) &&
9928 INSNA(11,8) == BITS4(1,1,1,1) &&
9929 INSNA(7,4) == BITS4(1,0,0,1)) {
9930 regD = INSNA(15,12);
9931 regN = INSNA(19,16);
9932 regM = INSNA(3,0);
9933 if (regD != 15 && regN != 15 && regM != 15)
9934 gate = True;
9935 }
9936 }
9937
9938 if (gate) {
9939 IRTemp rNt = newTemp(Ity_I32);
9940 IRTemp rMt = newTemp(Ity_I32);
9941 IRTemp res_q = newTemp(Ity_I32);
9942
9943 assign( rNt, isT ? getIRegT(regN) : getIRegA(regN) );
9944 assign( rMt, isT ? getIRegT(regM) : getIRegA(regM) );
9945
9946 assign(res_q, binop(Iop_HAdd8Ux4, mkexpr(rNt), mkexpr(rMt)));
9947 if (isT)
9948 putIRegT( regD, mkexpr(res_q), condT );
9949 else
9950 putIRegA( regD, mkexpr(res_q), condT, Ijk_Boring );
9951
9952 DIP("uhadd8%s r%u, r%u, r%u\n", nCC(conq),regD,regN,regM);
9953 return True;
9954 }
9955 /* fall through */
9956 }
9957
sewardj9de28092012-06-22 09:27:54 +00009958 /* ----------------- uhadd16<c> <Rd>,<Rn>,<Rm> ------------------- */
9959 {
9960 UInt regD = 99, regN = 99, regM = 99;
9961 Bool gate = False;
9962
9963 if (isT) {
9964 if (INSNT0(15,4) == 0xFA9 && (INSNT1(15,0) & 0xF0F0) == 0xF060) {
9965 regN = INSNT0(3,0);
9966 regD = INSNT1(11,8);
9967 regM = INSNT1(3,0);
9968 if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
9969 gate = True;
9970 }
9971 } else {
9972 if (INSNA(27,20) == BITS8(0,1,1,0,0,1,1,1) &&
9973 INSNA(11,8) == BITS4(1,1,1,1) &&
9974 INSNA(7,4) == BITS4(0,0,0,1)) {
9975 regD = INSNA(15,12);
9976 regN = INSNA(19,16);
9977 regM = INSNA(3,0);
9978 if (regD != 15 && regN != 15 && regM != 15)
9979 gate = True;
9980 }
9981 }
9982
9983 if (gate) {
9984 IRTemp rNt = newTemp(Ity_I32);
9985 IRTemp rMt = newTemp(Ity_I32);
9986 IRTemp res_q = newTemp(Ity_I32);
9987
9988 assign( rNt, isT ? getIRegT(regN) : getIRegA(regN) );
9989 assign( rMt, isT ? getIRegT(regM) : getIRegA(regM) );
9990
9991 assign(res_q, binop(Iop_HAdd16Ux2, mkexpr(rNt), mkexpr(rMt)));
9992 if (isT)
9993 putIRegT( regD, mkexpr(res_q), condT );
9994 else
9995 putIRegA( regD, mkexpr(res_q), condT, Ijk_Boring );
9996
9997 DIP("uhadd16%s r%u, r%u, r%u\n", nCC(conq),regD,regN,regM);
9998 return True;
9999 }
10000 /* fall through */
10001 }
10002
sewardje2ea1762010-09-22 00:56:37 +000010003 /* ----------------- shadd8<c> <Rd>,<Rn>,<Rm> ------------------- */
10004 {
10005 UInt regD = 99, regN = 99, regM = 99;
10006 Bool gate = False;
10007
10008 if (isT) {
10009 if (INSNT0(15,4) == 0xFA8 && (INSNT1(15,0) & 0xF0F0) == 0xF020) {
10010 regN = INSNT0(3,0);
10011 regD = INSNT1(11,8);
10012 regM = INSNT1(3,0);
10013 if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
10014 gate = True;
10015 }
10016 } else {
10017 if (INSNA(27,20) == BITS8(0,1,1,0,0,0,1,1) &&
10018 INSNA(11,8) == BITS4(1,1,1,1) &&
10019 INSNA(7,4) == BITS4(1,0,0,1)) {
10020 regD = INSNA(15,12);
10021 regN = INSNA(19,16);
10022 regM = INSNA(3,0);
10023 if (regD != 15 && regN != 15 && regM != 15)
10024 gate = True;
10025 }
10026 }
10027
10028 if (gate) {
10029 IRTemp rNt = newTemp(Ity_I32);
10030 IRTemp rMt = newTemp(Ity_I32);
10031 IRTemp res_q = newTemp(Ity_I32);
10032
10033 assign( rNt, isT ? getIRegT(regN) : getIRegA(regN) );
10034 assign( rMt, isT ? getIRegT(regM) : getIRegA(regM) );
10035
10036 assign(res_q, binop(Iop_HAdd8Sx4, mkexpr(rNt), mkexpr(rMt)));
10037 if (isT)
10038 putIRegT( regD, mkexpr(res_q), condT );
10039 else
10040 putIRegA( regD, mkexpr(res_q), condT, Ijk_Boring );
10041
10042 DIP("shadd8%s r%u, r%u, r%u\n", nCC(conq),regD,regN,regM);
sewardj1f139f52010-08-29 12:33:02 +000010043 return True;
10044 }
10045 /* fall through */
10046 }
10047
10048 /* ------------------ qadd16<c> <Rd>,<Rn>,<Rm> ------------------ */
10049 {
10050 UInt regD = 99, regN = 99, regM = 99;
10051 Bool gate = False;
10052
10053 if (isT) {
10054 if (INSNT0(15,4) == 0xFA9 && (INSNT1(15,0) & 0xF0F0) == 0xF010) {
10055 regN = INSNT0(3,0);
10056 regD = INSNT1(11,8);
10057 regM = INSNT1(3,0);
10058 if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
10059 gate = True;
10060 }
10061 } else {
10062 if (INSNA(27,20) == BITS8(0,1,1,0,0,0,1,0) &&
10063 INSNA(11,8) == BITS4(1,1,1,1) &&
10064 INSNA(7,4) == BITS4(0,0,0,1)) {
10065 regD = INSNA(15,12);
10066 regN = INSNA(19,16);
10067 regM = INSNA(3,0);
10068 if (regD != 15 && regN != 15 && regM != 15)
10069 gate = True;
10070 }
10071 }
10072
10073 if (gate) {
sewardje2ea1762010-09-22 00:56:37 +000010074 IRTemp rNt = newTemp(Ity_I32);
10075 IRTemp rMt = newTemp(Ity_I32);
10076 IRTemp res_q = newTemp(Ity_I32);
sewardj1f139f52010-08-29 12:33:02 +000010077
sewardje2ea1762010-09-22 00:56:37 +000010078 assign( rNt, isT ? getIRegT(regN) : getIRegA(regN) );
10079 assign( rMt, isT ? getIRegT(regM) : getIRegA(regM) );
sewardj1f139f52010-08-29 12:33:02 +000010080
sewardje2ea1762010-09-22 00:56:37 +000010081 assign(res_q, binop(Iop_QAdd16Sx2, mkexpr(rNt), mkexpr(rMt)));
sewardj1f139f52010-08-29 12:33:02 +000010082 if (isT)
sewardje2ea1762010-09-22 00:56:37 +000010083 putIRegT( regD, mkexpr(res_q), condT );
sewardj1f139f52010-08-29 12:33:02 +000010084 else
sewardje2ea1762010-09-22 00:56:37 +000010085 putIRegA( regD, mkexpr(res_q), condT, Ijk_Boring );
sewardj1f139f52010-08-29 12:33:02 +000010086
sewardje2ea1762010-09-22 00:56:37 +000010087 DIP("qadd16%s r%u, r%u, r%u\n", nCC(conq),regD,regN,regM);
sewardj1f139f52010-08-29 12:33:02 +000010088 return True;
10089 }
10090 /* fall through */
10091 }
10092
10093 /* ------------------ qsub16<c> <Rd>,<Rn>,<Rm> ------------------ */
10094 {
10095 UInt regD = 99, regN = 99, regM = 99;
10096 Bool gate = False;
10097
sewardje2ea1762010-09-22 00:56:37 +000010098 if (isT) {
sewardj1f139f52010-08-29 12:33:02 +000010099 if (INSNT0(15,4) == 0xFAD && (INSNT1(15,0) & 0xF0F0) == 0xF010) {
10100 regN = INSNT0(3,0);
10101 regD = INSNT1(11,8);
10102 regM = INSNT1(3,0);
10103 if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
10104 gate = True;
10105 }
10106 } else {
10107 if (INSNA(27,20) == BITS8(0,1,1,0,0,0,1,0) &&
10108 INSNA(11,8) == BITS4(1,1,1,1) &&
10109 INSNA(7,4) == BITS4(0,1,1,1)) {
10110 regD = INSNA(15,12);
10111 regN = INSNA(19,16);
10112 regM = INSNA(3,0);
10113 if (regD != 15 && regN != 15 && regM != 15)
10114 gate = True;
10115 }
10116 }
10117
10118 if (gate) {
sewardje2ea1762010-09-22 00:56:37 +000010119 IRTemp rNt = newTemp(Ity_I32);
10120 IRTemp rMt = newTemp(Ity_I32);
10121 IRTemp res_q = newTemp(Ity_I32);
sewardj1f139f52010-08-29 12:33:02 +000010122
sewardje2ea1762010-09-22 00:56:37 +000010123 assign( rNt, isT ? getIRegT(regN) : getIRegA(regN) );
10124 assign( rMt, isT ? getIRegT(regM) : getIRegA(regM) );
sewardj1f139f52010-08-29 12:33:02 +000010125
sewardje2ea1762010-09-22 00:56:37 +000010126 assign(res_q, binop(Iop_QSub16Sx2, mkexpr(rNt), mkexpr(rMt)));
sewardj1f139f52010-08-29 12:33:02 +000010127 if (isT)
sewardje2ea1762010-09-22 00:56:37 +000010128 putIRegT( regD, mkexpr(res_q), condT );
sewardj1f139f52010-08-29 12:33:02 +000010129 else
sewardje2ea1762010-09-22 00:56:37 +000010130 putIRegA( regD, mkexpr(res_q), condT, Ijk_Boring );
sewardj1f139f52010-08-29 12:33:02 +000010131
sewardje2ea1762010-09-22 00:56:37 +000010132 DIP("qsub16%s r%u, r%u, r%u\n", nCC(conq),regD,regN,regM);
sewardj1f139f52010-08-29 12:33:02 +000010133 return True;
10134 }
10135 /* fall through */
10136 }
10137
sewardje2ea1762010-09-22 00:56:37 +000010138 /////////////////////////////////////////////////////////////////
10139 /////////////////////////////////////////////////////////////////
10140 /////////////////////////////////////////////////////////////////
10141 /////////////////////////////////////////////////////////////////
10142 /////////////////////////////////////////////////////////////////
10143
sewardj1f139f52010-08-29 12:33:02 +000010144 /* ------------------- qsax<c> <Rd>,<Rn>,<Rm> ------------------- */
10145 /* note: the hardware seems to construct the result differently
10146 from wot the manual says. */
10147 {
10148 UInt regD = 99, regN = 99, regM = 99;
10149 Bool gate = False;
10150
10151 if (isT) {
10152 if (INSNT0(15,4) == 0xFAE && (INSNT1(15,0) & 0xF0F0) == 0xF010) {
10153 regN = INSNT0(3,0);
10154 regD = INSNT1(11,8);
10155 regM = INSNT1(3,0);
10156 if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
10157 gate = True;
10158 }
10159 } else {
10160 if (INSNA(27,20) == BITS8(0,1,1,0,0,0,1,0) &&
10161 INSNA(11,8) == BITS4(1,1,1,1) &&
10162 INSNA(7,4) == BITS4(0,1,0,1)) {
10163 regD = INSNA(15,12);
10164 regN = INSNA(19,16);
10165 regM = INSNA(3,0);
10166 if (regD != 15 && regN != 15 && regM != 15)
10167 gate = True;
10168 }
10169 }
10170
10171 if (gate) {
10172 IRTemp irt_regN = newTemp(Ity_I32);
10173 IRTemp irt_regM = newTemp(Ity_I32);
10174 IRTemp irt_sum = newTemp(Ity_I32);
10175 IRTemp irt_diff = newTemp(Ity_I32);
10176 IRTemp irt_sum_res = newTemp(Ity_I32);
10177 IRTemp irt_diff_res = newTemp(Ity_I32);
10178
10179 assign( irt_regN, isT ? getIRegT(regN) : getIRegA(regN) );
10180 assign( irt_regM, isT ? getIRegT(regM) : getIRegA(regM) );
10181
10182 assign( irt_diff,
10183 binop( Iop_Sub32,
10184 binop( Iop_Sar32, mkexpr(irt_regN), mkU8(16) ),
10185 binop( Iop_Sar32,
10186 binop(Iop_Shl32, mkexpr(irt_regM), mkU8(16)),
10187 mkU8(16) ) ) );
10188 armSignedSatQ( irt_diff, 0x10, &irt_diff_res, NULL);
10189
10190 assign( irt_sum,
10191 binop( Iop_Add32,
10192 binop( Iop_Sar32,
10193 binop( Iop_Shl32, mkexpr(irt_regN), mkU8(16) ),
10194 mkU8(16) ),
10195 binop( Iop_Sar32, mkexpr(irt_regM), mkU8(16) )) );
10196 armSignedSatQ( irt_sum, 0x10, &irt_sum_res, NULL );
10197
10198 IRExpr* ire_result = binop( Iop_Or32,
10199 binop( Iop_Shl32, mkexpr(irt_diff_res),
10200 mkU8(16) ),
10201 binop( Iop_And32, mkexpr(irt_sum_res),
10202 mkU32(0xFFFF)) );
10203
10204 if (isT)
10205 putIRegT( regD, ire_result, condT );
10206 else
10207 putIRegA( regD, ire_result, condT, Ijk_Boring );
10208
10209 DIP( "qsax%s r%u, r%u, r%u\n", nCC(conq), regD, regN, regM );
10210 return True;
10211 }
10212 /* fall through */
10213 }
10214
10215 /* ------------------- qasx<c> <Rd>,<Rn>,<Rm> ------------------- */
10216 {
10217 UInt regD = 99, regN = 99, regM = 99;
10218 Bool gate = False;
10219
10220 if (isT) {
10221 if (INSNT0(15,4) == 0xFAA && (INSNT1(15,0) & 0xF0F0) == 0xF010) {
10222 regN = INSNT0(3,0);
10223 regD = INSNT1(11,8);
10224 regM = INSNT1(3,0);
10225 if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
10226 gate = True;
10227 }
10228 } else {
10229 if (INSNA(27,20) == BITS8(0,1,1,0,0,0,1,0) &&
10230 INSNA(11,8) == BITS4(1,1,1,1) &&
10231 INSNA(7,4) == BITS4(0,0,1,1)) {
10232 regD = INSNA(15,12);
10233 regN = INSNA(19,16);
10234 regM = INSNA(3,0);
10235 if (regD != 15 && regN != 15 && regM != 15)
10236 gate = True;
10237 }
10238 }
10239
10240 if (gate) {
10241 IRTemp irt_regN = newTemp(Ity_I32);
10242 IRTemp irt_regM = newTemp(Ity_I32);
10243 IRTemp irt_sum = newTemp(Ity_I32);
10244 IRTemp irt_diff = newTemp(Ity_I32);
10245 IRTemp irt_res_sum = newTemp(Ity_I32);
10246 IRTemp irt_res_diff = newTemp(Ity_I32);
10247
10248 assign( irt_regN, isT ? getIRegT(regN) : getIRegA(regN) );
10249 assign( irt_regM, isT ? getIRegT(regM) : getIRegA(regM) );
10250
10251 assign( irt_diff,
10252 binop( Iop_Sub32,
10253 binop( Iop_Sar32,
10254 binop( Iop_Shl32, mkexpr(irt_regN), mkU8(16) ),
10255 mkU8(16) ),
10256 binop( Iop_Sar32, mkexpr(irt_regM), mkU8(16) ) ) );
10257 armSignedSatQ( irt_diff, 0x10, &irt_res_diff, NULL );
10258
10259 assign( irt_sum,
10260 binop( Iop_Add32,
10261 binop( Iop_Sar32, mkexpr(irt_regN), mkU8(16) ),
10262 binop( Iop_Sar32,
10263 binop( Iop_Shl32, mkexpr(irt_regM), mkU8(16) ),
10264 mkU8(16) ) ) );
10265 armSignedSatQ( irt_sum, 0x10, &irt_res_sum, NULL );
10266
10267 IRExpr* ire_result
10268 = binop( Iop_Or32,
10269 binop( Iop_Shl32, mkexpr(irt_res_sum), mkU8(16) ),
10270 binop( Iop_And32, mkexpr(irt_res_diff), mkU32(0xFFFF) ) );
10271
10272 if (isT)
10273 putIRegT( regD, ire_result, condT );
10274 else
10275 putIRegA( regD, ire_result, condT, Ijk_Boring );
10276
10277 DIP( "qasx%s r%u, r%u, r%u\n", nCC(conq), regD, regN, regM );
10278 return True;
10279 }
10280 /* fall through */
10281 }
10282
sewardj22ac5962010-09-20 22:35:35 +000010283 /* ------------------- sasx<c> <Rd>,<Rn>,<Rm> ------------------- */
10284 {
10285 UInt regD = 99, regN = 99, regM = 99;
10286 Bool gate = False;
10287
10288 if (isT) {
10289 if (INSNT0(15,4) == 0xFAA && (INSNT1(15,0) & 0xF0F0) == 0xF000) {
10290 regN = INSNT0(3,0);
10291 regD = INSNT1(11,8);
10292 regM = INSNT1(3,0);
10293 if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
10294 gate = True;
10295 }
10296 } else {
10297 if (INSNA(27,20) == BITS8(0,1,1,0,0,0,0,1) &&
10298 INSNA(11,8) == BITS4(1,1,1,1) &&
10299 INSNA(7,4) == BITS4(0,0,1,1)) {
10300 regD = INSNA(15,12);
10301 regN = INSNA(19,16);
10302 regM = INSNA(3,0);
10303 if (regD != 15 && regN != 15 && regM != 15)
10304 gate = True;
10305 }
10306 }
10307
10308 if (gate) {
10309 IRTemp irt_regN = newTemp(Ity_I32);
10310 IRTemp irt_regM = newTemp(Ity_I32);
10311 IRTemp irt_sum = newTemp(Ity_I32);
10312 IRTemp irt_diff = newTemp(Ity_I32);
10313
10314 assign( irt_regN, isT ? getIRegT(regN) : getIRegA(regN) );
10315 assign( irt_regM, isT ? getIRegT(regM) : getIRegA(regM) );
10316
10317 assign( irt_diff,
10318 binop( Iop_Sub32,
10319 binop( Iop_Sar32,
10320 binop( Iop_Shl32, mkexpr(irt_regN), mkU8(16) ),
10321 mkU8(16) ),
10322 binop( Iop_Sar32, mkexpr(irt_regM), mkU8(16) ) ) );
10323
10324 assign( irt_sum,
10325 binop( Iop_Add32,
10326 binop( Iop_Sar32, mkexpr(irt_regN), mkU8(16) ),
10327 binop( Iop_Sar32,
10328 binop( Iop_Shl32, mkexpr(irt_regM), mkU8(16) ),
10329 mkU8(16) ) ) );
10330
10331 IRExpr* ire_result
10332 = binop( Iop_Or32,
10333 binop( Iop_Shl32, mkexpr(irt_sum), mkU8(16) ),
10334 binop( Iop_And32, mkexpr(irt_diff), mkU32(0xFFFF) ) );
10335
10336 IRTemp ge10 = newTemp(Ity_I32);
10337 assign(ge10, unop(Iop_Not32, mkexpr(irt_diff)));
10338 put_GEFLAG32( 0, 31, mkexpr(ge10), condT );
10339 put_GEFLAG32( 1, 31, mkexpr(ge10), condT );
10340
10341 IRTemp ge32 = newTemp(Ity_I32);
10342 assign(ge32, unop(Iop_Not32, mkexpr(irt_sum)));
10343 put_GEFLAG32( 2, 31, mkexpr(ge32), condT );
10344 put_GEFLAG32( 3, 31, mkexpr(ge32), condT );
10345
10346 if (isT)
10347 putIRegT( regD, ire_result, condT );
10348 else
10349 putIRegA( regD, ire_result, condT, Ijk_Boring );
10350
10351 DIP( "sasx%s r%u, r%u, r%u\n", nCC(conq), regD, regN, regM );
10352 return True;
10353 }
10354 /* fall through */
10355 }
10356
sewardj1f139f52010-08-29 12:33:02 +000010357 /* --------------- smuad, smuadx<c><Rd>,<Rn>,<Rm> --------------- */
sewardj310d6b22010-10-18 16:29:40 +000010358 /* --------------- smsad, smsadx<c><Rd>,<Rn>,<Rm> --------------- */
sewardj1f139f52010-08-29 12:33:02 +000010359 {
10360 UInt regD = 99, regN = 99, regM = 99, bitM = 99;
sewardj310d6b22010-10-18 16:29:40 +000010361 Bool gate = False, isAD = False;
sewardj1f139f52010-08-29 12:33:02 +000010362
10363 if (isT) {
sewardj310d6b22010-10-18 16:29:40 +000010364 if ((INSNT0(15,4) == 0xFB2 || INSNT0(15,4) == 0xFB4)
10365 && (INSNT1(15,0) & 0xF0E0) == 0xF000) {
sewardj1f139f52010-08-29 12:33:02 +000010366 regN = INSNT0(3,0);
10367 regD = INSNT1(11,8);
10368 regM = INSNT1(3,0);
10369 bitM = INSNT1(4,4);
sewardj310d6b22010-10-18 16:29:40 +000010370 isAD = INSNT0(15,4) == 0xFB2;
sewardj1f139f52010-08-29 12:33:02 +000010371 if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
10372 gate = True;
10373 }
10374 } else {
10375 if (INSNA(27,20) == BITS8(0,1,1,1,0,0,0,0) &&
10376 INSNA(15,12) == BITS4(1,1,1,1) &&
sewardj310d6b22010-10-18 16:29:40 +000010377 (INSNA(7,4) & BITS4(1,0,0,1)) == BITS4(0,0,0,1) ) {
sewardj1f139f52010-08-29 12:33:02 +000010378 regD = INSNA(19,16);
10379 regN = INSNA(3,0);
10380 regM = INSNA(11,8);
10381 bitM = INSNA(5,5);
sewardj310d6b22010-10-18 16:29:40 +000010382 isAD = INSNA(6,6) == 0;
sewardj1f139f52010-08-29 12:33:02 +000010383 if (regD != 15 && regN != 15 && regM != 15)
10384 gate = True;
10385 }
10386 }
10387
10388 if (gate) {
10389 IRTemp irt_regN = newTemp(Ity_I32);
10390 IRTemp irt_regM = newTemp(Ity_I32);
10391 IRTemp irt_prod_lo = newTemp(Ity_I32);
10392 IRTemp irt_prod_hi = newTemp(Ity_I32);
10393 IRTemp tmpM = newTemp(Ity_I32);
10394
10395 assign( irt_regN, isT ? getIRegT(regN) : getIRegA(regN) );
10396
10397 assign( tmpM, isT ? getIRegT(regM) : getIRegA(regM) );
10398 assign( irt_regM, genROR32(tmpM, (bitM & 1) ? 16 : 0) );
10399
10400 assign( irt_prod_lo,
10401 binop( Iop_Mul32,
10402 binop( Iop_Sar32,
10403 binop(Iop_Shl32, mkexpr(irt_regN), mkU8(16)),
10404 mkU8(16) ),
10405 binop( Iop_Sar32,
10406 binop(Iop_Shl32, mkexpr(irt_regM), mkU8(16)),
10407 mkU8(16) ) ) );
10408 assign( irt_prod_hi, binop(Iop_Mul32,
10409 binop(Iop_Sar32, mkexpr(irt_regN), mkU8(16)),
10410 binop(Iop_Sar32, mkexpr(irt_regM), mkU8(16))) );
10411 IRExpr* ire_result
sewardj310d6b22010-10-18 16:29:40 +000010412 = binop( isAD ? Iop_Add32 : Iop_Sub32,
10413 mkexpr(irt_prod_lo), mkexpr(irt_prod_hi) );
sewardj1f139f52010-08-29 12:33:02 +000010414
10415 if (isT)
10416 putIRegT( regD, ire_result, condT );
10417 else
10418 putIRegA( regD, ire_result, condT, Ijk_Boring );
10419
sewardj310d6b22010-10-18 16:29:40 +000010420 if (isAD) {
10421 or_into_QFLAG32(
10422 signed_overflow_after_Add32( ire_result,
10423 irt_prod_lo, irt_prod_hi ),
10424 condT
10425 );
10426 }
sewardj1f139f52010-08-29 12:33:02 +000010427
sewardj310d6b22010-10-18 16:29:40 +000010428 DIP("smu%cd%s%s r%u, r%u, r%u\n",
10429 isAD ? 'a' : 's',
sewardj1f139f52010-08-29 12:33:02 +000010430 bitM ? "x" : "", nCC(conq), regD, regN, regM);
10431 return True;
10432 }
10433 /* fall through */
10434 }
10435
10436 /* --------------- smlad{X}<c> <Rd>,<Rn>,<Rm>,<Ra> -------------- */
sewardj310d6b22010-10-18 16:29:40 +000010437 /* --------------- smlsd{X}<c> <Rd>,<Rn>,<Rm>,<Ra> -------------- */
sewardj1f139f52010-08-29 12:33:02 +000010438 {
10439 UInt regD = 99, regN = 99, regM = 99, regA = 99, bitM = 99;
sewardj310d6b22010-10-18 16:29:40 +000010440 Bool gate = False, isAD = False;
sewardj1f139f52010-08-29 12:33:02 +000010441
10442 if (isT) {
sewardj310d6b22010-10-18 16:29:40 +000010443 if ((INSNT0(15,4) == 0xFB2 || INSNT0(15,4) == 0xFB4)
10444 && INSNT1(7,5) == BITS3(0,0,0)) {
sewardj1f139f52010-08-29 12:33:02 +000010445 regN = INSNT0(3,0);
10446 regD = INSNT1(11,8);
10447 regM = INSNT1(3,0);
10448 regA = INSNT1(15,12);
10449 bitM = INSNT1(4,4);
sewardj310d6b22010-10-18 16:29:40 +000010450 isAD = INSNT0(15,4) == 0xFB2;
sewardj1f139f52010-08-29 12:33:02 +000010451 if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM)
10452 && !isBadRegT(regA))
10453 gate = True;
10454 }
10455 } else {
10456 if (INSNA(27,20) == BITS8(0,1,1,1,0,0,0,0) &&
sewardj310d6b22010-10-18 16:29:40 +000010457 (INSNA(7,4) & BITS4(1,0,0,1)) == BITS4(0,0,0,1)) {
sewardj1f139f52010-08-29 12:33:02 +000010458 regD = INSNA(19,16);
10459 regA = INSNA(15,12);
10460 regN = INSNA(3,0);
10461 regM = INSNA(11,8);
10462 bitM = INSNA(5,5);
sewardj310d6b22010-10-18 16:29:40 +000010463 isAD = INSNA(6,6) == 0;
sewardj1f139f52010-08-29 12:33:02 +000010464 if (regD != 15 && regN != 15 && regM != 15 && regA != 15)
10465 gate = True;
10466 }
10467 }
10468
10469 if (gate) {
10470 IRTemp irt_regN = newTemp(Ity_I32);
10471 IRTemp irt_regM = newTemp(Ity_I32);
10472 IRTemp irt_regA = newTemp(Ity_I32);
10473 IRTemp irt_prod_lo = newTemp(Ity_I32);
10474 IRTemp irt_prod_hi = newTemp(Ity_I32);
10475 IRTemp irt_sum = newTemp(Ity_I32);
10476 IRTemp tmpM = newTemp(Ity_I32);
10477
10478 assign( irt_regN, isT ? getIRegT(regN) : getIRegA(regN) );
10479 assign( irt_regA, isT ? getIRegT(regA) : getIRegA(regA) );
10480
10481 assign( tmpM, isT ? getIRegT(regM) : getIRegA(regM) );
10482 assign( irt_regM, genROR32(tmpM, (bitM & 1) ? 16 : 0) );
10483
10484 assign( irt_prod_lo,
10485 binop(Iop_Mul32,
10486 binop(Iop_Sar32,
10487 binop( Iop_Shl32, mkexpr(irt_regN), mkU8(16) ),
10488 mkU8(16)),
10489 binop(Iop_Sar32,
10490 binop( Iop_Shl32, mkexpr(irt_regM), mkU8(16) ),
10491 mkU8(16))) );
10492 assign( irt_prod_hi,
10493 binop( Iop_Mul32,
10494 binop( Iop_Sar32, mkexpr(irt_regN), mkU8(16) ),
10495 binop( Iop_Sar32, mkexpr(irt_regM), mkU8(16) ) ) );
sewardj310d6b22010-10-18 16:29:40 +000010496 assign( irt_sum, binop( isAD ? Iop_Add32 : Iop_Sub32,
sewardj1f139f52010-08-29 12:33:02 +000010497 mkexpr(irt_prod_lo), mkexpr(irt_prod_hi) ) );
10498
10499 IRExpr* ire_result = binop(Iop_Add32, mkexpr(irt_sum), mkexpr(irt_regA));
10500
10501 if (isT)
10502 putIRegT( regD, ire_result, condT );
10503 else
10504 putIRegA( regD, ire_result, condT, Ijk_Boring );
10505
sewardj310d6b22010-10-18 16:29:40 +000010506 if (isAD) {
10507 or_into_QFLAG32(
10508 signed_overflow_after_Add32( mkexpr(irt_sum),
10509 irt_prod_lo, irt_prod_hi ),
10510 condT
10511 );
10512 }
sewardj1f139f52010-08-29 12:33:02 +000010513
sewardj310d6b22010-10-18 16:29:40 +000010514 or_into_QFLAG32(
10515 signed_overflow_after_Add32( ire_result, irt_sum, irt_regA ),
10516 condT
10517 );
10518
10519 DIP("sml%cd%s%s r%u, r%u, r%u, r%u\n",
10520 isAD ? 'a' : 's',
sewardj1f139f52010-08-29 12:33:02 +000010521 bitM ? "x" : "", nCC(conq), regD, regN, regM, regA);
10522 return True;
10523 }
10524 /* fall through */
10525 }
10526
10527 /* ----- smlabb, smlabt, smlatb, smlatt <Rd>,<Rn>,<Rm>,<Ra> ----- */
10528 {
10529 UInt regD = 99, regN = 99, regM = 99, regA = 99, bitM = 99, bitN = 99;
10530 Bool gate = False;
10531
10532 if (isT) {
10533 if (INSNT0(15,4) == 0xFB1 && INSNT1(7,6) == BITS2(0,0)) {
10534 regN = INSNT0(3,0);
10535 regD = INSNT1(11,8);
10536 regM = INSNT1(3,0);
10537 regA = INSNT1(15,12);
10538 bitM = INSNT1(4,4);
10539 bitN = INSNT1(5,5);
10540 if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM)
10541 && !isBadRegT(regA))
10542 gate = True;
10543 }
10544 } else {
10545 if (INSNA(27,20) == BITS8(0,0,0,1,0,0,0,0) &&
10546 (INSNA(7,4) & BITS4(1,0,0,1)) == BITS4(1,0,0,0)) {
10547 regD = INSNA(19,16);
10548 regN = INSNA(3,0);
10549 regM = INSNA(11,8);
10550 regA = INSNA(15,12);
10551 bitM = INSNA(6,6);
10552 bitN = INSNA(5,5);
10553 if (regD != 15 && regN != 15 && regM != 15 && regA != 15)
10554 gate = True;
10555 }
10556 }
10557
10558 if (gate) {
10559 IRTemp irt_regA = newTemp(Ity_I32);
10560 IRTemp irt_prod = newTemp(Ity_I32);
10561
10562 assign( irt_prod,
10563 binop(Iop_Mul32,
10564 binop(Iop_Sar32,
10565 binop(Iop_Shl32,
10566 isT ? getIRegT(regN) : getIRegA(regN),
10567 mkU8(bitN ? 0 : 16)),
10568 mkU8(16)),
10569 binop(Iop_Sar32,
10570 binop(Iop_Shl32,
10571 isT ? getIRegT(regM) : getIRegA(regM),
10572 mkU8(bitM ? 0 : 16)),
10573 mkU8(16))) );
10574
10575 assign( irt_regA, isT ? getIRegT(regA) : getIRegA(regA) );
10576
10577 IRExpr* ire_result = binop(Iop_Add32, mkexpr(irt_prod), mkexpr(irt_regA));
10578
10579 if (isT)
10580 putIRegT( regD, ire_result, condT );
10581 else
10582 putIRegA( regD, ire_result, condT, Ijk_Boring );
10583
sewardj310d6b22010-10-18 16:29:40 +000010584 or_into_QFLAG32(
10585 signed_overflow_after_Add32( ire_result, irt_prod, irt_regA ),
10586 condT
10587 );
sewardj1f139f52010-08-29 12:33:02 +000010588
10589 DIP( "smla%c%c%s r%u, r%u, r%u, r%u\n",
10590 bitN ? 't' : 'b', bitM ? 't' : 'b',
10591 nCC(conq), regD, regN, regM, regA );
10592 return True;
10593 }
10594 /* fall through */
10595 }
10596
sewardj44db1e72013-03-04 18:33:56 +000010597 /* ----- smlalbb, smlalbt, smlaltb, smlaltt <Rd>,<Rn>,<Rm>,<Ra> ----- */
10598 {
10599 UInt regDHi = 99, regN = 99, regM = 99, regDLo = 99, bitM = 99, bitN = 99;
10600 Bool gate = False;
10601
10602 if (isT) {
10603 if (INSNT0(15,4) == 0xFBC && INSNT1(7,6) == BITS2(1,0)) {
10604 regN = INSNT0(3,0);
10605 regDHi = INSNT1(11,8);
10606 regM = INSNT1(3,0);
10607 regDLo = INSNT1(15,12);
10608 bitM = INSNT1(4,4);
10609 bitN = INSNT1(5,5);
10610 if (!isBadRegT(regDHi) && !isBadRegT(regN) && !isBadRegT(regM)
10611 && !isBadRegT(regDLo) && regDHi != regDLo)
10612 gate = True;
10613 }
10614 } else {
10615 if (INSNA(27,20) == BITS8(0,0,0,1,0,1,0,0) &&
10616 (INSNA(7,4) & BITS4(1,0,0,1)) == BITS4(1,0,0,0)) {
10617 regDHi = INSNA(19,16);
10618 regN = INSNA(3,0);
10619 regM = INSNA(11,8);
10620 regDLo = INSNA(15,12);
10621 bitM = INSNA(6,6);
10622 bitN = INSNA(5,5);
10623 if (regDHi != 15 && regN != 15 && regM != 15 && regDLo != 15 &&
10624 regDHi != regDLo)
10625 gate = True;
10626 }
10627 }
10628
10629 if (gate) {
10630 IRTemp irt_regD = newTemp(Ity_I64);
10631 IRTemp irt_prod = newTemp(Ity_I64);
10632 IRTemp irt_res = newTemp(Ity_I64);
10633 IRTemp irt_resHi = newTemp(Ity_I32);
10634 IRTemp irt_resLo = newTemp(Ity_I32);
10635
10636 assign( irt_prod,
10637 binop(Iop_MullS32,
10638 binop(Iop_Sar32,
10639 binop(Iop_Shl32,
10640 isT ? getIRegT(regN) : getIRegA(regN),
10641 mkU8(bitN ? 0 : 16)),
10642 mkU8(16)),
10643 binop(Iop_Sar32,
10644 binop(Iop_Shl32,
10645 isT ? getIRegT(regM) : getIRegA(regM),
10646 mkU8(bitM ? 0 : 16)),
10647 mkU8(16))) );
10648
10649 assign( irt_regD, binop(Iop_32HLto64,
10650 isT ? getIRegT(regDHi) : getIRegA(regDHi),
10651 isT ? getIRegT(regDLo) : getIRegA(regDLo)) );
10652 assign( irt_res, binop(Iop_Add64, mkexpr(irt_regD), mkexpr(irt_prod)) );
10653 assign( irt_resHi, unop(Iop_64HIto32, mkexpr(irt_res)) );
10654 assign( irt_resLo, unop(Iop_64to32, mkexpr(irt_res)) );
10655
10656 if (isT) {
10657 putIRegT( regDHi, mkexpr(irt_resHi), condT );
10658 putIRegT( regDLo, mkexpr(irt_resLo), condT );
10659 } else {
10660 putIRegA( regDHi, mkexpr(irt_resHi), condT, Ijk_Boring );
10661 putIRegA( regDLo, mkexpr(irt_resLo), condT, Ijk_Boring );
10662 }
10663
10664 DIP( "smlal%c%c%s r%u, r%u, r%u, r%u\n",
10665 bitN ? 't' : 'b', bitM ? 't' : 'b',
10666 nCC(conq), regDHi, regN, regM, regDLo );
10667 return True;
10668 }
10669 /* fall through */
10670 }
10671
sewardj22ac5962010-09-20 22:35:35 +000010672 /* ----- smlawb, smlawt <Rd>,<Rn>,<Rm>,<Ra> ----- */
10673 {
10674 UInt regD = 99, regN = 99, regM = 99, regA = 99, bitM = 99;
10675 Bool gate = False;
10676
10677 if (isT) {
10678 if (INSNT0(15,4) == 0xFB3 && INSNT1(7,5) == BITS3(0,0,0)) {
10679 regN = INSNT0(3,0);
10680 regD = INSNT1(11,8);
10681 regM = INSNT1(3,0);
10682 regA = INSNT1(15,12);
10683 bitM = INSNT1(4,4);
10684 if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM)
10685 && !isBadRegT(regA))
10686 gate = True;
10687 }
10688 } else {
10689 if (INSNA(27,20) == BITS8(0,0,0,1,0,0,1,0) &&
10690 (INSNA(7,4) & BITS4(1,0,1,1)) == BITS4(1,0,0,0)) {
10691 regD = INSNA(19,16);
10692 regN = INSNA(3,0);
10693 regM = INSNA(11,8);
10694 regA = INSNA(15,12);
10695 bitM = INSNA(6,6);
10696 if (regD != 15 && regN != 15 && regM != 15 && regA != 15)
10697 gate = True;
10698 }
10699 }
10700
10701 if (gate) {
10702 IRTemp irt_regA = newTemp(Ity_I32);
10703 IRTemp irt_prod = newTemp(Ity_I64);
10704
10705 assign( irt_prod,
10706 binop(Iop_MullS32,
10707 isT ? getIRegT(regN) : getIRegA(regN),
10708 binop(Iop_Sar32,
10709 binop(Iop_Shl32,
10710 isT ? getIRegT(regM) : getIRegA(regM),
10711 mkU8(bitM ? 0 : 16)),
10712 mkU8(16))) );
10713
10714 assign( irt_regA, isT ? getIRegT(regA) : getIRegA(regA) );
10715
10716 IRTemp prod32 = newTemp(Ity_I32);
10717 assign(prod32,
10718 binop(Iop_Or32,
10719 binop(Iop_Shl32, unop(Iop_64HIto32, mkexpr(irt_prod)), mkU8(16)),
10720 binop(Iop_Shr32, unop(Iop_64to32, mkexpr(irt_prod)), mkU8(16))
10721 ));
10722
10723 IRExpr* ire_result = binop(Iop_Add32, mkexpr(prod32), mkexpr(irt_regA));
10724
10725 if (isT)
10726 putIRegT( regD, ire_result, condT );
10727 else
10728 putIRegA( regD, ire_result, condT, Ijk_Boring );
10729
sewardj310d6b22010-10-18 16:29:40 +000010730 or_into_QFLAG32(
10731 signed_overflow_after_Add32( ire_result, prod32, irt_regA ),
10732 condT
10733 );
sewardj22ac5962010-09-20 22:35:35 +000010734
10735 DIP( "smlaw%c%s r%u, r%u, r%u, r%u\n",
10736 bitM ? 't' : 'b',
10737 nCC(conq), regD, regN, regM, regA );
10738 return True;
10739 }
10740 /* fall through */
10741 }
10742
sewardj1f139f52010-08-29 12:33:02 +000010743 /* ------------------- sel<c> <Rd>,<Rn>,<Rm> -------------------- */
10744 /* fixme: fix up the test in v6media.c so that we can pass the ge
10745 flags as part of the test. */
10746 {
10747 UInt regD = 99, regN = 99, regM = 99;
10748 Bool gate = False;
10749
10750 if (isT) {
10751 if (INSNT0(15,4) == 0xFAA && (INSNT1(15,0) & 0xF0F0) == 0xF080) {
10752 regN = INSNT0(3,0);
10753 regD = INSNT1(11,8);
10754 regM = INSNT1(3,0);
10755 if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
10756 gate = True;
10757 }
10758 } else {
10759 if (INSNA(27,20) == BITS8(0,1,1,0,1,0,0,0) &&
10760 INSNA(11,8) == BITS4(1,1,1,1) &&
10761 INSNA(7,4) == BITS4(1,0,1,1)) {
10762 regD = INSNA(15,12);
10763 regN = INSNA(19,16);
10764 regM = INSNA(3,0);
10765 if (regD != 15 && regN != 15 && regM != 15)
10766 gate = True;
10767 }
10768 }
10769
10770 if (gate) {
10771 IRTemp irt_ge_flag0 = newTemp(Ity_I32);
10772 IRTemp irt_ge_flag1 = newTemp(Ity_I32);
10773 IRTemp irt_ge_flag2 = newTemp(Ity_I32);
10774 IRTemp irt_ge_flag3 = newTemp(Ity_I32);
10775
10776 assign( irt_ge_flag0, get_GEFLAG32(0) );
10777 assign( irt_ge_flag1, get_GEFLAG32(1) );
10778 assign( irt_ge_flag2, get_GEFLAG32(2) );
10779 assign( irt_ge_flag3, get_GEFLAG32(3) );
10780
10781 IRExpr* ire_ge_flag0_or
10782 = binop(Iop_Or32, mkexpr(irt_ge_flag0),
10783 binop(Iop_Sub32, mkU32(0), mkexpr(irt_ge_flag0)));
10784 IRExpr* ire_ge_flag1_or
10785 = binop(Iop_Or32, mkexpr(irt_ge_flag1),
10786 binop(Iop_Sub32, mkU32(0), mkexpr(irt_ge_flag1)));
10787 IRExpr* ire_ge_flag2_or
10788 = binop(Iop_Or32, mkexpr(irt_ge_flag2),
10789 binop(Iop_Sub32, mkU32(0), mkexpr(irt_ge_flag2)));
10790 IRExpr* ire_ge_flag3_or
10791 = binop(Iop_Or32, mkexpr(irt_ge_flag3),
10792 binop(Iop_Sub32, mkU32(0), mkexpr(irt_ge_flag3)));
10793
10794 IRExpr* ire_ge_flags
10795 = binop( Iop_Or32,
10796 binop(Iop_Or32,
10797 binop(Iop_And32,
10798 binop(Iop_Sar32, ire_ge_flag0_or, mkU8(31)),
10799 mkU32(0x000000ff)),
10800 binop(Iop_And32,
10801 binop(Iop_Sar32, ire_ge_flag1_or, mkU8(31)),
10802 mkU32(0x0000ff00))),
10803 binop(Iop_Or32,
10804 binop(Iop_And32,
10805 binop(Iop_Sar32, ire_ge_flag2_or, mkU8(31)),
10806 mkU32(0x00ff0000)),
10807 binop(Iop_And32,
10808 binop(Iop_Sar32, ire_ge_flag3_or, mkU8(31)),
10809 mkU32(0xff000000))) );
10810
10811 IRExpr* ire_result
10812 = binop(Iop_Or32,
10813 binop(Iop_And32,
10814 isT ? getIRegT(regN) : getIRegA(regN),
10815 ire_ge_flags ),
10816 binop(Iop_And32,
10817 isT ? getIRegT(regM) : getIRegA(regM),
10818 unop(Iop_Not32, ire_ge_flags)));
10819
10820 if (isT)
10821 putIRegT( regD, ire_result, condT );
10822 else
10823 putIRegA( regD, ire_result, condT, Ijk_Boring );
10824
10825 DIP("sel%s r%u, r%u, r%u\n", nCC(conq), regD, regN, regM );
10826 return True;
10827 }
10828 /* fall through */
10829 }
10830
sewardj1f139f52010-08-29 12:33:02 +000010831 /* ----------------- uxtab16<c> Rd,Rn,Rm{,rot} ------------------ */
10832 {
10833 UInt regD = 99, regN = 99, regM = 99, rotate = 99;
10834 Bool gate = False;
10835
10836 if (isT) {
10837 if (INSNT0(15,4) == 0xFA3 && (INSNT1(15,0) & 0xF0C0) == 0xF080) {
10838 regN = INSNT0(3,0);
10839 regD = INSNT1(11,8);
10840 regM = INSNT1(3,0);
10841 rotate = INSNT1(5,4);
10842 if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
10843 gate = True;
10844 }
10845 } else {
10846 if (INSNA(27,20) == BITS8(0,1,1,0,1,1,0,0) &&
10847 INSNA(9,4) == BITS6(0,0,0,1,1,1) ) {
10848 regD = INSNA(15,12);
10849 regN = INSNA(19,16);
10850 regM = INSNA(3,0);
10851 rotate = INSNA(11,10);
10852 if (regD != 15 && regN != 15 && regM != 15)
10853 gate = True;
10854 }
10855 }
10856
10857 if (gate) {
10858 IRTemp irt_regN = newTemp(Ity_I32);
10859 assign( irt_regN, isT ? getIRegT(regN) : getIRegA(regN) );
10860
10861 IRTemp irt_regM = newTemp(Ity_I32);
10862 assign( irt_regM, isT ? getIRegT(regM) : getIRegA(regM) );
10863
10864 IRTemp irt_rot = newTemp(Ity_I32);
10865 assign( irt_rot, binop(Iop_And32,
10866 genROR32(irt_regM, 8 * rotate),
10867 mkU32(0x00FF00FF)) );
10868
10869 IRExpr* resLo
10870 = binop(Iop_And32,
10871 binop(Iop_Add32, mkexpr(irt_regN), mkexpr(irt_rot)),
10872 mkU32(0x0000FFFF));
10873
10874 IRExpr* resHi
10875 = binop(Iop_Add32,
10876 binop(Iop_And32, mkexpr(irt_regN), mkU32(0xFFFF0000)),
10877 binop(Iop_And32, mkexpr(irt_rot), mkU32(0xFFFF0000)));
10878
10879 IRExpr* ire_result
10880 = binop( Iop_Or32, resHi, resLo );
10881
10882 if (isT)
10883 putIRegT( regD, ire_result, condT );
10884 else
10885 putIRegA( regD, ire_result, condT, Ijk_Boring );
10886
10887 DIP( "uxtab16%s r%u, r%u, r%u, ROR #%u\n",
10888 nCC(conq), regD, regN, regM, 8 * rotate );
10889 return True;
10890 }
10891 /* fall through */
10892 }
10893
sewardj310d6b22010-10-18 16:29:40 +000010894 /* --------------- usad8 Rd,Rn,Rm ---------------- */
10895 /* --------------- usada8 Rd,Rn,Rm,Ra ---------------- */
10896 {
10897 UInt rD = 99, rN = 99, rM = 99, rA = 99;
10898 Bool gate = False;
10899
10900 if (isT) {
10901 if (INSNT0(15,4) == 0xFB7 && INSNT1(7,4) == BITS4(0,0,0,0)) {
10902 rN = INSNT0(3,0);
10903 rA = INSNT1(15,12);
10904 rD = INSNT1(11,8);
10905 rM = INSNT1(3,0);
10906 if (!isBadRegT(rD) && !isBadRegT(rN) && !isBadRegT(rM) && rA != 13)
10907 gate = True;
10908 }
10909 } else {
10910 if (INSNA(27,20) == BITS8(0,1,1,1,1,0,0,0) &&
10911 INSNA(7,4) == BITS4(0,0,0,1) ) {
10912 rD = INSNA(19,16);
10913 rA = INSNA(15,12);
10914 rM = INSNA(11,8);
10915 rN = INSNA(3,0);
10916 if (rD != 15 && rN != 15 && rM != 15 /* but rA can be 15 */)
10917 gate = True;
10918 }
10919 }
10920 /* We allow rA == 15, to denote the usad8 (no accumulator) case. */
10921
10922 if (gate) {
10923 IRExpr* rNe = isT ? getIRegT(rN) : getIRegA(rN);
10924 IRExpr* rMe = isT ? getIRegT(rM) : getIRegA(rM);
10925 IRExpr* rAe = rA == 15 ? mkU32(0)
10926 : (isT ? getIRegT(rA) : getIRegA(rA));
10927 IRExpr* res = binop(Iop_Add32,
10928 binop(Iop_Sad8Ux4, rNe, rMe),
10929 rAe);
10930 if (isT)
10931 putIRegT( rD, res, condT );
10932 else
10933 putIRegA( rD, res, condT, Ijk_Boring );
10934
10935 if (rA == 15) {
10936 DIP( "usad8%s r%u, r%u, r%u\n",
10937 nCC(conq), rD, rN, rM );
10938 } else {
10939 DIP( "usada8%s r%u, r%u, r%u, r%u\n",
10940 nCC(conq), rD, rN, rM, rA );
10941 }
10942 return True;
10943 }
10944 /* fall through */
10945 }
10946
sewardj44ce46d2012-07-11 13:19:10 +000010947 /* ------------------ qadd<c> <Rd>,<Rn>,<Rm> ------------------- */
10948 {
10949 UInt regD = 99, regN = 99, regM = 99;
10950 Bool gate = False;
10951
10952 if (isT) {
10953 if (INSNT0(15,4) == 0xFA8 && (INSNT1(15,0) & 0xF0F0) == 0xF080) {
10954 regN = INSNT0(3,0);
10955 regD = INSNT1(11,8);
10956 regM = INSNT1(3,0);
10957 if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
10958 gate = True;
10959 }
10960 } else {
10961 if (INSNA(27,20) == BITS8(0,0,0,1,0,0,0,0) &&
10962 INSNA(11,8) == BITS4(0,0,0,0) &&
10963 INSNA(7,4) == BITS4(0,1,0,1)) {
10964 regD = INSNA(15,12);
10965 regN = INSNA(19,16);
10966 regM = INSNA(3,0);
10967 if (regD != 15 && regN != 15 && regM != 15)
10968 gate = True;
10969 }
10970 }
10971
10972 if (gate) {
10973 IRTemp rNt = newTemp(Ity_I32);
10974 IRTemp rMt = newTemp(Ity_I32);
10975 IRTemp res_q = newTemp(Ity_I32);
10976
10977 assign( rNt, isT ? getIRegT(regN) : getIRegA(regN) );
10978 assign( rMt, isT ? getIRegT(regM) : getIRegA(regM) );
10979
10980 assign(res_q, binop(Iop_QAdd32S, mkexpr(rMt), mkexpr(rNt)));
10981 if (isT)
10982 putIRegT( regD, mkexpr(res_q), condT );
10983 else
10984 putIRegA( regD, mkexpr(res_q), condT, Ijk_Boring );
10985
10986 or_into_QFLAG32(
10987 signed_overflow_after_Add32(
10988 binop(Iop_Add32, mkexpr(rMt), mkexpr(rNt)), rMt, rNt),
10989 condT
10990 );
10991
10992 DIP("qadd%s r%u, r%u, r%u\n", nCC(conq),regD,regM,regN);
10993 return True;
10994 }
10995 /* fall through */
10996 }
10997
sewardj5a34b8b2012-08-23 20:56:17 +000010998 /* ------------------ qdadd<c> <Rd>,<Rm>,<Rn> ------------------- */
10999 {
11000 UInt regD = 99, regN = 99, regM = 99;
11001 Bool gate = False;
11002
11003 if (isT) {
11004 if (INSNT0(15,4) == 0xFA8 && (INSNT1(15,0) & 0xF0F0) == 0xF090) {
11005 regN = INSNT0(3,0);
11006 regD = INSNT1(11,8);
11007 regM = INSNT1(3,0);
11008 if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
11009 gate = True;
11010 }
11011 } else {
11012 if (INSNA(27,20) == BITS8(0,0,0,1,0,1,0,0) &&
11013 INSNA(11,8) == BITS4(0,0,0,0) &&
11014 INSNA(7,4) == BITS4(0,1,0,1)) {
11015 regD = INSNA(15,12);
11016 regN = INSNA(19,16);
11017 regM = INSNA(3,0);
11018 if (regD != 15 && regN != 15 && regM != 15)
11019 gate = True;
11020 }
11021 }
11022
11023 if (gate) {
11024 IRTemp rNt = newTemp(Ity_I32);
11025 IRTemp rMt = newTemp(Ity_I32);
11026 IRTemp rN_d = newTemp(Ity_I32);
11027 IRTemp res_q = newTemp(Ity_I32);
11028
11029 assign( rNt, isT ? getIRegT(regN) : getIRegA(regN) );
11030 assign( rMt, isT ? getIRegT(regM) : getIRegA(regM) );
11031
11032 or_into_QFLAG32(
11033 signed_overflow_after_Add32(
11034 binop(Iop_Add32, mkexpr(rNt), mkexpr(rNt)), rNt, rNt),
11035 condT
11036 );
11037
11038 assign(rN_d, binop(Iop_QAdd32S, mkexpr(rNt), mkexpr(rNt)));
11039 assign(res_q, binop(Iop_QAdd32S, mkexpr(rMt), mkexpr(rN_d)));
11040 if (isT)
11041 putIRegT( regD, mkexpr(res_q), condT );
11042 else
11043 putIRegA( regD, mkexpr(res_q), condT, Ijk_Boring );
11044
11045 or_into_QFLAG32(
11046 signed_overflow_after_Add32(
11047 binop(Iop_Add32, mkexpr(rMt), mkexpr(rN_d)), rMt, rN_d),
11048 condT
11049 );
11050
11051 DIP("qdadd%s r%u, r%u, r%u\n", nCC(conq),regD,regM,regN);
11052 return True;
11053 }
11054 /* fall through */
11055 }
11056
sewardj44ce46d2012-07-11 13:19:10 +000011057 /* ------------------ qsub<c> <Rd>,<Rn>,<Rm> ------------------- */
11058 {
11059 UInt regD = 99, regN = 99, regM = 99;
11060 Bool gate = False;
11061
11062 if (isT) {
11063 if (INSNT0(15,4) == 0xFA8 && (INSNT1(15,0) & 0xF0F0) == 0xF0A0) {
11064 regN = INSNT0(3,0);
11065 regD = INSNT1(11,8);
11066 regM = INSNT1(3,0);
11067 if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
11068 gate = True;
11069 }
11070 } else {
11071 if (INSNA(27,20) == BITS8(0,0,0,1,0,0,1,0) &&
11072 INSNA(11,8) == BITS4(0,0,0,0) &&
11073 INSNA(7,4) == BITS4(0,1,0,1)) {
11074 regD = INSNA(15,12);
11075 regN = INSNA(19,16);
11076 regM = INSNA(3,0);
11077 if (regD != 15 && regN != 15 && regM != 15)
11078 gate = True;
11079 }
11080 }
11081
11082 if (gate) {
11083 IRTemp rNt = newTemp(Ity_I32);
11084 IRTemp rMt = newTemp(Ity_I32);
11085 IRTemp res_q = newTemp(Ity_I32);
11086
11087 assign( rNt, isT ? getIRegT(regN) : getIRegA(regN) );
11088 assign( rMt, isT ? getIRegT(regM) : getIRegA(regM) );
11089
11090 assign(res_q, binop(Iop_QSub32S, mkexpr(rMt), mkexpr(rNt)));
11091 if (isT)
11092 putIRegT( regD, mkexpr(res_q), condT );
11093 else
11094 putIRegA( regD, mkexpr(res_q), condT, Ijk_Boring );
11095
11096 or_into_QFLAG32(
11097 signed_overflow_after_Sub32(
11098 binop(Iop_Sub32, mkexpr(rMt), mkexpr(rNt)), rMt, rNt),
11099 condT
11100 );
11101
11102 DIP("qsub%s r%u, r%u, r%u\n", nCC(conq),regD,regM,regN);
11103 return True;
11104 }
11105 /* fall through */
11106 }
11107
sewardj5a34b8b2012-08-23 20:56:17 +000011108 /* ------------------ qdsub<c> <Rd>,<Rm>,<Rn> ------------------- */
11109 {
11110 UInt regD = 99, regN = 99, regM = 99;
11111 Bool gate = False;
11112
11113 if (isT) {
11114 if (INSNT0(15,4) == 0xFA8 && (INSNT1(15,0) & 0xF0F0) == 0xF0B0) {
11115 regN = INSNT0(3,0);
11116 regD = INSNT1(11,8);
11117 regM = INSNT1(3,0);
11118 if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
11119 gate = True;
11120 }
11121 } else {
11122 if (INSNA(27,20) == BITS8(0,0,0,1,0,1,1,0) &&
11123 INSNA(11,8) == BITS4(0,0,0,0) &&
11124 INSNA(7,4) == BITS4(0,1,0,1)) {
11125 regD = INSNA(15,12);
11126 regN = INSNA(19,16);
11127 regM = INSNA(3,0);
11128 if (regD != 15 && regN != 15 && regM != 15)
11129 gate = True;
11130 }
11131 }
11132
11133 if (gate) {
11134 IRTemp rNt = newTemp(Ity_I32);
11135 IRTemp rMt = newTemp(Ity_I32);
11136 IRTemp rN_d = newTemp(Ity_I32);
11137 IRTemp res_q = newTemp(Ity_I32);
11138
11139 assign( rNt, isT ? getIRegT(regN) : getIRegA(regN) );
11140 assign( rMt, isT ? getIRegT(regM) : getIRegA(regM) );
11141
11142 or_into_QFLAG32(
11143 signed_overflow_after_Add32(
11144 binop(Iop_Add32, mkexpr(rNt), mkexpr(rNt)), rNt, rNt),
11145 condT
11146 );
11147
11148 assign(rN_d, binop(Iop_QAdd32S, mkexpr(rNt), mkexpr(rNt)));
11149 assign(res_q, binop(Iop_QSub32S, mkexpr(rMt), mkexpr(rN_d)));
11150 if (isT)
11151 putIRegT( regD, mkexpr(res_q), condT );
11152 else
11153 putIRegA( regD, mkexpr(res_q), condT, Ijk_Boring );
11154
11155 or_into_QFLAG32(
11156 signed_overflow_after_Sub32(
11157 binop(Iop_Sub32, mkexpr(rMt), mkexpr(rN_d)), rMt, rN_d),
11158 condT
11159 );
11160
11161 DIP("qdsub%s r%u, r%u, r%u\n", nCC(conq),regD,regM,regN);
11162 return True;
11163 }
11164 /* fall through */
11165 }
11166
sewardj32dd5382012-09-17 15:27:58 +000011167 /* ------------------ uqsub16<c> <Rd>,<Rn>,<Rm> ------------------ */
11168 {
11169 UInt regD = 99, regN = 99, regM = 99;
11170 Bool gate = False;
11171
11172 if (isT) {
11173 if (INSNT0(15,4) == 0xFAD && (INSNT1(15,0) & 0xF0F0) == 0xF050) {
11174 regN = INSNT0(3,0);
11175 regD = INSNT1(11,8);
11176 regM = INSNT1(3,0);
11177 if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
11178 gate = True;
11179 }
11180 } else {
11181 if (INSNA(27,20) == BITS8(0,1,1,0,0,1,1,0) &&
11182 INSNA(11,8) == BITS4(1,1,1,1) &&
11183 INSNA(7,4) == BITS4(0,1,1,1)) {
11184 regD = INSNA(15,12);
11185 regN = INSNA(19,16);
11186 regM = INSNA(3,0);
11187 if (regD != 15 && regN != 15 && regM != 15)
11188 gate = True;
11189 }
11190 }
11191
11192 if (gate) {
11193 IRTemp rNt = newTemp(Ity_I32);
11194 IRTemp rMt = newTemp(Ity_I32);
11195 IRTemp res_q = newTemp(Ity_I32);
11196
11197 assign( rNt, isT ? getIRegT(regN) : getIRegA(regN) );
11198 assign( rMt, isT ? getIRegT(regM) : getIRegA(regM) );
11199
11200 assign(res_q, binop(Iop_QSub16Ux2, mkexpr(rNt), mkexpr(rMt)));
11201 if (isT)
11202 putIRegT( regD, mkexpr(res_q), condT );
11203 else
11204 putIRegA( regD, mkexpr(res_q), condT, Ijk_Boring );
11205
11206 DIP("uqsub16%s r%u, r%u, r%u\n", nCC(conq),regD,regN,regM);
11207 return True;
11208 }
11209 /* fall through */
11210 }
11211
11212 /* ----------------- shadd16<c> <Rd>,<Rn>,<Rm> ------------------- */
11213 {
11214 UInt regD = 99, regN = 99, regM = 99;
11215 Bool gate = False;
11216
11217 if (isT) {
11218 if (INSNT0(15,4) == 0xFA9 && (INSNT1(15,0) & 0xF0F0) == 0xF020) {
11219 regN = INSNT0(3,0);
11220 regD = INSNT1(11,8);
11221 regM = INSNT1(3,0);
11222 if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
11223 gate = True;
11224 }
11225 } else {
11226 if (INSNA(27,20) == BITS8(0,1,1,0,0,0,1,1) &&
11227 INSNA(11,8) == BITS4(1,1,1,1) &&
11228 INSNA(7,4) == BITS4(0,0,0,1)) {
11229 regD = INSNA(15,12);
11230 regN = INSNA(19,16);
11231 regM = INSNA(3,0);
11232 if (regD != 15 && regN != 15 && regM != 15)
11233 gate = True;
11234 }
11235 }
11236
11237 if (gate) {
11238 IRTemp rNt = newTemp(Ity_I32);
11239 IRTemp rMt = newTemp(Ity_I32);
11240 IRTemp res_q = newTemp(Ity_I32);
11241
11242 assign( rNt, isT ? getIRegT(regN) : getIRegA(regN) );
11243 assign( rMt, isT ? getIRegT(regM) : getIRegA(regM) );
11244
11245 assign(res_q, binop(Iop_HAdd16Sx2, mkexpr(rNt), mkexpr(rMt)));
11246 if (isT)
11247 putIRegT( regD, mkexpr(res_q), condT );
11248 else
11249 putIRegA( regD, mkexpr(res_q), condT, Ijk_Boring );
11250
11251 DIP("shadd16%s r%u, r%u, r%u\n", nCC(conq),regD,regN,regM);
11252 return True;
11253 }
11254 /* fall through */
11255 }
11256
11257 /* ----------------- uhsub8<c> <Rd>,<Rn>,<Rm> ------------------- */
11258 {
11259 UInt regD = 99, regN = 99, regM = 99;
11260 Bool gate = False;
11261
11262 if (isT) {
11263 if (INSNT0(15,4) == 0xFAC && (INSNT1(15,0) & 0xF0F0) == 0xF060) {
11264 regN = INSNT0(3,0);
11265 regD = INSNT1(11,8);
11266 regM = INSNT1(3,0);
11267 if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
11268 gate = True;
11269 }
11270 } else {
11271 if (INSNA(27,20) == BITS8(0,1,1,0,0,1,1,1) &&
11272 INSNA(11,8) == BITS4(1,1,1,1) &&
11273 INSNA(7,4) == BITS4(1,1,1,1)) {
11274 regD = INSNA(15,12);
11275 regN = INSNA(19,16);
11276 regM = INSNA(3,0);
11277 if (regD != 15 && regN != 15 && regM != 15)
11278 gate = True;
11279 }
11280 }
11281
11282 if (gate) {
11283 IRTemp rNt = newTemp(Ity_I32);
11284 IRTemp rMt = newTemp(Ity_I32);
11285 IRTemp res_q = newTemp(Ity_I32);
11286
11287 assign( rNt, isT ? getIRegT(regN) : getIRegA(regN) );
11288 assign( rMt, isT ? getIRegT(regM) : getIRegA(regM) );
11289
11290 assign(res_q, binop(Iop_HSub8Ux4, mkexpr(rNt), mkexpr(rMt)));
11291 if (isT)
11292 putIRegT( regD, mkexpr(res_q), condT );
11293 else
11294 putIRegA( regD, mkexpr(res_q), condT, Ijk_Boring );
11295
11296 DIP("uhsub8%s r%u, r%u, r%u\n", nCC(conq),regD,regN,regM);
11297 return True;
11298 }
11299 /* fall through */
11300 }
11301
11302 /* ----------------- uhsub16<c> <Rd>,<Rn>,<Rm> ------------------- */
11303 {
11304 UInt regD = 99, regN = 99, regM = 99;
11305 Bool gate = False;
11306
11307 if (isT) {
11308 if (INSNT0(15,4) == 0xFAD && (INSNT1(15,0) & 0xF0F0) == 0xF060) {
11309 regN = INSNT0(3,0);
11310 regD = INSNT1(11,8);
11311 regM = INSNT1(3,0);
11312 if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
11313 gate = True;
11314 }
11315 } else {
11316 if (INSNA(27,20) == BITS8(0,1,1,0,0,1,1,1) &&
11317 INSNA(11,8) == BITS4(1,1,1,1) &&
11318 INSNA(7,4) == BITS4(0,1,1,1)) {
11319 regD = INSNA(15,12);
11320 regN = INSNA(19,16);
11321 regM = INSNA(3,0);
11322 if (regD != 15 && regN != 15 && regM != 15)
11323 gate = True;
11324 }
11325 }
11326
11327 if (gate) {
11328 IRTemp rNt = newTemp(Ity_I32);
11329 IRTemp rMt = newTemp(Ity_I32);
11330 IRTemp res_q = newTemp(Ity_I32);
11331
11332 assign( rNt, isT ? getIRegT(regN) : getIRegA(regN) );
11333 assign( rMt, isT ? getIRegT(regM) : getIRegA(regM) );
11334
11335 assign(res_q, binop(Iop_HSub16Ux2, mkexpr(rNt), mkexpr(rMt)));
11336 if (isT)
11337 putIRegT( regD, mkexpr(res_q), condT );
11338 else
11339 putIRegA( regD, mkexpr(res_q), condT, Ijk_Boring );
11340
11341 DIP("uhsub16%s r%u, r%u, r%u\n", nCC(conq),regD,regN,regM);
11342 return True;
11343 }
11344 /* fall through */
11345 }
11346
sewardj1f139f52010-08-29 12:33:02 +000011347 /* ---------- Doesn't match anything. ---------- */
11348 return False;
11349
11350# undef INSNA
11351# undef INSNT0
11352# undef INSNT1
11353}
11354
11355
11356/*------------------------------------------------------------*/
sewardjd2664472010-08-22 12:44:20 +000011357/*--- LDMxx/STMxx helper (both ARM and Thumb32) ---*/
11358/*------------------------------------------------------------*/
11359
11360/* Generate IR for LDMxx and STMxx. This is complex. Assumes it's
11361 unconditional, so the caller must produce a jump-around before
11362 calling this, if the insn is to be conditional. Caller is
11363 responsible for all validation of parameters. For LDMxx, if PC is
11364 amongst the values loaded, caller is also responsible for
11365 generating the jump. */
11366static void mk_ldm_stm ( Bool arm, /* True: ARM, False: Thumb */
11367 UInt rN, /* base reg */
11368 UInt bINC, /* 1: inc, 0: dec */
11369 UInt bBEFORE, /* 1: inc/dec before, 0: after */
11370 UInt bW, /* 1: writeback to Rn */
11371 UInt bL, /* 1: load, 0: store */
11372 UInt regList )
11373{
11374 Int i, r, m, nRegs;
sewardjf5800652011-10-14 15:44:00 +000011375 IRTemp jk = Ijk_Boring;
sewardjd2664472010-08-22 12:44:20 +000011376
11377 /* Get hold of the old Rn value. We might need to write its value
11378 to memory during a store, and if it's also the writeback
11379 register then we need to get its value now. We can't treat it
11380 exactly like the other registers we're going to transfer,
11381 because for xxMDA and xxMDB writeback forms, the generated IR
11382 updates Rn in the guest state before any transfers take place.
11383 We have to do this as per comments below, in order that if Rn is
11384 the stack pointer then it always has a value is below or equal
11385 to any of the transfer addresses. Ick. */
11386 IRTemp oldRnT = newTemp(Ity_I32);
11387 assign(oldRnT, arm ? getIRegA(rN) : getIRegT(rN));
11388
11389 IRTemp anchorT = newTemp(Ity_I32);
11390 /* The old (Addison-Wesley) ARM ARM seems to say that LDMxx/STMxx
11391 ignore the bottom two bits of the address. However, Cortex-A8
11392 doesn't seem to care. Hence: */
11393 /* No .. don't force alignment .. */
11394 /* assign(anchorT, binop(Iop_And32, mkexpr(oldRnT), mkU32(~3U))); */
11395 /* Instead, use the potentially misaligned address directly. */
11396 assign(anchorT, mkexpr(oldRnT));
11397
11398 IROp opADDorSUB = bINC ? Iop_Add32 : Iop_Sub32;
11399 // bINC == 1: xxMIA, xxMIB
11400 // bINC == 0: xxMDA, xxMDB
11401
11402 // For xxMDA and xxMDB, update Rn first if necessary. We have
11403 // to do this first so that, for the common idiom of the transfers
11404 // faulting because we're pushing stuff onto a stack and the stack
11405 // is growing down onto allocate-on-fault pages (as Valgrind simulates),
11406 // we need to have the SP up-to-date "covering" (pointing below) the
11407 // transfer area. For the same reason, if we are doing xxMIA or xxMIB,
11408 // do the transfer first, and then update rN afterwards.
11409 nRegs = 0;
11410 for (i = 0; i < 16; i++) {
11411 if ((regList & (1 << i)) != 0)
11412 nRegs++;
11413 }
11414 if (bW == 1 && !bINC) {
11415 IRExpr* e = binop(opADDorSUB, mkexpr(oldRnT), mkU32(4*nRegs));
11416 if (arm)
11417 putIRegA( rN, e, IRTemp_INVALID, Ijk_Boring );
11418 else
11419 putIRegT( rN, e, IRTemp_INVALID );
11420 }
11421
11422 // Make up a list of the registers to transfer, and their offsets
11423 // in memory relative to the anchor. If the base reg (Rn) is part
11424 // of the transfer, then do it last for a load and first for a store.
11425 UInt xReg[16], xOff[16];
11426 Int nX = 0;
11427 m = 0;
11428 for (i = 0; i < 16; i++) {
11429 r = bINC ? i : (15-i);
11430 if (0 == (regList & (1<<r)))
11431 continue;
11432 if (bBEFORE)
11433 m++;
11434 /* paranoia: check we aren't transferring the writeback
11435 register during a load. Should be assured by decode-point
11436 check above. */
11437 if (bW == 1 && bL == 1)
11438 vassert(r != rN);
11439
11440 xOff[nX] = 4 * m;
11441 xReg[nX] = r;
11442 nX++;
11443
11444 if (!bBEFORE)
11445 m++;
11446 }
11447 vassert(m == nRegs);
11448 vassert(nX == nRegs);
11449 vassert(nX <= 16);
11450
11451 if (bW == 0 && (regList & (1<<rN)) != 0) {
11452 /* Non-writeback, and basereg is to be transferred. Do its
11453 transfer last for a load and first for a store. Requires
11454 reordering xOff/xReg. */
11455 if (0) {
11456 vex_printf("\nREG_LIST_PRE: (rN=%d)\n", rN);
11457 for (i = 0; i < nX; i++)
11458 vex_printf("reg %d off %d\n", xReg[i], xOff[i]);
11459 vex_printf("\n");
11460 }
11461
11462 vassert(nX > 0);
11463 for (i = 0; i < nX; i++) {
11464 if (xReg[i] == rN)
11465 break;
11466 }
11467 vassert(i < nX); /* else we didn't find it! */
11468 UInt tReg = xReg[i];
11469 UInt tOff = xOff[i];
11470 if (bL == 1) {
11471 /* load; make this transfer happen last */
11472 if (i < nX-1) {
11473 for (m = i+1; m < nX; m++) {
11474 xReg[m-1] = xReg[m];
11475 xOff[m-1] = xOff[m];
11476 }
11477 vassert(m == nX);
11478 xReg[m-1] = tReg;
11479 xOff[m-1] = tOff;
11480 }
11481 } else {
11482 /* store; make this transfer happen first */
11483 if (i > 0) {
11484 for (m = i-1; m >= 0; m--) {
11485 xReg[m+1] = xReg[m];
11486 xOff[m+1] = xOff[m];
11487 }
11488 vassert(m == -1);
11489 xReg[0] = tReg;
11490 xOff[0] = tOff;
11491 }
11492 }
11493
11494 if (0) {
11495 vex_printf("REG_LIST_POST:\n");
11496 for (i = 0; i < nX; i++)
11497 vex_printf("reg %d off %d\n", xReg[i], xOff[i]);
11498 vex_printf("\n");
11499 }
11500 }
11501
sewardjf5800652011-10-14 15:44:00 +000011502 /* According to the Cortex A8 TRM Sec. 5.2.1, LDM(1) with r13 as the base
11503 register and PC in the register list is a return for purposes of branch
11504 prediction.
11505 The ARM ARM Sec. C9.10.1 further specifies that writeback must be enabled
11506 to be counted in event 0x0E (Procedure return).*/
11507 if (rN == 13 && bL == 1 && bINC && !bBEFORE && bW == 1) {
11508 jk = Ijk_Ret;
11509 }
11510
sewardjd2664472010-08-22 12:44:20 +000011511 /* Actually generate the transfers */
11512 for (i = 0; i < nX; i++) {
11513 r = xReg[i];
11514 if (bL == 1) {
11515 IRExpr* e = loadLE(Ity_I32,
11516 binop(opADDorSUB, mkexpr(anchorT),
11517 mkU32(xOff[i])));
11518 if (arm) {
sewardjf5800652011-10-14 15:44:00 +000011519 putIRegA( r, e, IRTemp_INVALID, jk );
sewardjd2664472010-08-22 12:44:20 +000011520 } else {
11521 // no: putIRegT( r, e, IRTemp_INVALID );
11522 // putIRegT refuses to write to R15. But that might happen.
11523 // Since this is uncond, and we need to be able to
11524 // write the PC, just use the low level put:
11525 llPutIReg( r, e );
11526 }
11527 } else {
11528 /* if we're storing Rn, make sure we use the correct
11529 value, as per extensive comments above */
11530 storeLE( binop(opADDorSUB, mkexpr(anchorT), mkU32(xOff[i])),
11531 r == rN ? mkexpr(oldRnT)
11532 : (arm ? getIRegA(r) : getIRegT(r) ) );
11533 }
11534 }
11535
11536 // If we are doing xxMIA or xxMIB,
11537 // do the transfer first, and then update rN afterwards.
11538 if (bW == 1 && bINC) {
11539 IRExpr* e = binop(opADDorSUB, mkexpr(oldRnT), mkU32(4*nRegs));
11540 if (arm)
11541 putIRegA( rN, e, IRTemp_INVALID, Ijk_Boring );
11542 else
11543 putIRegT( rN, e, IRTemp_INVALID );
11544 }
11545}
11546
11547
11548/*------------------------------------------------------------*/
11549/*--- VFP (CP 10 and 11) instructions ---*/
11550/*------------------------------------------------------------*/
11551
11552/* Both ARM and Thumb */
11553
11554/* Translate a CP10 or CP11 instruction. If successful, returns
11555 True and *dres may or may not be updated. If failure, returns
11556 False and doesn't change *dres nor create any IR.
11557
11558 The ARM and Thumb encodings are identical for the low 28 bits of
11559 the insn (yay!) and that's what the caller must supply, iow, imm28
11560 has the top 4 bits masked out. Caller is responsible for
11561 determining whether the masked-out bits are valid for a CP10/11
11562 insn. The rules for the top 4 bits are:
11563
11564 ARM: 0000 to 1110 allowed, and this is the gating condition.
11565 1111 (NV) is not allowed.
11566
11567 Thumb: must be 1110. The gating condition is taken from
11568 ITSTATE in the normal way.
11569
11570 Conditionalisation:
11571
11572 Caller must supply an IRTemp 'condT' holding the gating condition,
11573 or IRTemp_INVALID indicating the insn is always executed.
11574
11575 Caller must also supply an ARMCondcode 'cond'. This is only used
11576 for debug printing, no other purpose. For ARM, this is simply the
11577 top 4 bits of the original instruction. For Thumb, the condition
11578 is not (really) known until run time, and so ARMCondAL should be
11579 passed, only so that printing of these instructions does not show
11580 any condition.
11581
11582 Finally, the caller must indicate whether this occurs in ARM or
11583 Thumb code.
11584*/
11585static Bool decode_CP10_CP11_instruction (
11586 /*MOD*/DisResult* dres,
11587 UInt insn28,
11588 IRTemp condT,
11589 ARMCondcode conq,
11590 Bool isT
11591 )
11592{
11593# define INSN(_bMax,_bMin) SLICE_UInt(insn28, (_bMax), (_bMin))
11594
11595 vassert(INSN(31,28) == BITS4(0,0,0,0)); // caller's obligation
11596
11597 if (isT) {
11598 vassert(conq == ARMCondAL);
11599 } else {
11600 vassert(conq >= ARMCondEQ && conq <= ARMCondAL);
11601 }
11602
11603 /* ----------------------------------------------------------- */
11604 /* -- VFP instructions -- double precision (mostly) -- */
11605 /* ----------------------------------------------------------- */
11606
11607 /* --------------------- fldmx, fstmx --------------------- */
11608 /*
11609 31 27 23 19 15 11 7 0
11610 P U WL
11611 C4-100, C5-26 1 FSTMX cond 1100 1000 Rn Dd 1011 offset
11612 C4-100, C5-28 2 FSTMIAX cond 1100 1010 Rn Dd 1011 offset
11613 C4-100, C5-30 3 FSTMDBX cond 1101 0010 Rn Dd 1011 offset
11614
11615 C4-42, C5-26 1 FLDMX cond 1100 1001 Rn Dd 1011 offset
11616 C4-42, C5-28 2 FLDMIAX cond 1100 1011 Rn Dd 1011 offset
11617 C4-42, C5-30 3 FLDMDBX cond 1101 0011 Rn Dd 1011 offset
11618
11619 Regs transferred: Dd .. D(d + (offset-3)/2)
11620 offset must be odd, must not imply a reg > 15
11621 IA/DB: Rn is changed by (4 + 8 x # regs transferred)
11622
11623 case coding:
11624 1 at-Rn (access at Rn)
11625 2 ia-Rn (access at Rn, then Rn += 4+8n)
11626 3 db-Rn (Rn -= 4+8n, then access at Rn)
11627 */
11628 if (BITS8(1,1,0,0,0,0,0,0) == (INSN(27,20) & BITS8(1,1,1,0,0,0,0,0))
11629 && INSN(11,8) == BITS4(1,0,1,1)) {
11630 UInt bP = (insn28 >> 24) & 1;
11631 UInt bU = (insn28 >> 23) & 1;
11632 UInt bW = (insn28 >> 21) & 1;
11633 UInt bL = (insn28 >> 20) & 1;
11634 UInt offset = (insn28 >> 0) & 0xFF;
11635 UInt rN = INSN(19,16);
11636 UInt dD = (INSN(22,22) << 4) | INSN(15,12);
11637 UInt nRegs = (offset - 1) / 2;
11638 UInt summary = 0;
11639 Int i;
11640
11641 /**/ if (bP == 0 && bU == 1 && bW == 0) {
11642 summary = 1;
11643 }
11644 else if (bP == 0 && bU == 1 && bW == 1) {
11645 summary = 2;
11646 }
11647 else if (bP == 1 && bU == 0 && bW == 1) {
11648 summary = 3;
11649 }
11650 else goto after_vfp_fldmx_fstmx;
11651
11652 /* no writebacks to r15 allowed. No use of r15 in thumb mode. */
11653 if (rN == 15 && (summary == 2 || summary == 3 || isT))
11654 goto after_vfp_fldmx_fstmx;
11655
11656 /* offset must be odd, and specify at least one register */
11657 if (0 == (offset & 1) || offset < 3)
11658 goto after_vfp_fldmx_fstmx;
11659
11660 /* can't transfer regs after D15 */
11661 if (dD + nRegs - 1 >= 32)
11662 goto after_vfp_fldmx_fstmx;
11663
11664 /* Now, we can't do a conditional load or store, since that very
11665 likely will generate an exception. So we have to take a side
11666 exit at this point if the condition is false. */
11667 if (condT != IRTemp_INVALID) {
11668 if (isT)
11669 mk_skip_over_T32_if_cond_is_false( condT );
11670 else
11671 mk_skip_over_A32_if_cond_is_false( condT );
11672 condT = IRTemp_INVALID;
11673 }
11674 /* Ok, now we're unconditional. Do the load or store. */
11675
11676 /* get the old Rn value */
11677 IRTemp rnT = newTemp(Ity_I32);
11678 assign(rnT, align4if(isT ? getIRegT(rN) : getIRegA(rN),
11679 rN == 15));
11680
11681 /* make a new value for Rn, post-insn */
11682 IRTemp rnTnew = IRTemp_INVALID;
11683 if (summary == 2 || summary == 3) {
11684 rnTnew = newTemp(Ity_I32);
11685 assign(rnTnew, binop(summary == 2 ? Iop_Add32 : Iop_Sub32,
11686 mkexpr(rnT),
11687 mkU32(4 + 8 * nRegs)));
11688 }
11689
11690 /* decide on the base transfer address */
11691 IRTemp taT = newTemp(Ity_I32);
11692 assign(taT, summary == 3 ? mkexpr(rnTnew) : mkexpr(rnT));
11693
11694 /* update Rn if necessary -- in case 3, we're moving it down, so
11695 update before any memory reference, in order to keep Memcheck
11696 and V's stack-extending logic (on linux) happy */
11697 if (summary == 3) {
11698 if (isT)
11699 putIRegT(rN, mkexpr(rnTnew), IRTemp_INVALID);
11700 else
11701 putIRegA(rN, mkexpr(rnTnew), IRTemp_INVALID, Ijk_Boring);
11702 }
11703
11704 /* generate the transfers */
11705 for (i = 0; i < nRegs; i++) {
11706 IRExpr* addr = binop(Iop_Add32, mkexpr(taT), mkU32(8*i));
11707 if (bL) {
11708 putDReg(dD + i, loadLE(Ity_F64, addr), IRTemp_INVALID);
11709 } else {
11710 storeLE(addr, getDReg(dD + i));
11711 }
11712 }
11713
11714 /* update Rn if necessary -- in case 2, we're moving it up, so
11715 update after any memory reference, in order to keep Memcheck
11716 and V's stack-extending logic (on linux) happy */
11717 if (summary == 2) {
11718 if (isT)
11719 putIRegT(rN, mkexpr(rnTnew), IRTemp_INVALID);
11720 else
11721 putIRegA(rN, mkexpr(rnTnew), IRTemp_INVALID, Ijk_Boring);
11722 }
11723
florian55085f82012-11-21 00:36:55 +000011724 const HChar* nm = bL==1 ? "ld" : "st";
sewardjd2664472010-08-22 12:44:20 +000011725 switch (summary) {
11726 case 1: DIP("f%smx%s r%u, {d%u-d%u}\n",
11727 nm, nCC(conq), rN, dD, dD + nRegs - 1);
11728 break;
11729 case 2: DIP("f%smiax%s r%u!, {d%u-d%u}\n",
11730 nm, nCC(conq), rN, dD, dD + nRegs - 1);
11731 break;
11732 case 3: DIP("f%smdbx%s r%u!, {d%u-d%u}\n",
11733 nm, nCC(conq), rN, dD, dD + nRegs - 1);
11734 break;
11735 default: vassert(0);
11736 }
11737
11738 goto decode_success_vfp;
11739 /* FIXME alignment constraints? */
11740 }
11741
11742 after_vfp_fldmx_fstmx:
11743
11744 /* --------------------- fldmd, fstmd --------------------- */
11745 /*
11746 31 27 23 19 15 11 7 0
11747 P U WL
11748 C4-96, C5-26 1 FSTMD cond 1100 1000 Rn Dd 1011 offset
11749 C4-96, C5-28 2 FSTMDIA cond 1100 1010 Rn Dd 1011 offset
11750 C4-96, C5-30 3 FSTMDDB cond 1101 0010 Rn Dd 1011 offset
11751
11752 C4-38, C5-26 1 FLDMD cond 1100 1001 Rn Dd 1011 offset
11753 C4-38, C5-28 2 FLDMIAD cond 1100 1011 Rn Dd 1011 offset
11754 C4-38, C5-30 3 FLDMDBD cond 1101 0011 Rn Dd 1011 offset
11755
11756 Regs transferred: Dd .. D(d + (offset-2)/2)
11757 offset must be even, must not imply a reg > 15
11758 IA/DB: Rn is changed by (8 x # regs transferred)
11759
11760 case coding:
11761 1 at-Rn (access at Rn)
11762 2 ia-Rn (access at Rn, then Rn += 8n)
11763 3 db-Rn (Rn -= 8n, then access at Rn)
11764 */
11765 if (BITS8(1,1,0,0,0,0,0,0) == (INSN(27,20) & BITS8(1,1,1,0,0,0,0,0))
11766 && INSN(11,8) == BITS4(1,0,1,1)) {
11767 UInt bP = (insn28 >> 24) & 1;
11768 UInt bU = (insn28 >> 23) & 1;
11769 UInt bW = (insn28 >> 21) & 1;
11770 UInt bL = (insn28 >> 20) & 1;
11771 UInt offset = (insn28 >> 0) & 0xFF;
11772 UInt rN = INSN(19,16);
11773 UInt dD = (INSN(22,22) << 4) | INSN(15,12);
11774 UInt nRegs = offset / 2;
11775 UInt summary = 0;
11776 Int i;
11777
11778 /**/ if (bP == 0 && bU == 1 && bW == 0) {
11779 summary = 1;
11780 }
11781 else if (bP == 0 && bU == 1 && bW == 1) {
11782 summary = 2;
11783 }
11784 else if (bP == 1 && bU == 0 && bW == 1) {
11785 summary = 3;
11786 }
11787 else goto after_vfp_fldmd_fstmd;
11788
11789 /* no writebacks to r15 allowed. No use of r15 in thumb mode. */
11790 if (rN == 15 && (summary == 2 || summary == 3 || isT))
11791 goto after_vfp_fldmd_fstmd;
11792
11793 /* offset must be even, and specify at least one register */
11794 if (1 == (offset & 1) || offset < 2)
11795 goto after_vfp_fldmd_fstmd;
11796
11797 /* can't transfer regs after D15 */
11798 if (dD + nRegs - 1 >= 32)
11799 goto after_vfp_fldmd_fstmd;
11800
11801 /* Now, we can't do a conditional load or store, since that very
11802 likely will generate an exception. So we have to take a side
11803 exit at this point if the condition is false. */
11804 if (condT != IRTemp_INVALID) {
11805 if (isT)
11806 mk_skip_over_T32_if_cond_is_false( condT );
11807 else
11808 mk_skip_over_A32_if_cond_is_false( condT );
11809 condT = IRTemp_INVALID;
11810 }
11811 /* Ok, now we're unconditional. Do the load or store. */
11812
11813 /* get the old Rn value */
11814 IRTemp rnT = newTemp(Ity_I32);
11815 assign(rnT, align4if(isT ? getIRegT(rN) : getIRegA(rN),
11816 rN == 15));
11817
11818 /* make a new value for Rn, post-insn */
11819 IRTemp rnTnew = IRTemp_INVALID;
11820 if (summary == 2 || summary == 3) {
11821 rnTnew = newTemp(Ity_I32);
11822 assign(rnTnew, binop(summary == 2 ? Iop_Add32 : Iop_Sub32,
11823 mkexpr(rnT),
11824 mkU32(8 * nRegs)));
11825 }
11826
11827 /* decide on the base transfer address */
11828 IRTemp taT = newTemp(Ity_I32);
11829 assign(taT, summary == 3 ? mkexpr(rnTnew) : mkexpr(rnT));
11830
11831 /* update Rn if necessary -- in case 3, we're moving it down, so
11832 update before any memory reference, in order to keep Memcheck
11833 and V's stack-extending logic (on linux) happy */
11834 if (summary == 3) {
11835 if (isT)
11836 putIRegT(rN, mkexpr(rnTnew), IRTemp_INVALID);
11837 else
11838 putIRegA(rN, mkexpr(rnTnew), IRTemp_INVALID, Ijk_Boring);
11839 }
11840
11841 /* generate the transfers */
11842 for (i = 0; i < nRegs; i++) {
11843 IRExpr* addr = binop(Iop_Add32, mkexpr(taT), mkU32(8*i));
11844 if (bL) {
11845 putDReg(dD + i, loadLE(Ity_F64, addr), IRTemp_INVALID);
11846 } else {
11847 storeLE(addr, getDReg(dD + i));
11848 }
11849 }
11850
11851 /* update Rn if necessary -- in case 2, we're moving it up, so
11852 update after any memory reference, in order to keep Memcheck
11853 and V's stack-extending logic (on linux) happy */
11854 if (summary == 2) {
11855 if (isT)
11856 putIRegT(rN, mkexpr(rnTnew), IRTemp_INVALID);
11857 else
11858 putIRegA(rN, mkexpr(rnTnew), IRTemp_INVALID, Ijk_Boring);
11859 }
11860
florian55085f82012-11-21 00:36:55 +000011861 const HChar* nm = bL==1 ? "ld" : "st";
sewardjd2664472010-08-22 12:44:20 +000011862 switch (summary) {
11863 case 1: DIP("f%smd%s r%u, {d%u-d%u}\n",
11864 nm, nCC(conq), rN, dD, dD + nRegs - 1);
11865 break;
11866 case 2: DIP("f%smiad%s r%u!, {d%u-d%u}\n",
11867 nm, nCC(conq), rN, dD, dD + nRegs - 1);
11868 break;
11869 case 3: DIP("f%smdbd%s r%u!, {d%u-d%u}\n",
11870 nm, nCC(conq), rN, dD, dD + nRegs - 1);
11871 break;
11872 default: vassert(0);
11873 }
11874
11875 goto decode_success_vfp;
11876 /* FIXME alignment constraints? */
11877 }
11878
11879 after_vfp_fldmd_fstmd:
11880
11881 /* ------------------- fmrx, fmxr ------------------- */
11882 if (BITS8(1,1,1,0,1,1,1,1) == INSN(27,20)
11883 && BITS4(1,0,1,0) == INSN(11,8)
11884 && BITS8(0,0,0,1,0,0,0,0) == (insn28 & 0xFF)) {
11885 UInt rD = INSN(15,12);
11886 UInt reg = INSN(19,16);
11887 if (reg == BITS4(0,0,0,1)) {
11888 if (rD == 15) {
11889 IRTemp nzcvT = newTemp(Ity_I32);
11890 /* When rD is 15, we are copying the top 4 bits of FPSCR
11891 into CPSR. That is, set the flags thunk to COPY and
11892 install FPSCR[31:28] as the value to copy. */
11893 assign(nzcvT, binop(Iop_And32,
11894 IRExpr_Get(OFFB_FPSCR, Ity_I32),
11895 mkU32(0xF0000000)));
11896 setFlags_D1(ARMG_CC_OP_COPY, nzcvT, condT);
11897 DIP("fmstat%s\n", nCC(conq));
11898 } else {
11899 /* Otherwise, merely transfer FPSCR to r0 .. r14. */
11900 IRExpr* e = IRExpr_Get(OFFB_FPSCR, Ity_I32);
11901 if (isT)
11902 putIRegT(rD, e, condT);
11903 else
11904 putIRegA(rD, e, condT, Ijk_Boring);
11905 DIP("fmrx%s r%u, fpscr\n", nCC(conq), rD);
11906 }
11907 goto decode_success_vfp;
11908 }
11909 /* fall through */
11910 }
11911
11912 if (BITS8(1,1,1,0,1,1,1,0) == INSN(27,20)
11913 && BITS4(1,0,1,0) == INSN(11,8)
11914 && BITS8(0,0,0,1,0,0,0,0) == (insn28 & 0xFF)) {
11915 UInt rD = INSN(15,12);
11916 UInt reg = INSN(19,16);
11917 if (reg == BITS4(0,0,0,1)) {
11918 putMiscReg32(OFFB_FPSCR,
11919 isT ? getIRegT(rD) : getIRegA(rD), condT);
11920 DIP("fmxr%s fpscr, r%u\n", nCC(conq), rD);
11921 goto decode_success_vfp;
11922 }
11923 /* fall through */
11924 }
11925
11926 /* --------------------- vmov --------------------- */
11927 // VMOV dM, rD, rN
11928 if (0x0C400B10 == (insn28 & 0x0FF00FD0)) {
11929 UInt dM = INSN(3,0) | (INSN(5,5) << 4);
11930 UInt rD = INSN(15,12); /* lo32 */
11931 UInt rN = INSN(19,16); /* hi32 */
sewardj93ba93f2010-09-22 16:15:50 +000011932 if (rD == 15 || rN == 15 || (isT && (rD == 13 || rN == 13))) {
sewardjd2664472010-08-22 12:44:20 +000011933 /* fall through */
11934 } else {
11935 putDReg(dM,
11936 unop(Iop_ReinterpI64asF64,
11937 binop(Iop_32HLto64,
11938 isT ? getIRegT(rN) : getIRegA(rN),
11939 isT ? getIRegT(rD) : getIRegA(rD))),
11940 condT);
11941 DIP("vmov%s d%u, r%u, r%u\n", nCC(conq), dM, rD, rN);
11942 goto decode_success_vfp;
11943 }
11944 /* fall through */
11945 }
11946
11947 // VMOV rD, rN, dM
11948 if (0x0C500B10 == (insn28 & 0x0FF00FD0)) {
11949 UInt dM = INSN(3,0) | (INSN(5,5) << 4);
11950 UInt rD = INSN(15,12); /* lo32 */
11951 UInt rN = INSN(19,16); /* hi32 */
sewardj93ba93f2010-09-22 16:15:50 +000011952 if (rD == 15 || rN == 15 || (isT && (rD == 13 || rN == 13))
11953 || rD == rN) {
sewardjd2664472010-08-22 12:44:20 +000011954 /* fall through */
11955 } else {
11956 IRTemp i64 = newTemp(Ity_I64);
11957 assign(i64, unop(Iop_ReinterpF64asI64, getDReg(dM)));
11958 IRExpr* hi32 = unop(Iop_64HIto32, mkexpr(i64));
11959 IRExpr* lo32 = unop(Iop_64to32, mkexpr(i64));
11960 if (isT) {
11961 putIRegT(rN, hi32, condT);
11962 putIRegT(rD, lo32, condT);
11963 } else {
11964 putIRegA(rN, hi32, condT, Ijk_Boring);
11965 putIRegA(rD, lo32, condT, Ijk_Boring);
11966 }
11967 DIP("vmov%s r%u, r%u, d%u\n", nCC(conq), rD, rN, dM);
11968 goto decode_success_vfp;
11969 }
11970 /* fall through */
11971 }
11972
sewardj93ba93f2010-09-22 16:15:50 +000011973 // VMOV sD, sD+1, rN, rM
11974 if (0x0C400A10 == (insn28 & 0x0FF00FD0)) {
11975 UInt sD = (INSN(3,0) << 1) | INSN(5,5);
11976 UInt rN = INSN(15,12);
11977 UInt rM = INSN(19,16);
11978 if (rM == 15 || rN == 15 || (isT && (rM == 13 || rN == 13))
11979 || sD == 31) {
11980 /* fall through */
11981 } else {
11982 putFReg(sD,
11983 unop(Iop_ReinterpI32asF32, isT ? getIRegT(rN) : getIRegA(rN)),
11984 condT);
11985 putFReg(sD+1,
11986 unop(Iop_ReinterpI32asF32, isT ? getIRegT(rM) : getIRegA(rM)),
11987 condT);
11988 DIP("vmov%s, s%u, s%u, r%u, r%u\n",
11989 nCC(conq), sD, sD + 1, rN, rM);
11990 goto decode_success_vfp;
11991 }
11992 }
11993
11994 // VMOV rN, rM, sD, sD+1
11995 if (0x0C500A10 == (insn28 & 0x0FF00FD0)) {
11996 UInt sD = (INSN(3,0) << 1) | INSN(5,5);
11997 UInt rN = INSN(15,12);
11998 UInt rM = INSN(19,16);
11999 if (rM == 15 || rN == 15 || (isT && (rM == 13 || rN == 13))
12000 || sD == 31 || rN == rM) {
12001 /* fall through */
12002 } else {
12003 IRExpr* res0 = unop(Iop_ReinterpF32asI32, getFReg(sD));
12004 IRExpr* res1 = unop(Iop_ReinterpF32asI32, getFReg(sD+1));
12005 if (isT) {
12006 putIRegT(rN, res0, condT);
12007 putIRegT(rM, res1, condT);
12008 } else {
12009 putIRegA(rN, res0, condT, Ijk_Boring);
12010 putIRegA(rM, res1, condT, Ijk_Boring);
12011 }
12012 DIP("vmov%s, r%u, r%u, s%u, s%u\n",
12013 nCC(conq), rN, rM, sD, sD + 1);
12014 goto decode_success_vfp;
12015 }
12016 }
12017
12018 // VMOV rD[x], rT (ARM core register to scalar)
sewardjd2664472010-08-22 12:44:20 +000012019 if (0x0E000B10 == (insn28 & 0x0F900F1F)) {
12020 UInt rD = (INSN(7,7) << 4) | INSN(19,16);
12021 UInt rT = INSN(15,12);
12022 UInt opc = (INSN(22,21) << 2) | INSN(6,5);
12023 UInt index;
sewardj93ba93f2010-09-22 16:15:50 +000012024 if (rT == 15 || (isT && rT == 13)) {
sewardjd2664472010-08-22 12:44:20 +000012025 /* fall through */
12026 } else {
12027 if ((opc & BITS4(1,0,0,0)) == BITS4(1,0,0,0)) {
12028 index = opc & 7;
12029 putDRegI64(rD, triop(Iop_SetElem8x8,
12030 getDRegI64(rD),
12031 mkU8(index),
12032 unop(Iop_32to8,
12033 isT ? getIRegT(rT) : getIRegA(rT))),
12034 condT);
12035 DIP("vmov%s.8 d%u[%u], r%u\n", nCC(conq), rD, index, rT);
12036 goto decode_success_vfp;
12037 }
12038 else if ((opc & BITS4(1,0,0,1)) == BITS4(0,0,0,1)) {
12039 index = (opc >> 1) & 3;
12040 putDRegI64(rD, triop(Iop_SetElem16x4,
12041 getDRegI64(rD),
12042 mkU8(index),
12043 unop(Iop_32to16,
12044 isT ? getIRegT(rT) : getIRegA(rT))),
12045 condT);
12046 DIP("vmov%s.16 d%u[%u], r%u\n", nCC(conq), rD, index, rT);
12047 goto decode_success_vfp;
12048 }
12049 else if ((opc & BITS4(1,0,1,1)) == BITS4(0,0,0,0)) {
12050 index = (opc >> 2) & 1;
12051 putDRegI64(rD, triop(Iop_SetElem32x2,
12052 getDRegI64(rD),
12053 mkU8(index),
12054 isT ? getIRegT(rT) : getIRegA(rT)),
12055 condT);
12056 DIP("vmov%s.32 d%u[%u], r%u\n", nCC(conq), rD, index, rT);
12057 goto decode_success_vfp;
12058 } else {
12059 /* fall through */
12060 }
12061 }
12062 }
12063
sewardj93ba93f2010-09-22 16:15:50 +000012064 // VMOV (scalar to ARM core register)
sewardjd2664472010-08-22 12:44:20 +000012065 // VMOV rT, rD[x]
12066 if (0x0E100B10 == (insn28 & 0x0F100F1F)) {
12067 UInt rN = (INSN(7,7) << 4) | INSN(19,16);
12068 UInt rT = INSN(15,12);
12069 UInt U = INSN(23,23);
12070 UInt opc = (INSN(22,21) << 2) | INSN(6,5);
12071 UInt index;
sewardj93ba93f2010-09-22 16:15:50 +000012072 if (rT == 15 || (isT && rT == 13)) {
sewardjd2664472010-08-22 12:44:20 +000012073 /* fall through */
12074 } else {
12075 if ((opc & BITS4(1,0,0,0)) == BITS4(1,0,0,0)) {
12076 index = opc & 7;
12077 IRExpr* e = unop(U ? Iop_8Uto32 : Iop_8Sto32,
12078 binop(Iop_GetElem8x8,
12079 getDRegI64(rN),
12080 mkU8(index)));
12081 if (isT)
12082 putIRegT(rT, e, condT);
12083 else
12084 putIRegA(rT, e, condT, Ijk_Boring);
12085 DIP("vmov%s.%c8 r%u, d%u[%u]\n", nCC(conq), U ? 'u' : 's',
12086 rT, rN, index);
12087 goto decode_success_vfp;
12088 }
12089 else if ((opc & BITS4(1,0,0,1)) == BITS4(0,0,0,1)) {
12090 index = (opc >> 1) & 3;
12091 IRExpr* e = unop(U ? Iop_16Uto32 : Iop_16Sto32,
12092 binop(Iop_GetElem16x4,
12093 getDRegI64(rN),
12094 mkU8(index)));
12095 if (isT)
12096 putIRegT(rT, e, condT);
12097 else
12098 putIRegA(rT, e, condT, Ijk_Boring);
12099 DIP("vmov%s.%c16 r%u, d%u[%u]\n", nCC(conq), U ? 'u' : 's',
12100 rT, rN, index);
12101 goto decode_success_vfp;
12102 }
12103 else if ((opc & BITS4(1,0,1,1)) == BITS4(0,0,0,0) && U == 0) {
12104 index = (opc >> 2) & 1;
12105 IRExpr* e = binop(Iop_GetElem32x2, getDRegI64(rN), mkU8(index));
12106 if (isT)
12107 putIRegT(rT, e, condT);
12108 else
12109 putIRegA(rT, e, condT, Ijk_Boring);
12110 DIP("vmov%s.32 r%u, d%u[%u]\n", nCC(conq), rT, rN, index);
12111 goto decode_success_vfp;
12112 } else {
12113 /* fall through */
12114 }
12115 }
12116 }
12117
12118 // VMOV.F32 sD, #imm
12119 // FCONSTS sD, #imm
12120 if (BITS8(1,1,1,0,1,0,1,1) == (INSN(27,20) & BITS8(1,1,1,1,1,0,1,1))
12121 && BITS4(0,0,0,0) == INSN(7,4) && INSN(11,8) == BITS4(1,0,1,0)) {
12122 UInt rD = (INSN(15,12) << 1) | INSN(22,22);
12123 UInt imm8 = (INSN(19,16) << 4) | INSN(3,0);
12124 UInt b = (imm8 >> 6) & 1;
12125 UInt imm;
12126 imm = (BITS8((imm8 >> 7) & 1,(~b) & 1,b,b,b,b,b,(imm8 >> 5) & 1) << 8)
12127 | ((imm8 & 0x1f) << 3);
12128 imm <<= 16;
12129 putFReg(rD, unop(Iop_ReinterpI32asF32, mkU32(imm)), condT);
12130 DIP("fconsts%s s%u #%u", nCC(conq), rD, imm8);
12131 goto decode_success_vfp;
12132 }
12133
12134 // VMOV.F64 dD, #imm
12135 // FCONSTD dD, #imm
12136 if (BITS8(1,1,1,0,1,0,1,1) == (INSN(27,20) & BITS8(1,1,1,1,1,0,1,1))
12137 && BITS4(0,0,0,0) == INSN(7,4) && INSN(11,8) == BITS4(1,0,1,1)) {
12138 UInt rD = INSN(15,12) | (INSN(22,22) << 4);
12139 UInt imm8 = (INSN(19,16) << 4) | INSN(3,0);
12140 UInt b = (imm8 >> 6) & 1;
12141 ULong imm;
12142 imm = (BITS8((imm8 >> 7) & 1,(~b) & 1,b,b,b,b,b,b) << 8)
12143 | BITS8(b,b,0,0,0,0,0,0) | (imm8 & 0x3f);
12144 imm <<= 48;
12145 putDReg(rD, unop(Iop_ReinterpI64asF64, mkU64(imm)), condT);
12146 DIP("fconstd%s d%u #%u", nCC(conq), rD, imm8);
12147 goto decode_success_vfp;
12148 }
12149
12150 /* ---------------------- vdup ------------------------- */
12151 // VDUP dD, rT
12152 // VDUP qD, rT
12153 if (BITS8(1,1,1,0,1,0,0,0) == (INSN(27,20) & BITS8(1,1,1,1,1,0,0,1))
12154 && BITS4(1,0,1,1) == INSN(11,8) && INSN(6,6) == 0 && INSN(4,4) == 1) {
12155 UInt rD = (INSN(7,7) << 4) | INSN(19,16);
12156 UInt rT = INSN(15,12);
12157 UInt Q = INSN(21,21);
12158 UInt size = (INSN(22,22) << 1) | INSN(5,5);
sewardj4d475472011-02-02 13:35:01 +000012159 if (rT == 15 || (isT && rT == 13) || size == 3 || (Q && (rD & 1))) {
sewardjd2664472010-08-22 12:44:20 +000012160 /* fall through */
12161 } else {
12162 IRExpr* e = isT ? getIRegT(rT) : getIRegA(rT);
12163 if (Q) {
12164 rD >>= 1;
12165 switch (size) {
12166 case 0:
12167 putQReg(rD, unop(Iop_Dup32x4, e), condT);
12168 break;
12169 case 1:
12170 putQReg(rD, unop(Iop_Dup16x8, unop(Iop_32to16, e)),
12171 condT);
12172 break;
12173 case 2:
12174 putQReg(rD, unop(Iop_Dup8x16, unop(Iop_32to8, e)),
12175 condT);
12176 break;
12177 default:
12178 vassert(0);
12179 }
12180 DIP("vdup.%u q%u, r%u\n", 32 / (1<<size), rD, rT);
12181 } else {
12182 switch (size) {
12183 case 0:
12184 putDRegI64(rD, unop(Iop_Dup32x2, e), condT);
12185 break;
12186 case 1:
12187 putDRegI64(rD, unop(Iop_Dup16x4, unop(Iop_32to16, e)),
12188 condT);
12189 break;
12190 case 2:
12191 putDRegI64(rD, unop(Iop_Dup8x8, unop(Iop_32to8, e)),
12192 condT);
12193 break;
12194 default:
12195 vassert(0);
12196 }
12197 DIP("vdup.%u d%u, r%u\n", 32 / (1<<size), rD, rT);
12198 }
12199 goto decode_success_vfp;
12200 }
12201 }
12202
12203 /* --------------------- f{ld,st}d --------------------- */
12204 // FLDD, FSTD
sewardj93ba93f2010-09-22 16:15:50 +000012205 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 +000012206 && BITS4(1,0,1,1) == INSN(11,8)) {
sewardj93ba93f2010-09-22 16:15:50 +000012207 UInt dD = INSN(15,12) | (INSN(22,22) << 4);
sewardjd2664472010-08-22 12:44:20 +000012208 UInt rN = INSN(19,16);
12209 UInt offset = (insn28 & 0xFF) << 2;
12210 UInt bU = (insn28 >> 23) & 1; /* 1: +offset 0: -offset */
12211 UInt bL = (insn28 >> 20) & 1; /* 1: load 0: store */
12212 /* make unconditional */
12213 if (condT != IRTemp_INVALID) {
12214 if (isT)
12215 mk_skip_over_T32_if_cond_is_false( condT );
12216 else
12217 mk_skip_over_A32_if_cond_is_false( condT );
12218 condT = IRTemp_INVALID;
12219 }
12220 IRTemp ea = newTemp(Ity_I32);
12221 assign(ea, binop(bU ? Iop_Add32 : Iop_Sub32,
12222 align4if(isT ? getIRegT(rN) : getIRegA(rN),
12223 rN == 15),
12224 mkU32(offset)));
12225 if (bL) {
12226 putDReg(dD, loadLE(Ity_F64,mkexpr(ea)), IRTemp_INVALID);
12227 } else {
12228 storeLE(mkexpr(ea), getDReg(dD));
12229 }
12230 DIP("f%sd%s d%u, [r%u, %c#%u]\n",
12231 bL ? "ld" : "st", nCC(conq), dD, rN,
12232 bU ? '+' : '-', offset);
12233 goto decode_success_vfp;
12234 }
12235
12236 /* --------------------- dp insns (D) --------------------- */
sewardj93ba93f2010-09-22 16:15:50 +000012237 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 +000012238 && BITS4(1,0,1,1) == INSN(11,8)
sewardj93ba93f2010-09-22 16:15:50 +000012239 && BITS4(0,0,0,0) == (INSN(7,4) & BITS4(0,0,0,1))) {
12240 UInt dM = INSN(3,0) | (INSN(5,5) << 4); /* argR */
12241 UInt dD = INSN(15,12) | (INSN(22,22) << 4); /* dst/acc */
12242 UInt dN = INSN(19,16) | (INSN(7,7) << 4); /* argL */
sewardjd2664472010-08-22 12:44:20 +000012243 UInt bP = (insn28 >> 23) & 1;
12244 UInt bQ = (insn28 >> 21) & 1;
12245 UInt bR = (insn28 >> 20) & 1;
12246 UInt bS = (insn28 >> 6) & 1;
12247 UInt opc = (bP << 3) | (bQ << 2) | (bR << 1) | bS;
12248 IRExpr* rm = get_FAKE_roundingmode(); /* XXXROUNDINGFIXME */
12249 switch (opc) {
12250 case BITS4(0,0,0,0): /* MAC: d + n * m */
12251 putDReg(dD, triop(Iop_AddF64, rm,
12252 getDReg(dD),
12253 triop(Iop_MulF64, rm, getDReg(dN),
12254 getDReg(dM))),
12255 condT);
12256 DIP("fmacd%s d%u, d%u, d%u\n", nCC(conq), dD, dN, dM);
12257 goto decode_success_vfp;
sewardj93ba93f2010-09-22 16:15:50 +000012258 case BITS4(0,0,0,1): /* NMAC: d + -(n * m) */
12259 putDReg(dD, triop(Iop_AddF64, rm,
sewardjd2664472010-08-22 12:44:20 +000012260 getDReg(dD),
sewardj93ba93f2010-09-22 16:15:50 +000012261 unop(Iop_NegF64,
12262 triop(Iop_MulF64, rm, getDReg(dN),
12263 getDReg(dM)))),
sewardjd2664472010-08-22 12:44:20 +000012264 condT);
12265 DIP("fnmacd%s d%u, d%u, d%u\n", nCC(conq), dD, dN, dM);
12266 goto decode_success_vfp;
12267 case BITS4(0,0,1,0): /* MSC: - d + n * m */
12268 putDReg(dD, triop(Iop_AddF64, rm,
12269 unop(Iop_NegF64, getDReg(dD)),
12270 triop(Iop_MulF64, rm, getDReg(dN),
12271 getDReg(dM))),
12272 condT);
12273 DIP("fmscd%s d%u, d%u, d%u\n", nCC(conq), dD, dN, dM);
12274 goto decode_success_vfp;
sewardj93ba93f2010-09-22 16:15:50 +000012275 case BITS4(0,0,1,1): /* NMSC: - d + -(n * m) */
12276 putDReg(dD, triop(Iop_AddF64, rm,
sewardjd2664472010-08-22 12:44:20 +000012277 unop(Iop_NegF64, getDReg(dD)),
sewardj93ba93f2010-09-22 16:15:50 +000012278 unop(Iop_NegF64,
12279 triop(Iop_MulF64, rm, getDReg(dN),
12280 getDReg(dM)))),
sewardjd2664472010-08-22 12:44:20 +000012281 condT);
12282 DIP("fnmscd%s d%u, d%u, d%u\n", nCC(conq), dD, dN, dM);
12283 goto decode_success_vfp;
12284 case BITS4(0,1,0,0): /* MUL: n * m */
12285 putDReg(dD, triop(Iop_MulF64, rm, getDReg(dN), getDReg(dM)),
12286 condT);
12287 DIP("fmuld%s d%u, d%u, d%u\n", nCC(conq), dD, dN, dM);
12288 goto decode_success_vfp;
12289 case BITS4(0,1,0,1): /* NMUL: - n * m */
12290 putDReg(dD, unop(Iop_NegF64,
12291 triop(Iop_MulF64, rm, getDReg(dN),
12292 getDReg(dM))),
12293 condT);
12294 DIP("fnmuld%s d%u, d%u, d%u\n", nCC(conq), dD, dN, dM);
12295 goto decode_success_vfp;
12296 case BITS4(0,1,1,0): /* ADD: n + m */
12297 putDReg(dD, triop(Iop_AddF64, rm, getDReg(dN), getDReg(dM)),
12298 condT);
12299 DIP("faddd%s d%u, d%u, d%u\n", nCC(conq), dD, dN, dM);
12300 goto decode_success_vfp;
12301 case BITS4(0,1,1,1): /* SUB: n - m */
12302 putDReg(dD, triop(Iop_SubF64, rm, getDReg(dN), getDReg(dM)),
12303 condT);
12304 DIP("fsubd%s d%u, d%u, d%u\n", nCC(conq), dD, dN, dM);
12305 goto decode_success_vfp;
12306 case BITS4(1,0,0,0): /* DIV: n / m */
12307 putDReg(dD, triop(Iop_DivF64, rm, getDReg(dN), getDReg(dM)),
12308 condT);
12309 DIP("fdivd%s d%u, d%u, d%u\n", nCC(conq), dD, dN, dM);
12310 goto decode_success_vfp;
12311 default:
12312 break;
12313 }
12314 }
12315
12316 /* --------------------- compares (D) --------------------- */
12317 /* 31 27 23 19 15 11 7 3
12318 28 24 20 16 12 8 4 0
sewardj93ba93f2010-09-22 16:15:50 +000012319 FCMPD cond 1110 1D11 0100 Dd 1011 0100 Dm
12320 FCMPED cond 1110 1D11 0100 Dd 1011 1100 Dm
12321 FCMPZD cond 1110 1D11 0101 Dd 1011 0100 0000
12322 FCMPZED cond 1110 1D11 0101 Dd 1011 1100 0000
sewardjd2664472010-08-22 12:44:20 +000012323 Z N
12324
12325 Z=0 Compare Dd vs Dm and set FPSCR 31:28 accordingly
12326 Z=1 Compare Dd vs zero
12327
12328 N=1 generates Invalid Operation exn if either arg is any kind of NaN
12329 N=0 generates Invalid Operation exn if either arg is a signalling NaN
12330 (Not that we pay any attention to N here)
12331 */
sewardj93ba93f2010-09-22 16:15:50 +000012332 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 +000012333 && BITS4(0,1,0,0) == (INSN(19,16) & BITS4(1,1,1,0))
12334 && BITS4(1,0,1,1) == INSN(11,8)
sewardj93ba93f2010-09-22 16:15:50 +000012335 && BITS4(0,1,0,0) == (INSN(7,4) & BITS4(0,1,0,1))) {
sewardjd2664472010-08-22 12:44:20 +000012336 UInt bZ = (insn28 >> 16) & 1;
12337 UInt bN = (insn28 >> 7) & 1;
sewardj93ba93f2010-09-22 16:15:50 +000012338 UInt dD = INSN(15,12) | (INSN(22,22) << 4);
12339 UInt dM = INSN(3,0) | (INSN(5,5) << 4);
sewardjd2664472010-08-22 12:44:20 +000012340 if (bZ && INSN(3,0) != 0) {
12341 /* does not decode; fall through */
12342 } else {
12343 IRTemp argL = newTemp(Ity_F64);
12344 IRTemp argR = newTemp(Ity_F64);
12345 IRTemp irRes = newTemp(Ity_I32);
12346 assign(argL, getDReg(dD));
12347 assign(argR, bZ ? IRExpr_Const(IRConst_F64i(0)) : getDReg(dM));
12348 assign(irRes, binop(Iop_CmpF64, mkexpr(argL), mkexpr(argR)));
12349
12350 IRTemp nzcv = IRTemp_INVALID;
12351 IRTemp oldFPSCR = newTemp(Ity_I32);
12352 IRTemp newFPSCR = newTemp(Ity_I32);
12353
12354 /* This is where the fun starts. We have to convert 'irRes'
12355 from an IR-convention return result (IRCmpF64Result) to an
12356 ARM-encoded (N,Z,C,V) group. The final result is in the
12357 bottom 4 bits of 'nzcv'. */
12358 /* Map compare result from IR to ARM(nzcv) */
12359 /*
12360 FP cmp result | IR | ARM(nzcv)
12361 --------------------------------
12362 UN 0x45 0011
12363 LT 0x01 1000
12364 GT 0x00 0010
12365 EQ 0x40 0110
12366 */
12367 nzcv = mk_convert_IRCmpF64Result_to_NZCV(irRes);
12368
12369 /* And update FPSCR accordingly */
12370 assign(oldFPSCR, IRExpr_Get(OFFB_FPSCR, Ity_I32));
12371 assign(newFPSCR,
12372 binop(Iop_Or32,
12373 binop(Iop_And32, mkexpr(oldFPSCR), mkU32(0x0FFFFFFF)),
12374 binop(Iop_Shl32, mkexpr(nzcv), mkU8(28))));
12375
12376 putMiscReg32(OFFB_FPSCR, mkexpr(newFPSCR), condT);
12377
12378 if (bZ) {
12379 DIP("fcmpz%sd%s d%u\n", bN ? "e" : "", nCC(conq), dD);
12380 } else {
12381 DIP("fcmp%sd%s d%u, d%u\n", bN ? "e" : "", nCC(conq), dD, dM);
12382 }
12383 goto decode_success_vfp;
12384 }
12385 /* fall through */
12386 }
12387
12388 /* --------------------- unary (D) --------------------- */
sewardj93ba93f2010-09-22 16:15:50 +000012389 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 +000012390 && BITS4(0,0,0,0) == (INSN(19,16) & BITS4(1,1,1,0))
12391 && BITS4(1,0,1,1) == INSN(11,8)
sewardj93ba93f2010-09-22 16:15:50 +000012392 && BITS4(0,1,0,0) == (INSN(7,4) & BITS4(0,1,0,1))) {
12393 UInt dD = INSN(15,12) | (INSN(22,22) << 4);
12394 UInt dM = INSN(3,0) | (INSN(5,5) << 4);
sewardjd2664472010-08-22 12:44:20 +000012395 UInt b16 = (insn28 >> 16) & 1;
12396 UInt b7 = (insn28 >> 7) & 1;
12397 /**/ if (b16 == 0 && b7 == 0) {
12398 // FCPYD
12399 putDReg(dD, getDReg(dM), condT);
12400 DIP("fcpyd%s d%u, d%u\n", nCC(conq), dD, dM);
12401 goto decode_success_vfp;
12402 }
12403 else if (b16 == 0 && b7 == 1) {
12404 // FABSD
12405 putDReg(dD, unop(Iop_AbsF64, getDReg(dM)), condT);
12406 DIP("fabsd%s d%u, d%u\n", nCC(conq), dD, dM);
12407 goto decode_success_vfp;
12408 }
12409 else if (b16 == 1 && b7 == 0) {
12410 // FNEGD
12411 putDReg(dD, unop(Iop_NegF64, getDReg(dM)), condT);
12412 DIP("fnegd%s d%u, d%u\n", nCC(conq), dD, dM);
12413 goto decode_success_vfp;
12414 }
12415 else if (b16 == 1 && b7 == 1) {
12416 // FSQRTD
12417 IRExpr* rm = get_FAKE_roundingmode(); /* XXXROUNDINGFIXME */
12418 putDReg(dD, binop(Iop_SqrtF64, rm, getDReg(dM)), condT);
12419 DIP("fsqrtd%s d%u, d%u\n", nCC(conq), dD, dM);
12420 goto decode_success_vfp;
12421 }
12422 else
12423 vassert(0);
12424
12425 /* fall through */
12426 }
12427
12428 /* ----------------- I <-> D conversions ----------------- */
12429
12430 // F{S,U}ITOD dD, fM
sewardj93ba93f2010-09-22 16:15:50 +000012431 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 +000012432 && BITS4(1,0,0,0) == (INSN(19,16) & BITS4(1,1,1,1))
12433 && BITS4(1,0,1,1) == INSN(11,8)
12434 && BITS4(0,1,0,0) == (INSN(7,4) & BITS4(0,1,0,1))) {
12435 UInt bM = (insn28 >> 5) & 1;
12436 UInt fM = (INSN(3,0) << 1) | bM;
sewardj93ba93f2010-09-22 16:15:50 +000012437 UInt dD = INSN(15,12) | (INSN(22,22) << 4);
sewardjd2664472010-08-22 12:44:20 +000012438 UInt syned = (insn28 >> 7) & 1;
12439 if (syned) {
12440 // FSITOD
12441 putDReg(dD, unop(Iop_I32StoF64,
12442 unop(Iop_ReinterpF32asI32, getFReg(fM))),
12443 condT);
12444 DIP("fsitod%s d%u, s%u\n", nCC(conq), dD, fM);
12445 } else {
12446 // FUITOD
12447 putDReg(dD, unop(Iop_I32UtoF64,
12448 unop(Iop_ReinterpF32asI32, getFReg(fM))),
12449 condT);
12450 DIP("fuitod%s d%u, s%u\n", nCC(conq), dD, fM);
12451 }
12452 goto decode_success_vfp;
12453 }
12454
12455 // FTO{S,U}ID fD, dM
12456 if (BITS8(1,1,1,0,1,0,1,1) == (INSN(27,20) & BITS8(1,1,1,1,1,0,1,1))
12457 && BITS4(1,1,0,0) == (INSN(19,16) & BITS4(1,1,1,0))
12458 && BITS4(1,0,1,1) == INSN(11,8)
sewardj93ba93f2010-09-22 16:15:50 +000012459 && BITS4(0,1,0,0) == (INSN(7,4) & BITS4(0,1,0,1))) {
sewardjd2664472010-08-22 12:44:20 +000012460 UInt bD = (insn28 >> 22) & 1;
12461 UInt fD = (INSN(15,12) << 1) | bD;
sewardj93ba93f2010-09-22 16:15:50 +000012462 UInt dM = INSN(3,0) | (INSN(5,5) << 4);
sewardjd2664472010-08-22 12:44:20 +000012463 UInt bZ = (insn28 >> 7) & 1;
12464 UInt syned = (insn28 >> 16) & 1;
12465 IRTemp rmode = newTemp(Ity_I32);
12466 assign(rmode, bZ ? mkU32(Irrm_ZERO)
12467 : mkexpr(mk_get_IR_rounding_mode()));
12468 if (syned) {
12469 // FTOSID
12470 putFReg(fD, unop(Iop_ReinterpI32asF32,
12471 binop(Iop_F64toI32S, mkexpr(rmode),
12472 getDReg(dM))),
12473 condT);
12474 DIP("ftosi%sd%s s%u, d%u\n", bZ ? "z" : "",
12475 nCC(conq), fD, dM);
12476 } else {
12477 // FTOUID
12478 putFReg(fD, unop(Iop_ReinterpI32asF32,
12479 binop(Iop_F64toI32U, mkexpr(rmode),
12480 getDReg(dM))),
12481 condT);
12482 DIP("ftoui%sd%s s%u, d%u\n", bZ ? "z" : "",
12483 nCC(conq), fD, dM);
12484 }
12485 goto decode_success_vfp;
12486 }
12487
12488 /* ----------------------------------------------------------- */
12489 /* -- VFP instructions -- single precision -- */
12490 /* ----------------------------------------------------------- */
12491
12492 /* --------------------- fldms, fstms --------------------- */
12493 /*
12494 31 27 23 19 15 11 7 0
12495 P UDWL
12496 C4-98, C5-26 1 FSTMD cond 1100 1x00 Rn Fd 1010 offset
12497 C4-98, C5-28 2 FSTMDIA cond 1100 1x10 Rn Fd 1010 offset
12498 C4-98, C5-30 3 FSTMDDB cond 1101 0x10 Rn Fd 1010 offset
12499
12500 C4-40, C5-26 1 FLDMD cond 1100 1x01 Rn Fd 1010 offset
12501 C4-40, C5-26 2 FLDMIAD cond 1100 1x11 Rn Fd 1010 offset
12502 C4-40, C5-26 3 FLDMDBD cond 1101 0x11 Rn Fd 1010 offset
12503
12504 Regs transferred: F(Fd:D) .. F(Fd:d + offset)
12505 offset must not imply a reg > 15
12506 IA/DB: Rn is changed by (4 x # regs transferred)
12507
12508 case coding:
12509 1 at-Rn (access at Rn)
12510 2 ia-Rn (access at Rn, then Rn += 4n)
12511 3 db-Rn (Rn -= 4n, then access at Rn)
12512 */
12513 if (BITS8(1,1,0,0,0,0,0,0) == (INSN(27,20) & BITS8(1,1,1,0,0,0,0,0))
12514 && INSN(11,8) == BITS4(1,0,1,0)) {
12515 UInt bP = (insn28 >> 24) & 1;
12516 UInt bU = (insn28 >> 23) & 1;
12517 UInt bW = (insn28 >> 21) & 1;
12518 UInt bL = (insn28 >> 20) & 1;
12519 UInt bD = (insn28 >> 22) & 1;
12520 UInt offset = (insn28 >> 0) & 0xFF;
12521 UInt rN = INSN(19,16);
12522 UInt fD = (INSN(15,12) << 1) | bD;
12523 UInt nRegs = offset;
12524 UInt summary = 0;
12525 Int i;
12526
12527 /**/ if (bP == 0 && bU == 1 && bW == 0) {
12528 summary = 1;
12529 }
12530 else if (bP == 0 && bU == 1 && bW == 1) {
12531 summary = 2;
12532 }
12533 else if (bP == 1 && bU == 0 && bW == 1) {
12534 summary = 3;
12535 }
12536 else goto after_vfp_fldms_fstms;
12537
12538 /* no writebacks to r15 allowed. No use of r15 in thumb mode. */
12539 if (rN == 15 && (summary == 2 || summary == 3 || isT))
12540 goto after_vfp_fldms_fstms;
12541
12542 /* offset must specify at least one register */
12543 if (offset < 1)
12544 goto after_vfp_fldms_fstms;
12545
12546 /* can't transfer regs after S31 */
12547 if (fD + nRegs - 1 >= 32)
12548 goto after_vfp_fldms_fstms;
12549
12550 /* Now, we can't do a conditional load or store, since that very
12551 likely will generate an exception. So we have to take a side
12552 exit at this point if the condition is false. */
12553 if (condT != IRTemp_INVALID) {
12554 if (isT)
12555 mk_skip_over_T32_if_cond_is_false( condT );
12556 else
12557 mk_skip_over_A32_if_cond_is_false( condT );
12558 condT = IRTemp_INVALID;
12559 }
12560 /* Ok, now we're unconditional. Do the load or store. */
12561
12562 /* get the old Rn value */
12563 IRTemp rnT = newTemp(Ity_I32);
12564 assign(rnT, align4if(isT ? getIRegT(rN) : getIRegA(rN),
12565 rN == 15));
12566
12567 /* make a new value for Rn, post-insn */
12568 IRTemp rnTnew = IRTemp_INVALID;
12569 if (summary == 2 || summary == 3) {
12570 rnTnew = newTemp(Ity_I32);
12571 assign(rnTnew, binop(summary == 2 ? Iop_Add32 : Iop_Sub32,
12572 mkexpr(rnT),
12573 mkU32(4 * nRegs)));
12574 }
12575
12576 /* decide on the base transfer address */
12577 IRTemp taT = newTemp(Ity_I32);
12578 assign(taT, summary == 3 ? mkexpr(rnTnew) : mkexpr(rnT));
12579
12580 /* update Rn if necessary -- in case 3, we're moving it down, so
12581 update before any memory reference, in order to keep Memcheck
12582 and V's stack-extending logic (on linux) happy */
12583 if (summary == 3) {
12584 if (isT)
12585 putIRegT(rN, mkexpr(rnTnew), IRTemp_INVALID);
12586 else
12587 putIRegA(rN, mkexpr(rnTnew), IRTemp_INVALID, Ijk_Boring);
12588 }
12589
12590 /* generate the transfers */
12591 for (i = 0; i < nRegs; i++) {
12592 IRExpr* addr = binop(Iop_Add32, mkexpr(taT), mkU32(4*i));
12593 if (bL) {
12594 putFReg(fD + i, loadLE(Ity_F32, addr), IRTemp_INVALID);
12595 } else {
12596 storeLE(addr, getFReg(fD + i));
12597 }
12598 }
12599
12600 /* update Rn if necessary -- in case 2, we're moving it up, so
12601 update after any memory reference, in order to keep Memcheck
12602 and V's stack-extending logic (on linux) happy */
12603 if (summary == 2) {
12604 if (isT)
12605 putIRegT(rN, mkexpr(rnTnew), IRTemp_INVALID);
12606 else
12607 putIRegA(rN, mkexpr(rnTnew), IRTemp_INVALID, Ijk_Boring);
12608 }
12609
florian55085f82012-11-21 00:36:55 +000012610 const HChar* nm = bL==1 ? "ld" : "st";
sewardjd2664472010-08-22 12:44:20 +000012611 switch (summary) {
12612 case 1: DIP("f%sms%s r%u, {s%u-s%u}\n",
12613 nm, nCC(conq), rN, fD, fD + nRegs - 1);
12614 break;
12615 case 2: DIP("f%smias%s r%u!, {s%u-s%u}\n",
12616 nm, nCC(conq), rN, fD, fD + nRegs - 1);
12617 break;
12618 case 3: DIP("f%smdbs%s r%u!, {s%u-s%u}\n",
12619 nm, nCC(conq), rN, fD, fD + nRegs - 1);
12620 break;
12621 default: vassert(0);
12622 }
12623
12624 goto decode_success_vfp;
12625 /* FIXME alignment constraints? */
12626 }
12627
12628 after_vfp_fldms_fstms:
12629
12630 /* --------------------- fmsr, fmrs --------------------- */
12631 if (BITS8(1,1,1,0,0,0,0,0) == (INSN(27,20) & BITS8(1,1,1,1,1,1,1,0))
12632 && BITS4(1,0,1,0) == INSN(11,8)
12633 && BITS4(0,0,0,0) == INSN(3,0)
12634 && BITS4(0,0,0,1) == (INSN(7,4) & BITS4(0,1,1,1))) {
12635 UInt rD = INSN(15,12);
12636 UInt b7 = (insn28 >> 7) & 1;
12637 UInt fN = (INSN(19,16) << 1) | b7;
12638 UInt b20 = (insn28 >> 20) & 1;
12639 if (rD == 15) {
12640 /* fall through */
12641 /* Let's assume that no sane person would want to do
12642 floating-point transfers to or from the program counter,
12643 and simply decline to decode the instruction. The ARM ARM
12644 doesn't seem to explicitly disallow this case, though. */
12645 } else {
12646 if (b20) {
12647 IRExpr* res = unop(Iop_ReinterpF32asI32, getFReg(fN));
12648 if (isT)
12649 putIRegT(rD, res, condT);
12650 else
12651 putIRegA(rD, res, condT, Ijk_Boring);
12652 DIP("fmrs%s r%u, s%u\n", nCC(conq), rD, fN);
12653 } else {
12654 putFReg(fN, unop(Iop_ReinterpI32asF32,
12655 isT ? getIRegT(rD) : getIRegA(rD)),
12656 condT);
12657 DIP("fmsr%s s%u, r%u\n", nCC(conq), fN, rD);
12658 }
12659 goto decode_success_vfp;
12660 }
12661 /* fall through */
12662 }
12663
12664 /* --------------------- f{ld,st}s --------------------- */
12665 // FLDS, FSTS
12666 if (BITS8(1,1,0,1,0,0,0,0) == (INSN(27,20) & BITS8(1,1,1,1,0,0,1,0))
12667 && BITS4(1,0,1,0) == INSN(11,8)) {
12668 UInt bD = (insn28 >> 22) & 1;
12669 UInt fD = (INSN(15,12) << 1) | bD;
12670 UInt rN = INSN(19,16);
12671 UInt offset = (insn28 & 0xFF) << 2;
12672 UInt bU = (insn28 >> 23) & 1; /* 1: +offset 0: -offset */
12673 UInt bL = (insn28 >> 20) & 1; /* 1: load 0: store */
12674 /* make unconditional */
12675 if (condT != IRTemp_INVALID) {
12676 if (isT)
12677 mk_skip_over_T32_if_cond_is_false( condT );
12678 else
12679 mk_skip_over_A32_if_cond_is_false( condT );
12680 condT = IRTemp_INVALID;
12681 }
12682 IRTemp ea = newTemp(Ity_I32);
12683 assign(ea, binop(bU ? Iop_Add32 : Iop_Sub32,
12684 align4if(isT ? getIRegT(rN) : getIRegA(rN),
12685 rN == 15),
12686 mkU32(offset)));
12687 if (bL) {
12688 putFReg(fD, loadLE(Ity_F32,mkexpr(ea)), IRTemp_INVALID);
12689 } else {
12690 storeLE(mkexpr(ea), getFReg(fD));
12691 }
12692 DIP("f%ss%s s%u, [r%u, %c#%u]\n",
12693 bL ? "ld" : "st", nCC(conq), fD, rN,
12694 bU ? '+' : '-', offset);
12695 goto decode_success_vfp;
12696 }
12697
12698 /* --------------------- dp insns (F) --------------------- */
12699 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 +000012700 && BITS4(1,0,1,0) == (INSN(11,8) & BITS4(1,1,1,0))
sewardjd2664472010-08-22 12:44:20 +000012701 && BITS4(0,0,0,0) == (INSN(7,4) & BITS4(0,0,0,1))) {
12702 UInt bM = (insn28 >> 5) & 1;
12703 UInt bD = (insn28 >> 22) & 1;
12704 UInt bN = (insn28 >> 7) & 1;
12705 UInt fM = (INSN(3,0) << 1) | bM; /* argR */
12706 UInt fD = (INSN(15,12) << 1) | bD; /* dst/acc */
12707 UInt fN = (INSN(19,16) << 1) | bN; /* argL */
12708 UInt bP = (insn28 >> 23) & 1;
12709 UInt bQ = (insn28 >> 21) & 1;
12710 UInt bR = (insn28 >> 20) & 1;
12711 UInt bS = (insn28 >> 6) & 1;
12712 UInt opc = (bP << 3) | (bQ << 2) | (bR << 1) | bS;
12713 IRExpr* rm = get_FAKE_roundingmode(); /* XXXROUNDINGFIXME */
12714 switch (opc) {
12715 case BITS4(0,0,0,0): /* MAC: d + n * m */
12716 putFReg(fD, triop(Iop_AddF32, rm,
12717 getFReg(fD),
12718 triop(Iop_MulF32, rm, getFReg(fN), getFReg(fM))),
12719 condT);
12720 DIP("fmacs%s s%u, s%u, s%u\n", nCC(conq), fD, fN, fM);
12721 goto decode_success_vfp;
sewardj93ba93f2010-09-22 16:15:50 +000012722 case BITS4(0,0,0,1): /* NMAC: d + -(n * m) */
12723 putFReg(fD, triop(Iop_AddF32, rm,
sewardjd2664472010-08-22 12:44:20 +000012724 getFReg(fD),
sewardj93ba93f2010-09-22 16:15:50 +000012725 unop(Iop_NegF32,
12726 triop(Iop_MulF32, rm, getFReg(fN),
12727 getFReg(fM)))),
sewardjd2664472010-08-22 12:44:20 +000012728 condT);
12729 DIP("fnmacs%s s%u, s%u, s%u\n", nCC(conq), fD, fN, fM);
12730 goto decode_success_vfp;
12731 case BITS4(0,0,1,0): /* MSC: - d + n * m */
12732 putFReg(fD, triop(Iop_AddF32, rm,
12733 unop(Iop_NegF32, getFReg(fD)),
12734 triop(Iop_MulF32, rm, getFReg(fN), getFReg(fM))),
12735 condT);
12736 DIP("fmscs%s s%u, s%u, s%u\n", nCC(conq), fD, fN, fM);
12737 goto decode_success_vfp;
sewardj93ba93f2010-09-22 16:15:50 +000012738 case BITS4(0,0,1,1): /* NMSC: - d + -(n * m) */
12739 putFReg(fD, triop(Iop_AddF32, rm,
12740 unop(Iop_NegF32, getFReg(fD)),
12741 unop(Iop_NegF32,
12742 triop(Iop_MulF32, rm,
12743 getFReg(fN),
12744 getFReg(fM)))),
12745 condT);
12746 DIP("fnmscs%s s%u, s%u, s%u\n", nCC(conq), fD, fN, fM);
12747 goto decode_success_vfp;
sewardjd2664472010-08-22 12:44:20 +000012748 case BITS4(0,1,0,0): /* MUL: n * m */
12749 putFReg(fD, triop(Iop_MulF32, rm, getFReg(fN), getFReg(fM)),
12750 condT);
12751 DIP("fmuls%s s%u, s%u, s%u\n", nCC(conq), fD, fN, fM);
12752 goto decode_success_vfp;
12753 case BITS4(0,1,0,1): /* NMUL: - n * m */
12754 putFReg(fD, unop(Iop_NegF32,
12755 triop(Iop_MulF32, rm, getFReg(fN),
12756 getFReg(fM))),
12757 condT);
12758 DIP("fnmuls%s s%u, s%u, s%u\n", nCC(conq), fD, fN, fM);
12759 goto decode_success_vfp;
12760 case BITS4(0,1,1,0): /* ADD: n + m */
12761 putFReg(fD, triop(Iop_AddF32, rm, getFReg(fN), getFReg(fM)),
12762 condT);
12763 DIP("fadds%s s%u, s%u, s%u\n", nCC(conq), fD, fN, fM);
12764 goto decode_success_vfp;
12765 case BITS4(0,1,1,1): /* SUB: n - m */
12766 putFReg(fD, triop(Iop_SubF32, rm, getFReg(fN), getFReg(fM)),
12767 condT);
12768 DIP("fsubs%s s%u, s%u, s%u\n", nCC(conq), fD, fN, fM);
12769 goto decode_success_vfp;
12770 case BITS4(1,0,0,0): /* DIV: n / m */
12771 putFReg(fD, triop(Iop_DivF32, rm, getFReg(fN), getFReg(fM)),
12772 condT);
12773 DIP("fdivs%s s%u, s%u, s%u\n", nCC(conq), fD, fN, fM);
12774 goto decode_success_vfp;
12775 default:
12776 break;
12777 }
12778 }
12779
12780 /* --------------------- compares (S) --------------------- */
12781 /* 31 27 23 19 15 11 7 3
12782 28 24 20 16 12 8 4 0
12783 FCMPS cond 1110 1D11 0100 Fd 1010 01M0 Fm
12784 FCMPES cond 1110 1D11 0100 Fd 1010 11M0 Fm
12785 FCMPZS cond 1110 1D11 0101 Fd 1010 0100 0000
12786 FCMPZED cond 1110 1D11 0101 Fd 1010 1100 0000
12787 Z N
12788
12789 Z=0 Compare Fd:D vs Fm:M and set FPSCR 31:28 accordingly
12790 Z=1 Compare Fd:D vs zero
12791
12792 N=1 generates Invalid Operation exn if either arg is any kind of NaN
12793 N=0 generates Invalid Operation exn if either arg is a signalling NaN
12794 (Not that we pay any attention to N here)
12795 */
12796 if (BITS8(1,1,1,0,1,0,1,1) == (INSN(27,20) & BITS8(1,1,1,1,1,0,1,1))
12797 && BITS4(0,1,0,0) == (INSN(19,16) & BITS4(1,1,1,0))
12798 && BITS4(1,0,1,0) == INSN(11,8)
12799 && BITS4(0,1,0,0) == (INSN(7,4) & BITS4(0,1,0,1))) {
12800 UInt bZ = (insn28 >> 16) & 1;
12801 UInt bN = (insn28 >> 7) & 1;
12802 UInt bD = (insn28 >> 22) & 1;
12803 UInt bM = (insn28 >> 5) & 1;
12804 UInt fD = (INSN(15,12) << 1) | bD;
12805 UInt fM = (INSN(3,0) << 1) | bM;
12806 if (bZ && (INSN(3,0) != 0 || (INSN(7,4) & 3) != 0)) {
12807 /* does not decode; fall through */
12808 } else {
12809 IRTemp argL = newTemp(Ity_F64);
12810 IRTemp argR = newTemp(Ity_F64);
12811 IRTemp irRes = newTemp(Ity_I32);
12812
12813 assign(argL, unop(Iop_F32toF64, getFReg(fD)));
12814 assign(argR, bZ ? IRExpr_Const(IRConst_F64i(0))
12815 : unop(Iop_F32toF64, getFReg(fM)));
12816 assign(irRes, binop(Iop_CmpF64, mkexpr(argL), mkexpr(argR)));
12817
12818 IRTemp nzcv = IRTemp_INVALID;
12819 IRTemp oldFPSCR = newTemp(Ity_I32);
12820 IRTemp newFPSCR = newTemp(Ity_I32);
12821
12822 /* This is where the fun starts. We have to convert 'irRes'
12823 from an IR-convention return result (IRCmpF64Result) to an
12824 ARM-encoded (N,Z,C,V) group. The final result is in the
12825 bottom 4 bits of 'nzcv'. */
12826 /* Map compare result from IR to ARM(nzcv) */
12827 /*
12828 FP cmp result | IR | ARM(nzcv)
12829 --------------------------------
12830 UN 0x45 0011
12831 LT 0x01 1000
12832 GT 0x00 0010
12833 EQ 0x40 0110
12834 */
12835 nzcv = mk_convert_IRCmpF64Result_to_NZCV(irRes);
12836
12837 /* And update FPSCR accordingly */
12838 assign(oldFPSCR, IRExpr_Get(OFFB_FPSCR, Ity_I32));
12839 assign(newFPSCR,
12840 binop(Iop_Or32,
12841 binop(Iop_And32, mkexpr(oldFPSCR), mkU32(0x0FFFFFFF)),
12842 binop(Iop_Shl32, mkexpr(nzcv), mkU8(28))));
12843
12844 putMiscReg32(OFFB_FPSCR, mkexpr(newFPSCR), condT);
12845
12846 if (bZ) {
12847 DIP("fcmpz%ss%s s%u\n", bN ? "e" : "", nCC(conq), fD);
12848 } else {
12849 DIP("fcmp%ss%s s%u, s%u\n", bN ? "e" : "",
12850 nCC(conq), fD, fM);
12851 }
12852 goto decode_success_vfp;
12853 }
12854 /* fall through */
12855 }
12856
12857 /* --------------------- unary (S) --------------------- */
12858 if (BITS8(1,1,1,0,1,0,1,1) == (INSN(27,20) & BITS8(1,1,1,1,1,0,1,1))
12859 && BITS4(0,0,0,0) == (INSN(19,16) & BITS4(1,1,1,0))
12860 && BITS4(1,0,1,0) == INSN(11,8)
12861 && BITS4(0,1,0,0) == (INSN(7,4) & BITS4(0,1,0,1))) {
12862 UInt bD = (insn28 >> 22) & 1;
12863 UInt bM = (insn28 >> 5) & 1;
12864 UInt fD = (INSN(15,12) << 1) | bD;
12865 UInt fM = (INSN(3,0) << 1) | bM;
12866 UInt b16 = (insn28 >> 16) & 1;
12867 UInt b7 = (insn28 >> 7) & 1;
12868 /**/ if (b16 == 0 && b7 == 0) {
12869 // FCPYS
12870 putFReg(fD, getFReg(fM), condT);
12871 DIP("fcpys%s s%u, s%u\n", nCC(conq), fD, fM);
12872 goto decode_success_vfp;
12873 }
12874 else if (b16 == 0 && b7 == 1) {
12875 // FABSS
12876 putFReg(fD, unop(Iop_AbsF32, getFReg(fM)), condT);
12877 DIP("fabss%s s%u, s%u\n", nCC(conq), fD, fM);
12878 goto decode_success_vfp;
12879 }
12880 else if (b16 == 1 && b7 == 0) {
12881 // FNEGS
12882 putFReg(fD, unop(Iop_NegF32, getFReg(fM)), condT);
12883 DIP("fnegs%s s%u, s%u\n", nCC(conq), fD, fM);
12884 goto decode_success_vfp;
12885 }
12886 else if (b16 == 1 && b7 == 1) {
12887 // FSQRTS
12888 IRExpr* rm = get_FAKE_roundingmode(); /* XXXROUNDINGFIXME */
12889 putFReg(fD, binop(Iop_SqrtF32, rm, getFReg(fM)), condT);
12890 DIP("fsqrts%s s%u, s%u\n", nCC(conq), fD, fM);
12891 goto decode_success_vfp;
12892 }
12893 else
12894 vassert(0);
12895
12896 /* fall through */
12897 }
12898
12899 /* ----------------- I <-> S conversions ----------------- */
12900
12901 // F{S,U}ITOS fD, fM
12902 /* These are more complex than FSITOD/FUITOD. In the D cases, a 32
12903 bit int will always fit within the 53 bit mantissa, so there's
12904 no possibility of a loss of precision, but that's obviously not
12905 the case here. Hence this case possibly requires rounding, and
12906 so it drags in the current rounding mode. */
12907 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 +000012908 && BITS4(1,0,0,0) == INSN(19,16)
12909 && BITS4(1,0,1,0) == (INSN(11,8) & BITS4(1,1,1,0))
sewardjd2664472010-08-22 12:44:20 +000012910 && BITS4(0,1,0,0) == (INSN(7,4) & BITS4(0,1,0,1))) {
12911 UInt bM = (insn28 >> 5) & 1;
12912 UInt bD = (insn28 >> 22) & 1;
12913 UInt fM = (INSN(3,0) << 1) | bM;
12914 UInt fD = (INSN(15,12) << 1) | bD;
12915 UInt syned = (insn28 >> 7) & 1;
12916 IRTemp rmode = newTemp(Ity_I32);
12917 assign(rmode, mkexpr(mk_get_IR_rounding_mode()));
12918 if (syned) {
12919 // FSITOS
12920 putFReg(fD, binop(Iop_F64toF32,
12921 mkexpr(rmode),
12922 unop(Iop_I32StoF64,
12923 unop(Iop_ReinterpF32asI32, getFReg(fM)))),
12924 condT);
12925 DIP("fsitos%s s%u, s%u\n", nCC(conq), fD, fM);
12926 } else {
12927 // FUITOS
12928 putFReg(fD, binop(Iop_F64toF32,
12929 mkexpr(rmode),
12930 unop(Iop_I32UtoF64,
12931 unop(Iop_ReinterpF32asI32, getFReg(fM)))),
12932 condT);
12933 DIP("fuitos%s s%u, s%u\n", nCC(conq), fD, fM);
12934 }
12935 goto decode_success_vfp;
12936 }
12937
12938 // FTO{S,U}IS fD, fM
12939 if (BITS8(1,1,1,0,1,0,1,1) == (INSN(27,20) & BITS8(1,1,1,1,1,0,1,1))
12940 && BITS4(1,1,0,0) == (INSN(19,16) & BITS4(1,1,1,0))
12941 && BITS4(1,0,1,0) == INSN(11,8)
12942 && BITS4(0,1,0,0) == (INSN(7,4) & BITS4(0,1,0,1))) {
12943 UInt bM = (insn28 >> 5) & 1;
12944 UInt bD = (insn28 >> 22) & 1;
12945 UInt fD = (INSN(15,12) << 1) | bD;
12946 UInt fM = (INSN(3,0) << 1) | bM;
12947 UInt bZ = (insn28 >> 7) & 1;
12948 UInt syned = (insn28 >> 16) & 1;
12949 IRTemp rmode = newTemp(Ity_I32);
12950 assign(rmode, bZ ? mkU32(Irrm_ZERO)
12951 : mkexpr(mk_get_IR_rounding_mode()));
12952 if (syned) {
12953 // FTOSIS
12954 putFReg(fD, unop(Iop_ReinterpI32asF32,
12955 binop(Iop_F64toI32S, mkexpr(rmode),
12956 unop(Iop_F32toF64, getFReg(fM)))),
12957 condT);
12958 DIP("ftosi%ss%s s%u, d%u\n", bZ ? "z" : "",
12959 nCC(conq), fD, fM);
12960 goto decode_success_vfp;
12961 } else {
12962 // FTOUIS
12963 putFReg(fD, unop(Iop_ReinterpI32asF32,
12964 binop(Iop_F64toI32U, mkexpr(rmode),
12965 unop(Iop_F32toF64, getFReg(fM)))),
12966 condT);
12967 DIP("ftoui%ss%s s%u, d%u\n", bZ ? "z" : "",
12968 nCC(conq), fD, fM);
12969 goto decode_success_vfp;
12970 }
12971 }
12972
12973 /* ----------------- S <-> D conversions ----------------- */
12974
12975 // FCVTDS
sewardj93ba93f2010-09-22 16:15:50 +000012976 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 +000012977 && BITS4(0,1,1,1) == INSN(19,16)
12978 && BITS4(1,0,1,0) == INSN(11,8)
12979 && BITS4(1,1,0,0) == (INSN(7,4) & BITS4(1,1,0,1))) {
sewardj93ba93f2010-09-22 16:15:50 +000012980 UInt dD = INSN(15,12) | (INSN(22,22) << 4);
sewardjd2664472010-08-22 12:44:20 +000012981 UInt bM = (insn28 >> 5) & 1;
12982 UInt fM = (INSN(3,0) << 1) | bM;
12983 putDReg(dD, unop(Iop_F32toF64, getFReg(fM)), condT);
12984 DIP("fcvtds%s d%u, s%u\n", nCC(conq), dD, fM);
12985 goto decode_success_vfp;
12986 }
12987
12988 // FCVTSD
12989 if (BITS8(1,1,1,0,1,0,1,1) == (INSN(27,20) & BITS8(1,1,1,1,1,0,1,1))
12990 && BITS4(0,1,1,1) == INSN(19,16)
12991 && BITS4(1,0,1,1) == INSN(11,8)
sewardj93ba93f2010-09-22 16:15:50 +000012992 && BITS4(1,1,0,0) == (INSN(7,4) & BITS4(1,1,0,1))) {
sewardjd2664472010-08-22 12:44:20 +000012993 UInt bD = (insn28 >> 22) & 1;
12994 UInt fD = (INSN(15,12) << 1) | bD;
sewardj93ba93f2010-09-22 16:15:50 +000012995 UInt dM = INSN(3,0) | (INSN(5,5) << 4);
sewardjd2664472010-08-22 12:44:20 +000012996 IRTemp rmode = newTemp(Ity_I32);
12997 assign(rmode, mkexpr(mk_get_IR_rounding_mode()));
12998 putFReg(fD, binop(Iop_F64toF32, mkexpr(rmode), getDReg(dM)),
12999 condT);
13000 DIP("fcvtsd%s s%u, d%u\n", nCC(conq), fD, dM);
13001 goto decode_success_vfp;
13002 }
13003
sewardj9fe0cc72012-08-01 20:05:42 +000013004 /* --------------- VCVT fixed<->floating, VFP --------------- */
13005 /* 31 27 23 19 15 11 7 3
13006 28 24 20 16 12 8 4 0
13007
13008 cond 1110 1D11 1p1U Vd 101f x1i0 imm4
13009
13010 VCVT<c>.<Td>.F64 <Dd>, <Dd>, #fbits
13011 VCVT<c>.<Td>.F32 <Dd>, <Dd>, #fbits
13012 VCVT<c>.F64.<Td> <Dd>, <Dd>, #fbits
13013 VCVT<c>.F32.<Td> <Dd>, <Dd>, #fbits
13014 are of this form. We only handle a subset of the cases though.
13015 */
13016 if (BITS8(1,1,1,0,1,0,1,1) == (INSN(27,20) & BITS8(1,1,1,1,1,0,1,1))
13017 && BITS4(1,0,1,0) == (INSN(19,16) & BITS4(1,0,1,0))
13018 && BITS3(1,0,1) == INSN(11,9)
13019 && BITS3(1,0,0) == (INSN(6,4) & BITS3(1,0,1))) {
sewardj6b7bdec2013-03-05 14:26:22 +000013020 UInt bD = INSN(22,22);
13021 UInt bOP = INSN(18,18);
13022 UInt bU = INSN(16,16);
13023 UInt Vd = INSN(15,12);
13024 UInt bSF = INSN(8,8);
13025 UInt bSX = INSN(7,7);
13026 UInt bI = INSN(5,5);
13027 UInt imm4 = INSN(3,0);
13028 Bool to_fixed = bOP == 1;
13029 Bool dp_op = bSF == 1;
13030 Bool unsyned = bU == 1;
13031 UInt size = bSX == 0 ? 16 : 32;
13032 Int frac_bits = size - ((imm4 << 1) | bI);
13033 UInt d = dp_op ? ((bD << 4) | Vd) : ((Vd << 1) | bD);
13034 if (frac_bits >= 1 && frac_bits <= 32 && !to_fixed && !dp_op
13035 && size == 32) {
sewardj9fe0cc72012-08-01 20:05:42 +000013036 /* VCVT.F32.{S,U}32 S[d], S[d], #frac_bits */
13037 /* This generates really horrible code. We could potentially
13038 do much better. */
13039 IRTemp rmode = newTemp(Ity_I32);
sewardj6b7bdec2013-03-05 14:26:22 +000013040 assign(rmode, mkU32(Irrm_NEAREST)); // per the spec
sewardj9fe0cc72012-08-01 20:05:42 +000013041 IRTemp src32 = newTemp(Ity_I32);
13042 assign(src32, unop(Iop_ReinterpF32asI32, getFReg(d)));
13043 IRExpr* as_F64 = unop( unsyned ? Iop_I32UtoF64 : Iop_I32StoF64,
13044 mkexpr(src32 ) );
13045 IRTemp scale = newTemp(Ity_F64);
13046 assign(scale, unop(Iop_I32UtoF64, mkU32( 1 << (frac_bits-1) )));
13047 IRExpr* rm = mkU32(Irrm_NEAREST);
13048 IRExpr* resF64 = triop(Iop_DivF64,
13049 rm, as_F64,
sewardj6b7bdec2013-03-05 14:26:22 +000013050 triop(Iop_AddF64, rm, mkexpr(scale),
13051 mkexpr(scale)));
sewardj9fe0cc72012-08-01 20:05:42 +000013052 IRExpr* resF32 = binop(Iop_F64toF32, mkexpr(rmode), resF64);
13053 putFReg(d, resF32, condT);
13054 DIP("vcvt.f32.%c32, s%u, s%u, #%d\n",
13055 unsyned ? 'u' : 's', d, d, frac_bits);
13056 goto decode_success_vfp;
13057 }
sewardj6b7bdec2013-03-05 14:26:22 +000013058 if (frac_bits >= 1 && frac_bits <= 32 && !to_fixed && dp_op
13059 && size == 32) {
13060 /* VCVT.F64.{S,U}32 D[d], D[d], #frac_bits */
13061 /* This generates really horrible code. We could potentially
13062 do much better. */
sewardj6b7bdec2013-03-05 14:26:22 +000013063 IRTemp src32 = newTemp(Ity_I32);
sewardja39fb0c2013-03-22 13:28:50 +000013064 assign(src32, unop(Iop_64to32, getDRegI64(d)));
sewardj6b7bdec2013-03-05 14:26:22 +000013065 IRExpr* as_F64 = unop( unsyned ? Iop_I32UtoF64 : Iop_I32StoF64,
13066 mkexpr(src32 ) );
13067 IRTemp scale = newTemp(Ity_F64);
13068 assign(scale, unop(Iop_I32UtoF64, mkU32( 1 << (frac_bits-1) )));
13069 IRExpr* rm = mkU32(Irrm_NEAREST);
13070 IRExpr* resF64 = triop(Iop_DivF64,
13071 rm, as_F64,
13072 triop(Iop_AddF64, rm, mkexpr(scale),
13073 mkexpr(scale)));
13074 putDReg(d, resF64, condT);
13075 DIP("vcvt.f64.%c32, d%u, d%u, #%d\n",
13076 unsyned ? 'u' : 's', d, d, frac_bits);
13077 goto decode_success_vfp;
13078 }
sewardjade55522013-03-06 08:34:04 +000013079 if (frac_bits >= 1 && frac_bits <= 32 && to_fixed && dp_op
13080 && size == 32) {
13081 /* VCVT.{S,U}32.F64 D[d], D[d], #frac_bits */
13082 IRTemp srcF64 = newTemp(Ity_F64);
13083 assign(srcF64, getDReg(d));
13084 IRTemp scale = newTemp(Ity_F64);
13085 assign(scale, unop(Iop_I32UtoF64, mkU32( 1 << (frac_bits-1) )));
13086 IRTemp scaledF64 = newTemp(Ity_F64);
13087 IRExpr* rm = mkU32(Irrm_NEAREST);
13088 assign(scaledF64, triop(Iop_MulF64,
13089 rm, mkexpr(srcF64),
13090 triop(Iop_AddF64, rm, mkexpr(scale),
13091 mkexpr(scale))));
13092 IRTemp rmode = newTemp(Ity_I32);
13093 assign(rmode, mkU32(Irrm_ZERO)); // as per the spec
13094 IRTemp asI32 = newTemp(Ity_I32);
13095 assign(asI32, binop(unsyned ? Iop_F64toI32U : Iop_F64toI32S,
13096 mkexpr(rmode), mkexpr(scaledF64)));
13097 putDRegI64(d, unop(unsyned ? Iop_32Uto64 : Iop_32Sto64,
13098 mkexpr(asI32)), condT);
13099 goto decode_success_vfp;
13100 }
sewardj9fe0cc72012-08-01 20:05:42 +000013101 /* fall through */
13102 }
13103
sewardjd2664472010-08-22 12:44:20 +000013104 /* FAILURE */
13105 return False;
13106
13107 decode_success_vfp:
13108 /* Check that any accepted insn really is a CP10 or CP11 insn, iow,
13109 assert that we aren't accepting, in this fn, insns that actually
13110 should be handled somewhere else. */
13111 vassert(INSN(11,9) == BITS3(1,0,1)); // 11:8 = 1010 or 1011
13112 return True;
13113
13114# undef INSN
13115}
13116
13117
sewardjc2c87162004-11-25 13:07:02 +000013118/*------------------------------------------------------------*/
sewardj80bea7b2010-01-09 11:43:21 +000013119/*--- Instructions in NV (never) space ---*/
13120/*------------------------------------------------------------*/
13121
sewardjd2664472010-08-22 12:44:20 +000013122/* ARM only */
13123/* Translate a NV space instruction. If successful, returns True and
13124 *dres may or may not be updated. If failure, returns False and
13125 doesn't change *dres nor create any IR.
13126
13127 Note that all NEON instructions (in ARM mode) are handled through
13128 here, since they are all in NV space.
13129*/
sewardj1fce8de2010-09-09 07:27:24 +000013130static Bool decode_NV_instruction ( /*MOD*/DisResult* dres,
13131 VexArchInfo* archinfo,
13132 UInt insn )
sewardj80bea7b2010-01-09 11:43:21 +000013133{
13134# define INSN(_bMax,_bMin) SLICE_UInt(insn, (_bMax), (_bMin))
13135# define INSN_COND SLICE_UInt(insn, 31, 28)
13136
13137 HChar dis_buf[128];
13138
13139 // Should only be called for NV instructions
13140 vassert(BITS4(1,1,1,1) == INSN_COND);
13141
13142 /* ------------------------ pld ------------------------ */
13143 if (BITS8(0,1,0,1, 0, 1,0,1) == (INSN(27,20) & BITS8(1,1,1,1,0,1,1,1))
13144 && BITS4(1,1,1,1) == INSN(15,12)) {
13145 UInt rN = INSN(19,16);
13146 UInt imm12 = INSN(11,0);
13147 UInt bU = INSN(23,23);
13148 DIP("pld [r%u, #%c%u]\n", rN, bU ? '+' : '-', imm12);
13149 return True;
13150 }
13151
13152 if (BITS8(0,1,1,1, 0, 1,0,1) == (INSN(27,20) & BITS8(1,1,1,1,0,1,1,1))
13153 && BITS4(1,1,1,1) == INSN(15,12)
13154 && 0 == INSN(4,4)) {
13155 UInt rN = INSN(19,16);
13156 UInt rM = INSN(3,0);
13157 UInt imm5 = INSN(11,7);
13158 UInt sh2 = INSN(6,5);
13159 UInt bU = INSN(23,23);
13160 if (rM != 15) {
13161 IRExpr* eaE = mk_EA_reg_plusminus_shifted_reg(rN, bU, rM,
13162 sh2, imm5, dis_buf);
13163 IRTemp eaT = newTemp(Ity_I32);
13164 /* Bind eaE to a temp merely for debugging-vex purposes, so we
13165 can check it's a plausible decoding. It will get removed
13166 by iropt a little later on. */
13167 vassert(eaE);
13168 assign(eaT, eaE);
13169 DIP("pld %s\n", dis_buf);
13170 return True;
13171 }
13172 /* fall through */
13173 }
13174
sewardj4c3839e2010-08-31 09:31:06 +000013175 /* ------------------------ pli ------------------------ */
13176 if (BITS8(0,1,0,0, 0, 1,0,1) == (INSN(27,20) & BITS8(1,1,1,1,0,1,1,1))
13177 && BITS4(1,1,1,1) == INSN(15,12)) {
13178 UInt rN = INSN(19,16);
13179 UInt imm12 = INSN(11,0);
13180 UInt bU = INSN(23,23);
13181 DIP("pli [r%u, #%c%u]\n", rN, bU ? '+' : '-', imm12);
13182 return True;
13183 }
13184
sewardjd2664472010-08-22 12:44:20 +000013185 /* --------------------- Interworking branches --------------------- */
13186
13187 // BLX (1), viz, unconditional branch and link to R15+simm24
13188 // and set CPSR.T = 1, that is, switch to Thumb mode
13189 if (INSN(31,25) == BITS7(1,1,1,1,1,0,1)) {
13190 UInt bitH = INSN(24,24);
13191 Int uimm24 = INSN(23,0);
13192 Int simm24 = (((uimm24 << 8) >> 8) << 2) + (bitH << 1);
13193 /* Now this is a bit tricky. Since we're decoding an ARM insn,
13194 it is implies that CPSR.T == 0. Hence the current insn's
13195 address is guaranteed to be of the form X--(30)--X00. So, no
13196 need to mask any bits off it. But need to set the lowest bit
13197 to 1 to denote we're in Thumb mode after this, since
13198 guest_R15T has CPSR.T as the lowest bit. And we can't chase
13199 into the call, so end the block at this point. */
13200 UInt dst = guest_R15_curr_instr_notENC + 8 + (simm24 | 1);
13201 putIRegA( 14, mkU32(guest_R15_curr_instr_notENC + 4),
13202 IRTemp_INVALID/*because AL*/, Ijk_Boring );
sewardjc6f970f2012-04-02 21:54:49 +000013203 llPutIReg(15, mkU32(dst));
13204 dres->jk_StopHere = Ijk_Call;
13205 dres->whatNext = Dis_StopHere;
sewardjd2664472010-08-22 12:44:20 +000013206 DIP("blx 0x%x (and switch to Thumb mode)\n", dst - 1);
13207 return True;
13208 }
13209
sewardj412098c2010-05-04 08:48:43 +000013210 /* ------------------- v7 barrier insns ------------------- */
13211 switch (insn) {
13212 case 0xF57FF06F: /* ISB */
13213 stmt( IRStmt_MBE(Imbe_Fence) );
13214 DIP("ISB\n");
13215 return True;
sewardje407ced2011-05-03 14:57:59 +000013216 case 0xF57FF04F: /* DSB sy */
13217 case 0xF57FF04E: /* DSB st */
13218 case 0xF57FF04B: /* DSB ish */
13219 case 0xF57FF04A: /* DSB ishst */
13220 case 0xF57FF047: /* DSB nsh */
13221 case 0xF57FF046: /* DSB nshst */
13222 case 0xF57FF043: /* DSB osh */
13223 case 0xF57FF042: /* DSB oshst */
sewardj412098c2010-05-04 08:48:43 +000013224 stmt( IRStmt_MBE(Imbe_Fence) );
13225 DIP("DSB\n");
13226 return True;
sewardje407ced2011-05-03 14:57:59 +000013227 case 0xF57FF05F: /* DMB sy */
13228 case 0xF57FF05E: /* DMB st */
13229 case 0xF57FF05B: /* DMB ish */
13230 case 0xF57FF05A: /* DMB ishst */
13231 case 0xF57FF057: /* DMB nsh */
13232 case 0xF57FF056: /* DMB nshst */
13233 case 0xF57FF053: /* DMB osh */
13234 case 0xF57FF052: /* DMB oshst */
sewardj412098c2010-05-04 08:48:43 +000013235 stmt( IRStmt_MBE(Imbe_Fence) );
13236 DIP("DMB\n");
13237 return True;
13238 default:
13239 break;
13240 }
13241
sewardj6d615ba2011-09-26 16:19:43 +000013242 /* ------------------- CLREX ------------------ */
13243 if (insn == 0xF57FF01F) {
13244 /* AFAICS, this simply cancels a (all?) reservations made by a
13245 (any?) preceding LDREX(es). Arrange to hand it through to
13246 the back end. */
13247 stmt( IRStmt_MBE(Imbe_CancelReservation) );
13248 DIP("clrex\n");
13249 return True;
13250 }
13251
sewardjd2664472010-08-22 12:44:20 +000013252 /* ------------------- NEON ------------------- */
sewardj1fce8de2010-09-09 07:27:24 +000013253 if (archinfo->hwcaps & VEX_HWCAPS_ARM_NEON) {
13254 Bool ok_neon = decode_NEON_instruction(
13255 dres, insn, IRTemp_INVALID/*unconditional*/,
13256 False/*!isT*/
13257 );
13258 if (ok_neon)
13259 return True;
sewardj1f139f52010-08-29 12:33:02 +000013260 }
sewardjd2664472010-08-22 12:44:20 +000013261
13262 // unrecognised
sewardj80bea7b2010-01-09 11:43:21 +000013263 return False;
13264
13265# undef INSN_COND
13266# undef INSN
13267}
13268
13269
13270/*------------------------------------------------------------*/
sewardjd2664472010-08-22 12:44:20 +000013271/*--- Disassemble a single ARM instruction ---*/
sewardjc2c87162004-11-25 13:07:02 +000013272/*------------------------------------------------------------*/
13273
sewardjd2664472010-08-22 12:44:20 +000013274/* Disassemble a single ARM instruction into IR. The instruction is
13275 located in host memory at guest_instr, and has (decoded) guest IP
13276 of guest_R15_curr_instr_notENC, which will have been set before the
13277 call here. */
sewardj6c299f32009-12-31 18:00:12 +000013278
sewardjd2664472010-08-22 12:44:20 +000013279static
sewardj6c299f32009-12-31 18:00:12 +000013280DisResult disInstr_ARM_WRK (
sewardj6c299f32009-12-31 18:00:12 +000013281 Bool (*resteerOkFn) ( /*opaque*/void*, Addr64 ),
sewardj82f56882010-01-17 09:36:11 +000013282 Bool resteerCisOk,
sewardj6c299f32009-12-31 18:00:12 +000013283 void* callback_opaque,
13284 UChar* guest_instr,
13285 VexArchInfo* archinfo,
sewardj442e51a2012-12-06 18:08:04 +000013286 VexAbiInfo* abiinfo,
13287 Bool sigill_diag
sewardj6c299f32009-12-31 18:00:12 +000013288 )
sewardjc2c87162004-11-25 13:07:02 +000013289{
sewardj6c299f32009-12-31 18:00:12 +000013290 // A macro to fish bits out of 'insn'.
sewardj80bea7b2010-01-09 11:43:21 +000013291# define INSN(_bMax,_bMin) SLICE_UInt(insn, (_bMax), (_bMin))
13292# define INSN_COND SLICE_UInt(insn, 31, 28)
sewardj6c299f32009-12-31 18:00:12 +000013293
13294 DisResult dres;
13295 UInt insn;
13296 //Bool allow_VFP = False;
13297 //UInt hwcaps = archinfo->hwcaps;
13298 IRTemp condT; /* :: Ity_I32 */
13299 UInt summary;
13300 HChar dis_buf[128]; // big enough to hold LDMIA etc text
13301
13302 /* What insn variants are we supporting today? */
13303 //allow_VFP = (0 != (hwcaps & VEX_HWCAPS_ARM_VFP));
13304 // etc etc
13305
13306 /* Set result defaults. */
sewardjc6f970f2012-04-02 21:54:49 +000013307 dres.whatNext = Dis_Continue;
13308 dres.len = 4;
13309 dres.continueAt = 0;
13310 dres.jk_StopHere = Ijk_INVALID;
sewardj6c299f32009-12-31 18:00:12 +000013311
13312 /* Set default actions for post-insn handling of writes to r15, if
13313 required. */
13314 r15written = False;
13315 r15guard = IRTemp_INVALID; /* unconditional */
13316 r15kind = Ijk_Boring;
sewardjc2c87162004-11-25 13:07:02 +000013317
sewardjc2c87162004-11-25 13:07:02 +000013318 /* At least this is simple on ARM: insns are all 4 bytes long, and
13319 4-aligned. So just fish the whole thing out of memory right now
13320 and have done. */
sewardj6c299f32009-12-31 18:00:12 +000013321 insn = getUIntLittleEndianly( guest_instr );
sewardjc2c87162004-11-25 13:07:02 +000013322
sewardj6c299f32009-12-31 18:00:12 +000013323 if (0) vex_printf("insn: 0x%x\n", insn);
sewardjc2c87162004-11-25 13:07:02 +000013324
sewardjd2664472010-08-22 12:44:20 +000013325 DIP("\t(arm) 0x%x: ", (UInt)guest_R15_curr_instr_notENC);
cerionc60c01e2004-12-02 20:19:22 +000013326
sewardjd2664472010-08-22 12:44:20 +000013327 vassert(0 == (guest_R15_curr_instr_notENC & 3));
sewardjc2c87162004-11-25 13:07:02 +000013328
sewardj6c299f32009-12-31 18:00:12 +000013329 /* ----------------------------------------------------------- */
cerionc60c01e2004-12-02 20:19:22 +000013330
sewardj6c299f32009-12-31 18:00:12 +000013331 /* Spot "Special" instructions (see comment at top of file). */
sewardjc2c87162004-11-25 13:07:02 +000013332 {
sewardj6c299f32009-12-31 18:00:12 +000013333 UChar* code = (UChar*)guest_instr;
13334 /* Spot the 16-byte preamble:
sewardjcca71942004-12-02 23:35:18 +000013335
sewardj6c299f32009-12-31 18:00:12 +000013336 e1a0c1ec mov r12, r12, ROR #3
13337 e1a0c6ec mov r12, r12, ROR #13
13338 e1a0ceec mov r12, r12, ROR #29
13339 e1a0c9ec mov r12, r12, ROR #19
13340 */
13341 UInt word1 = 0xE1A0C1EC;
13342 UInt word2 = 0xE1A0C6EC;
13343 UInt word3 = 0xE1A0CEEC;
13344 UInt word4 = 0xE1A0C9EC;
13345 if (getUIntLittleEndianly(code+ 0) == word1 &&
13346 getUIntLittleEndianly(code+ 4) == word2 &&
13347 getUIntLittleEndianly(code+ 8) == word3 &&
13348 getUIntLittleEndianly(code+12) == word4) {
13349 /* Got a "Special" instruction preamble. Which one is it? */
13350 if (getUIntLittleEndianly(code+16) == 0xE18AA00A
13351 /* orr r10,r10,r10 */) {
13352 /* R3 = client_request ( R4 ) */
13353 DIP("r3 = client_request ( %%r4 )\n");
sewardjc6f970f2012-04-02 21:54:49 +000013354 llPutIReg(15, mkU32( guest_R15_curr_instr_notENC + 20 ));
13355 dres.jk_StopHere = Ijk_ClientReq;
13356 dres.whatNext = Dis_StopHere;
sewardj6c299f32009-12-31 18:00:12 +000013357 goto decode_success;
13358 }
13359 else
13360 if (getUIntLittleEndianly(code+16) == 0xE18BB00B
13361 /* orr r11,r11,r11 */) {
13362 /* R3 = guest_NRADDR */
13363 DIP("r3 = guest_NRADDR\n");
13364 dres.len = 20;
13365 llPutIReg(3, IRExpr_Get( OFFB_NRADDR, Ity_I32 ));
13366 goto decode_success;
13367 }
13368 else
13369 if (getUIntLittleEndianly(code+16) == 0xE18CC00C
13370 /* orr r12,r12,r12 */) {
13371 /* branch-and-link-to-noredir R4 */
13372 DIP("branch-and-link-to-noredir r4\n");
sewardjd2664472010-08-22 12:44:20 +000013373 llPutIReg(14, mkU32( guest_R15_curr_instr_notENC + 20) );
sewardjc6f970f2012-04-02 21:54:49 +000013374 llPutIReg(15, llGetIReg(4));
13375 dres.jk_StopHere = Ijk_NoRedir;
13376 dres.whatNext = Dis_StopHere;
sewardj6c299f32009-12-31 18:00:12 +000013377 goto decode_success;
13378 }
florian2245ce92012-08-28 16:49:30 +000013379 else
sewardja0d8eb82012-09-03 21:48:42 +000013380 if (getUIntLittleEndianly(code+16) == 0xE1899009
13381 /* orr r9,r9,r9 */) {
florian2245ce92012-08-28 16:49:30 +000013382 /* IR injection */
13383 DIP("IR injection\n");
florian2245ce92012-08-28 16:49:30 +000013384 vex_inject_ir(irsb, Iend_LE);
florian2245ce92012-08-28 16:49:30 +000013385 // Invalidate the current insn. The reason is that the IRop we're
13386 // injecting here can change. In which case the translation has to
13387 // be redone. For ease of handling, we simply invalidate all the
13388 // time.
florian2245ce92012-08-28 16:49:30 +000013389 stmt(IRStmt_Put(OFFB_TISTART, mkU32(guest_R15_curr_instr_notENC)));
13390 stmt(IRStmt_Put(OFFB_TILEN, mkU32(20)));
florian2245ce92012-08-28 16:49:30 +000013391 llPutIReg(15, mkU32( guest_R15_curr_instr_notENC + 20 ));
florian2245ce92012-08-28 16:49:30 +000013392 dres.whatNext = Dis_StopHere;
13393 dres.jk_StopHere = Ijk_TInval;
13394 goto decode_success;
florian2245ce92012-08-28 16:49:30 +000013395 }
sewardj6c299f32009-12-31 18:00:12 +000013396 /* We don't know what it is. Set opc1/opc2 so decode_failure
13397 can print the insn following the Special-insn preamble. */
13398 insn = getUIntLittleEndianly(code+16);
13399 goto decode_failure;
13400 /*NOTREACHED*/
13401 }
13402
13403 }
13404
13405 /* ----------------------------------------------------------- */
13406
sewardjd2664472010-08-22 12:44:20 +000013407 /* Main ARM instruction decoder starts here. */
sewardj6c299f32009-12-31 18:00:12 +000013408
13409 /* Deal with the condition. Strategy is to merely generate a
sewardjd2664472010-08-22 12:44:20 +000013410 condition temporary at this point (or IRTemp_INVALID, meaning
sewardj6c299f32009-12-31 18:00:12 +000013411 unconditional). We leave it to lower-level instruction decoders
13412 to decide whether they can generate straight-line code, or
13413 whether they must generate a side exit before the instruction.
13414 condT :: Ity_I32 and is always either zero or one. */
13415 condT = IRTemp_INVALID;
13416 switch ( (ARMCondcode)INSN_COND ) {
sewardj80bea7b2010-01-09 11:43:21 +000013417 case ARMCondNV: {
13418 // Illegal instruction prior to v5 (see ARM ARM A3-5), but
13419 // some cases are acceptable
sewardj1fce8de2010-09-09 07:27:24 +000013420 Bool ok = decode_NV_instruction(&dres, archinfo, insn);
sewardj80bea7b2010-01-09 11:43:21 +000013421 if (ok)
13422 goto decode_success;
13423 else
13424 goto decode_failure;
13425 }
sewardj6c299f32009-12-31 18:00:12 +000013426 case ARMCondAL: // Always executed
13427 break;
13428 case ARMCondEQ: case ARMCondNE: case ARMCondHS: case ARMCondLO:
13429 case ARMCondMI: case ARMCondPL: case ARMCondVS: case ARMCondVC:
13430 case ARMCondHI: case ARMCondLS: case ARMCondGE: case ARMCondLT:
13431 case ARMCondGT: case ARMCondLE:
13432 condT = newTemp(Ity_I32);
13433 assign( condT, mk_armg_calculate_condition( INSN_COND ));
13434 break;
13435 }
13436
13437 /* ----------------------------------------------------------- */
13438 /* -- ARMv5 integer instructions -- */
13439 /* ----------------------------------------------------------- */
13440
13441 /* ---------------- Data processing ops ------------------- */
13442
13443 if (0 == (INSN(27,20) & BITS8(1,1,0,0,0,0,0,0))
13444 && !(INSN(25,25) == 0 && INSN(7,7) == 1 && INSN(4,4) == 1)) {
13445 IRTemp shop = IRTemp_INVALID; /* shifter operand */
13446 IRTemp shco = IRTemp_INVALID; /* shifter carry out */
13447 UInt rD = (insn >> 12) & 0xF; /* 15:12 */
13448 UInt rN = (insn >> 16) & 0xF; /* 19:16 */
13449 UInt bitS = (insn >> 20) & 1; /* 20:20 */
13450 IRTemp rNt = IRTemp_INVALID;
13451 IRTemp res = IRTemp_INVALID;
13452 IRTemp oldV = IRTemp_INVALID;
13453 IRTemp oldC = IRTemp_INVALID;
florian55085f82012-11-21 00:36:55 +000013454 const HChar* name = NULL;
sewardj6c299f32009-12-31 18:00:12 +000013455 IROp op = Iop_INVALID;
13456 Bool ok;
13457
13458 switch (INSN(24,21)) {
13459
13460 /* --------- ADD, SUB, AND, OR --------- */
13461 case BITS4(0,1,0,0): /* ADD: Rd = Rn + shifter_operand */
13462 name = "add"; op = Iop_Add32; goto rd_eq_rn_op_SO;
13463 case BITS4(0,0,1,0): /* SUB: Rd = Rn - shifter_operand */
13464 name = "sub"; op = Iop_Sub32; goto rd_eq_rn_op_SO;
13465 case BITS4(0,0,1,1): /* RSB: Rd = shifter_operand - Rn */
13466 name = "rsb"; op = Iop_Sub32; goto rd_eq_rn_op_SO;
13467 case BITS4(0,0,0,0): /* AND: Rd = Rn & shifter_operand */
13468 name = "and"; op = Iop_And32; goto rd_eq_rn_op_SO;
13469 case BITS4(1,1,0,0): /* OR: Rd = Rn | shifter_operand */
13470 name = "orr"; op = Iop_Or32; goto rd_eq_rn_op_SO;
13471 case BITS4(0,0,0,1): /* EOR: Rd = Rn ^ shifter_operand */
13472 name = "eor"; op = Iop_Xor32; goto rd_eq_rn_op_SO;
13473 case BITS4(1,1,1,0): /* BIC: Rd = Rn & ~shifter_operand */
13474 name = "bic"; op = Iop_And32; goto rd_eq_rn_op_SO;
13475 rd_eq_rn_op_SO: {
13476 Bool isRSB = False;
13477 Bool isBIC = False;
13478 switch (INSN(24,21)) {
13479 case BITS4(0,0,1,1):
13480 vassert(op == Iop_Sub32); isRSB = True; break;
13481 case BITS4(1,1,1,0):
13482 vassert(op == Iop_And32); isBIC = True; break;
13483 default:
13484 break;
13485 }
13486 rNt = newTemp(Ity_I32);
sewardjd2664472010-08-22 12:44:20 +000013487 assign(rNt, getIRegA(rN));
sewardj6c299f32009-12-31 18:00:12 +000013488 ok = mk_shifter_operand(
13489 INSN(25,25), INSN(11,0),
13490 &shop, bitS ? &shco : NULL, dis_buf
13491 );
13492 if (!ok)
13493 break;
13494 res = newTemp(Ity_I32);
13495 // compute the main result
13496 if (isRSB) {
13497 // reverse-subtract: shifter_operand - Rn
13498 vassert(op == Iop_Sub32);
13499 assign(res, binop(op, mkexpr(shop), mkexpr(rNt)) );
13500 } else if (isBIC) {
13501 // andn: shifter_operand & ~Rn
13502 vassert(op == Iop_And32);
13503 assign(res, binop(op, mkexpr(rNt),
13504 unop(Iop_Not32, mkexpr(shop))) );
13505 } else {
13506 // normal: Rn op shifter_operand
13507 assign(res, binop(op, mkexpr(rNt), mkexpr(shop)) );
13508 }
13509 // but don't commit it until after we've finished
13510 // all necessary reads from the guest state
13511 if (bitS
13512 && (op == Iop_And32 || op == Iop_Or32 || op == Iop_Xor32)) {
13513 oldV = newTemp(Ity_I32);
13514 assign( oldV, mk_armg_calculate_flag_v() );
13515 }
sewardjd2664472010-08-22 12:44:20 +000013516 // can't safely read guest state after here
sewardj6c299f32009-12-31 18:00:12 +000013517 // now safe to put the main result
sewardjd2664472010-08-22 12:44:20 +000013518 putIRegA( rD, mkexpr(res), condT, Ijk_Boring );
sewardj6c299f32009-12-31 18:00:12 +000013519 // XXXX!! not safe to read any guest state after
13520 // this point (I think the code below doesn't do that).
13521 if (!bitS)
13522 vassert(shco == IRTemp_INVALID);
13523 /* Update the flags thunk if necessary */
13524 if (bitS) {
13525 vassert(shco != IRTemp_INVALID);
13526 switch (op) {
13527 case Iop_Add32:
13528 setFlags_D1_D2( ARMG_CC_OP_ADD, rNt, shop, condT );
13529 break;
13530 case Iop_Sub32:
13531 if (isRSB) {
13532 setFlags_D1_D2( ARMG_CC_OP_SUB, shop, rNt, condT );
13533 } else {
13534 setFlags_D1_D2( ARMG_CC_OP_SUB, rNt, shop, condT );
13535 }
13536 break;
13537 case Iop_And32: /* BIC and AND set the flags the same */
13538 case Iop_Or32:
13539 case Iop_Xor32:
13540 // oldV has been read just above
13541 setFlags_D1_D2_ND( ARMG_CC_OP_LOGIC,
13542 res, shco, oldV, condT );
13543 break;
13544 default:
13545 vassert(0);
13546 }
13547 }
13548 DIP("%s%s%s r%u, r%u, %s\n",
13549 name, nCC(INSN_COND), bitS ? "s" : "", rD, rN, dis_buf );
13550 goto decode_success;
13551 }
13552
13553 /* --------- MOV, MVN --------- */
13554 case BITS4(1,1,0,1): /* MOV: Rd = shifter_operand */
13555 case BITS4(1,1,1,1): { /* MVN: Rd = not(shifter_operand) */
13556 Bool isMVN = INSN(24,21) == BITS4(1,1,1,1);
sewardjf5800652011-10-14 15:44:00 +000013557 IRTemp jk = Ijk_Boring;
sewardj6c299f32009-12-31 18:00:12 +000013558 if (rN != 0)
13559 break; /* rN must be zero */
13560 ok = mk_shifter_operand(
13561 INSN(25,25), INSN(11,0),
13562 &shop, bitS ? &shco : NULL, dis_buf
13563 );
13564 if (!ok)
13565 break;
13566 res = newTemp(Ity_I32);
13567 assign( res, isMVN ? unop(Iop_Not32, mkexpr(shop))
13568 : mkexpr(shop) );
13569 if (bitS) {
13570 vassert(shco != IRTemp_INVALID);
13571 oldV = newTemp(Ity_I32);
13572 assign( oldV, mk_armg_calculate_flag_v() );
13573 } else {
13574 vassert(shco == IRTemp_INVALID);
13575 }
sewardjf5800652011-10-14 15:44:00 +000013576 /* According to the Cortex A8 TRM Sec. 5.2.1, MOV PC, r14 is a
13577 return for purposes of branch prediction. */
13578 if (!isMVN && INSN(11,0) == 14) {
13579 jk = Ijk_Ret;
13580 }
sewardj6c299f32009-12-31 18:00:12 +000013581 // can't safely read guest state after here
sewardjf5800652011-10-14 15:44:00 +000013582 putIRegA( rD, mkexpr(res), condT, jk );
sewardj6c299f32009-12-31 18:00:12 +000013583 /* Update the flags thunk if necessary */
13584 if (bitS) {
13585 setFlags_D1_D2_ND( ARMG_CC_OP_LOGIC,
13586 res, shco, oldV, condT );
13587 }
13588 DIP("%s%s%s r%u, %s\n",
13589 isMVN ? "mvn" : "mov",
13590 nCC(INSN_COND), bitS ? "s" : "", rD, dis_buf );
13591 goto decode_success;
13592 }
13593
13594 /* --------- CMP --------- */
13595 case BITS4(1,0,1,0): /* CMP: (void) Rn - shifter_operand */
13596 case BITS4(1,0,1,1): { /* CMN: (void) Rn + shifter_operand */
13597 Bool isCMN = INSN(24,21) == BITS4(1,0,1,1);
13598 if (rD != 0)
13599 break; /* rD must be zero */
13600 if (bitS == 0)
13601 break; /* if S (bit 20) is not set, it's not CMP/CMN */
13602 rNt = newTemp(Ity_I32);
sewardjd2664472010-08-22 12:44:20 +000013603 assign(rNt, getIRegA(rN));
sewardj6c299f32009-12-31 18:00:12 +000013604 ok = mk_shifter_operand(
13605 INSN(25,25), INSN(11,0),
13606 &shop, NULL, dis_buf
13607 );
13608 if (!ok)
13609 break;
sewardjd2664472010-08-22 12:44:20 +000013610 // can't safely read guest state after here
sewardj6c299f32009-12-31 18:00:12 +000013611 /* Update the flags thunk. */
13612 setFlags_D1_D2( isCMN ? ARMG_CC_OP_ADD : ARMG_CC_OP_SUB,
13613 rNt, shop, condT );
13614 DIP("%s%s r%u, %s\n",
13615 isCMN ? "cmn" : "cmp",
13616 nCC(INSN_COND), rN, dis_buf );
13617 goto decode_success;
13618 }
13619
13620 /* --------- TST --------- */
13621 case BITS4(1,0,0,0): /* TST: (void) Rn & shifter_operand */
13622 case BITS4(1,0,0,1): { /* TEQ: (void) Rn ^ shifter_operand */
13623 Bool isTEQ = INSN(24,21) == BITS4(1,0,0,1);
13624 if (rD != 0)
13625 break; /* rD must be zero */
13626 if (bitS == 0)
13627 break; /* if S (bit 20) is not set, it's not TST/TEQ */
13628 rNt = newTemp(Ity_I32);
sewardjd2664472010-08-22 12:44:20 +000013629 assign(rNt, getIRegA(rN));
sewardj6c299f32009-12-31 18:00:12 +000013630 ok = mk_shifter_operand(
13631 INSN(25,25), INSN(11,0),
13632 &shop, &shco, dis_buf
13633 );
13634 if (!ok)
13635 break;
13636 /* Update the flags thunk. */
13637 res = newTemp(Ity_I32);
13638 assign( res, binop(isTEQ ? Iop_Xor32 : Iop_And32,
13639 mkexpr(rNt), mkexpr(shop)) );
13640 oldV = newTemp(Ity_I32);
13641 assign( oldV, mk_armg_calculate_flag_v() );
sewardjd2664472010-08-22 12:44:20 +000013642 // can't safely read guest state after here
sewardj6c299f32009-12-31 18:00:12 +000013643 setFlags_D1_D2_ND( ARMG_CC_OP_LOGIC,
13644 res, shco, oldV, condT );
13645 DIP("%s%s r%u, %s\n",
13646 isTEQ ? "teq" : "tst",
13647 nCC(INSN_COND), rN, dis_buf );
13648 goto decode_success;
13649 }
13650
13651 /* --------- ADC, SBC, RSC --------- */
13652 case BITS4(0,1,0,1): /* ADC: Rd = Rn + shifter_operand + oldC */
13653 name = "adc"; goto rd_eq_rn_op_SO_op_oldC;
13654 case BITS4(0,1,1,0): /* SBC: Rd = Rn - shifter_operand - (oldC ^ 1) */
13655 name = "sbc"; goto rd_eq_rn_op_SO_op_oldC;
13656 case BITS4(0,1,1,1): /* RSC: Rd = shifter_operand - Rn - (oldC ^ 1) */
13657 name = "rsc"; goto rd_eq_rn_op_SO_op_oldC;
13658 rd_eq_rn_op_SO_op_oldC: {
sewardjd2664472010-08-22 12:44:20 +000013659 // FIXME: shco isn't used for anything. Get rid of it.
sewardj6c299f32009-12-31 18:00:12 +000013660 rNt = newTemp(Ity_I32);
sewardjd2664472010-08-22 12:44:20 +000013661 assign(rNt, getIRegA(rN));
sewardj6c299f32009-12-31 18:00:12 +000013662 ok = mk_shifter_operand(
13663 INSN(25,25), INSN(11,0),
13664 &shop, bitS ? &shco : NULL, dis_buf
13665 );
13666 if (!ok)
13667 break;
13668 oldC = newTemp(Ity_I32);
13669 assign( oldC, mk_armg_calculate_flag_c() );
13670 res = newTemp(Ity_I32);
13671 // compute the main result
13672 switch (INSN(24,21)) {
13673 case BITS4(0,1,0,1): /* ADC */
13674 assign(res,
13675 binop(Iop_Add32,
13676 binop(Iop_Add32, mkexpr(rNt), mkexpr(shop)),
13677 mkexpr(oldC) ));
13678 break;
13679 case BITS4(0,1,1,0): /* SBC */
13680 assign(res,
13681 binop(Iop_Sub32,
13682 binop(Iop_Sub32, mkexpr(rNt), mkexpr(shop)),
13683 binop(Iop_Xor32, mkexpr(oldC), mkU32(1)) ));
13684 break;
13685 case BITS4(0,1,1,1): /* RSC */
13686 assign(res,
13687 binop(Iop_Sub32,
13688 binop(Iop_Sub32, mkexpr(shop), mkexpr(rNt)),
13689 binop(Iop_Xor32, mkexpr(oldC), mkU32(1)) ));
13690 break;
13691 default:
13692 vassert(0);
13693 }
13694 // but don't commit it until after we've finished
13695 // all necessary reads from the guest state
13696 // now safe to put the main result
sewardjd2664472010-08-22 12:44:20 +000013697 putIRegA( rD, mkexpr(res), condT, Ijk_Boring );
sewardj6c299f32009-12-31 18:00:12 +000013698 // XXXX!! not safe to read any guest state after
13699 // this point (I think the code below doesn't do that).
13700 if (!bitS)
13701 vassert(shco == IRTemp_INVALID);
13702 /* Update the flags thunk if necessary */
13703 if (bitS) {
13704 vassert(shco != IRTemp_INVALID);
13705 switch (INSN(24,21)) {
13706 case BITS4(0,1,0,1): /* ADC */
13707 setFlags_D1_D2_ND( ARMG_CC_OP_ADC,
13708 rNt, shop, oldC, condT );
13709 break;
13710 case BITS4(0,1,1,0): /* SBC */
13711 setFlags_D1_D2_ND( ARMG_CC_OP_SBB,
13712 rNt, shop, oldC, condT );
13713 break;
13714 case BITS4(0,1,1,1): /* RSC */
13715 setFlags_D1_D2_ND( ARMG_CC_OP_SBB,
13716 shop, rNt, oldC, condT );
13717 break;
13718 default:
13719 vassert(0);
13720 }
13721 }
13722 DIP("%s%s%s r%u, r%u, %s\n",
13723 name, nCC(INSN_COND), bitS ? "s" : "", rD, rN, dis_buf );
13724 goto decode_success;
13725 }
13726
sewardj6c299f32009-12-31 18:00:12 +000013727 default:
florianc6c7a0d2013-01-23 17:17:22 +000013728 vassert(0);
sewardj6c299f32009-12-31 18:00:12 +000013729 }
13730 } /* if (0 == (INSN(27,20) & BITS8(1,1,0,0,0,0,0,0)) */
13731
13732 /* --------------------- Load/store (ubyte & word) -------- */
13733 // LDR STR LDRB STRB
13734 /* 31 27 23 19 15 11 6 4 3 # highest bit
13735 28 24 20 16 12
13736 A5-20 1 | 16 cond 0101 UB0L Rn Rd imm12
13737 A5-22 1 | 32 cond 0111 UBOL Rn Rd imm5 sh2 0 Rm
13738 A5-24 2 | 16 cond 0101 UB1L Rn Rd imm12
13739 A5-26 2 | 32 cond 0111 UB1L Rn Rd imm5 sh2 0 Rm
13740 A5-28 3 | 16 cond 0100 UB0L Rn Rd imm12
13741 A5-32 3 | 32 cond 0110 UB0L Rn Rd imm5 sh2 0 Rm
13742 */
13743 /* case coding:
13744 1 at-ea (access at ea)
13745 2 at-ea-then-upd (access at ea, then Rn = ea)
13746 3 at-Rn-then-upd (access at Rn, then Rn = ea)
13747 ea coding
13748 16 Rn +/- imm12
13749 32 Rn +/- Rm sh2 imm5
13750 */
13751 /* Quickly skip over all of this for hopefully most instructions */
13752 if ((INSN(27,24) & BITS4(1,1,0,0)) != BITS4(0,1,0,0))
13753 goto after_load_store_ubyte_or_word;
13754
13755 summary = 0;
13756
13757 /**/ if (INSN(27,24) == BITS4(0,1,0,1) && INSN(21,21) == 0) {
13758 summary = 1 | 16;
13759 }
13760 else if (INSN(27,24) == BITS4(0,1,1,1) && INSN(21,21) == 0
13761 && INSN(4,4) == 0) {
13762 summary = 1 | 32;
13763 }
13764 else if (INSN(27,24) == BITS4(0,1,0,1) && INSN(21,21) == 1) {
13765 summary = 2 | 16;
13766 }
13767 else if (INSN(27,24) == BITS4(0,1,1,1) && INSN(21,21) == 1
13768 && INSN(4,4) == 0) {
13769 summary = 2 | 32;
13770 }
13771 else if (INSN(27,24) == BITS4(0,1,0,0) && INSN(21,21) == 0) {
13772 summary = 3 | 16;
13773 }
13774 else if (INSN(27,24) == BITS4(0,1,1,0) && INSN(21,21) == 0
13775 && INSN(4,4) == 0) {
13776 summary = 3 | 32;
13777 }
13778 else goto after_load_store_ubyte_or_word;
13779
13780 { UInt rN = (insn >> 16) & 0xF; /* 19:16 */
13781 UInt rD = (insn >> 12) & 0xF; /* 15:12 */
13782 UInt rM = (insn >> 0) & 0xF; /* 3:0 */
13783 UInt bU = (insn >> 23) & 1; /* 23 */
13784 UInt bB = (insn >> 22) & 1; /* 22 */
13785 UInt bL = (insn >> 20) & 1; /* 20 */
13786 UInt imm12 = (insn >> 0) & 0xFFF; /* 11:0 */
13787 UInt imm5 = (insn >> 7) & 0x1F; /* 11:7 */
13788 UInt sh2 = (insn >> 5) & 3; /* 6:5 */
13789
13790 /* Skip some invalid cases, which would lead to two competing
13791 updates to the same register, or which are otherwise
13792 disallowed by the spec. */
13793 switch (summary) {
13794 case 1 | 16:
13795 break;
13796 case 1 | 32:
13797 if (rM == 15) goto after_load_store_ubyte_or_word;
13798 break;
13799 case 2 | 16: case 3 | 16:
13800 if (rN == 15) goto after_load_store_ubyte_or_word;
13801 if (bL == 1 && rN == rD) goto after_load_store_ubyte_or_word;
13802 break;
13803 case 2 | 32: case 3 | 32:
13804 if (rM == 15) goto after_load_store_ubyte_or_word;
13805 if (rN == 15) goto after_load_store_ubyte_or_word;
13806 if (rN == rM) goto after_load_store_ubyte_or_word;
13807 if (bL == 1 && rN == rD) goto after_load_store_ubyte_or_word;
13808 break;
13809 default:
13810 vassert(0);
13811 }
13812
sewardj6c299f32009-12-31 18:00:12 +000013813 /* compute the effective address. Bind it to a tmp since we
13814 may need to use it twice. */
13815 IRExpr* eaE = NULL;
13816 switch (summary & 0xF0) {
13817 case 16:
13818 eaE = mk_EA_reg_plusminus_imm12( rN, bU, imm12, dis_buf );
13819 break;
13820 case 32:
13821 eaE = mk_EA_reg_plusminus_shifted_reg( rN, bU, rM, sh2, imm5,
13822 dis_buf );
13823 break;
13824 }
13825 vassert(eaE);
13826 IRTemp eaT = newTemp(Ity_I32);
13827 assign(eaT, eaE);
13828
13829 /* get the old Rn value */
13830 IRTemp rnT = newTemp(Ity_I32);
sewardjd2664472010-08-22 12:44:20 +000013831 assign(rnT, getIRegA(rN));
sewardj6c299f32009-12-31 18:00:12 +000013832
13833 /* decide on the transfer address */
13834 IRTemp taT = IRTemp_INVALID;
13835 switch (summary & 0x0F) {
13836 case 1: case 2: taT = eaT; break;
13837 case 3: taT = rnT; break;
13838 }
13839 vassert(taT != IRTemp_INVALID);
13840
13841 if (bL == 0) {
13842 /* Store. If necessary, update the base register before the
13843 store itself, so that the common idiom of "str rX, [sp,
13844 #-4]!" (store rX at sp-4, then do new sp = sp-4, a.k.a "push
13845 rX") doesn't cause Memcheck to complain that the access is
13846 below the stack pointer. Also, not updating sp before the
13847 store confuses Valgrind's dynamic stack-extending logic. So
13848 do it before the store. Hence we need to snarf the store
13849 data before doing the basereg update. */
13850
13851 /* get hold of the data to be stored */
13852 IRTemp rDt = newTemp(Ity_I32);
sewardjd2664472010-08-22 12:44:20 +000013853 assign(rDt, getIRegA(rD));
sewardj6c299f32009-12-31 18:00:12 +000013854
13855 /* Update Rn if necessary. */
13856 switch (summary & 0x0F) {
13857 case 2: case 3:
sewardjcfe046e2013-01-17 14:23:53 +000013858 putIRegA( rN, mkexpr(eaT), condT, Ijk_Boring );
sewardj6c299f32009-12-31 18:00:12 +000013859 break;
13860 }
13861
13862 /* generate the transfer */
13863 if (bB == 0) { // word store
sewardjcfe046e2013-01-17 14:23:53 +000013864 storeGuardedLE( mkexpr(taT), mkexpr(rDt), condT );
sewardj6c299f32009-12-31 18:00:12 +000013865 } else { // byte store
13866 vassert(bB == 1);
sewardjcfe046e2013-01-17 14:23:53 +000013867 storeGuardedLE( mkexpr(taT), unop(Iop_32to8, mkexpr(rDt)), condT );
sewardj6c299f32009-12-31 18:00:12 +000013868 }
13869
13870 } else {
13871 /* Load */
13872 vassert(bL == 1);
13873
13874 /* generate the transfer */
13875 if (bB == 0) { // word load
sewardjf5800652011-10-14 15:44:00 +000013876 IRTemp jk = Ijk_Boring;
13877 /* According to the Cortex A8 TRM Sec. 5.2.1, LDR(1) with r13 as the
13878 base register and PC as the destination register is a return for
13879 purposes of branch prediction.
13880 The ARM ARM Sec. C9.10.1 further specifies that it must use a
13881 post-increment by immediate addressing mode to be counted in
13882 event 0x0E (Procedure return).*/
13883 if (rN == 13 && summary == (3 | 16) && bB == 0) {
13884 jk = Ijk_Ret;
13885 }
sewardjcfe046e2013-01-17 14:23:53 +000013886 IRTemp tD = newTemp(Ity_I32);
13887 loadGuardedLE( tD, ILGop_Ident32,
13888 mkexpr(taT), llGetIReg(rD), condT );
13889 /* "rD == 15 ? condT : IRTemp_INVALID": simply
13890 IRTemp_INVALID would be correct in all cases here, and
13891 for the non-r15 case it generates better code, by
13892 avoiding two tests of the cond (since it is already
13893 tested by loadGuardedLE). However, the logic at the end
13894 of this function, that deals with writes to r15, has an
13895 optimisation which depends on seeing whether or not the
13896 write is conditional. Hence in this particular case we
13897 let it "see" the guard condition. */
13898 putIRegA( rD, mkexpr(tD),
13899 rD == 15 ? condT : IRTemp_INVALID, jk );
sewardj6c299f32009-12-31 18:00:12 +000013900 } else { // byte load
sewardjd2664472010-08-22 12:44:20 +000013901 vassert(bB == 1);
sewardjcfe046e2013-01-17 14:23:53 +000013902 IRTemp tD = newTemp(Ity_I32);
13903 loadGuardedLE( tD, ILGop_8Uto32, mkexpr(taT), llGetIReg(rD), condT );
13904 /* No point in similar 3rd arg complexity here, since we
13905 can't sanely write anything to r15 like this. */
13906 putIRegA( rD, mkexpr(tD), IRTemp_INVALID, Ijk_Boring );
sewardj6c299f32009-12-31 18:00:12 +000013907 }
13908
13909 /* Update Rn if necessary. */
13910 switch (summary & 0x0F) {
13911 case 2: case 3:
13912 // should be assured by logic above:
13913 if (bL == 1)
13914 vassert(rD != rN); /* since we just wrote rD */
sewardjcfe046e2013-01-17 14:23:53 +000013915 putIRegA( rN, mkexpr(eaT), condT, Ijk_Boring );
sewardj6c299f32009-12-31 18:00:12 +000013916 break;
13917 }
13918 }
13919
13920 switch (summary & 0x0F) {
13921 case 1: DIP("%sr%s%s r%u, %s\n",
13922 bL == 0 ? "st" : "ld",
13923 bB == 0 ? "" : "b", nCC(INSN_COND), rD, dis_buf);
13924 break;
13925 case 2: DIP("%sr%s%s r%u, %s! (at-EA-then-Rn=EA)\n",
13926 bL == 0 ? "st" : "ld",
13927 bB == 0 ? "" : "b", nCC(INSN_COND), rD, dis_buf);
13928 break;
13929 case 3: DIP("%sr%s%s r%u, %s! (at-Rn-then-Rn=EA)\n",
13930 bL == 0 ? "st" : "ld",
13931 bB == 0 ? "" : "b", nCC(INSN_COND), rD, dis_buf);
13932 break;
13933 default: vassert(0);
13934 }
13935
13936 /* XXX deal with alignment constraints */
13937
13938 goto decode_success;
13939
13940 /* Complications:
13941
13942 For all loads: if the Amode specifies base register
13943 writeback, and the same register is specified for Rd and Rn,
13944 the results are UNPREDICTABLE.
13945
13946 For all loads and stores: if R15 is written, branch to
13947 that address afterwards.
13948
13949 STRB: straightforward
13950 LDRB: loaded data is zero extended
13951 STR: lowest 2 bits of address are ignored
13952 LDR: if the lowest 2 bits of the address are nonzero
13953 then the loaded value is rotated right by 8 * the lowest 2 bits
13954 */
13955 }
13956
13957 after_load_store_ubyte_or_word:
13958
13959 /* --------------------- Load/store (sbyte & hword) -------- */
13960 // LDRH LDRSH STRH LDRSB
13961 /* 31 27 23 19 15 11 7 3 # highest bit
13962 28 24 20 16 12 8 4 0
13963 A5-36 1 | 16 cond 0001 U10L Rn Rd im4h 1SH1 im4l
13964 A5-38 1 | 32 cond 0001 U00L Rn Rd 0000 1SH1 Rm
13965 A5-40 2 | 16 cond 0001 U11L Rn Rd im4h 1SH1 im4l
13966 A5-42 2 | 32 cond 0001 U01L Rn Rd 0000 1SH1 Rm
13967 A5-44 3 | 16 cond 0000 U10L Rn Rd im4h 1SH1 im4l
13968 A5-46 3 | 32 cond 0000 U00L Rn Rd 0000 1SH1 Rm
13969 */
13970 /* case coding:
13971 1 at-ea (access at ea)
13972 2 at-ea-then-upd (access at ea, then Rn = ea)
13973 3 at-Rn-then-upd (access at Rn, then Rn = ea)
13974 ea coding
13975 16 Rn +/- imm8
13976 32 Rn +/- Rm
13977 */
13978 /* Quickly skip over all of this for hopefully most instructions */
13979 if ((INSN(27,24) & BITS4(1,1,1,0)) != BITS4(0,0,0,0))
13980 goto after_load_store_sbyte_or_hword;
13981
13982 /* Check the "1SH1" thing. */
13983 if ((INSN(7,4) & BITS4(1,0,0,1)) != BITS4(1,0,0,1))
13984 goto after_load_store_sbyte_or_hword;
13985
13986 summary = 0;
13987
13988 /**/ if (INSN(27,24) == BITS4(0,0,0,1) && INSN(22,21) == BITS2(1,0)) {
13989 summary = 1 | 16;
13990 }
13991 else if (INSN(27,24) == BITS4(0,0,0,1) && INSN(22,21) == BITS2(0,0)) {
13992 summary = 1 | 32;
13993 }
13994 else if (INSN(27,24) == BITS4(0,0,0,1) && INSN(22,21) == BITS2(1,1)) {
13995 summary = 2 | 16;
13996 }
13997 else if (INSN(27,24) == BITS4(0,0,0,1) && INSN(22,21) == BITS2(0,1)) {
13998 summary = 2 | 32;
13999 }
14000 else if (INSN(27,24) == BITS4(0,0,0,0) && INSN(22,21) == BITS2(1,0)) {
14001 summary = 3 | 16;
14002 }
14003 else if (INSN(27,24) == BITS4(0,0,0,0) && INSN(22,21) == BITS2(0,0)) {
14004 summary = 3 | 32;
14005 }
14006 else goto after_load_store_sbyte_or_hword;
14007
14008 { UInt rN = (insn >> 16) & 0xF; /* 19:16 */
14009 UInt rD = (insn >> 12) & 0xF; /* 15:12 */
14010 UInt rM = (insn >> 0) & 0xF; /* 3:0 */
14011 UInt bU = (insn >> 23) & 1; /* 23 U=1 offset+, U=0 offset- */
14012 UInt bL = (insn >> 20) & 1; /* 20 L=1 load, L=0 store */
14013 UInt bH = (insn >> 5) & 1; /* H=1 halfword, H=0 byte */
14014 UInt bS = (insn >> 6) & 1; /* S=1 signed, S=0 unsigned */
14015 UInt imm8 = ((insn >> 4) & 0xF0) | (insn & 0xF); /* 11:8, 3:0 */
14016
14017 /* Skip combinations that are either meaningless or already
14018 handled by main word-or-unsigned-byte load-store
14019 instructions. */
14020 if (bS == 0 && bH == 0) /* "unsigned byte" */
14021 goto after_load_store_sbyte_or_hword;
14022 if (bS == 1 && bL == 0) /* "signed store" */
14023 goto after_load_store_sbyte_or_hword;
14024
14025 /* Require 11:8 == 0 for Rn +/- Rm cases */
14026 if ((summary & 32) != 0 && (imm8 & 0xF0) != 0)
14027 goto after_load_store_sbyte_or_hword;
14028
14029 /* Skip some invalid cases, which would lead to two competing
14030 updates to the same register, or which are otherwise
14031 disallowed by the spec. */
14032 switch (summary) {
14033 case 1 | 16:
14034 break;
14035 case 1 | 32:
14036 if (rM == 15) goto after_load_store_sbyte_or_hword;
14037 break;
14038 case 2 | 16: case 3 | 16:
14039 if (rN == 15) goto after_load_store_sbyte_or_hword;
14040 if (bL == 1 && rN == rD) goto after_load_store_sbyte_or_hword;
14041 break;
14042 case 2 | 32: case 3 | 32:
14043 if (rM == 15) goto after_load_store_sbyte_or_hword;
14044 if (rN == 15) goto after_load_store_sbyte_or_hword;
14045 if (rN == rM) goto after_load_store_sbyte_or_hword;
14046 if (bL == 1 && rN == rD) goto after_load_store_sbyte_or_hword;
14047 break;
14048 default:
14049 vassert(0);
14050 }
14051
sewardjcfe046e2013-01-17 14:23:53 +000014052 /* If this is a branch, make it unconditional at this point.
14053 Doing conditional branches in-line is too complex (for now).
14054 Note that you'd have to be insane to use any of these loads to
14055 do a branch, since they only load 16 bits at most, but we
14056 handle it just in case. */
14057 if (bL == 1 && rD == 15 && condT != IRTemp_INVALID) {
14058 // go uncond
sewardjd2664472010-08-22 12:44:20 +000014059 mk_skip_over_A32_if_cond_is_false( condT );
sewardj6c299f32009-12-31 18:00:12 +000014060 condT = IRTemp_INVALID;
sewardjcfe046e2013-01-17 14:23:53 +000014061 // now uncond
sewardj6c299f32009-12-31 18:00:12 +000014062 }
sewardj6c299f32009-12-31 18:00:12 +000014063
14064 /* compute the effective address. Bind it to a tmp since we
14065 may need to use it twice. */
14066 IRExpr* eaE = NULL;
14067 switch (summary & 0xF0) {
14068 case 16:
14069 eaE = mk_EA_reg_plusminus_imm8( rN, bU, imm8, dis_buf );
14070 break;
14071 case 32:
14072 eaE = mk_EA_reg_plusminus_reg( rN, bU, rM, dis_buf );
14073 break;
14074 }
14075 vassert(eaE);
14076 IRTemp eaT = newTemp(Ity_I32);
14077 assign(eaT, eaE);
14078
14079 /* get the old Rn value */
14080 IRTemp rnT = newTemp(Ity_I32);
sewardjd2664472010-08-22 12:44:20 +000014081 assign(rnT, getIRegA(rN));
sewardj6c299f32009-12-31 18:00:12 +000014082
14083 /* decide on the transfer address */
14084 IRTemp taT = IRTemp_INVALID;
14085 switch (summary & 0x0F) {
14086 case 1: case 2: taT = eaT; break;
14087 case 3: taT = rnT; break;
14088 }
14089 vassert(taT != IRTemp_INVALID);
14090
sewardjcfe046e2013-01-17 14:23:53 +000014091 /* ll previous value of rD, for dealing with conditional loads */
14092 IRTemp llOldRd = newTemp(Ity_I32);
14093 assign(llOldRd, llGetIReg(rD));
14094
sewardj6c299f32009-12-31 18:00:12 +000014095 /* halfword store H 1 L 0 S 0
14096 uhalf load H 1 L 1 S 0
14097 shalf load H 1 L 1 S 1
14098 sbyte load H 0 L 1 S 1
14099 */
florian55085f82012-11-21 00:36:55 +000014100 const HChar* name = NULL;
sewardj6c299f32009-12-31 18:00:12 +000014101 /* generate the transfer */
14102 /**/ if (bH == 1 && bL == 0 && bS == 0) { // halfword store
sewardjcfe046e2013-01-17 14:23:53 +000014103 storeGuardedLE( mkexpr(taT),
14104 unop(Iop_32to16, getIRegA(rD)), condT );
sewardj6c299f32009-12-31 18:00:12 +000014105 name = "strh";
14106 }
14107 else if (bH == 1 && bL == 1 && bS == 0) { // uhalf load
sewardjcfe046e2013-01-17 14:23:53 +000014108 IRTemp newRd = newTemp(Ity_I32);
14109 loadGuardedLE( newRd, ILGop_16Uto32,
14110 mkexpr(taT), mkexpr(llOldRd), condT );
14111 putIRegA( rD, mkexpr(newRd), IRTemp_INVALID, Ijk_Boring );
sewardj6c299f32009-12-31 18:00:12 +000014112 name = "ldrh";
14113 }
14114 else if (bH == 1 && bL == 1 && bS == 1) { // shalf load
sewardjcfe046e2013-01-17 14:23:53 +000014115 IRTemp newRd = newTemp(Ity_I32);
14116 loadGuardedLE( newRd, ILGop_16Sto32,
14117 mkexpr(taT), mkexpr(llOldRd), condT );
14118 putIRegA( rD, mkexpr(newRd), IRTemp_INVALID, Ijk_Boring );
sewardj6c299f32009-12-31 18:00:12 +000014119 name = "ldrsh";
14120 }
14121 else if (bH == 0 && bL == 1 && bS == 1) { // sbyte load
sewardjcfe046e2013-01-17 14:23:53 +000014122 IRTemp newRd = newTemp(Ity_I32);
14123 loadGuardedLE( newRd, ILGop_8Sto32,
14124 mkexpr(taT), mkexpr(llOldRd), condT );
14125 putIRegA( rD, mkexpr(newRd), IRTemp_INVALID, Ijk_Boring );
sewardj6c299f32009-12-31 18:00:12 +000014126 name = "ldrsb";
14127 }
14128 else
14129 vassert(0); // should be assured by logic above
14130
14131 /* Update Rn if necessary. */
14132 switch (summary & 0x0F) {
14133 case 2: case 3:
14134 // should be assured by logic above:
14135 if (bL == 1)
14136 vassert(rD != rN); /* since we just wrote rD */
sewardjcfe046e2013-01-17 14:23:53 +000014137 putIRegA( rN, mkexpr(eaT), condT, Ijk_Boring );
sewardj6c299f32009-12-31 18:00:12 +000014138 break;
14139 }
14140
14141 switch (summary & 0x0F) {
14142 case 1: DIP("%s%s r%u, %s\n", name, nCC(INSN_COND), rD, dis_buf);
14143 break;
14144 case 2: DIP("%s%s r%u, %s! (at-EA-then-Rn=EA)\n",
14145 name, nCC(INSN_COND), rD, dis_buf);
14146 break;
14147 case 3: DIP("%s%s r%u, %s! (at-Rn-then-Rn=EA)\n",
14148 name, nCC(INSN_COND), rD, dis_buf);
14149 break;
14150 default: vassert(0);
14151 }
14152
14153 /* XXX deal with alignment constraints */
14154
14155 goto decode_success;
14156
14157 /* Complications:
14158
14159 For all loads: if the Amode specifies base register
14160 writeback, and the same register is specified for Rd and Rn,
14161 the results are UNPREDICTABLE.
14162
14163 For all loads and stores: if R15 is written, branch to
14164 that address afterwards.
14165
14166 Misaligned halfword stores => Unpredictable
14167 Misaligned halfword loads => Unpredictable
14168 */
14169 }
14170
14171 after_load_store_sbyte_or_hword:
14172
14173 /* --------------------- Load/store multiple -------------- */
14174 // LD/STMIA LD/STMIB LD/STMDA LD/STMDB
14175 // Remarkably complex and difficult to get right
14176 // match 27:20 as 100XX0WL
14177 if (BITS8(1,0,0,0,0,0,0,0) == (INSN(27,20) & BITS8(1,1,1,0,0,1,0,0))) {
14178 // A5-50 LD/STMIA cond 1000 10WL Rn RegList
14179 // A5-51 LD/STMIB cond 1001 10WL Rn RegList
14180 // A5-53 LD/STMDA cond 1000 00WL Rn RegList
14181 // A5-53 LD/STMDB cond 1001 00WL Rn RegList
14182 // 28 24 20 16 0
14183
sewardj6c299f32009-12-31 18:00:12 +000014184 UInt bINC = (insn >> 23) & 1;
14185 UInt bBEFORE = (insn >> 24) & 1;
14186
14187 UInt bL = (insn >> 20) & 1; /* load=1, store=0 */
14188 UInt bW = (insn >> 21) & 1; /* Rn wback=1, no wback=0 */
14189 UInt rN = (insn >> 16) & 0xF;
14190 UInt regList = insn & 0xFFFF;
14191 /* Skip some invalid cases, which would lead to two competing
14192 updates to the same register, or which are otherwise
14193 disallowed by the spec. Note the test above has required
14194 that S == 0, since that looks like a kernel-mode only thing.
14195 Done by forcing the real pattern, viz 100XXSWL to actually be
14196 100XX0WL. */
14197 if (rN == 15) goto after_load_store_multiple;
14198 // reglist can't be empty
14199 if (regList == 0) goto after_load_store_multiple;
14200 // if requested to writeback Rn, and this is a load instruction,
14201 // then Rn can't appear in RegList, since we'd have two competing
14202 // new values for Rn. We do however accept this case for store
14203 // instructions.
14204 if (bW == 1 && bL == 1 && ((1 << rN) & regList) > 0)
14205 goto after_load_store_multiple;
14206
14207 /* Now, we can't do a conditional load or store, since that very
14208 likely will generate an exception. So we have to take a side
14209 exit at this point if the condition is false. */
14210 if (condT != IRTemp_INVALID) {
sewardjd2664472010-08-22 12:44:20 +000014211 mk_skip_over_A32_if_cond_is_false( condT );
sewardj6c299f32009-12-31 18:00:12 +000014212 condT = IRTemp_INVALID;
14213 }
sewardj6c299f32009-12-31 18:00:12 +000014214
sewardjd2664472010-08-22 12:44:20 +000014215 /* Ok, now we're unconditional. Generate the IR. */
14216 mk_ldm_stm( True/*arm*/, rN, bINC, bBEFORE, bW, bL, regList );
sewardj6c299f32009-12-31 18:00:12 +000014217
sewardj6c299f32009-12-31 18:00:12 +000014218 DIP("%sm%c%c%s r%u%s, {0x%04x}\n",
14219 bL == 1 ? "ld" : "st", bINC ? 'i' : 'd', bBEFORE ? 'b' : 'a',
14220 nCC(INSN_COND),
14221 rN, bW ? "!" : "", regList);
14222
14223 goto decode_success;
14224 }
14225
14226 after_load_store_multiple:
14227
14228 /* --------------------- Control flow --------------------- */
14229 // B, BL (Branch, or Branch-and-Link, to immediate offset)
14230 //
14231 if (BITS8(1,0,1,0,0,0,0,0) == (INSN(27,20) & BITS8(1,1,1,0,0,0,0,0))) {
14232 UInt link = (insn >> 24) & 1;
14233 UInt uimm24 = insn & ((1<<24)-1);
14234 Int simm24 = (Int)uimm24;
sewardjd2664472010-08-22 12:44:20 +000014235 UInt dst = guest_R15_curr_instr_notENC + 8
14236 + (((simm24 << 8) >> 8) << 2);
sewardj6c299f32009-12-31 18:00:12 +000014237 IRJumpKind jk = link ? Ijk_Call : Ijk_Boring;
14238 if (link) {
sewardjd2664472010-08-22 12:44:20 +000014239 putIRegA(14, mkU32(guest_R15_curr_instr_notENC + 4),
14240 condT, Ijk_Boring);
sewardj6c299f32009-12-31 18:00:12 +000014241 }
14242 if (condT == IRTemp_INVALID) {
14243 /* unconditional transfer to 'dst'. See if we can simply
14244 continue tracing at the destination. */
14245 if (resteerOkFn( callback_opaque, (Addr64)dst )) {
14246 /* yes */
sewardj984d9b12010-01-15 10:53:21 +000014247 dres.whatNext = Dis_ResteerU;
sewardj6c299f32009-12-31 18:00:12 +000014248 dres.continueAt = (Addr64)dst;
14249 } else {
14250 /* no; terminate the SB at this point. */
sewardjc6f970f2012-04-02 21:54:49 +000014251 llPutIReg(15, mkU32(dst));
14252 dres.jk_StopHere = jk;
14253 dres.whatNext = Dis_StopHere;
sewardj6c299f32009-12-31 18:00:12 +000014254 }
14255 DIP("b%s 0x%x\n", link ? "l" : "", dst);
14256 } else {
14257 /* conditional transfer to 'dst' */
florian55085f82012-11-21 00:36:55 +000014258 const HChar* comment = "";
sewardj82f56882010-01-17 09:36:11 +000014259
14260 /* First see if we can do some speculative chasing into one
14261 arm or the other. Be conservative and only chase if
14262 !link, that is, this is a normal conditional branch to a
14263 known destination. */
14264 if (!link
14265 && resteerCisOk
14266 && vex_control.guest_chase_cond
sewardjd2664472010-08-22 12:44:20 +000014267 && dst < guest_R15_curr_instr_notENC
sewardj82f56882010-01-17 09:36:11 +000014268 && resteerOkFn( callback_opaque, (Addr64)(Addr32)dst) ) {
14269 /* Speculation: assume this backward branch is taken. So
14270 we need to emit a side-exit to the insn following this
14271 one, on the negation of the condition, and continue at
14272 the branch target address (dst). */
14273 stmt( IRStmt_Exit( unop(Iop_Not1,
14274 unop(Iop_32to1, mkexpr(condT))),
14275 Ijk_Boring,
sewardjc6f970f2012-04-02 21:54:49 +000014276 IRConst_U32(guest_R15_curr_instr_notENC+4),
14277 OFFB_R15T ));
sewardj82f56882010-01-17 09:36:11 +000014278 dres.whatNext = Dis_ResteerC;
14279 dres.continueAt = (Addr64)(Addr32)dst;
14280 comment = "(assumed taken)";
14281 }
14282 else
14283 if (!link
14284 && resteerCisOk
14285 && vex_control.guest_chase_cond
sewardjd2664472010-08-22 12:44:20 +000014286 && dst >= guest_R15_curr_instr_notENC
sewardj82f56882010-01-17 09:36:11 +000014287 && resteerOkFn( callback_opaque,
sewardjd2664472010-08-22 12:44:20 +000014288 (Addr64)(Addr32)
14289 (guest_R15_curr_instr_notENC+4)) ) {
sewardj82f56882010-01-17 09:36:11 +000014290 /* Speculation: assume this forward branch is not taken.
14291 So we need to emit a side-exit to dst (the dest) and
14292 continue disassembling at the insn immediately
14293 following this one. */
14294 stmt( IRStmt_Exit( unop(Iop_32to1, mkexpr(condT)),
14295 Ijk_Boring,
sewardjc6f970f2012-04-02 21:54:49 +000014296 IRConst_U32(dst),
14297 OFFB_R15T ));
sewardj82f56882010-01-17 09:36:11 +000014298 dres.whatNext = Dis_ResteerC;
sewardjd2664472010-08-22 12:44:20 +000014299 dres.continueAt = (Addr64)(Addr32)
14300 (guest_R15_curr_instr_notENC+4);
sewardj82f56882010-01-17 09:36:11 +000014301 comment = "(assumed not taken)";
14302 }
14303 else {
14304 /* Conservative default translation - end the block at
14305 this point. */
14306 stmt( IRStmt_Exit( unop(Iop_32to1, mkexpr(condT)),
sewardjc6f970f2012-04-02 21:54:49 +000014307 jk, IRConst_U32(dst), OFFB_R15T ));
14308 llPutIReg(15, mkU32(guest_R15_curr_instr_notENC + 4));
14309 dres.jk_StopHere = Ijk_Boring;
14310 dres.whatNext = Dis_StopHere;
sewardj82f56882010-01-17 09:36:11 +000014311 }
14312 DIP("b%s%s 0x%x %s\n", link ? "l" : "", nCC(INSN_COND),
14313 dst, comment);
sewardj6c299f32009-12-31 18:00:12 +000014314 }
14315 goto decode_success;
14316 }
14317
sewardjd2664472010-08-22 12:44:20 +000014318 // B, BL (Branch, or Branch-and-Link, to a register)
14319 // NB: interworking branch
sewardj6c299f32009-12-31 18:00:12 +000014320 if (INSN(27,20) == BITS8(0,0,0,1,0,0,1,0)
14321 && INSN(19,12) == BITS8(1,1,1,1,1,1,1,1)
14322 && (INSN(11,4) == BITS8(1,1,1,1,0,0,1,1)
14323 || INSN(11,4) == BITS8(1,1,1,1,0,0,0,1))) {
sewardjb706a0f2011-07-19 08:20:24 +000014324 IRTemp dst = newTemp(Ity_I32);
sewardj6c299f32009-12-31 18:00:12 +000014325 UInt link = (INSN(11,4) >> 1) & 1;
14326 UInt rM = INSN(3,0);
14327 // we don't decode the case (link && rM == 15), as that's
14328 // Unpredictable.
14329 if (!(link && rM == 15)) {
14330 if (condT != IRTemp_INVALID) {
sewardjd2664472010-08-22 12:44:20 +000014331 mk_skip_over_A32_if_cond_is_false( condT );
sewardj6c299f32009-12-31 18:00:12 +000014332 }
sewardjd2664472010-08-22 12:44:20 +000014333 // rM contains an interworking address exactly as we require
14334 // (with continuation CPSR.T in bit 0), so we can use it
14335 // as-is, with no masking.
sewardjb706a0f2011-07-19 08:20:24 +000014336 assign( dst, getIRegA(rM) );
sewardj6c299f32009-12-31 18:00:12 +000014337 if (link) {
sewardjd2664472010-08-22 12:44:20 +000014338 putIRegA( 14, mkU32(guest_R15_curr_instr_notENC + 4),
14339 IRTemp_INVALID/*because AL*/, Ijk_Boring );
sewardj6c299f32009-12-31 18:00:12 +000014340 }
sewardjc6f970f2012-04-02 21:54:49 +000014341 llPutIReg(15, mkexpr(dst));
14342 dres.jk_StopHere = link ? Ijk_Call
14343 : (rM == 14 ? Ijk_Ret : Ijk_Boring);
14344 dres.whatNext = Dis_StopHere;
sewardj6c299f32009-12-31 18:00:12 +000014345 if (condT == IRTemp_INVALID) {
14346 DIP("b%sx r%u\n", link ? "l" : "", rM);
14347 } else {
14348 DIP("b%sx%s r%u\n", link ? "l" : "", nCC(INSN_COND), rM);
14349 }
sewardjc2c87162004-11-25 13:07:02 +000014350 goto decode_success;
14351 }
sewardj6c299f32009-12-31 18:00:12 +000014352 /* else: (link && rM == 15): just fall through */
sewardjc2c87162004-11-25 13:07:02 +000014353 }
cerionc60c01e2004-12-02 20:19:22 +000014354
sewardjd2664472010-08-22 12:44:20 +000014355 /* --- NB: ARM interworking branches are in NV space, hence
14356 are handled elsewhere by decode_NV_instruction.
14357 ---
14358 */
14359
sewardj6c299f32009-12-31 18:00:12 +000014360 /* --------------------- Clz --------------------- */
14361 // CLZ
14362 if (INSN(27,20) == BITS8(0,0,0,1,0,1,1,0)
14363 && INSN(19,16) == BITS4(1,1,1,1)
14364 && INSN(11,4) == BITS8(1,1,1,1,0,0,0,1)) {
14365 UInt rD = INSN(15,12);
14366 UInt rM = INSN(3,0);
14367 IRTemp arg = newTemp(Ity_I32);
14368 IRTemp res = newTemp(Ity_I32);
sewardjd2664472010-08-22 12:44:20 +000014369 assign(arg, getIRegA(rM));
florian99dd03e2013-01-29 03:56:06 +000014370 assign(res, IRExpr_ITE(
sewardj009230b2013-01-26 11:47:55 +000014371 binop(Iop_CmpEQ32, mkexpr(arg), mkU32(0)),
florian99dd03e2013-01-29 03:56:06 +000014372 mkU32(32),
14373 unop(Iop_Clz32, mkexpr(arg))
sewardj6c299f32009-12-31 18:00:12 +000014374 ));
sewardjd2664472010-08-22 12:44:20 +000014375 putIRegA(rD, mkexpr(res), condT, Ijk_Boring);
sewardj6c299f32009-12-31 18:00:12 +000014376 DIP("clz%s r%u, r%u\n", nCC(INSN_COND), rD, rM);
14377 goto decode_success;
cerionc60c01e2004-12-02 20:19:22 +000014378 }
cerionc60c01e2004-12-02 20:19:22 +000014379
sewardj6c299f32009-12-31 18:00:12 +000014380 /* --------------------- Mul etc --------------------- */
14381 // MUL
14382 if (BITS8(0,0,0,0,0,0,0,0) == (INSN(27,20) & BITS8(1,1,1,1,1,1,1,0))
14383 && INSN(15,12) == BITS4(0,0,0,0)
14384 && INSN(7,4) == BITS4(1,0,0,1)) {
14385 UInt bitS = (insn >> 20) & 1; /* 20:20 */
14386 UInt rD = INSN(19,16);
14387 UInt rS = INSN(11,8);
14388 UInt rM = INSN(3,0);
14389 if (rD == 15 || rM == 15 || rS == 15) {
14390 /* Unpredictable; don't decode; fall through */
14391 } else {
14392 IRTemp argL = newTemp(Ity_I32);
14393 IRTemp argR = newTemp(Ity_I32);
14394 IRTemp res = newTemp(Ity_I32);
14395 IRTemp oldC = IRTemp_INVALID;
14396 IRTemp oldV = IRTemp_INVALID;
sewardjd2664472010-08-22 12:44:20 +000014397 assign( argL, getIRegA(rM));
14398 assign( argR, getIRegA(rS));
sewardj6c299f32009-12-31 18:00:12 +000014399 assign( res, binop(Iop_Mul32, mkexpr(argL), mkexpr(argR)) );
14400 if (bitS) {
14401 oldC = newTemp(Ity_I32);
14402 assign(oldC, mk_armg_calculate_flag_c());
14403 oldV = newTemp(Ity_I32);
14404 assign(oldV, mk_armg_calculate_flag_v());
cerionb85e8bb2005-02-16 08:54:33 +000014405 }
sewardj6c299f32009-12-31 18:00:12 +000014406 // now update guest state
sewardjd2664472010-08-22 12:44:20 +000014407 putIRegA( rD, mkexpr(res), condT, Ijk_Boring );
sewardj6c299f32009-12-31 18:00:12 +000014408 if (bitS) {
14409 IRTemp pair = newTemp(Ity_I32);
14410 assign( pair, binop(Iop_Or32,
14411 binop(Iop_Shl32, mkexpr(oldC), mkU8(1)),
14412 mkexpr(oldV)) );
14413 setFlags_D1_ND( ARMG_CC_OP_MUL, res, pair, condT );
cerionb85e8bb2005-02-16 08:54:33 +000014414 }
sewardj6c299f32009-12-31 18:00:12 +000014415 DIP("mul%c%s r%u, r%u, r%u\n",
14416 bitS ? 's' : ' ', nCC(INSN_COND), rD, rM, rS);
14417 goto decode_success;
cerionb85e8bb2005-02-16 08:54:33 +000014418 }
sewardj6c299f32009-12-31 18:00:12 +000014419 /* fall through */
14420 }
cerionf7da63d2004-12-09 19:04:57 +000014421
sewardj8bde7f12013-04-11 13:57:43 +000014422 /* --------------------- Integer Divides --------------------- */
14423 // SDIV
14424 if (BITS8(0,1,1,1,0,0,0,1) == INSN(27,20)
14425 && INSN(15,12) == BITS4(1,1,1,1)
14426 && INSN(7,4) == BITS4(0,0,0,1)) {
14427 UInt rD = INSN(19,16);
14428 UInt rM = INSN(11,8);
14429 UInt rN = INSN(3,0);
14430 if (rD == 15 || rM == 15 || rN == 15) {
14431 /* Unpredictable; don't decode; fall through */
14432 } else {
14433 IRTemp res = newTemp(Ity_I32);
14434 IRTemp argL = newTemp(Ity_I32);
14435 IRTemp argR = newTemp(Ity_I32);
14436 assign(argL, getIRegA(rN));
14437 assign(argR, getIRegA(rM));
14438 assign(res, binop(Iop_DivS32, mkexpr(argL), mkexpr(argR)));
14439 putIRegA(rD, mkexpr(res), condT, Ijk_Boring);
14440 DIP("sdiv r%u, r%u, r%u\n", rD, rN, rM);
14441 goto decode_success;
14442 }
14443 }
14444
14445 // UDIV
14446 if (BITS8(0,1,1,1,0,0,1,1) == INSN(27,20)
14447 && INSN(15,12) == BITS4(1,1,1,1)
14448 && INSN(7,4) == BITS4(0,0,0,1)) {
14449 UInt rD = INSN(19,16);
14450 UInt rM = INSN(11,8);
14451 UInt rN = INSN(3,0);
14452 if (rD == 15 || rM == 15 || rN == 15) {
14453 /* Unpredictable; don't decode; fall through */
14454 } else {
14455 IRTemp res = newTemp(Ity_I32);
14456 IRTemp argL = newTemp(Ity_I32);
14457 IRTemp argR = newTemp(Ity_I32);
14458 assign(argL, getIRegA(rN));
14459 assign(argR, getIRegA(rM));
14460 assign(res, binop(Iop_DivU32, mkexpr(argL), mkexpr(argR)));
14461 putIRegA(rD, mkexpr(res), condT, Ijk_Boring);
14462 DIP("udiv r%u, r%u, r%u\n", rD, rN, rM);
14463 goto decode_success;
14464 }
14465 }
14466
sewardj6c299f32009-12-31 18:00:12 +000014467 // MLA, MLS
14468 if (BITS8(0,0,0,0,0,0,1,0) == (INSN(27,20) & BITS8(1,1,1,1,1,0,1,0))
14469 && INSN(7,4) == BITS4(1,0,0,1)) {
14470 UInt bitS = (insn >> 20) & 1; /* 20:20 */
14471 UInt isMLS = (insn >> 22) & 1; /* 22:22 */
14472 UInt rD = INSN(19,16);
14473 UInt rN = INSN(15,12);
14474 UInt rS = INSN(11,8);
14475 UInt rM = INSN(3,0);
14476 if (bitS == 1 && isMLS == 1) {
14477 /* This isn't allowed (MLS that sets flags). don't decode;
14478 fall through */
cerionb85e8bb2005-02-16 08:54:33 +000014479 }
sewardj6c299f32009-12-31 18:00:12 +000014480 else
14481 if (rD == 15 || rM == 15 || rS == 15 || rN == 15) {
14482 /* Unpredictable; don't decode; fall through */
14483 } else {
14484 IRTemp argL = newTemp(Ity_I32);
14485 IRTemp argR = newTemp(Ity_I32);
14486 IRTemp argP = newTemp(Ity_I32);
14487 IRTemp res = newTemp(Ity_I32);
14488 IRTemp oldC = IRTemp_INVALID;
14489 IRTemp oldV = IRTemp_INVALID;
sewardjd2664472010-08-22 12:44:20 +000014490 assign( argL, getIRegA(rM));
14491 assign( argR, getIRegA(rS));
14492 assign( argP, getIRegA(rN));
sewardj6c299f32009-12-31 18:00:12 +000014493 assign( res, binop(isMLS ? Iop_Sub32 : Iop_Add32,
14494 mkexpr(argP),
14495 binop(Iop_Mul32, mkexpr(argL), mkexpr(argR)) ));
14496 if (bitS) {
14497 vassert(!isMLS); // guaranteed above
14498 oldC = newTemp(Ity_I32);
14499 assign(oldC, mk_armg_calculate_flag_c());
14500 oldV = newTemp(Ity_I32);
14501 assign(oldV, mk_armg_calculate_flag_v());
14502 }
14503 // now update guest state
sewardjd2664472010-08-22 12:44:20 +000014504 putIRegA( rD, mkexpr(res), condT, Ijk_Boring );
sewardj6c299f32009-12-31 18:00:12 +000014505 if (bitS) {
14506 IRTemp pair = newTemp(Ity_I32);
14507 assign( pair, binop(Iop_Or32,
14508 binop(Iop_Shl32, mkexpr(oldC), mkU8(1)),
14509 mkexpr(oldV)) );
14510 setFlags_D1_ND( ARMG_CC_OP_MUL, res, pair, condT );
14511 }
14512 DIP("ml%c%c%s r%u, r%u, r%u, r%u\n",
sewardjd2664472010-08-22 12:44:20 +000014513 isMLS ? 's' : 'a', bitS ? 's' : ' ',
14514 nCC(INSN_COND), rD, rM, rS, rN);
sewardj6c299f32009-12-31 18:00:12 +000014515 goto decode_success;
14516 }
14517 /* fall through */
14518 }
14519
14520 // SMULL, UMULL
14521 if (BITS8(0,0,0,0,1,0,0,0) == (INSN(27,20) & BITS8(1,1,1,1,1,0,1,0))
14522 && INSN(7,4) == BITS4(1,0,0,1)) {
14523 UInt bitS = (insn >> 20) & 1; /* 20:20 */
14524 UInt rDhi = INSN(19,16);
14525 UInt rDlo = INSN(15,12);
14526 UInt rS = INSN(11,8);
14527 UInt rM = INSN(3,0);
14528 UInt isS = (INSN(27,20) >> 2) & 1; /* 22:22 */
14529 if (rDhi == 15 || rDlo == 15 || rM == 15 || rS == 15 || rDhi == rDlo) {
14530 /* Unpredictable; don't decode; fall through */
14531 } else {
14532 IRTemp argL = newTemp(Ity_I32);
14533 IRTemp argR = newTemp(Ity_I32);
14534 IRTemp res = newTemp(Ity_I64);
14535 IRTemp resHi = newTemp(Ity_I32);
14536 IRTemp resLo = newTemp(Ity_I32);
14537 IRTemp oldC = IRTemp_INVALID;
14538 IRTemp oldV = IRTemp_INVALID;
14539 IROp mulOp = isS ? Iop_MullS32 : Iop_MullU32;
sewardjd2664472010-08-22 12:44:20 +000014540 assign( argL, getIRegA(rM));
14541 assign( argR, getIRegA(rS));
sewardj6c299f32009-12-31 18:00:12 +000014542 assign( res, binop(mulOp, mkexpr(argL), mkexpr(argR)) );
14543 assign( resHi, unop(Iop_64HIto32, mkexpr(res)) );
14544 assign( resLo, unop(Iop_64to32, mkexpr(res)) );
14545 if (bitS) {
14546 oldC = newTemp(Ity_I32);
14547 assign(oldC, mk_armg_calculate_flag_c());
14548 oldV = newTemp(Ity_I32);
14549 assign(oldV, mk_armg_calculate_flag_v());
14550 }
14551 // now update guest state
sewardjd2664472010-08-22 12:44:20 +000014552 putIRegA( rDhi, mkexpr(resHi), condT, Ijk_Boring );
14553 putIRegA( rDlo, mkexpr(resLo), condT, Ijk_Boring );
sewardj6c299f32009-12-31 18:00:12 +000014554 if (bitS) {
14555 IRTemp pair = newTemp(Ity_I32);
14556 assign( pair, binop(Iop_Or32,
14557 binop(Iop_Shl32, mkexpr(oldC), mkU8(1)),
14558 mkexpr(oldV)) );
14559 setFlags_D1_D2_ND( ARMG_CC_OP_MULL, resLo, resHi, pair, condT );
14560 }
14561 DIP("%cmull%c%s r%u, r%u, r%u, r%u\n",
14562 isS ? 's' : 'u', bitS ? 's' : ' ',
14563 nCC(INSN_COND), rDlo, rDhi, rM, rS);
14564 goto decode_success;
14565 }
14566 /* fall through */
14567 }
14568
14569 // SMLAL, UMLAL
14570 if (BITS8(0,0,0,0,1,0,1,0) == (INSN(27,20) & BITS8(1,1,1,1,1,0,1,0))
14571 && INSN(7,4) == BITS4(1,0,0,1)) {
14572 UInt bitS = (insn >> 20) & 1; /* 20:20 */
14573 UInt rDhi = INSN(19,16);
14574 UInt rDlo = INSN(15,12);
14575 UInt rS = INSN(11,8);
14576 UInt rM = INSN(3,0);
14577 UInt isS = (INSN(27,20) >> 2) & 1; /* 22:22 */
14578 if (rDhi == 15 || rDlo == 15 || rM == 15 || rS == 15 || rDhi == rDlo) {
14579 /* Unpredictable; don't decode; fall through */
14580 } else {
14581 IRTemp argL = newTemp(Ity_I32);
14582 IRTemp argR = newTemp(Ity_I32);
14583 IRTemp old = newTemp(Ity_I64);
14584 IRTemp res = newTemp(Ity_I64);
14585 IRTemp resHi = newTemp(Ity_I32);
14586 IRTemp resLo = newTemp(Ity_I32);
14587 IRTemp oldC = IRTemp_INVALID;
14588 IRTemp oldV = IRTemp_INVALID;
14589 IROp mulOp = isS ? Iop_MullS32 : Iop_MullU32;
sewardjd2664472010-08-22 12:44:20 +000014590 assign( argL, getIRegA(rM));
14591 assign( argR, getIRegA(rS));
14592 assign( old, binop(Iop_32HLto64, getIRegA(rDhi), getIRegA(rDlo)) );
sewardj6c299f32009-12-31 18:00:12 +000014593 assign( res, binop(Iop_Add64,
14594 mkexpr(old),
14595 binop(mulOp, mkexpr(argL), mkexpr(argR))) );
14596 assign( resHi, unop(Iop_64HIto32, mkexpr(res)) );
14597 assign( resLo, unop(Iop_64to32, mkexpr(res)) );
14598 if (bitS) {
14599 oldC = newTemp(Ity_I32);
14600 assign(oldC, mk_armg_calculate_flag_c());
14601 oldV = newTemp(Ity_I32);
14602 assign(oldV, mk_armg_calculate_flag_v());
14603 }
14604 // now update guest state
sewardjd2664472010-08-22 12:44:20 +000014605 putIRegA( rDhi, mkexpr(resHi), condT, Ijk_Boring );
14606 putIRegA( rDlo, mkexpr(resLo), condT, Ijk_Boring );
sewardj6c299f32009-12-31 18:00:12 +000014607 if (bitS) {
14608 IRTemp pair = newTemp(Ity_I32);
14609 assign( pair, binop(Iop_Or32,
14610 binop(Iop_Shl32, mkexpr(oldC), mkU8(1)),
14611 mkexpr(oldV)) );
14612 setFlags_D1_D2_ND( ARMG_CC_OP_MULL, resLo, resHi, pair, condT );
14613 }
14614 DIP("%cmlal%c%s r%u, r%u, r%u, r%u\n",
14615 isS ? 's' : 'u', bitS ? 's' : ' ', nCC(INSN_COND),
14616 rDlo, rDhi, rM, rS);
14617 goto decode_success;
14618 }
14619 /* fall through */
14620 }
14621
sewardjabf39452012-12-12 00:16:41 +000014622 // UMAAL
14623 if (BITS8(0,0,0,0,0,1,0,0) == INSN(27,20) && INSN(7,4) == BITS4(1,0,0,1)) {
14624 UInt rDhi = INSN(19,16);
14625 UInt rDlo = INSN(15,12);
14626 UInt rM = INSN(11,8);
14627 UInt rN = INSN(3,0);
14628 if (rDlo == 15 || rDhi == 15 || rN == 15 || rM == 15 || rDhi == rDlo) {
14629 /* Unpredictable; don't decode; fall through */
14630 } else {
14631 IRTemp argN = newTemp(Ity_I32);
14632 IRTemp argM = newTemp(Ity_I32);
14633 IRTemp argDhi = newTemp(Ity_I32);
14634 IRTemp argDlo = newTemp(Ity_I32);
14635 IRTemp res = newTemp(Ity_I64);
14636 IRTemp resHi = newTemp(Ity_I32);
14637 IRTemp resLo = newTemp(Ity_I32);
14638 assign( argN, getIRegA(rN) );
14639 assign( argM, getIRegA(rM) );
14640 assign( argDhi, getIRegA(rDhi) );
14641 assign( argDlo, getIRegA(rDlo) );
14642 assign( res,
14643 binop(Iop_Add64,
14644 binop(Iop_Add64,
14645 binop(Iop_MullU32, mkexpr(argN), mkexpr(argM)),
14646 unop(Iop_32Uto64, mkexpr(argDhi))),
14647 unop(Iop_32Uto64, mkexpr(argDlo))) );
14648 assign( resHi, unop(Iop_64HIto32, mkexpr(res)) );
14649 assign( resLo, unop(Iop_64to32, mkexpr(res)) );
14650 // now update guest state
14651 putIRegA( rDhi, mkexpr(resHi), condT, Ijk_Boring );
14652 putIRegA( rDlo, mkexpr(resLo), condT, Ijk_Boring );
14653 DIP("umaal %s r%u, r%u, r%u, r%u\n",
14654 nCC(INSN_COND), rDlo, rDhi, rN, rM);
14655 goto decode_success;
14656 }
14657 /* fall through */
14658 }
14659
sewardj6c299f32009-12-31 18:00:12 +000014660 /* --------------------- Msr etc --------------------- */
14661
sewardj1f139f52010-08-29 12:33:02 +000014662 // MSR apsr, #imm
14663 if (INSN(27,20) == BITS8(0,0,1,1,0,0,1,0)
14664 && INSN(17,12) == BITS6(0,0,1,1,1,1)) {
14665 UInt write_ge = INSN(18,18);
14666 UInt write_nzcvq = INSN(19,19);
14667 if (write_nzcvq || write_ge) {
sewardj6c299f32009-12-31 18:00:12 +000014668 UInt imm = (INSN(11,0) >> 0) & 0xFF;
14669 UInt rot = 2 * ((INSN(11,0) >> 8) & 0xF);
14670 IRTemp immT = newTemp(Ity_I32);
14671 vassert(rot <= 30);
14672 imm = ROR32(imm, rot);
sewardj1f139f52010-08-29 12:33:02 +000014673 assign(immT, mkU32(imm));
14674 desynthesise_APSR( write_nzcvq, write_ge, immT, condT );
14675 DIP("msr%s cpsr%s%sf, #0x%08x\n", nCC(INSN_COND),
14676 write_nzcvq ? "f" : "", write_ge ? "g" : "", imm);
sewardj6c299f32009-12-31 18:00:12 +000014677 goto decode_success;
14678 }
14679 /* fall through */
14680 }
14681
sewardj1f139f52010-08-29 12:33:02 +000014682 // MSR apsr, reg
14683 if (INSN(27,20) == BITS8(0,0,0,1,0,0,1,0)
14684 && INSN(17,12) == BITS6(0,0,1,1,1,1)
14685 && INSN(11,4) == BITS8(0,0,0,0,0,0,0,0)) {
14686 UInt rN = INSN(3,0);
14687 UInt write_ge = INSN(18,18);
14688 UInt write_nzcvq = INSN(19,19);
14689 if (rN != 15 && (write_nzcvq || write_ge)) {
14690 IRTemp rNt = newTemp(Ity_I32);
14691 assign(rNt, getIRegA(rN));
14692 desynthesise_APSR( write_nzcvq, write_ge, rNt, condT );
14693 DIP("msr%s cpsr_%s%s, r%u\n", nCC(INSN_COND),
14694 write_nzcvq ? "f" : "", write_ge ? "g" : "", rN);
sewardjd2664472010-08-22 12:44:20 +000014695 goto decode_success;
14696 }
14697 /* fall through */
14698 }
14699
14700 // MRS rD, cpsr
sewardj1f139f52010-08-29 12:33:02 +000014701 if ((insn & 0x0FFF0FFF) == 0x010F0000) {
sewardj6c299f32009-12-31 18:00:12 +000014702 UInt rD = INSN(15,12);
sewardj1f139f52010-08-29 12:33:02 +000014703 if (rD != 15) {
14704 IRTemp apsr = synthesise_APSR();
14705 putIRegA( rD, mkexpr(apsr), condT, Ijk_Boring );
sewardj6c299f32009-12-31 18:00:12 +000014706 DIP("mrs%s r%u, cpsr\n", nCC(INSN_COND), rD);
14707 goto decode_success;
14708 }
14709 /* fall through */
14710 }
14711
14712 /* --------------------- Svc --------------------- */
14713 if (BITS8(1,1,1,1,0,0,0,0) == (INSN(27,20) & BITS8(1,1,1,1,0,0,0,0))) {
14714 UInt imm24 = (insn >> 0) & 0xFFFFFF;
14715 if (imm24 == 0) {
14716 /* A syscall. We can't do this conditionally, hence: */
14717 if (condT != IRTemp_INVALID) {
sewardjd2664472010-08-22 12:44:20 +000014718 mk_skip_over_A32_if_cond_is_false( condT );
sewardj6c299f32009-12-31 18:00:12 +000014719 }
14720 // AL after here
sewardjc6f970f2012-04-02 21:54:49 +000014721 llPutIReg(15, mkU32( guest_R15_curr_instr_notENC + 4 ));
14722 dres.jk_StopHere = Ijk_Sys_syscall;
14723 dres.whatNext = Dis_StopHere;
sewardj6c299f32009-12-31 18:00:12 +000014724 DIP("svc%s #0x%08x\n", nCC(INSN_COND), imm24);
14725 goto decode_success;
14726 }
14727 /* fall through */
14728 }
14729
14730 /* ------------------------ swp ------------------------ */
14731
14732 // SWP, SWPB
14733 if (BITS8(0,0,0,1,0,0,0,0) == (INSN(27,20) & BITS8(1,1,1,1,1,0,1,1))
14734 && BITS4(0,0,0,0) == INSN(11,8)
14735 && BITS4(1,0,0,1) == INSN(7,4)) {
14736 UInt rN = INSN(19,16);
14737 UInt rD = INSN(15,12);
14738 UInt rM = INSN(3,0);
14739 IRTemp tRn = newTemp(Ity_I32);
14740 IRTemp tNew = newTemp(Ity_I32);
14741 IRTemp tOld = IRTemp_INVALID;
14742 IRTemp tSC1 = newTemp(Ity_I1);
14743 UInt isB = (insn >> 22) & 1;
14744
14745 if (rD == 15 || rN == 15 || rM == 15 || rN == rM || rN == rD) {
14746 /* undecodable; fall through */
14747 } else {
14748 /* make unconditional */
14749 if (condT != IRTemp_INVALID) {
sewardjd2664472010-08-22 12:44:20 +000014750 mk_skip_over_A32_if_cond_is_false( condT );
sewardj6c299f32009-12-31 18:00:12 +000014751 condT = IRTemp_INVALID;
14752 }
14753 /* Ok, now we're unconditional. Generate a LL-SC loop. */
sewardjd2664472010-08-22 12:44:20 +000014754 assign(tRn, getIRegA(rN));
14755 assign(tNew, getIRegA(rM));
sewardj6c299f32009-12-31 18:00:12 +000014756 if (isB) {
14757 /* swpb */
14758 tOld = newTemp(Ity_I8);
14759 stmt( IRStmt_LLSC(Iend_LE, tOld, mkexpr(tRn),
14760 NULL/*=>isLL*/) );
14761 stmt( IRStmt_LLSC(Iend_LE, tSC1, mkexpr(tRn),
14762 unop(Iop_32to8, mkexpr(tNew))) );
14763 } else {
14764 /* swp */
14765 tOld = newTemp(Ity_I32);
14766 stmt( IRStmt_LLSC(Iend_LE, tOld, mkexpr(tRn),
14767 NULL/*=>isLL*/) );
14768 stmt( IRStmt_LLSC(Iend_LE, tSC1, mkexpr(tRn),
14769 mkexpr(tNew)) );
14770 }
14771 stmt( IRStmt_Exit(unop(Iop_Not1, mkexpr(tSC1)),
14772 /*Ijk_NoRedir*/Ijk_Boring,
sewardjc6f970f2012-04-02 21:54:49 +000014773 IRConst_U32(guest_R15_curr_instr_notENC),
14774 OFFB_R15T ));
sewardjd2664472010-08-22 12:44:20 +000014775 putIRegA(rD, isB ? unop(Iop_8Uto32, mkexpr(tOld)) : mkexpr(tOld),
14776 IRTemp_INVALID, Ijk_Boring);
sewardj6c299f32009-12-31 18:00:12 +000014777 DIP("swp%s%s r%u, r%u, [r%u]\n",
14778 isB ? "b" : "", nCC(INSN_COND), rD, rM, rN);
14779 goto decode_success;
14780 }
14781 /* fall through */
14782 }
14783
14784 /* ----------------------------------------------------------- */
sewardj6c299f32009-12-31 18:00:12 +000014785 /* -- ARMv6 instructions -- */
14786 /* ----------------------------------------------------------- */
14787
sewardjff7f5b72011-07-11 11:43:38 +000014788 /* ------------------- {ldr,str}ex{,b,h,d} ------------------- */
sewardj6c299f32009-12-31 18:00:12 +000014789
sewardjff7f5b72011-07-11 11:43:38 +000014790 // LDREXD, LDREX, LDREXH, LDREXB
14791 if (0x01900F9F == (insn & 0x0F900FFF)) {
14792 UInt rT = INSN(15,12);
14793 UInt rN = INSN(19,16);
14794 IRType ty = Ity_INVALID;
14795 IROp widen = Iop_INVALID;
florian55085f82012-11-21 00:36:55 +000014796 const HChar* nm = NULL;
sewardjff7f5b72011-07-11 11:43:38 +000014797 Bool valid = True;
14798 switch (INSN(22,21)) {
14799 case 0: nm = ""; ty = Ity_I32; break;
14800 case 1: nm = "d"; ty = Ity_I64; break;
14801 case 2: nm = "b"; ty = Ity_I8; widen = Iop_8Uto32; break;
14802 case 3: nm = "h"; ty = Ity_I16; widen = Iop_16Uto32; break;
14803 default: vassert(0);
14804 }
14805 if (ty == Ity_I32 || ty == Ity_I16 || ty == Ity_I8) {
14806 if (rT == 15 || rN == 15)
14807 valid = False;
sewardj6c299f32009-12-31 18:00:12 +000014808 } else {
sewardjff7f5b72011-07-11 11:43:38 +000014809 vassert(ty == Ity_I64);
14810 if ((rT & 1) == 1 || rT == 14 || rN == 15)
14811 valid = False;
14812 }
14813 if (valid) {
sewardj6c299f32009-12-31 18:00:12 +000014814 IRTemp res;
14815 /* make unconditional */
14816 if (condT != IRTemp_INVALID) {
sewardjff7f5b72011-07-11 11:43:38 +000014817 mk_skip_over_A32_if_cond_is_false( condT );
14818 condT = IRTemp_INVALID;
sewardj6c299f32009-12-31 18:00:12 +000014819 }
14820 /* Ok, now we're unconditional. Do the load. */
sewardjff7f5b72011-07-11 11:43:38 +000014821 res = newTemp(ty);
14822 // FIXME: assumes little-endian guest
sewardjd2664472010-08-22 12:44:20 +000014823 stmt( IRStmt_LLSC(Iend_LE, res, getIRegA(rN),
14824 NULL/*this is a load*/) );
sewardjff7f5b72011-07-11 11:43:38 +000014825 if (ty == Ity_I64) {
14826 // FIXME: assumes little-endian guest
14827 putIRegA(rT+0, unop(Iop_64to32, mkexpr(res)),
14828 IRTemp_INVALID, Ijk_Boring);
14829 putIRegA(rT+1, unop(Iop_64HIto32, mkexpr(res)),
14830 IRTemp_INVALID, Ijk_Boring);
14831 DIP("ldrex%s%s r%u, r%u, [r%u]\n",
14832 nm, nCC(INSN_COND), rT+0, rT+1, rN);
14833 } else {
14834 putIRegA(rT, widen == Iop_INVALID
14835 ? mkexpr(res) : unop(widen, mkexpr(res)),
14836 IRTemp_INVALID, Ijk_Boring);
14837 DIP("ldrex%s%s r%u, [r%u]\n", nm, nCC(INSN_COND), rT, rN);
14838 }
sewardj6c299f32009-12-31 18:00:12 +000014839 goto decode_success;
14840 }
sewardjff7f5b72011-07-11 11:43:38 +000014841 /* undecodable; fall through */
sewardj6c299f32009-12-31 18:00:12 +000014842 }
14843
sewardjff7f5b72011-07-11 11:43:38 +000014844 // STREXD, STREX, STREXH, STREXB
14845 if (0x01800F90 == (insn & 0x0F900FF0)) {
14846 UInt rT = INSN(3,0);
14847 UInt rN = INSN(19,16);
14848 UInt rD = INSN(15,12);
14849 IRType ty = Ity_INVALID;
14850 IROp narrow = Iop_INVALID;
florian55085f82012-11-21 00:36:55 +000014851 const HChar* nm = NULL;
sewardjff7f5b72011-07-11 11:43:38 +000014852 Bool valid = True;
14853 switch (INSN(22,21)) {
14854 case 0: nm = ""; ty = Ity_I32; break;
14855 case 1: nm = "d"; ty = Ity_I64; break;
14856 case 2: nm = "b"; ty = Ity_I8; narrow = Iop_32to8; break;
14857 case 3: nm = "h"; ty = Ity_I16; narrow = Iop_32to16; break;
14858 default: vassert(0);
14859 }
14860 if (ty == Ity_I32 || ty == Ity_I16 || ty == Ity_I8) {
14861 if (rD == 15 || rN == 15 || rT == 15
14862 || rD == rN || rD == rT)
14863 valid = False;
sewardj6c299f32009-12-31 18:00:12 +000014864 } else {
sewardjff7f5b72011-07-11 11:43:38 +000014865 vassert(ty == Ity_I64);
14866 if (rD == 15 || (rT & 1) == 1 || rT == 14 || rN == 15
14867 || rD == rN || rD == rT || rD == rT+1)
14868 valid = False;
14869 }
14870 if (valid) {
14871 IRTemp resSC1, resSC32, data;
sewardj6c299f32009-12-31 18:00:12 +000014872 /* make unconditional */
14873 if (condT != IRTemp_INVALID) {
sewardjd2664472010-08-22 12:44:20 +000014874 mk_skip_over_A32_if_cond_is_false( condT );
sewardj6c299f32009-12-31 18:00:12 +000014875 condT = IRTemp_INVALID;
14876 }
sewardj6c299f32009-12-31 18:00:12 +000014877 /* Ok, now we're unconditional. Do the store. */
sewardjff7f5b72011-07-11 11:43:38 +000014878 data = newTemp(ty);
14879 assign(data,
14880 ty == Ity_I64
14881 // FIXME: assumes little-endian guest
14882 ? binop(Iop_32HLto64, getIRegA(rT+1), getIRegA(rT+0))
14883 : narrow == Iop_INVALID
14884 ? getIRegA(rT)
14885 : unop(narrow, getIRegA(rT)));
sewardj6c299f32009-12-31 18:00:12 +000014886 resSC1 = newTemp(Ity_I1);
sewardjff7f5b72011-07-11 11:43:38 +000014887 // FIXME: assumes little-endian guest
14888 stmt( IRStmt_LLSC(Iend_LE, resSC1, getIRegA(rN), mkexpr(data)) );
sewardj6c299f32009-12-31 18:00:12 +000014889
14890 /* Set rD to 1 on failure, 0 on success. Currently we have
14891 resSC1 == 0 on failure, 1 on success. */
14892 resSC32 = newTemp(Ity_I32);
14893 assign(resSC32,
14894 unop(Iop_1Uto32, unop(Iop_Not1, mkexpr(resSC1))));
14895
sewardjd2664472010-08-22 12:44:20 +000014896 putIRegA(rD, mkexpr(resSC32),
14897 IRTemp_INVALID, Ijk_Boring);
sewardjff7f5b72011-07-11 11:43:38 +000014898 if (ty == Ity_I64) {
14899 DIP("strex%s%s r%u, r%u, r%u, [r%u]\n",
14900 nm, nCC(INSN_COND), rD, rT, rT+1, rN);
14901 } else {
14902 DIP("strex%s%s r%u, r%u, [r%u]\n",
14903 nm, nCC(INSN_COND), rD, rT, rN);
14904 }
sewardj6c299f32009-12-31 18:00:12 +000014905 goto decode_success;
14906 }
14907 /* fall through */
14908 }
14909
14910 /* --------------------- movw, movt --------------------- */
14911 if (0x03000000 == (insn & 0x0FF00000)
14912 || 0x03400000 == (insn & 0x0FF00000)) /* pray for CSE */ {
14913 UInt rD = INSN(15,12);
14914 UInt imm16 = (insn & 0xFFF) | ((insn >> 4) & 0x0000F000);
14915 UInt isT = (insn >> 22) & 1;
14916 if (rD == 15) {
14917 /* forget it */
14918 } else {
14919 if (isT) {
sewardjd2664472010-08-22 12:44:20 +000014920 putIRegA(rD,
14921 binop(Iop_Or32,
14922 binop(Iop_And32, getIRegA(rD), mkU32(0xFFFF)),
14923 mkU32(imm16 << 16)),
14924 condT, Ijk_Boring);
sewardj6c299f32009-12-31 18:00:12 +000014925 DIP("movt%s r%u, #0x%04x\n", nCC(INSN_COND), rD, imm16);
14926 goto decode_success;
14927 } else {
sewardjd2664472010-08-22 12:44:20 +000014928 putIRegA(rD, mkU32(imm16), condT, Ijk_Boring);
sewardj6c299f32009-12-31 18:00:12 +000014929 DIP("movw%s r%u, #0x%04x\n", nCC(INSN_COND), rD, imm16);
14930 goto decode_success;
14931 }
14932 }
14933 /* fall through */
14934 }
14935
sewardj1f139f52010-08-29 12:33:02 +000014936 /* ----------- uxtb, sxtb, uxth, sxth, uxtb16, sxtb16 ----------- */
14937 /* FIXME: this is an exact duplicate of the Thumb version. They
14938 should be commoned up. */
sewardj6c299f32009-12-31 18:00:12 +000014939 if (BITS8(0,1,1,0,1, 0,0,0) == (INSN(27,20) & BITS8(1,1,1,1,1,0,0,0))
14940 && BITS4(1,1,1,1) == INSN(19,16)
14941 && BITS4(0,1,1,1) == INSN(7,4)
14942 && BITS4(0,0, 0,0) == (INSN(11,8) & BITS4(0,0,1,1))) {
14943 UInt subopc = INSN(27,20) & BITS8(0,0,0,0,0, 1,1,1);
14944 if (subopc != BITS4(0,0,0,1) && subopc != BITS4(0,1,0,1)) {
14945 Int rot = (INSN(11,8) >> 2) & 3;
14946 UInt rM = INSN(3,0);
14947 UInt rD = INSN(15,12);
14948 IRTemp srcT = newTemp(Ity_I32);
14949 IRTemp rotT = newTemp(Ity_I32);
14950 IRTemp dstT = newTemp(Ity_I32);
florian55085f82012-11-21 00:36:55 +000014951 const HChar* nm = "???";
sewardjd2664472010-08-22 12:44:20 +000014952 assign(srcT, getIRegA(rM));
sewardj6c299f32009-12-31 18:00:12 +000014953 assign(rotT, genROR32(srcT, 8 * rot)); /* 0, 8, 16 or 24 only */
14954 switch (subopc) {
14955 case BITS4(0,1,1,0): // UXTB
14956 assign(dstT, unop(Iop_8Uto32, unop(Iop_32to8, mkexpr(rotT))));
14957 nm = "uxtb";
14958 break;
14959 case BITS4(0,0,1,0): // SXTB
14960 assign(dstT, unop(Iop_8Sto32, unop(Iop_32to8, mkexpr(rotT))));
14961 nm = "sxtb";
14962 break;
14963 case BITS4(0,1,1,1): // UXTH
14964 assign(dstT, unop(Iop_16Uto32, unop(Iop_32to16, mkexpr(rotT))));
14965 nm = "uxth";
14966 break;
14967 case BITS4(0,0,1,1): // SXTH
14968 assign(dstT, unop(Iop_16Sto32, unop(Iop_32to16, mkexpr(rotT))));
14969 nm = "sxth";
14970 break;
14971 case BITS4(0,1,0,0): // UXTB16
14972 assign(dstT, binop(Iop_And32, mkexpr(rotT), mkU32(0x00FF00FF)));
14973 nm = "uxtb16";
14974 break;
14975 case BITS4(0,0,0,0): { // SXTB16
14976 IRTemp lo32 = newTemp(Ity_I32);
14977 IRTemp hi32 = newTemp(Ity_I32);
14978 assign(lo32, binop(Iop_And32, mkexpr(rotT), mkU32(0xFF)));
14979 assign(hi32, binop(Iop_Shr32, mkexpr(rotT), mkU8(16)));
14980 assign(
14981 dstT,
14982 binop(Iop_Or32,
14983 binop(Iop_And32,
14984 unop(Iop_8Sto32,
14985 unop(Iop_32to8, mkexpr(lo32))),
14986 mkU32(0xFFFF)),
14987 binop(Iop_Shl32,
14988 unop(Iop_8Sto32,
14989 unop(Iop_32to8, mkexpr(hi32))),
14990 mkU8(16))
14991 ));
sewardj1f139f52010-08-29 12:33:02 +000014992 nm = "sxtb16";
sewardj6c299f32009-12-31 18:00:12 +000014993 break;
14994 }
14995 default:
14996 vassert(0); // guarded by "if" above
14997 }
sewardjd2664472010-08-22 12:44:20 +000014998 putIRegA(rD, mkexpr(dstT), condT, Ijk_Boring);
sewardj6c299f32009-12-31 18:00:12 +000014999 DIP("%s%s r%u, r%u, ROR #%u\n", nm, nCC(INSN_COND), rD, rM, rot);
15000 goto decode_success;
15001 }
15002 /* fall through */
15003 }
15004
15005 /* ------------------- bfi, bfc ------------------- */
15006 if (BITS8(0,1,1,1,1,1,0, 0) == (INSN(27,20) & BITS8(1,1,1,1,1,1,1,0))
15007 && BITS4(0, 0,0,1) == (INSN(7,4) & BITS4(0,1,1,1))) {
15008 UInt rD = INSN(15,12);
15009 UInt rN = INSN(3,0);
15010 UInt msb = (insn >> 16) & 0x1F; /* 20:16 */
15011 UInt lsb = (insn >> 7) & 0x1F; /* 11:7 */
15012 if (rD == 15 || msb < lsb) {
15013 /* undecodable; fall through */
15014 } else {
15015 IRTemp src = newTemp(Ity_I32);
15016 IRTemp olddst = newTemp(Ity_I32);
15017 IRTemp newdst = newTemp(Ity_I32);
15018 UInt mask = 1 << (msb - lsb);
15019 mask = (mask - 1) + mask;
15020 vassert(mask != 0); // guaranteed by "msb < lsb" check above
15021 mask <<= lsb;
15022
sewardjd2664472010-08-22 12:44:20 +000015023 assign(src, rN == 15 ? mkU32(0) : getIRegA(rN));
15024 assign(olddst, getIRegA(rD));
sewardj6c299f32009-12-31 18:00:12 +000015025 assign(newdst,
15026 binop(Iop_Or32,
15027 binop(Iop_And32,
15028 binop(Iop_Shl32, mkexpr(src), mkU8(lsb)),
15029 mkU32(mask)),
15030 binop(Iop_And32,
15031 mkexpr(olddst),
15032 mkU32(~mask)))
15033 );
15034
sewardjd2664472010-08-22 12:44:20 +000015035 putIRegA(rD, mkexpr(newdst), condT, Ijk_Boring);
sewardj6c299f32009-12-31 18:00:12 +000015036
15037 if (rN == 15) {
15038 DIP("bfc%s r%u, #%u, #%u\n",
15039 nCC(INSN_COND), rD, lsb, msb-lsb+1);
15040 } else {
15041 DIP("bfi%s r%u, r%u, #%u, #%u\n",
15042 nCC(INSN_COND), rD, rN, lsb, msb-lsb+1);
15043 }
15044 goto decode_success;
15045 }
15046 /* fall through */
15047 }
15048
15049 /* ------------------- {u,s}bfx ------------------- */
15050 if (BITS8(0,1,1,1,1,0,1,0) == (INSN(27,20) & BITS8(1,1,1,1,1,0,1,0))
15051 && BITS4(0,1,0,1) == (INSN(7,4) & BITS4(0,1,1,1))) {
15052 UInt rD = INSN(15,12);
15053 UInt rN = INSN(3,0);
15054 UInt wm1 = (insn >> 16) & 0x1F; /* 20:16 */
15055 UInt lsb = (insn >> 7) & 0x1F; /* 11:7 */
15056 UInt msb = lsb + wm1;
15057 UInt isU = (insn >> 22) & 1; /* 22:22 */
15058 if (rD == 15 || rN == 15 || msb >= 32) {
15059 /* undecodable; fall through */
15060 } else {
15061 IRTemp src = newTemp(Ity_I32);
15062 IRTemp tmp = newTemp(Ity_I32);
15063 IRTemp res = newTemp(Ity_I32);
15064 UInt mask = ((1 << wm1) - 1) + (1 << wm1);
15065 vassert(msb >= 0 && msb <= 31);
15066 vassert(mask != 0); // guaranteed by msb being in 0 .. 31 inclusive
15067
sewardjd2664472010-08-22 12:44:20 +000015068 assign(src, getIRegA(rN));
sewardj6c299f32009-12-31 18:00:12 +000015069 assign(tmp, binop(Iop_And32,
15070 binop(Iop_Shr32, mkexpr(src), mkU8(lsb)),
15071 mkU32(mask)));
15072 assign(res, binop(isU ? Iop_Shr32 : Iop_Sar32,
15073 binop(Iop_Shl32, mkexpr(tmp), mkU8(31-wm1)),
15074 mkU8(31-wm1)));
15075
sewardjd2664472010-08-22 12:44:20 +000015076 putIRegA(rD, mkexpr(res), condT, Ijk_Boring);
sewardj6c299f32009-12-31 18:00:12 +000015077
15078 DIP("%s%s r%u, r%u, #%u, #%u\n",
15079 isU ? "ubfx" : "sbfx",
15080 nCC(INSN_COND), rD, rN, lsb, wm1 + 1);
15081 goto decode_success;
15082 }
15083 /* fall through */
15084 }
15085
sewardj6c299f32009-12-31 18:00:12 +000015086 /* --------------------- Load/store doubleword ------------- */
15087 // LDRD STRD
15088 /* 31 27 23 19 15 11 7 3 # highest bit
15089 28 24 20 16 12 8 4 0
15090 A5-36 1 | 16 cond 0001 U100 Rn Rd im4h 11S1 im4l
15091 A5-38 1 | 32 cond 0001 U000 Rn Rd 0000 11S1 Rm
15092 A5-40 2 | 16 cond 0001 U110 Rn Rd im4h 11S1 im4l
15093 A5-42 2 | 32 cond 0001 U010 Rn Rd 0000 11S1 Rm
15094 A5-44 3 | 16 cond 0000 U100 Rn Rd im4h 11S1 im4l
15095 A5-46 3 | 32 cond 0000 U000 Rn Rd 0000 11S1 Rm
15096 */
15097 /* case coding:
15098 1 at-ea (access at ea)
15099 2 at-ea-then-upd (access at ea, then Rn = ea)
15100 3 at-Rn-then-upd (access at Rn, then Rn = ea)
15101 ea coding
15102 16 Rn +/- imm8
15103 32 Rn +/- Rm
15104 */
15105 /* Quickly skip over all of this for hopefully most instructions */
15106 if ((INSN(27,24) & BITS4(1,1,1,0)) != BITS4(0,0,0,0))
15107 goto after_load_store_doubleword;
15108
15109 /* Check the "11S1" thing. */
15110 if ((INSN(7,4) & BITS4(1,1,0,1)) != BITS4(1,1,0,1))
15111 goto after_load_store_doubleword;
15112
15113 summary = 0;
15114
15115 /**/ if (INSN(27,24) == BITS4(0,0,0,1) && INSN(22,20) == BITS3(1,0,0)) {
15116 summary = 1 | 16;
15117 }
15118 else if (INSN(27,24) == BITS4(0,0,0,1) && INSN(22,20) == BITS3(0,0,0)) {
15119 summary = 1 | 32;
15120 }
15121 else if (INSN(27,24) == BITS4(0,0,0,1) && INSN(22,20) == BITS3(1,1,0)) {
15122 summary = 2 | 16;
15123 }
15124 else if (INSN(27,24) == BITS4(0,0,0,1) && INSN(22,20) == BITS3(0,1,0)) {
15125 summary = 2 | 32;
15126 }
15127 else if (INSN(27,24) == BITS4(0,0,0,0) && INSN(22,20) == BITS3(1,0,0)) {
15128 summary = 3 | 16;
15129 }
15130 else if (INSN(27,24) == BITS4(0,0,0,0) && INSN(22,20) == BITS3(0,0,0)) {
15131 summary = 3 | 32;
sewardj6c299f32009-12-31 18:00:12 +000015132 }
15133 else goto after_load_store_doubleword;
15134
15135 { UInt rN = (insn >> 16) & 0xF; /* 19:16 */
15136 UInt rD = (insn >> 12) & 0xF; /* 15:12 */
15137 UInt rM = (insn >> 0) & 0xF; /* 3:0 */
15138 UInt bU = (insn >> 23) & 1; /* 23 U=1 offset+, U=0 offset- */
15139 UInt bS = (insn >> 5) & 1; /* S=1 store, S=0 load */
15140 UInt imm8 = ((insn >> 4) & 0xF0) | (insn & 0xF); /* 11:8, 3:0 */
15141
15142 /* Require rD to be an even numbered register */
15143 if ((rD & 1) != 0)
15144 goto after_load_store_doubleword;
15145
15146 /* Require 11:8 == 0 for Rn +/- Rm cases */
15147 if ((summary & 32) != 0 && (imm8 & 0xF0) != 0)
15148 goto after_load_store_doubleword;
15149
15150 /* Skip some invalid cases, which would lead to two competing
15151 updates to the same register, or which are otherwise
15152 disallowed by the spec. */
15153 switch (summary) {
15154 case 1 | 16:
15155 break;
15156 case 1 | 32:
15157 if (rM == 15) goto after_load_store_doubleword;
15158 break;
15159 case 2 | 16: case 3 | 16:
15160 if (rN == 15) goto after_load_store_doubleword;
15161 if (bS == 0 && (rN == rD || rN == rD+1))
15162 goto after_load_store_doubleword;
15163 break;
15164 case 2 | 32: case 3 | 32:
15165 if (rM == 15) goto after_load_store_doubleword;
15166 if (rN == 15) goto after_load_store_doubleword;
15167 if (rN == rM) goto after_load_store_doubleword;
15168 if (bS == 0 && (rN == rD || rN == rD+1))
15169 goto after_load_store_doubleword;
15170 break;
15171 default:
15172 vassert(0);
15173 }
15174
sewardjcfe046e2013-01-17 14:23:53 +000015175 /* If this is a branch, make it unconditional at this point.
15176 Doing conditional branches in-line is too complex (for
15177 now). */
15178 vassert((rD & 1) == 0); /* from tests above */
15179 if (bS == 0 && rD+1 == 15 && condT != IRTemp_INVALID) {
15180 // go uncond
sewardjd2664472010-08-22 12:44:20 +000015181 mk_skip_over_A32_if_cond_is_false( condT );
sewardj6c299f32009-12-31 18:00:12 +000015182 condT = IRTemp_INVALID;
sewardjcfe046e2013-01-17 14:23:53 +000015183 // now uncond
sewardj6c299f32009-12-31 18:00:12 +000015184 }
sewardj6c299f32009-12-31 18:00:12 +000015185
15186 /* compute the effective address. Bind it to a tmp since we
15187 may need to use it twice. */
15188 IRExpr* eaE = NULL;
15189 switch (summary & 0xF0) {
15190 case 16:
15191 eaE = mk_EA_reg_plusminus_imm8( rN, bU, imm8, dis_buf );
15192 break;
15193 case 32:
15194 eaE = mk_EA_reg_plusminus_reg( rN, bU, rM, dis_buf );
15195 break;
15196 }
15197 vassert(eaE);
15198 IRTemp eaT = newTemp(Ity_I32);
15199 assign(eaT, eaE);
15200
15201 /* get the old Rn value */
15202 IRTemp rnT = newTemp(Ity_I32);
sewardjd2664472010-08-22 12:44:20 +000015203 assign(rnT, getIRegA(rN));
sewardj6c299f32009-12-31 18:00:12 +000015204
15205 /* decide on the transfer address */
15206 IRTemp taT = IRTemp_INVALID;
15207 switch (summary & 0x0F) {
15208 case 1: case 2: taT = eaT; break;
15209 case 3: taT = rnT; break;
15210 }
15211 vassert(taT != IRTemp_INVALID);
15212
15213 /* XXX deal with alignment constraints */
15214 /* XXX: but the A8 doesn't seem to trap for misaligned loads, so,
15215 ignore alignment issues for the time being. */
15216
sewardj92001d42013-04-26 10:24:31 +000015217 /* For almost all cases, we do the writeback after the transfers.
15218 However, that leaves the stack "uncovered" in this case:
15219 strd rD, [sp, #-8]
15220 In which case, do the writeback to SP now, instead of later.
15221 This is bad in that it makes the insn non-restartable if the
15222 accesses fault, but at least keeps Memcheck happy. */
15223 Bool writeback_already_done = False;
15224 if (bS == 1 /*store*/ && summary == (2 | 16)
15225 && rN == 13 && rN != rD && rN != rD+1
15226 && bU == 0/*minus*/ && imm8 == 8) {
15227 putIRegA( rN, mkexpr(eaT), condT, Ijk_Boring );
15228 writeback_already_done = True;
15229 }
15230
sewardj6c299f32009-12-31 18:00:12 +000015231 /* doubleword store S 1
15232 doubleword load S 0
15233 */
florian55085f82012-11-21 00:36:55 +000015234 const HChar* name = NULL;
sewardj6c299f32009-12-31 18:00:12 +000015235 /* generate the transfers */
15236 if (bS == 1) { // doubleword store
sewardjcfe046e2013-01-17 14:23:53 +000015237 storeGuardedLE( binop(Iop_Add32, mkexpr(taT), mkU32(0)),
15238 getIRegA(rD+0), condT );
15239 storeGuardedLE( binop(Iop_Add32, mkexpr(taT), mkU32(4)),
15240 getIRegA(rD+1), condT );
sewardj6c299f32009-12-31 18:00:12 +000015241 name = "strd";
15242 } else { // doubleword load
sewardjcfe046e2013-01-17 14:23:53 +000015243 IRTemp oldRd0 = newTemp(Ity_I32);
15244 IRTemp oldRd1 = newTemp(Ity_I32);
15245 assign(oldRd0, llGetIReg(rD+0));
15246 assign(oldRd1, llGetIReg(rD+1));
15247 IRTemp newRd0 = newTemp(Ity_I32);
15248 IRTemp newRd1 = newTemp(Ity_I32);
15249 loadGuardedLE( newRd0, ILGop_Ident32,
15250 binop(Iop_Add32, mkexpr(taT), mkU32(0)),
15251 mkexpr(oldRd0), condT );
15252 putIRegA( rD+0, mkexpr(newRd0), IRTemp_INVALID, Ijk_Boring );
15253 loadGuardedLE( newRd1, ILGop_Ident32,
15254 binop(Iop_Add32, mkexpr(taT), mkU32(4)),
15255 mkexpr(oldRd1), condT );
15256 putIRegA( rD+1, mkexpr(newRd1), IRTemp_INVALID, Ijk_Boring );
sewardj6c299f32009-12-31 18:00:12 +000015257 name = "ldrd";
15258 }
15259
15260 /* Update Rn if necessary. */
15261 switch (summary & 0x0F) {
15262 case 2: case 3:
15263 // should be assured by logic above:
sewardjcfe046e2013-01-17 14:23:53 +000015264 vassert(rN != 15); /* from checks above */
sewardj6c299f32009-12-31 18:00:12 +000015265 if (bS == 0) {
15266 vassert(rD+0 != rN); /* since we just wrote rD+0 */
15267 vassert(rD+1 != rN); /* since we just wrote rD+1 */
15268 }
sewardj92001d42013-04-26 10:24:31 +000015269 if (!writeback_already_done)
15270 putIRegA( rN, mkexpr(eaT), condT, Ijk_Boring );
sewardj6c299f32009-12-31 18:00:12 +000015271 break;
15272 }
15273
15274 switch (summary & 0x0F) {
15275 case 1: DIP("%s%s r%u, %s\n", name, nCC(INSN_COND), rD, dis_buf);
15276 break;
15277 case 2: DIP("%s%s r%u, %s! (at-EA-then-Rn=EA)\n",
15278 name, nCC(INSN_COND), rD, dis_buf);
15279 break;
15280 case 3: DIP("%s%s r%u, %s! (at-Rn-then-Rn=EA)\n",
15281 name, nCC(INSN_COND), rD, dis_buf);
15282 break;
15283 default: vassert(0);
15284 }
15285
15286 goto decode_success;
15287 }
15288
15289 after_load_store_doubleword:
15290
sewardj04ac5de2010-03-08 14:49:03 +000015291 /* ------------------- {s,u}xtab ------------- */
15292 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 +000015293 && BITS4(0,0,0,0) == (INSN(11,8) & BITS4(0,0,1,1))
15294 && BITS4(0,1,1,1) == INSN(7,4)) {
15295 UInt rN = INSN(19,16);
15296 UInt rD = INSN(15,12);
15297 UInt rM = INSN(3,0);
15298 UInt rot = (insn >> 10) & 3;
sewardj04ac5de2010-03-08 14:49:03 +000015299 UInt isU = INSN(22,22);
15300 if (rN == 15/*it's {S,U}XTB*/ || rD == 15 || rM == 15) {
sewardj6c299f32009-12-31 18:00:12 +000015301 /* undecodable; fall through */
15302 } else {
15303 IRTemp srcL = newTemp(Ity_I32);
15304 IRTemp srcR = newTemp(Ity_I32);
15305 IRTemp res = newTemp(Ity_I32);
sewardjd2664472010-08-22 12:44:20 +000015306 assign(srcR, getIRegA(rM));
15307 assign(srcL, getIRegA(rN));
sewardj6c299f32009-12-31 18:00:12 +000015308 assign(res, binop(Iop_Add32,
15309 mkexpr(srcL),
sewardj04ac5de2010-03-08 14:49:03 +000015310 unop(isU ? Iop_8Uto32 : Iop_8Sto32,
sewardj6c299f32009-12-31 18:00:12 +000015311 unop(Iop_32to8,
15312 genROR32(srcR, 8 * rot)))));
sewardjd2664472010-08-22 12:44:20 +000015313 putIRegA(rD, mkexpr(res), condT, Ijk_Boring);
sewardj04ac5de2010-03-08 14:49:03 +000015314 DIP("%cxtab%s r%u, r%u, r%u, ror #%u\n",
15315 isU ? 'u' : 's', nCC(INSN_COND), rD, rN, rM, rot);
sewardj6c299f32009-12-31 18:00:12 +000015316 goto decode_success;
15317 }
15318 /* fall through */
15319 }
15320
sewardj04ac5de2010-03-08 14:49:03 +000015321 /* ------------------- {s,u}xtah ------------- */
15322 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 +000015323 && BITS4(0,0,0,0) == (INSN(11,8) & BITS4(0,0,1,1))
15324 && BITS4(0,1,1,1) == INSN(7,4)) {
15325 UInt rN = INSN(19,16);
15326 UInt rD = INSN(15,12);
15327 UInt rM = INSN(3,0);
15328 UInt rot = (insn >> 10) & 3;
sewardj04ac5de2010-03-08 14:49:03 +000015329 UInt isU = INSN(22,22);
15330 if (rN == 15/*it's {S,U}XTH*/ || rD == 15 || rM == 15) {
sewardj6c299f32009-12-31 18:00:12 +000015331 /* undecodable; fall through */
15332 } else {
15333 IRTemp srcL = newTemp(Ity_I32);
15334 IRTemp srcR = newTemp(Ity_I32);
15335 IRTemp res = newTemp(Ity_I32);
sewardjd2664472010-08-22 12:44:20 +000015336 assign(srcR, getIRegA(rM));
15337 assign(srcL, getIRegA(rN));
sewardj6c299f32009-12-31 18:00:12 +000015338 assign(res, binop(Iop_Add32,
15339 mkexpr(srcL),
sewardj04ac5de2010-03-08 14:49:03 +000015340 unop(isU ? Iop_16Uto32 : Iop_16Sto32,
sewardj6c299f32009-12-31 18:00:12 +000015341 unop(Iop_32to16,
15342 genROR32(srcR, 8 * rot)))));
sewardjd2664472010-08-22 12:44:20 +000015343 putIRegA(rD, mkexpr(res), condT, Ijk_Boring);
sewardj6c299f32009-12-31 18:00:12 +000015344
sewardj04ac5de2010-03-08 14:49:03 +000015345 DIP("%cxtah%s r%u, r%u, r%u, ror #%u\n",
15346 isU ? 'u' : 's', nCC(INSN_COND), rD, rN, rM, rot);
sewardj6c299f32009-12-31 18:00:12 +000015347 goto decode_success;
15348 }
15349 /* fall through */
15350 }
15351
sewardjdb1c20a2010-09-22 22:26:40 +000015352 /* ------------------- rev16, rev ------------------ */
15353 if (INSN(27,16) == 0x6BF
15354 && (INSN(11,4) == 0xFB/*rev16*/ || INSN(11,4) == 0xF3/*rev*/)) {
15355 Bool isREV = INSN(11,4) == 0xF3;
15356 UInt rM = INSN(3,0);
15357 UInt rD = INSN(15,12);
15358 if (rM != 15 && rD != 15) {
15359 IRTemp rMt = newTemp(Ity_I32);
15360 assign(rMt, getIRegA(rM));
sewardj27312d32010-09-26 00:48:41 +000015361 IRTemp res = isREV ? gen_REV(rMt) : gen_REV16(rMt);
15362 putIRegA(rD, mkexpr(res), condT, Ijk_Boring);
sewardjdb1c20a2010-09-22 22:26:40 +000015363 DIP("rev%s%s r%u, r%u\n", isREV ? "" : "16",
15364 nCC(INSN_COND), rD, rM);
15365 goto decode_success;
15366 }
15367 }
15368
sewardj389239a2010-09-24 21:59:55 +000015369 /* ------------------- rbit ------------------ */
15370 if (INSN(27,16) == 0x6FF && INSN(11,4) == 0xF3) {
15371 UInt rD = INSN(15,12);
15372 UInt rM = INSN(3,0);
15373 if (rD != 15 && rM != 15) {
15374 IRTemp arg = newTemp(Ity_I32);
15375 assign(arg, getIRegA(rM));
15376 IRTemp res = gen_BITREV(arg);
15377 putIRegA(rD, mkexpr(res), condT, Ijk_Boring);
15378 DIP("rbit r%u, r%u\n", rD, rM);
15379 goto decode_success;
15380 }
15381 }
15382
sewardjdb1c20a2010-09-22 22:26:40 +000015383 /* ------------------- smmul ------------------ */
15384 if (INSN(27,20) == BITS8(0,1,1,1,0,1,0,1)
15385 && INSN(15,12) == BITS4(1,1,1,1)
15386 && (INSN(7,4) & BITS4(1,1,0,1)) == BITS4(0,0,0,1)) {
15387 UInt bitR = INSN(5,5);
15388 UInt rD = INSN(19,16);
15389 UInt rM = INSN(11,8);
15390 UInt rN = INSN(3,0);
15391 if (rD != 15 && rM != 15 && rN != 15) {
15392 IRExpr* res
15393 = unop(Iop_64HIto32,
15394 binop(Iop_Add64,
15395 binop(Iop_MullS32, getIRegA(rN), getIRegA(rM)),
15396 mkU64(bitR ? 0x80000000ULL : 0ULL)));
15397 putIRegA(rD, res, condT, Ijk_Boring);
15398 DIP("smmul%s%s r%u, r%u, r%u\n",
15399 nCC(INSN_COND), bitR ? "r" : "", rD, rN, rM);
15400 goto decode_success;
15401 }
15402 }
15403
sewardjccff5f42013-04-23 08:56:43 +000015404 /* ------------------- smmla ------------------ */
15405 if (INSN(27,20) == BITS8(0,1,1,1,0,1,0,1)
15406 && INSN(15,12) != BITS4(1,1,1,1)
15407 && (INSN(7,4) & BITS4(1,1,0,1)) == BITS4(0,0,0,1)) {
15408 UInt bitR = INSN(5,5);
15409 UInt rD = INSN(19,16);
15410 UInt rA = INSN(15,12);
15411 UInt rM = INSN(11,8);
15412 UInt rN = INSN(3,0);
15413 if (rD != 15 && rM != 15 && rN != 15) {
15414 IRExpr* res
15415 = unop(Iop_64HIto32,
15416 binop(Iop_Add64,
15417 binop(Iop_Add64,
15418 binop(Iop_32HLto64, getIRegA(rA), mkU32(0)),
15419 binop(Iop_MullS32, getIRegA(rN), getIRegA(rM))),
15420 mkU64(bitR ? 0x80000000ULL : 0ULL)));
15421 putIRegA(rD, res, condT, Ijk_Boring);
15422 DIP("smmla%s%s r%u, r%u, r%u, r%u\n",
15423 nCC(INSN_COND), bitR ? "r" : "", rD, rN, rM, rA);
15424 goto decode_success;
15425 }
15426 }
15427
sewardj646bc002010-10-11 18:57:10 +000015428 /* ------------------- NOP ------------------ */
15429 if (0x0320F000 == (insn & 0x0FFFFFFF)) {
15430 DIP("nop%s\n", nCC(INSN_COND));
15431 goto decode_success;
15432 }
15433
sewardj6c299f32009-12-31 18:00:12 +000015434 /* ----------------------------------------------------------- */
15435 /* -- ARMv7 instructions -- */
15436 /* ----------------------------------------------------------- */
15437
15438 /* -------------- read CP15 TPIDRURO register ------------- */
15439 /* mrc p15, 0, r0, c13, c0, 3 up to
15440 mrc p15, 0, r14, c13, c0, 3
15441 */
15442 /* I don't know whether this is really v7-only. But anyway, we
15443 have to support it since arm-linux uses TPIDRURO as a thread
15444 state register. */
15445 if (0x0E1D0F70 == (insn & 0x0FFF0FFF)) {
15446 UInt rD = INSN(15,12);
15447 if (rD <= 14) {
15448 /* skip r15, that's too stupid to handle */
sewardjd2664472010-08-22 12:44:20 +000015449 putIRegA(rD, IRExpr_Get(OFFB_TPIDRURO, Ity_I32),
15450 condT, Ijk_Boring);
sewardj6c299f32009-12-31 18:00:12 +000015451 DIP("mrc%s p15,0, r%u, c13, c0, 3\n", nCC(INSN_COND), rD);
15452 goto decode_success;
15453 }
15454 /* fall through */
15455 }
15456
sewardj412098c2010-05-04 08:48:43 +000015457 /* Handle various kinds of barriers. This is rather indiscriminate
15458 in the sense that they are all turned into an IR Fence, which
15459 means we don't know which they are, so the back end has to
15460 re-emit them all when it comes acrosss an IR Fence.
15461 */
sewardj1331f4d2012-02-17 15:07:09 +000015462 /* v6 */ /* mcr 15, 0, rT, c7, c10, 5 */
15463 if (0xEE070FBA == (insn & 0xFFFF0FFF)) {
15464 UInt rT = INSN(15,12);
15465 if (rT <= 14) {
15466 /* mcr 15, 0, rT, c7, c10, 5 (v6) equiv to DMB (v7). Data
15467 Memory Barrier -- ensures ordering of memory accesses. */
15468 stmt( IRStmt_MBE(Imbe_Fence) );
15469 DIP("mcr 15, 0, r%u, c7, c10, 5 (data memory barrier)\n", rT);
15470 goto decode_success;
15471 }
15472 /* fall through */
15473 }
15474 /* other flavours of barrier */
sewardj412098c2010-05-04 08:48:43 +000015475 switch (insn) {
15476 case 0xEE070F9A: /* v6 */
15477 /* mcr 15, 0, r0, c7, c10, 4 (v6) equiv to DSB (v7). Data
15478 Synch Barrier -- ensures completion of memory accesses. */
15479 stmt( IRStmt_MBE(Imbe_Fence) );
15480 DIP("mcr 15, 0, r0, c7, c10, 4 (data synch barrier)\n");
15481 goto decode_success;
sewardj412098c2010-05-04 08:48:43 +000015482 case 0xEE070F95: /* v6 */
15483 /* mcr 15, 0, r0, c7, c5, 4 (v6) equiv to ISB (v7).
15484 Instruction Synchronisation Barrier (or Flush Prefetch
15485 Buffer) -- a pipe flush, I think. I suspect we could
15486 ignore those, but to be on the safe side emit a fence
15487 anyway. */
15488 stmt( IRStmt_MBE(Imbe_Fence) );
15489 DIP("mcr 15, 0, r0, c7, c5, 4 (insn synch barrier)\n");
15490 goto decode_success;
15491 default:
15492 break;
15493 }
15494
sewardj6c299f32009-12-31 18:00:12 +000015495 /* ----------------------------------------------------------- */
sewardjd2664472010-08-22 12:44:20 +000015496 /* -- VFP (CP 10, CP 11) instructions (in ARM mode) -- */
15497 /* ----------------------------------------------------------- */
15498
15499 if (INSN_COND != ARMCondNV) {
15500 Bool ok_vfp = decode_CP10_CP11_instruction (
15501 &dres, INSN(27,0), condT, INSN_COND,
15502 False/*!isT*/
15503 );
15504 if (ok_vfp)
15505 goto decode_success;
15506 }
15507
15508 /* ----------------------------------------------------------- */
15509 /* -- NEON instructions (in ARM mode) -- */
15510 /* ----------------------------------------------------------- */
15511
15512 /* These are all in NV space, and so are taken care of (far) above,
15513 by a call from this function to decode_NV_instruction(). */
15514
15515 /* ----------------------------------------------------------- */
sewardj1f139f52010-08-29 12:33:02 +000015516 /* -- v6 media instructions (in ARM mode) -- */
15517 /* ----------------------------------------------------------- */
15518
15519 { Bool ok_v6m = decode_V6MEDIA_instruction(
15520 &dres, INSN(27,0), condT, INSN_COND,
15521 False/*!isT*/
15522 );
15523 if (ok_v6m)
15524 goto decode_success;
15525 }
15526
15527 /* ----------------------------------------------------------- */
sewardj6c299f32009-12-31 18:00:12 +000015528 /* -- Undecodable -- */
15529 /* ----------------------------------------------------------- */
15530
15531 goto decode_failure;
15532 /*NOTREACHED*/
15533
15534 decode_failure:
sewardjc2c87162004-11-25 13:07:02 +000015535 /* All decode failures end up here. */
sewardj442e51a2012-12-06 18:08:04 +000015536 if (sigill_diag) {
15537 vex_printf("disInstr(arm): unhandled instruction: "
15538 "0x%x\n", insn);
15539 vex_printf(" cond=%d(0x%x) 27:20=%u(0x%02x) "
15540 "4:4=%d "
15541 "3:0=%u(0x%x)\n",
15542 (Int)INSN_COND, (UInt)INSN_COND,
15543 (Int)INSN(27,20), (UInt)INSN(27,20),
15544 (Int)INSN(4,4),
15545 (Int)INSN(3,0), (UInt)INSN(3,0) );
15546 }
sewardj6c299f32009-12-31 18:00:12 +000015547
15548 /* Tell the dispatcher that this insn cannot be decoded, and so has
15549 not been executed, and (is currently) the next to be executed.
15550 R15 should be up-to-date since it made so at the start of each
15551 insn, but nevertheless be paranoid and update it again right
15552 now. */
sewardjd2664472010-08-22 12:44:20 +000015553 vassert(0 == (guest_R15_curr_instr_notENC & 3));
15554 llPutIReg( 15, mkU32(guest_R15_curr_instr_notENC) );
sewardjc6f970f2012-04-02 21:54:49 +000015555 dres.whatNext = Dis_StopHere;
15556 dres.jk_StopHere = Ijk_NoDecode;
15557 dres.len = 0;
sewardj6c299f32009-12-31 18:00:12 +000015558 return dres;
15559
sewardjc2c87162004-11-25 13:07:02 +000015560 decode_success:
15561 /* All decode successes end up here. */
sewardjc2c87162004-11-25 13:07:02 +000015562 DIP("\n");
sewardj6c299f32009-12-31 18:00:12 +000015563
15564 vassert(dres.len == 4 || dres.len == 20);
15565
15566 /* Now then. Do we have an implicit jump to r15 to deal with? */
15567 if (r15written) {
15568 /* If we get jump to deal with, we assume that there's been no
15569 other competing branch stuff previously generated for this
15570 insn. That's reasonable, in the sense that the ARM insn set
15571 appears to declare as "Unpredictable" any instruction which
15572 generates more than one possible new value for r15. Hence
15573 just assert. The decoders themselves should check against
15574 all such instructions which are thusly Unpredictable, and
15575 decline to decode them. Hence we should never get here if we
15576 have competing new values for r15, and hence it is safe to
15577 assert here. */
15578 vassert(dres.whatNext == Dis_Continue);
15579 vassert(irsb->next == NULL);
sewardjf6d2cf92011-05-03 11:08:39 +000015580 vassert(irsb->jumpkind == Ijk_Boring);
sewardj6c299f32009-12-31 18:00:12 +000015581 /* If r15 is unconditionally written, terminate the block by
15582 jumping to it. If it's conditionally written, still
15583 terminate the block (a shame, but we can't do side exits to
15584 arbitrary destinations), but first jump to the next
15585 instruction if the condition doesn't hold. */
15586 /* We can't use getIReg(15) to get the destination, since that
15587 will produce r15+8, which isn't what we want. Must use
15588 llGetIReg(15) instead. */
15589 if (r15guard == IRTemp_INVALID) {
15590 /* unconditional */
15591 } else {
15592 /* conditional */
sewardjd2664472010-08-22 12:44:20 +000015593 stmt( IRStmt_Exit(
15594 unop(Iop_32to1,
15595 binop(Iop_Xor32,
15596 mkexpr(r15guard), mkU32(1))),
15597 r15kind,
sewardjc6f970f2012-04-02 21:54:49 +000015598 IRConst_U32(guest_R15_curr_instr_notENC + 4),
15599 OFFB_R15T
sewardj6c299f32009-12-31 18:00:12 +000015600 ));
15601 }
sewardjc6f970f2012-04-02 21:54:49 +000015602 /* This seems crazy, but we're required to finish the insn with
15603 a write to the guest PC. As usual we rely on ir_opt to tidy
15604 up later. */
15605 llPutIReg(15, llGetIReg(15));
15606 dres.whatNext = Dis_StopHere;
15607 dres.jk_StopHere = r15kind;
15608 } else {
15609 /* Set up the end-state in the normal way. */
15610 switch (dres.whatNext) {
15611 case Dis_Continue:
15612 llPutIReg(15, mkU32(dres.len + guest_R15_curr_instr_notENC));
15613 break;
15614 case Dis_ResteerU:
15615 case Dis_ResteerC:
15616 llPutIReg(15, mkU32(dres.continueAt));
15617 break;
15618 case Dis_StopHere:
15619 break;
15620 default:
15621 vassert(0);
15622 }
sewardj6c299f32009-12-31 18:00:12 +000015623 }
15624
15625 return dres;
15626
sewardj6c299f32009-12-31 18:00:12 +000015627# undef INSN_COND
sewardj80bea7b2010-01-09 11:43:21 +000015628# undef INSN
sewardjc2c87162004-11-25 13:07:02 +000015629}
15630
sewardjd2664472010-08-22 12:44:20 +000015631
15632/*------------------------------------------------------------*/
15633/*--- Disassemble a single Thumb2 instruction ---*/
15634/*------------------------------------------------------------*/
15635
sewardj66c8c9b2011-07-04 16:58:40 +000015636static const UChar it_length_table[256]; /* fwds */
15637
sewardjd2664472010-08-22 12:44:20 +000015638/* NB: in Thumb mode we do fetches of regs with getIRegT, which
15639 automagically adds 4 to fetches of r15. However, writes to regs
15640 are done with putIRegT, which disallows writes to r15. Hence any
15641 r15 writes and associated jumps have to be done "by hand". */
15642
15643/* Disassemble a single Thumb instruction into IR. The instruction is
15644 located in host memory at guest_instr, and has (decoded) guest IP
15645 of guest_R15_curr_instr_notENC, which will have been set before the
15646 call here. */
15647
15648static
15649DisResult disInstr_THUMB_WRK (
sewardjd2664472010-08-22 12:44:20 +000015650 Bool (*resteerOkFn) ( /*opaque*/void*, Addr64 ),
15651 Bool resteerCisOk,
15652 void* callback_opaque,
15653 UChar* guest_instr,
15654 VexArchInfo* archinfo,
sewardj442e51a2012-12-06 18:08:04 +000015655 VexAbiInfo* abiinfo,
15656 Bool sigill_diag
sewardjd2664472010-08-22 12:44:20 +000015657 )
15658{
15659 /* A macro to fish bits out of insn0. There's also INSN1, to fish
15660 bits out of insn1, but that's defined only after the end of the
15661 16-bit insn decoder, so as to stop it mistakenly being used
15662 therein. */
15663# define INSN0(_bMax,_bMin) SLICE_UInt(((UInt)insn0), (_bMax), (_bMin))
15664
15665 DisResult dres;
sewardj5276ff52012-07-14 14:21:56 +000015666 UShort insn0; /* first 16 bits of the insn */
15667 UShort insn1; /* second 16 bits of the insn */
sewardjd2664472010-08-22 12:44:20 +000015668 //Bool allow_VFP = False;
15669 //UInt hwcaps = archinfo->hwcaps;
15670 HChar dis_buf[128]; // big enough to hold LDMIA etc text
15671
sewardja002def2010-10-05 22:29:49 +000015672 /* Summary result of the ITxxx backwards analysis: False == safe
15673 but suboptimal. */
15674 Bool guaranteedUnconditional = False;
15675
sewardjd2664472010-08-22 12:44:20 +000015676 /* What insn variants are we supporting today? */
15677 //allow_VFP = (0 != (hwcaps & VEX_HWCAPS_ARM_VFP));
15678 // etc etc
15679
15680 /* Set result defaults. */
sewardjc6f970f2012-04-02 21:54:49 +000015681 dres.whatNext = Dis_Continue;
15682 dres.len = 2;
15683 dres.continueAt = 0;
15684 dres.jk_StopHere = Ijk_INVALID;
sewardjd2664472010-08-22 12:44:20 +000015685
15686 /* Set default actions for post-insn handling of writes to r15, if
15687 required. */
15688 r15written = False;
15689 r15guard = IRTemp_INVALID; /* unconditional */
15690 r15kind = Ijk_Boring;
15691
15692 /* Insns could be 2 or 4 bytes long. Just get the first 16 bits at
15693 this point. If we need the second 16, get them later. We can't
15694 get them both out immediately because it risks a fault (very
15695 unlikely, but ..) if the second 16 bits aren't actually
15696 necessary. */
15697 insn0 = getUShortLittleEndianly( guest_instr );
sewardj5276ff52012-07-14 14:21:56 +000015698 insn1 = 0; /* We'll get it later, once we know we need it. */
15699
15700 /* Similarly, will set this later. */
15701 IRTemp old_itstate = IRTemp_INVALID;
sewardjd2664472010-08-22 12:44:20 +000015702
15703 if (0) vex_printf("insn: 0x%x\n", insn0);
15704
15705 DIP("\t(thumb) 0x%x: ", (UInt)guest_R15_curr_instr_notENC);
15706
sewardjd2664472010-08-22 12:44:20 +000015707 vassert(0 == (guest_R15_curr_instr_notENC & 1));
sewardjd2664472010-08-22 12:44:20 +000015708
15709 /* ----------------------------------------------------------- */
15710 /* Spot "Special" instructions (see comment at top of file). */
15711 {
15712 UChar* code = (UChar*)guest_instr;
15713 /* Spot the 16-byte preamble:
15714
15715 ea4f 0cfc mov.w ip, ip, ror #3
15716 ea4f 3c7c mov.w ip, ip, ror #13
15717 ea4f 7c7c mov.w ip, ip, ror #29
15718 ea4f 4cfc mov.w ip, ip, ror #19
15719 */
15720 UInt word1 = 0x0CFCEA4F;
15721 UInt word2 = 0x3C7CEA4F;
15722 UInt word3 = 0x7C7CEA4F;
15723 UInt word4 = 0x4CFCEA4F;
15724 if (getUIntLittleEndianly(code+ 0) == word1 &&
15725 getUIntLittleEndianly(code+ 4) == word2 &&
15726 getUIntLittleEndianly(code+ 8) == word3 &&
15727 getUIntLittleEndianly(code+12) == word4) {
15728 /* Got a "Special" instruction preamble. Which one is it? */
15729 // 0x 0A 0A EA 4A
15730 if (getUIntLittleEndianly(code+16) == 0x0A0AEA4A
15731 /* orr.w r10,r10,r10 */) {
15732 /* R3 = client_request ( R4 ) */
15733 DIP("r3 = client_request ( %%r4 )\n");
sewardjc6f970f2012-04-02 21:54:49 +000015734 llPutIReg(15, mkU32( (guest_R15_curr_instr_notENC + 20) | 1 ));
15735 dres.jk_StopHere = Ijk_ClientReq;
15736 dres.whatNext = Dis_StopHere;
sewardjd2664472010-08-22 12:44:20 +000015737 goto decode_success;
15738 }
sewardjd2664472010-08-22 12:44:20 +000015739 else
15740 // 0x 0B 0B EA 4B
sewardjc0704052010-08-22 22:21:19 +000015741 if (getUIntLittleEndianly(code+16) == 0x0B0BEA4B
sewardjd2664472010-08-22 12:44:20 +000015742 /* orr r11,r11,r11 */) {
15743 /* R3 = guest_NRADDR */
15744 DIP("r3 = guest_NRADDR\n");
15745 dres.len = 20;
15746 llPutIReg(3, IRExpr_Get( OFFB_NRADDR, Ity_I32 ));
15747 goto decode_success;
15748 }
15749 else
15750 // 0x 0C 0C EA 4C
sewardjc0704052010-08-22 22:21:19 +000015751 if (getUIntLittleEndianly(code+16) == 0x0C0CEA4C
sewardjd2664472010-08-22 12:44:20 +000015752 /* orr r12,r12,r12 */) {
15753 /* branch-and-link-to-noredir R4 */
15754 DIP("branch-and-link-to-noredir r4\n");
sewardjc0704052010-08-22 22:21:19 +000015755 llPutIReg(14, mkU32( (guest_R15_curr_instr_notENC + 20) | 1 ));
sewardjc6f970f2012-04-02 21:54:49 +000015756 llPutIReg(15, getIRegT(4));
15757 dres.jk_StopHere = Ijk_NoRedir;
15758 dres.whatNext = Dis_StopHere;
sewardjd2664472010-08-22 12:44:20 +000015759 goto decode_success;
15760 }
sewardja0d8eb82012-09-03 21:48:42 +000015761 else
15762 // 0x 09 09 EA 49
15763 if (getUIntLittleEndianly(code+16) == 0x0909EA49
15764 /* orr r9,r9,r9 */) {
15765 /* IR injection */
15766 DIP("IR injection\n");
15767 vex_inject_ir(irsb, Iend_LE);
15768 // Invalidate the current insn. The reason is that the IRop we're
15769 // injecting here can change. In which case the translation has to
15770 // be redone. For ease of handling, we simply invalidate all the
15771 // time.
15772 stmt(IRStmt_Put(OFFB_TISTART, mkU32(guest_R15_curr_instr_notENC)));
15773 stmt(IRStmt_Put(OFFB_TILEN, mkU32(20)));
15774 llPutIReg(15, mkU32( (guest_R15_curr_instr_notENC + 20) | 1 ));
15775 dres.whatNext = Dis_StopHere;
15776 dres.jk_StopHere = Ijk_TInval;
15777 goto decode_success;
15778 }
sewardjd2664472010-08-22 12:44:20 +000015779 /* We don't know what it is. Set insn0 so decode_failure
15780 can print the insn following the Special-insn preamble. */
15781 insn0 = getUShortLittleEndianly(code+16);
15782 goto decode_failure;
15783 /*NOTREACHED*/
15784 }
15785
15786 }
15787
15788 /* ----------------------------------------------------------- */
15789
15790 /* Main Thumb instruction decoder starts here. It's a series of
15791 switches which examine ever longer bit sequences at the MSB of
15792 the instruction word, first for 16-bit insns, then for 32-bit
15793 insns. */
15794
sewardja002def2010-10-05 22:29:49 +000015795 /* --- BEGIN ITxxx optimisation analysis --- */
sewardjd2664472010-08-22 12:44:20 +000015796 /* This is a crucial optimisation for the ITState boilerplate that
15797 follows. Examine the 9 halfwords preceding this instruction,
15798 and if we are absolutely sure that none of them constitute an
15799 'it' instruction, then we can be sure that this instruction is
15800 not under the control of any 'it' instruction, and so
15801 guest_ITSTATE must be zero. So write zero into ITSTATE right
15802 now, so that iropt can fold out almost all of the resulting
15803 junk.
15804
15805 If we aren't sure, we can always safely skip this step. So be a
15806 bit conservative about it: only poke around in the same page as
15807 this instruction, lest we get a fault from the previous page
15808 that would not otherwise have happened. The saving grace is
15809 that such skipping is pretty rare -- it only happens,
15810 statistically, 18/4096ths of the time, so is judged unlikely to
15811 be a performance problems.
15812
15813 FIXME: do better. Take into account the number of insns covered
15814 by any IT insns we find, to rule out cases where an IT clearly
15815 cannot cover this instruction. This would improve behaviour for
15816 branch targets immediately following an IT-guarded group that is
15817 not of full length. Eg, (and completely ignoring issues of 16-
15818 vs 32-bit insn length):
15819
15820 ite cond
15821 insn1
15822 insn2
15823 label: insn3
15824 insn4
15825
15826 The 'it' only conditionalises insn1 and insn2. However, the
15827 current analysis is conservative and considers insn3 and insn4
15828 also possibly guarded. Hence if 'label:' is the start of a hot
15829 loop we will get a big performance hit.
15830 */
15831 {
15832 /* Summary result of this analysis: False == safe but
15833 suboptimal. */
sewardja002def2010-10-05 22:29:49 +000015834 vassert(guaranteedUnconditional == False);
sewardjd2664472010-08-22 12:44:20 +000015835
15836 UInt pc = guest_R15_curr_instr_notENC;
15837 vassert(0 == (pc & 1));
15838
15839 UInt pageoff = pc & 0xFFF;
15840 if (pageoff >= 18) {
15841 /* It's safe to poke about in the 9 halfwords preceding this
15842 insn. So, have a look at them. */
sewardj66c8c9b2011-07-04 16:58:40 +000015843 guaranteedUnconditional = True; /* assume no 'it' insn found,
15844 till we do */
sewardjdf86f162010-08-22 18:47:30 +000015845 UShort* hwp = (UShort*)(HWord)pc;
sewardjd2664472010-08-22 12:44:20 +000015846 Int i;
15847 for (i = -1; i >= -9; i--) {
15848 /* We're in the same page. (True, but commented out due
15849 to expense.) */
15850 /*
15851 vassert( ( ((UInt)(&hwp[i])) & 0xFFFFF000 )
15852 == ( pc & 0xFFFFF000 ) );
15853 */
15854 /* All valid IT instructions must have the form 0xBFxy,
sewardj66c8c9b2011-07-04 16:58:40 +000015855 where x can be anything, but y must be nonzero. Find
15856 the number of insns covered by it (1 .. 4) and check to
15857 see if it can possibly reach up to the instruction in
15858 question. Some (x,y) combinations mean UNPREDICTABLE,
15859 and the table is constructed to be conservative by
15860 returning 4 for those cases, so the analysis is safe
15861 even if the code uses unpredictable IT instructions (in
15862 which case its authors are nuts, but hey.) */
15863 UShort hwp_i = hwp[i];
15864 if (UNLIKELY((hwp_i & 0xFF00) == 0xBF00 && (hwp_i & 0xF) != 0)) {
15865 /* might be an 'it' insn. */
15866 /* # guarded insns */
15867 Int n_guarded = (Int)it_length_table[hwp_i & 0xFF];
15868 vassert(n_guarded >= 1 && n_guarded <= 4);
15869 if (n_guarded * 2 /* # guarded HWs, worst case */
15870 > (-(i+1))) /* -(i+1): # remaining HWs after the IT */
15871 /* -(i+0) also seems to work, even though I think
15872 it's wrong. I don't understand that. */
15873 guaranteedUnconditional = False;
sewardjd2664472010-08-22 12:44:20 +000015874 break;
15875 }
15876 }
15877 }
sewardjd2664472010-08-22 12:44:20 +000015878 }
sewardja002def2010-10-05 22:29:49 +000015879 /* --- END ITxxx optimisation analysis --- */
sewardjd2664472010-08-22 12:44:20 +000015880
15881 /* Generate the guarding condition for this insn, by examining
15882 ITSTATE. Assign it to condT. Also, generate new
15883 values for ITSTATE ready for stuffing back into the
15884 guest state, but don't actually do the Put yet, since it will
15885 need to stuffed back in only after the instruction gets to a
15886 point where it is sure to complete. Mostly we let the code at
15887 decode_success handle this, but in cases where the insn contains
15888 a side exit, we have to update them before the exit. */
15889
sewardja002def2010-10-05 22:29:49 +000015890 /* If the ITxxx optimisation analysis above could not prove that
15891 this instruction is guaranteed unconditional, we insert a
15892 lengthy IR preamble to compute the guarding condition at
15893 runtime. If it can prove it (which obviously we hope is the
15894 normal case) then we insert a minimal preamble, which is
15895 equivalent to setting guest_ITSTATE to zero and then folding
15896 that through the full preamble (which completely disappears). */
sewardjd2664472010-08-22 12:44:20 +000015897
sewardja002def2010-10-05 22:29:49 +000015898 IRTemp condT = IRTemp_INVALID;
sewardja002def2010-10-05 22:29:49 +000015899 IRTemp cond_AND_notInIT_T = IRTemp_INVALID;
sewardjd2664472010-08-22 12:44:20 +000015900
sewardj5276ff52012-07-14 14:21:56 +000015901 IRTemp new_itstate = IRTemp_INVALID;
15902 vassert(old_itstate == IRTemp_INVALID);
15903
sewardja002def2010-10-05 22:29:49 +000015904 if (guaranteedUnconditional) {
15905 /* BEGIN "partial eval { ITSTATE = 0; STANDARD_PREAMBLE; }" */
sewardjd2664472010-08-22 12:44:20 +000015906
sewardja002def2010-10-05 22:29:49 +000015907 // ITSTATE = 0 :: I32
15908 IRTemp z32 = newTemp(Ity_I32);
15909 assign(z32, mkU32(0));
15910 put_ITSTATE(z32);
15911
15912 // old_itstate = 0 :: I32
15913 //
15914 // old_itstate = get_ITSTATE();
15915 old_itstate = z32; /* 0 :: I32 */
15916
15917 // new_itstate = old_itstate >> 8
15918 // = 0 >> 8
15919 // = 0 :: I32
15920 //
15921 // new_itstate = newTemp(Ity_I32);
15922 // assign(new_itstate,
15923 // binop(Iop_Shr32, mkexpr(old_itstate), mkU8(8)));
15924 new_itstate = z32;
15925
15926 // ITSTATE = 0 :: I32(again)
15927 //
15928 // put_ITSTATE(new_itstate);
15929
15930 // condT1 = calc_cond_dyn( xor(and(old_istate,0xF0), 0xE0) )
15931 // = calc_cond_dyn( xor(0,0xE0) )
15932 // = calc_cond_dyn ( 0xE0 )
15933 // = 1 :: I32
15934 // Not that this matters, since the computed value is not used:
15935 // see condT folding below
15936 //
15937 // IRTemp condT1 = newTemp(Ity_I32);
15938 // assign(condT1,
15939 // mk_armg_calculate_condition_dyn(
15940 // binop(Iop_Xor32,
15941 // binop(Iop_And32, mkexpr(old_itstate), mkU32(0xF0)),
15942 // mkU32(0xE0))
15943 // )
15944 // );
15945
15946 // condT = 32to8(and32(old_itstate,0xF0)) == 0 ? 1 : condT1
15947 // = 32to8(and32(0,0xF0)) == 0 ? 1 : condT1
15948 // = 32to8(0) == 0 ? 1 : condT1
15949 // = 0 == 0 ? 1 : condT1
15950 // = 1
15951 //
15952 // condT = newTemp(Ity_I32);
florian99dd03e2013-01-29 03:56:06 +000015953 // assign(condT, IRExpr_ITE(
sewardja002def2010-10-05 22:29:49 +000015954 // unop(Iop_32to8, binop(Iop_And32,
15955 // mkexpr(old_itstate),
15956 // mkU32(0xF0))),
florian99dd03e2013-01-29 03:56:06 +000015957 // mkexpr(condT1),
15958 // mkU32(1))
sewardja002def2010-10-05 22:29:49 +000015959 // ));
15960 condT = newTemp(Ity_I32);
15961 assign(condT, mkU32(1));
15962
15963 // notInITt = xor32(and32(old_itstate, 1), 1)
15964 // = xor32(and32(0, 1), 1)
15965 // = xor32(0, 1)
15966 // = 1 :: I32
15967 //
15968 // IRTemp notInITt = newTemp(Ity_I32);
15969 // assign(notInITt,
15970 // binop(Iop_Xor32,
15971 // binop(Iop_And32, mkexpr(old_itstate), mkU32(1)),
15972 // mkU32(1)));
15973
15974 // cond_AND_notInIT_T = and32(notInITt, condT)
15975 // = and32(1, 1)
15976 // = 1
15977 //
15978 // cond_AND_notInIT_T = newTemp(Ity_I32);
15979 // assign(cond_AND_notInIT_T,
15980 // binop(Iop_And32, mkexpr(notInITt), mkexpr(condT)));
15981 cond_AND_notInIT_T = condT; /* 1 :: I32 */
15982
15983 /* END "partial eval { ITSTATE = 0; STANDARD_PREAMBLE; }" */
15984 } else {
15985 /* BEGIN { STANDARD PREAMBLE; } */
15986
15987 old_itstate = get_ITSTATE();
15988
15989 new_itstate = newTemp(Ity_I32);
15990 assign(new_itstate,
15991 binop(Iop_Shr32, mkexpr(old_itstate), mkU8(8)));
15992
15993 put_ITSTATE(new_itstate);
15994
15995 /* Same strategy as for ARM insns: generate a condition
15996 temporary at this point (or IRTemp_INVALID, meaning
15997 unconditional). We leave it to lower-level instruction
15998 decoders to decide whether they can generate straight-line
15999 code, or whether they must generate a side exit before the
16000 instruction. condT :: Ity_I32 and is always either zero or
16001 one. */
16002 IRTemp condT1 = newTemp(Ity_I32);
16003 assign(condT1,
16004 mk_armg_calculate_condition_dyn(
16005 binop(Iop_Xor32,
16006 binop(Iop_And32, mkexpr(old_itstate), mkU32(0xF0)),
16007 mkU32(0xE0))
16008 )
16009 );
16010
16011 /* This is a bit complex, but needed to make Memcheck understand
16012 that, if the condition in old_itstate[7:4] denotes AL (that
16013 is, if this instruction is to be executed unconditionally),
16014 then condT does not depend on the results of calling the
16015 helper.
16016
16017 We test explicitly for old_itstate[7:4] == AL ^ 0xE, and in
16018 that case set condT directly to 1. Else we use the results
16019 of the helper. Since old_itstate is always defined and
florian99dd03e2013-01-29 03:56:06 +000016020 because Memcheck does lazy V-bit propagation through ITE,
sewardja002def2010-10-05 22:29:49 +000016021 this will cause condT to always be a defined 1 if the
16022 condition is 'AL'. From an execution semantics point of view
16023 this is irrelevant since we're merely duplicating part of the
16024 behaviour of the helper. But it makes it clear to Memcheck,
16025 in this case, that condT does not in fact depend on the
16026 contents of the condition code thunk. Without it, we get
16027 quite a lot of false errors.
16028
16029 So, just to clarify: from a straight semantics point of view,
16030 we can simply do "assign(condT, mkexpr(condT1))", and the
16031 simulator still runs fine. It's just that we get loads of
16032 false errors from Memcheck. */
16033 condT = newTemp(Ity_I32);
florian99dd03e2013-01-29 03:56:06 +000016034 assign(condT, IRExpr_ITE(
sewardj009230b2013-01-26 11:47:55 +000016035 binop(Iop_CmpNE32, binop(Iop_And32,
16036 mkexpr(old_itstate),
16037 mkU32(0xF0)),
16038 mkU32(0)),
florian99dd03e2013-01-29 03:56:06 +000016039 mkexpr(condT1),
16040 mkU32(1)
sewardja002def2010-10-05 22:29:49 +000016041 ));
16042
16043 /* Something we don't have in ARM: generate a 0 or 1 value
16044 indicating whether or not we are in an IT block (NB: 0 = in
16045 IT block, 1 = not in IT block). This is used to gate
16046 condition code updates in 16-bit Thumb instructions. */
16047 IRTemp notInITt = newTemp(Ity_I32);
16048 assign(notInITt,
sewardjd2664472010-08-22 12:44:20 +000016049 binop(Iop_Xor32,
sewardja002def2010-10-05 22:29:49 +000016050 binop(Iop_And32, mkexpr(old_itstate), mkU32(1)),
16051 mkU32(1)));
sewardjd2664472010-08-22 12:44:20 +000016052
sewardja002def2010-10-05 22:29:49 +000016053 /* Compute 'condT && notInITt' -- that is, the instruction is
16054 going to execute, and we're not in an IT block. This is the
16055 gating condition for updating condition codes in 16-bit Thumb
16056 instructions, except for CMP, CMN and TST. */
16057 cond_AND_notInIT_T = newTemp(Ity_I32);
16058 assign(cond_AND_notInIT_T,
16059 binop(Iop_And32, mkexpr(notInITt), mkexpr(condT)));
16060 /* END { STANDARD PREAMBLE; } */
16061 }
sewardjd2664472010-08-22 12:44:20 +000016062
sewardjd2664472010-08-22 12:44:20 +000016063
16064 /* At this point:
16065 * ITSTATE has been updated
16066 * condT holds the guarding condition for this instruction (0 or 1),
16067 * notInITt is 1 if we're in "normal" code, 0 if in an IT block
16068 * cond_AND_notInIT_T is the AND of the above two.
16069
16070 If the instruction proper can't trap, then there's nothing else
16071 to do w.r.t. ITSTATE -- just go and and generate IR for the
16072 insn, taking into account the guarding condition.
16073
16074 If, however, the instruction might trap, then we must back up
16075 ITSTATE to the old value, and re-update it after the potentially
16076 trapping IR section. A trap can happen either via a memory
16077 reference or because we need to throw SIGILL.
16078
16079 If an instruction has a side exit, we need to be sure that any
16080 ITSTATE backup is re-updated before the side exit.
16081 */
16082
16083 /* ----------------------------------------------------------- */
16084 /* -- -- */
16085 /* -- Thumb 16-bit integer instructions -- */
16086 /* -- -- */
16087 /* -- IMPORTANT: references to insn1 or INSN1 are -- */
16088 /* -- not allowed in this section -- */
16089 /* -- -- */
16090 /* ----------------------------------------------------------- */
16091
16092 /* 16-bit instructions inside an IT block, apart from CMP, CMN and
16093 TST, do not set the condition codes. Hence we must dynamically
16094 test for this case for every condition code update. */
16095
16096 IROp anOp = Iop_INVALID;
florian55085f82012-11-21 00:36:55 +000016097 const HChar* anOpNm = NULL;
sewardjd2664472010-08-22 12:44:20 +000016098
16099 /* ================ 16-bit 15:6 cases ================ */
16100
16101 switch (INSN0(15,6)) {
16102
16103 case 0x10a: // CMP
16104 case 0x10b: { // CMN
16105 /* ---------------- CMP Rn, Rm ---------------- */
16106 Bool isCMN = INSN0(15,6) == 0x10b;
16107 UInt rN = INSN0(2,0);
16108 UInt rM = INSN0(5,3);
16109 IRTemp argL = newTemp(Ity_I32);
16110 IRTemp argR = newTemp(Ity_I32);
16111 assign( argL, getIRegT(rN) );
16112 assign( argR, getIRegT(rM) );
16113 /* Update flags regardless of whether in an IT block or not. */
16114 setFlags_D1_D2( isCMN ? ARMG_CC_OP_ADD : ARMG_CC_OP_SUB,
16115 argL, argR, condT );
16116 DIP("%s r%u, r%u\n", isCMN ? "cmn" : "cmp", rN, rM);
16117 goto decode_success;
16118 }
16119
16120 case 0x108: {
16121 /* ---------------- TST Rn, Rm ---------------- */
16122 UInt rN = INSN0(2,0);
16123 UInt rM = INSN0(5,3);
16124 IRTemp oldC = newTemp(Ity_I32);
16125 IRTemp oldV = newTemp(Ity_I32);
16126 IRTemp res = newTemp(Ity_I32);
16127 assign( oldC, mk_armg_calculate_flag_c() );
16128 assign( oldV, mk_armg_calculate_flag_v() );
16129 assign( res, binop(Iop_And32, getIRegT(rN), getIRegT(rM)) );
16130 /* Update flags regardless of whether in an IT block or not. */
16131 setFlags_D1_D2_ND( ARMG_CC_OP_LOGIC, res, oldC, oldV, condT );
16132 DIP("tst r%u, r%u\n", rN, rM);
16133 goto decode_success;
16134 }
16135
16136 case 0x109: {
16137 /* ---------------- NEGS Rd, Rm ---------------- */
16138 /* Rd = -Rm */
16139 UInt rM = INSN0(5,3);
16140 UInt rD = INSN0(2,0);
16141 IRTemp arg = newTemp(Ity_I32);
16142 IRTemp zero = newTemp(Ity_I32);
16143 assign(arg, getIRegT(rM));
16144 assign(zero, mkU32(0));
16145 // rD can never be r15
16146 putIRegT(rD, binop(Iop_Sub32, mkexpr(zero), mkexpr(arg)), condT);
16147 setFlags_D1_D2( ARMG_CC_OP_SUB, zero, arg, cond_AND_notInIT_T);
16148 DIP("negs r%u, r%u\n", rD, rM);
16149 goto decode_success;
16150 }
16151
16152 case 0x10F: {
16153 /* ---------------- MVNS Rd, Rm ---------------- */
16154 /* Rd = ~Rm */
16155 UInt rM = INSN0(5,3);
16156 UInt rD = INSN0(2,0);
16157 IRTemp oldV = newTemp(Ity_I32);
16158 IRTemp oldC = newTemp(Ity_I32);
16159 IRTemp res = newTemp(Ity_I32);
16160 assign( oldV, mk_armg_calculate_flag_v() );
16161 assign( oldC, mk_armg_calculate_flag_c() );
16162 assign(res, unop(Iop_Not32, getIRegT(rM)));
16163 // rD can never be r15
16164 putIRegT(rD, mkexpr(res), condT);
16165 setFlags_D1_D2_ND( ARMG_CC_OP_LOGIC, res, oldC, oldV,
16166 cond_AND_notInIT_T );
16167 DIP("mvns r%u, r%u\n", rD, rM);
16168 goto decode_success;
16169 }
16170
16171 case 0x10C:
16172 /* ---------------- ORRS Rd, Rm ---------------- */
16173 anOp = Iop_Or32; anOpNm = "orr"; goto and_orr_eor_mul;
16174 case 0x100:
16175 /* ---------------- ANDS Rd, Rm ---------------- */
16176 anOp = Iop_And32; anOpNm = "and"; goto and_orr_eor_mul;
16177 case 0x101:
16178 /* ---------------- EORS Rd, Rm ---------------- */
16179 anOp = Iop_Xor32; anOpNm = "eor"; goto and_orr_eor_mul;
16180 case 0x10d:
16181 /* ---------------- MULS Rd, Rm ---------------- */
16182 anOp = Iop_Mul32; anOpNm = "mul"; goto and_orr_eor_mul;
16183 and_orr_eor_mul: {
16184 /* Rd = Rd `op` Rm */
16185 UInt rM = INSN0(5,3);
16186 UInt rD = INSN0(2,0);
16187 IRTemp res = newTemp(Ity_I32);
16188 IRTemp oldV = newTemp(Ity_I32);
16189 IRTemp oldC = newTemp(Ity_I32);
16190 assign( oldV, mk_armg_calculate_flag_v() );
16191 assign( oldC, mk_armg_calculate_flag_c() );
16192 assign( res, binop(anOp, getIRegT(rD), getIRegT(rM) ));
16193 // not safe to read guest state after here
16194 // rD can never be r15
16195 putIRegT(rD, mkexpr(res), condT);
16196 setFlags_D1_D2_ND( ARMG_CC_OP_LOGIC, res, oldC, oldV,
16197 cond_AND_notInIT_T );
16198 DIP("%s r%u, r%u\n", anOpNm, rD, rM);
16199 goto decode_success;
16200 }
16201
16202 case 0x10E: {
16203 /* ---------------- BICS Rd, Rm ---------------- */
16204 /* Rd = Rd & ~Rm */
16205 UInt rM = INSN0(5,3);
16206 UInt rD = INSN0(2,0);
16207 IRTemp res = newTemp(Ity_I32);
16208 IRTemp oldV = newTemp(Ity_I32);
16209 IRTemp oldC = newTemp(Ity_I32);
16210 assign( oldV, mk_armg_calculate_flag_v() );
16211 assign( oldC, mk_armg_calculate_flag_c() );
16212 assign( res, binop(Iop_And32, getIRegT(rD),
16213 unop(Iop_Not32, getIRegT(rM) )));
16214 // not safe to read guest state after here
16215 // rD can never be r15
16216 putIRegT(rD, mkexpr(res), condT);
16217 setFlags_D1_D2_ND( ARMG_CC_OP_LOGIC, res, oldC, oldV,
16218 cond_AND_notInIT_T );
16219 DIP("bics r%u, r%u\n", rD, rM);
16220 goto decode_success;
16221 }
16222
16223 case 0x105: {
16224 /* ---------------- ADCS Rd, Rm ---------------- */
16225 /* Rd = Rd + Rm + oldC */
16226 UInt rM = INSN0(5,3);
16227 UInt rD = INSN0(2,0);
16228 IRTemp argL = newTemp(Ity_I32);
16229 IRTemp argR = newTemp(Ity_I32);
16230 IRTemp oldC = newTemp(Ity_I32);
16231 IRTemp res = newTemp(Ity_I32);
16232 assign(argL, getIRegT(rD));
16233 assign(argR, getIRegT(rM));
16234 assign(oldC, mk_armg_calculate_flag_c());
16235 assign(res, binop(Iop_Add32,
16236 binop(Iop_Add32, mkexpr(argL), mkexpr(argR)),
16237 mkexpr(oldC)));
16238 // rD can never be r15
16239 putIRegT(rD, mkexpr(res), condT);
16240 setFlags_D1_D2_ND( ARMG_CC_OP_ADC, argL, argR, oldC,
16241 cond_AND_notInIT_T );
16242 DIP("adcs r%u, r%u\n", rD, rM);
16243 goto decode_success;
16244 }
16245
16246 case 0x106: {
16247 /* ---------------- SBCS Rd, Rm ---------------- */
16248 /* Rd = Rd - Rm - (oldC ^ 1) */
16249 UInt rM = INSN0(5,3);
16250 UInt rD = INSN0(2,0);
16251 IRTemp argL = newTemp(Ity_I32);
16252 IRTemp argR = newTemp(Ity_I32);
16253 IRTemp oldC = newTemp(Ity_I32);
16254 IRTemp res = newTemp(Ity_I32);
16255 assign(argL, getIRegT(rD));
16256 assign(argR, getIRegT(rM));
16257 assign(oldC, mk_armg_calculate_flag_c());
16258 assign(res, binop(Iop_Sub32,
16259 binop(Iop_Sub32, mkexpr(argL), mkexpr(argR)),
16260 binop(Iop_Xor32, mkexpr(oldC), mkU32(1))));
16261 // rD can never be r15
16262 putIRegT(rD, mkexpr(res), condT);
16263 setFlags_D1_D2_ND( ARMG_CC_OP_SBB, argL, argR, oldC,
16264 cond_AND_notInIT_T );
16265 DIP("sbcs r%u, r%u\n", rD, rM);
16266 goto decode_success;
16267 }
16268
16269 case 0x2CB: {
16270 /* ---------------- UXTB Rd, Rm ---------------- */
16271 /* Rd = 8Uto32(Rm) */
16272 UInt rM = INSN0(5,3);
16273 UInt rD = INSN0(2,0);
16274 putIRegT(rD, binop(Iop_And32, getIRegT(rM), mkU32(0xFF)),
16275 condT);
16276 DIP("uxtb r%u, r%u\n", rD, rM);
16277 goto decode_success;
16278 }
16279
16280 case 0x2C9: {
16281 /* ---------------- SXTB Rd, Rm ---------------- */
16282 /* Rd = 8Sto32(Rm) */
16283 UInt rM = INSN0(5,3);
16284 UInt rD = INSN0(2,0);
16285 putIRegT(rD, binop(Iop_Sar32,
16286 binop(Iop_Shl32, getIRegT(rM), mkU8(24)),
16287 mkU8(24)),
16288 condT);
16289 DIP("sxtb r%u, r%u\n", rD, rM);
16290 goto decode_success;
16291 }
16292
16293 case 0x2CA: {
16294 /* ---------------- UXTH Rd, Rm ---------------- */
16295 /* Rd = 16Uto32(Rm) */
16296 UInt rM = INSN0(5,3);
16297 UInt rD = INSN0(2,0);
16298 putIRegT(rD, binop(Iop_And32, getIRegT(rM), mkU32(0xFFFF)),
16299 condT);
16300 DIP("uxth r%u, r%u\n", rD, rM);
16301 goto decode_success;
16302 }
16303
16304 case 0x2C8: {
16305 /* ---------------- SXTH Rd, Rm ---------------- */
16306 /* Rd = 16Sto32(Rm) */
16307 UInt rM = INSN0(5,3);
16308 UInt rD = INSN0(2,0);
16309 putIRegT(rD, binop(Iop_Sar32,
16310 binop(Iop_Shl32, getIRegT(rM), mkU8(16)),
16311 mkU8(16)),
16312 condT);
16313 DIP("sxth r%u, r%u\n", rD, rM);
16314 goto decode_success;
16315 }
16316
16317 case 0x102: // LSLS
16318 case 0x103: // LSRS
16319 case 0x104: // ASRS
16320 case 0x107: { // RORS
16321 /* ---------------- LSLS Rs, Rd ---------------- */
16322 /* ---------------- LSRS Rs, Rd ---------------- */
16323 /* ---------------- ASRS Rs, Rd ---------------- */
16324 /* ---------------- RORS Rs, Rd ---------------- */
16325 /* Rd = Rd `op` Rs, and set flags */
16326 UInt rS = INSN0(5,3);
16327 UInt rD = INSN0(2,0);
16328 IRTemp oldV = newTemp(Ity_I32);
16329 IRTemp rDt = newTemp(Ity_I32);
16330 IRTemp rSt = newTemp(Ity_I32);
16331 IRTemp res = newTemp(Ity_I32);
16332 IRTemp resC = newTemp(Ity_I32);
florian55085f82012-11-21 00:36:55 +000016333 const HChar* wot = "???";
sewardjd2664472010-08-22 12:44:20 +000016334 assign(rSt, getIRegT(rS));
16335 assign(rDt, getIRegT(rD));
16336 assign(oldV, mk_armg_calculate_flag_v());
16337 /* Does not appear to be the standard 'how' encoding. */
16338 switch (INSN0(15,6)) {
16339 case 0x102:
16340 compute_result_and_C_after_LSL_by_reg(
16341 dis_buf, &res, &resC, rDt, rSt, rD, rS
16342 );
16343 wot = "lsl";
16344 break;
16345 case 0x103:
16346 compute_result_and_C_after_LSR_by_reg(
16347 dis_buf, &res, &resC, rDt, rSt, rD, rS
16348 );
16349 wot = "lsr";
16350 break;
16351 case 0x104:
16352 compute_result_and_C_after_ASR_by_reg(
16353 dis_buf, &res, &resC, rDt, rSt, rD, rS
16354 );
16355 wot = "asr";
16356 break;
16357 case 0x107:
16358 compute_result_and_C_after_ROR_by_reg(
16359 dis_buf, &res, &resC, rDt, rSt, rD, rS
16360 );
16361 wot = "ror";
16362 break;
16363 default:
16364 /*NOTREACHED*/vassert(0);
16365 }
16366 // not safe to read guest state after this point
16367 putIRegT(rD, mkexpr(res), condT);
16368 setFlags_D1_D2_ND( ARMG_CC_OP_LOGIC, res, resC, oldV,
16369 cond_AND_notInIT_T );
16370 DIP("%ss r%u, r%u\n", wot, rS, rD);
16371 goto decode_success;
16372 }
16373
sewardj27312d32010-09-26 00:48:41 +000016374 case 0x2E8: // REV
16375 case 0x2E9: { // REV16
16376 /* ---------------- REV Rd, Rm ---------------- */
16377 /* ---------------- REV16 Rd, Rm ---------------- */
16378 UInt rM = INSN0(5,3);
16379 UInt rD = INSN0(2,0);
16380 Bool isREV = INSN0(15,6) == 0x2E8;
16381 IRTemp arg = newTemp(Ity_I32);
16382 assign(arg, getIRegT(rM));
16383 IRTemp res = isREV ? gen_REV(arg) : gen_REV16(arg);
16384 putIRegT(rD, mkexpr(res), condT);
16385 DIP("rev%s r%u, r%u\n", isREV ? "" : "16", rD, rM);
16386 goto decode_success;
16387 }
16388
sewardjd2664472010-08-22 12:44:20 +000016389 default:
16390 break; /* examine the next shortest prefix */
16391
16392 }
16393
16394
16395 /* ================ 16-bit 15:7 cases ================ */
16396
16397 switch (INSN0(15,7)) {
16398
16399 case BITS9(1,0,1,1,0,0,0,0,0): {
16400 /* ------------ ADD SP, #imm7 * 4 ------------ */
16401 UInt uimm7 = INSN0(6,0);
16402 putIRegT(13, binop(Iop_Add32, getIRegT(13), mkU32(uimm7 * 4)),
16403 condT);
16404 DIP("add sp, #%u\n", uimm7 * 4);
16405 goto decode_success;
16406 }
16407
16408 case BITS9(1,0,1,1,0,0,0,0,1): {
16409 /* ------------ SUB SP, #imm7 * 4 ------------ */
16410 UInt uimm7 = INSN0(6,0);
16411 putIRegT(13, binop(Iop_Sub32, getIRegT(13), mkU32(uimm7 * 4)),
16412 condT);
16413 DIP("sub sp, #%u\n", uimm7 * 4);
16414 goto decode_success;
16415 }
16416
16417 case BITS9(0,1,0,0,0,1,1,1,0): {
16418 /* ---------------- BX rM ---------------- */
16419 /* Branch to reg, and optionally switch modes. Reg contains a
16420 suitably encoded address therefore (w CPSR.T at the bottom).
16421 Have to special-case r15, as usual. */
16422 UInt rM = (INSN0(6,6) << 3) | INSN0(5,3);
sewardj8e074cc2010-09-02 21:14:10 +000016423 if (BITS3(0,0,0) == INSN0(2,0)) {
sewardjd2664472010-08-22 12:44:20 +000016424 IRTemp dst = newTemp(Ity_I32);
16425 gen_SIGILL_T_if_in_but_NLI_ITBlock(old_itstate, new_itstate);
16426 mk_skip_over_T16_if_cond_is_false(condT);
16427 condT = IRTemp_INVALID;
16428 // now uncond
16429 if (rM <= 14) {
16430 assign( dst, getIRegT(rM) );
16431 } else {
sewardjd2664472010-08-22 12:44:20 +000016432 vassert(rM == 15);
16433 assign( dst, mkU32(guest_R15_curr_instr_notENC + 4) );
16434 }
sewardjc6f970f2012-04-02 21:54:49 +000016435 llPutIReg(15, mkexpr(dst));
16436 dres.jk_StopHere = rM == 14 ? Ijk_Ret : Ijk_Boring;
16437 dres.whatNext = Dis_StopHere;
sewardjd2664472010-08-22 12:44:20 +000016438 DIP("bx r%u (possibly switch to ARM mode)\n", rM);
16439 goto decode_success;
16440 }
16441 break;
16442 }
16443
16444 /* ---------------- BLX rM ---------------- */
16445 /* Branch and link to interworking address in rM. */
16446 case BITS9(0,1,0,0,0,1,1,1,1): {
16447 if (BITS3(0,0,0) == INSN0(2,0)) {
16448 UInt rM = (INSN0(6,6) << 3) | INSN0(5,3);
16449 IRTemp dst = newTemp(Ity_I32);
16450 if (rM <= 14) {
16451 gen_SIGILL_T_if_in_but_NLI_ITBlock(old_itstate, new_itstate);
16452 mk_skip_over_T16_if_cond_is_false(condT);
16453 condT = IRTemp_INVALID;
16454 // now uncond
16455 /* We're returning to Thumb code, hence "| 1" */
16456 assign( dst, getIRegT(rM) );
16457 putIRegT( 14, mkU32( (guest_R15_curr_instr_notENC + 2) | 1 ),
16458 IRTemp_INVALID );
sewardjc6f970f2012-04-02 21:54:49 +000016459 llPutIReg(15, mkexpr(dst));
16460 dres.jk_StopHere = Ijk_Call;
16461 dres.whatNext = Dis_StopHere;
sewardjd2664472010-08-22 12:44:20 +000016462 DIP("blx r%u (possibly switch to ARM mode)\n", rM);
16463 goto decode_success;
16464 }
16465 /* else unpredictable, fall through */
16466 }
16467 break;
16468 }
16469
16470 default:
16471 break; /* examine the next shortest prefix */
16472
16473 }
16474
16475
16476 /* ================ 16-bit 15:8 cases ================ */
16477
16478 switch (INSN0(15,8)) {
16479
16480 case BITS8(1,1,0,1,1,1,1,1): {
16481 /* ---------------- SVC ---------------- */
16482 UInt imm8 = INSN0(7,0);
16483 if (imm8 == 0) {
16484 /* A syscall. We can't do this conditionally, hence: */
16485 mk_skip_over_T16_if_cond_is_false( condT );
16486 // FIXME: what if we have to back up and restart this insn?
16487 // then ITSTATE will be wrong (we'll have it as "used")
16488 // when it isn't. Correct is to save ITSTATE in a
16489 // stash pseudo-reg, and back up from that if we have to
16490 // restart.
16491 // uncond after here
sewardjc6f970f2012-04-02 21:54:49 +000016492 llPutIReg(15, mkU32( (guest_R15_curr_instr_notENC + 2) | 1 ));
16493 dres.jk_StopHere = Ijk_Sys_syscall;
16494 dres.whatNext = Dis_StopHere;
sewardjd2664472010-08-22 12:44:20 +000016495 DIP("svc #0x%08x\n", imm8);
16496 goto decode_success;
16497 }
16498 /* else fall through */
16499 break;
16500 }
16501
16502 case BITS8(0,1,0,0,0,1,0,0): {
16503 /* ---------------- ADD(HI) Rd, Rm ---------------- */
16504 UInt h1 = INSN0(7,7);
16505 UInt h2 = INSN0(6,6);
16506 UInt rM = (h2 << 3) | INSN0(5,3);
16507 UInt rD = (h1 << 3) | INSN0(2,0);
16508 //if (h1 == 0 && h2 == 0) { // Original T1 was more restrictive
16509 if (rD == 15 && rM == 15) {
16510 // then it's invalid
16511 } else {
16512 IRTemp res = newTemp(Ity_I32);
16513 assign( res, binop(Iop_Add32, getIRegT(rD), getIRegT(rM) ));
16514 if (rD != 15) {
16515 putIRegT( rD, mkexpr(res), condT );
16516 } else {
16517 /* Only allowed outside or last-in IT block; SIGILL if not so. */
16518 gen_SIGILL_T_if_in_but_NLI_ITBlock(old_itstate, new_itstate);
16519 /* jump over insn if not selected */
16520 mk_skip_over_T16_if_cond_is_false(condT);
16521 condT = IRTemp_INVALID;
16522 // now uncond
16523 /* non-interworking branch */
16524 irsb->next = binop(Iop_Or32, mkexpr(res), mkU32(1));
16525 irsb->jumpkind = Ijk_Boring;
16526 dres.whatNext = Dis_StopHere;
16527 }
16528 DIP("add(hi) r%u, r%u\n", rD, rM);
16529 goto decode_success;
16530 }
16531 break;
16532 }
16533
16534 case BITS8(0,1,0,0,0,1,0,1): {
16535 /* ---------------- CMP(HI) Rd, Rm ---------------- */
16536 UInt h1 = INSN0(7,7);
16537 UInt h2 = INSN0(6,6);
16538 UInt rM = (h2 << 3) | INSN0(5,3);
16539 UInt rN = (h1 << 3) | INSN0(2,0);
16540 if (h1 != 0 || h2 != 0) {
16541 IRTemp argL = newTemp(Ity_I32);
16542 IRTemp argR = newTemp(Ity_I32);
16543 assign( argL, getIRegT(rN) );
16544 assign( argR, getIRegT(rM) );
16545 /* Update flags regardless of whether in an IT block or not. */
16546 setFlags_D1_D2( ARMG_CC_OP_SUB, argL, argR, condT );
16547 DIP("cmphi r%u, r%u\n", rN, rM);
16548 goto decode_success;
16549 }
16550 break;
16551 }
16552
16553 case BITS8(0,1,0,0,0,1,1,0): {
16554 /* ---------------- MOV(HI) Rd, Rm ---------------- */
16555 UInt h1 = INSN0(7,7);
16556 UInt h2 = INSN0(6,6);
16557 UInt rM = (h2 << 3) | INSN0(5,3);
16558 UInt rD = (h1 << 3) | INSN0(2,0);
16559 /* The old ARM ARM seems to disallow the case where both Rd and
16560 Rm are "low" registers, but newer versions allow it. */
16561 if (1 /*h1 != 0 || h2 != 0*/) {
16562 IRTemp val = newTemp(Ity_I32);
16563 assign( val, getIRegT(rM) );
16564 if (rD != 15) {
16565 putIRegT( rD, mkexpr(val), condT );
16566 } else {
16567 /* Only allowed outside or last-in IT block; SIGILL if not so. */
16568 gen_SIGILL_T_if_in_but_NLI_ITBlock(old_itstate, new_itstate);
16569 /* jump over insn if not selected */
16570 mk_skip_over_T16_if_cond_is_false(condT);
16571 condT = IRTemp_INVALID;
16572 // now uncond
16573 /* non-interworking branch */
sewardjc6f970f2012-04-02 21:54:49 +000016574 llPutIReg(15, binop(Iop_Or32, mkexpr(val), mkU32(1)));
16575 dres.jk_StopHere = rM == 14 ? Ijk_Ret : Ijk_Boring;
16576 dres.whatNext = Dis_StopHere;
sewardjd2664472010-08-22 12:44:20 +000016577 }
16578 DIP("mov r%u, r%u\n", rD, rM);
16579 goto decode_success;
16580 }
16581 break;
16582 }
16583
16584 case BITS8(1,0,1,1,1,1,1,1): {
16585 /* ---------------- IT (if-then) ---------------- */
16586 UInt firstcond = INSN0(7,4);
16587 UInt mask = INSN0(3,0);
16588 UInt newITSTATE = 0;
16589 /* This is the ITSTATE represented as described in
16590 libvex_guest_arm.h. It is not the ARM ARM representation. */
florian5df8ab02012-10-13 19:34:19 +000016591 HChar c1 = '.';
16592 HChar c2 = '.';
16593 HChar c3 = '.';
sewardjd2664472010-08-22 12:44:20 +000016594 Bool valid = compute_ITSTATE( &newITSTATE, &c1, &c2, &c3,
16595 firstcond, mask );
16596 if (valid && firstcond != 0xF/*NV*/) {
16597 /* Not allowed in an IT block; SIGILL if so. */
16598 gen_SIGILL_T_if_in_ITBlock(old_itstate, new_itstate);
16599
16600 IRTemp t = newTemp(Ity_I32);
16601 assign(t, mkU32(newITSTATE));
16602 put_ITSTATE(t);
16603
16604 DIP("it%c%c%c %s\n", c1, c2, c3, nCC(firstcond));
16605 goto decode_success;
16606 }
16607 break;
16608 }
16609
16610 case BITS8(1,0,1,1,0,0,0,1):
16611 case BITS8(1,0,1,1,0,0,1,1):
16612 case BITS8(1,0,1,1,1,0,0,1):
16613 case BITS8(1,0,1,1,1,0,1,1): {
16614 /* ---------------- CB{N}Z ---------------- */
16615 UInt rN = INSN0(2,0);
16616 UInt bOP = INSN0(11,11);
16617 UInt imm32 = (INSN0(9,9) << 6) | (INSN0(7,3) << 1);
16618 gen_SIGILL_T_if_in_ITBlock(old_itstate, new_itstate);
16619 /* It's a conditional branch forward. */
16620 IRTemp kond = newTemp(Ity_I1);
16621 assign( kond, binop(bOP ? Iop_CmpNE32 : Iop_CmpEQ32,
16622 getIRegT(rN), mkU32(0)) );
16623
16624 vassert(0 == (guest_R15_curr_instr_notENC & 1));
16625 /* Looks like the nearest insn we can branch to is the one after
16626 next. That makes sense, as there's no point in being able to
16627 encode a conditional branch to the next instruction. */
16628 UInt dst = (guest_R15_curr_instr_notENC + 4 + imm32) | 1;
16629 stmt(IRStmt_Exit( mkexpr(kond),
16630 Ijk_Boring,
sewardjc6f970f2012-04-02 21:54:49 +000016631 IRConst_U32(toUInt(dst)),
16632 OFFB_R15T ));
sewardjd2664472010-08-22 12:44:20 +000016633 DIP("cb%s r%u, 0x%x\n", bOP ? "nz" : "z", rN, dst - 1);
16634 goto decode_success;
16635 }
16636
16637 default:
16638 break; /* examine the next shortest prefix */
16639
16640 }
16641
16642
16643 /* ================ 16-bit 15:9 cases ================ */
16644
16645 switch (INSN0(15,9)) {
16646
16647 case BITS7(1,0,1,1,0,1,0): {
16648 /* ---------------- PUSH ---------------- */
16649 /* This is a bit like STMxx, but way simpler. Complications we
16650 don't have to deal with:
16651 * SP being one of the transferred registers
16652 * direction (increment vs decrement)
16653 * before-vs-after-ness
16654 */
16655 Int i, nRegs;
16656 UInt bitR = INSN0(8,8);
16657 UInt regList = INSN0(7,0);
16658 if (bitR) regList |= (1 << 14);
16659
sewardjb0f1df22012-06-11 21:54:58 +000016660 /* At least one register must be transferred, else result is
16661 UNPREDICTABLE. */
sewardjd2664472010-08-22 12:44:20 +000016662 if (regList != 0) {
16663 /* Since we can't generate a guaranteed non-trapping IR
16664 sequence, (1) jump over the insn if it is gated false, and
16665 (2) back out the ITSTATE update. */
16666 mk_skip_over_T16_if_cond_is_false(condT);
16667 condT = IRTemp_INVALID;
16668 put_ITSTATE(old_itstate);
16669 // now uncond
16670
16671 nRegs = 0;
16672 for (i = 0; i < 16; i++) {
16673 if ((regList & (1 << i)) != 0)
16674 nRegs++;
16675 }
sewardjb0f1df22012-06-11 21:54:58 +000016676 vassert(nRegs >= 1 && nRegs <= 9);
sewardjd2664472010-08-22 12:44:20 +000016677
16678 /* Move SP down first of all, so we're "covered". And don't
16679 mess with its alignment. */
16680 IRTemp newSP = newTemp(Ity_I32);
16681 assign(newSP, binop(Iop_Sub32, getIRegT(13), mkU32(4 * nRegs)));
16682 putIRegT(13, mkexpr(newSP), IRTemp_INVALID);
16683
16684 /* Generate a transfer base address as a forced-aligned
16685 version of the final SP value. */
16686 IRTemp base = newTemp(Ity_I32);
16687 assign(base, binop(Iop_And32, mkexpr(newSP), mkU32(~3)));
16688
16689 /* Now the transfers */
16690 nRegs = 0;
16691 for (i = 0; i < 16; i++) {
16692 if ((regList & (1 << i)) != 0) {
16693 storeLE( binop(Iop_Add32, mkexpr(base), mkU32(4 * nRegs)),
16694 getIRegT(i) );
16695 nRegs++;
16696 }
16697 }
16698
16699 /* Reinstate the ITSTATE update. */
16700 put_ITSTATE(new_itstate);
16701
16702 DIP("push {%s0x%04x}\n", bitR ? "lr," : "", regList & 0xFF);
16703 goto decode_success;
16704 }
16705 break;
16706 }
16707
16708 case BITS7(1,0,1,1,1,1,0): {
16709 /* ---------------- POP ---------------- */
16710 Int i, nRegs;
16711 UInt bitR = INSN0(8,8);
16712 UInt regList = INSN0(7,0);
16713
sewardjb0f1df22012-06-11 21:54:58 +000016714 /* At least one register must be transferred, else result is
16715 UNPREDICTABLE. */
sewardjd2664472010-08-22 12:44:20 +000016716 if (regList != 0 || bitR) {
16717 /* Since we can't generate a guaranteed non-trapping IR
16718 sequence, (1) jump over the insn if it is gated false, and
16719 (2) back out the ITSTATE update. */
16720 mk_skip_over_T16_if_cond_is_false(condT);
16721 condT = IRTemp_INVALID;
16722 put_ITSTATE(old_itstate);
16723 // now uncond
16724
16725 nRegs = 0;
16726 for (i = 0; i < 8; i++) {
16727 if ((regList & (1 << i)) != 0)
16728 nRegs++;
16729 }
sewardjb0f1df22012-06-11 21:54:58 +000016730 vassert(nRegs >= 0 && nRegs <= 8);
sewardjd2664472010-08-22 12:44:20 +000016731 vassert(bitR == 0 || bitR == 1);
16732
16733 IRTemp oldSP = newTemp(Ity_I32);
16734 assign(oldSP, getIRegT(13));
16735
16736 /* Generate a transfer base address as a forced-aligned
16737 version of the original SP value. */
16738 IRTemp base = newTemp(Ity_I32);
16739 assign(base, binop(Iop_And32, mkexpr(oldSP), mkU32(~3)));
16740
16741 /* Compute a new value for SP, but don't install it yet, so
16742 that we're "covered" until all the transfers are done.
16743 And don't mess with its alignment. */
16744 IRTemp newSP = newTemp(Ity_I32);
16745 assign(newSP, binop(Iop_Add32, mkexpr(oldSP),
16746 mkU32(4 * (nRegs + bitR))));
16747
16748 /* Now the transfers, not including PC */
16749 nRegs = 0;
16750 for (i = 0; i < 8; i++) {
16751 if ((regList & (1 << i)) != 0) {
16752 putIRegT(i, loadLE( Ity_I32,
16753 binop(Iop_Add32, mkexpr(base),
16754 mkU32(4 * nRegs))),
16755 IRTemp_INVALID );
16756 nRegs++;
16757 }
16758 }
16759
16760 IRTemp newPC = IRTemp_INVALID;
16761 if (bitR) {
16762 newPC = newTemp(Ity_I32);
16763 assign( newPC, loadLE( Ity_I32,
16764 binop(Iop_Add32, mkexpr(base),
16765 mkU32(4 * nRegs))));
16766 }
16767
16768 /* Now we can safely install the new SP value */
16769 putIRegT(13, mkexpr(newSP), IRTemp_INVALID);
16770
16771 /* Reinstate the ITSTATE update. */
16772 put_ITSTATE(new_itstate);
16773
16774 /* now, do we also have to do a branch? If so, it turns out
16775 that the new PC value is encoded exactly as we need it to
16776 be -- with CPSR.T in the bottom bit. So we can simply use
16777 it as is, no need to mess with it. Note, therefore, this
16778 is an interworking return. */
16779 if (bitR) {
sewardjc6f970f2012-04-02 21:54:49 +000016780 llPutIReg(15, mkexpr(newPC));
16781 dres.jk_StopHere = Ijk_Ret;
16782 dres.whatNext = Dis_StopHere;
sewardjd2664472010-08-22 12:44:20 +000016783 }
16784
16785 DIP("pop {%s0x%04x}\n", bitR ? "pc," : "", regList & 0xFF);
16786 goto decode_success;
16787 }
16788 break;
16789 }
16790
16791 case BITS7(0,0,0,1,1,1,0): /* ADDS */
16792 case BITS7(0,0,0,1,1,1,1): { /* SUBS */
16793 /* ---------------- ADDS Rd, Rn, #uimm3 ---------------- */
16794 /* ---------------- SUBS Rd, Rn, #uimm3 ---------------- */
16795 UInt uimm3 = INSN0(8,6);
16796 UInt rN = INSN0(5,3);
16797 UInt rD = INSN0(2,0);
16798 UInt isSub = INSN0(9,9);
16799 IRTemp argL = newTemp(Ity_I32);
16800 IRTemp argR = newTemp(Ity_I32);
16801 assign( argL, getIRegT(rN) );
16802 assign( argR, mkU32(uimm3) );
16803 putIRegT(rD, binop(isSub ? Iop_Sub32 : Iop_Add32,
16804 mkexpr(argL), mkexpr(argR)),
16805 condT);
16806 setFlags_D1_D2( isSub ? ARMG_CC_OP_SUB : ARMG_CC_OP_ADD,
16807 argL, argR, cond_AND_notInIT_T );
16808 DIP("%s r%u, r%u, #%u\n", isSub ? "subs" : "adds", rD, rN, uimm3);
16809 goto decode_success;
16810 }
16811
16812 case BITS7(0,0,0,1,1,0,0): /* ADDS */
16813 case BITS7(0,0,0,1,1,0,1): { /* SUBS */
16814 /* ---------------- ADDS Rd, Rn, Rm ---------------- */
16815 /* ---------------- SUBS Rd, Rn, Rm ---------------- */
16816 UInt rM = INSN0(8,6);
16817 UInt rN = INSN0(5,3);
16818 UInt rD = INSN0(2,0);
16819 UInt isSub = INSN0(9,9);
16820 IRTemp argL = newTemp(Ity_I32);
16821 IRTemp argR = newTemp(Ity_I32);
16822 assign( argL, getIRegT(rN) );
16823 assign( argR, getIRegT(rM) );
16824 putIRegT( rD, binop(isSub ? Iop_Sub32 : Iop_Add32,
16825 mkexpr(argL), mkexpr(argR)),
16826 condT );
16827 setFlags_D1_D2( isSub ? ARMG_CC_OP_SUB : ARMG_CC_OP_ADD,
16828 argL, argR, cond_AND_notInIT_T );
16829 DIP("%s r%u, r%u, r%u\n", isSub ? "subs" : "adds", rD, rN, rM);
16830 goto decode_success;
16831 }
16832
16833 case BITS7(0,1,0,1,0,0,0): /* STR */
16834 case BITS7(0,1,0,1,1,0,0): { /* LDR */
16835 /* ------------- LDR Rd, [Rn, Rm] ------------- */
16836 /* ------------- STR Rd, [Rn, Rm] ------------- */
16837 /* LDR/STR Rd, [Rn + Rm] */
16838 UInt rD = INSN0(2,0);
16839 UInt rN = INSN0(5,3);
16840 UInt rM = INSN0(8,6);
16841 UInt isLD = INSN0(11,11);
16842
sewardjd2664472010-08-22 12:44:20 +000016843 IRExpr* ea = binop(Iop_Add32, getIRegT(rN), getIRegT(rM));
16844 put_ITSTATE(old_itstate); // backout
16845 if (isLD) {
sewardjcfe046e2013-01-17 14:23:53 +000016846 IRTemp tD = newTemp(Ity_I32);
16847 loadGuardedLE( tD, ILGop_Ident32, ea, llGetIReg(rD), condT );
16848 putIRegT(rD, mkexpr(tD), IRTemp_INVALID);
sewardjd2664472010-08-22 12:44:20 +000016849 } else {
sewardjcfe046e2013-01-17 14:23:53 +000016850 storeGuardedLE(ea, getIRegT(rD), condT);
sewardjd2664472010-08-22 12:44:20 +000016851 }
16852 put_ITSTATE(new_itstate); // restore
16853
16854 DIP("%s r%u, [r%u, r%u]\n", isLD ? "ldr" : "str", rD, rN, rM);
16855 goto decode_success;
16856 }
16857
16858 case BITS7(0,1,0,1,0,0,1):
16859 case BITS7(0,1,0,1,1,0,1): {
16860 /* ------------- LDRH Rd, [Rn, Rm] ------------- */
16861 /* ------------- STRH Rd, [Rn, Rm] ------------- */
16862 /* LDRH/STRH Rd, [Rn + Rm] */
16863 UInt rD = INSN0(2,0);
16864 UInt rN = INSN0(5,3);
16865 UInt rM = INSN0(8,6);
16866 UInt isLD = INSN0(11,11);
16867
sewardjd2664472010-08-22 12:44:20 +000016868 IRExpr* ea = binop(Iop_Add32, getIRegT(rN), getIRegT(rM));
16869 put_ITSTATE(old_itstate); // backout
16870 if (isLD) {
sewardjcfe046e2013-01-17 14:23:53 +000016871 IRTemp tD = newTemp(Ity_I32);
16872 loadGuardedLE(tD, ILGop_16Uto32, ea, llGetIReg(rD), condT);
16873 putIRegT(rD, mkexpr(tD), IRTemp_INVALID);
sewardjd2664472010-08-22 12:44:20 +000016874 } else {
sewardjcfe046e2013-01-17 14:23:53 +000016875 storeGuardedLE( ea, unop(Iop_32to16, getIRegT(rD)), condT );
sewardjd2664472010-08-22 12:44:20 +000016876 }
16877 put_ITSTATE(new_itstate); // restore
16878
16879 DIP("%sh r%u, [r%u, r%u]\n", isLD ? "ldr" : "str", rD, rN, rM);
16880 goto decode_success;
16881 }
16882
16883 case BITS7(0,1,0,1,1,1,1): {
16884 /* ------------- LDRSH Rd, [Rn, Rm] ------------- */
16885 /* LDRSH Rd, [Rn + Rm] */
16886 UInt rD = INSN0(2,0);
16887 UInt rN = INSN0(5,3);
16888 UInt rM = INSN0(8,6);
16889
sewardjd2664472010-08-22 12:44:20 +000016890 IRExpr* ea = binop(Iop_Add32, getIRegT(rN), getIRegT(rM));
16891 put_ITSTATE(old_itstate); // backout
sewardjcfe046e2013-01-17 14:23:53 +000016892 IRTemp tD = newTemp(Ity_I32);
16893 loadGuardedLE(tD, ILGop_16Sto32, ea, llGetIReg(rD), condT);
16894 putIRegT(rD, mkexpr(tD), IRTemp_INVALID);
sewardjd2664472010-08-22 12:44:20 +000016895 put_ITSTATE(new_itstate); // restore
16896
16897 DIP("ldrsh r%u, [r%u, r%u]\n", rD, rN, rM);
16898 goto decode_success;
16899 }
16900
16901 case BITS7(0,1,0,1,0,1,1): {
16902 /* ------------- LDRSB Rd, [Rn, Rm] ------------- */
16903 /* LDRSB Rd, [Rn + Rm] */
16904 UInt rD = INSN0(2,0);
16905 UInt rN = INSN0(5,3);
16906 UInt rM = INSN0(8,6);
16907
sewardjd2664472010-08-22 12:44:20 +000016908 IRExpr* ea = binop(Iop_Add32, getIRegT(rN), getIRegT(rM));
16909 put_ITSTATE(old_itstate); // backout
sewardjcfe046e2013-01-17 14:23:53 +000016910 IRTemp tD = newTemp(Ity_I32);
16911 loadGuardedLE(tD, ILGop_8Sto32, ea, llGetIReg(rD), condT);
16912 putIRegT(rD, mkexpr(tD), IRTemp_INVALID);
sewardjd2664472010-08-22 12:44:20 +000016913 put_ITSTATE(new_itstate); // restore
16914
16915 DIP("ldrsb r%u, [r%u, r%u]\n", rD, rN, rM);
16916 goto decode_success;
16917 }
16918
16919 case BITS7(0,1,0,1,0,1,0):
16920 case BITS7(0,1,0,1,1,1,0): {
16921 /* ------------- LDRB Rd, [Rn, Rm] ------------- */
16922 /* ------------- STRB Rd, [Rn, Rm] ------------- */
16923 /* LDRB/STRB Rd, [Rn + Rm] */
16924 UInt rD = INSN0(2,0);
16925 UInt rN = INSN0(5,3);
16926 UInt rM = INSN0(8,6);
16927 UInt isLD = INSN0(11,11);
16928
sewardjd2664472010-08-22 12:44:20 +000016929 IRExpr* ea = binop(Iop_Add32, getIRegT(rN), getIRegT(rM));
16930 put_ITSTATE(old_itstate); // backout
16931 if (isLD) {
sewardjcfe046e2013-01-17 14:23:53 +000016932 IRTemp tD = newTemp(Ity_I32);
16933 loadGuardedLE(tD, ILGop_8Uto32, ea, llGetIReg(rD), condT);
16934 putIRegT(rD, mkexpr(tD), IRTemp_INVALID);
sewardjd2664472010-08-22 12:44:20 +000016935 } else {
sewardjcfe046e2013-01-17 14:23:53 +000016936 storeGuardedLE( ea, unop(Iop_32to8, getIRegT(rD)), condT );
sewardjd2664472010-08-22 12:44:20 +000016937 }
16938 put_ITSTATE(new_itstate); // restore
16939
16940 DIP("%sb r%u, [r%u, r%u]\n", isLD ? "ldr" : "str", rD, rN, rM);
16941 goto decode_success;
16942 }
16943
16944 default:
16945 break; /* examine the next shortest prefix */
16946
16947 }
16948
16949
16950 /* ================ 16-bit 15:11 cases ================ */
16951
16952 switch (INSN0(15,11)) {
16953
16954 case BITS5(0,0,1,1,0):
16955 case BITS5(0,0,1,1,1): {
16956 /* ---------------- ADDS Rn, #uimm8 ---------------- */
16957 /* ---------------- SUBS Rn, #uimm8 ---------------- */
16958 UInt isSub = INSN0(11,11);
16959 UInt rN = INSN0(10,8);
16960 UInt uimm8 = INSN0(7,0);
16961 IRTemp argL = newTemp(Ity_I32);
16962 IRTemp argR = newTemp(Ity_I32);
16963 assign( argL, getIRegT(rN) );
16964 assign( argR, mkU32(uimm8) );
16965 putIRegT( rN, binop(isSub ? Iop_Sub32 : Iop_Add32,
16966 mkexpr(argL), mkexpr(argR)), condT );
16967 setFlags_D1_D2( isSub ? ARMG_CC_OP_SUB : ARMG_CC_OP_ADD,
16968 argL, argR, cond_AND_notInIT_T );
16969 DIP("%s r%u, #%u\n", isSub ? "subs" : "adds", rN, uimm8);
16970 goto decode_success;
16971 }
16972
16973 case BITS5(1,0,1,0,0): {
16974 /* ---------------- ADD rD, PC, #imm8 * 4 ---------------- */
16975 /* a.k.a. ADR */
16976 /* rD = align4(PC) + imm8 * 4 */
16977 UInt rD = INSN0(10,8);
16978 UInt imm8 = INSN0(7,0);
16979 putIRegT(rD, binop(Iop_Add32,
sewardjdf86f162010-08-22 18:47:30 +000016980 binop(Iop_And32, getIRegT(15), mkU32(~3U)),
sewardjd2664472010-08-22 12:44:20 +000016981 mkU32(imm8 * 4)),
16982 condT);
16983 DIP("add r%u, pc, #%u\n", rD, imm8 * 4);
16984 goto decode_success;
16985 }
16986
16987 case BITS5(1,0,1,0,1): {
16988 /* ---------------- ADD rD, SP, #imm8 * 4 ---------------- */
16989 UInt rD = INSN0(10,8);
16990 UInt imm8 = INSN0(7,0);
16991 putIRegT(rD, binop(Iop_Add32, getIRegT(13), mkU32(imm8 * 4)),
16992 condT);
16993 DIP("add r%u, r13, #%u\n", rD, imm8 * 4);
16994 goto decode_success;
16995 }
16996
16997 case BITS5(0,0,1,0,1): {
16998 /* ---------------- CMP Rn, #uimm8 ---------------- */
16999 UInt rN = INSN0(10,8);
17000 UInt uimm8 = INSN0(7,0);
17001 IRTemp argL = newTemp(Ity_I32);
17002 IRTemp argR = newTemp(Ity_I32);
17003 assign( argL, getIRegT(rN) );
17004 assign( argR, mkU32(uimm8) );
17005 /* Update flags regardless of whether in an IT block or not. */
17006 setFlags_D1_D2( ARMG_CC_OP_SUB, argL, argR, condT );
17007 DIP("cmp r%u, #%u\n", rN, uimm8);
17008 goto decode_success;
17009 }
17010
17011 case BITS5(0,0,1,0,0): {
17012 /* -------------- (T1) MOVS Rn, #uimm8 -------------- */
17013 UInt rD = INSN0(10,8);
17014 UInt uimm8 = INSN0(7,0);
17015 IRTemp oldV = newTemp(Ity_I32);
17016 IRTemp oldC = newTemp(Ity_I32);
17017 IRTemp res = newTemp(Ity_I32);
17018 assign( oldV, mk_armg_calculate_flag_v() );
17019 assign( oldC, mk_armg_calculate_flag_c() );
17020 assign( res, mkU32(uimm8) );
17021 putIRegT(rD, mkexpr(res), condT);
17022 setFlags_D1_D2_ND( ARMG_CC_OP_LOGIC, res, oldC, oldV,
17023 cond_AND_notInIT_T );
17024 DIP("movs r%u, #%u\n", rD, uimm8);
17025 goto decode_success;
17026 }
17027
17028 case BITS5(0,1,0,0,1): {
17029 /* ------------- LDR Rd, [PC, #imm8 * 4] ------------- */
17030 /* LDR Rd, [align4(PC) + imm8 * 4] */
17031 UInt rD = INSN0(10,8);
17032 UInt imm8 = INSN0(7,0);
17033 IRTemp ea = newTemp(Ity_I32);
17034
sewardjd2664472010-08-22 12:44:20 +000017035 assign(ea, binop(Iop_Add32,
sewardjdf86f162010-08-22 18:47:30 +000017036 binop(Iop_And32, getIRegT(15), mkU32(~3U)),
sewardjd2664472010-08-22 12:44:20 +000017037 mkU32(imm8 * 4)));
17038 put_ITSTATE(old_itstate); // backout
sewardjcfe046e2013-01-17 14:23:53 +000017039 IRTemp tD = newTemp(Ity_I32);
17040 loadGuardedLE( tD, ILGop_Ident32, mkexpr(ea), llGetIReg(rD), condT );
17041 putIRegT(rD, mkexpr(tD), IRTemp_INVALID);
sewardjd2664472010-08-22 12:44:20 +000017042 put_ITSTATE(new_itstate); // restore
17043
17044 DIP("ldr r%u, [pc, #%u]\n", rD, imm8 * 4);
17045 goto decode_success;
17046 }
17047
17048 case BITS5(0,1,1,0,0): /* STR */
17049 case BITS5(0,1,1,0,1): { /* LDR */
17050 /* ------------- LDR Rd, [Rn, #imm5 * 4] ------------- */
17051 /* ------------- STR Rd, [Rn, #imm5 * 4] ------------- */
17052 /* LDR/STR Rd, [Rn + imm5 * 4] */
17053 UInt rD = INSN0(2,0);
17054 UInt rN = INSN0(5,3);
17055 UInt imm5 = INSN0(10,6);
17056 UInt isLD = INSN0(11,11);
17057
sewardjd2664472010-08-22 12:44:20 +000017058 IRExpr* ea = binop(Iop_Add32, getIRegT(rN), mkU32(imm5 * 4));
17059 put_ITSTATE(old_itstate); // backout
17060 if (isLD) {
sewardjcfe046e2013-01-17 14:23:53 +000017061 IRTemp tD = newTemp(Ity_I32);
17062 loadGuardedLE( tD, ILGop_Ident32, ea, llGetIReg(rD), condT );
17063 putIRegT(rD, mkexpr(tD), IRTemp_INVALID);
sewardjd2664472010-08-22 12:44:20 +000017064 } else {
sewardjcfe046e2013-01-17 14:23:53 +000017065 storeGuardedLE( ea, getIRegT(rD), condT );
sewardjd2664472010-08-22 12:44:20 +000017066 }
17067 put_ITSTATE(new_itstate); // restore
17068
17069 DIP("%s r%u, [r%u, #%u]\n", isLD ? "ldr" : "str", rD, rN, imm5 * 4);
17070 goto decode_success;
17071 }
17072
17073 case BITS5(1,0,0,0,0): /* STRH */
17074 case BITS5(1,0,0,0,1): { /* LDRH */
17075 /* ------------- LDRH Rd, [Rn, #imm5 * 2] ------------- */
17076 /* ------------- STRH Rd, [Rn, #imm5 * 2] ------------- */
17077 /* LDRH/STRH Rd, [Rn + imm5 * 2] */
17078 UInt rD = INSN0(2,0);
17079 UInt rN = INSN0(5,3);
17080 UInt imm5 = INSN0(10,6);
17081 UInt isLD = INSN0(11,11);
17082
sewardjd2664472010-08-22 12:44:20 +000017083 IRExpr* ea = binop(Iop_Add32, getIRegT(rN), mkU32(imm5 * 2));
17084 put_ITSTATE(old_itstate); // backout
17085 if (isLD) {
sewardjcfe046e2013-01-17 14:23:53 +000017086 IRTemp tD = newTemp(Ity_I32);
17087 loadGuardedLE( tD, ILGop_16Uto32, ea, llGetIReg(rD), condT );
17088 putIRegT(rD, mkexpr(tD), IRTemp_INVALID);
sewardjd2664472010-08-22 12:44:20 +000017089 } else {
sewardjcfe046e2013-01-17 14:23:53 +000017090 storeGuardedLE( ea, unop(Iop_32to16, getIRegT(rD)), condT );
sewardjd2664472010-08-22 12:44:20 +000017091 }
17092 put_ITSTATE(new_itstate); // restore
17093
17094 DIP("%sh r%u, [r%u, #%u]\n", isLD ? "ldr" : "str", rD, rN, imm5 * 2);
17095 goto decode_success;
17096 }
17097
17098 case BITS5(0,1,1,1,0): /* STRB */
17099 case BITS5(0,1,1,1,1): { /* LDRB */
17100 /* ------------- LDRB Rd, [Rn, #imm5] ------------- */
17101 /* ------------- STRB Rd, [Rn, #imm5] ------------- */
17102 /* LDRB/STRB Rd, [Rn + imm5] */
17103 UInt rD = INSN0(2,0);
17104 UInt rN = INSN0(5,3);
17105 UInt imm5 = INSN0(10,6);
17106 UInt isLD = INSN0(11,11);
17107
sewardjd2664472010-08-22 12:44:20 +000017108 IRExpr* ea = binop(Iop_Add32, getIRegT(rN), mkU32(imm5));
17109 put_ITSTATE(old_itstate); // backout
17110 if (isLD) {
sewardjcfe046e2013-01-17 14:23:53 +000017111 IRTemp tD = newTemp(Ity_I32);
17112 loadGuardedLE( tD, ILGop_8Uto32, ea, llGetIReg(rD), condT );
17113 putIRegT(rD, mkexpr(tD), IRTemp_INVALID);
sewardjd2664472010-08-22 12:44:20 +000017114 } else {
sewardjcfe046e2013-01-17 14:23:53 +000017115 storeGuardedLE( ea, unop(Iop_32to8, getIRegT(rD)), condT );
sewardjd2664472010-08-22 12:44:20 +000017116 }
17117 put_ITSTATE(new_itstate); // restore
17118
17119 DIP("%sb r%u, [r%u, #%u]\n", isLD ? "ldr" : "str", rD, rN, imm5);
17120 goto decode_success;
17121 }
17122
17123 case BITS5(1,0,0,1,0): /* STR */
17124 case BITS5(1,0,0,1,1): { /* LDR */
17125 /* ------------- LDR Rd, [SP, #imm8 * 4] ------------- */
17126 /* ------------- STR Rd, [SP, #imm8 * 4] ------------- */
17127 /* LDR/STR Rd, [SP + imm8 * 4] */
17128 UInt rD = INSN0(10,8);
17129 UInt imm8 = INSN0(7,0);
17130 UInt isLD = INSN0(11,11);
17131
sewardjd2664472010-08-22 12:44:20 +000017132 IRExpr* ea = binop(Iop_Add32, getIRegT(13), mkU32(imm8 * 4));
17133 put_ITSTATE(old_itstate); // backout
17134 if (isLD) {
sewardjcfe046e2013-01-17 14:23:53 +000017135 IRTemp tD = newTemp(Ity_I32);
17136 loadGuardedLE( tD, ILGop_Ident32, ea, llGetIReg(rD), condT );
17137 putIRegT(rD, mkexpr(tD), IRTemp_INVALID);
sewardjd2664472010-08-22 12:44:20 +000017138 } else {
sewardjcfe046e2013-01-17 14:23:53 +000017139 storeGuardedLE(ea, getIRegT(rD), condT);
sewardjd2664472010-08-22 12:44:20 +000017140 }
17141 put_ITSTATE(new_itstate); // restore
17142
17143 DIP("%s r%u, [sp, #%u]\n", isLD ? "ldr" : "str", rD, imm8 * 4);
17144 goto decode_success;
17145 }
17146
17147 case BITS5(1,1,0,0,1): {
17148 /* ------------- LDMIA Rn!, {reglist} ------------- */
17149 Int i, nRegs = 0;
17150 UInt rN = INSN0(10,8);
17151 UInt list = INSN0(7,0);
17152 /* Empty lists aren't allowed. */
17153 if (list != 0) {
17154 mk_skip_over_T16_if_cond_is_false(condT);
17155 condT = IRTemp_INVALID;
17156 put_ITSTATE(old_itstate);
17157 // now uncond
17158
17159 IRTemp oldRn = newTemp(Ity_I32);
17160 IRTemp base = newTemp(Ity_I32);
17161 assign(oldRn, getIRegT(rN));
sewardjdf86f162010-08-22 18:47:30 +000017162 assign(base, binop(Iop_And32, mkexpr(oldRn), mkU32(~3U)));
sewardjd2664472010-08-22 12:44:20 +000017163 for (i = 0; i < 8; i++) {
17164 if (0 == (list & (1 << i)))
17165 continue;
17166 nRegs++;
17167 putIRegT(
17168 i, loadLE(Ity_I32,
17169 binop(Iop_Add32, mkexpr(base),
17170 mkU32(nRegs * 4 - 4))),
17171 IRTemp_INVALID
17172 );
17173 }
17174 /* Only do the writeback for rN if it isn't in the list of
17175 registers to be transferred. */
17176 if (0 == (list & (1 << rN))) {
17177 putIRegT(rN,
17178 binop(Iop_Add32, mkexpr(oldRn),
17179 mkU32(nRegs * 4)),
17180 IRTemp_INVALID
17181 );
17182 }
17183
17184 /* Reinstate the ITSTATE update. */
17185 put_ITSTATE(new_itstate);
17186
17187 DIP("ldmia r%u!, {0x%04x}\n", rN, list);
17188 goto decode_success;
17189 }
17190 break;
17191 }
17192
17193 case BITS5(1,1,0,0,0): {
17194 /* ------------- STMIA Rn!, {reglist} ------------- */
17195 Int i, nRegs = 0;
17196 UInt rN = INSN0(10,8);
17197 UInt list = INSN0(7,0);
17198 /* Empty lists aren't allowed. Also, if rN is in the list then
17199 it must be the lowest numbered register in the list. */
17200 Bool valid = list != 0;
17201 if (valid && 0 != (list & (1 << rN))) {
17202 for (i = 0; i < rN; i++) {
17203 if (0 != (list & (1 << i)))
17204 valid = False;
17205 }
17206 }
17207 if (valid) {
17208 mk_skip_over_T16_if_cond_is_false(condT);
17209 condT = IRTemp_INVALID;
17210 put_ITSTATE(old_itstate);
17211 // now uncond
17212
17213 IRTemp oldRn = newTemp(Ity_I32);
17214 IRTemp base = newTemp(Ity_I32);
17215 assign(oldRn, getIRegT(rN));
sewardjdf86f162010-08-22 18:47:30 +000017216 assign(base, binop(Iop_And32, mkexpr(oldRn), mkU32(~3U)));
sewardjd2664472010-08-22 12:44:20 +000017217 for (i = 0; i < 8; i++) {
17218 if (0 == (list & (1 << i)))
17219 continue;
17220 nRegs++;
17221 storeLE( binop(Iop_Add32, mkexpr(base), mkU32(nRegs * 4 - 4)),
17222 getIRegT(i) );
17223 }
17224 /* Always do the writeback. */
17225 putIRegT(rN,
17226 binop(Iop_Add32, mkexpr(oldRn),
17227 mkU32(nRegs * 4)),
17228 IRTemp_INVALID);
17229
17230 /* Reinstate the ITSTATE update. */
17231 put_ITSTATE(new_itstate);
17232
17233 DIP("stmia r%u!, {0x%04x}\n", rN, list);
17234 goto decode_success;
17235 }
17236 break;
17237 }
17238
17239 case BITS5(0,0,0,0,0): /* LSLS */
17240 case BITS5(0,0,0,0,1): /* LSRS */
17241 case BITS5(0,0,0,1,0): { /* ASRS */
17242 /* ---------------- LSLS Rd, Rm, #imm5 ---------------- */
17243 /* ---------------- LSRS Rd, Rm, #imm5 ---------------- */
17244 /* ---------------- ASRS Rd, Rm, #imm5 ---------------- */
17245 UInt rD = INSN0(2,0);
17246 UInt rM = INSN0(5,3);
17247 UInt imm5 = INSN0(10,6);
17248 IRTemp res = newTemp(Ity_I32);
17249 IRTemp resC = newTemp(Ity_I32);
17250 IRTemp rMt = newTemp(Ity_I32);
17251 IRTemp oldV = newTemp(Ity_I32);
florian55085f82012-11-21 00:36:55 +000017252 const HChar* wot = "???";
sewardjd2664472010-08-22 12:44:20 +000017253 assign(rMt, getIRegT(rM));
17254 assign(oldV, mk_armg_calculate_flag_v());
17255 /* Looks like INSN0(12,11) are the standard 'how' encoding.
17256 Could compactify if the ROR case later appears. */
17257 switch (INSN0(15,11)) {
17258 case BITS5(0,0,0,0,0):
17259 compute_result_and_C_after_LSL_by_imm5(
17260 dis_buf, &res, &resC, rMt, imm5, rM
17261 );
17262 wot = "lsl";
17263 break;
17264 case BITS5(0,0,0,0,1):
17265 compute_result_and_C_after_LSR_by_imm5(
17266 dis_buf, &res, &resC, rMt, imm5, rM
17267 );
17268 wot = "lsr";
17269 break;
17270 case BITS5(0,0,0,1,0):
17271 compute_result_and_C_after_ASR_by_imm5(
17272 dis_buf, &res, &resC, rMt, imm5, rM
17273 );
17274 wot = "asr";
17275 break;
17276 default:
17277 /*NOTREACHED*/vassert(0);
17278 }
17279 // not safe to read guest state after this point
17280 putIRegT(rD, mkexpr(res), condT);
17281 setFlags_D1_D2_ND( ARMG_CC_OP_LOGIC, res, resC, oldV,
17282 cond_AND_notInIT_T );
17283 /* ignore buf and roll our own output */
17284 DIP("%ss r%u, r%u, #%u\n", wot, rD, rM, imm5);
17285 goto decode_success;
17286 }
17287
17288 case BITS5(1,1,1,0,0): {
17289 /* ---------------- B #simm11 ---------------- */
17290 Int simm11 = INSN0(10,0);
17291 simm11 = (simm11 << 21) >> 20;
17292 UInt dst = simm11 + guest_R15_curr_instr_notENC + 4;
17293 /* Only allowed outside or last-in IT block; SIGILL if not so. */
17294 gen_SIGILL_T_if_in_but_NLI_ITBlock(old_itstate, new_itstate);
17295 // and skip this insn if not selected; being cleverer is too
17296 // difficult
17297 mk_skip_over_T16_if_cond_is_false(condT);
17298 condT = IRTemp_INVALID;
17299 // now uncond
sewardjc6f970f2012-04-02 21:54:49 +000017300 llPutIReg(15, mkU32( dst | 1 /*CPSR.T*/ ));
17301 dres.jk_StopHere = Ijk_Boring;
17302 dres.whatNext = Dis_StopHere;
sewardjd2664472010-08-22 12:44:20 +000017303 DIP("b 0x%x\n", dst);
17304 goto decode_success;
17305 }
17306
17307 default:
17308 break; /* examine the next shortest prefix */
17309
17310 }
17311
17312
17313 /* ================ 16-bit 15:12 cases ================ */
17314
17315 switch (INSN0(15,12)) {
17316
17317 case BITS4(1,1,0,1): {
17318 /* ---------------- Bcond #simm8 ---------------- */
17319 UInt cond = INSN0(11,8);
17320 Int simm8 = INSN0(7,0);
17321 simm8 = (simm8 << 24) >> 23;
17322 UInt dst = simm8 + guest_R15_curr_instr_notENC + 4;
17323 if (cond != ARMCondAL && cond != ARMCondNV) {
17324 /* Not allowed in an IT block; SIGILL if so. */
17325 gen_SIGILL_T_if_in_ITBlock(old_itstate, new_itstate);
17326
17327 IRTemp kondT = newTemp(Ity_I32);
17328 assign( kondT, mk_armg_calculate_condition(cond) );
17329 stmt( IRStmt_Exit( unop(Iop_32to1, mkexpr(kondT)),
17330 Ijk_Boring,
sewardjc6f970f2012-04-02 21:54:49 +000017331 IRConst_U32(dst | 1/*CPSR.T*/),
17332 OFFB_R15T ));
17333 llPutIReg(15, mkU32( (guest_R15_curr_instr_notENC + 2)
17334 | 1 /*CPSR.T*/ ));
17335 dres.jk_StopHere = Ijk_Boring;
17336 dres.whatNext = Dis_StopHere;
sewardjd2664472010-08-22 12:44:20 +000017337 DIP("b%s 0x%x\n", nCC(cond), dst);
17338 goto decode_success;
17339 }
17340 break;
17341 }
17342
17343 default:
17344 break; /* hmm, nothing matched */
17345
17346 }
17347
17348 /* ================ 16-bit misc cases ================ */
17349
sewardj0ef8d9e2013-03-01 21:13:24 +000017350 switch (INSN0(15,0)) {
17351 case 0xBF00:
17352 /* ------ NOP ------ */
17353 DIP("nop\n");
17354 goto decode_success;
17355 case 0xBF20:
17356 /* ------ WFE ------ */
17357 /* WFE gets used as a spin-loop hint. Do the usual thing,
17358 which is to continue after yielding. */
17359 stmt( IRStmt_Exit( unop(Iop_32to1, mkexpr(condT)),
17360 Ijk_Yield,
17361 IRConst_U32((guest_R15_curr_instr_notENC + 2)
17362 | 1 /*CPSR.T*/),
17363 OFFB_R15T ));
17364 DIP("wfe\n");
17365 goto decode_success;
17366 case 0xBF40:
17367 /* ------ SEV ------ */
17368 /* Treat this as a no-op. Any matching WFEs won't really
17369 cause the host CPU to snooze; they just cause V to try to
17370 run some other thread for a while. So there's no point in
17371 really doing anything for SEV. */
17372 DIP("sev\n");
17373 goto decode_success;
17374 default:
17375 break; /* fall through */
sewardjd2664472010-08-22 12:44:20 +000017376 }
17377
17378 /* ----------------------------------------------------------- */
17379 /* -- -- */
17380 /* -- Thumb 32-bit integer instructions -- */
17381 /* -- -- */
17382 /* ----------------------------------------------------------- */
17383
17384# define INSN1(_bMax,_bMin) SLICE_UInt(((UInt)insn1), (_bMax), (_bMin))
17385
17386 /* second 16 bits of the instruction, if any */
sewardj5276ff52012-07-14 14:21:56 +000017387 vassert(insn1 == 0);
17388 insn1 = getUShortLittleEndianly( guest_instr+2 );
sewardjd2664472010-08-22 12:44:20 +000017389
17390 anOp = Iop_INVALID; /* paranoia */
17391 anOpNm = NULL; /* paranoia */
17392
17393 /* Change result defaults to suit 32-bit insns. */
17394 vassert(dres.whatNext == Dis_Continue);
17395 vassert(dres.len == 2);
17396 vassert(dres.continueAt == 0);
17397 dres.len = 4;
17398
17399 /* ---------------- BL/BLX simm26 ---------------- */
17400 if (BITS5(1,1,1,1,0) == INSN0(15,11) && BITS2(1,1) == INSN1(15,14)) {
17401 UInt isBL = INSN1(12,12);
17402 UInt bS = INSN0(10,10);
17403 UInt bJ1 = INSN1(13,13);
17404 UInt bJ2 = INSN1(11,11);
17405 UInt bI1 = 1 ^ (bJ1 ^ bS);
17406 UInt bI2 = 1 ^ (bJ2 ^ bS);
17407 Int simm25
17408 = (bS << (1 + 1 + 10 + 11 + 1))
17409 | (bI1 << (1 + 10 + 11 + 1))
17410 | (bI2 << (10 + 11 + 1))
17411 | (INSN0(9,0) << (11 + 1))
17412 | (INSN1(10,0) << 1);
17413 simm25 = (simm25 << 7) >> 7;
17414
17415 vassert(0 == (guest_R15_curr_instr_notENC & 1));
17416 UInt dst = simm25 + guest_R15_curr_instr_notENC + 4;
17417
17418 /* One further validity case to check: in the case of BLX
17419 (not-BL), that insn1[0] must be zero. */
17420 Bool valid = True;
17421 if (isBL == 0 && INSN1(0,0) == 1) valid = False;
17422 if (valid) {
17423 /* Only allowed outside or last-in IT block; SIGILL if not so. */
17424 gen_SIGILL_T_if_in_but_NLI_ITBlock(old_itstate, new_itstate);
17425 // and skip this insn if not selected; being cleverer is too
17426 // difficult
17427 mk_skip_over_T32_if_cond_is_false(condT);
17428 condT = IRTemp_INVALID;
17429 // now uncond
17430
17431 /* We're returning to Thumb code, hence "| 1" */
17432 putIRegT( 14, mkU32( (guest_R15_curr_instr_notENC + 4) | 1 ),
17433 IRTemp_INVALID);
17434 if (isBL) {
17435 /* BL: unconditional T -> T call */
17436 /* we're calling Thumb code, hence "| 1" */
sewardjc6f970f2012-04-02 21:54:49 +000017437 llPutIReg(15, mkU32( dst | 1 ));
sewardjd2664472010-08-22 12:44:20 +000017438 DIP("bl 0x%x (stay in Thumb mode)\n", dst);
17439 } else {
17440 /* BLX: unconditional T -> A call */
17441 /* we're calling ARM code, hence "& 3" to align to a
17442 valid ARM insn address */
sewardjc6f970f2012-04-02 21:54:49 +000017443 llPutIReg(15, mkU32( dst & ~3 ));
sewardjd2664472010-08-22 12:44:20 +000017444 DIP("blx 0x%x (switch to ARM mode)\n", dst & ~3);
17445 }
sewardjc6f970f2012-04-02 21:54:49 +000017446 dres.whatNext = Dis_StopHere;
17447 dres.jk_StopHere = Ijk_Call;
sewardjd2664472010-08-22 12:44:20 +000017448 goto decode_success;
17449 }
17450 }
17451
17452 /* ---------------- {LD,ST}M{IA,DB} ---------------- */
17453 if (0x3a2 == INSN0(15,6) // {LD,ST}MIA
17454 || 0x3a4 == INSN0(15,6)) { // {LD,ST}MDB
17455 UInt bW = INSN0(5,5); /* writeback Rn ? */
17456 UInt bL = INSN0(4,4);
17457 UInt rN = INSN0(3,0);
17458 UInt bP = INSN1(15,15); /* reglist entry for r15 */
17459 UInt bM = INSN1(14,14); /* reglist entry for r14 */
17460 UInt rLmost = INSN1(12,0); /* reglist entry for r0 .. 12 */
17461 UInt rL13 = INSN1(13,13); /* must be zero */
17462 UInt regList = 0;
17463 Bool valid = True;
17464
17465 UInt bINC = 1;
17466 UInt bBEFORE = 0;
17467 if (INSN0(15,6) == 0x3a4) {
17468 bINC = 0;
17469 bBEFORE = 1;
17470 }
17471
17472 /* detect statically invalid cases, and construct the final
17473 reglist */
17474 if (rL13 == 1)
17475 valid = False;
17476
17477 if (bL == 1) {
17478 regList = (bP << 15) | (bM << 14) | rLmost;
17479 if (rN == 15) valid = False;
17480 if (popcount32(regList) < 2) valid = False;
17481 if (bP == 1 && bM == 1) valid = False;
17482 if (bW == 1 && (regList & (1<<rN))) valid = False;
17483 } else {
17484 regList = (bM << 14) | rLmost;
17485 if (bP == 1) valid = False;
17486 if (rN == 15) valid = False;
17487 if (popcount32(regList) < 2) valid = False;
17488 if (bW == 1 && (regList & (1<<rN))) valid = False;
sewardjd2664472010-08-22 12:44:20 +000017489 }
17490
17491 if (valid) {
17492 if (bL == 1 && bP == 1) {
17493 // We'll be writing the PC. Hence:
17494 /* Only allowed outside or last-in IT block; SIGILL if not so. */
17495 gen_SIGILL_T_if_in_but_NLI_ITBlock(old_itstate, new_itstate);
17496 }
17497
17498 /* Go uncond: */
17499 mk_skip_over_T32_if_cond_is_false(condT);
17500 condT = IRTemp_INVALID;
17501 // now uncond
17502
sewardjc6f970f2012-04-02 21:54:49 +000017503 /* Generate the IR. This might generate a write to R15. */
sewardjd2664472010-08-22 12:44:20 +000017504 mk_ldm_stm(False/*!arm*/, rN, bINC, bBEFORE, bW, bL, regList);
17505
17506 if (bL == 1 && (regList & (1<<15))) {
17507 // If we wrote to R15, we have an interworking return to
17508 // deal with.
sewardjc6f970f2012-04-02 21:54:49 +000017509 llPutIReg(15, llGetIReg(15));
17510 dres.jk_StopHere = Ijk_Ret;
17511 dres.whatNext = Dis_StopHere;
sewardjd2664472010-08-22 12:44:20 +000017512 }
17513
17514 DIP("%sm%c%c r%u%s, {0x%04x}\n",
17515 bL == 1 ? "ld" : "st", bINC ? 'i' : 'd', bBEFORE ? 'b' : 'a',
17516 rN, bW ? "!" : "", regList);
17517
17518 goto decode_success;
17519 }
17520 }
17521
17522 /* -------------- (T3) ADD{S}.W Rd, Rn, #constT -------------- */
17523 if (INSN0(15,11) == BITS5(1,1,1,1,0)
17524 && INSN0(9,5) == BITS5(0,1,0,0,0)
17525 && INSN1(15,15) == 0) {
17526 UInt bS = INSN0(4,4);
17527 UInt rN = INSN0(3,0);
17528 UInt rD = INSN1(11,8);
17529 Bool valid = !isBadRegT(rN) && !isBadRegT(rD);
sewardj51016d12011-10-26 15:06:25 +000017530 /* but allow "add.w reg, sp, #constT" for reg != PC */
17531 if (!valid && rD <= 14 && rN == 13)
sewardjd2664472010-08-22 12:44:20 +000017532 valid = True;
17533 if (valid) {
17534 IRTemp argL = newTemp(Ity_I32);
17535 IRTemp argR = newTemp(Ity_I32);
17536 IRTemp res = newTemp(Ity_I32);
17537 UInt imm32 = thumbExpandImm_from_I0_I1(NULL, insn0, insn1);
17538 assign(argL, getIRegT(rN));
17539 assign(argR, mkU32(imm32));
17540 assign(res, binop(Iop_Add32, mkexpr(argL), mkexpr(argR)));
17541 putIRegT(rD, mkexpr(res), condT);
17542 if (bS == 1)
17543 setFlags_D1_D2( ARMG_CC_OP_ADD, argL, argR, condT );
17544 DIP("add%s.w r%u, r%u, #%u\n",
17545 bS == 1 ? "s" : "", rD, rN, imm32);
17546 goto decode_success;
17547 }
17548 }
17549
sewardjdbf3d592011-07-08 15:36:59 +000017550 /* ---------------- (T4) ADDW Rd, Rn, #uimm12 -------------- */
17551 if (INSN0(15,11) == BITS5(1,1,1,1,0)
17552 && INSN0(9,4) == BITS6(1,0,0,0,0,0)
17553 && INSN1(15,15) == 0) {
17554 UInt rN = INSN0(3,0);
17555 UInt rD = INSN1(11,8);
17556 Bool valid = !isBadRegT(rN) && !isBadRegT(rD);
sewardj51016d12011-10-26 15:06:25 +000017557 /* but allow "addw reg, sp, #uimm12" for reg != PC */
17558 if (!valid && rD <= 14 && rN == 13)
sewardjdbf3d592011-07-08 15:36:59 +000017559 valid = True;
17560 if (valid) {
17561 IRTemp argL = newTemp(Ity_I32);
17562 IRTemp argR = newTemp(Ity_I32);
17563 IRTemp res = newTemp(Ity_I32);
17564 UInt imm12 = (INSN0(10,10) << 11) | (INSN1(14,12) << 8) | INSN1(7,0);
17565 assign(argL, getIRegT(rN));
17566 assign(argR, mkU32(imm12));
17567 assign(res, binop(Iop_Add32, mkexpr(argL), mkexpr(argR)));
17568 putIRegT(rD, mkexpr(res), condT);
17569 DIP("addw r%u, r%u, #%u\n", rD, rN, imm12);
17570 goto decode_success;
17571 }
17572 }
17573
sewardjd2664472010-08-22 12:44:20 +000017574 /* ---------------- (T2) CMP.W Rn, #constT ---------------- */
17575 /* ---------------- (T2) CMN.W Rn, #constT ---------------- */
17576 if (INSN0(15,11) == BITS5(1,1,1,1,0)
17577 && ( INSN0(9,4) == BITS6(0,1,1,0,1,1) // CMP
17578 || INSN0(9,4) == BITS6(0,1,0,0,0,1)) // CMN
17579 && INSN1(15,15) == 0
17580 && INSN1(11,8) == BITS4(1,1,1,1)) {
17581 UInt rN = INSN0(3,0);
17582 if (rN != 15) {
17583 IRTemp argL = newTemp(Ity_I32);
17584 IRTemp argR = newTemp(Ity_I32);
17585 Bool isCMN = INSN0(9,4) == BITS6(0,1,0,0,0,1);
17586 UInt imm32 = thumbExpandImm_from_I0_I1(NULL, insn0, insn1);
17587 assign(argL, getIRegT(rN));
17588 assign(argR, mkU32(imm32));
17589 setFlags_D1_D2( isCMN ? ARMG_CC_OP_ADD : ARMG_CC_OP_SUB,
17590 argL, argR, condT );
17591 DIP("%s.w r%u, #%u\n", isCMN ? "cmn" : "cmp", rN, imm32);
17592 goto decode_success;
17593 }
17594 }
17595
17596 /* -------------- (T1) TST.W Rn, #constT -------------- */
17597 /* -------------- (T1) TEQ.W Rn, #constT -------------- */
17598 if (INSN0(15,11) == BITS5(1,1,1,1,0)
17599 && ( INSN0(9,4) == BITS6(0,0,0,0,0,1) // TST
17600 || INSN0(9,4) == BITS6(0,0,1,0,0,1)) // TEQ
17601 && INSN1(15,15) == 0
17602 && INSN1(11,8) == BITS4(1,1,1,1)) {
17603 UInt rN = INSN0(3,0);
17604 if (!isBadRegT(rN)) { // yes, really, it's inconsistent with CMP.W
17605 Bool isTST = INSN0(9,4) == BITS6(0,0,0,0,0,1);
17606 IRTemp argL = newTemp(Ity_I32);
17607 IRTemp argR = newTemp(Ity_I32);
17608 IRTemp res = newTemp(Ity_I32);
17609 IRTemp oldV = newTemp(Ity_I32);
17610 IRTemp oldC = newTemp(Ity_I32);
17611 Bool updC = False;
17612 UInt imm32 = thumbExpandImm_from_I0_I1(&updC, insn0, insn1);
17613 assign(argL, getIRegT(rN));
17614 assign(argR, mkU32(imm32));
17615 assign(res, binop(isTST ? Iop_And32 : Iop_Xor32,
17616 mkexpr(argL), mkexpr(argR)));
17617 assign( oldV, mk_armg_calculate_flag_v() );
17618 assign( oldC, updC
17619 ? mkU32((imm32 >> 31) & 1)
17620 : mk_armg_calculate_flag_c() );
17621 setFlags_D1_D2_ND( ARMG_CC_OP_LOGIC, res, oldC, oldV, condT );
17622 DIP("%s.w r%u, #%u\n", isTST ? "tst" : "teq", rN, imm32);
17623 goto decode_success;
17624 }
17625 }
17626
17627 /* -------------- (T3) SUB{S}.W Rd, Rn, #constT -------------- */
17628 /* -------------- (T3) RSB{S}.W Rd, Rn, #constT -------------- */
17629 if (INSN0(15,11) == BITS5(1,1,1,1,0)
17630 && (INSN0(9,5) == BITS5(0,1,1,0,1) // SUB
17631 || INSN0(9,5) == BITS5(0,1,1,1,0)) // RSB
17632 && INSN1(15,15) == 0) {
17633 Bool isRSB = INSN0(9,5) == BITS5(0,1,1,1,0);
17634 UInt bS = INSN0(4,4);
17635 UInt rN = INSN0(3,0);
17636 UInt rD = INSN1(11,8);
17637 Bool valid = !isBadRegT(rN) && !isBadRegT(rD);
sewardj15c01042011-03-24 11:14:02 +000017638 /* but allow "sub{s}.w reg, sp, #constT
17639 this is (T2) of "SUB (SP minus immediate)" */
17640 if (!valid && !isRSB && rN == 13 && rD != 15)
sewardjd2664472010-08-22 12:44:20 +000017641 valid = True;
17642 if (valid) {
17643 IRTemp argL = newTemp(Ity_I32);
17644 IRTemp argR = newTemp(Ity_I32);
17645 IRTemp res = newTemp(Ity_I32);
17646 UInt imm32 = thumbExpandImm_from_I0_I1(NULL, insn0, insn1);
17647 assign(argL, getIRegT(rN));
17648 assign(argR, mkU32(imm32));
17649 assign(res, isRSB
17650 ? binop(Iop_Sub32, mkexpr(argR), mkexpr(argL))
17651 : binop(Iop_Sub32, mkexpr(argL), mkexpr(argR)));
17652 putIRegT(rD, mkexpr(res), condT);
17653 if (bS == 1) {
17654 if (isRSB)
17655 setFlags_D1_D2( ARMG_CC_OP_SUB, argR, argL, condT );
17656 else
17657 setFlags_D1_D2( ARMG_CC_OP_SUB, argL, argR, condT );
17658 }
17659 DIP("%s%s.w r%u, r%u, #%u\n",
17660 isRSB ? "rsb" : "sub", bS == 1 ? "s" : "", rD, rN, imm32);
17661 goto decode_success;
17662 }
17663 }
17664
sewardjdbf3d592011-07-08 15:36:59 +000017665 /* -------------- (T4) SUBW Rd, Rn, #uimm12 ------------------- */
17666 if (INSN0(15,11) == BITS5(1,1,1,1,0)
17667 && INSN0(9,4) == BITS6(1,0,1,0,1,0)
17668 && INSN1(15,15) == 0) {
17669 UInt rN = INSN0(3,0);
17670 UInt rD = INSN1(11,8);
17671 Bool valid = !isBadRegT(rN) && !isBadRegT(rD);
17672 /* but allow "subw sp, sp, #uimm12" */
17673 if (!valid && rD == 13 && rN == 13)
17674 valid = True;
17675 if (valid) {
17676 IRTemp argL = newTemp(Ity_I32);
17677 IRTemp argR = newTemp(Ity_I32);
17678 IRTemp res = newTemp(Ity_I32);
17679 UInt imm12 = (INSN0(10,10) << 11) | (INSN1(14,12) << 8) | INSN1(7,0);
17680 assign(argL, getIRegT(rN));
17681 assign(argR, mkU32(imm12));
17682 assign(res, binop(Iop_Sub32, mkexpr(argL), mkexpr(argR)));
17683 putIRegT(rD, mkexpr(res), condT);
17684 DIP("subw r%u, r%u, #%u\n", rD, rN, imm12);
17685 goto decode_success;
17686 }
17687 }
17688
sewardjd2664472010-08-22 12:44:20 +000017689 /* -------------- (T1) ADC{S}.W Rd, Rn, #constT -------------- */
17690 /* -------------- (T1) SBC{S}.W Rd, Rn, #constT -------------- */
17691 if (INSN0(15,11) == BITS5(1,1,1,1,0)
17692 && ( INSN0(9,5) == BITS5(0,1,0,1,0) // ADC
17693 || INSN0(9,5) == BITS5(0,1,0,1,1)) // SBC
17694 && INSN1(15,15) == 0) {
17695 /* ADC: Rd = Rn + constT + oldC */
17696 /* SBC: Rd = Rn - constT - (oldC ^ 1) */
17697 UInt bS = INSN0(4,4);
17698 UInt rN = INSN0(3,0);
17699 UInt rD = INSN1(11,8);
17700 if (!isBadRegT(rN) && !isBadRegT(rD)) {
17701 IRTemp argL = newTemp(Ity_I32);
17702 IRTemp argR = newTemp(Ity_I32);
17703 IRTemp res = newTemp(Ity_I32);
17704 IRTemp oldC = newTemp(Ity_I32);
17705 UInt imm32 = thumbExpandImm_from_I0_I1(NULL, insn0, insn1);
17706 assign(argL, getIRegT(rN));
17707 assign(argR, mkU32(imm32));
17708 assign(oldC, mk_armg_calculate_flag_c() );
florian55085f82012-11-21 00:36:55 +000017709 const HChar* nm = "???";
sewardjd2664472010-08-22 12:44:20 +000017710 switch (INSN0(9,5)) {
17711 case BITS5(0,1,0,1,0): // ADC
17712 nm = "adc";
17713 assign(res,
17714 binop(Iop_Add32,
17715 binop(Iop_Add32, mkexpr(argL), mkexpr(argR)),
17716 mkexpr(oldC) ));
17717 putIRegT(rD, mkexpr(res), condT);
17718 if (bS)
17719 setFlags_D1_D2_ND( ARMG_CC_OP_ADC,
17720 argL, argR, oldC, condT );
17721 break;
17722 case BITS5(0,1,0,1,1): // SBC
17723 nm = "sbc";
17724 assign(res,
17725 binop(Iop_Sub32,
17726 binop(Iop_Sub32, mkexpr(argL), mkexpr(argR)),
17727 binop(Iop_Xor32, mkexpr(oldC), mkU32(1)) ));
17728 putIRegT(rD, mkexpr(res), condT);
17729 if (bS)
17730 setFlags_D1_D2_ND( ARMG_CC_OP_SBB,
17731 argL, argR, oldC, condT );
17732 break;
17733 default:
17734 vassert(0);
17735 }
17736 DIP("%s%s.w r%u, r%u, #%u\n",
17737 nm, bS == 1 ? "s" : "", rD, rN, imm32);
17738 goto decode_success;
17739 }
17740 }
17741
17742 /* -------------- (T1) ORR{S}.W Rd, Rn, #constT -------------- */
17743 /* -------------- (T1) AND{S}.W Rd, Rn, #constT -------------- */
17744 /* -------------- (T1) BIC{S}.W Rd, Rn, #constT -------------- */
17745 /* -------------- (T1) EOR{S}.W Rd, Rn, #constT -------------- */
17746 if (INSN0(15,11) == BITS5(1,1,1,1,0)
17747 && ( INSN0(9,5) == BITS5(0,0,0,1,0) // ORR
17748 || INSN0(9,5) == BITS5(0,0,0,0,0) // AND
17749 || INSN0(9,5) == BITS5(0,0,0,0,1) // BIC
sewardj04d6da32010-09-25 22:06:12 +000017750 || INSN0(9,5) == BITS5(0,0,1,0,0) // EOR
17751 || INSN0(9,5) == BITS5(0,0,0,1,1)) // ORN
sewardjd2664472010-08-22 12:44:20 +000017752 && INSN1(15,15) == 0) {
17753 UInt bS = INSN0(4,4);
17754 UInt rN = INSN0(3,0);
17755 UInt rD = INSN1(11,8);
17756 if (!isBadRegT(rN) && !isBadRegT(rD)) {
sewardj04d6da32010-09-25 22:06:12 +000017757 Bool notArgR = False;
17758 IROp op = Iop_INVALID;
florian55085f82012-11-21 00:36:55 +000017759 const HChar* nm = "???";
sewardjd2664472010-08-22 12:44:20 +000017760 switch (INSN0(9,5)) {
17761 case BITS5(0,0,0,1,0): op = Iop_Or32; nm = "orr"; break;
17762 case BITS5(0,0,0,0,0): op = Iop_And32; nm = "and"; break;
17763 case BITS5(0,0,0,0,1): op = Iop_And32; nm = "bic";
sewardj04d6da32010-09-25 22:06:12 +000017764 notArgR = True; break;
17765 case BITS5(0,0,1,0,0): op = Iop_Xor32; nm = "eor"; break;
17766 case BITS5(0,0,0,1,1): op = Iop_Or32; nm = "orn";
17767 notArgR = True; break;
sewardjd2664472010-08-22 12:44:20 +000017768 default: vassert(0);
17769 }
17770 IRTemp argL = newTemp(Ity_I32);
17771 IRTemp argR = newTemp(Ity_I32);
17772 IRTemp res = newTemp(Ity_I32);
17773 Bool updC = False;
17774 UInt imm32 = thumbExpandImm_from_I0_I1(&updC, insn0, insn1);
17775 assign(argL, getIRegT(rN));
sewardj04d6da32010-09-25 22:06:12 +000017776 assign(argR, mkU32(notArgR ? ~imm32 : imm32));
sewardjd2664472010-08-22 12:44:20 +000017777 assign(res, binop(op, mkexpr(argL), mkexpr(argR)));
17778 putIRegT(rD, mkexpr(res), condT);
17779 if (bS) {
17780 IRTemp oldV = newTemp(Ity_I32);
17781 IRTemp oldC = newTemp(Ity_I32);
17782 assign( oldV, mk_armg_calculate_flag_v() );
17783 assign( oldC, updC
17784 ? mkU32((imm32 >> 31) & 1)
17785 : mk_armg_calculate_flag_c() );
17786 setFlags_D1_D2_ND( ARMG_CC_OP_LOGIC, res, oldC, oldV,
17787 condT );
17788 }
17789 DIP("%s%s.w r%u, r%u, #%u\n",
17790 nm, bS == 1 ? "s" : "", rD, rN, imm32);
17791 goto decode_success;
17792 }
17793 }
17794
17795 /* ---------- (T3) ADD{S}.W Rd, Rn, Rm, {shift} ---------- */
17796 /* ---------- (T3) SUB{S}.W Rd, Rn, Rm, {shift} ---------- */
17797 /* ---------- (T3) RSB{S}.W Rd, Rn, Rm, {shift} ---------- */
17798 if (INSN0(15,9) == BITS7(1,1,1,0,1,0,1)
17799 && ( INSN0(8,5) == BITS4(1,0,0,0) // add subopc
17800 || INSN0(8,5) == BITS4(1,1,0,1) // sub subopc
17801 || INSN0(8,5) == BITS4(1,1,1,0)) // rsb subopc
17802 && INSN1(15,15) == 0) {
17803 UInt rN = INSN0(3,0);
17804 UInt rD = INSN1(11,8);
17805 UInt rM = INSN1(3,0);
17806 UInt bS = INSN0(4,4);
17807 UInt imm5 = (INSN1(14,12) << 2) | INSN1(7,6);
17808 UInt how = INSN1(5,4);
17809
17810 Bool valid = !isBadRegT(rD) && !isBadRegT(rN) && !isBadRegT(rM);
sewardjfd5f4a42012-03-21 19:36:37 +000017811 /* but allow "add.w reg, sp, reg, lsl #N for N=0,1,2 or 3
sewardj15c01042011-03-24 11:14:02 +000017812 (T3) "ADD (SP plus register) */
sewardjd2664472010-08-22 12:44:20 +000017813 if (!valid && INSN0(8,5) == BITS4(1,0,0,0) // add
sewardjfd5f4a42012-03-21 19:36:37 +000017814 && rD != 15 && rN == 13 && imm5 <= 3 && how == 0) {
sewardjd2664472010-08-22 12:44:20 +000017815 valid = True;
17816 }
sewardj15c01042011-03-24 11:14:02 +000017817 /* also allow "sub.w reg, sp, reg w/ no shift
17818 (T1) "SUB (SP minus register) */
17819 if (!valid && INSN0(8,5) == BITS4(1,1,0,1) // sub
17820 && rD != 15 && rN == 13 && imm5 == 0 && how == 0) {
sewardjd2664472010-08-22 12:44:20 +000017821 valid = True;
17822 }
17823 if (valid) {
17824 Bool swap = False;
17825 IROp op = Iop_INVALID;
florian55085f82012-11-21 00:36:55 +000017826 const HChar* nm = "???";
sewardjd2664472010-08-22 12:44:20 +000017827 switch (INSN0(8,5)) {
17828 case BITS4(1,0,0,0): op = Iop_Add32; nm = "add"; break;
17829 case BITS4(1,1,0,1): op = Iop_Sub32; nm = "sub"; break;
17830 case BITS4(1,1,1,0): op = Iop_Sub32; nm = "rsb";
17831 swap = True; break;
17832 default: vassert(0);
17833 }
17834
17835 IRTemp argL = newTemp(Ity_I32);
17836 assign(argL, getIRegT(rN));
17837
17838 IRTemp rMt = newTemp(Ity_I32);
17839 assign(rMt, getIRegT(rM));
17840
17841 IRTemp argR = newTemp(Ity_I32);
17842 compute_result_and_C_after_shift_by_imm5(
17843 dis_buf, &argR, NULL, rMt, how, imm5, rM
17844 );
17845
17846 IRTemp res = newTemp(Ity_I32);
17847 assign(res, swap
17848 ? binop(op, mkexpr(argR), mkexpr(argL))
17849 : binop(op, mkexpr(argL), mkexpr(argR)));
17850
17851 putIRegT(rD, mkexpr(res), condT);
17852 if (bS) {
17853 switch (op) {
17854 case Iop_Add32:
17855 setFlags_D1_D2( ARMG_CC_OP_ADD, argL, argR, condT );
17856 break;
17857 case Iop_Sub32:
17858 if (swap)
17859 setFlags_D1_D2( ARMG_CC_OP_SUB, argR, argL, condT );
17860 else
17861 setFlags_D1_D2( ARMG_CC_OP_SUB, argL, argR, condT );
17862 break;
17863 default:
17864 vassert(0);
17865 }
17866 }
17867
17868 DIP("%s%s.w r%u, r%u, %s\n",
17869 nm, bS ? "s" : "", rD, rN, dis_buf);
17870 goto decode_success;
17871 }
17872 }
17873
17874 /* ---------- (T3) ADC{S}.W Rd, Rn, Rm, {shift} ---------- */
17875 /* ---------- (T2) SBC{S}.W Rd, Rn, Rm, {shift} ---------- */
17876 if (INSN0(15,9) == BITS7(1,1,1,0,1,0,1)
17877 && ( INSN0(8,5) == BITS4(1,0,1,0) // adc subopc
17878 || INSN0(8,5) == BITS4(1,0,1,1)) // sbc subopc
17879 && INSN1(15,15) == 0) {
17880 /* ADC: Rd = Rn + shifter_operand + oldC */
17881 /* SBC: Rd = Rn - shifter_operand - (oldC ^ 1) */
17882 UInt rN = INSN0(3,0);
17883 UInt rD = INSN1(11,8);
17884 UInt rM = INSN1(3,0);
17885 if (!isBadRegT(rD) && !isBadRegT(rN) && !isBadRegT(rM)) {
17886 UInt bS = INSN0(4,4);
17887 UInt imm5 = (INSN1(14,12) << 2) | INSN1(7,6);
17888 UInt how = INSN1(5,4);
17889
17890 IRTemp argL = newTemp(Ity_I32);
17891 assign(argL, getIRegT(rN));
17892
17893 IRTemp rMt = newTemp(Ity_I32);
17894 assign(rMt, getIRegT(rM));
17895
17896 IRTemp oldC = newTemp(Ity_I32);
17897 assign(oldC, mk_armg_calculate_flag_c());
17898
17899 IRTemp argR = newTemp(Ity_I32);
17900 compute_result_and_C_after_shift_by_imm5(
17901 dis_buf, &argR, NULL, rMt, how, imm5, rM
17902 );
17903
florian55085f82012-11-21 00:36:55 +000017904 const HChar* nm = "???";
sewardjd2664472010-08-22 12:44:20 +000017905 IRTemp res = newTemp(Ity_I32);
17906 switch (INSN0(8,5)) {
17907 case BITS4(1,0,1,0): // ADC
17908 nm = "adc";
17909 assign(res,
17910 binop(Iop_Add32,
17911 binop(Iop_Add32, mkexpr(argL), mkexpr(argR)),
17912 mkexpr(oldC) ));
17913 putIRegT(rD, mkexpr(res), condT);
17914 if (bS)
17915 setFlags_D1_D2_ND( ARMG_CC_OP_ADC,
17916 argL, argR, oldC, condT );
17917 break;
17918 case BITS4(1,0,1,1): // SBC
17919 nm = "sbc";
17920 assign(res,
17921 binop(Iop_Sub32,
17922 binop(Iop_Sub32, mkexpr(argL), mkexpr(argR)),
17923 binop(Iop_Xor32, mkexpr(oldC), mkU32(1)) ));
17924 putIRegT(rD, mkexpr(res), condT);
17925 if (bS)
17926 setFlags_D1_D2_ND( ARMG_CC_OP_SBB,
17927 argL, argR, oldC, condT );
17928 break;
17929 default:
17930 vassert(0);
17931 }
17932
17933 DIP("%s%s.w r%u, r%u, %s\n",
17934 nm, bS ? "s" : "", rD, rN, dis_buf);
17935 goto decode_success;
17936 }
17937 }
17938
17939 /* ---------- (T3) AND{S}.W Rd, Rn, Rm, {shift} ---------- */
17940 /* ---------- (T3) ORR{S}.W Rd, Rn, Rm, {shift} ---------- */
17941 /* ---------- (T3) EOR{S}.W Rd, Rn, Rm, {shift} ---------- */
17942 /* ---------- (T3) BIC{S}.W Rd, Rn, Rm, {shift} ---------- */
sewardj04d6da32010-09-25 22:06:12 +000017943 /* ---------- (T1) ORN{S}.W Rd, Rn, Rm, {shift} ---------- */
sewardjd2664472010-08-22 12:44:20 +000017944 if (INSN0(15,9) == BITS7(1,1,1,0,1,0,1)
17945 && ( INSN0(8,5) == BITS4(0,0,0,0) // and subopc
17946 || INSN0(8,5) == BITS4(0,0,1,0) // orr subopc
17947 || INSN0(8,5) == BITS4(0,1,0,0) // eor subopc
sewardj04d6da32010-09-25 22:06:12 +000017948 || INSN0(8,5) == BITS4(0,0,0,1) // bic subopc
17949 || INSN0(8,5) == BITS4(0,0,1,1)) // orn subopc
sewardjd2664472010-08-22 12:44:20 +000017950 && INSN1(15,15) == 0) {
17951 UInt rN = INSN0(3,0);
17952 UInt rD = INSN1(11,8);
17953 UInt rM = INSN1(3,0);
17954 if (!isBadRegT(rD) && !isBadRegT(rN) && !isBadRegT(rM)) {
sewardj04d6da32010-09-25 22:06:12 +000017955 Bool notArgR = False;
17956 IROp op = Iop_INVALID;
florian55085f82012-11-21 00:36:55 +000017957 const HChar* nm = "???";
sewardjd2664472010-08-22 12:44:20 +000017958 switch (INSN0(8,5)) {
17959 case BITS4(0,0,0,0): op = Iop_And32; nm = "and"; break;
17960 case BITS4(0,0,1,0): op = Iop_Or32; nm = "orr"; break;
17961 case BITS4(0,1,0,0): op = Iop_Xor32; nm = "eor"; break;
17962 case BITS4(0,0,0,1): op = Iop_And32; nm = "bic";
sewardj04d6da32010-09-25 22:06:12 +000017963 notArgR = True; break;
17964 case BITS4(0,0,1,1): op = Iop_Or32; nm = "orn";
17965 notArgR = True; break;
sewardjd2664472010-08-22 12:44:20 +000017966 default: vassert(0);
17967 }
17968 UInt bS = INSN0(4,4);
17969 UInt imm5 = (INSN1(14,12) << 2) | INSN1(7,6);
17970 UInt how = INSN1(5,4);
17971
17972 IRTemp rNt = newTemp(Ity_I32);
17973 assign(rNt, getIRegT(rN));
17974
17975 IRTemp rMt = newTemp(Ity_I32);
17976 assign(rMt, getIRegT(rM));
17977
17978 IRTemp argR = newTemp(Ity_I32);
17979 IRTemp oldC = bS ? newTemp(Ity_I32) : IRTemp_INVALID;
17980
17981 compute_result_and_C_after_shift_by_imm5(
17982 dis_buf, &argR, bS ? &oldC : NULL, rMt, how, imm5, rM
17983 );
17984
17985 IRTemp res = newTemp(Ity_I32);
sewardj04d6da32010-09-25 22:06:12 +000017986 if (notArgR) {
17987 vassert(op == Iop_And32 || op == Iop_Or32);
sewardjd2664472010-08-22 12:44:20 +000017988 assign(res, binop(op, mkexpr(rNt),
17989 unop(Iop_Not32, mkexpr(argR))));
17990 } else {
17991 assign(res, binop(op, mkexpr(rNt), mkexpr(argR)));
17992 }
17993
17994 putIRegT(rD, mkexpr(res), condT);
17995 if (bS) {
17996 IRTemp oldV = newTemp(Ity_I32);
17997 assign( oldV, mk_armg_calculate_flag_v() );
17998 setFlags_D1_D2_ND( ARMG_CC_OP_LOGIC, res, oldC, oldV,
17999 condT );
18000 }
18001
18002 DIP("%s%s.w r%u, r%u, %s\n",
18003 nm, bS ? "s" : "", rD, rN, dis_buf);
18004 goto decode_success;
18005 }
18006 }
18007
18008 /* -------------- (T?) LSL{S}.W Rd, Rn, Rm -------------- */
18009 /* -------------- (T?) LSR{S}.W Rd, Rn, Rm -------------- */
18010 /* -------------- (T?) ASR{S}.W Rd, Rn, Rm -------------- */
18011 /* -------------- (T?) ROR{S}.W Rd, Rn, Rm -------------- */
18012 if (INSN0(15,7) == BITS9(1,1,1,1,1,0,1,0,0)
18013 && INSN1(15,12) == BITS4(1,1,1,1)
18014 && INSN1(7,4) == BITS4(0,0,0,0)) {
18015 UInt how = INSN0(6,5); // standard encoding
18016 UInt rN = INSN0(3,0);
18017 UInt rD = INSN1(11,8);
18018 UInt rM = INSN1(3,0);
18019 UInt bS = INSN0(4,4);
18020 Bool valid = !isBadRegT(rN) && !isBadRegT(rM) && !isBadRegT(rD);
sewardjd2664472010-08-22 12:44:20 +000018021 if (valid) {
18022 IRTemp rNt = newTemp(Ity_I32);
18023 IRTemp rMt = newTemp(Ity_I32);
18024 IRTemp res = newTemp(Ity_I32);
18025 IRTemp oldC = bS ? newTemp(Ity_I32) : IRTemp_INVALID;
18026 IRTemp oldV = bS ? newTemp(Ity_I32) : IRTemp_INVALID;
florian55085f82012-11-21 00:36:55 +000018027 const HChar* nms[4] = { "lsl", "lsr", "asr", "ror" };
18028 const HChar* nm = nms[how];
sewardjd2664472010-08-22 12:44:20 +000018029 assign(rNt, getIRegT(rN));
18030 assign(rMt, getIRegT(rM));
18031 compute_result_and_C_after_shift_by_reg(
18032 dis_buf, &res, bS ? &oldC : NULL,
18033 rNt, how, rMt, rN, rM
18034 );
18035 if (bS)
18036 assign(oldV, mk_armg_calculate_flag_v());
18037 putIRegT(rD, mkexpr(res), condT);
18038 if (bS) {
18039 setFlags_D1_D2_ND( ARMG_CC_OP_LOGIC, res, oldC, oldV,
18040 condT );
18041 }
18042 DIP("%s%s.w r%u, r%u, r%u\n",
18043 nm, bS ? "s" : "", rD, rN, rM);
18044 goto decode_success;
18045 }
18046 }
18047
18048 /* ------------ (T?) MOV{S}.W Rd, Rn, {shift} ------------ */
18049 /* ------------ (T?) MVN{S}.W Rd, Rn, {shift} ------------ */
18050 if ((INSN0(15,0) & 0xFFCF) == 0xEA4F
18051 && INSN1(15,15) == 0) {
18052 UInt rD = INSN1(11,8);
18053 UInt rN = INSN1(3,0);
18054 if (!isBadRegT(rD) && !isBadRegT(rN)) {
18055 UInt bS = INSN0(4,4);
18056 UInt isMVN = INSN0(5,5);
18057 UInt imm5 = (INSN1(14,12) << 2) | INSN1(7,6);
18058 UInt how = INSN1(5,4);
18059
18060 IRTemp rNt = newTemp(Ity_I32);
18061 assign(rNt, getIRegT(rN));
18062
18063 IRTemp oldRn = newTemp(Ity_I32);
18064 IRTemp oldC = bS ? newTemp(Ity_I32) : IRTemp_INVALID;
18065 compute_result_and_C_after_shift_by_imm5(
18066 dis_buf, &oldRn, bS ? &oldC : NULL, rNt, how, imm5, rN
18067 );
18068
18069 IRTemp res = newTemp(Ity_I32);
18070 assign(res, isMVN ? unop(Iop_Not32, mkexpr(oldRn))
18071 : mkexpr(oldRn));
18072
18073 putIRegT(rD, mkexpr(res), condT);
18074 if (bS) {
18075 IRTemp oldV = newTemp(Ity_I32);
18076 assign( oldV, mk_armg_calculate_flag_v() );
18077 setFlags_D1_D2_ND( ARMG_CC_OP_LOGIC, res, oldC, oldV, condT);
18078 }
18079 DIP("%s%s.w r%u, %s\n",
18080 isMVN ? "mvn" : "mov", bS ? "s" : "", rD, dis_buf);
18081 goto decode_success;
18082 }
18083 }
18084
18085 /* -------------- (T?) TST.W Rn, Rm, {shift} -------------- */
18086 /* -------------- (T?) TEQ.W Rn, Rm, {shift} -------------- */
18087 if (INSN0(15,9) == BITS7(1,1,1,0,1,0,1)
18088 && ( INSN0(8,4) == BITS5(0,0,0,0,1) // TST
18089 || INSN0(8,4) == BITS5(0,1,0,0,1)) // TEQ
18090 && INSN1(15,15) == 0
18091 && INSN1(11,8) == BITS4(1,1,1,1)) {
18092 UInt rN = INSN0(3,0);
18093 UInt rM = INSN1(3,0);
18094 if (!isBadRegT(rN) && !isBadRegT(rM)) {
18095 Bool isTST = INSN0(8,4) == BITS5(0,0,0,0,1);
18096
18097 UInt how = INSN1(5,4);
18098 UInt imm5 = (INSN1(14,12) << 2) | INSN1(7,6);
18099
18100 IRTemp argL = newTemp(Ity_I32);
18101 assign(argL, getIRegT(rN));
18102
18103 IRTemp rMt = newTemp(Ity_I32);
18104 assign(rMt, getIRegT(rM));
18105
18106 IRTemp argR = newTemp(Ity_I32);
18107 IRTemp oldC = newTemp(Ity_I32);
18108 compute_result_and_C_after_shift_by_imm5(
18109 dis_buf, &argR, &oldC, rMt, how, imm5, rM
18110 );
18111
18112 IRTemp oldV = newTemp(Ity_I32);
18113 assign( oldV, mk_armg_calculate_flag_v() );
18114
18115 IRTemp res = newTemp(Ity_I32);
18116 assign(res, binop(isTST ? Iop_And32 : Iop_Xor32,
18117 mkexpr(argL), mkexpr(argR)));
18118
18119 setFlags_D1_D2_ND( ARMG_CC_OP_LOGIC, res, oldC, oldV,
18120 condT );
18121 DIP("%s.w r%u, %s\n", isTST ? "tst" : "teq", rN, dis_buf);
18122 goto decode_success;
18123 }
18124 }
18125
18126 /* -------------- (T3) CMP.W Rn, Rm, {shift} -------------- */
18127 /* -------------- (T2) CMN.W Rn, Rm, {shift} -------------- */
18128 if (INSN0(15,9) == BITS7(1,1,1,0,1,0,1)
18129 && ( INSN0(8,4) == BITS5(1,1,0,1,1) // CMP
18130 || INSN0(8,4) == BITS5(1,0,0,0,1)) // CMN
18131 && INSN1(15,15) == 0
18132 && INSN1(11,8) == BITS4(1,1,1,1)) {
18133 UInt rN = INSN0(3,0);
18134 UInt rM = INSN1(3,0);
18135 if (!isBadRegT(rN) && !isBadRegT(rM)) {
18136 Bool isCMN = INSN0(8,4) == BITS5(1,0,0,0,1);
18137 UInt how = INSN1(5,4);
18138 UInt imm5 = (INSN1(14,12) << 2) | INSN1(7,6);
18139
18140 IRTemp argL = newTemp(Ity_I32);
18141 assign(argL, getIRegT(rN));
18142
18143 IRTemp rMt = newTemp(Ity_I32);
18144 assign(rMt, getIRegT(rM));
18145
18146 IRTemp argR = newTemp(Ity_I32);
18147 compute_result_and_C_after_shift_by_imm5(
18148 dis_buf, &argR, NULL, rMt, how, imm5, rM
18149 );
18150
18151 setFlags_D1_D2( isCMN ? ARMG_CC_OP_ADD : ARMG_CC_OP_SUB,
18152 argL, argR, condT );
18153
18154 DIP("%s.w r%u, %s\n", isCMN ? "cmn" : "cmp", rN, dis_buf);
18155 goto decode_success;
18156 }
18157 }
18158
18159 /* -------------- (T2) MOV{S}.W Rd, #constT -------------- */
18160 /* -------------- (T2) MVN{S}.W Rd, #constT -------------- */
18161 if (INSN0(15,11) == BITS5(1,1,1,1,0)
18162 && ( INSN0(9,5) == BITS5(0,0,0,1,0) // MOV
18163 || INSN0(9,5) == BITS5(0,0,0,1,1)) // MVN
18164 && INSN0(3,0) == BITS4(1,1,1,1)
18165 && INSN1(15,15) == 0) {
18166 UInt rD = INSN1(11,8);
18167 if (!isBadRegT(rD)) {
18168 Bool updC = False;
18169 UInt bS = INSN0(4,4);
18170 Bool isMVN = INSN0(5,5) == 1;
18171 UInt imm32 = thumbExpandImm_from_I0_I1(&updC, insn0, insn1);
18172 IRTemp res = newTemp(Ity_I32);
18173 assign(res, mkU32(isMVN ? ~imm32 : imm32));
18174 putIRegT(rD, mkexpr(res), condT);
18175 if (bS) {
18176 IRTemp oldV = newTemp(Ity_I32);
18177 IRTemp oldC = newTemp(Ity_I32);
18178 assign( oldV, mk_armg_calculate_flag_v() );
18179 assign( oldC, updC
18180 ? mkU32((imm32 >> 31) & 1)
18181 : mk_armg_calculate_flag_c() );
18182 setFlags_D1_D2_ND( ARMG_CC_OP_LOGIC, res, oldC, oldV,
18183 condT );
18184 }
18185 DIP("%s%s.w r%u, #%u\n",
18186 isMVN ? "mvn" : "mov", bS ? "s" : "", rD, imm32);
18187 goto decode_success;
18188 }
18189 }
18190
18191 /* -------------- (T3) MOVW Rd, #imm16 -------------- */
18192 if (INSN0(15,11) == BITS5(1,1,1,1,0)
18193 && INSN0(9,4) == BITS6(1,0,0,1,0,0)
18194 && INSN1(15,15) == 0) {
18195 UInt rD = INSN1(11,8);
18196 if (!isBadRegT(rD)) {
18197 UInt imm16 = (INSN0(3,0) << 12) | (INSN0(10,10) << 11)
18198 | (INSN1(14,12) << 8) | INSN1(7,0);
18199 putIRegT(rD, mkU32(imm16), condT);
18200 DIP("movw r%u, #%u\n", rD, imm16);
18201 goto decode_success;
18202 }
18203 }
18204
18205 /* ---------------- MOVT Rd, #imm16 ---------------- */
18206 if (INSN0(15,11) == BITS5(1,1,1,1,0)
18207 && INSN0(9,4) == BITS6(1,0,1,1,0,0)
18208 && INSN1(15,15) == 0) {
18209 UInt rD = INSN1(11,8);
18210 if (!isBadRegT(rD)) {
18211 UInt imm16 = (INSN0(3,0) << 12) | (INSN0(10,10) << 11)
18212 | (INSN1(14,12) << 8) | INSN1(7,0);
18213 IRTemp res = newTemp(Ity_I32);
18214 assign(res,
18215 binop(Iop_Or32,
18216 binop(Iop_And32, getIRegT(rD), mkU32(0xFFFF)),
18217 mkU32(imm16 << 16)));
18218 putIRegT(rD, mkexpr(res), condT);
18219 DIP("movt r%u, #%u\n", rD, imm16);
18220 goto decode_success;
18221 }
18222 }
18223
18224 /* ---------------- LD/ST reg+/-#imm8 ---------------- */
18225 /* Loads and stores of the form:
18226 op Rt, [Rn, #-imm8] or
18227 op Rt, [Rn], #+/-imm8 or
18228 op Rt, [Rn, #+/-imm8]!
18229 where op is one of
18230 ldrb ldrh ldr ldrsb ldrsh
18231 strb strh str
18232 */
18233 if (INSN0(15,9) == BITS7(1,1,1,1,1,0,0) && INSN1(11,11) == 1) {
18234 Bool valid = True;
18235 Bool syned = False;
18236 Bool isST = False;
18237 IRType ty = Ity_I8;
florian55085f82012-11-21 00:36:55 +000018238 const HChar* nm = "???";
sewardjd2664472010-08-22 12:44:20 +000018239
18240 switch (INSN0(8,4)) {
18241 case BITS5(0,0,0,0,0): // strb
18242 nm = "strb"; isST = True; break;
18243 case BITS5(0,0,0,0,1): // ldrb
18244 nm = "ldrb"; break;
18245 case BITS5(1,0,0,0,1): // ldrsb
18246 nm = "ldrsb"; syned = True; break;
18247 case BITS5(0,0,0,1,0): // strh
18248 nm = "strh"; ty = Ity_I16; isST = True; break;
18249 case BITS5(0,0,0,1,1): // ldrh
18250 nm = "ldrh"; ty = Ity_I16; break;
18251 case BITS5(1,0,0,1,1): // ldrsh
18252 nm = "ldrsh"; ty = Ity_I16; syned = True; break;
18253 case BITS5(0,0,1,0,0): // str
18254 nm = "str"; ty = Ity_I32; isST = True; break;
18255 case BITS5(0,0,1,0,1):
18256 nm = "ldr"; ty = Ity_I32; break; // ldr
18257 default:
18258 valid = False; break;
18259 }
18260
18261 UInt rN = INSN0(3,0);
18262 UInt rT = INSN1(15,12);
18263 UInt bP = INSN1(10,10);
18264 UInt bU = INSN1(9,9);
18265 UInt bW = INSN1(8,8);
18266 UInt imm8 = INSN1(7,0);
18267 Bool loadsPC = False;
18268
18269 if (valid) {
18270 if (bP == 1 && bU == 1 && bW == 0)
18271 valid = False;
18272 if (bP == 0 && bW == 0)
18273 valid = False;
18274 if (rN == 15)
18275 valid = False;
18276 if (bW == 1 && rN == rT)
18277 valid = False;
18278 if (ty == Ity_I8 || ty == Ity_I16) {
18279 if (isBadRegT(rT))
18280 valid = False;
18281 } else {
18282 /* ty == Ity_I32 */
18283 if (isST && rT == 15)
18284 valid = False;
18285 if (!isST && rT == 15)
18286 loadsPC = True;
18287 }
18288 }
18289
18290 if (valid) {
18291 // if it's a branch, it can't happen in the middle of an IT block
sewardjcfe046e2013-01-17 14:23:53 +000018292 // Also, if it is a branch, make it unconditional at this point.
18293 // Doing conditional branches in-line is too complex (for now)
18294 if (loadsPC) {
sewardjd2664472010-08-22 12:44:20 +000018295 gen_SIGILL_T_if_in_but_NLI_ITBlock(old_itstate, new_itstate);
sewardjcfe046e2013-01-17 14:23:53 +000018296 // go uncond
18297 mk_skip_over_T32_if_cond_is_false(condT);
18298 condT = IRTemp_INVALID;
18299 // now uncond
18300 }
sewardjd2664472010-08-22 12:44:20 +000018301
18302 IRTemp preAddr = newTemp(Ity_I32);
18303 assign(preAddr, getIRegT(rN));
18304
18305 IRTemp postAddr = newTemp(Ity_I32);
18306 assign(postAddr, binop(bU == 1 ? Iop_Add32 : Iop_Sub32,
18307 mkexpr(preAddr), mkU32(imm8)));
18308
18309 IRTemp transAddr = bP == 1 ? postAddr : preAddr;
18310
18311 if (isST) {
18312
sewardjcfe046e2013-01-17 14:23:53 +000018313 /* Store. If necessary, update the base register before
18314 the store itself, so that the common idiom of "str rX,
18315 [sp, #-4]!" (store rX at sp-4, then do new sp = sp-4,
18316 a.k.a "push rX") doesn't cause Memcheck to complain
18317 that the access is below the stack pointer. Also, not
18318 updating sp before the store confuses Valgrind's
18319 dynamic stack-extending logic. So do it before the
18320 store. Hence we need to snarf the store data before
18321 doing the basereg update. */
sewardjd2664472010-08-22 12:44:20 +000018322
18323 /* get hold of the data to be stored */
18324 IRTemp oldRt = newTemp(Ity_I32);
18325 assign(oldRt, getIRegT(rT));
18326
18327 /* Update Rn if necessary. */
18328 if (bW == 1) {
18329 vassert(rN != rT); // assured by validity check above
sewardjcfe046e2013-01-17 14:23:53 +000018330 putIRegT(rN, mkexpr(postAddr), condT);
sewardjd2664472010-08-22 12:44:20 +000018331 }
18332
18333 /* generate the transfer */
sewardjcfe046e2013-01-17 14:23:53 +000018334 IRExpr* data = NULL;
sewardjd2664472010-08-22 12:44:20 +000018335 switch (ty) {
18336 case Ity_I8:
sewardjcfe046e2013-01-17 14:23:53 +000018337 data = unop(Iop_32to8, mkexpr(oldRt));
sewardjd2664472010-08-22 12:44:20 +000018338 break;
18339 case Ity_I16:
sewardjcfe046e2013-01-17 14:23:53 +000018340 data = unop(Iop_32to16, mkexpr(oldRt));
sewardjd2664472010-08-22 12:44:20 +000018341 break;
sewardjd2664472010-08-22 12:44:20 +000018342 case Ity_I32:
sewardjcfe046e2013-01-17 14:23:53 +000018343 data = mkexpr(oldRt);
sewardjd2664472010-08-22 12:44:20 +000018344 break;
18345 default:
18346 vassert(0);
18347 }
sewardjcfe046e2013-01-17 14:23:53 +000018348 storeGuardedLE(mkexpr(transAddr), data, condT);
18349
18350 } else {
18351
18352 /* Load. */
18353 IRTemp llOldRt = newTemp(Ity_I32);
18354 assign(llOldRt, llGetIReg(rT));
18355
18356 /* generate the transfer */
18357 IRTemp newRt = newTemp(Ity_I32);
18358 IRLoadGOp widen = ILGop_INVALID;
18359 switch (ty) {
18360 case Ity_I8:
18361 widen = syned ? ILGop_8Sto32 : ILGop_8Uto32; break;
18362 case Ity_I16:
18363 widen = syned ? ILGop_16Sto32 : ILGop_16Uto32; break;
18364 case Ity_I32:
18365 widen = ILGop_Ident32; break;
18366 default:
18367 vassert(0);
sewardjd2664472010-08-22 12:44:20 +000018368 }
sewardjcfe046e2013-01-17 14:23:53 +000018369 loadGuardedLE(newRt, widen,
18370 mkexpr(transAddr), mkexpr(llOldRt), condT);
18371 if (rT == 15) {
18372 vassert(loadsPC);
18373 /* We'll do the write to the PC just below */
sewardjd2664472010-08-22 12:44:20 +000018374 } else {
sewardjcfe046e2013-01-17 14:23:53 +000018375 vassert(!loadsPC);
18376 /* IRTemp_INVALID is OK here because in the case where
18377 condT is false at run time, we're just putting the
18378 old rT value back. */
sewardjd2664472010-08-22 12:44:20 +000018379 putIRegT(rT, mkexpr(newRt), IRTemp_INVALID);
18380 }
18381
sewardjd2664472010-08-22 12:44:20 +000018382 /* Update Rn if necessary. */
18383 if (bW == 1) {
18384 vassert(rN != rT); // assured by validity check above
sewardjcfe046e2013-01-17 14:23:53 +000018385 putIRegT(rN, mkexpr(postAddr), condT);
sewardjd2664472010-08-22 12:44:20 +000018386 }
sewardjc6f970f2012-04-02 21:54:49 +000018387
18388 if (loadsPC) {
18389 /* Presumably this is an interworking branch. */
18390 vassert(rN != 15); // assured by validity check above
sewardjcfe046e2013-01-17 14:23:53 +000018391 vassert(rT == 15);
18392 vassert(condT == IRTemp_INVALID); /* due to check above */
sewardjc6f970f2012-04-02 21:54:49 +000018393 llPutIReg(15, mkexpr(newRt));
18394 dres.jk_StopHere = Ijk_Boring; /* or _Ret ? */
18395 dres.whatNext = Dis_StopHere;
18396 }
sewardjd2664472010-08-22 12:44:20 +000018397 }
18398
18399 if (bP == 1 && bW == 0) {
18400 DIP("%s.w r%u, [r%u, #%c%u]\n",
18401 nm, rT, rN, bU ? '+' : '-', imm8);
18402 }
18403 else if (bP == 1 && bW == 1) {
18404 DIP("%s.w r%u, [r%u, #%c%u]!\n",
18405 nm, rT, rN, bU ? '+' : '-', imm8);
18406 }
18407 else {
18408 vassert(bP == 0 && bW == 1);
18409 DIP("%s.w r%u, [r%u], #%c%u\n",
18410 nm, rT, rN, bU ? '+' : '-', imm8);
18411 }
18412
18413 goto decode_success;
18414 }
18415 }
18416
18417 /* ------------- LD/ST reg+(reg<<imm2) ------------- */
18418 /* Loads and stores of the form:
18419 op Rt, [Rn, Rm, LSL #imm8]
18420 where op is one of
18421 ldrb ldrh ldr ldrsb ldrsh
18422 strb strh str
18423 */
18424 if (INSN0(15,9) == BITS7(1,1,1,1,1,0,0)
18425 && INSN1(11,6) == BITS6(0,0,0,0,0,0)) {
18426 Bool valid = True;
18427 Bool syned = False;
18428 Bool isST = False;
18429 IRType ty = Ity_I8;
florian55085f82012-11-21 00:36:55 +000018430 const HChar* nm = "???";
sewardjd2664472010-08-22 12:44:20 +000018431
18432 switch (INSN0(8,4)) {
18433 case BITS5(0,0,0,0,0): // strb
18434 nm = "strb"; isST = True; break;
18435 case BITS5(0,0,0,0,1): // ldrb
18436 nm = "ldrb"; break;
18437 case BITS5(1,0,0,0,1): // ldrsb
18438 nm = "ldrsb"; syned = True; break;
18439 case BITS5(0,0,0,1,0): // strh
18440 nm = "strh"; ty = Ity_I16; isST = True; break;
18441 case BITS5(0,0,0,1,1): // ldrh
18442 nm = "ldrh"; ty = Ity_I16; break;
18443 case BITS5(1,0,0,1,1): // ldrsh
18444 nm = "ldrsh"; ty = Ity_I16; syned = True; break;
18445 case BITS5(0,0,1,0,0): // str
18446 nm = "str"; ty = Ity_I32; isST = True; break;
18447 case BITS5(0,0,1,0,1):
18448 nm = "ldr"; ty = Ity_I32; break; // ldr
18449 default:
18450 valid = False; break;
18451 }
18452
18453 UInt rN = INSN0(3,0);
18454 UInt rM = INSN1(3,0);
18455 UInt rT = INSN1(15,12);
18456 UInt imm2 = INSN1(5,4);
18457 Bool loadsPC = False;
18458
18459 if (ty == Ity_I8 || ty == Ity_I16) {
18460 /* all 8- and 16-bit load and store cases have the
18461 same exclusion set. */
18462 if (rN == 15 || isBadRegT(rT) || isBadRegT(rM))
18463 valid = False;
18464 } else {
18465 vassert(ty == Ity_I32);
18466 if (rN == 15 || isBadRegT(rM))
18467 valid = False;
18468 if (isST && rT == 15)
18469 valid = False;
18470 /* If it is a load and rT is 15, that's only allowable if we
18471 not in an IT block, or are the last in it. Need to insert
18472 a dynamic check for that. */
18473 if (!isST && rT == 15)
18474 loadsPC = True;
18475 }
18476
18477 if (valid) {
18478 // if it's a branch, it can't happen in the middle of an IT block
sewardjcfe046e2013-01-17 14:23:53 +000018479 // Also, if it is a branch, make it unconditional at this point.
18480 // Doing conditional branches in-line is too complex (for now)
18481 if (loadsPC) {
sewardjd2664472010-08-22 12:44:20 +000018482 gen_SIGILL_T_if_in_but_NLI_ITBlock(old_itstate, new_itstate);
sewardjcfe046e2013-01-17 14:23:53 +000018483 // go uncond
18484 mk_skip_over_T32_if_cond_is_false(condT);
18485 condT = IRTemp_INVALID;
18486 // now uncond
18487 }
sewardjd2664472010-08-22 12:44:20 +000018488
18489 IRTemp transAddr = newTemp(Ity_I32);
18490 assign(transAddr,
18491 binop( Iop_Add32,
18492 getIRegT(rN),
18493 binop(Iop_Shl32, getIRegT(rM), mkU8(imm2)) ));
18494
18495 if (isST) {
sewardjcfe046e2013-01-17 14:23:53 +000018496
18497 /* get hold of the data to be stored */
sewardjd2664472010-08-22 12:44:20 +000018498 IRTemp oldRt = newTemp(Ity_I32);
18499 assign(oldRt, getIRegT(rT));
sewardjcfe046e2013-01-17 14:23:53 +000018500
18501 /* generate the transfer */
18502 IRExpr* data = NULL;
sewardjd2664472010-08-22 12:44:20 +000018503 switch (ty) {
18504 case Ity_I8:
sewardjcfe046e2013-01-17 14:23:53 +000018505 data = unop(Iop_32to8, mkexpr(oldRt));
sewardjd2664472010-08-22 12:44:20 +000018506 break;
18507 case Ity_I16:
sewardjcfe046e2013-01-17 14:23:53 +000018508 data = unop(Iop_32to16, mkexpr(oldRt));
sewardjd2664472010-08-22 12:44:20 +000018509 break;
18510 case Ity_I32:
sewardjcfe046e2013-01-17 14:23:53 +000018511 data = mkexpr(oldRt);
sewardjd2664472010-08-22 12:44:20 +000018512 break;
18513 default:
18514 vassert(0);
18515 }
sewardjcfe046e2013-01-17 14:23:53 +000018516 storeGuardedLE(mkexpr(transAddr), data, condT);
18517
sewardjd2664472010-08-22 12:44:20 +000018518 } else {
sewardjcfe046e2013-01-17 14:23:53 +000018519
18520 /* Load. */
18521 IRTemp llOldRt = newTemp(Ity_I32);
18522 assign(llOldRt, llGetIReg(rT));
18523
18524 /* generate the transfer */
18525 IRTemp newRt = newTemp(Ity_I32);
18526 IRLoadGOp widen = ILGop_INVALID;
sewardjd2664472010-08-22 12:44:20 +000018527 switch (ty) {
18528 case Ity_I8:
sewardjcfe046e2013-01-17 14:23:53 +000018529 widen = syned ? ILGop_8Sto32 : ILGop_8Uto32; break;
sewardjd2664472010-08-22 12:44:20 +000018530 case Ity_I16:
sewardjcfe046e2013-01-17 14:23:53 +000018531 widen = syned ? ILGop_16Sto32 : ILGop_16Uto32; break;
sewardjd2664472010-08-22 12:44:20 +000018532 case Ity_I32:
sewardjcfe046e2013-01-17 14:23:53 +000018533 widen = ILGop_Ident32; break;
sewardjd2664472010-08-22 12:44:20 +000018534 default:
18535 vassert(0);
18536 }
sewardjcfe046e2013-01-17 14:23:53 +000018537 loadGuardedLE(newRt, widen,
18538 mkexpr(transAddr), mkexpr(llOldRt), condT);
sewardjd2664472010-08-22 12:44:20 +000018539
sewardjcfe046e2013-01-17 14:23:53 +000018540 if (rT == 15) {
18541 vassert(loadsPC);
18542 /* We'll do the write to the PC just below */
sewardjd2664472010-08-22 12:44:20 +000018543 } else {
sewardjcfe046e2013-01-17 14:23:53 +000018544 vassert(!loadsPC);
18545 /* IRTemp_INVALID is OK here because in the case where
18546 condT is false at run time, we're just putting the
18547 old rT value back. */
sewardjd2664472010-08-22 12:44:20 +000018548 putIRegT(rT, mkexpr(newRt), IRTemp_INVALID);
18549 }
18550
18551 if (loadsPC) {
18552 /* Presumably this is an interworking branch. */
sewardjcfe046e2013-01-17 14:23:53 +000018553 vassert(rN != 15); // assured by validity check above
18554 vassert(rT == 15);
18555 vassert(condT == IRTemp_INVALID); /* due to check above */
sewardjc6f970f2012-04-02 21:54:49 +000018556 llPutIReg(15, mkexpr(newRt));
18557 dres.jk_StopHere = Ijk_Boring; /* or _Ret ? */
18558 dres.whatNext = Dis_StopHere;
sewardjd2664472010-08-22 12:44:20 +000018559 }
18560 }
18561
18562 DIP("%s.w r%u, [r%u, r%u, LSL #%u]\n",
18563 nm, rT, rN, rM, imm2);
18564
18565 goto decode_success;
18566 }
18567 }
18568
18569 /* --------------- LD/ST reg+imm12 --------------- */
18570 /* Loads and stores of the form:
18571 op Rt, [Rn, +#imm12]
18572 where op is one of
18573 ldrb ldrh ldr ldrsb ldrsh
18574 strb strh str
18575 */
18576 if (INSN0(15,9) == BITS7(1,1,1,1,1,0,0)) {
18577 Bool valid = True;
18578 Bool syned = False;
18579 Bool isST = False;
18580 IRType ty = Ity_I8;
florian55085f82012-11-21 00:36:55 +000018581 const HChar* nm = "???";
sewardjd2664472010-08-22 12:44:20 +000018582
18583 switch (INSN0(8,4)) {
18584 case BITS5(0,1,0,0,0): // strb
18585 nm = "strb"; isST = True; break;
18586 case BITS5(0,1,0,0,1): // ldrb
18587 nm = "ldrb"; break;
18588 case BITS5(1,1,0,0,1): // ldrsb
18589 nm = "ldrsb"; syned = True; break;
18590 case BITS5(0,1,0,1,0): // strh
18591 nm = "strh"; ty = Ity_I16; isST = True; break;
18592 case BITS5(0,1,0,1,1): // ldrh
18593 nm = "ldrh"; ty = Ity_I16; break;
18594 case BITS5(1,1,0,1,1): // ldrsh
18595 nm = "ldrsh"; ty = Ity_I16; syned = True; break;
18596 case BITS5(0,1,1,0,0): // str
18597 nm = "str"; ty = Ity_I32; isST = True; break;
18598 case BITS5(0,1,1,0,1):
18599 nm = "ldr"; ty = Ity_I32; break; // ldr
18600 default:
18601 valid = False; break;
18602 }
18603
18604 UInt rN = INSN0(3,0);
18605 UInt rT = INSN1(15,12);
18606 UInt imm12 = INSN1(11,0);
18607 Bool loadsPC = False;
18608
18609 if (ty == Ity_I8 || ty == Ity_I16) {
18610 /* all 8- and 16-bit load and store cases have the
18611 same exclusion set. */
18612 if (rN == 15 || isBadRegT(rT))
18613 valid = False;
18614 } else {
18615 vassert(ty == Ity_I32);
18616 if (isST) {
18617 if (rN == 15 || rT == 15)
18618 valid = False;
18619 } else {
18620 /* For a 32-bit load, rT == 15 is only allowable if we not
18621 in an IT block, or are the last in it. Need to insert
18622 a dynamic check for that. Also, in this particular
18623 case, rN == 15 is allowable. In this case however, the
18624 value obtained for rN is (apparently)
18625 "word-align(address of current insn + 4)". */
18626 if (rT == 15)
18627 loadsPC = True;
18628 }
18629 }
18630
18631 if (valid) {
18632 // if it's a branch, it can't happen in the middle of an IT block
sewardjcfe046e2013-01-17 14:23:53 +000018633 // Also, if it is a branch, make it unconditional at this point.
18634 // Doing conditional branches in-line is too complex (for now)
18635 if (loadsPC) {
sewardjd2664472010-08-22 12:44:20 +000018636 gen_SIGILL_T_if_in_but_NLI_ITBlock(old_itstate, new_itstate);
sewardjcfe046e2013-01-17 14:23:53 +000018637 // go uncond
18638 mk_skip_over_T32_if_cond_is_false(condT);
18639 condT = IRTemp_INVALID;
18640 // now uncond
18641 }
sewardjd2664472010-08-22 12:44:20 +000018642
18643 IRTemp rNt = newTemp(Ity_I32);
18644 if (rN == 15) {
18645 vassert(ty == Ity_I32 && !isST);
18646 assign(rNt, binop(Iop_And32, getIRegT(rN), mkU32(~3)));
18647 } else {
18648 assign(rNt, getIRegT(rN));
18649 }
18650
18651 IRTemp transAddr = newTemp(Ity_I32);
18652 assign(transAddr,
18653 binop( Iop_Add32, mkexpr(rNt), mkU32(imm12) ));
18654
sewardjcfe046e2013-01-17 14:23:53 +000018655 IRTemp oldRt = newTemp(Ity_I32);
18656 assign(oldRt, getIRegT(rT));
18657
18658 IRTemp llOldRt = newTemp(Ity_I32);
18659 assign(llOldRt, llGetIReg(rT));
18660
sewardjd2664472010-08-22 12:44:20 +000018661 if (isST) {
sewardjcfe046e2013-01-17 14:23:53 +000018662 IRExpr* data = NULL;
sewardjd2664472010-08-22 12:44:20 +000018663 switch (ty) {
18664 case Ity_I8:
sewardjcfe046e2013-01-17 14:23:53 +000018665 data = unop(Iop_32to8, mkexpr(oldRt));
sewardjd2664472010-08-22 12:44:20 +000018666 break;
18667 case Ity_I16:
sewardjcfe046e2013-01-17 14:23:53 +000018668 data = unop(Iop_32to16, mkexpr(oldRt));
sewardjd2664472010-08-22 12:44:20 +000018669 break;
18670 case Ity_I32:
sewardjcfe046e2013-01-17 14:23:53 +000018671 data = mkexpr(oldRt);
sewardjd2664472010-08-22 12:44:20 +000018672 break;
18673 default:
18674 vassert(0);
18675 }
sewardjcfe046e2013-01-17 14:23:53 +000018676 storeGuardedLE(mkexpr(transAddr), data, condT);
sewardjd2664472010-08-22 12:44:20 +000018677 } else {
sewardjcfe046e2013-01-17 14:23:53 +000018678 IRTemp newRt = newTemp(Ity_I32);
18679 IRLoadGOp widen = ILGop_INVALID;
sewardjd2664472010-08-22 12:44:20 +000018680 switch (ty) {
18681 case Ity_I8:
sewardjcfe046e2013-01-17 14:23:53 +000018682 widen = syned ? ILGop_8Sto32 : ILGop_8Uto32; break;
sewardjd2664472010-08-22 12:44:20 +000018683 case Ity_I16:
sewardjcfe046e2013-01-17 14:23:53 +000018684 widen = syned ? ILGop_16Sto32 : ILGop_16Uto32; break;
sewardjd2664472010-08-22 12:44:20 +000018685 case Ity_I32:
sewardjcfe046e2013-01-17 14:23:53 +000018686 widen = ILGop_Ident32; break;
sewardjd2664472010-08-22 12:44:20 +000018687 default:
18688 vassert(0);
18689 }
sewardjcfe046e2013-01-17 14:23:53 +000018690 loadGuardedLE(newRt, widen,
18691 mkexpr(transAddr), mkexpr(llOldRt), condT);
18692 if (rT == 15) {
18693 vassert(loadsPC);
18694 /* We'll do the write to the PC just below */
sewardjd2664472010-08-22 12:44:20 +000018695 } else {
sewardjcfe046e2013-01-17 14:23:53 +000018696 vassert(!loadsPC);
18697 /* IRTemp_INVALID is OK here because in the case where
18698 condT is false at run time, we're just putting the
18699 old rT value back. */
18700 putIRegT(rT, mkexpr(newRt), IRTemp_INVALID);
sewardjd2664472010-08-22 12:44:20 +000018701 }
sewardjd2664472010-08-22 12:44:20 +000018702
18703 if (loadsPC) {
18704 /* Presumably this is an interworking branch. */
sewardjcfe046e2013-01-17 14:23:53 +000018705 vassert(rT == 15);
18706 vassert(condT == IRTemp_INVALID); /* due to check above */
18707 llPutIReg(15, mkexpr(newRt));
sewardjd2664472010-08-22 12:44:20 +000018708 irsb->next = mkexpr(newRt);
18709 irsb->jumpkind = Ijk_Boring; /* or _Ret ? */
18710 dres.whatNext = Dis_StopHere;
18711 }
18712 }
18713
18714 DIP("%s.w r%u, [r%u, +#%u]\n", nm, rT, rN, imm12);
18715
18716 goto decode_success;
18717 }
18718 }
18719
18720 /* -------------- LDRD/STRD reg+/-#imm8 -------------- */
18721 /* Doubleword loads and stores of the form:
18722 ldrd/strd Rt, Rt2, [Rn, #-imm8] or
18723 ldrd/strd Rt, Rt2, [Rn], #+/-imm8 or
18724 ldrd/strd Rt, Rt2, [Rn, #+/-imm8]!
18725 */
18726 if (INSN0(15,9) == BITS7(1,1,1,0,1,0,0) && INSN0(6,6) == 1) {
18727 UInt bP = INSN0(8,8);
18728 UInt bU = INSN0(7,7);
18729 UInt bW = INSN0(5,5);
18730 UInt bL = INSN0(4,4); // 1: load 0: store
18731 UInt rN = INSN0(3,0);
18732 UInt rT = INSN1(15,12);
18733 UInt rT2 = INSN1(11,8);
18734 UInt imm8 = INSN1(7,0);
18735
18736 Bool valid = True;
18737 if (bP == 0 && bW == 0) valid = False;
18738 if (bW == 1 && (rN == rT || rN == rT2)) valid = False;
18739 if (isBadRegT(rT) || isBadRegT(rT2)) valid = False;
18740 if (rN == 15) valid = False;
18741 if (bL == 1 && rT == rT2) valid = False;
18742
18743 if (valid) {
sewardjd2664472010-08-22 12:44:20 +000018744 IRTemp preAddr = newTemp(Ity_I32);
18745 assign(preAddr, getIRegT(rN));
18746
18747 IRTemp postAddr = newTemp(Ity_I32);
18748 assign(postAddr, binop(bU == 1 ? Iop_Add32 : Iop_Sub32,
18749 mkexpr(preAddr), mkU32(imm8 << 2)));
18750
18751 IRTemp transAddr = bP == 1 ? postAddr : preAddr;
18752
sewardj92001d42013-04-26 10:24:31 +000018753 /* For almost all cases, we do the writeback after the transfers.
18754 However, that leaves the stack "uncovered" in this case:
18755 strd rD, [sp, #-8]
18756 In which case, do the writeback to SP now, instead of later.
18757 This is bad in that it makes the insn non-restartable if the
18758 accesses fault, but at least keeps Memcheck happy. */
18759 Bool writeback_already_done = False;
18760 if (bL == 0/*store*/ && bW == 1/*wb*/
18761 && rN == 13 && rN != rT && rN != rT2
18762 && bU == 0/*minus*/ && (imm8 << 2) == 8) {
18763 putIRegT(rN, mkexpr(postAddr), condT);
18764 writeback_already_done = True;
18765 }
18766
sewardjd2664472010-08-22 12:44:20 +000018767 if (bL == 0) {
18768 IRTemp oldRt = newTemp(Ity_I32);
18769 IRTemp oldRt2 = newTemp(Ity_I32);
18770 assign(oldRt, getIRegT(rT));
18771 assign(oldRt2, getIRegT(rT2));
sewardjcfe046e2013-01-17 14:23:53 +000018772 storeGuardedLE( mkexpr(transAddr),
18773 mkexpr(oldRt), condT );
18774 storeGuardedLE( binop(Iop_Add32, mkexpr(transAddr), mkU32(4)),
18775 mkexpr(oldRt2), condT );
sewardjd2664472010-08-22 12:44:20 +000018776 } else {
sewardjcfe046e2013-01-17 14:23:53 +000018777 IRTemp oldRt = newTemp(Ity_I32);
18778 IRTemp oldRt2 = newTemp(Ity_I32);
sewardjd2664472010-08-22 12:44:20 +000018779 IRTemp newRt = newTemp(Ity_I32);
18780 IRTemp newRt2 = newTemp(Ity_I32);
sewardjcfe046e2013-01-17 14:23:53 +000018781 assign(oldRt, llGetIReg(rT));
18782 assign(oldRt2, llGetIReg(rT2));
18783 loadGuardedLE( newRt, ILGop_Ident32,
18784 mkexpr(transAddr),
18785 mkexpr(oldRt), condT );
18786 loadGuardedLE( newRt2, ILGop_Ident32,
18787 binop(Iop_Add32, mkexpr(transAddr), mkU32(4)),
18788 mkexpr(oldRt2), condT );
18789 /* Put unconditionally, since we already switched on the condT
18790 in the guarded loads. */
18791 putIRegT(rT, mkexpr(newRt), IRTemp_INVALID);
sewardjd2664472010-08-22 12:44:20 +000018792 putIRegT(rT2, mkexpr(newRt2), IRTemp_INVALID);
18793 }
18794
sewardj92001d42013-04-26 10:24:31 +000018795 if (bW == 1 && !writeback_already_done) {
sewardjcfe046e2013-01-17 14:23:53 +000018796 putIRegT(rN, mkexpr(postAddr), condT);
sewardjd2664472010-08-22 12:44:20 +000018797 }
18798
florian55085f82012-11-21 00:36:55 +000018799 const HChar* nm = bL ? "ldrd" : "strd";
sewardjd2664472010-08-22 12:44:20 +000018800
18801 if (bP == 1 && bW == 0) {
18802 DIP("%s.w r%u, r%u, [r%u, #%c%u]\n",
18803 nm, rT, rT2, rN, bU ? '+' : '-', imm8 << 2);
18804 }
18805 else if (bP == 1 && bW == 1) {
18806 DIP("%s.w r%u, r%u, [r%u, #%c%u]!\n",
18807 nm, rT, rT2, rN, bU ? '+' : '-', imm8 << 2);
18808 }
18809 else {
18810 vassert(bP == 0 && bW == 1);
18811 DIP("%s.w r%u, r%u, [r%u], #%c%u\n",
18812 nm, rT, rT2, rN, bU ? '+' : '-', imm8 << 2);
18813 }
18814
18815 goto decode_success;
18816 }
18817 }
18818
18819 /* -------------- (T3) Bcond.W label -------------- */
18820 /* This variant carries its own condition, so can't be part of an
18821 IT block ... */
18822 if (INSN0(15,11) == BITS5(1,1,1,1,0)
18823 && INSN1(15,14) == BITS2(1,0)
18824 && INSN1(12,12) == 0) {
18825 UInt cond = INSN0(9,6);
18826 if (cond != ARMCondAL && cond != ARMCondNV) {
18827 Int simm21
18828 = (INSN0(10,10) << (1 + 1 + 6 + 11 + 1))
18829 | (INSN1(11,11) << (1 + 6 + 11 + 1))
18830 | (INSN1(13,13) << (6 + 11 + 1))
18831 | (INSN0(5,0) << (11 + 1))
18832 | (INSN1(10,0) << 1);
18833 simm21 = (simm21 << 11) >> 11;
18834
18835 vassert(0 == (guest_R15_curr_instr_notENC & 1));
18836 UInt dst = simm21 + guest_R15_curr_instr_notENC + 4;
18837
18838 /* Not allowed in an IT block; SIGILL if so. */
18839 gen_SIGILL_T_if_in_ITBlock(old_itstate, new_itstate);
18840
18841 IRTemp kondT = newTemp(Ity_I32);
18842 assign( kondT, mk_armg_calculate_condition(cond) );
18843 stmt( IRStmt_Exit( unop(Iop_32to1, mkexpr(kondT)),
18844 Ijk_Boring,
sewardjc6f970f2012-04-02 21:54:49 +000018845 IRConst_U32(dst | 1/*CPSR.T*/),
18846 OFFB_R15T ));
18847 llPutIReg(15, mkU32( (guest_R15_curr_instr_notENC + 4)
18848 | 1 /*CPSR.T*/ ));
18849 dres.jk_StopHere = Ijk_Boring;
18850 dres.whatNext = Dis_StopHere;
sewardjd2664472010-08-22 12:44:20 +000018851 DIP("b%s.w 0x%x\n", nCC(cond), dst);
18852 goto decode_success;
18853 }
18854 }
18855
18856 /* ---------------- (T4) B.W label ---------------- */
18857 /* ... whereas this variant doesn't carry its own condition, so it
18858 has to be either unconditional or the conditional by virtue of
18859 being the last in an IT block. The upside is that there's 4
18860 more bits available for the jump offset, so it has a 16-times
18861 greater branch range than the T3 variant. */
18862 if (INSN0(15,11) == BITS5(1,1,1,1,0)
18863 && INSN1(15,14) == BITS2(1,0)
18864 && INSN1(12,12) == 1) {
18865 if (1) {
18866 UInt bS = INSN0(10,10);
18867 UInt bJ1 = INSN1(13,13);
18868 UInt bJ2 = INSN1(11,11);
18869 UInt bI1 = 1 ^ (bJ1 ^ bS);
18870 UInt bI2 = 1 ^ (bJ2 ^ bS);
18871 Int simm25
18872 = (bS << (1 + 1 + 10 + 11 + 1))
18873 | (bI1 << (1 + 10 + 11 + 1))
18874 | (bI2 << (10 + 11 + 1))
18875 | (INSN0(9,0) << (11 + 1))
18876 | (INSN1(10,0) << 1);
18877 simm25 = (simm25 << 7) >> 7;
18878
18879 vassert(0 == (guest_R15_curr_instr_notENC & 1));
18880 UInt dst = simm25 + guest_R15_curr_instr_notENC + 4;
18881
18882 /* If in an IT block, must be the last insn. */
18883 gen_SIGILL_T_if_in_but_NLI_ITBlock(old_itstate, new_itstate);
18884
18885 // go uncond
18886 mk_skip_over_T32_if_cond_is_false(condT);
18887 condT = IRTemp_INVALID;
18888 // now uncond
18889
18890 // branch to dst
sewardjc6f970f2012-04-02 21:54:49 +000018891 llPutIReg(15, mkU32( dst | 1 /*CPSR.T*/ ));
18892 dres.jk_StopHere = Ijk_Boring;
18893 dres.whatNext = Dis_StopHere;
sewardjd2664472010-08-22 12:44:20 +000018894 DIP("b.w 0x%x\n", dst);
18895 goto decode_success;
18896 }
18897 }
18898
18899 /* ------------------ TBB, TBH ------------------ */
18900 if (INSN0(15,4) == 0xE8D && INSN1(15,5) == 0x780) {
18901 UInt rN = INSN0(3,0);
18902 UInt rM = INSN1(3,0);
18903 UInt bH = INSN1(4,4);
18904 if (bH/*ATC*/ || (rN != 13 && !isBadRegT(rM))) {
18905 /* Must be last or not-in IT block */
18906 gen_SIGILL_T_if_in_but_NLI_ITBlock(old_itstate, new_itstate);
18907 /* Go uncond */
18908 mk_skip_over_T32_if_cond_is_false(condT);
18909 condT = IRTemp_INVALID;
18910
18911 IRExpr* ea
18912 = binop(Iop_Add32,
18913 getIRegT(rN),
18914 bH ? binop(Iop_Shl32, getIRegT(rM), mkU8(1))
18915 : getIRegT(rM));
18916
18917 IRTemp delta = newTemp(Ity_I32);
18918 if (bH) {
18919 assign(delta, unop(Iop_16Uto32, loadLE(Ity_I16, ea)));
18920 } else {
18921 assign(delta, unop(Iop_8Uto32, loadLE(Ity_I8, ea)));
18922 }
18923
sewardjc6f970f2012-04-02 21:54:49 +000018924 llPutIReg(
18925 15,
18926 binop(Iop_Or32,
18927 binop(Iop_Add32,
18928 getIRegT(15),
18929 binop(Iop_Shl32, mkexpr(delta), mkU8(1))
18930 ),
18931 mkU32(1)
18932 ));
18933 dres.jk_StopHere = Ijk_Boring;
18934 dres.whatNext = Dis_StopHere;
sewardjd2664472010-08-22 12:44:20 +000018935 DIP("tb%c [r%u, r%u%s]\n",
18936 bH ? 'h' : 'b', rN, rM, bH ? ", LSL #1" : "");
18937 goto decode_success;
18938 }
18939 }
18940
18941 /* ------------------ UBFX ------------------ */
18942 /* ------------------ SBFX ------------------ */
18943 /* There's also ARM versions of same, but it doesn't seem worth the
18944 hassle to common up the handling (it's only a couple of C
18945 statements). */
18946 if ((INSN0(15,4) == 0xF3C // UBFX
18947 || INSN0(15,4) == 0xF34) // SBFX
18948 && INSN1(15,15) == 0 && INSN1(5,5) == 0) {
18949 UInt rN = INSN0(3,0);
18950 UInt rD = INSN1(11,8);
18951 UInt lsb = (INSN1(14,12) << 2) | INSN1(7,6);
18952 UInt wm1 = INSN1(4,0);
18953 UInt msb = lsb + wm1;
18954 if (!isBadRegT(rD) && !isBadRegT(rN) && msb <= 31) {
18955 Bool isU = INSN0(15,4) == 0xF3C;
18956 IRTemp src = newTemp(Ity_I32);
18957 IRTemp tmp = newTemp(Ity_I32);
18958 IRTemp res = newTemp(Ity_I32);
18959 UInt mask = ((1 << wm1) - 1) + (1 << wm1);
18960 vassert(msb >= 0 && msb <= 31);
18961 vassert(mask != 0); // guaranteed by msb being in 0 .. 31 inclusive
18962
18963 assign(src, getIRegT(rN));
18964 assign(tmp, binop(Iop_And32,
18965 binop(Iop_Shr32, mkexpr(src), mkU8(lsb)),
18966 mkU32(mask)));
18967 assign(res, binop(isU ? Iop_Shr32 : Iop_Sar32,
18968 binop(Iop_Shl32, mkexpr(tmp), mkU8(31-wm1)),
18969 mkU8(31-wm1)));
18970
18971 putIRegT(rD, mkexpr(res), condT);
18972
18973 DIP("%s r%u, r%u, #%u, #%u\n",
18974 isU ? "ubfx" : "sbfx", rD, rN, lsb, wm1 + 1);
18975 goto decode_success;
18976 }
18977 }
18978
18979 /* ------------------ UXTB ------------------ */
18980 /* ------------------ UXTH ------------------ */
18981 /* ------------------ SXTB ------------------ */
18982 /* ------------------ SXTH ------------------ */
sewardj1f139f52010-08-29 12:33:02 +000018983 /* ----------------- UXTB16 ----------------- */
18984 /* ----------------- SXTB16 ----------------- */
18985 /* FIXME: this is an exact duplicate of the ARM version. They
18986 should be commoned up. */
sewardjd2664472010-08-22 12:44:20 +000018987 if ((INSN0(15,0) == 0xFA5F // UXTB
18988 || INSN0(15,0) == 0xFA1F // UXTH
18989 || INSN0(15,0) == 0xFA4F // SXTB
sewardj1f139f52010-08-29 12:33:02 +000018990 || INSN0(15,0) == 0xFA0F // SXTH
18991 || INSN0(15,0) == 0xFA3F // UXTB16
18992 || INSN0(15,0) == 0xFA2F) // SXTB16
sewardjd2664472010-08-22 12:44:20 +000018993 && INSN1(15,12) == BITS4(1,1,1,1)
18994 && INSN1(7,6) == BITS2(1,0)) {
18995 UInt rD = INSN1(11,8);
18996 UInt rM = INSN1(3,0);
18997 UInt rot = INSN1(5,4);
18998 if (!isBadRegT(rD) && !isBadRegT(rM)) {
florian55085f82012-11-21 00:36:55 +000018999 const HChar* nm = "???";
sewardjd2664472010-08-22 12:44:20 +000019000 IRTemp srcT = newTemp(Ity_I32);
19001 IRTemp rotT = newTemp(Ity_I32);
19002 IRTemp dstT = newTemp(Ity_I32);
19003 assign(srcT, getIRegT(rM));
19004 assign(rotT, genROR32(srcT, 8 * rot));
19005 switch (INSN0(15,0)) {
19006 case 0xFA5F: // UXTB
19007 nm = "uxtb";
19008 assign(dstT, unop(Iop_8Uto32,
19009 unop(Iop_32to8, mkexpr(rotT))));
19010 break;
19011 case 0xFA1F: // UXTH
19012 nm = "uxth";
19013 assign(dstT, unop(Iop_16Uto32,
19014 unop(Iop_32to16, mkexpr(rotT))));
19015 break;
19016 case 0xFA4F: // SXTB
19017 nm = "sxtb";
19018 assign(dstT, unop(Iop_8Sto32,
19019 unop(Iop_32to8, mkexpr(rotT))));
19020 break;
19021 case 0xFA0F: // SXTH
19022 nm = "sxth";
19023 assign(dstT, unop(Iop_16Sto32,
19024 unop(Iop_32to16, mkexpr(rotT))));
19025 break;
sewardj1f139f52010-08-29 12:33:02 +000019026 case 0xFA3F: // UXTB16
19027 nm = "uxtb16";
19028 assign(dstT, binop(Iop_And32, mkexpr(rotT),
19029 mkU32(0x00FF00FF)));
19030 break;
19031 case 0xFA2F: { // SXTB16
19032 nm = "sxtb16";
19033 IRTemp lo32 = newTemp(Ity_I32);
19034 IRTemp hi32 = newTemp(Ity_I32);
19035 assign(lo32, binop(Iop_And32, mkexpr(rotT), mkU32(0xFF)));
19036 assign(hi32, binop(Iop_Shr32, mkexpr(rotT), mkU8(16)));
19037 assign(
19038 dstT,
19039 binop(Iop_Or32,
19040 binop(Iop_And32,
19041 unop(Iop_8Sto32,
19042 unop(Iop_32to8, mkexpr(lo32))),
19043 mkU32(0xFFFF)),
19044 binop(Iop_Shl32,
19045 unop(Iop_8Sto32,
19046 unop(Iop_32to8, mkexpr(hi32))),
19047 mkU8(16))
19048 ));
19049 break;
19050 }
sewardjd2664472010-08-22 12:44:20 +000019051 default:
19052 vassert(0);
19053 }
19054 putIRegT(rD, mkexpr(dstT), condT);
19055 DIP("%s r%u, r%u, ror #%u\n", nm, rD, rM, 8 * rot);
19056 goto decode_success;
19057 }
19058 }
19059
19060 /* -------------- MUL.W Rd, Rn, Rm -------------- */
19061 if (INSN0(15,4) == 0xFB0
19062 && (INSN1(15,0) & 0xF0F0) == 0xF000) {
19063 UInt rN = INSN0(3,0);
19064 UInt rD = INSN1(11,8);
19065 UInt rM = INSN1(3,0);
19066 if (!isBadRegT(rD) && !isBadRegT(rN) && !isBadRegT(rM)) {
19067 IRTemp res = newTemp(Ity_I32);
19068 assign(res, binop(Iop_Mul32, getIRegT(rN), getIRegT(rM)));
19069 putIRegT(rD, mkexpr(res), condT);
19070 DIP("mul.w r%u, r%u, r%u\n", rD, rN, rM);
19071 goto decode_success;
19072 }
19073 }
19074
sewardj8bde7f12013-04-11 13:57:43 +000019075 /* -------------- SDIV.W Rd, Rn, Rm -------------- */
19076 if (INSN0(15,4) == 0xFB9
19077 && (INSN1(15,0) & 0xF0F0) == 0xF0F0) {
19078 UInt rN = INSN0(3,0);
19079 UInt rD = INSN1(11,8);
19080 UInt rM = INSN1(3,0);
19081 if (!isBadRegT(rD) && !isBadRegT(rN) && !isBadRegT(rM)) {
19082 IRTemp res = newTemp(Ity_I32);
19083 IRTemp argL = newTemp(Ity_I32);
19084 IRTemp argR = newTemp(Ity_I32);
19085 assign(argL, getIRegT(rN));
19086 assign(argR, getIRegT(rM));
19087 assign(res, binop(Iop_DivS32, mkexpr(argL), mkexpr(argR)));
19088 putIRegT(rD, mkexpr(res), condT);
19089 DIP("sdiv.w r%u, r%u, r%u\n", rD, rN, rM);
19090 goto decode_success;
19091 }
19092 }
19093
19094 /* -------------- UDIV.W Rd, Rn, Rm -------------- */
19095 if (INSN0(15,4) == 0xFBB
19096 && (INSN1(15,0) & 0xF0F0) == 0xF0F0) {
19097 UInt rN = INSN0(3,0);
19098 UInt rD = INSN1(11,8);
19099 UInt rM = INSN1(3,0);
19100 if (!isBadRegT(rD) && !isBadRegT(rN) && !isBadRegT(rM)) {
19101 IRTemp res = newTemp(Ity_I32);
19102 IRTemp argL = newTemp(Ity_I32);
19103 IRTemp argR = newTemp(Ity_I32);
19104 assign(argL, getIRegT(rN));
19105 assign(argR, getIRegT(rM));
19106 assign(res, binop(Iop_DivU32, mkexpr(argL), mkexpr(argR)));
19107 putIRegT(rD, mkexpr(res), condT);
19108 DIP("udiv.w r%u, r%u, r%u\n", rD, rN, rM);
19109 goto decode_success;
19110 }
19111 }
19112
sewardjd2664472010-08-22 12:44:20 +000019113 /* ------------------ {U,S}MULL ------------------ */
19114 if ((INSN0(15,4) == 0xFB8 || INSN0(15,4) == 0xFBA)
19115 && INSN1(7,4) == BITS4(0,0,0,0)) {
19116 UInt isU = INSN0(5,5);
19117 UInt rN = INSN0(3,0);
19118 UInt rDlo = INSN1(15,12);
19119 UInt rDhi = INSN1(11,8);
19120 UInt rM = INSN1(3,0);
19121 if (!isBadRegT(rDhi) && !isBadRegT(rDlo)
19122 && !isBadRegT(rN) && !isBadRegT(rM) && rDlo != rDhi) {
19123 IRTemp res = newTemp(Ity_I64);
19124 assign(res, binop(isU ? Iop_MullU32 : Iop_MullS32,
19125 getIRegT(rN), getIRegT(rM)));
19126 putIRegT( rDhi, unop(Iop_64HIto32, mkexpr(res)), condT );
19127 putIRegT( rDlo, unop(Iop_64to32, mkexpr(res)), condT );
19128 DIP("%cmull r%u, r%u, r%u, r%u\n",
19129 isU ? 'u' : 's', rDlo, rDhi, rN, rM);
19130 goto decode_success;
19131 }
19132 }
19133
19134 /* ------------------ ML{A,S} ------------------ */
19135 if (INSN0(15,4) == 0xFB0
19136 && ( INSN1(7,4) == BITS4(0,0,0,0) // MLA
19137 || INSN1(7,4) == BITS4(0,0,0,1))) { // MLS
19138 UInt rN = INSN0(3,0);
19139 UInt rA = INSN1(15,12);
19140 UInt rD = INSN1(11,8);
19141 UInt rM = INSN1(3,0);
19142 if (!isBadRegT(rD) && !isBadRegT(rN)
19143 && !isBadRegT(rM) && !isBadRegT(rA)) {
19144 Bool isMLA = INSN1(7,4) == BITS4(0,0,0,0);
19145 IRTemp res = newTemp(Ity_I32);
19146 assign(res,
19147 binop(isMLA ? Iop_Add32 : Iop_Sub32,
19148 getIRegT(rA),
19149 binop(Iop_Mul32, getIRegT(rN), getIRegT(rM))));
19150 putIRegT(rD, mkexpr(res), condT);
19151 DIP("%s r%u, r%u, r%u, r%u\n",
19152 isMLA ? "mla" : "mls", rD, rN, rM, rA);
19153 goto decode_success;
19154 }
19155 }
19156
19157 /* ------------------ (T3) ADR ------------------ */
19158 if ((INSN0(15,0) == 0xF20F || INSN0(15,0) == 0xF60F)
19159 && INSN1(15,15) == 0) {
19160 /* rD = align4(PC) + imm32 */
19161 UInt rD = INSN1(11,8);
19162 if (!isBadRegT(rD)) {
19163 UInt imm32 = (INSN0(10,10) << 11)
19164 | (INSN1(14,12) << 8) | INSN1(7,0);
19165 putIRegT(rD, binop(Iop_Add32,
sewardjdf86f162010-08-22 18:47:30 +000019166 binop(Iop_And32, getIRegT(15), mkU32(~3U)),
sewardjd2664472010-08-22 12:44:20 +000019167 mkU32(imm32)),
19168 condT);
19169 DIP("add r%u, pc, #%u\n", rD, imm32);
19170 goto decode_success;
19171 }
19172 }
19173
19174 /* ----------------- (T1) UMLAL ----------------- */
19175 /* ----------------- (T1) SMLAL ----------------- */
19176 if ((INSN0(15,4) == 0xFBE // UMLAL
19177 || INSN0(15,4) == 0xFBC) // SMLAL
19178 && INSN1(7,4) == BITS4(0,0,0,0)) {
19179 UInt rN = INSN0(3,0);
19180 UInt rDlo = INSN1(15,12);
19181 UInt rDhi = INSN1(11,8);
19182 UInt rM = INSN1(3,0);
19183 if (!isBadRegT(rDlo) && !isBadRegT(rDhi) && !isBadRegT(rN)
19184 && !isBadRegT(rM) && rDhi != rDlo) {
19185 Bool isS = INSN0(15,4) == 0xFBC;
19186 IRTemp argL = newTemp(Ity_I32);
19187 IRTemp argR = newTemp(Ity_I32);
19188 IRTemp old = newTemp(Ity_I64);
19189 IRTemp res = newTemp(Ity_I64);
19190 IRTemp resHi = newTemp(Ity_I32);
19191 IRTemp resLo = newTemp(Ity_I32);
19192 IROp mulOp = isS ? Iop_MullS32 : Iop_MullU32;
19193 assign( argL, getIRegT(rM));
19194 assign( argR, getIRegT(rN));
19195 assign( old, binop(Iop_32HLto64, getIRegT(rDhi), getIRegT(rDlo)) );
19196 assign( res, binop(Iop_Add64,
19197 mkexpr(old),
19198 binop(mulOp, mkexpr(argL), mkexpr(argR))) );
19199 assign( resHi, unop(Iop_64HIto32, mkexpr(res)) );
19200 assign( resLo, unop(Iop_64to32, mkexpr(res)) );
19201 putIRegT( rDhi, mkexpr(resHi), condT );
19202 putIRegT( rDlo, mkexpr(resLo), condT );
19203 DIP("%cmlal r%u, r%u, r%u, r%u\n",
19204 isS ? 's' : 'u', rDlo, rDhi, rN, rM);
19205 goto decode_success;
19206 }
19207 }
19208
sewardjabf39452012-12-12 00:16:41 +000019209 /* ------------------ (T1) UMAAL ------------------ */
19210 if (INSN0(15,4) == 0xFBE && INSN1(7,4) == BITS4(0,1,1,0)) {
19211 UInt rN = INSN0(3,0);
19212 UInt rDlo = INSN1(15,12);
19213 UInt rDhi = INSN1(11,8);
19214 UInt rM = INSN1(3,0);
19215 if (!isBadRegT(rDlo) && !isBadRegT(rDhi) && !isBadRegT(rN)
19216 && !isBadRegT(rM) && rDhi != rDlo) {
19217 IRTemp argN = newTemp(Ity_I32);
19218 IRTemp argM = newTemp(Ity_I32);
19219 IRTemp argDhi = newTemp(Ity_I32);
19220 IRTemp argDlo = newTemp(Ity_I32);
19221 IRTemp res = newTemp(Ity_I64);
19222 IRTemp resHi = newTemp(Ity_I32);
19223 IRTemp resLo = newTemp(Ity_I32);
19224 assign( argN, getIRegT(rN) );
19225 assign( argM, getIRegT(rM) );
19226 assign( argDhi, getIRegT(rDhi) );
19227 assign( argDlo, getIRegT(rDlo) );
19228 assign( res,
19229 binop(Iop_Add64,
19230 binop(Iop_Add64,
19231 binop(Iop_MullU32, mkexpr(argN), mkexpr(argM)),
19232 unop(Iop_32Uto64, mkexpr(argDhi))),
19233 unop(Iop_32Uto64, mkexpr(argDlo))) );
19234 assign( resHi, unop(Iop_64HIto32, mkexpr(res)) );
19235 assign( resLo, unop(Iop_64to32, mkexpr(res)) );
19236 putIRegT( rDhi, mkexpr(resHi), condT );
19237 putIRegT( rDlo, mkexpr(resLo), condT );
19238 DIP("umaal r%u, r%u, r%u, r%u\n", rDlo, rDhi, rN, rM);
19239 goto decode_success;
19240 }
19241 }
19242
sewardjccff5f42013-04-23 08:56:43 +000019243 /* ------------------- (T1) SMMUL{R} ------------------ */
19244 if (INSN0(15,7) == BITS9(1,1,1,1,1,0,1,1,0)
19245 && INSN0(6,4) == BITS3(1,0,1)
19246 && INSN1(15,12) == BITS4(1,1,1,1)
19247 && INSN1(7,5) == BITS3(0,0,0)) {
19248 UInt bitR = INSN1(4,4);
19249 UInt rD = INSN1(11,8);
19250 UInt rM = INSN1(3,0);
19251 UInt rN = INSN0(3,0);
19252 if (!isBadRegT(rD) && !isBadRegT(rN) && !isBadRegT(rM)) {
19253 IRExpr* res
19254 = unop(Iop_64HIto32,
19255 binop(Iop_Add64,
19256 binop(Iop_MullS32, getIRegT(rN), getIRegT(rM)),
19257 mkU64(bitR ? 0x80000000ULL : 0ULL)));
19258 putIRegT(rD, res, condT);
19259 DIP("smmul%s r%u, r%u, r%u\n",
19260 bitR ? "r" : "", rD, rN, rM);
19261 goto decode_success;
19262 }
19263 }
19264
19265 /* ------------------- (T1) SMMLA{R} ------------------ */
19266 if (INSN0(15,7) == BITS9(1,1,1,1,1,0,1,1,0)
19267 && INSN0(6,4) == BITS3(1,0,1)
19268 && INSN1(7,5) == BITS3(0,0,0)) {
19269 UInt bitR = INSN1(4,4);
19270 UInt rA = INSN1(15,12);
19271 UInt rD = INSN1(11,8);
19272 UInt rM = INSN1(3,0);
19273 UInt rN = INSN0(3,0);
19274 if (!isBadRegT(rD) && !isBadRegT(rN) && !isBadRegT(rM) && (rA != 13)) {
19275 IRExpr* res
19276 = unop(Iop_64HIto32,
19277 binop(Iop_Add64,
19278 binop(Iop_Add64,
19279 binop(Iop_32HLto64, getIRegT(rA), mkU32(0)),
19280 binop(Iop_MullS32, getIRegT(rN), getIRegT(rM))),
19281 mkU64(bitR ? 0x80000000ULL : 0ULL)));
19282 putIRegT(rD, res, condT);
19283 DIP("smmla%s r%u, r%u, r%u, r%u\n",
19284 bitR ? "r" : "", rD, rN, rM, rA);
19285 goto decode_success;
19286 }
19287 }
19288
sewardjd2664472010-08-22 12:44:20 +000019289 /* ------------------ (T2) ADR ------------------ */
19290 if ((INSN0(15,0) == 0xF2AF || INSN0(15,0) == 0xF6AF)
19291 && INSN1(15,15) == 0) {
19292 /* rD = align4(PC) - imm32 */
19293 UInt rD = INSN1(11,8);
19294 if (!isBadRegT(rD)) {
19295 UInt imm32 = (INSN0(10,10) << 11)
19296 | (INSN1(14,12) << 8) | INSN1(7,0);
19297 putIRegT(rD, binop(Iop_Sub32,
sewardjdf86f162010-08-22 18:47:30 +000019298 binop(Iop_And32, getIRegT(15), mkU32(~3U)),
sewardjd2664472010-08-22 12:44:20 +000019299 mkU32(imm32)),
19300 condT);
19301 DIP("sub r%u, pc, #%u\n", rD, imm32);
19302 goto decode_success;
19303 }
19304 }
19305
19306 /* ------------------- (T1) BFI ------------------- */
19307 /* ------------------- (T1) BFC ------------------- */
19308 if (INSN0(15,4) == 0xF36 && INSN1(15,15) == 0 && INSN1(5,5) == 0) {
19309 UInt rD = INSN1(11,8);
19310 UInt rN = INSN0(3,0);
19311 UInt msb = INSN1(4,0);
19312 UInt lsb = (INSN1(14,12) << 2) | INSN1(7,6);
19313 if (isBadRegT(rD) || rN == 13 || msb < lsb) {
19314 /* undecodable; fall through */
19315 } else {
19316 IRTemp src = newTemp(Ity_I32);
19317 IRTemp olddst = newTemp(Ity_I32);
19318 IRTemp newdst = newTemp(Ity_I32);
19319 UInt mask = 1 << (msb - lsb);
19320 mask = (mask - 1) + mask;
19321 vassert(mask != 0); // guaranteed by "msb < lsb" check above
19322 mask <<= lsb;
19323
19324 assign(src, rN == 15 ? mkU32(0) : getIRegT(rN));
19325 assign(olddst, getIRegT(rD));
19326 assign(newdst,
19327 binop(Iop_Or32,
19328 binop(Iop_And32,
19329 binop(Iop_Shl32, mkexpr(src), mkU8(lsb)),
19330 mkU32(mask)),
19331 binop(Iop_And32,
19332 mkexpr(olddst),
19333 mkU32(~mask)))
19334 );
19335
19336 putIRegT(rD, mkexpr(newdst), condT);
19337
19338 if (rN == 15) {
19339 DIP("bfc r%u, #%u, #%u\n",
19340 rD, lsb, msb-lsb+1);
19341 } else {
19342 DIP("bfi r%u, r%u, #%u, #%u\n",
19343 rD, rN, lsb, msb-lsb+1);
19344 }
19345 goto decode_success;
19346 }
19347 }
19348
sewardjd2664472010-08-22 12:44:20 +000019349 /* ------------------- (T1) SXTAH ------------------- */
19350 /* ------------------- (T1) UXTAH ------------------- */
19351 if ((INSN0(15,4) == 0xFA1 // UXTAH
19352 || INSN0(15,4) == 0xFA0) // SXTAH
19353 && INSN1(15,12) == BITS4(1,1,1,1)
19354 && INSN1(7,6) == BITS2(1,0)) {
19355 Bool isU = INSN0(15,4) == 0xFA1;
19356 UInt rN = INSN0(3,0);
19357 UInt rD = INSN1(11,8);
19358 UInt rM = INSN1(3,0);
19359 UInt rot = INSN1(5,4);
19360 if (!isBadRegT(rD) && !isBadRegT(rN) && !isBadRegT(rM)) {
19361 IRTemp srcL = newTemp(Ity_I32);
19362 IRTemp srcR = newTemp(Ity_I32);
19363 IRTemp res = newTemp(Ity_I32);
19364 assign(srcR, getIRegT(rM));
19365 assign(srcL, getIRegT(rN));
19366 assign(res, binop(Iop_Add32,
19367 mkexpr(srcL),
19368 unop(isU ? Iop_16Uto32 : Iop_16Sto32,
19369 unop(Iop_32to16,
19370 genROR32(srcR, 8 * rot)))));
19371 putIRegT(rD, mkexpr(res), condT);
19372 DIP("%cxtah r%u, r%u, r%u, ror #%u\n",
19373 isU ? 'u' : 's', rD, rN, rM, rot);
19374 goto decode_success;
19375 }
19376 }
19377
19378 /* ------------------- (T1) SXTAB ------------------- */
19379 /* ------------------- (T1) UXTAB ------------------- */
19380 if ((INSN0(15,4) == 0xFA5 // UXTAB
19381 || INSN0(15,4) == 0xFA4) // SXTAB
19382 && INSN1(15,12) == BITS4(1,1,1,1)
19383 && INSN1(7,6) == BITS2(1,0)) {
19384 Bool isU = INSN0(15,4) == 0xFA5;
19385 UInt rN = INSN0(3,0);
19386 UInt rD = INSN1(11,8);
19387 UInt rM = INSN1(3,0);
19388 UInt rot = INSN1(5,4);
19389 if (!isBadRegT(rD) && !isBadRegT(rN) && !isBadRegT(rM)) {
19390 IRTemp srcL = newTemp(Ity_I32);
19391 IRTemp srcR = newTemp(Ity_I32);
19392 IRTemp res = newTemp(Ity_I32);
19393 assign(srcR, getIRegT(rM));
19394 assign(srcL, getIRegT(rN));
19395 assign(res, binop(Iop_Add32,
19396 mkexpr(srcL),
19397 unop(isU ? Iop_8Uto32 : Iop_8Sto32,
19398 unop(Iop_32to8,
19399 genROR32(srcR, 8 * rot)))));
19400 putIRegT(rD, mkexpr(res), condT);
19401 DIP("%cxtab r%u, r%u, r%u, ror #%u\n",
19402 isU ? 'u' : 's', rD, rN, rM, rot);
19403 goto decode_success;
19404 }
19405 }
19406
19407 /* ------------------- (T1) CLZ ------------------- */
19408 if (INSN0(15,4) == 0xFAB
19409 && INSN1(15,12) == BITS4(1,1,1,1)
19410 && INSN1(7,4) == BITS4(1,0,0,0)) {
19411 UInt rM1 = INSN0(3,0);
sewardj677e5af2010-09-02 21:02:47 +000019412 UInt rD = INSN1(11,8);
sewardjd2664472010-08-22 12:44:20 +000019413 UInt rM2 = INSN1(3,0);
19414 if (!isBadRegT(rD) && !isBadRegT(rM1) && rM1 == rM2) {
19415 IRTemp arg = newTemp(Ity_I32);
19416 IRTemp res = newTemp(Ity_I32);
19417 assign(arg, getIRegT(rM1));
florian99dd03e2013-01-29 03:56:06 +000019418 assign(res, IRExpr_ITE(
sewardj009230b2013-01-26 11:47:55 +000019419 binop(Iop_CmpEQ32, mkexpr(arg), mkU32(0)),
florian99dd03e2013-01-29 03:56:06 +000019420 mkU32(32),
19421 unop(Iop_Clz32, mkexpr(arg))
sewardjd2664472010-08-22 12:44:20 +000019422 ));
19423 putIRegT(rD, mkexpr(res), condT);
19424 DIP("clz r%u, r%u\n", rD, rM1);
19425 goto decode_success;
19426 }
19427 }
19428
sewardj677e5af2010-09-02 21:02:47 +000019429 /* ------------------- (T1) RBIT ------------------- */
19430 if (INSN0(15,4) == 0xFA9
19431 && INSN1(15,12) == BITS4(1,1,1,1)
19432 && INSN1(7,4) == BITS4(1,0,1,0)) {
19433 UInt rM1 = INSN0(3,0);
19434 UInt rD = INSN1(11,8);
19435 UInt rM2 = INSN1(3,0);
19436 if (!isBadRegT(rD) && !isBadRegT(rM1) && rM1 == rM2) {
19437 IRTemp arg = newTemp(Ity_I32);
19438 assign(arg, getIRegT(rM1));
19439 IRTemp res = gen_BITREV(arg);
19440 putIRegT(rD, mkexpr(res), condT);
19441 DIP("rbit r%u, r%u\n", rD, rM1);
19442 goto decode_success;
19443 }
19444 }
19445
sewardj27312d32010-09-26 00:48:41 +000019446 /* ------------------- (T2) REV ------------------- */
19447 /* ------------------- (T2) REV16 ------------------- */
19448 if (INSN0(15,4) == 0xFA9
19449 && INSN1(15,12) == BITS4(1,1,1,1)
19450 && ( INSN1(7,4) == BITS4(1,0,0,0) // REV
19451 || INSN1(7,4) == BITS4(1,0,0,1))) { // REV16
19452 UInt rM1 = INSN0(3,0);
19453 UInt rD = INSN1(11,8);
19454 UInt rM2 = INSN1(3,0);
19455 Bool isREV = INSN1(7,4) == BITS4(1,0,0,0);
19456 if (!isBadRegT(rD) && !isBadRegT(rM1) && rM1 == rM2) {
19457 IRTemp arg = newTemp(Ity_I32);
19458 assign(arg, getIRegT(rM1));
19459 IRTemp res = isREV ? gen_REV(arg) : gen_REV16(arg);
19460 putIRegT(rD, mkexpr(res), condT);
19461 DIP("rev%s r%u, r%u\n", isREV ? "" : "16", rD, rM1);
19462 goto decode_success;
19463 }
19464 }
19465
sewardjd2664472010-08-22 12:44:20 +000019466 /* -------------- (T1) MSR apsr, reg -------------- */
19467 if (INSN0(15,4) == 0xF38
19468 && INSN1(15,12) == BITS4(1,0,0,0) && INSN1(9,0) == 0x000) {
19469 UInt rN = INSN0(3,0);
19470 UInt write_ge = INSN1(10,10);
19471 UInt write_nzcvq = INSN1(11,11);
sewardj1f139f52010-08-29 12:33:02 +000019472 if (!isBadRegT(rN) && (write_nzcvq || write_ge)) {
sewardjd2664472010-08-22 12:44:20 +000019473 IRTemp rNt = newTemp(Ity_I32);
19474 assign(rNt, getIRegT(rN));
sewardj1f139f52010-08-29 12:33:02 +000019475 desynthesise_APSR( write_nzcvq, write_ge, rNt, condT );
19476 DIP("msr cpsr_%s%s, r%u\n",
19477 write_nzcvq ? "f" : "", write_ge ? "g" : "", rN);
sewardjd2664472010-08-22 12:44:20 +000019478 goto decode_success;
19479 }
19480 }
19481
19482 /* -------------- (T1) MRS reg, apsr -------------- */
19483 if (INSN0(15,0) == 0xF3EF
19484 && INSN1(15,12) == BITS4(1,0,0,0) && INSN1(7,0) == 0x00) {
19485 UInt rD = INSN1(11,8);
19486 if (!isBadRegT(rD)) {
sewardj1f139f52010-08-29 12:33:02 +000019487 IRTemp apsr = synthesise_APSR();
19488 putIRegT( rD, mkexpr(apsr), condT );
sewardjd2664472010-08-22 12:44:20 +000019489 DIP("mrs r%u, cpsr\n", rD);
19490 goto decode_success;
19491 }
19492 }
19493
sewardje1a93962010-09-24 23:35:59 +000019494 /* ----------------- (T1) LDREX ----------------- */
19495 if (INSN0(15,4) == 0xE85 && INSN1(11,8) == BITS4(1,1,1,1)) {
19496 UInt rN = INSN0(3,0);
19497 UInt rT = INSN1(15,12);
19498 UInt imm8 = INSN1(7,0);
19499 if (!isBadRegT(rT) && rN != 15) {
19500 IRTemp res;
19501 // go uncond
19502 mk_skip_over_T32_if_cond_is_false( condT );
19503 // now uncond
19504 res = newTemp(Ity_I32);
19505 stmt( IRStmt_LLSC(Iend_LE,
19506 res,
19507 binop(Iop_Add32, getIRegT(rN), mkU32(imm8 * 4)),
19508 NULL/*this is a load*/ ));
19509 putIRegT(rT, mkexpr(res), IRTemp_INVALID);
19510 DIP("ldrex r%u, [r%u, #+%u]\n", rT, rN, imm8 * 4);
19511 goto decode_success;
19512 }
19513 }
19514
sewardjff7f5b72011-07-11 11:43:38 +000019515 /* --------------- (T1) LDREX{B,H} --------------- */
19516 if (INSN0(15,4) == 0xE8D
19517 && (INSN1(11,0) == 0xF4F || INSN1(11,0) == 0xF5F)) {
19518 UInt rN = INSN0(3,0);
19519 UInt rT = INSN1(15,12);
19520 Bool isH = INSN1(11,0) == 0xF5F;
19521 if (!isBadRegT(rT) && rN != 15) {
19522 IRTemp res;
19523 // go uncond
19524 mk_skip_over_T32_if_cond_is_false( condT );
19525 // now uncond
19526 res = newTemp(isH ? Ity_I16 : Ity_I8);
19527 stmt( IRStmt_LLSC(Iend_LE, res, getIRegT(rN),
19528 NULL/*this is a load*/ ));
19529 putIRegT(rT, unop(isH ? Iop_16Uto32 : Iop_8Uto32, mkexpr(res)),
19530 IRTemp_INVALID);
19531 DIP("ldrex%c r%u, [r%u]\n", isH ? 'h' : 'b', rT, rN);
19532 goto decode_success;
19533 }
19534 }
19535
19536 /* --------------- (T1) LDREXD --------------- */
19537 if (INSN0(15,4) == 0xE8D && INSN1(7,0) == 0x7F) {
19538 UInt rN = INSN0(3,0);
19539 UInt rT = INSN1(15,12);
19540 UInt rT2 = INSN1(11,8);
19541 if (!isBadRegT(rT) && !isBadRegT(rT2) && rT != rT2 && rN != 15) {
19542 IRTemp res;
19543 // go uncond
19544 mk_skip_over_T32_if_cond_is_false( condT );
19545 // now uncond
19546 res = newTemp(Ity_I64);
19547 // FIXME: assumes little-endian guest
19548 stmt( IRStmt_LLSC(Iend_LE, res, getIRegT(rN),
19549 NULL/*this is a load*/ ));
19550 // FIXME: assumes little-endian guest
19551 putIRegT(rT, unop(Iop_64to32, mkexpr(res)), IRTemp_INVALID);
19552 putIRegT(rT2, unop(Iop_64HIto32, mkexpr(res)), IRTemp_INVALID);
19553 DIP("ldrexd r%u, r%u, [r%u]\n", rT, rT2, rN);
19554 goto decode_success;
19555 }
19556 }
19557
sewardje1a93962010-09-24 23:35:59 +000019558 /* ----------------- (T1) STREX ----------------- */
19559 if (INSN0(15,4) == 0xE84) {
19560 UInt rN = INSN0(3,0);
19561 UInt rT = INSN1(15,12);
19562 UInt rD = INSN1(11,8);
19563 UInt imm8 = INSN1(7,0);
19564 if (!isBadRegT(rD) && !isBadRegT(rT) && rN != 15
19565 && rD != rN && rD != rT) {
19566 IRTemp resSC1, resSC32;
sewardje1a93962010-09-24 23:35:59 +000019567 // go uncond
19568 mk_skip_over_T32_if_cond_is_false( condT );
19569 // now uncond
sewardje1a93962010-09-24 23:35:59 +000019570 /* Ok, now we're unconditional. Do the store. */
19571 resSC1 = newTemp(Ity_I1);
19572 stmt( IRStmt_LLSC(Iend_LE,
19573 resSC1,
19574 binop(Iop_Add32, getIRegT(rN), mkU32(imm8 * 4)),
19575 getIRegT(rT)) );
sewardje1a93962010-09-24 23:35:59 +000019576 /* Set rD to 1 on failure, 0 on success. Currently we have
19577 resSC1 == 0 on failure, 1 on success. */
19578 resSC32 = newTemp(Ity_I32);
19579 assign(resSC32,
19580 unop(Iop_1Uto32, unop(Iop_Not1, mkexpr(resSC1))));
sewardje1a93962010-09-24 23:35:59 +000019581 putIRegT(rD, mkexpr(resSC32), IRTemp_INVALID);
19582 DIP("strex r%u, r%u, [r%u, #+%u]\n", rD, rT, rN, imm8 * 4);
19583 goto decode_success;
19584 }
19585 }
19586
sewardjff7f5b72011-07-11 11:43:38 +000019587 /* --------------- (T1) STREX{B,H} --------------- */
19588 if (INSN0(15,4) == 0xE8C
19589 && (INSN1(11,4) == 0xF4 || INSN1(11,4) == 0xF5)) {
19590 UInt rN = INSN0(3,0);
19591 UInt rT = INSN1(15,12);
19592 UInt rD = INSN1(3,0);
19593 Bool isH = INSN1(11,4) == 0xF5;
19594 if (!isBadRegT(rD) && !isBadRegT(rT) && rN != 15
19595 && rD != rN && rD != rT) {
19596 IRTemp resSC1, resSC32;
19597 // go uncond
19598 mk_skip_over_T32_if_cond_is_false( condT );
19599 // now uncond
19600 /* Ok, now we're unconditional. Do the store. */
19601 resSC1 = newTemp(Ity_I1);
19602 stmt( IRStmt_LLSC(Iend_LE, resSC1, getIRegT(rN),
19603 unop(isH ? Iop_32to16 : Iop_32to8,
19604 getIRegT(rT))) );
19605 /* Set rD to 1 on failure, 0 on success. Currently we have
19606 resSC1 == 0 on failure, 1 on success. */
19607 resSC32 = newTemp(Ity_I32);
19608 assign(resSC32,
19609 unop(Iop_1Uto32, unop(Iop_Not1, mkexpr(resSC1))));
19610 putIRegT(rD, mkexpr(resSC32), IRTemp_INVALID);
19611 DIP("strex%c r%u, r%u, [r%u]\n", isH ? 'h' : 'b', rD, rT, rN);
19612 goto decode_success;
19613 }
19614 }
19615
19616 /* ---------------- (T1) STREXD ---------------- */
19617 if (INSN0(15,4) == 0xE8C && INSN1(7,4) == BITS4(0,1,1,1)) {
19618 UInt rN = INSN0(3,0);
19619 UInt rT = INSN1(15,12);
19620 UInt rT2 = INSN1(11,8);
19621 UInt rD = INSN1(3,0);
19622 if (!isBadRegT(rD) && !isBadRegT(rT) && !isBadRegT(rT2)
19623 && rN != 15 && rD != rN && rD != rT && rD != rT) {
19624 IRTemp resSC1, resSC32, data;
19625 // go uncond
19626 mk_skip_over_T32_if_cond_is_false( condT );
19627 // now uncond
19628 /* Ok, now we're unconditional. Do the store. */
19629 resSC1 = newTemp(Ity_I1);
19630 data = newTemp(Ity_I64);
19631 // FIXME: assumes little-endian guest
19632 assign(data, binop(Iop_32HLto64, getIRegT(rT2), getIRegT(rT)));
19633 // FIXME: assumes little-endian guest
19634 stmt( IRStmt_LLSC(Iend_LE, resSC1, getIRegT(rN), mkexpr(data)));
19635 /* Set rD to 1 on failure, 0 on success. Currently we have
19636 resSC1 == 0 on failure, 1 on success. */
19637 resSC32 = newTemp(Ity_I32);
19638 assign(resSC32,
19639 unop(Iop_1Uto32, unop(Iop_Not1, mkexpr(resSC1))));
19640 putIRegT(rD, mkexpr(resSC32), IRTemp_INVALID);
19641 DIP("strexd r%u, r%u, r%u, [r%u]\n", rD, rT, rT2, rN);
19642 goto decode_success;
19643 }
19644 }
sewardjccff5f42013-04-23 08:56:43 +000019645
sewardj4aec3762010-09-24 23:48:29 +000019646 /* -------------- v7 barrier insns -------------- */
sewardj5bb6ca22011-05-08 09:09:12 +000019647 if (INSN0(15,0) == 0xF3BF && (INSN1(15,0) & 0xFF00) == 0x8F00) {
sewardj6d615ba2011-09-26 16:19:43 +000019648 /* FIXME: should this be unconditional? */
sewardj646bc002010-10-11 18:57:10 +000019649 /* XXX this isn't really right, is it? The generated IR does
19650 them unconditionally. I guess it doesn't matter since it
19651 doesn't do any harm to do them even when the guarding
19652 condition is false -- it's just a performance loss. */
sewardj5bb6ca22011-05-08 09:09:12 +000019653 switch (INSN1(7,0)) {
19654 case 0x4F: /* DSB sy */
19655 case 0x4E: /* DSB st */
19656 case 0x4B: /* DSB ish */
19657 case 0x4A: /* DSB ishst */
19658 case 0x47: /* DSB nsh */
19659 case 0x46: /* DSB nshst */
19660 case 0x43: /* DSB osh */
19661 case 0x42: /* DSB oshst */
sewardj4aec3762010-09-24 23:48:29 +000019662 stmt( IRStmt_MBE(Imbe_Fence) );
19663 DIP("DSB\n");
19664 goto decode_success;
sewardj5bb6ca22011-05-08 09:09:12 +000019665 case 0x5F: /* DMB sy */
19666 case 0x5E: /* DMB st */
19667 case 0x5B: /* DMB ish */
19668 case 0x5A: /* DMB ishst */
19669 case 0x57: /* DMB nsh */
19670 case 0x56: /* DMB nshst */
19671 case 0x53: /* DMB osh */
19672 case 0x52: /* DMB oshst */
sewardj4aec3762010-09-24 23:48:29 +000019673 stmt( IRStmt_MBE(Imbe_Fence) );
19674 DIP("DMB\n");
19675 goto decode_success;
sewardj5bb6ca22011-05-08 09:09:12 +000019676 case 0x6F: /* ISB */
sewardj4aec3762010-09-24 23:48:29 +000019677 stmt( IRStmt_MBE(Imbe_Fence) );
19678 DIP("ISB\n");
19679 goto decode_success;
19680 default:
19681 break;
19682 }
19683 }
19684
sewardj7f5a8412011-07-21 06:17:21 +000019685 /* ---------------------- PLD{,W} ---------------------- */
19686 if ((INSN0(15,4) & 0xFFD) == 0xF89 && INSN1(15,12) == 0xF) {
sewardj6d615ba2011-09-26 16:19:43 +000019687 /* FIXME: should this be unconditional? */
sewardj7f5a8412011-07-21 06:17:21 +000019688 /* PLD/PLDW immediate, encoding T1 */
19689 UInt rN = INSN0(3,0);
19690 UInt bW = INSN0(5,5);
19691 UInt imm12 = INSN1(11,0);
19692 DIP("pld%s [r%u, #%u]\n", bW ? "w" : "", rN, imm12);
19693 goto decode_success;
19694 }
19695
19696 if ((INSN0(15,4) & 0xFFD) == 0xF81 && INSN1(15,8) == 0xFC) {
sewardj6d615ba2011-09-26 16:19:43 +000019697 /* FIXME: should this be unconditional? */
sewardj7f5a8412011-07-21 06:17:21 +000019698 /* PLD/PLDW immediate, encoding T2 */
19699 UInt rN = INSN0(3,0);
19700 UInt bW = INSN0(5,5);
19701 UInt imm8 = INSN1(7,0);
19702 DIP("pld%s [r%u, #-%u]\n", bW ? "w" : "", rN, imm8);
19703 goto decode_success;
19704 }
19705
19706 if ((INSN0(15,4) & 0xFFD) == 0xF81 && INSN1(15,6) == 0x3C0) {
sewardj6d615ba2011-09-26 16:19:43 +000019707 /* FIXME: should this be unconditional? */
sewardj7f5a8412011-07-21 06:17:21 +000019708 /* PLD/PLDW register, encoding T1 */
19709 UInt rN = INSN0(3,0);
19710 UInt rM = INSN1(3,0);
19711 UInt bW = INSN0(5,5);
19712 UInt imm2 = INSN1(5,4);
19713 if (!isBadRegT(rM)) {
19714 DIP("pld%s [r%u, r%u, lsl %d]\n", bW ? "w" : "", rN, rM, imm2);
19715 goto decode_success;
19716 }
19717 /* fall through */
19718 }
19719
sewardjed75a682011-02-09 14:21:45 +000019720 /* -------------- read CP15 TPIDRURO register ------------- */
19721 /* mrc p15, 0, r0, c13, c0, 3 up to
19722 mrc p15, 0, r14, c13, c0, 3
19723 */
19724 /* I don't know whether this is really v7-only. But anyway, we
19725 have to support it since arm-linux uses TPIDRURO as a thread
19726 state register. */
sewardjed75a682011-02-09 14:21:45 +000019727 if ((INSN0(15,0) == 0xEE1D) && (INSN1(11,0) == 0x0F70)) {
sewardj6d615ba2011-09-26 16:19:43 +000019728 /* FIXME: should this be unconditional? */
sewardjed75a682011-02-09 14:21:45 +000019729 UInt rD = INSN1(15,12);
19730 if (!isBadRegT(rD)) {
19731 putIRegT(rD, IRExpr_Get(OFFB_TPIDRURO, Ity_I32), IRTemp_INVALID);
19732 DIP("mrc p15,0, r%u, c13, c0, 3\n", rD);
19733 goto decode_success;
19734 }
19735 /* fall through */
19736 }
19737
sewardj6d615ba2011-09-26 16:19:43 +000019738 /* ------------------- CLREX ------------------ */
19739 if (INSN0(15,0) == 0xF3BF && INSN1(15,0) == 0x8F2F) {
19740 /* AFAICS, this simply cancels a (all?) reservations made by a
19741 (any?) preceding LDREX(es). Arrange to hand it through to
19742 the back end. */
19743 mk_skip_over_T32_if_cond_is_false( condT );
19744 stmt( IRStmt_MBE(Imbe_CancelReservation) );
19745 DIP("clrex\n");
19746 goto decode_success;
19747 }
19748
sewardj646bc002010-10-11 18:57:10 +000019749 /* ------------------- NOP ------------------ */
19750 if (INSN0(15,0) == 0xF3AF && INSN1(15,0) == 0x8000) {
19751 DIP("nop\n");
19752 goto decode_success;
19753 }
19754
sewardj7af76872013-04-11 10:56:42 +000019755 /* -------------- (T1) LDRT reg+#imm8 -------------- */
19756 /* Load Register Unprivileged:
19757 ldrt Rt, [Rn, #imm8]
19758 */
19759 if (INSN0(15,6) == BITS10(1,1,1,1,1,0,0,0,0,1) && INSN0(5,4) == BITS2(0,1)
19760 && INSN1(11,8) == BITS4(1,1,1,0)) {
19761 UInt rT = INSN1(15,12);
19762 UInt rN = INSN0(3,0);
19763 UInt imm8 = INSN1(7,0);
19764 Bool valid = True;
19765 if (rN == 15 || isBadRegT(rT)) valid = False;
19766 if (valid) {
19767 put_ITSTATE(old_itstate);
19768 IRExpr* ea = binop(Iop_Add32, getIRegT(rN), mkU32(imm8));
19769 IRTemp newRt = newTemp(Ity_I32);
19770 loadGuardedLE( newRt, ILGop_Ident32, ea, llGetIReg(rT), condT );
19771 putIRegT(rT, mkexpr(newRt), IRTemp_INVALID);
19772 put_ITSTATE(new_itstate);
19773 DIP("ldrt r%u, [r%u, #%u]\n", rT, rN, imm8);
19774 goto decode_success;
19775 }
19776 }
19777
sewardj80f674a2013-05-13 10:28:59 +000019778 /* -------------- (T1) STRT reg+#imm8 -------------- */
19779 /* Store Register Unprivileged:
19780 strt Rt, [Rn, #imm8]
19781 */
19782 if (INSN0(15,6) == BITS10(1,1,1,1,1,0,0,0,0,1) && INSN0(5,4) == BITS2(0,0)
19783 && INSN1(11,8) == BITS4(1,1,1,0)) {
19784 UInt rT = INSN1(15,12);
19785 UInt rN = INSN0(3,0);
19786 UInt imm8 = INSN1(7,0);
19787 Bool valid = True;
19788 if (rN == 15 || isBadRegT(rT)) valid = False;
19789 if (valid) {
19790 put_ITSTATE(old_itstate);
19791 IRExpr* address = binop(Iop_Add32, getIRegT(rN), mkU32(imm8));
19792 storeGuardedLE( address, llGetIReg(rT), condT );
19793 put_ITSTATE(new_itstate);
19794 DIP("strt r%u, [r%u, #%u]\n", rT, rN, imm8);
19795 goto decode_success;
19796 }
19797 }
19798
19799
sewardjd2664472010-08-22 12:44:20 +000019800 /* ----------------------------------------------------------- */
19801 /* -- VFP (CP 10, CP 11) instructions (in Thumb mode) -- */
19802 /* ----------------------------------------------------------- */
19803
19804 if (INSN0(15,12) == BITS4(1,1,1,0)) {
19805 UInt insn28 = (INSN0(11,0) << 16) | INSN1(15,0);
19806 Bool ok_vfp = decode_CP10_CP11_instruction (
19807 &dres, insn28, condT, ARMCondAL/*bogus*/,
19808 True/*isT*/
19809 );
19810 if (ok_vfp)
19811 goto decode_success;
19812 }
19813
19814 /* ----------------------------------------------------------- */
19815 /* -- NEON instructions (in Thumb mode) -- */
19816 /* ----------------------------------------------------------- */
19817
sewardj1fce8de2010-09-09 07:27:24 +000019818 if (archinfo->hwcaps & VEX_HWCAPS_ARM_NEON) {
19819 UInt insn32 = (INSN0(15,0) << 16) | INSN1(15,0);
19820 Bool ok_neon = decode_NEON_instruction(
19821 &dres, insn32, condT, True/*isT*/
19822 );
19823 if (ok_neon)
19824 goto decode_success;
sewardjd2664472010-08-22 12:44:20 +000019825 }
19826
19827 /* ----------------------------------------------------------- */
sewardj1f139f52010-08-29 12:33:02 +000019828 /* -- v6 media instructions (in Thumb mode) -- */
19829 /* ----------------------------------------------------------- */
19830
19831 { UInt insn32 = (INSN0(15,0) << 16) | INSN1(15,0);
19832 Bool ok_v6m = decode_V6MEDIA_instruction(
19833 &dres, insn32, condT, ARMCondAL/*bogus*/,
19834 True/*isT*/
19835 );
19836 if (ok_v6m)
19837 goto decode_success;
19838 }
19839
19840 /* ----------------------------------------------------------- */
sewardjd2664472010-08-22 12:44:20 +000019841 /* -- Undecodable -- */
19842 /* ----------------------------------------------------------- */
19843
19844 goto decode_failure;
19845 /*NOTREACHED*/
19846
19847 decode_failure:
19848 /* All decode failures end up here. */
sewardj442e51a2012-12-06 18:08:04 +000019849 if (sigill_diag)
19850 vex_printf("disInstr(thumb): unhandled instruction: "
19851 "0x%04x 0x%04x\n", (UInt)insn0, (UInt)insn1);
sewardjd2664472010-08-22 12:44:20 +000019852
19853 /* Back up ITSTATE to the initial value for this instruction.
19854 If we don't do that, any subsequent restart of the instruction
19855 will restart with the wrong value. */
sewardj5276ff52012-07-14 14:21:56 +000019856 if (old_itstate != IRTemp_INVALID)
19857 put_ITSTATE(old_itstate);
19858
sewardjd2664472010-08-22 12:44:20 +000019859 /* Tell the dispatcher that this insn cannot be decoded, and so has
19860 not been executed, and (is currently) the next to be executed.
19861 R15 should be up-to-date since it made so at the start of each
19862 insn, but nevertheless be paranoid and update it again right
19863 now. */
19864 vassert(0 == (guest_R15_curr_instr_notENC & 1));
19865 llPutIReg( 15, mkU32(guest_R15_curr_instr_notENC | 1) );
sewardjc6f970f2012-04-02 21:54:49 +000019866 dres.whatNext = Dis_StopHere;
19867 dres.jk_StopHere = Ijk_NoDecode;
19868 dres.len = 0;
sewardjd2664472010-08-22 12:44:20 +000019869 return dres;
19870
19871 decode_success:
19872 /* All decode successes end up here. */
sewardjc6f970f2012-04-02 21:54:49 +000019873 vassert(dres.len == 4 || dres.len == 2 || dres.len == 20);
19874 switch (dres.whatNext) {
19875 case Dis_Continue:
19876 llPutIReg(15, mkU32(dres.len + (guest_R15_curr_instr_notENC | 1)));
19877 break;
19878 case Dis_ResteerU:
19879 case Dis_ResteerC:
19880 llPutIReg(15, mkU32(dres.continueAt));
19881 break;
19882 case Dis_StopHere:
19883 break;
19884 default:
19885 vassert(0);
sewardjd2664472010-08-22 12:44:20 +000019886 }
sewardjc6f970f2012-04-02 21:54:49 +000019887
19888 DIP("\n");
sewardjd2664472010-08-22 12:44:20 +000019889
19890 return dres;
19891
19892# undef INSN0
19893# undef INSN1
19894}
19895
sewardjc2c87162004-11-25 13:07:02 +000019896#undef DIP
19897#undef DIS
19898
sewardj6c299f32009-12-31 18:00:12 +000019899
sewardj66c8c9b2011-07-04 16:58:40 +000019900/* Helper table for figuring out how many insns an IT insn
19901 conditionalises.
19902
19903 An ITxyz instruction of the format "1011 1111 firstcond mask"
19904 conditionalises some number of instructions, as indicated by the
19905 following table. A value of zero indicates the instruction is
19906 invalid in some way.
19907
19908 mask = 0 means this isn't an IT instruction
19909 fc = 15 (NV) means unpredictable
19910
19911 The line fc = 14 (AL) is different from the others; there are
19912 additional constraints in this case.
19913
19914 mask(0 .. 15)
19915 +--------------------------------
19916 fc(0 | 0 4 3 4 2 4 3 4 1 4 3 4 2 4 3 4
19917 .. | 0 4 3 4 2 4 3 4 1 4 3 4 2 4 3 4
19918 | 0 4 3 4 2 4 3 4 1 4 3 4 2 4 3 4
19919 | 0 4 3 4 2 4 3 4 1 4 3 4 2 4 3 4
19920 | 0 4 3 4 2 4 3 4 1 4 3 4 2 4 3 4
19921 | 0 4 3 4 2 4 3 4 1 4 3 4 2 4 3 4
19922 | 0 4 3 4 2 4 3 4 1 4 3 4 2 4 3 4
19923 | 0 4 3 4 2 4 3 4 1 4 3 4 2 4 3 4
19924 | 0 4 3 4 2 4 3 4 1 4 3 4 2 4 3 4
19925 | 0 4 3 4 2 4 3 4 1 4 3 4 2 4 3 4
19926 | 0 4 3 4 2 4 3 4 1 4 3 4 2 4 3 4
19927 | 0 4 3 4 2 4 3 4 1 4 3 4 2 4 3 4
19928 | 0 4 3 4 2 4 3 4 1 4 3 4 2 4 3 4
19929 | 0 4 3 4 2 4 3 4 1 4 3 4 2 4 3 4
19930 | 0 4 3 0 2 0 0 0 1 0 0 0 0 0 0 0
19931 15) | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
19932
19933 To be conservative with the analysis, let's rule out the mask = 0
19934 case, since that isn't an IT insn at all. But for all the other
19935 cases where the table contains zero, that means unpredictable, so
19936 let's say 4 to be conservative. Hence we have a safe value for any
19937 IT (mask,fc) pair that the CPU would actually identify as an IT
19938 instruction. The final table is
19939
19940 mask(0 .. 15)
19941 +--------------------------------
19942 fc(0 | 0 4 3 4 2 4 3 4 1 4 3 4 2 4 3 4
19943 .. | 0 4 3 4 2 4 3 4 1 4 3 4 2 4 3 4
19944 | 0 4 3 4 2 4 3 4 1 4 3 4 2 4 3 4
19945 | 0 4 3 4 2 4 3 4 1 4 3 4 2 4 3 4
19946 | 0 4 3 4 2 4 3 4 1 4 3 4 2 4 3 4
19947 | 0 4 3 4 2 4 3 4 1 4 3 4 2 4 3 4
19948 | 0 4 3 4 2 4 3 4 1 4 3 4 2 4 3 4
19949 | 0 4 3 4 2 4 3 4 1 4 3 4 2 4 3 4
19950 | 0 4 3 4 2 4 3 4 1 4 3 4 2 4 3 4
19951 | 0 4 3 4 2 4 3 4 1 4 3 4 2 4 3 4
19952 | 0 4 3 4 2 4 3 4 1 4 3 4 2 4 3 4
19953 | 0 4 3 4 2 4 3 4 1 4 3 4 2 4 3 4
19954 | 0 4 3 4 2 4 3 4 1 4 3 4 2 4 3 4
19955 | 0 4 3 4 2 4 3 4 1 4 3 4 2 4 3 4
19956 | 0 4 3 4 2 4 4 4 1 4 4 4 4 4 4 4
19957 15) | 0 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4
19958*/
19959static const UChar it_length_table[256]
19960 = { 0, 4, 3, 4, 2, 4, 3, 4, 1, 4, 3, 4, 2, 4, 3, 4,
19961 0, 4, 3, 4, 2, 4, 3, 4, 1, 4, 3, 4, 2, 4, 3, 4,
19962 0, 4, 3, 4, 2, 4, 3, 4, 1, 4, 3, 4, 2, 4, 3, 4,
19963 0, 4, 3, 4, 2, 4, 3, 4, 1, 4, 3, 4, 2, 4, 3, 4,
19964 0, 4, 3, 4, 2, 4, 3, 4, 1, 4, 3, 4, 2, 4, 3, 4,
19965 0, 4, 3, 4, 2, 4, 3, 4, 1, 4, 3, 4, 2, 4, 3, 4,
19966 0, 4, 3, 4, 2, 4, 3, 4, 1, 4, 3, 4, 2, 4, 3, 4,
19967 0, 4, 3, 4, 2, 4, 3, 4, 1, 4, 3, 4, 2, 4, 3, 4,
19968 0, 4, 3, 4, 2, 4, 3, 4, 1, 4, 3, 4, 2, 4, 3, 4,
19969 0, 4, 3, 4, 2, 4, 3, 4, 1, 4, 3, 4, 2, 4, 3, 4,
19970 0, 4, 3, 4, 2, 4, 3, 4, 1, 4, 3, 4, 2, 4, 3, 4,
19971 0, 4, 3, 4, 2, 4, 3, 4, 1, 4, 3, 4, 2, 4, 3, 4,
19972 0, 4, 3, 4, 2, 4, 3, 4, 1, 4, 3, 4, 2, 4, 3, 4,
19973 0, 4, 3, 4, 2, 4, 3, 4, 1, 4, 3, 4, 2, 4, 3, 4,
19974 0, 4, 3, 4, 2, 4, 4, 4, 1, 4, 4, 4, 4, 4, 4, 4,
19975 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4
19976 };
19977
19978
sewardj6c299f32009-12-31 18:00:12 +000019979/*------------------------------------------------------------*/
19980/*--- Top-level fn ---*/
19981/*------------------------------------------------------------*/
19982
19983/* Disassemble a single instruction into IR. The instruction
19984 is located in host memory at &guest_code[delta]. */
19985
19986DisResult disInstr_ARM ( IRSB* irsb_IN,
sewardj6c299f32009-12-31 18:00:12 +000019987 Bool (*resteerOkFn) ( void*, Addr64 ),
sewardj984d9b12010-01-15 10:53:21 +000019988 Bool resteerCisOk,
sewardj6c299f32009-12-31 18:00:12 +000019989 void* callback_opaque,
19990 UChar* guest_code_IN,
sewardjd2664472010-08-22 12:44:20 +000019991 Long delta_ENCODED,
19992 Addr64 guest_IP_ENCODED,
sewardj6c299f32009-12-31 18:00:12 +000019993 VexArch guest_arch,
19994 VexArchInfo* archinfo,
19995 VexAbiInfo* abiinfo,
sewardj442e51a2012-12-06 18:08:04 +000019996 Bool host_bigendian_IN,
19997 Bool sigill_diag_IN )
sewardj6c299f32009-12-31 18:00:12 +000019998{
19999 DisResult dres;
sewardjd2664472010-08-22 12:44:20 +000020000 Bool isThumb = (Bool)(guest_IP_ENCODED & 1);
sewardj6c299f32009-12-31 18:00:12 +000020001
20002 /* Set globals (see top of this file) */
20003 vassert(guest_arch == VexArchARM);
sewardj6c299f32009-12-31 18:00:12 +000020004
sewardjd2664472010-08-22 12:44:20 +000020005 irsb = irsb_IN;
20006 host_is_bigendian = host_bigendian_IN;
20007 __curr_is_Thumb = isThumb;
20008
20009 if (isThumb) {
20010 guest_R15_curr_instr_notENC = (Addr32)guest_IP_ENCODED - 1;
20011 } else {
20012 guest_R15_curr_instr_notENC = (Addr32)guest_IP_ENCODED;
20013 }
20014
20015 if (isThumb) {
sewardjc6f970f2012-04-02 21:54:49 +000020016 dres = disInstr_THUMB_WRK ( resteerOkFn,
sewardjd2664472010-08-22 12:44:20 +000020017 resteerCisOk, callback_opaque,
20018 &guest_code_IN[delta_ENCODED - 1],
sewardj442e51a2012-12-06 18:08:04 +000020019 archinfo, abiinfo, sigill_diag_IN );
sewardjd2664472010-08-22 12:44:20 +000020020 } else {
sewardjc6f970f2012-04-02 21:54:49 +000020021 dres = disInstr_ARM_WRK ( resteerOkFn,
sewardjd2664472010-08-22 12:44:20 +000020022 resteerCisOk, callback_opaque,
20023 &guest_code_IN[delta_ENCODED],
sewardj442e51a2012-12-06 18:08:04 +000020024 archinfo, abiinfo, sigill_diag_IN );
sewardjd2664472010-08-22 12:44:20 +000020025 }
sewardj6c299f32009-12-31 18:00:12 +000020026
20027 return dres;
20028}
20029
20030/* Test program for the conversion of IRCmpF64Result values to VFP
20031 nzcv values. See handling of FCMPD et al above. */
20032/*
20033UInt foo ( UInt x )
20034{
20035 UInt ix = ((x >> 5) & 3) | (x & 1);
20036 UInt termL = (((((ix ^ 1) << 30) - 1) >> 29) + 1);
20037 UInt termR = (ix & (ix >> 1) & 1);
20038 return termL - termR;
20039}
20040
20041void try ( char* s, UInt ir, UInt req )
20042{
20043 UInt act = foo(ir);
20044 printf("%s 0x%02x -> req %d%d%d%d act %d%d%d%d (0x%x)\n",
20045 s, ir, (req >> 3) & 1, (req >> 2) & 1,
20046 (req >> 1) & 1, (req >> 0) & 1,
20047 (act >> 3) & 1, (act >> 2) & 1,
20048 (act >> 1) & 1, (act >> 0) & 1, act);
20049
20050}
20051
20052int main ( void )
20053{
20054 printf("\n");
20055 try("UN", 0x45, 0b0011);
20056 try("LT", 0x01, 0b1000);
20057 try("GT", 0x00, 0b0010);
20058 try("EQ", 0x40, 0b0110);
20059 printf("\n");
20060 return 0;
20061}
20062*/
20063
sewardj1df80962013-04-18 11:50:58 +000020064/* Spare code for doing reference implementations of various 64-bit
20065 SIMD interleaves/deinterleaves/concatenation ops. */
20066/*
20067// Split a 64 bit value into 4 16 bit ones, in 32-bit IRTemps with
20068// the top halves guaranteed to be zero.
20069static void break64to16s ( IRTemp* out3, IRTemp* out2, IRTemp* out1,
20070 IRTemp* out0, IRTemp v64 )
20071{
20072 if (out3) *out3 = newTemp(Ity_I32);
20073 if (out2) *out2 = newTemp(Ity_I32);
20074 if (out1) *out1 = newTemp(Ity_I32);
20075 if (out0) *out0 = newTemp(Ity_I32);
20076 IRTemp hi32 = newTemp(Ity_I32);
20077 IRTemp lo32 = newTemp(Ity_I32);
20078 assign(hi32, unop(Iop_64HIto32, mkexpr(v64)) );
20079 assign(lo32, unop(Iop_64to32, mkexpr(v64)) );
20080 if (out3) assign(*out3, binop(Iop_Shr32, mkexpr(hi32), mkU8(16)));
20081 if (out2) assign(*out2, binop(Iop_And32, mkexpr(hi32), mkU32(0xFFFF)));
20082 if (out1) assign(*out1, binop(Iop_Shr32, mkexpr(lo32), mkU8(16)));
20083 if (out0) assign(*out0, binop(Iop_And32, mkexpr(lo32), mkU32(0xFFFF)));
20084}
20085
20086// Make a 64 bit value from 4 16 bit ones, each of which is in a 32 bit
20087// IRTemp.
20088static IRTemp mk64from16s ( IRTemp in3, IRTemp in2, IRTemp in1, IRTemp in0 )
20089{
20090 IRTemp hi32 = newTemp(Ity_I32);
20091 IRTemp lo32 = newTemp(Ity_I32);
20092 assign(hi32,
20093 binop(Iop_Or32,
20094 binop(Iop_Shl32, mkexpr(in3), mkU8(16)),
20095 binop(Iop_And32, mkexpr(in2), mkU32(0xFFFF))));
20096 assign(lo32,
20097 binop(Iop_Or32,
20098 binop(Iop_Shl32, mkexpr(in1), mkU8(16)),
20099 binop(Iop_And32, mkexpr(in0), mkU32(0xFFFF))));
20100 IRTemp res = newTemp(Ity_I64);
20101 assign(res, binop(Iop_32HLto64, mkexpr(hi32), mkexpr(lo32)));
20102 return res;
20103}
20104
20105static IRExpr* mk_InterleaveLO16x4 ( IRTemp a3210, IRTemp b3210 )
20106{
20107 // returns a1 b1 a0 b0
20108 IRTemp a1, a0, b1, b0;
20109 break64to16s(NULL, NULL, &a1, &a0, a3210);
20110 break64to16s(NULL, NULL, &b1, &b0, b3210);
20111 return mkexpr(mk64from16s(a1, b1, a0, b0));
20112}
20113
20114static IRExpr* mk_InterleaveHI16x4 ( IRTemp a3210, IRTemp b3210 )
20115{
20116 // returns a3 b3 a2 b2
20117 IRTemp a3, a2, b3, b2;
20118 break64to16s(&a3, &a2, NULL, NULL, a3210);
20119 break64to16s(&b3, &b2, NULL, NULL, b3210);
20120 return mkexpr(mk64from16s(a3, b3, a2, b2));
20121}
20122
20123static IRExpr* mk_CatEvenLanes16x4 ( IRTemp a3210, IRTemp b3210 )
20124{
20125 // returns a2 a0 b2 b0
20126 IRTemp a2, a0, b2, b0;
20127 break64to16s(NULL, &a2, NULL, &a0, a3210);
20128 break64to16s(NULL, &b2, NULL, &b0, b3210);
20129 return mkexpr(mk64from16s(a2, a0, b2, b0));
20130}
20131
20132static IRExpr* mk_CatOddLanes16x4 ( IRTemp a3210, IRTemp b3210 )
20133{
20134 // returns a3 a1 b3 b1
20135 IRTemp a3, a1, b3, b1;
20136 break64to16s(&a3, NULL, &a1, NULL, a3210);
20137 break64to16s(&b3, NULL, &b1, NULL, b3210);
20138 return mkexpr(mk64from16s(a3, a1, b3, b1));
20139}
20140
20141static IRExpr* mk_InterleaveOddLanes16x4 ( IRTemp a3210, IRTemp b3210 )
20142{
20143 // returns a3 b3 a1 b1
20144 IRTemp a3, b3, a1, b1;
20145 break64to16s(&a3, NULL, &a1, NULL, a3210);
20146 break64to16s(&b3, NULL, &b1, NULL, b3210);
20147 return mkexpr(mk64from16s(a3, b3, a1, b1));
20148}
20149
20150static IRExpr* mk_InterleaveEvenLanes16x4 ( IRTemp a3210, IRTemp b3210 )
20151{
20152 // returns a2 b2 a0 b0
20153 IRTemp a2, b2, a0, b0;
20154 break64to16s(NULL, &a2, NULL, &a0, a3210);
20155 break64to16s(NULL, &b2, NULL, &b0, b3210);
20156 return mkexpr(mk64from16s(a2, b2, a0, b0));
20157}
20158
20159static void break64to8s ( IRTemp* out7, IRTemp* out6, IRTemp* out5,
20160 IRTemp* out4, IRTemp* out3, IRTemp* out2,
20161 IRTemp* out1,IRTemp* out0, IRTemp v64 )
20162{
20163 if (out7) *out7 = newTemp(Ity_I32);
20164 if (out6) *out6 = newTemp(Ity_I32);
20165 if (out5) *out5 = newTemp(Ity_I32);
20166 if (out4) *out4 = newTemp(Ity_I32);
20167 if (out3) *out3 = newTemp(Ity_I32);
20168 if (out2) *out2 = newTemp(Ity_I32);
20169 if (out1) *out1 = newTemp(Ity_I32);
20170 if (out0) *out0 = newTemp(Ity_I32);
20171 IRTemp hi32 = newTemp(Ity_I32);
20172 IRTemp lo32 = newTemp(Ity_I32);
20173 assign(hi32, unop(Iop_64HIto32, mkexpr(v64)) );
20174 assign(lo32, unop(Iop_64to32, mkexpr(v64)) );
20175 if (out7)
20176 assign(*out7, binop(Iop_And32,
20177 binop(Iop_Shr32, mkexpr(hi32), mkU8(24)),
20178 mkU32(0xFF)));
20179 if (out6)
20180 assign(*out6, binop(Iop_And32,
20181 binop(Iop_Shr32, mkexpr(hi32), mkU8(16)),
20182 mkU32(0xFF)));
20183 if (out5)
20184 assign(*out5, binop(Iop_And32,
20185 binop(Iop_Shr32, mkexpr(hi32), mkU8(8)),
20186 mkU32(0xFF)));
20187 if (out4)
20188 assign(*out4, binop(Iop_And32, mkexpr(hi32), mkU32(0xFF)));
20189 if (out3)
20190 assign(*out3, binop(Iop_And32,
20191 binop(Iop_Shr32, mkexpr(lo32), mkU8(24)),
20192 mkU32(0xFF)));
20193 if (out2)
20194 assign(*out2, binop(Iop_And32,
20195 binop(Iop_Shr32, mkexpr(lo32), mkU8(16)),
20196 mkU32(0xFF)));
20197 if (out1)
20198 assign(*out1, binop(Iop_And32,
20199 binop(Iop_Shr32, mkexpr(lo32), mkU8(8)),
20200 mkU32(0xFF)));
20201 if (out0)
20202 assign(*out0, binop(Iop_And32, mkexpr(lo32), mkU32(0xFF)));
20203}
20204
20205static IRTemp mk64from8s ( IRTemp in7, IRTemp in6, IRTemp in5, IRTemp in4,
20206 IRTemp in3, IRTemp in2, IRTemp in1, IRTemp in0 )
20207{
20208 IRTemp hi32 = newTemp(Ity_I32);
20209 IRTemp lo32 = newTemp(Ity_I32);
20210 assign(hi32,
20211 binop(Iop_Or32,
20212 binop(Iop_Or32,
20213 binop(Iop_Shl32,
20214 binop(Iop_And32, mkexpr(in7), mkU32(0xFF)),
20215 mkU8(24)),
20216 binop(Iop_Shl32,
20217 binop(Iop_And32, mkexpr(in6), mkU32(0xFF)),
20218 mkU8(16))),
20219 binop(Iop_Or32,
20220 binop(Iop_Shl32,
20221 binop(Iop_And32, mkexpr(in5), mkU32(0xFF)), mkU8(8)),
20222 binop(Iop_And32,
20223 mkexpr(in4), mkU32(0xFF)))));
20224 assign(lo32,
20225 binop(Iop_Or32,
20226 binop(Iop_Or32,
20227 binop(Iop_Shl32,
20228 binop(Iop_And32, mkexpr(in3), mkU32(0xFF)),
20229 mkU8(24)),
20230 binop(Iop_Shl32,
20231 binop(Iop_And32, mkexpr(in2), mkU32(0xFF)),
20232 mkU8(16))),
20233 binop(Iop_Or32,
20234 binop(Iop_Shl32,
20235 binop(Iop_And32, mkexpr(in1), mkU32(0xFF)), mkU8(8)),
20236 binop(Iop_And32,
20237 mkexpr(in0), mkU32(0xFF)))));
20238 IRTemp res = newTemp(Ity_I64);
20239 assign(res, binop(Iop_32HLto64, mkexpr(hi32), mkexpr(lo32)));
20240 return res;
20241}
20242
20243static IRExpr* mk_InterleaveLO8x8 ( IRTemp a76543210, IRTemp b76543210 )
20244{
20245 // returns a3 b3 a2 b2 a1 b1 a0 b0
20246 IRTemp a3, b3, a2, b2, a1, a0, b1, b0;
20247 break64to8s(NULL, NULL, NULL, NULL, &a3, &a2, &a1, &a0, a76543210);
20248 break64to8s(NULL, NULL, NULL, NULL, &b3, &b2, &b1, &b0, b76543210);
20249 return mkexpr(mk64from8s(a3, b3, a2, b2, a1, b1, a0, b0));
20250}
20251
20252static IRExpr* mk_InterleaveHI8x8 ( IRTemp a76543210, IRTemp b76543210 )
20253{
20254 // returns a7 b7 a6 b6 a5 b5 a4 b4
20255 IRTemp a7, b7, a6, b6, a5, b5, a4, b4;
20256 break64to8s(&a7, &a6, &a5, &a4, NULL, NULL, NULL, NULL, a76543210);
20257 break64to8s(&b7, &b6, &b5, &b4, NULL, NULL, NULL, NULL, b76543210);
20258 return mkexpr(mk64from8s(a7, b7, a6, b6, a5, b5, a4, b4));
20259}
20260
20261static IRExpr* mk_CatEvenLanes8x8 ( IRTemp a76543210, IRTemp b76543210 )
20262{
20263 // returns a6 a4 a2 a0 b6 b4 b2 b0
20264 IRTemp a6, a4, a2, a0, b6, b4, b2, b0;
20265 break64to8s(NULL, &a6, NULL, &a4, NULL, &a2, NULL, &a0, a76543210);
20266 break64to8s(NULL, &b6, NULL, &b4, NULL, &b2, NULL, &b0, b76543210);
20267 return mkexpr(mk64from8s(a6, a4, a2, a0, b6, b4, b2, b0));
20268}
20269
20270static IRExpr* mk_CatOddLanes8x8 ( IRTemp a76543210, IRTemp b76543210 )
20271{
20272 // returns a7 a5 a3 a1 b7 b5 b3 b1
20273 IRTemp a7, a5, a3, a1, b7, b5, b3, b1;
20274 break64to8s(&a7, NULL, &a5, NULL, &a3, NULL, &a1, NULL, a76543210);
20275 break64to8s(&b7, NULL, &b5, NULL, &b3, NULL, &b1, NULL, b76543210);
20276 return mkexpr(mk64from8s(a7, a5, a3, a1, b7, b5, b3, b1));
20277}
20278
20279static IRExpr* mk_InterleaveEvenLanes8x8 ( IRTemp a76543210, IRTemp b76543210 )
20280{
20281 // returns a6 b6 a4 b4 a2 b2 a0 b0
20282 IRTemp a6, b6, a4, b4, a2, b2, a0, b0;
20283 break64to8s(NULL, &a6, NULL, &a4, NULL, &a2, NULL, &a0, a76543210);
20284 break64to8s(NULL, &b6, NULL, &b4, NULL, &b2, NULL, &b0, b76543210);
20285 return mkexpr(mk64from8s(a6, b6, a4, b4, a2, b2, a0, b0));
20286}
20287
20288static IRExpr* mk_InterleaveOddLanes8x8 ( IRTemp a76543210, IRTemp b76543210 )
20289{
20290 // returns a7 b7 a5 b5 a3 b3 a1 b1
20291 IRTemp a7, b7, a5, b5, a3, b3, a1, b1;
20292 break64to8s(&a7, NULL, &a5, NULL, &a3, NULL, &a1, NULL, a76543210);
20293 break64to8s(&b7, NULL, &b5, NULL, &b3, NULL, &b1, NULL, b76543210);
20294 return mkexpr(mk64from8s(a7, b7, a5, b5, a3, b3, a1, b1));
20295}
20296
20297static IRExpr* mk_InterleaveLO32x2 ( IRTemp a10, IRTemp b10 )
20298{
20299 // returns a0 b0
20300 return binop(Iop_32HLto64, unop(Iop_64to32, mkexpr(a10)),
20301 unop(Iop_64to32, mkexpr(b10)));
20302}
20303
20304static IRExpr* mk_InterleaveHI32x2 ( IRTemp a10, IRTemp b10 )
20305{
20306 // returns a1 b1
20307 return binop(Iop_32HLto64, unop(Iop_64HIto32, mkexpr(a10)),
20308 unop(Iop_64HIto32, mkexpr(b10)));
20309}
20310*/
20311
sewardjc2c87162004-11-25 13:07:02 +000020312/*--------------------------------------------------------------------*/
sewardjcef7d3e2009-07-02 12:21:59 +000020313/*--- end guest_arm_toIR.c ---*/
sewardjc2c87162004-11-25 13:07:02 +000020314/*--------------------------------------------------------------------*/