Add a test program for the membarrier() system call
[valgrind.git] / VEX / priv / guest_arm_toIR.c
blobd858c85e0bcca21da5f96d052d85e402a46dcffb
2 /*--------------------------------------------------------------------*/
3 /*--- begin guest_arm_toIR.c ---*/
4 /*--------------------------------------------------------------------*/
6 /*
7 This file is part of Valgrind, a dynamic binary instrumentation
8 framework.
10 Copyright (C) 2004-2017 OpenWorks LLP
11 info@open-works.net
13 NEON support is
14 Copyright (C) 2010-2017 Samsung Electronics
15 contributed by Dmitry Zhurikhin <zhur@ispras.ru>
16 and Kirill Batuzov <batuzovk@ispras.ru>
18 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.
23 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.
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
31 02110-1301, USA.
33 The GNU General Public License is contained in the file COPYING.
36 /* XXXX thumb to check:
37 that all cases where putIRegT writes r15, we generate a jump.
39 All uses of newTemp assign to an IRTemp and not a UInt
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).
46 VFP on thumb: check that we exclude all r13/r15 cases that we
47 should.
49 XXXX thumb to do: improve the ITSTATE-zeroing optimisation by
50 taking into account the number of insns guarded by an IT.
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.
56 add specialisations for armg_calculate_flag_c and _v, as they
57 are moderately often needed in Thumb code.
59 Correctness: ITSTATE handling in Thumb SVCs is wrong.
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.
68 /* Limitations, etc
70 - 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.
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.
79 /* "Special" instructions.
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:
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)
90 Following that, one of the following 3 are allowed
91 (standard interpretation in parentheses):
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
96 E1899009 (orr r9,r9,r9) IR injection
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.
104 /* Translates ARM(v5) code to IR. */
106 #include "libvex_basictypes.h"
107 #include "libvex_ir.h"
108 #include "libvex.h"
109 #include "libvex_guest_arm.h"
111 #include "main_util.h"
112 #include "main_globals.h"
113 #include "guest_generic_bb_to_IR.h"
114 #include "guest_arm_defs.h"
117 /*------------------------------------------------------------*/
118 /*--- Globals ---*/
119 /*------------------------------------------------------------*/
121 /* 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.
126 /* CONST: what is the host's endianness? This has to do with float vs
127 double register accesses on VFP, but it's complex and not properly
128 thought out. */
129 static VexEndness host_endness;
131 /* CONST: The guest address for the instruction currently being
132 translated. This is the real, "decoded" address (not subject
133 to the CPSR.T kludge). */
134 static Addr32 guest_R15_curr_instr_notENC;
136 /* CONST, FOR ASSERTIONS ONLY. Indicates whether currently processed
137 insn is Thumb (True) or ARM (False). */
138 static Bool __curr_is_Thumb;
140 /* MOD: The IRSB* into which we're generating code. */
141 static IRSB* irsb;
143 /* 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. */
152 /* MOD. Initially False; set to True iff abovementioned handling is
153 required. */
154 static Bool r15written;
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. */
160 static IRTemp r15guard; /* :: Ity_I32, 0 or 1 */
162 /* MOD. Initially Ijk_Boring. If an r15 branch is to be generated,
163 this holds the jump kind. */
164 static IRTemp r15kind;
167 /*------------------------------------------------------------*/
168 /*--- Debugging output ---*/
169 /*------------------------------------------------------------*/
171 #define DIP(format, args...) \
172 if (vex_traceflags & VEX_TRACE_FE) \
173 vex_printf(format, ## args)
175 #define DIS(buf, format, args...) \
176 if (vex_traceflags & VEX_TRACE_FE) \
177 vex_sprintf(buf, format, ## args)
179 #define ASSERT_IS_THUMB \
180 do { vassert(__curr_is_Thumb); } while (0)
182 #define ASSERT_IS_ARM \
183 do { vassert(! __curr_is_Thumb); } while (0)
186 /*------------------------------------------------------------*/
187 /*--- Helper bits and pieces for deconstructing the ---*/
188 /*--- arm insn stream. ---*/
189 /*------------------------------------------------------------*/
191 /* Do a little-endian load of a 32-bit word, regardless of the
192 endianness of the underlying host. */
193 static inline UInt getUIntLittleEndianly ( const UChar* p )
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;
203 /* Do a little-endian load of a 16-bit word, regardless of the
204 endianness of the underlying host. */
205 static inline UShort getUShortLittleEndianly ( const UChar* p )
207 UShort w = 0;
208 w = (w << 8) | p[1];
209 w = (w << 8) | p[0];
210 return w;
213 static 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);
221 static Int popcount32 ( UInt x )
223 Int res = 0, i;
224 for (i = 0; i < 32; i++) {
225 res += (x & 1);
226 x >>= 1;
228 return res;
231 static UInt setbit32 ( UInt x, Int ix, UInt b )
233 UInt mask = 1 << ix;
234 x &= ~mask;
235 x |= ((b << ix) & mask);
236 return x;
239 #define BITS2(_b1,_b0) \
240 (((_b1) << 1) | (_b0))
242 #define BITS3(_b2,_b1,_b0) \
243 (((_b2) << 2) | ((_b1) << 1) | (_b0))
245 #define BITS4(_b3,_b2,_b1,_b0) \
246 (((_b3) << 3) | ((_b2) << 2) | ((_b1) << 1) | (_b0))
248 #define BITS8(_b7,_b6,_b5,_b4,_b3,_b2,_b1,_b0) \
249 ((BITS4((_b7),(_b6),(_b5),(_b4)) << 4) \
250 | BITS4((_b3),(_b2),(_b1),(_b0)))
252 #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)))
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)))
263 #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)))
267 #define BITS11(_b10,_b9,_b8,_b7,_b6,_b5,_b4,_b3,_b2,_b1,_b0) \
268 ( ((_b10) << 10) | ((_b9) << 9) | ((_b8) << 8) \
269 | BITS8((_b7),(_b6),(_b5),(_b4),(_b3),(_b2),(_b1),(_b0)))
271 #define BITS12(_b11,_b10,_b9,_b8,_b7,_b6,_b5,_b4,_b3,_b2,_b1,_b0) \
272 ( ((_b11) << 11) | ((_b10) << 10) | ((_b9) << 9) | ((_b8) << 8) \
273 | BITS8((_b7),(_b6),(_b5),(_b4),(_b3),(_b2),(_b1),(_b0)))
275 /* produces _uint[_bMax:_bMin] */
276 #define SLICE_UInt(_uint,_bMax,_bMin) \
277 (( ((UInt)(_uint)) >> (_bMin)) \
278 & (UInt)((1ULL << ((_bMax) - (_bMin) + 1)) - 1ULL))
281 /*------------------------------------------------------------*/
282 /*--- Helper bits and pieces for creating IR fragments. ---*/
283 /*------------------------------------------------------------*/
285 static IRExpr* mkU64 ( ULong i )
287 return IRExpr_Const(IRConst_U64(i));
290 static IRExpr* mkU32 ( UInt i )
292 return IRExpr_Const(IRConst_U32(i));
295 static IRExpr* mkU8 ( UInt i )
297 vassert(i < 256);
298 return IRExpr_Const(IRConst_U8( (UChar)i ));
301 static IRExpr* mkexpr ( IRTemp tmp )
303 return IRExpr_RdTmp(tmp);
306 static IRExpr* unop ( IROp op, IRExpr* a )
308 return IRExpr_Unop(op, a);
311 static IRExpr* binop ( IROp op, IRExpr* a1, IRExpr* a2 )
313 return IRExpr_Binop(op, a1, a2);
316 static IRExpr* triop ( IROp op, IRExpr* a1, IRExpr* a2, IRExpr* a3 )
318 return IRExpr_Triop(op, a1, a2, a3);
321 static IRExpr* loadLE ( IRType ty, IRExpr* addr )
323 return IRExpr_Load(Iend_LE, ty, addr);
326 /* Add a statement to the list held by "irbb". */
327 static void stmt ( IRStmt* st )
329 addStmtToIRSB( irsb, st );
332 static void assign ( IRTemp dst, IRExpr* e )
334 stmt( IRStmt_WrTmp(dst, e) );
337 static void storeLE ( IRExpr* addr, IRExpr* data )
339 stmt( IRStmt_Store(Iend_LE, addr, data) );
342 static void storeGuardedLE ( IRExpr* addr, IRExpr* data, IRTemp guardT )
344 if (guardT == IRTemp_INVALID) {
345 /* unconditional */
346 storeLE(addr, data);
347 } else {
348 stmt( IRStmt_StoreG(Iend_LE, addr, data,
349 binop(Iop_CmpNE32, mkexpr(guardT), mkU32(0))) );
353 static void loadGuardedLE ( IRTemp dst, IRLoadGOp cvt,
354 IRExpr* addr, IRExpr* alt,
355 IRTemp guardT /* :: Ity_I32, 0 or 1 */ )
357 if (guardT == IRTemp_INVALID) {
358 /* unconditional */
359 IRExpr* loaded = NULL;
360 switch (cvt) {
361 case ILGop_Ident32:
362 loaded = loadLE(Ity_I32, addr); break;
363 case ILGop_8Uto32:
364 loaded = unop(Iop_8Uto32, loadLE(Ity_I8, addr)); break;
365 case ILGop_8Sto32:
366 loaded = unop(Iop_8Sto32, loadLE(Ity_I8, addr)); break;
367 case ILGop_16Uto32:
368 loaded = unop(Iop_16Uto32, loadLE(Ity_I16, addr)); break;
369 case ILGop_16Sto32:
370 loaded = unop(Iop_16Sto32, loadLE(Ity_I16, addr)); break;
371 default:
372 vassert(0);
374 vassert(loaded != NULL);
375 assign(dst, loaded);
376 } else {
377 /* Generate a guarded load into 'dst', but apply 'cvt' to the
378 loaded data before putting the data in 'dst'. If the load
379 does not take place, 'alt' is placed directly in 'dst'. */
380 stmt( IRStmt_LoadG(Iend_LE, cvt, dst, addr, alt,
381 binop(Iop_CmpNE32, mkexpr(guardT), mkU32(0))) );
385 /* Generate a new temporary of the given type. */
386 static IRTemp newTemp ( IRType ty )
388 vassert(isPlausibleIRType(ty));
389 return newIRTemp( irsb->tyenv, ty );
392 /* Produces a value in 0 .. 3, which is encoded as per the type
393 IRRoundingMode. */
394 static IRExpr* /* :: Ity_I32 */ get_FAKE_roundingmode ( void )
396 return mkU32(Irrm_NEAREST);
399 /* Generate an expression for SRC rotated right by ROT. */
400 static IRExpr* genROR32( IRTemp src, Int rot )
402 vassert(rot >= 0 && rot < 32);
403 if (rot == 0)
404 return mkexpr(src);
405 return
406 binop(Iop_Or32,
407 binop(Iop_Shl32, mkexpr(src), mkU8(32 - rot)),
408 binop(Iop_Shr32, mkexpr(src), mkU8(rot)));
411 static IRExpr* mkU128 ( ULong i )
413 return binop(Iop_64HLtoV128, mkU64(i), mkU64(i));
416 /* Generate a 4-aligned version of the given expression if
417 the given condition is true. Else return it unchanged. */
418 static IRExpr* align4if ( IRExpr* e, Bool b )
420 if (b)
421 return binop(Iop_And32, e, mkU32(~3));
422 else
423 return e;
427 /*------------------------------------------------------------*/
428 /*--- Helpers for accessing guest registers. ---*/
429 /*------------------------------------------------------------*/
431 #define OFFB_R0 offsetof(VexGuestARMState,guest_R0)
432 #define OFFB_R1 offsetof(VexGuestARMState,guest_R1)
433 #define OFFB_R2 offsetof(VexGuestARMState,guest_R2)
434 #define OFFB_R3 offsetof(VexGuestARMState,guest_R3)
435 #define OFFB_R4 offsetof(VexGuestARMState,guest_R4)
436 #define OFFB_R5 offsetof(VexGuestARMState,guest_R5)
437 #define OFFB_R6 offsetof(VexGuestARMState,guest_R6)
438 #define OFFB_R7 offsetof(VexGuestARMState,guest_R7)
439 #define OFFB_R8 offsetof(VexGuestARMState,guest_R8)
440 #define OFFB_R9 offsetof(VexGuestARMState,guest_R9)
441 #define OFFB_R10 offsetof(VexGuestARMState,guest_R10)
442 #define OFFB_R11 offsetof(VexGuestARMState,guest_R11)
443 #define OFFB_R12 offsetof(VexGuestARMState,guest_R12)
444 #define OFFB_R13 offsetof(VexGuestARMState,guest_R13)
445 #define OFFB_R14 offsetof(VexGuestARMState,guest_R14)
446 #define OFFB_R15T offsetof(VexGuestARMState,guest_R15T)
448 #define OFFB_CC_OP offsetof(VexGuestARMState,guest_CC_OP)
449 #define OFFB_CC_DEP1 offsetof(VexGuestARMState,guest_CC_DEP1)
450 #define OFFB_CC_DEP2 offsetof(VexGuestARMState,guest_CC_DEP2)
451 #define OFFB_CC_NDEP offsetof(VexGuestARMState,guest_CC_NDEP)
452 #define OFFB_NRADDR offsetof(VexGuestARMState,guest_NRADDR)
454 #define OFFB_D0 offsetof(VexGuestARMState,guest_D0)
455 #define OFFB_D1 offsetof(VexGuestARMState,guest_D1)
456 #define OFFB_D2 offsetof(VexGuestARMState,guest_D2)
457 #define OFFB_D3 offsetof(VexGuestARMState,guest_D3)
458 #define OFFB_D4 offsetof(VexGuestARMState,guest_D4)
459 #define OFFB_D5 offsetof(VexGuestARMState,guest_D5)
460 #define OFFB_D6 offsetof(VexGuestARMState,guest_D6)
461 #define OFFB_D7 offsetof(VexGuestARMState,guest_D7)
462 #define OFFB_D8 offsetof(VexGuestARMState,guest_D8)
463 #define OFFB_D9 offsetof(VexGuestARMState,guest_D9)
464 #define OFFB_D10 offsetof(VexGuestARMState,guest_D10)
465 #define OFFB_D11 offsetof(VexGuestARMState,guest_D11)
466 #define OFFB_D12 offsetof(VexGuestARMState,guest_D12)
467 #define OFFB_D13 offsetof(VexGuestARMState,guest_D13)
468 #define OFFB_D14 offsetof(VexGuestARMState,guest_D14)
469 #define OFFB_D15 offsetof(VexGuestARMState,guest_D15)
470 #define OFFB_D16 offsetof(VexGuestARMState,guest_D16)
471 #define OFFB_D17 offsetof(VexGuestARMState,guest_D17)
472 #define OFFB_D18 offsetof(VexGuestARMState,guest_D18)
473 #define OFFB_D19 offsetof(VexGuestARMState,guest_D19)
474 #define OFFB_D20 offsetof(VexGuestARMState,guest_D20)
475 #define OFFB_D21 offsetof(VexGuestARMState,guest_D21)
476 #define OFFB_D22 offsetof(VexGuestARMState,guest_D22)
477 #define OFFB_D23 offsetof(VexGuestARMState,guest_D23)
478 #define OFFB_D24 offsetof(VexGuestARMState,guest_D24)
479 #define OFFB_D25 offsetof(VexGuestARMState,guest_D25)
480 #define OFFB_D26 offsetof(VexGuestARMState,guest_D26)
481 #define OFFB_D27 offsetof(VexGuestARMState,guest_D27)
482 #define OFFB_D28 offsetof(VexGuestARMState,guest_D28)
483 #define OFFB_D29 offsetof(VexGuestARMState,guest_D29)
484 #define OFFB_D30 offsetof(VexGuestARMState,guest_D30)
485 #define OFFB_D31 offsetof(VexGuestARMState,guest_D31)
487 #define OFFB_FPSCR offsetof(VexGuestARMState,guest_FPSCR)
488 #define OFFB_TPIDRURO offsetof(VexGuestARMState,guest_TPIDRURO)
489 #define OFFB_TPIDRURW offsetof(VexGuestARMState,guest_TPIDRURW)
490 #define OFFB_ITSTATE offsetof(VexGuestARMState,guest_ITSTATE)
491 #define OFFB_QFLAG32 offsetof(VexGuestARMState,guest_QFLAG32)
492 #define OFFB_GEFLAG0 offsetof(VexGuestARMState,guest_GEFLAG0)
493 #define OFFB_GEFLAG1 offsetof(VexGuestARMState,guest_GEFLAG1)
494 #define OFFB_GEFLAG2 offsetof(VexGuestARMState,guest_GEFLAG2)
495 #define OFFB_GEFLAG3 offsetof(VexGuestARMState,guest_GEFLAG3)
497 #define OFFB_CMSTART offsetof(VexGuestARMState,guest_CMSTART)
498 #define OFFB_CMLEN offsetof(VexGuestARMState,guest_CMLEN)
501 /* ---------------- Integer registers ---------------- */
503 static Int integerGuestRegOffset ( UInt iregNo )
505 /* Do we care about endianness here? We do if sub-parts of integer
506 registers are accessed, but I don't think that ever happens on
507 ARM. */
508 switch (iregNo) {
509 case 0: return OFFB_R0;
510 case 1: return OFFB_R1;
511 case 2: return OFFB_R2;
512 case 3: return OFFB_R3;
513 case 4: return OFFB_R4;
514 case 5: return OFFB_R5;
515 case 6: return OFFB_R6;
516 case 7: return OFFB_R7;
517 case 8: return OFFB_R8;
518 case 9: return OFFB_R9;
519 case 10: return OFFB_R10;
520 case 11: return OFFB_R11;
521 case 12: return OFFB_R12;
522 case 13: return OFFB_R13;
523 case 14: return OFFB_R14;
524 case 15: return OFFB_R15T;
525 default: vassert(0);
529 /* Plain ("low level") read from a reg; no +8 offset magic for r15. */
530 static IRExpr* llGetIReg ( UInt iregNo )
532 vassert(iregNo < 16);
533 return IRExpr_Get( integerGuestRegOffset(iregNo), Ity_I32 );
536 /* Architected read from a reg in ARM mode. This automagically adds 8
537 to all reads of r15. */
538 static IRExpr* getIRegA ( UInt iregNo )
540 IRExpr* e;
541 ASSERT_IS_ARM;
542 vassert(iregNo < 16);
543 if (iregNo == 15) {
544 /* If asked for r15, don't read the guest state value, as that
545 may not be up to date in the case where loop unrolling has
546 happened, because the first insn's write to the block is
547 omitted; hence in the 2nd and subsequent unrollings we don't
548 have a correct value in guest r15. Instead produce the
549 constant that we know would be produced at this point. */
550 vassert(0 == (guest_R15_curr_instr_notENC & 3));
551 e = mkU32(guest_R15_curr_instr_notENC + 8);
552 } else {
553 e = IRExpr_Get( integerGuestRegOffset(iregNo), Ity_I32 );
555 return e;
558 /* Architected read from a reg in Thumb mode. This automagically adds
559 4 to all reads of r15. */
560 static IRExpr* getIRegT ( UInt iregNo )
562 IRExpr* e;
563 ASSERT_IS_THUMB;
564 vassert(iregNo < 16);
565 if (iregNo == 15) {
566 /* Ditto comment in getIReg. */
567 vassert(0 == (guest_R15_curr_instr_notENC & 1));
568 e = mkU32(guest_R15_curr_instr_notENC + 4);
569 } else {
570 e = IRExpr_Get( integerGuestRegOffset(iregNo), Ity_I32 );
572 return e;
575 /* Plain ("low level") write to a reg; no jump or alignment magic for
576 r15. */
577 static void llPutIReg ( UInt iregNo, IRExpr* e )
579 vassert(iregNo < 16);
580 vassert(typeOfIRExpr(irsb->tyenv, e) == Ity_I32);
581 stmt( IRStmt_Put(integerGuestRegOffset(iregNo), e) );
584 /* Architected write to an integer register in ARM mode. If it is to
585 r15, record info so at the end of this insn's translation, a branch
586 to it can be made. Also handles conditional writes to the
587 register: if guardT == IRTemp_INVALID then the write is
588 unconditional. If writing r15, also 4-align it. */
589 static void putIRegA ( UInt iregNo,
590 IRExpr* e,
591 IRTemp guardT /* :: Ity_I32, 0 or 1 */,
592 IRJumpKind jk /* if a jump is generated */ )
594 /* if writing r15, force e to be 4-aligned. */
595 // INTERWORKING FIXME. this needs to be relaxed so that
596 // puts caused by LDMxx which load r15 interwork right.
597 // but is no aligned too relaxed?
598 //if (iregNo == 15)
599 // e = binop(Iop_And32, e, mkU32(~3));
600 ASSERT_IS_ARM;
601 /* So, generate either an unconditional or a conditional write to
602 the reg. */
603 if (guardT == IRTemp_INVALID) {
604 /* unconditional write */
605 llPutIReg( iregNo, e );
606 } else {
607 llPutIReg( iregNo,
608 IRExpr_ITE( binop(Iop_CmpNE32, mkexpr(guardT), mkU32(0)),
609 e, llGetIReg(iregNo) ));
611 if (iregNo == 15) {
612 // assert against competing r15 updates. Shouldn't
613 // happen; should be ruled out by the instr matching
614 // logic.
615 vassert(r15written == False);
616 vassert(r15guard == IRTemp_INVALID);
617 vassert(r15kind == Ijk_Boring);
618 r15written = True;
619 r15guard = guardT;
620 r15kind = jk;
625 /* Architected write to an integer register in Thumb mode. Writes to
626 r15 are not allowed. Handles conditional writes to the register:
627 if guardT == IRTemp_INVALID then the write is unconditional. */
628 static void putIRegT ( UInt iregNo,
629 IRExpr* e,
630 IRTemp guardT /* :: Ity_I32, 0 or 1 */ )
632 /* So, generate either an unconditional or a conditional write to
633 the reg. */
634 ASSERT_IS_THUMB;
635 vassert(iregNo >= 0 && iregNo <= 14);
636 if (guardT == IRTemp_INVALID) {
637 /* unconditional write */
638 llPutIReg( iregNo, e );
639 } else {
640 llPutIReg( iregNo,
641 IRExpr_ITE( binop(Iop_CmpNE32, mkexpr(guardT), mkU32(0)),
642 e, llGetIReg(iregNo) ));
647 /* Thumb16 and Thumb32 only.
648 Returns true if reg is 13 or 15. Implements the BadReg
649 predicate in the ARM ARM. */
650 static Bool isBadRegT ( UInt r )
652 vassert(r <= 15);
653 ASSERT_IS_THUMB;
654 return r == 13 || r == 15;
658 /* ---------------- Double registers ---------------- */
660 static Int doubleGuestRegOffset ( UInt dregNo )
662 /* Do we care about endianness here? Probably do if we ever get
663 into the situation of dealing with the single-precision VFP
664 registers. */
665 switch (dregNo) {
666 case 0: return OFFB_D0;
667 case 1: return OFFB_D1;
668 case 2: return OFFB_D2;
669 case 3: return OFFB_D3;
670 case 4: return OFFB_D4;
671 case 5: return OFFB_D5;
672 case 6: return OFFB_D6;
673 case 7: return OFFB_D7;
674 case 8: return OFFB_D8;
675 case 9: return OFFB_D9;
676 case 10: return OFFB_D10;
677 case 11: return OFFB_D11;
678 case 12: return OFFB_D12;
679 case 13: return OFFB_D13;
680 case 14: return OFFB_D14;
681 case 15: return OFFB_D15;
682 case 16: return OFFB_D16;
683 case 17: return OFFB_D17;
684 case 18: return OFFB_D18;
685 case 19: return OFFB_D19;
686 case 20: return OFFB_D20;
687 case 21: return OFFB_D21;
688 case 22: return OFFB_D22;
689 case 23: return OFFB_D23;
690 case 24: return OFFB_D24;
691 case 25: return OFFB_D25;
692 case 26: return OFFB_D26;
693 case 27: return OFFB_D27;
694 case 28: return OFFB_D28;
695 case 29: return OFFB_D29;
696 case 30: return OFFB_D30;
697 case 31: return OFFB_D31;
698 default: vassert(0);
702 /* Plain ("low level") read from a VFP Dreg. */
703 static IRExpr* llGetDReg ( UInt dregNo )
705 vassert(dregNo < 32);
706 return IRExpr_Get( doubleGuestRegOffset(dregNo), Ity_F64 );
709 /* Architected read from a VFP Dreg. */
710 static IRExpr* getDReg ( UInt dregNo ) {
711 return llGetDReg( dregNo );
714 /* Plain ("low level") write to a VFP Dreg. */
715 static void llPutDReg ( UInt dregNo, IRExpr* e )
717 vassert(dregNo < 32);
718 vassert(typeOfIRExpr(irsb->tyenv, e) == Ity_F64);
719 stmt( IRStmt_Put(doubleGuestRegOffset(dregNo), e) );
722 /* Architected write to a VFP Dreg. Handles conditional writes to the
723 register: if guardT == IRTemp_INVALID then the write is
724 unconditional. */
725 static void putDReg ( UInt dregNo,
726 IRExpr* e,
727 IRTemp guardT /* :: Ity_I32, 0 or 1 */)
729 /* So, generate either an unconditional or a conditional write to
730 the reg. */
731 if (guardT == IRTemp_INVALID) {
732 /* unconditional write */
733 llPutDReg( dregNo, e );
734 } else {
735 llPutDReg( dregNo,
736 IRExpr_ITE( binop(Iop_CmpNE32, mkexpr(guardT), mkU32(0)),
737 e, llGetDReg(dregNo) ));
741 /* And now exactly the same stuff all over again, but this time
742 taking/returning I64 rather than F64, to support 64-bit Neon
743 ops. */
745 /* Plain ("low level") read from a Neon Integer Dreg. */
746 static IRExpr* llGetDRegI64 ( UInt dregNo )
748 vassert(dregNo < 32);
749 return IRExpr_Get( doubleGuestRegOffset(dregNo), Ity_I64 );
752 /* Architected read from a Neon Integer Dreg. */
753 static IRExpr* getDRegI64 ( UInt dregNo ) {
754 return llGetDRegI64( dregNo );
757 /* Plain ("low level") write to a Neon Integer Dreg. */
758 static void llPutDRegI64 ( UInt dregNo, IRExpr* e )
760 vassert(dregNo < 32);
761 vassert(typeOfIRExpr(irsb->tyenv, e) == Ity_I64);
762 stmt( IRStmt_Put(doubleGuestRegOffset(dregNo), e) );
765 /* Architected write to a Neon Integer Dreg. Handles conditional
766 writes to the register: if guardT == IRTemp_INVALID then the write
767 is unconditional. */
768 static void putDRegI64 ( UInt dregNo,
769 IRExpr* e,
770 IRTemp guardT /* :: Ity_I32, 0 or 1 */)
772 /* So, generate either an unconditional or a conditional write to
773 the reg. */
774 if (guardT == IRTemp_INVALID) {
775 /* unconditional write */
776 llPutDRegI64( dregNo, e );
777 } else {
778 llPutDRegI64( dregNo,
779 IRExpr_ITE( binop(Iop_CmpNE32, mkexpr(guardT), mkU32(0)),
780 e, llGetDRegI64(dregNo) ));
784 /* ---------------- Quad registers ---------------- */
786 static Int quadGuestRegOffset ( UInt qregNo )
788 /* Do we care about endianness here? Probably do if we ever get
789 into the situation of dealing with the 64 bit Neon registers. */
790 switch (qregNo) {
791 case 0: return OFFB_D0;
792 case 1: return OFFB_D2;
793 case 2: return OFFB_D4;
794 case 3: return OFFB_D6;
795 case 4: return OFFB_D8;
796 case 5: return OFFB_D10;
797 case 6: return OFFB_D12;
798 case 7: return OFFB_D14;
799 case 8: return OFFB_D16;
800 case 9: return OFFB_D18;
801 case 10: return OFFB_D20;
802 case 11: return OFFB_D22;
803 case 12: return OFFB_D24;
804 case 13: return OFFB_D26;
805 case 14: return OFFB_D28;
806 case 15: return OFFB_D30;
807 default: vassert(0);
811 /* Plain ("low level") read from a Neon Qreg. */
812 static IRExpr* llGetQReg ( UInt qregNo )
814 vassert(qregNo < 16);
815 return IRExpr_Get( quadGuestRegOffset(qregNo), Ity_V128 );
818 /* Architected read from a Neon Qreg. */
819 static IRExpr* getQReg ( UInt qregNo ) {
820 return llGetQReg( qregNo );
823 /* Plain ("low level") write to a Neon Qreg. */
824 static void llPutQReg ( UInt qregNo, IRExpr* e )
826 vassert(qregNo < 16);
827 vassert(typeOfIRExpr(irsb->tyenv, e) == Ity_V128);
828 stmt( IRStmt_Put(quadGuestRegOffset(qregNo), e) );
831 /* Architected write to a Neon Qreg. Handles conditional writes to the
832 register: if guardT == IRTemp_INVALID then the write is
833 unconditional. */
834 static void putQReg ( UInt qregNo,
835 IRExpr* e,
836 IRTemp guardT /* :: Ity_I32, 0 or 1 */)
838 /* So, generate either an unconditional or a conditional write to
839 the reg. */
840 if (guardT == IRTemp_INVALID) {
841 /* unconditional write */
842 llPutQReg( qregNo, e );
843 } else {
844 llPutQReg( qregNo,
845 IRExpr_ITE( binop(Iop_CmpNE32, mkexpr(guardT), mkU32(0)),
846 e, llGetQReg(qregNo) ));
851 /* ---------------- Float registers ---------------- */
853 static Int floatGuestRegOffset ( UInt fregNo )
855 /* Start with the offset of the containing double, and then correct
856 for endianness. Actually this is completely bogus and needs
857 careful thought. */
858 Int off;
859 /* NB! Limit is 64, not 32, because we might be pulling F32 bits
860 out of SIMD registers, and there are 16 SIMD registers each of
861 128 bits (4 x F32). */
862 vassert(fregNo < 64);
863 off = doubleGuestRegOffset(fregNo >> 1);
864 if (host_endness == VexEndnessLE) {
865 if (fregNo & 1)
866 off += 4;
867 } else {
868 vassert(0);
870 return off;
873 /* Plain ("low level") read from a VFP Freg. */
874 static IRExpr* llGetFReg ( UInt fregNo )
876 vassert(fregNo < 32);
877 return IRExpr_Get( floatGuestRegOffset(fregNo), Ity_F32 );
880 static IRExpr* llGetFReg_up_to_64 ( UInt fregNo )
882 vassert(fregNo < 64);
883 return IRExpr_Get( floatGuestRegOffset(fregNo), Ity_F32 );
886 /* Architected read from a VFP Freg. */
887 static IRExpr* getFReg ( UInt fregNo ) {
888 return llGetFReg( fregNo );
891 /* Plain ("low level") write to a VFP Freg. */
892 static void llPutFReg ( UInt fregNo, IRExpr* e )
894 vassert(fregNo < 32);
895 vassert(typeOfIRExpr(irsb->tyenv, e) == Ity_F32);
896 stmt( IRStmt_Put(floatGuestRegOffset(fregNo), e) );
899 static void llPutFReg_up_to_64 ( UInt fregNo, IRExpr* e )
901 vassert(fregNo < 64);
902 vassert(typeOfIRExpr(irsb->tyenv, e) == Ity_F32);
903 stmt( IRStmt_Put(floatGuestRegOffset(fregNo), e) );
906 /* Architected write to a VFP Freg. Handles conditional writes to the
907 register: if guardT == IRTemp_INVALID then the write is
908 unconditional. */
909 static void putFReg ( UInt fregNo,
910 IRExpr* e,
911 IRTemp guardT /* :: Ity_I32, 0 or 1 */)
913 /* So, generate either an unconditional or a conditional write to
914 the reg. */
915 if (guardT == IRTemp_INVALID) {
916 /* unconditional write */
917 llPutFReg( fregNo, e );
918 } else {
919 llPutFReg( fregNo,
920 IRExpr_ITE( binop(Iop_CmpNE32, mkexpr(guardT), mkU32(0)),
921 e, llGetFReg(fregNo) ));
926 /* ---------------- Misc registers ---------------- */
928 static void putMiscReg32 ( UInt gsoffset,
929 IRExpr* e, /* :: Ity_I32 */
930 IRTemp guardT /* :: Ity_I32, 0 or 1 */)
932 switch (gsoffset) {
933 case OFFB_FPSCR: break;
934 case OFFB_QFLAG32: break;
935 case OFFB_GEFLAG0: break;
936 case OFFB_GEFLAG1: break;
937 case OFFB_GEFLAG2: break;
938 case OFFB_GEFLAG3: break;
939 case OFFB_TPIDRURW: break;
940 default: vassert(0); /* awaiting more cases */
942 vassert(typeOfIRExpr(irsb->tyenv, e) == Ity_I32);
944 if (guardT == IRTemp_INVALID) {
945 /* unconditional write */
946 stmt(IRStmt_Put(gsoffset, e));
947 } else {
948 stmt(IRStmt_Put(
949 gsoffset,
950 IRExpr_ITE( binop(Iop_CmpNE32, mkexpr(guardT), mkU32(0)),
951 e, IRExpr_Get(gsoffset, Ity_I32) )
956 static IRTemp get_ITSTATE ( void )
958 ASSERT_IS_THUMB;
959 IRTemp t = newTemp(Ity_I32);
960 assign(t, IRExpr_Get( OFFB_ITSTATE, Ity_I32));
961 return t;
964 static void put_ITSTATE ( IRTemp t )
966 ASSERT_IS_THUMB;
967 stmt( IRStmt_Put( OFFB_ITSTATE, mkexpr(t)) );
970 static IRTemp get_QFLAG32 ( void )
972 IRTemp t = newTemp(Ity_I32);
973 assign(t, IRExpr_Get( OFFB_QFLAG32, Ity_I32));
974 return t;
977 static void put_QFLAG32 ( IRTemp t, IRTemp condT )
979 putMiscReg32( OFFB_QFLAG32, mkexpr(t), condT );
982 /* Stickily set the 'Q' flag (APSR bit 27) of the APSR (Application Program
983 Status Register) to indicate that overflow or saturation occurred.
984 Nb: t must be zero to denote no saturation, and any nonzero
985 value to indicate saturation. */
986 static void or_into_QFLAG32 ( IRExpr* e, IRTemp condT )
988 IRTemp old = get_QFLAG32();
989 IRTemp nyu = newTemp(Ity_I32);
990 assign(nyu, binop(Iop_Or32, mkexpr(old), e) );
991 put_QFLAG32(nyu, condT);
994 /* Generate code to set APSR.GE[flagNo]. Each fn call sets 1 bit.
995 flagNo: which flag bit to set [3...0]
996 lowbits_to_ignore: 0 = look at all 32 bits
997 8 = look at top 24 bits only
998 16 = look at top 16 bits only
999 31 = look at the top bit only
1000 e: input value to be evaluated.
1001 The new value is taken from 'e' with the lowest 'lowbits_to_ignore'
1002 masked out. If the resulting value is zero then the GE flag is
1003 set to 0; any other value sets the flag to 1. */
1004 static void put_GEFLAG32 ( Int flagNo, /* 0, 1, 2 or 3 */
1005 Int lowbits_to_ignore, /* 0, 8, 16 or 31 */
1006 IRExpr* e, /* Ity_I32 */
1007 IRTemp condT )
1009 vassert( flagNo >= 0 && flagNo <= 3 );
1010 vassert( lowbits_to_ignore == 0 ||
1011 lowbits_to_ignore == 8 ||
1012 lowbits_to_ignore == 16 ||
1013 lowbits_to_ignore == 31 );
1014 IRTemp masked = newTemp(Ity_I32);
1015 assign(masked, binop(Iop_Shr32, e, mkU8(lowbits_to_ignore)));
1017 switch (flagNo) {
1018 case 0: putMiscReg32(OFFB_GEFLAG0, mkexpr(masked), condT); break;
1019 case 1: putMiscReg32(OFFB_GEFLAG1, mkexpr(masked), condT); break;
1020 case 2: putMiscReg32(OFFB_GEFLAG2, mkexpr(masked), condT); break;
1021 case 3: putMiscReg32(OFFB_GEFLAG3, mkexpr(masked), condT); break;
1022 default: vassert(0);
1026 /* Return the (32-bit, zero-or-nonzero representation scheme) of
1027 the specified GE flag. */
1028 static IRExpr* get_GEFLAG32( Int flagNo /* 0, 1, 2, 3 */ )
1030 switch (flagNo) {
1031 case 0: return IRExpr_Get( OFFB_GEFLAG0, Ity_I32 );
1032 case 1: return IRExpr_Get( OFFB_GEFLAG1, Ity_I32 );
1033 case 2: return IRExpr_Get( OFFB_GEFLAG2, Ity_I32 );
1034 case 3: return IRExpr_Get( OFFB_GEFLAG3, Ity_I32 );
1035 default: vassert(0);
1039 /* Set all 4 GE flags from the given 32-bit value as follows: GE 3 and
1040 2 are set from bit 31 of the value, and GE 1 and 0 are set from bit
1041 15 of the value. All other bits are ignored. */
1042 static void set_GE_32_10_from_bits_31_15 ( IRTemp t32, IRTemp condT )
1044 IRTemp ge10 = newTemp(Ity_I32);
1045 IRTemp ge32 = newTemp(Ity_I32);
1046 assign(ge10, binop(Iop_And32, mkexpr(t32), mkU32(0x00008000)));
1047 assign(ge32, binop(Iop_And32, mkexpr(t32), mkU32(0x80000000)));
1048 put_GEFLAG32( 0, 0, mkexpr(ge10), condT );
1049 put_GEFLAG32( 1, 0, mkexpr(ge10), condT );
1050 put_GEFLAG32( 2, 0, mkexpr(ge32), condT );
1051 put_GEFLAG32( 3, 0, mkexpr(ge32), condT );
1055 /* Set all 4 GE flags from the given 32-bit value as follows: GE 3
1056 from bit 31, GE 2 from bit 23, GE 1 from bit 15, and GE0 from
1057 bit 7. All other bits are ignored. */
1058 static void set_GE_3_2_1_0_from_bits_31_23_15_7 ( IRTemp t32, IRTemp condT )
1060 IRTemp ge0 = newTemp(Ity_I32);
1061 IRTemp ge1 = newTemp(Ity_I32);
1062 IRTemp ge2 = newTemp(Ity_I32);
1063 IRTemp ge3 = newTemp(Ity_I32);
1064 assign(ge0, binop(Iop_And32, mkexpr(t32), mkU32(0x00000080)));
1065 assign(ge1, binop(Iop_And32, mkexpr(t32), mkU32(0x00008000)));
1066 assign(ge2, binop(Iop_And32, mkexpr(t32), mkU32(0x00800000)));
1067 assign(ge3, binop(Iop_And32, mkexpr(t32), mkU32(0x80000000)));
1068 put_GEFLAG32( 0, 0, mkexpr(ge0), condT );
1069 put_GEFLAG32( 1, 0, mkexpr(ge1), condT );
1070 put_GEFLAG32( 2, 0, mkexpr(ge2), condT );
1071 put_GEFLAG32( 3, 0, mkexpr(ge3), condT );
1075 /* ---------------- FPSCR stuff ---------------- */
1077 /* Generate IR to get hold of the rounding mode bits in FPSCR, and
1078 convert them to IR format. Bind the final result to the
1079 returned temp. */
1080 static IRTemp /* :: Ity_I32 */ mk_get_IR_rounding_mode ( void )
1082 /* The ARMvfp encoding for rounding mode bits is:
1083 00 to nearest
1084 01 to +infinity
1085 10 to -infinity
1086 11 to zero
1087 We need to convert that to the IR encoding:
1088 00 to nearest (the default)
1089 10 to +infinity
1090 01 to -infinity
1091 11 to zero
1092 Which can be done by swapping bits 0 and 1.
1093 The rmode bits are at 23:22 in FPSCR.
1095 IRTemp armEncd = newTemp(Ity_I32);
1096 IRTemp swapped = newTemp(Ity_I32);
1097 /* Fish FPSCR[23:22] out, and slide to bottom. Doesn't matter that
1098 we don't zero out bits 24 and above, since the assignment to
1099 'swapped' will mask them out anyway. */
1100 assign(armEncd,
1101 binop(Iop_Shr32, IRExpr_Get(OFFB_FPSCR, Ity_I32), mkU8(22)));
1102 /* Now swap them. */
1103 assign(swapped,
1104 binop(Iop_Or32,
1105 binop(Iop_And32,
1106 binop(Iop_Shl32, mkexpr(armEncd), mkU8(1)),
1107 mkU32(2)),
1108 binop(Iop_And32,
1109 binop(Iop_Shr32, mkexpr(armEncd), mkU8(1)),
1110 mkU32(1))
1112 return swapped;
1116 /*------------------------------------------------------------*/
1117 /*--- Helpers for flag handling and conditional insns ---*/
1118 /*------------------------------------------------------------*/
1120 static const HChar* name_ARMCondcode ( ARMCondcode cond )
1122 switch (cond) {
1123 case ARMCondEQ: return "{eq}";
1124 case ARMCondNE: return "{ne}";
1125 case ARMCondHS: return "{hs}"; // or 'cs'
1126 case ARMCondLO: return "{lo}"; // or 'cc'
1127 case ARMCondMI: return "{mi}";
1128 case ARMCondPL: return "{pl}";
1129 case ARMCondVS: return "{vs}";
1130 case ARMCondVC: return "{vc}";
1131 case ARMCondHI: return "{hi}";
1132 case ARMCondLS: return "{ls}";
1133 case ARMCondGE: return "{ge}";
1134 case ARMCondLT: return "{lt}";
1135 case ARMCondGT: return "{gt}";
1136 case ARMCondLE: return "{le}";
1137 case ARMCondAL: return ""; // {al}: is the default
1138 case ARMCondNV: return "{nv}";
1139 default: vpanic("name_ARMCondcode");
1142 /* and a handy shorthand for it */
1143 static const HChar* nCC ( ARMCondcode cond ) {
1144 return name_ARMCondcode(cond);
1148 /* Build IR to calculate some particular condition from stored
1149 CC_OP/CC_DEP1/CC_DEP2/CC_NDEP. Returns an expression of type
1150 Ity_I32, suitable for narrowing. Although the return type is
1151 Ity_I32, the returned value is either 0 or 1. 'cond' must be
1152 :: Ity_I32 and must denote the condition to compute in
1153 bits 7:4, and be zero everywhere else.
1155 static IRExpr* mk_armg_calculate_condition_dyn ( IRExpr* cond )
1157 vassert(typeOfIRExpr(irsb->tyenv, cond) == Ity_I32);
1158 /* And 'cond' had better produce a value in which only bits 7:4 are
1159 nonzero. However, obviously we can't assert for that. */
1161 /* So what we're constructing for the first argument is
1162 "(cond << 4) | stored-operation".
1163 However, as per comments above, 'cond' must be supplied
1164 pre-shifted to this function.
1166 This pairing scheme requires that the ARM_CC_OP_ values all fit
1167 in 4 bits. Hence we are passing a (COND, OP) pair in the lowest
1168 8 bits of the first argument. */
1169 IRExpr** args
1170 = mkIRExprVec_4(
1171 binop(Iop_Or32, IRExpr_Get(OFFB_CC_OP, Ity_I32), cond),
1172 IRExpr_Get(OFFB_CC_DEP1, Ity_I32),
1173 IRExpr_Get(OFFB_CC_DEP2, Ity_I32),
1174 IRExpr_Get(OFFB_CC_NDEP, Ity_I32)
1176 IRExpr* call
1177 = mkIRExprCCall(
1178 Ity_I32,
1179 0/*regparm*/,
1180 "armg_calculate_condition", &armg_calculate_condition,
1181 args
1184 /* Exclude the requested condition, OP and NDEP from definedness
1185 checking. We're only interested in DEP1 and DEP2. */
1186 call->Iex.CCall.cee->mcx_mask = (1<<0) | (1<<3);
1187 return call;
1191 /* Build IR to calculate some particular condition from stored
1192 CC_OP/CC_DEP1/CC_DEP2/CC_NDEP. Returns an expression of type
1193 Ity_I32, suitable for narrowing. Although the return type is
1194 Ity_I32, the returned value is either 0 or 1.
1196 static IRExpr* mk_armg_calculate_condition ( ARMCondcode cond )
1198 /* First arg is "(cond << 4) | condition". This requires that the
1199 ARM_CC_OP_ values all fit in 4 bits. Hence we are passing a
1200 (COND, OP) pair in the lowest 8 bits of the first argument. */
1201 vassert(cond >= 0 && cond <= 15);
1202 return mk_armg_calculate_condition_dyn( mkU32(cond << 4) );
1206 /* Build IR to calculate just the carry flag from stored
1207 CC_OP/CC_DEP1/CC_DEP2/CC_NDEP. Returns an expression ::
1208 Ity_I32. */
1209 static IRExpr* mk_armg_calculate_flag_c ( void )
1211 IRExpr** args
1212 = mkIRExprVec_4( IRExpr_Get(OFFB_CC_OP, Ity_I32),
1213 IRExpr_Get(OFFB_CC_DEP1, Ity_I32),
1214 IRExpr_Get(OFFB_CC_DEP2, Ity_I32),
1215 IRExpr_Get(OFFB_CC_NDEP, Ity_I32) );
1216 IRExpr* call
1217 = mkIRExprCCall(
1218 Ity_I32,
1219 0/*regparm*/,
1220 "armg_calculate_flag_c", &armg_calculate_flag_c,
1221 args
1223 /* Exclude OP and NDEP from definedness checking. We're only
1224 interested in DEP1 and DEP2. */
1225 call->Iex.CCall.cee->mcx_mask = (1<<0) | (1<<3);
1226 return call;
1230 /* Build IR to calculate just the overflow flag from stored
1231 CC_OP/CC_DEP1/CC_DEP2/CC_NDEP. Returns an expression ::
1232 Ity_I32. */
1233 static IRExpr* mk_armg_calculate_flag_v ( void )
1235 IRExpr** args
1236 = mkIRExprVec_4( IRExpr_Get(OFFB_CC_OP, Ity_I32),
1237 IRExpr_Get(OFFB_CC_DEP1, Ity_I32),
1238 IRExpr_Get(OFFB_CC_DEP2, Ity_I32),
1239 IRExpr_Get(OFFB_CC_NDEP, Ity_I32) );
1240 IRExpr* call
1241 = mkIRExprCCall(
1242 Ity_I32,
1243 0/*regparm*/,
1244 "armg_calculate_flag_v", &armg_calculate_flag_v,
1245 args
1247 /* Exclude OP and NDEP from definedness checking. We're only
1248 interested in DEP1 and DEP2. */
1249 call->Iex.CCall.cee->mcx_mask = (1<<0) | (1<<3);
1250 return call;
1254 /* Build IR to calculate N Z C V in bits 31:28 of the
1255 returned word. */
1256 static IRExpr* mk_armg_calculate_flags_nzcv ( void )
1258 IRExpr** args
1259 = mkIRExprVec_4( IRExpr_Get(OFFB_CC_OP, Ity_I32),
1260 IRExpr_Get(OFFB_CC_DEP1, Ity_I32),
1261 IRExpr_Get(OFFB_CC_DEP2, Ity_I32),
1262 IRExpr_Get(OFFB_CC_NDEP, Ity_I32) );
1263 IRExpr* call
1264 = mkIRExprCCall(
1265 Ity_I32,
1266 0/*regparm*/,
1267 "armg_calculate_flags_nzcv", &armg_calculate_flags_nzcv,
1268 args
1270 /* Exclude OP and NDEP from definedness checking. We're only
1271 interested in DEP1 and DEP2. */
1272 call->Iex.CCall.cee->mcx_mask = (1<<0) | (1<<3);
1273 return call;
1276 static IRExpr* mk_armg_calculate_flag_qc ( IRExpr* resL, IRExpr* resR, Bool Q )
1278 IRExpr** args1;
1279 IRExpr** args2;
1280 IRExpr *call1, *call2, *res;
1282 if (Q) {
1283 args1 = mkIRExprVec_4 ( binop(Iop_GetElem32x4, resL, mkU8(0)),
1284 binop(Iop_GetElem32x4, resL, mkU8(1)),
1285 binop(Iop_GetElem32x4, resR, mkU8(0)),
1286 binop(Iop_GetElem32x4, resR, mkU8(1)) );
1287 args2 = mkIRExprVec_4 ( binop(Iop_GetElem32x4, resL, mkU8(2)),
1288 binop(Iop_GetElem32x4, resL, mkU8(3)),
1289 binop(Iop_GetElem32x4, resR, mkU8(2)),
1290 binop(Iop_GetElem32x4, resR, mkU8(3)) );
1291 } else {
1292 args1 = mkIRExprVec_4 ( binop(Iop_GetElem32x2, resL, mkU8(0)),
1293 binop(Iop_GetElem32x2, resL, mkU8(1)),
1294 binop(Iop_GetElem32x2, resR, mkU8(0)),
1295 binop(Iop_GetElem32x2, resR, mkU8(1)) );
1298 call1 = mkIRExprCCall(
1299 Ity_I32,
1300 0/*regparm*/,
1301 "armg_calculate_flag_qc", &armg_calculate_flag_qc,
1302 args1
1304 if (Q) {
1305 call2 = mkIRExprCCall(
1306 Ity_I32,
1307 0/*regparm*/,
1308 "armg_calculate_flag_qc", &armg_calculate_flag_qc,
1309 args2
1312 if (Q) {
1313 res = binop(Iop_Or32, call1, call2);
1314 } else {
1315 res = call1;
1317 return res;
1320 // FIXME: this is named wrongly .. looks like a sticky set of
1321 // QC, not a write to it.
1322 static void setFlag_QC ( IRExpr* resL, IRExpr* resR, Bool Q,
1323 IRTemp condT )
1325 putMiscReg32 (OFFB_FPSCR,
1326 binop(Iop_Or32,
1327 IRExpr_Get(OFFB_FPSCR, Ity_I32),
1328 binop(Iop_Shl32,
1329 mk_armg_calculate_flag_qc(resL, resR, Q),
1330 mkU8(27))),
1331 condT);
1334 /* Build IR to conditionally set the flags thunk. As with putIReg, if
1335 guard is IRTemp_INVALID then it's unconditional, else it holds a
1336 condition :: Ity_I32. */
1337 static
1338 void setFlags_D1_D2_ND ( UInt cc_op, IRTemp t_dep1,
1339 IRTemp t_dep2, IRTemp t_ndep,
1340 IRTemp guardT /* :: Ity_I32, 0 or 1 */ )
1342 vassert(typeOfIRTemp(irsb->tyenv, t_dep1 == Ity_I32));
1343 vassert(typeOfIRTemp(irsb->tyenv, t_dep2 == Ity_I32));
1344 vassert(typeOfIRTemp(irsb->tyenv, t_ndep == Ity_I32));
1345 vassert(cc_op >= ARMG_CC_OP_COPY && cc_op < ARMG_CC_OP_NUMBER);
1346 if (guardT == IRTemp_INVALID) {
1347 /* unconditional */
1348 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(cc_op) ));
1349 stmt( IRStmt_Put( OFFB_CC_DEP1, mkexpr(t_dep1) ));
1350 stmt( IRStmt_Put( OFFB_CC_DEP2, mkexpr(t_dep2) ));
1351 stmt( IRStmt_Put( OFFB_CC_NDEP, mkexpr(t_ndep) ));
1352 } else {
1353 /* conditional */
1354 IRTemp c1 = newTemp(Ity_I1);
1355 assign( c1, binop(Iop_CmpNE32, mkexpr(guardT), mkU32(0)) );
1356 stmt( IRStmt_Put(
1357 OFFB_CC_OP,
1358 IRExpr_ITE( mkexpr(c1),
1359 mkU32(cc_op),
1360 IRExpr_Get(OFFB_CC_OP, Ity_I32) ) ));
1361 stmt( IRStmt_Put(
1362 OFFB_CC_DEP1,
1363 IRExpr_ITE( mkexpr(c1),
1364 mkexpr(t_dep1),
1365 IRExpr_Get(OFFB_CC_DEP1, Ity_I32) ) ));
1366 stmt( IRStmt_Put(
1367 OFFB_CC_DEP2,
1368 IRExpr_ITE( mkexpr(c1),
1369 mkexpr(t_dep2),
1370 IRExpr_Get(OFFB_CC_DEP2, Ity_I32) ) ));
1371 stmt( IRStmt_Put(
1372 OFFB_CC_NDEP,
1373 IRExpr_ITE( mkexpr(c1),
1374 mkexpr(t_ndep),
1375 IRExpr_Get(OFFB_CC_NDEP, Ity_I32) ) ));
1380 /* Minor variant of the above that sets NDEP to zero (if it
1381 sets it at all) */
1382 static void setFlags_D1_D2 ( UInt cc_op, IRTemp t_dep1,
1383 IRTemp t_dep2,
1384 IRTemp guardT /* :: Ity_I32, 0 or 1 */ )
1386 IRTemp z32 = newTemp(Ity_I32);
1387 assign( z32, mkU32(0) );
1388 setFlags_D1_D2_ND( cc_op, t_dep1, t_dep2, z32, guardT );
1392 /* Minor variant of the above that sets DEP2 to zero (if it
1393 sets it at all) */
1394 static void setFlags_D1_ND ( UInt cc_op, IRTemp t_dep1,
1395 IRTemp t_ndep,
1396 IRTemp guardT /* :: Ity_I32, 0 or 1 */ )
1398 IRTemp z32 = newTemp(Ity_I32);
1399 assign( z32, mkU32(0) );
1400 setFlags_D1_D2_ND( cc_op, t_dep1, z32, t_ndep, guardT );
1404 /* Minor variant of the above that sets DEP2 and NDEP to zero (if it
1405 sets them at all) */
1406 static void setFlags_D1 ( UInt cc_op, IRTemp t_dep1,
1407 IRTemp guardT /* :: Ity_I32, 0 or 1 */ )
1409 IRTemp z32 = newTemp(Ity_I32);
1410 assign( z32, mkU32(0) );
1411 setFlags_D1_D2_ND( cc_op, t_dep1, z32, z32, guardT );
1415 /* ARM only */
1416 /* Generate a side-exit to the next instruction, if the given guard
1417 expression :: Ity_I32 is 0 (note! the side exit is taken if the
1418 condition is false!) This is used to skip over conditional
1419 instructions which we can't generate straight-line code for, either
1420 because they are too complex or (more likely) they potentially
1421 generate exceptions.
1423 static void mk_skip_over_A32_if_cond_is_false (
1424 IRTemp guardT /* :: Ity_I32, 0 or 1 */
1427 ASSERT_IS_ARM;
1428 vassert(guardT != IRTemp_INVALID);
1429 vassert(0 == (guest_R15_curr_instr_notENC & 3));
1430 stmt( IRStmt_Exit(
1431 unop(Iop_Not1, unop(Iop_32to1, mkexpr(guardT))),
1432 Ijk_Boring,
1433 IRConst_U32(toUInt(guest_R15_curr_instr_notENC + 4)),
1434 OFFB_R15T
1438 /* Thumb16 only */
1439 /* ditto, but jump over a 16-bit thumb insn */
1440 static void mk_skip_over_T16_if_cond_is_false (
1441 IRTemp guardT /* :: Ity_I32, 0 or 1 */
1444 ASSERT_IS_THUMB;
1445 vassert(guardT != IRTemp_INVALID);
1446 vassert(0 == (guest_R15_curr_instr_notENC & 1));
1447 stmt( IRStmt_Exit(
1448 unop(Iop_Not1, unop(Iop_32to1, mkexpr(guardT))),
1449 Ijk_Boring,
1450 IRConst_U32(toUInt((guest_R15_curr_instr_notENC + 2) | 1)),
1451 OFFB_R15T
1456 /* Thumb32 only */
1457 /* ditto, but jump over a 32-bit thumb insn */
1458 static void mk_skip_over_T32_if_cond_is_false (
1459 IRTemp guardT /* :: Ity_I32, 0 or 1 */
1462 ASSERT_IS_THUMB;
1463 vassert(guardT != IRTemp_INVALID);
1464 vassert(0 == (guest_R15_curr_instr_notENC & 1));
1465 stmt( IRStmt_Exit(
1466 unop(Iop_Not1, unop(Iop_32to1, mkexpr(guardT))),
1467 Ijk_Boring,
1468 IRConst_U32(toUInt((guest_R15_curr_instr_notENC + 4) | 1)),
1469 OFFB_R15T
1474 /* Thumb16 and Thumb32 only
1475 Generate a SIGILL followed by a restart of the current instruction
1476 if the given temp is nonzero. */
1477 static void gen_SIGILL_T_if_nonzero ( IRTemp t /* :: Ity_I32 */ )
1479 ASSERT_IS_THUMB;
1480 vassert(t != IRTemp_INVALID);
1481 vassert(0 == (guest_R15_curr_instr_notENC & 1));
1482 stmt(
1483 IRStmt_Exit(
1484 binop(Iop_CmpNE32, mkexpr(t), mkU32(0)),
1485 Ijk_NoDecode,
1486 IRConst_U32(toUInt(guest_R15_curr_instr_notENC | 1)),
1487 OFFB_R15T
1493 /* Inspect the old_itstate, and generate a SIGILL if it indicates that
1494 we are currently in an IT block and are not the last in the block.
1495 This also rolls back guest_ITSTATE to its old value before the exit
1496 and restores it to its new value afterwards. This is so that if
1497 the exit is taken, we have an up to date version of ITSTATE
1498 available. Without doing that, we have no hope of making precise
1499 exceptions work. */
1500 static void gen_SIGILL_T_if_in_but_NLI_ITBlock (
1501 IRTemp old_itstate /* :: Ity_I32 */,
1502 IRTemp new_itstate /* :: Ity_I32 */
1505 ASSERT_IS_THUMB;
1506 put_ITSTATE(old_itstate); // backout
1507 IRTemp guards_for_next3 = newTemp(Ity_I32);
1508 assign(guards_for_next3,
1509 binop(Iop_Shr32, mkexpr(old_itstate), mkU8(8)));
1510 gen_SIGILL_T_if_nonzero(guards_for_next3);
1511 put_ITSTATE(new_itstate); //restore
1515 /* Simpler version of the above, which generates a SIGILL if
1516 we're anywhere within an IT block. */
1517 static void gen_SIGILL_T_if_in_ITBlock (
1518 IRTemp old_itstate /* :: Ity_I32 */,
1519 IRTemp new_itstate /* :: Ity_I32 */
1522 put_ITSTATE(old_itstate); // backout
1523 gen_SIGILL_T_if_nonzero(old_itstate);
1524 put_ITSTATE(new_itstate); //restore
1528 /* Generate an APSR value, from the NZCV thunk, and
1529 from QFLAG32 and GEFLAG0 .. GEFLAG3. */
1530 static IRTemp synthesise_APSR ( void )
1532 IRTemp res1 = newTemp(Ity_I32);
1533 // Get NZCV
1534 assign( res1, mk_armg_calculate_flags_nzcv() );
1535 // OR in the Q value
1536 IRTemp res2 = newTemp(Ity_I32);
1537 assign(
1538 res2,
1539 binop(Iop_Or32,
1540 mkexpr(res1),
1541 binop(Iop_Shl32,
1542 unop(Iop_1Uto32,
1543 binop(Iop_CmpNE32,
1544 mkexpr(get_QFLAG32()),
1545 mkU32(0))),
1546 mkU8(ARMG_CC_SHIFT_Q)))
1548 // OR in GE0 .. GE3
1549 IRExpr* ge0
1550 = unop(Iop_1Uto32, binop(Iop_CmpNE32, get_GEFLAG32(0), mkU32(0)));
1551 IRExpr* ge1
1552 = unop(Iop_1Uto32, binop(Iop_CmpNE32, get_GEFLAG32(1), mkU32(0)));
1553 IRExpr* ge2
1554 = unop(Iop_1Uto32, binop(Iop_CmpNE32, get_GEFLAG32(2), mkU32(0)));
1555 IRExpr* ge3
1556 = unop(Iop_1Uto32, binop(Iop_CmpNE32, get_GEFLAG32(3), mkU32(0)));
1557 IRTemp res3 = newTemp(Ity_I32);
1558 assign(res3,
1559 binop(Iop_Or32,
1560 mkexpr(res2),
1561 binop(Iop_Or32,
1562 binop(Iop_Or32,
1563 binop(Iop_Shl32, ge0, mkU8(16)),
1564 binop(Iop_Shl32, ge1, mkU8(17))),
1565 binop(Iop_Or32,
1566 binop(Iop_Shl32, ge2, mkU8(18)),
1567 binop(Iop_Shl32, ge3, mkU8(19))) )));
1568 return res3;
1572 /* and the inverse transformation: given an APSR value,
1573 set the NZCV thunk, the Q flag, and the GE flags. */
1574 static void desynthesise_APSR ( Bool write_nzcvq, Bool write_ge,
1575 IRTemp apsrT, IRTemp condT )
1577 vassert(write_nzcvq || write_ge);
1578 if (write_nzcvq) {
1579 // Do NZCV
1580 IRTemp immT = newTemp(Ity_I32);
1581 assign(immT, binop(Iop_And32, mkexpr(apsrT), mkU32(0xF0000000)) );
1582 setFlags_D1(ARMG_CC_OP_COPY, immT, condT);
1583 // Do Q
1584 IRTemp qnewT = newTemp(Ity_I32);
1585 assign(qnewT, binop(Iop_And32, mkexpr(apsrT), mkU32(ARMG_CC_MASK_Q)));
1586 put_QFLAG32(qnewT, condT);
1588 if (write_ge) {
1589 // Do GE3..0
1590 put_GEFLAG32(0, 0, binop(Iop_And32, mkexpr(apsrT), mkU32(1<<16)),
1591 condT);
1592 put_GEFLAG32(1, 0, binop(Iop_And32, mkexpr(apsrT), mkU32(1<<17)),
1593 condT);
1594 put_GEFLAG32(2, 0, binop(Iop_And32, mkexpr(apsrT), mkU32(1<<18)),
1595 condT);
1596 put_GEFLAG32(3, 0, binop(Iop_And32, mkexpr(apsrT), mkU32(1<<19)),
1597 condT);
1602 /*------------------------------------------------------------*/
1603 /*--- Helpers for saturation ---*/
1604 /*------------------------------------------------------------*/
1606 /* FIXME: absolutely the only diff. between (a) armUnsignedSatQ and
1607 (b) armSignedSatQ is that in (a) the floor is set to 0, whereas in
1608 (b) the floor is computed from the value of imm5. these two fnsn
1609 should be commoned up. */
1611 /* UnsignedSatQ(): 'clamp' each value so it lies between 0 <= x <= (2^N)-1
1612 Optionally return flag resQ saying whether saturation occurred.
1613 See definition in manual, section A2.2.1, page 41
1614 (bits(N), boolean) UnsignedSatQ( integer i, integer N )
1616 if ( i > (2^N)-1 ) { result = (2^N)-1; saturated = TRUE; }
1617 elsif ( i < 0 ) { result = 0; saturated = TRUE; }
1618 else { result = i; saturated = FALSE; }
1619 return ( result<N-1:0>, saturated );
1622 static void armUnsignedSatQ( IRTemp* res, /* OUT - Ity_I32 */
1623 IRTemp* resQ, /* OUT - Ity_I32 */
1624 IRTemp regT, /* value to clamp - Ity_I32 */
1625 UInt imm5 ) /* saturation ceiling */
1627 ULong ceil64 = (1ULL << imm5) - 1; // (2^imm5)-1
1628 UInt ceil = (UInt)ceil64;
1629 UInt floor = 0;
1631 IRTemp nd0 = newTemp(Ity_I32);
1632 IRTemp nd1 = newTemp(Ity_I32);
1633 IRTemp nd2 = newTemp(Ity_I1);
1634 IRTemp nd3 = newTemp(Ity_I32);
1635 IRTemp nd4 = newTemp(Ity_I32);
1636 IRTemp nd5 = newTemp(Ity_I1);
1637 IRTemp nd6 = newTemp(Ity_I32);
1639 assign( nd0, mkexpr(regT) );
1640 assign( nd1, mkU32(ceil) );
1641 assign( nd2, binop( Iop_CmpLT32S, mkexpr(nd1), mkexpr(nd0) ) );
1642 assign( nd3, IRExpr_ITE(mkexpr(nd2), mkexpr(nd1), mkexpr(nd0)) );
1643 assign( nd4, mkU32(floor) );
1644 assign( nd5, binop( Iop_CmpLT32S, mkexpr(nd3), mkexpr(nd4) ) );
1645 assign( nd6, IRExpr_ITE(mkexpr(nd5), mkexpr(nd4), mkexpr(nd3)) );
1646 assign( *res, mkexpr(nd6) );
1648 /* if saturation occurred, then resQ is set to some nonzero value
1649 if sat did not occur, resQ is guaranteed to be zero. */
1650 if (resQ) {
1651 assign( *resQ, binop(Iop_Xor32, mkexpr(*res), mkexpr(regT)) );
1656 /* SignedSatQ(): 'clamp' each value so it lies between -2^N <= x <= (2^N) - 1
1657 Optionally return flag resQ saying whether saturation occurred.
1658 - see definition in manual, section A2.2.1, page 41
1659 (bits(N), boolean ) SignedSatQ( integer i, integer N )
1661 if ( i > 2^(N-1) - 1 ) { result = 2^(N-1) - 1; saturated = TRUE; }
1662 elsif ( i < -(2^(N-1)) ) { result = -(2^(N-1)); saturated = FALSE; }
1663 else { result = i; saturated = FALSE; }
1664 return ( result[N-1:0], saturated );
1667 static void armSignedSatQ( IRTemp regT, /* value to clamp - Ity_I32 */
1668 UInt imm5, /* saturation ceiling */
1669 IRTemp* res, /* OUT - Ity_I32 */
1670 IRTemp* resQ ) /* OUT - Ity_I32 */
1672 Long ceil64 = (1LL << (imm5-1)) - 1; // (2^(imm5-1))-1
1673 Long floor64 = -(1LL << (imm5-1)); // -(2^(imm5-1))
1674 Int ceil = (Int)ceil64;
1675 Int floor = (Int)floor64;
1677 IRTemp nd0 = newTemp(Ity_I32);
1678 IRTemp nd1 = newTemp(Ity_I32);
1679 IRTemp nd2 = newTemp(Ity_I1);
1680 IRTemp nd3 = newTemp(Ity_I32);
1681 IRTemp nd4 = newTemp(Ity_I32);
1682 IRTemp nd5 = newTemp(Ity_I1);
1683 IRTemp nd6 = newTemp(Ity_I32);
1685 assign( nd0, mkexpr(regT) );
1686 assign( nd1, mkU32(ceil) );
1687 assign( nd2, binop( Iop_CmpLT32S, mkexpr(nd1), mkexpr(nd0) ) );
1688 assign( nd3, IRExpr_ITE( mkexpr(nd2), mkexpr(nd1), mkexpr(nd0) ) );
1689 assign( nd4, mkU32(floor) );
1690 assign( nd5, binop( Iop_CmpLT32S, mkexpr(nd3), mkexpr(nd4) ) );
1691 assign( nd6, IRExpr_ITE( mkexpr(nd5), mkexpr(nd4), mkexpr(nd3) ) );
1692 assign( *res, mkexpr(nd6) );
1694 /* if saturation occurred, then resQ is set to some nonzero value
1695 if sat did not occur, resQ is guaranteed to be zero. */
1696 if (resQ) {
1697 assign( *resQ, binop(Iop_Xor32, mkexpr(*res), mkexpr(regT)) );
1702 /* Compute a value 0 :: I32 or 1 :: I32, indicating whether signed
1703 overflow occurred for 32-bit addition. Needs both args and the
1704 result. HD p27. */
1705 static
1706 IRExpr* signed_overflow_after_Add32 ( IRExpr* resE,
1707 IRTemp argL, IRTemp argR )
1709 IRTemp res = newTemp(Ity_I32);
1710 assign(res, resE);
1711 return
1712 binop( Iop_Shr32,
1713 binop( Iop_And32,
1714 binop( Iop_Xor32, mkexpr(res), mkexpr(argL) ),
1715 binop( Iop_Xor32, mkexpr(res), mkexpr(argR) )),
1716 mkU8(31) );
1719 /* Similarly .. also from HD p27 .. */
1720 static
1721 IRExpr* signed_overflow_after_Sub32 ( IRExpr* resE,
1722 IRTemp argL, IRTemp argR )
1724 IRTemp res = newTemp(Ity_I32);
1725 assign(res, resE);
1726 return
1727 binop( Iop_Shr32,
1728 binop( Iop_And32,
1729 binop( Iop_Xor32, mkexpr(argL), mkexpr(argR) ),
1730 binop( Iop_Xor32, mkexpr(res), mkexpr(argL) )),
1731 mkU8(31) );
1735 /*------------------------------------------------------------*/
1736 /*--- Larger helpers ---*/
1737 /*------------------------------------------------------------*/
1739 /* Compute both the result and new C flag value for a LSL by an imm5
1740 or by a register operand. May generate reads of the old C value
1741 (hence only safe to use before any writes to guest state happen).
1742 Are factored out so can be used by both ARM and Thumb.
1744 Note that in compute_result_and_C_after_{LSL,LSR,ASR}_by{imm5,reg},
1745 "res" (the result) is a.k.a. "shop", shifter operand
1746 "newC" (the new C) is a.k.a. "shco", shifter carry out
1748 The calling convention for res and newC is a bit funny. They could
1749 be passed by value, but instead are passed by ref.
1751 The C (shco) value computed must be zero in bits 31:1, as the IR
1752 optimisations for flag handling (guest_arm_spechelper) rely on
1753 that, and the slow-path handlers (armg_calculate_flags_nzcv) assert
1754 for it. Same applies to all these functions that compute shco
1755 after a shift or rotate, not just this one.
1758 static void compute_result_and_C_after_LSL_by_imm5 (
1759 /*OUT*/HChar* buf,
1760 IRTemp* res,
1761 IRTemp* newC,
1762 IRTemp rMt, UInt shift_amt, /* operands */
1763 UInt rM /* only for debug printing */
1766 if (shift_amt == 0) {
1767 if (newC) {
1768 assign( *newC, mk_armg_calculate_flag_c() );
1770 assign( *res, mkexpr(rMt) );
1771 DIS(buf, "r%u", rM);
1772 } else {
1773 vassert(shift_amt >= 1 && shift_amt <= 31);
1774 if (newC) {
1775 assign( *newC,
1776 binop(Iop_And32,
1777 binop(Iop_Shr32, mkexpr(rMt),
1778 mkU8(32 - shift_amt)),
1779 mkU32(1)));
1781 assign( *res,
1782 binop(Iop_Shl32, mkexpr(rMt), mkU8(shift_amt)) );
1783 DIS(buf, "r%u, LSL #%u", rM, shift_amt);
1788 static void compute_result_and_C_after_LSL_by_reg (
1789 /*OUT*/HChar* buf,
1790 IRTemp* res,
1791 IRTemp* newC,
1792 IRTemp rMt, IRTemp rSt, /* operands */
1793 UInt rM, UInt rS /* only for debug printing */
1796 // shift left in range 0 .. 255
1797 // amt = rS & 255
1798 // res = amt < 32 ? Rm << amt : 0
1799 // newC = amt == 0 ? oldC :
1800 // amt in 1..32 ? Rm[32-amt] : 0
1801 IRTemp amtT = newTemp(Ity_I32);
1802 assign( amtT, binop(Iop_And32, mkexpr(rSt), mkU32(255)) );
1803 if (newC) {
1804 /* mux0X(amt == 0,
1805 mux0X(amt < 32,
1807 Rm[(32-amt) & 31]),
1808 oldC)
1810 /* About the best you can do is pray that iropt is able
1811 to nuke most or all of the following junk. */
1812 IRTemp oldC = newTemp(Ity_I32);
1813 assign(oldC, mk_armg_calculate_flag_c() );
1814 assign(
1815 *newC,
1816 IRExpr_ITE(
1817 binop(Iop_CmpEQ32, mkexpr(amtT), mkU32(0)),
1818 mkexpr(oldC),
1819 IRExpr_ITE(
1820 binop(Iop_CmpLE32U, mkexpr(amtT), mkU32(32)),
1821 binop(Iop_And32,
1822 binop(Iop_Shr32,
1823 mkexpr(rMt),
1824 unop(Iop_32to8,
1825 binop(Iop_And32,
1826 binop(Iop_Sub32,
1827 mkU32(32),
1828 mkexpr(amtT)),
1829 mkU32(31)
1833 mkU32(1)
1835 mkU32(0)
1840 // (Rm << (Rs & 31)) & (((Rs & 255) - 32) >>s 31)
1841 // Lhs of the & limits the shift to 31 bits, so as to
1842 // give known IR semantics. Rhs of the & is all 1s for
1843 // Rs <= 31 and all 0s for Rs >= 32.
1844 assign(
1845 *res,
1846 binop(
1847 Iop_And32,
1848 binop(Iop_Shl32,
1849 mkexpr(rMt),
1850 unop(Iop_32to8,
1851 binop(Iop_And32, mkexpr(rSt), mkU32(31)))),
1852 binop(Iop_Sar32,
1853 binop(Iop_Sub32,
1854 mkexpr(amtT),
1855 mkU32(32)),
1856 mkU8(31))));
1857 DIS(buf, "r%u, LSL r%u", rM, rS);
1861 static void compute_result_and_C_after_LSR_by_imm5 (
1862 /*OUT*/HChar* buf,
1863 IRTemp* res,
1864 IRTemp* newC,
1865 IRTemp rMt, UInt shift_amt, /* operands */
1866 UInt rM /* only for debug printing */
1869 if (shift_amt == 0) {
1870 // conceptually a 32-bit shift, however:
1871 // res = 0
1872 // newC = Rm[31]
1873 if (newC) {
1874 assign( *newC,
1875 binop(Iop_And32,
1876 binop(Iop_Shr32, mkexpr(rMt), mkU8(31)),
1877 mkU32(1)));
1879 assign( *res, mkU32(0) );
1880 DIS(buf, "r%u, LSR #0(a.k.a. 32)", rM);
1881 } else {
1882 // shift in range 1..31
1883 // res = Rm >>u shift_amt
1884 // newC = Rm[shift_amt - 1]
1885 vassert(shift_amt >= 1 && shift_amt <= 31);
1886 if (newC) {
1887 assign( *newC,
1888 binop(Iop_And32,
1889 binop(Iop_Shr32, mkexpr(rMt),
1890 mkU8(shift_amt - 1)),
1891 mkU32(1)));
1893 assign( *res,
1894 binop(Iop_Shr32, mkexpr(rMt), mkU8(shift_amt)) );
1895 DIS(buf, "r%u, LSR #%u", rM, shift_amt);
1900 static void compute_result_and_C_after_LSR_by_reg (
1901 /*OUT*/HChar* buf,
1902 IRTemp* res,
1903 IRTemp* newC,
1904 IRTemp rMt, IRTemp rSt, /* operands */
1905 UInt rM, UInt rS /* only for debug printing */
1908 // shift right in range 0 .. 255
1909 // amt = rS & 255
1910 // res = amt < 32 ? Rm >>u amt : 0
1911 // newC = amt == 0 ? oldC :
1912 // amt in 1..32 ? Rm[amt-1] : 0
1913 IRTemp amtT = newTemp(Ity_I32);
1914 assign( amtT, binop(Iop_And32, mkexpr(rSt), mkU32(255)) );
1915 if (newC) {
1916 /* mux0X(amt == 0,
1917 mux0X(amt < 32,
1919 Rm[(amt-1) & 31]),
1920 oldC)
1922 IRTemp oldC = newTemp(Ity_I32);
1923 assign(oldC, mk_armg_calculate_flag_c() );
1924 assign(
1925 *newC,
1926 IRExpr_ITE(
1927 binop(Iop_CmpEQ32, mkexpr(amtT), mkU32(0)),
1928 mkexpr(oldC),
1929 IRExpr_ITE(
1930 binop(Iop_CmpLE32U, mkexpr(amtT), mkU32(32)),
1931 binop(Iop_And32,
1932 binop(Iop_Shr32,
1933 mkexpr(rMt),
1934 unop(Iop_32to8,
1935 binop(Iop_And32,
1936 binop(Iop_Sub32,
1937 mkexpr(amtT),
1938 mkU32(1)),
1939 mkU32(31)
1943 mkU32(1)
1945 mkU32(0)
1950 // (Rm >>u (Rs & 31)) & (((Rs & 255) - 32) >>s 31)
1951 // Lhs of the & limits the shift to 31 bits, so as to
1952 // give known IR semantics. Rhs of the & is all 1s for
1953 // Rs <= 31 and all 0s for Rs >= 32.
1954 assign(
1955 *res,
1956 binop(
1957 Iop_And32,
1958 binop(Iop_Shr32,
1959 mkexpr(rMt),
1960 unop(Iop_32to8,
1961 binop(Iop_And32, mkexpr(rSt), mkU32(31)))),
1962 binop(Iop_Sar32,
1963 binop(Iop_Sub32,
1964 mkexpr(amtT),
1965 mkU32(32)),
1966 mkU8(31))));
1967 DIS(buf, "r%u, LSR r%u", rM, rS);
1971 static void compute_result_and_C_after_ASR_by_imm5 (
1972 /*OUT*/HChar* buf,
1973 IRTemp* res,
1974 IRTemp* newC,
1975 IRTemp rMt, UInt shift_amt, /* operands */
1976 UInt rM /* only for debug printing */
1979 if (shift_amt == 0) {
1980 // conceptually a 32-bit shift, however:
1981 // res = Rm >>s 31
1982 // newC = Rm[31]
1983 if (newC) {
1984 assign( *newC,
1985 binop(Iop_And32,
1986 binop(Iop_Shr32, mkexpr(rMt), mkU8(31)),
1987 mkU32(1)));
1989 assign( *res, binop(Iop_Sar32, mkexpr(rMt), mkU8(31)) );
1990 DIS(buf, "r%u, ASR #0(a.k.a. 32)", rM);
1991 } else {
1992 // shift in range 1..31
1993 // res = Rm >>s shift_amt
1994 // newC = Rm[shift_amt - 1]
1995 vassert(shift_amt >= 1 && shift_amt <= 31);
1996 if (newC) {
1997 assign( *newC,
1998 binop(Iop_And32,
1999 binop(Iop_Shr32, mkexpr(rMt),
2000 mkU8(shift_amt - 1)),
2001 mkU32(1)));
2003 assign( *res,
2004 binop(Iop_Sar32, mkexpr(rMt), mkU8(shift_amt)) );
2005 DIS(buf, "r%u, ASR #%u", rM, shift_amt);
2010 static void compute_result_and_C_after_ASR_by_reg (
2011 /*OUT*/HChar* buf,
2012 IRTemp* res,
2013 IRTemp* newC,
2014 IRTemp rMt, IRTemp rSt, /* operands */
2015 UInt rM, UInt rS /* only for debug printing */
2018 // arithmetic shift right in range 0 .. 255
2019 // amt = rS & 255
2020 // res = amt < 32 ? Rm >>s amt : Rm >>s 31
2021 // newC = amt == 0 ? oldC :
2022 // amt in 1..32 ? Rm[amt-1] : Rm[31]
2023 IRTemp amtT = newTemp(Ity_I32);
2024 assign( amtT, binop(Iop_And32, mkexpr(rSt), mkU32(255)) );
2025 if (newC) {
2026 /* mux0X(amt == 0,
2027 mux0X(amt < 32,
2028 Rm[31],
2029 Rm[(amt-1) & 31])
2030 oldC)
2032 IRTemp oldC = newTemp(Ity_I32);
2033 assign(oldC, mk_armg_calculate_flag_c() );
2034 assign(
2035 *newC,
2036 IRExpr_ITE(
2037 binop(Iop_CmpEQ32, mkexpr(amtT), mkU32(0)),
2038 mkexpr(oldC),
2039 IRExpr_ITE(
2040 binop(Iop_CmpLE32U, mkexpr(amtT), mkU32(32)),
2041 binop(Iop_And32,
2042 binop(Iop_Shr32,
2043 mkexpr(rMt),
2044 unop(Iop_32to8,
2045 binop(Iop_And32,
2046 binop(Iop_Sub32,
2047 mkexpr(amtT),
2048 mkU32(1)),
2049 mkU32(31)
2053 mkU32(1)
2055 binop(Iop_And32,
2056 binop(Iop_Shr32,
2057 mkexpr(rMt),
2058 mkU8(31)
2060 mkU32(1)
2066 // (Rm >>s (amt <u 32 ? amt : 31))
2067 assign(
2068 *res,
2069 binop(
2070 Iop_Sar32,
2071 mkexpr(rMt),
2072 unop(
2073 Iop_32to8,
2074 IRExpr_ITE(
2075 binop(Iop_CmpLT32U, mkexpr(amtT), mkU32(32)),
2076 mkexpr(amtT),
2077 mkU32(31)))));
2078 DIS(buf, "r%u, ASR r%u", rM, rS);
2082 static void compute_result_and_C_after_ROR_by_reg (
2083 /*OUT*/HChar* buf,
2084 IRTemp* res,
2085 IRTemp* newC,
2086 IRTemp rMt, IRTemp rSt, /* operands */
2087 UInt rM, UInt rS /* only for debug printing */
2090 // rotate right in range 0 .. 255
2091 // amt = rS & 255
2092 // shop = Rm `ror` (amt & 31)
2093 // shco = amt == 0 ? oldC : Rm[(amt-1) & 31]
2094 IRTemp amtT = newTemp(Ity_I32);
2095 assign( amtT, binop(Iop_And32, mkexpr(rSt), mkU32(255)) );
2096 IRTemp amt5T = newTemp(Ity_I32);
2097 assign( amt5T, binop(Iop_And32, mkexpr(rSt), mkU32(31)) );
2098 IRTemp oldC = newTemp(Ity_I32);
2099 assign(oldC, mk_armg_calculate_flag_c() );
2100 if (newC) {
2101 assign(
2102 *newC,
2103 IRExpr_ITE(
2104 binop(Iop_CmpNE32, mkexpr(amtT), mkU32(0)),
2105 binop(Iop_And32,
2106 binop(Iop_Shr32,
2107 mkexpr(rMt),
2108 unop(Iop_32to8,
2109 binop(Iop_And32,
2110 binop(Iop_Sub32,
2111 mkexpr(amtT),
2112 mkU32(1)
2114 mkU32(31)
2118 mkU32(1)
2120 mkexpr(oldC)
2124 assign(
2125 *res,
2126 IRExpr_ITE(
2127 binop(Iop_CmpNE32, mkexpr(amt5T), mkU32(0)),
2128 binop(Iop_Or32,
2129 binop(Iop_Shr32,
2130 mkexpr(rMt),
2131 unop(Iop_32to8, mkexpr(amt5T))
2133 binop(Iop_Shl32,
2134 mkexpr(rMt),
2135 unop(Iop_32to8,
2136 binop(Iop_Sub32, mkU32(32), mkexpr(amt5T))
2140 mkexpr(rMt)
2143 DIS(buf, "r%u, ROR r#%u", rM, rS);
2147 /* Generate an expression corresponding to the immediate-shift case of
2148 a shifter operand. This is used both for ARM and Thumb2.
2150 Bind it to a temporary, and return that via *res. If newC is
2151 non-NULL, also compute a value for the shifter's carry out (in the
2152 LSB of a word), bind it to a temporary, and return that via *shco.
2154 Generates GETs from the guest state and is therefore not safe to
2155 use once we start doing PUTs to it, for any given instruction.
2157 'how' is encoded thusly:
2158 00b LSL, 01b LSR, 10b ASR, 11b ROR
2159 Most but not all ARM and Thumb integer insns use this encoding.
2160 Be careful to ensure the right value is passed here.
2162 static void compute_result_and_C_after_shift_by_imm5 (
2163 /*OUT*/HChar* buf,
2164 /*OUT*/IRTemp* res,
2165 /*OUT*/IRTemp* newC,
2166 IRTemp rMt, /* reg to shift */
2167 UInt how, /* what kind of shift */
2168 UInt shift_amt, /* shift amount (0..31) */
2169 UInt rM /* only for debug printing */
2172 vassert(shift_amt < 32);
2173 vassert(how < 4);
2175 switch (how) {
2177 case 0:
2178 compute_result_and_C_after_LSL_by_imm5(
2179 buf, res, newC, rMt, shift_amt, rM
2181 break;
2183 case 1:
2184 compute_result_and_C_after_LSR_by_imm5(
2185 buf, res, newC, rMt, shift_amt, rM
2187 break;
2189 case 2:
2190 compute_result_and_C_after_ASR_by_imm5(
2191 buf, res, newC, rMt, shift_amt, rM
2193 break;
2195 case 3:
2196 if (shift_amt == 0) {
2197 IRTemp oldcT = newTemp(Ity_I32);
2198 // rotate right 1 bit through carry (?)
2199 // RRX -- described at ARM ARM A5-17
2200 // res = (oldC << 31) | (Rm >>u 1)
2201 // newC = Rm[0]
2202 if (newC) {
2203 assign( *newC,
2204 binop(Iop_And32, mkexpr(rMt), mkU32(1)));
2206 assign( oldcT, mk_armg_calculate_flag_c() );
2207 assign( *res,
2208 binop(Iop_Or32,
2209 binop(Iop_Shl32, mkexpr(oldcT), mkU8(31)),
2210 binop(Iop_Shr32, mkexpr(rMt), mkU8(1))) );
2211 DIS(buf, "r%u, RRX", rM);
2212 } else {
2213 // rotate right in range 1..31
2214 // res = Rm `ror` shift_amt
2215 // newC = Rm[shift_amt - 1]
2216 vassert(shift_amt >= 1 && shift_amt <= 31);
2217 if (newC) {
2218 assign( *newC,
2219 binop(Iop_And32,
2220 binop(Iop_Shr32, mkexpr(rMt),
2221 mkU8(shift_amt - 1)),
2222 mkU32(1)));
2224 assign( *res,
2225 binop(Iop_Or32,
2226 binop(Iop_Shr32, mkexpr(rMt), mkU8(shift_amt)),
2227 binop(Iop_Shl32, mkexpr(rMt),
2228 mkU8(32-shift_amt))));
2229 DIS(buf, "r%u, ROR #%u", rM, shift_amt);
2231 break;
2233 default:
2234 /*NOTREACHED*/
2235 vassert(0);
2240 /* Generate an expression corresponding to the register-shift case of
2241 a shifter operand. This is used both for ARM and Thumb2.
2243 Bind it to a temporary, and return that via *res. If newC is
2244 non-NULL, also compute a value for the shifter's carry out (in the
2245 LSB of a word), bind it to a temporary, and return that via *shco.
2247 Generates GETs from the guest state and is therefore not safe to
2248 use once we start doing PUTs to it, for any given instruction.
2250 'how' is encoded thusly:
2251 00b LSL, 01b LSR, 10b ASR, 11b ROR
2252 Most but not all ARM and Thumb integer insns use this encoding.
2253 Be careful to ensure the right value is passed here.
2255 static void compute_result_and_C_after_shift_by_reg (
2256 /*OUT*/HChar* buf,
2257 /*OUT*/IRTemp* res,
2258 /*OUT*/IRTemp* newC,
2259 IRTemp rMt, /* reg to shift */
2260 UInt how, /* what kind of shift */
2261 IRTemp rSt, /* shift amount */
2262 UInt rM, /* only for debug printing */
2263 UInt rS /* only for debug printing */
2266 vassert(how < 4);
2267 switch (how) {
2268 case 0: { /* LSL */
2269 compute_result_and_C_after_LSL_by_reg(
2270 buf, res, newC, rMt, rSt, rM, rS
2272 break;
2274 case 1: { /* LSR */
2275 compute_result_and_C_after_LSR_by_reg(
2276 buf, res, newC, rMt, rSt, rM, rS
2278 break;
2280 case 2: { /* ASR */
2281 compute_result_and_C_after_ASR_by_reg(
2282 buf, res, newC, rMt, rSt, rM, rS
2284 break;
2286 case 3: { /* ROR */
2287 compute_result_and_C_after_ROR_by_reg(
2288 buf, res, newC, rMt, rSt, rM, rS
2290 break;
2292 default:
2293 /*NOTREACHED*/
2294 vassert(0);
2299 /* Generate an expression corresponding to a shifter_operand, bind it
2300 to a temporary, and return that via *shop. If shco is non-NULL,
2301 also compute a value for the shifter's carry out (in the LSB of a
2302 word), bind it to a temporary, and return that via *shco.
2304 If for some reason we can't come up with a shifter operand (missing
2305 case? not really a shifter operand?) return False.
2307 Generates GETs from the guest state and is therefore not safe to
2308 use once we start doing PUTs to it, for any given instruction.
2310 For ARM insns only; not for Thumb.
2312 static Bool mk_shifter_operand ( UInt insn_25, UInt insn_11_0,
2313 /*OUT*/IRTemp* shop,
2314 /*OUT*/IRTemp* shco,
2315 /*OUT*/HChar* buf )
2317 UInt insn_4 = (insn_11_0 >> 4) & 1;
2318 UInt insn_7 = (insn_11_0 >> 7) & 1;
2319 vassert(insn_25 <= 0x1);
2320 vassert(insn_11_0 <= 0xFFF);
2322 vassert(shop && *shop == IRTemp_INVALID);
2323 *shop = newTemp(Ity_I32);
2325 if (shco) {
2326 vassert(*shco == IRTemp_INVALID);
2327 *shco = newTemp(Ity_I32);
2330 /* 32-bit immediate */
2332 if (insn_25 == 1) {
2333 /* immediate: (7:0) rotated right by 2 * (11:8) */
2334 UInt imm = (insn_11_0 >> 0) & 0xFF;
2335 UInt rot = 2 * ((insn_11_0 >> 8) & 0xF);
2336 vassert(rot <= 30);
2337 imm = ROR32(imm, rot);
2338 if (shco) {
2339 if (rot == 0) {
2340 assign( *shco, mk_armg_calculate_flag_c() );
2341 } else {
2342 assign( *shco, mkU32( (imm >> 31) & 1 ) );
2345 DIS(buf, "#0x%x", imm);
2346 assign( *shop, mkU32(imm) );
2347 return True;
2350 /* Shift/rotate by immediate */
2352 if (insn_25 == 0 && insn_4 == 0) {
2353 /* Rm (3:0) shifted (6:5) by immediate (11:7) */
2354 UInt shift_amt = (insn_11_0 >> 7) & 0x1F;
2355 UInt rM = (insn_11_0 >> 0) & 0xF;
2356 UInt how = (insn_11_0 >> 5) & 3;
2357 /* how: 00 = Shl, 01 = Shr, 10 = Sar, 11 = Ror */
2358 IRTemp rMt = newTemp(Ity_I32);
2359 assign(rMt, getIRegA(rM));
2361 vassert(shift_amt <= 31);
2363 compute_result_and_C_after_shift_by_imm5(
2364 buf, shop, shco, rMt, how, shift_amt, rM
2366 return True;
2369 /* Shift/rotate by register */
2370 if (insn_25 == 0 && insn_4 == 1) {
2371 /* Rm (3:0) shifted (6:5) by Rs (11:8) */
2372 UInt rM = (insn_11_0 >> 0) & 0xF;
2373 UInt rS = (insn_11_0 >> 8) & 0xF;
2374 UInt how = (insn_11_0 >> 5) & 3;
2375 /* how: 00 = Shl, 01 = Shr, 10 = Sar, 11 = Ror */
2376 IRTemp rMt = newTemp(Ity_I32);
2377 IRTemp rSt = newTemp(Ity_I32);
2379 if (insn_7 == 1)
2380 return False; /* not really a shifter operand */
2382 assign(rMt, getIRegA(rM));
2383 assign(rSt, getIRegA(rS));
2385 compute_result_and_C_after_shift_by_reg(
2386 buf, shop, shco, rMt, how, rSt, rM, rS
2388 return True;
2391 vex_printf("mk_shifter_operand(0x%x,0x%x)\n", insn_25, insn_11_0 );
2392 return False;
2396 /* ARM only */
2397 static
2398 IRExpr* mk_EA_reg_plusminus_imm12 ( UInt rN, UInt bU, UInt imm12,
2399 /*OUT*/HChar* buf )
2401 vassert(rN < 16);
2402 vassert(bU < 2);
2403 vassert(imm12 < 0x1000);
2404 HChar opChar = bU == 1 ? '+' : '-';
2405 DIS(buf, "[r%u, #%c%u]", rN, opChar, imm12);
2406 return
2407 binop( (bU == 1 ? Iop_Add32 : Iop_Sub32),
2408 getIRegA(rN),
2409 mkU32(imm12) );
2413 /* ARM only.
2414 NB: This is "DecodeImmShift" in newer versions of the the ARM ARM.
2416 static
2417 IRExpr* mk_EA_reg_plusminus_shifted_reg ( UInt rN, UInt bU, UInt rM,
2418 UInt sh2, UInt imm5,
2419 /*OUT*/HChar* buf )
2421 vassert(rN < 16);
2422 vassert(bU < 2);
2423 vassert(rM < 16);
2424 vassert(sh2 < 4);
2425 vassert(imm5 < 32);
2426 HChar opChar = bU == 1 ? '+' : '-';
2427 IRExpr* index = NULL;
2428 switch (sh2) {
2429 case 0: /* LSL */
2430 /* imm5 can be in the range 0 .. 31 inclusive. */
2431 index = binop(Iop_Shl32, getIRegA(rM), mkU8(imm5));
2432 DIS(buf, "[r%u, %c r%u LSL #%u]", rN, opChar, rM, imm5);
2433 break;
2434 case 1: /* LSR */
2435 if (imm5 == 0) {
2436 index = mkU32(0);
2437 vassert(0); // ATC
2438 } else {
2439 index = binop(Iop_Shr32, getIRegA(rM), mkU8(imm5));
2441 DIS(buf, "[r%u, %cr%u, LSR #%u]",
2442 rN, opChar, rM, imm5 == 0 ? 32 : imm5);
2443 break;
2444 case 2: /* ASR */
2445 /* Doesn't this just mean that the behaviour with imm5 == 0
2446 is the same as if it had been 31 ? */
2447 if (imm5 == 0) {
2448 index = binop(Iop_Sar32, getIRegA(rM), mkU8(31));
2449 vassert(0); // ATC
2450 } else {
2451 index = binop(Iop_Sar32, getIRegA(rM), mkU8(imm5));
2453 DIS(buf, "[r%u, %cr%u, ASR #%u]",
2454 rN, opChar, rM, imm5 == 0 ? 32 : imm5);
2455 break;
2456 case 3: /* ROR or RRX */
2457 if (imm5 == 0) {
2458 IRTemp rmT = newTemp(Ity_I32);
2459 IRTemp cflagT = newTemp(Ity_I32);
2460 assign(rmT, getIRegA(rM));
2461 assign(cflagT, mk_armg_calculate_flag_c());
2462 index = binop(Iop_Or32,
2463 binop(Iop_Shl32, mkexpr(cflagT), mkU8(31)),
2464 binop(Iop_Shr32, mkexpr(rmT), mkU8(1)));
2465 DIS(buf, "[r%u, %cr%u, RRX]", rN, opChar, rM);
2466 } else {
2467 IRTemp rmT = newTemp(Ity_I32);
2468 assign(rmT, getIRegA(rM));
2469 vassert(imm5 >= 1 && imm5 <= 31);
2470 index = binop(Iop_Or32,
2471 binop(Iop_Shl32, mkexpr(rmT), mkU8(32-imm5)),
2472 binop(Iop_Shr32, mkexpr(rmT), mkU8(imm5)));
2473 DIS(buf, "[r%u, %cr%u, ROR #%u]", rN, opChar, rM, imm5);
2475 break;
2476 default:
2477 vassert(0);
2479 vassert(index);
2480 return binop(bU == 1 ? Iop_Add32 : Iop_Sub32,
2481 getIRegA(rN), index);
2485 /* ARM only */
2486 static
2487 IRExpr* mk_EA_reg_plusminus_imm8 ( UInt rN, UInt bU, UInt imm8,
2488 /*OUT*/HChar* buf )
2490 vassert(rN < 16);
2491 vassert(bU < 2);
2492 vassert(imm8 < 0x100);
2493 HChar opChar = bU == 1 ? '+' : '-';
2494 DIS(buf, "[r%u, #%c%u]", rN, opChar, imm8);
2495 return
2496 binop( (bU == 1 ? Iop_Add32 : Iop_Sub32),
2497 getIRegA(rN),
2498 mkU32(imm8) );
2502 /* ARM only */
2503 static
2504 IRExpr* mk_EA_reg_plusminus_reg ( UInt rN, UInt bU, UInt rM,
2505 /*OUT*/HChar* buf )
2507 vassert(rN < 16);
2508 vassert(bU < 2);
2509 vassert(rM < 16);
2510 HChar opChar = bU == 1 ? '+' : '-';
2511 IRExpr* index = getIRegA(rM);
2512 DIS(buf, "[r%u, %c r%u]", rN, opChar, rM);
2513 return binop(bU == 1 ? Iop_Add32 : Iop_Sub32,
2514 getIRegA(rN), index);
2518 /* irRes :: Ity_I32 holds a floating point comparison result encoded
2519 as an IRCmpF64Result. Generate code to convert it to an
2520 ARM-encoded (N,Z,C,V) group in the lowest 4 bits of an I32 value.
2521 Assign a new temp to hold that value, and return the temp. */
2522 static
2523 IRTemp mk_convert_IRCmpF64Result_to_NZCV ( IRTemp irRes )
2525 IRTemp ix = newTemp(Ity_I32);
2526 IRTemp termL = newTemp(Ity_I32);
2527 IRTemp termR = newTemp(Ity_I32);
2528 IRTemp nzcv = newTemp(Ity_I32);
2530 /* This is where the fun starts. We have to convert 'irRes' from
2531 an IR-convention return result (IRCmpF64Result) to an
2532 ARM-encoded (N,Z,C,V) group. The final result is in the bottom
2533 4 bits of 'nzcv'. */
2534 /* Map compare result from IR to ARM(nzcv) */
2536 FP cmp result | IR | ARM(nzcv)
2537 --------------------------------
2538 UN 0x45 0011
2539 LT 0x01 1000
2540 GT 0x00 0010
2541 EQ 0x40 0110
2543 /* Now since you're probably wondering WTF ..
2545 ix fishes the useful bits out of the IR value, bits 6 and 0, and
2546 places them side by side, giving a number which is 0, 1, 2 or 3.
2548 termL is a sequence cooked up by GNU superopt. It converts ix
2549 into an almost correct value NZCV value (incredibly), except
2550 for the case of UN, where it produces 0100 instead of the
2551 required 0011.
2553 termR is therefore a correction term, also computed from ix. It
2554 is 1 in the UN case and 0 for LT, GT and UN. Hence, to get
2555 the final correct value, we subtract termR from termL.
2557 Don't take my word for it. There's a test program at the bottom
2558 of this file, to try this out with.
2560 assign(
2562 binop(Iop_Or32,
2563 binop(Iop_And32,
2564 binop(Iop_Shr32, mkexpr(irRes), mkU8(5)),
2565 mkU32(3)),
2566 binop(Iop_And32, mkexpr(irRes), mkU32(1))));
2568 assign(
2569 termL,
2570 binop(Iop_Add32,
2571 binop(Iop_Shr32,
2572 binop(Iop_Sub32,
2573 binop(Iop_Shl32,
2574 binop(Iop_Xor32, mkexpr(ix), mkU32(1)),
2575 mkU8(30)),
2576 mkU32(1)),
2577 mkU8(29)),
2578 mkU32(1)));
2580 assign(
2581 termR,
2582 binop(Iop_And32,
2583 binop(Iop_And32,
2584 mkexpr(ix),
2585 binop(Iop_Shr32, mkexpr(ix), mkU8(1))),
2586 mkU32(1)));
2588 assign(nzcv, binop(Iop_Sub32, mkexpr(termL), mkexpr(termR)));
2589 return nzcv;
2593 /* Thumb32 only. This is "ThumbExpandImm" in the ARM ARM. If
2594 updatesC is non-NULL, a boolean is written to it indicating whether
2595 or not the C flag is updated, as per ARM ARM "ThumbExpandImm_C".
2597 static UInt thumbExpandImm ( Bool* updatesC,
2598 UInt imm1, UInt imm3, UInt imm8 )
2600 vassert(imm1 < (1<<1));
2601 vassert(imm3 < (1<<3));
2602 vassert(imm8 < (1<<8));
2603 UInt i_imm3_a = (imm1 << 4) | (imm3 << 1) | ((imm8 >> 7) & 1);
2604 UInt abcdefgh = imm8;
2605 UInt lbcdefgh = imm8 | 0x80;
2606 if (updatesC) {
2607 *updatesC = i_imm3_a >= 8;
2609 switch (i_imm3_a) {
2610 case 0: case 1:
2611 return abcdefgh;
2612 case 2: case 3:
2613 return (abcdefgh << 16) | abcdefgh;
2614 case 4: case 5:
2615 return (abcdefgh << 24) | (abcdefgh << 8);
2616 case 6: case 7:
2617 return (abcdefgh << 24) | (abcdefgh << 16)
2618 | (abcdefgh << 8) | abcdefgh;
2619 case 8 ... 31:
2620 return lbcdefgh << (32 - i_imm3_a);
2621 default:
2622 break;
2624 /*NOTREACHED*/vassert(0);
2628 /* Version of thumbExpandImm where we simply feed it the
2629 instruction halfwords (the lowest addressed one is I0). */
2630 static UInt thumbExpandImm_from_I0_I1 ( Bool* updatesC,
2631 UShort i0s, UShort i1s )
2633 UInt i0 = (UInt)i0s;
2634 UInt i1 = (UInt)i1s;
2635 UInt imm1 = SLICE_UInt(i0,10,10);
2636 UInt imm3 = SLICE_UInt(i1,14,12);
2637 UInt imm8 = SLICE_UInt(i1,7,0);
2638 return thumbExpandImm(updatesC, imm1, imm3, imm8);
2642 /* Thumb16 only. Given the firstcond and mask fields from an IT
2643 instruction, compute the 32-bit ITSTATE value implied, as described
2644 in libvex_guest_arm.h. This is not the ARM ARM representation.
2645 Also produce the t/e chars for the 2nd, 3rd, 4th insns, for
2646 disassembly printing. Returns False if firstcond or mask
2647 denote something invalid.
2649 The number and conditions for the instructions to be
2650 conditionalised depend on firstcond and mask:
2652 mask cond 1 cond 2 cond 3 cond 4
2654 1000 fc[3:0]
2655 x100 fc[3:0] fc[3:1]:x
2656 xy10 fc[3:0] fc[3:1]:x fc[3:1]:y
2657 xyz1 fc[3:0] fc[3:1]:x fc[3:1]:y fc[3:1]:z
2659 The condition fields are assembled in *itstate backwards (cond 4 at
2660 the top, cond 1 at the bottom). Conditions are << 4'd and then
2661 ^0xE'd, and those fields that correspond to instructions in the IT
2662 block are tagged with a 1 bit.
2664 static Bool compute_ITSTATE ( /*OUT*/UInt* itstate,
2665 /*OUT*/HChar* ch1,
2666 /*OUT*/HChar* ch2,
2667 /*OUT*/HChar* ch3,
2668 UInt firstcond, UInt mask )
2670 vassert(firstcond <= 0xF);
2671 vassert(mask <= 0xF);
2672 *itstate = 0;
2673 *ch1 = *ch2 = *ch3 = '.';
2674 if (mask == 0)
2675 return False; /* the logic below actually ensures this anyway,
2676 but clearer to make it explicit. */
2677 if (firstcond == 0xF)
2678 return False; /* NV is not allowed */
2679 if (firstcond == 0xE && popcount32(mask) != 1)
2680 return False; /* if firstcond is AL then all the rest must be too */
2682 UInt m3 = (mask >> 3) & 1;
2683 UInt m2 = (mask >> 2) & 1;
2684 UInt m1 = (mask >> 1) & 1;
2685 UInt m0 = (mask >> 0) & 1;
2687 UInt fc = (firstcond << 4) | 1/*in-IT-block*/;
2688 UInt ni = (0xE/*AL*/ << 4) | 0/*not-in-IT-block*/;
2690 if (m3 == 1 && (m2|m1|m0) == 0) {
2691 *itstate = (ni << 24) | (ni << 16) | (ni << 8) | fc;
2692 *itstate ^= 0xE0E0E0E0;
2693 return True;
2696 if (m2 == 1 && (m1|m0) == 0) {
2697 *itstate = (ni << 24) | (ni << 16) | (setbit32(fc, 4, m3) << 8) | fc;
2698 *itstate ^= 0xE0E0E0E0;
2699 *ch1 = m3 == (firstcond & 1) ? 't' : 'e';
2700 return True;
2703 if (m1 == 1 && m0 == 0) {
2704 *itstate = (ni << 24)
2705 | (setbit32(fc, 4, m2) << 16)
2706 | (setbit32(fc, 4, m3) << 8) | fc;
2707 *itstate ^= 0xE0E0E0E0;
2708 *ch1 = m3 == (firstcond & 1) ? 't' : 'e';
2709 *ch2 = m2 == (firstcond & 1) ? 't' : 'e';
2710 return True;
2713 if (m0 == 1) {
2714 *itstate = (setbit32(fc, 4, m1) << 24)
2715 | (setbit32(fc, 4, m2) << 16)
2716 | (setbit32(fc, 4, m3) << 8) | fc;
2717 *itstate ^= 0xE0E0E0E0;
2718 *ch1 = m3 == (firstcond & 1) ? 't' : 'e';
2719 *ch2 = m2 == (firstcond & 1) ? 't' : 'e';
2720 *ch3 = m1 == (firstcond & 1) ? 't' : 'e';
2721 return True;
2724 return False;
2728 /* Generate IR to do 32-bit bit reversal, a la Hacker's Delight
2729 Chapter 7 Section 1. */
2730 static IRTemp gen_BITREV ( IRTemp x0 )
2732 IRTemp x1 = newTemp(Ity_I32);
2733 IRTemp x2 = newTemp(Ity_I32);
2734 IRTemp x3 = newTemp(Ity_I32);
2735 IRTemp x4 = newTemp(Ity_I32);
2736 IRTemp x5 = newTemp(Ity_I32);
2737 UInt c1 = 0x55555555;
2738 UInt c2 = 0x33333333;
2739 UInt c3 = 0x0F0F0F0F;
2740 UInt c4 = 0x00FF00FF;
2741 UInt c5 = 0x0000FFFF;
2742 assign(x1,
2743 binop(Iop_Or32,
2744 binop(Iop_Shl32,
2745 binop(Iop_And32, mkexpr(x0), mkU32(c1)),
2746 mkU8(1)),
2747 binop(Iop_Shr32,
2748 binop(Iop_And32, mkexpr(x0), mkU32(~c1)),
2749 mkU8(1))
2751 assign(x2,
2752 binop(Iop_Or32,
2753 binop(Iop_Shl32,
2754 binop(Iop_And32, mkexpr(x1), mkU32(c2)),
2755 mkU8(2)),
2756 binop(Iop_Shr32,
2757 binop(Iop_And32, mkexpr(x1), mkU32(~c2)),
2758 mkU8(2))
2760 assign(x3,
2761 binop(Iop_Or32,
2762 binop(Iop_Shl32,
2763 binop(Iop_And32, mkexpr(x2), mkU32(c3)),
2764 mkU8(4)),
2765 binop(Iop_Shr32,
2766 binop(Iop_And32, mkexpr(x2), mkU32(~c3)),
2767 mkU8(4))
2769 assign(x4,
2770 binop(Iop_Or32,
2771 binop(Iop_Shl32,
2772 binop(Iop_And32, mkexpr(x3), mkU32(c4)),
2773 mkU8(8)),
2774 binop(Iop_Shr32,
2775 binop(Iop_And32, mkexpr(x3), mkU32(~c4)),
2776 mkU8(8))
2778 assign(x5,
2779 binop(Iop_Or32,
2780 binop(Iop_Shl32,
2781 binop(Iop_And32, mkexpr(x4), mkU32(c5)),
2782 mkU8(16)),
2783 binop(Iop_Shr32,
2784 binop(Iop_And32, mkexpr(x4), mkU32(~c5)),
2785 mkU8(16))
2787 return x5;
2791 /* Generate IR to do rearrange bytes 3:2:1:0 in a word in to the order
2792 0:1:2:3 (aka byte-swap). */
2793 static IRTemp gen_REV ( IRTemp arg )
2795 IRTemp res = newTemp(Ity_I32);
2796 assign(res,
2797 binop(Iop_Or32,
2798 binop(Iop_Shl32, mkexpr(arg), mkU8(24)),
2799 binop(Iop_Or32,
2800 binop(Iop_And32, binop(Iop_Shl32, mkexpr(arg), mkU8(8)),
2801 mkU32(0x00FF0000)),
2802 binop(Iop_Or32,
2803 binop(Iop_And32, binop(Iop_Shr32, mkexpr(arg), mkU8(8)),
2804 mkU32(0x0000FF00)),
2805 binop(Iop_And32, binop(Iop_Shr32, mkexpr(arg), mkU8(24)),
2806 mkU32(0x000000FF) )
2807 ))));
2808 return res;
2812 /* Generate IR to do rearrange bytes 3:2:1:0 in a word in to the order
2813 2:3:0:1 (swap within lo and hi halves). */
2814 static IRTemp gen_REV16 ( IRTemp arg )
2816 IRTemp res = newTemp(Ity_I32);
2817 assign(res,
2818 binop(Iop_Or32,
2819 binop(Iop_And32,
2820 binop(Iop_Shl32, mkexpr(arg), mkU8(8)),
2821 mkU32(0xFF00FF00)),
2822 binop(Iop_And32,
2823 binop(Iop_Shr32, mkexpr(arg), mkU8(8)),
2824 mkU32(0x00FF00FF))));
2825 return res;
2829 /*------------------------------------------------------------*/
2830 /*--- Advanced SIMD (NEON) instructions ---*/
2831 /*------------------------------------------------------------*/
2833 /*------------------------------------------------------------*/
2834 /*--- NEON data processing ---*/
2835 /*------------------------------------------------------------*/
2837 /* For all NEON DP ops, we use the normal scheme to handle conditional
2838 writes to registers -- pass in condT and hand that on to the
2839 put*Reg functions. In ARM mode condT is always IRTemp_INVALID
2840 since NEON is unconditional for ARM. In Thumb mode condT is
2841 derived from the ITSTATE shift register in the normal way. */
2843 static
2844 UInt get_neon_d_regno(UInt theInstr)
2846 UInt x = ((theInstr >> 18) & 0x10) | ((theInstr >> 12) & 0xF);
2847 if (theInstr & 0x40) {
2848 if (x & 1) {
2849 x = x + 0x100;
2850 } else {
2851 x = x >> 1;
2854 return x;
2857 static
2858 UInt get_neon_n_regno(UInt theInstr)
2860 UInt x = ((theInstr >> 3) & 0x10) | ((theInstr >> 16) & 0xF);
2861 if (theInstr & 0x40) {
2862 if (x & 1) {
2863 x = x + 0x100;
2864 } else {
2865 x = x >> 1;
2868 return x;
2871 static
2872 UInt get_neon_m_regno(UInt theInstr)
2874 UInt x = ((theInstr >> 1) & 0x10) | (theInstr & 0xF);
2875 if (theInstr & 0x40) {
2876 if (x & 1) {
2877 x = x + 0x100;
2878 } else {
2879 x = x >> 1;
2882 return x;
2885 static
2886 Bool dis_neon_vext ( UInt theInstr, IRTemp condT )
2888 UInt dreg = get_neon_d_regno(theInstr);
2889 UInt mreg = get_neon_m_regno(theInstr);
2890 UInt nreg = get_neon_n_regno(theInstr);
2891 UInt imm4 = (theInstr >> 8) & 0xf;
2892 UInt Q = (theInstr >> 6) & 1;
2893 HChar reg_t = Q ? 'q' : 'd';
2895 if (Q) {
2896 putQReg(dreg, triop(Iop_SliceV128, /*hiV128*/getQReg(mreg),
2897 /*loV128*/getQReg(nreg), mkU8(imm4)), condT);
2898 } else {
2899 putDRegI64(dreg, triop(Iop_Slice64, /*hiI64*/getDRegI64(mreg),
2900 /*loI64*/getDRegI64(nreg), mkU8(imm4)), condT);
2902 DIP("vext.8 %c%u, %c%u, %c%u, #%u\n", reg_t, dreg, reg_t, nreg,
2903 reg_t, mreg, imm4);
2904 return True;
2907 /* Generate specific vector FP binary ops, possibly with a fake
2908 rounding mode as required by the primop. */
2909 static
2910 IRExpr* binop_w_fake_RM ( IROp op, IRExpr* argL, IRExpr* argR )
2912 switch (op) {
2913 case Iop_Add32Fx4:
2914 case Iop_Sub32Fx4:
2915 case Iop_Mul32Fx4:
2916 return triop(op, get_FAKE_roundingmode(), argL, argR );
2917 case Iop_Add32x4: case Iop_Add16x8:
2918 case Iop_Sub32x4: case Iop_Sub16x8:
2919 case Iop_Mul32x4: case Iop_Mul16x8:
2920 case Iop_Mul32x2: case Iop_Mul16x4:
2921 case Iop_Add32Fx2:
2922 case Iop_Sub32Fx2:
2923 case Iop_Mul32Fx2:
2924 case Iop_PwAdd32Fx2:
2925 return binop(op, argL, argR);
2926 default:
2927 ppIROp(op);
2928 vassert(0);
2932 /* VTBL, VTBX */
2933 static
2934 Bool dis_neon_vtb ( UInt theInstr, IRTemp condT )
2936 UInt op = (theInstr >> 6) & 1;
2937 UInt dreg = get_neon_d_regno(theInstr & ~(1 << 6));
2938 UInt nreg = get_neon_n_regno(theInstr & ~(1 << 6));
2939 UInt mreg = get_neon_m_regno(theInstr & ~(1 << 6));
2940 UInt len = (theInstr >> 8) & 3;
2941 Int i;
2942 IROp cmp;
2943 ULong imm;
2944 IRTemp arg_l;
2945 IRTemp old_mask, new_mask, cur_mask;
2946 IRTemp old_res, new_res;
2947 IRTemp old_arg, new_arg;
2949 if (dreg >= 0x100 || mreg >= 0x100 || nreg >= 0x100)
2950 return False;
2951 if (nreg + len > 31)
2952 return False;
2954 cmp = Iop_CmpGT8Ux8;
2956 old_mask = newTemp(Ity_I64);
2957 old_res = newTemp(Ity_I64);
2958 old_arg = newTemp(Ity_I64);
2959 assign(old_mask, mkU64(0));
2960 assign(old_res, mkU64(0));
2961 assign(old_arg, getDRegI64(mreg));
2962 imm = 8;
2963 imm = (imm << 8) | imm;
2964 imm = (imm << 16) | imm;
2965 imm = (imm << 32) | imm;
2967 for (i = 0; i <= len; i++) {
2968 arg_l = newTemp(Ity_I64);
2969 new_mask = newTemp(Ity_I64);
2970 cur_mask = newTemp(Ity_I64);
2971 new_res = newTemp(Ity_I64);
2972 new_arg = newTemp(Ity_I64);
2973 assign(arg_l, getDRegI64(nreg+i));
2974 assign(new_arg, binop(Iop_Sub8x8, mkexpr(old_arg), mkU64(imm)));
2975 assign(cur_mask, binop(cmp, mkU64(imm), mkexpr(old_arg)));
2976 assign(new_mask, binop(Iop_Or64, mkexpr(old_mask), mkexpr(cur_mask)));
2977 assign(new_res, binop(Iop_Or64,
2978 mkexpr(old_res),
2979 binop(Iop_And64,
2980 binop(Iop_Perm8x8,
2981 mkexpr(arg_l),
2982 binop(Iop_And64,
2983 mkexpr(old_arg),
2984 mkexpr(cur_mask))),
2985 mkexpr(cur_mask))));
2987 old_arg = new_arg;
2988 old_mask = new_mask;
2989 old_res = new_res;
2991 if (op) {
2992 new_res = newTemp(Ity_I64);
2993 assign(new_res, binop(Iop_Or64,
2994 binop(Iop_And64,
2995 getDRegI64(dreg),
2996 unop(Iop_Not64, mkexpr(old_mask))),
2997 mkexpr(old_res)));
2998 old_res = new_res;
3001 putDRegI64(dreg, mkexpr(old_res), condT);
3002 DIP("vtb%c.8 d%u, {", op ? 'x' : 'l', dreg);
3003 if (len > 0) {
3004 DIP("d%u-d%u", nreg, nreg + len);
3005 } else {
3006 DIP("d%u", nreg);
3008 DIP("}, d%u\n", mreg);
3009 return True;
3012 /* VDUP (scalar) */
3013 static
3014 Bool dis_neon_vdup ( UInt theInstr, IRTemp condT )
3016 UInt Q = (theInstr >> 6) & 1;
3017 UInt dreg = ((theInstr >> 18) & 0x10) | ((theInstr >> 12) & 0xF);
3018 UInt mreg = ((theInstr >> 1) & 0x10) | (theInstr & 0xF);
3019 UInt imm4 = (theInstr >> 16) & 0xF;
3020 UInt index;
3021 UInt size;
3022 IRTemp arg_m;
3023 IRTemp res;
3024 IROp op, op2;
3026 if ((imm4 == 0) || (imm4 == 8))
3027 return False;
3028 if ((Q == 1) && ((dreg & 1) == 1))
3029 return False;
3030 if (Q)
3031 dreg >>= 1;
3032 arg_m = newTemp(Ity_I64);
3033 assign(arg_m, getDRegI64(mreg));
3034 if (Q)
3035 res = newTemp(Ity_V128);
3036 else
3037 res = newTemp(Ity_I64);
3038 if ((imm4 & 1) == 1) {
3039 op = Q ? Iop_Dup8x16 : Iop_Dup8x8;
3040 op2 = Iop_GetElem8x8;
3041 index = imm4 >> 1;
3042 size = 8;
3043 } else if ((imm4 & 3) == 2) {
3044 op = Q ? Iop_Dup16x8 : Iop_Dup16x4;
3045 op2 = Iop_GetElem16x4;
3046 index = imm4 >> 2;
3047 size = 16;
3048 } else if ((imm4 & 7) == 4) {
3049 op = Q ? Iop_Dup32x4 : Iop_Dup32x2;
3050 op2 = Iop_GetElem32x2;
3051 index = imm4 >> 3;
3052 size = 32;
3053 } else {
3054 return False; // can this ever happen?
3056 assign(res, unop(op, binop(op2, mkexpr(arg_m), mkU8(index))));
3057 if (Q) {
3058 putQReg(dreg, mkexpr(res), condT);
3059 } else {
3060 putDRegI64(dreg, mkexpr(res), condT);
3062 DIP("vdup.%u %c%u, d%u[%u]\n", size, Q ? 'q' : 'd', dreg, mreg, index);
3063 return True;
3066 /* A7.4.1 Three registers of the same length */
3067 static
3068 Bool dis_neon_data_3same ( UInt theInstr, IRTemp condT )
3070 /* In paths where this returns False, indicating a non-decodable
3071 instruction, there may still be some IR assignments to temporaries
3072 generated. This is inconvenient but harmless, and the post-front-end
3073 IR optimisation pass will just remove them anyway. So there's no
3074 effort made here to tidy it up.
3076 UInt Q = (theInstr >> 6) & 1;
3077 UInt dreg = get_neon_d_regno(theInstr);
3078 UInt nreg = get_neon_n_regno(theInstr);
3079 UInt mreg = get_neon_m_regno(theInstr);
3080 UInt A = (theInstr >> 8) & 0xF;
3081 UInt B = (theInstr >> 4) & 1;
3082 UInt C = (theInstr >> 20) & 0x3;
3083 UInt U = (theInstr >> 24) & 1;
3084 UInt size = C;
3086 IRTemp arg_n;
3087 IRTemp arg_m;
3088 IRTemp res;
3090 if (Q) {
3091 arg_n = newTemp(Ity_V128);
3092 arg_m = newTemp(Ity_V128);
3093 res = newTemp(Ity_V128);
3094 assign(arg_n, getQReg(nreg));
3095 assign(arg_m, getQReg(mreg));
3096 } else {
3097 arg_n = newTemp(Ity_I64);
3098 arg_m = newTemp(Ity_I64);
3099 res = newTemp(Ity_I64);
3100 assign(arg_n, getDRegI64(nreg));
3101 assign(arg_m, getDRegI64(mreg));
3104 switch(A) {
3105 case 0:
3106 if (B == 0) {
3107 /* VHADD */
3108 ULong imm = 0;
3109 IRExpr *imm_val;
3110 IROp addOp;
3111 IROp andOp;
3112 IROp shOp;
3113 HChar regType = Q ? 'q' : 'd';
3115 if (size == 3)
3116 return False;
3117 switch(size) {
3118 case 0: imm = 0x101010101010101LL; break;
3119 case 1: imm = 0x1000100010001LL; break;
3120 case 2: imm = 0x100000001LL; break;
3121 default: vassert(0);
3123 if (Q) {
3124 imm_val = binop(Iop_64HLtoV128, mkU64(imm), mkU64(imm));
3125 andOp = Iop_AndV128;
3126 } else {
3127 imm_val = mkU64(imm);
3128 andOp = Iop_And64;
3130 if (U) {
3131 switch(size) {
3132 case 0:
3133 addOp = Q ? Iop_Add8x16 : Iop_Add8x8;
3134 shOp = Q ? Iop_ShrN8x16 : Iop_ShrN8x8;
3135 break;
3136 case 1:
3137 addOp = Q ? Iop_Add16x8 : Iop_Add16x4;
3138 shOp = Q ? Iop_ShrN16x8 : Iop_ShrN16x4;
3139 break;
3140 case 2:
3141 addOp = Q ? Iop_Add32x4 : Iop_Add32x2;
3142 shOp = Q ? Iop_ShrN32x4 : Iop_ShrN32x2;
3143 break;
3144 default:
3145 vassert(0);
3147 } else {
3148 switch(size) {
3149 case 0:
3150 addOp = Q ? Iop_Add8x16 : Iop_Add8x8;
3151 shOp = Q ? Iop_SarN8x16 : Iop_SarN8x8;
3152 break;
3153 case 1:
3154 addOp = Q ? Iop_Add16x8 : Iop_Add16x4;
3155 shOp = Q ? Iop_SarN16x8 : Iop_SarN16x4;
3156 break;
3157 case 2:
3158 addOp = Q ? Iop_Add32x4 : Iop_Add32x2;
3159 shOp = Q ? Iop_SarN32x4 : Iop_SarN32x2;
3160 break;
3161 default:
3162 vassert(0);
3165 assign(res,
3166 binop(addOp,
3167 binop(addOp,
3168 binop(shOp, mkexpr(arg_m), mkU8(1)),
3169 binop(shOp, mkexpr(arg_n), mkU8(1))),
3170 binop(shOp,
3171 binop(addOp,
3172 binop(andOp, mkexpr(arg_m), imm_val),
3173 binop(andOp, mkexpr(arg_n), imm_val)),
3174 mkU8(1))));
3175 DIP("vhadd.%c%d %c%u, %c%u, %c%u\n",
3176 U ? 'u' : 's', 8 << size, regType,
3177 dreg, regType, nreg, regType, mreg);
3178 } else {
3179 /* VQADD */
3180 IROp op, op2;
3181 IRTemp tmp;
3182 HChar reg_t = Q ? 'q' : 'd';
3183 if (Q) {
3184 switch (size) {
3185 case 0:
3186 op = U ? Iop_QAdd8Ux16 : Iop_QAdd8Sx16;
3187 op2 = Iop_Add8x16;
3188 break;
3189 case 1:
3190 op = U ? Iop_QAdd16Ux8 : Iop_QAdd16Sx8;
3191 op2 = Iop_Add16x8;
3192 break;
3193 case 2:
3194 op = U ? Iop_QAdd32Ux4 : Iop_QAdd32Sx4;
3195 op2 = Iop_Add32x4;
3196 break;
3197 case 3:
3198 op = U ? Iop_QAdd64Ux2 : Iop_QAdd64Sx2;
3199 op2 = Iop_Add64x2;
3200 break;
3201 default:
3202 vassert(0);
3204 } else {
3205 switch (size) {
3206 case 0:
3207 op = U ? Iop_QAdd8Ux8 : Iop_QAdd8Sx8;
3208 op2 = Iop_Add8x8;
3209 break;
3210 case 1:
3211 op = U ? Iop_QAdd16Ux4 : Iop_QAdd16Sx4;
3212 op2 = Iop_Add16x4;
3213 break;
3214 case 2:
3215 op = U ? Iop_QAdd32Ux2 : Iop_QAdd32Sx2;
3216 op2 = Iop_Add32x2;
3217 break;
3218 case 3:
3219 op = U ? Iop_QAdd64Ux1 : Iop_QAdd64Sx1;
3220 op2 = Iop_Add64;
3221 break;
3222 default:
3223 vassert(0);
3226 if (Q) {
3227 tmp = newTemp(Ity_V128);
3228 } else {
3229 tmp = newTemp(Ity_I64);
3231 assign(res, binop(op, mkexpr(arg_n), mkexpr(arg_m)));
3232 assign(tmp, binop(op2, mkexpr(arg_n), mkexpr(arg_m)));
3233 setFlag_QC(mkexpr(res), mkexpr(tmp), Q, condT);
3234 DIP("vqadd.%c%d %c%u %c%u, %c%u\n",
3235 U ? 'u' : 's',
3236 8 << size, reg_t, dreg, reg_t, nreg, reg_t, mreg);
3238 break;
3239 case 1:
3240 if (B == 0) {
3241 /* VRHADD */
3242 /* VRHADD C, A, B ::=
3243 C = (A >> 1) + (B >> 1) + (((A & 1) + (B & 1) + 1) >> 1) */
3244 IROp shift_op, add_op;
3245 IRTemp cc;
3246 ULong one = 1;
3247 HChar reg_t = Q ? 'q' : 'd';
3248 switch (size) {
3249 case 0: one = (one << 8) | one; /* fall through */
3250 case 1: one = (one << 16) | one; /* fall through */
3251 case 2: one = (one << 32) | one; break;
3252 case 3: return False;
3253 default: vassert(0);
3255 if (Q) {
3256 switch (size) {
3257 case 0:
3258 shift_op = U ? Iop_ShrN8x16 : Iop_SarN8x16;
3259 add_op = Iop_Add8x16;
3260 break;
3261 case 1:
3262 shift_op = U ? Iop_ShrN16x8 : Iop_SarN16x8;
3263 add_op = Iop_Add16x8;
3264 break;
3265 case 2:
3266 shift_op = U ? Iop_ShrN32x4 : Iop_SarN32x4;
3267 add_op = Iop_Add32x4;
3268 break;
3269 case 3:
3270 return False;
3271 default:
3272 vassert(0);
3274 } else {
3275 switch (size) {
3276 case 0:
3277 shift_op = U ? Iop_ShrN8x8 : Iop_SarN8x8;
3278 add_op = Iop_Add8x8;
3279 break;
3280 case 1:
3281 shift_op = U ? Iop_ShrN16x4 : Iop_SarN16x4;
3282 add_op = Iop_Add16x4;
3283 break;
3284 case 2:
3285 shift_op = U ? Iop_ShrN32x2 : Iop_SarN32x2;
3286 add_op = Iop_Add32x2;
3287 break;
3288 case 3:
3289 return False;
3290 default:
3291 vassert(0);
3294 if (Q) {
3295 cc = newTemp(Ity_V128);
3296 assign(cc, binop(shift_op,
3297 binop(add_op,
3298 binop(add_op,
3299 binop(Iop_AndV128,
3300 mkexpr(arg_n),
3301 binop(Iop_64HLtoV128,
3302 mkU64(one),
3303 mkU64(one))),
3304 binop(Iop_AndV128,
3305 mkexpr(arg_m),
3306 binop(Iop_64HLtoV128,
3307 mkU64(one),
3308 mkU64(one)))),
3309 binop(Iop_64HLtoV128,
3310 mkU64(one),
3311 mkU64(one))),
3312 mkU8(1)));
3313 assign(res, binop(add_op,
3314 binop(add_op,
3315 binop(shift_op,
3316 mkexpr(arg_n),
3317 mkU8(1)),
3318 binop(shift_op,
3319 mkexpr(arg_m),
3320 mkU8(1))),
3321 mkexpr(cc)));
3322 } else {
3323 cc = newTemp(Ity_I64);
3324 assign(cc, binop(shift_op,
3325 binop(add_op,
3326 binop(add_op,
3327 binop(Iop_And64,
3328 mkexpr(arg_n),
3329 mkU64(one)),
3330 binop(Iop_And64,
3331 mkexpr(arg_m),
3332 mkU64(one))),
3333 mkU64(one)),
3334 mkU8(1)));
3335 assign(res, binop(add_op,
3336 binop(add_op,
3337 binop(shift_op,
3338 mkexpr(arg_n),
3339 mkU8(1)),
3340 binop(shift_op,
3341 mkexpr(arg_m),
3342 mkU8(1))),
3343 mkexpr(cc)));
3345 DIP("vrhadd.%c%d %c%u, %c%u, %c%u\n",
3346 U ? 'u' : 's',
3347 8 << size, reg_t, dreg, reg_t, nreg, reg_t, mreg);
3348 } else {
3349 if (U == 0) {
3350 switch(C) {
3351 case 0: {
3352 /* VAND */
3353 HChar reg_t = Q ? 'q' : 'd';
3354 if (Q) {
3355 assign(res, binop(Iop_AndV128, mkexpr(arg_n),
3356 mkexpr(arg_m)));
3357 } else {
3358 assign(res, binop(Iop_And64, mkexpr(arg_n),
3359 mkexpr(arg_m)));
3361 DIP("vand %c%u, %c%u, %c%u\n",
3362 reg_t, dreg, reg_t, nreg, reg_t, mreg);
3363 break;
3365 case 1: {
3366 /* VBIC */
3367 HChar reg_t = Q ? 'q' : 'd';
3368 if (Q) {
3369 assign(res, binop(Iop_AndV128,mkexpr(arg_n),
3370 unop(Iop_NotV128, mkexpr(arg_m))));
3371 } else {
3372 assign(res, binop(Iop_And64, mkexpr(arg_n),
3373 unop(Iop_Not64, mkexpr(arg_m))));
3375 DIP("vbic %c%u, %c%u, %c%u\n",
3376 reg_t, dreg, reg_t, nreg, reg_t, mreg);
3377 break;
3379 case 2:
3380 if ( nreg != mreg) {
3381 /* VORR */
3382 HChar reg_t = Q ? 'q' : 'd';
3383 if (Q) {
3384 assign(res, binop(Iop_OrV128, mkexpr(arg_n),
3385 mkexpr(arg_m)));
3386 } else {
3387 assign(res, binop(Iop_Or64, mkexpr(arg_n),
3388 mkexpr(arg_m)));
3390 DIP("vorr %c%u, %c%u, %c%u\n",
3391 reg_t, dreg, reg_t, nreg, reg_t, mreg);
3392 } else {
3393 /* VMOV */
3394 HChar reg_t = Q ? 'q' : 'd';
3395 assign(res, mkexpr(arg_m));
3396 DIP("vmov %c%u, %c%u\n", reg_t, dreg, reg_t, mreg);
3398 break;
3399 case 3:{
3400 /* VORN */
3401 HChar reg_t = Q ? 'q' : 'd';
3402 if (Q) {
3403 assign(res, binop(Iop_OrV128,mkexpr(arg_n),
3404 unop(Iop_NotV128, mkexpr(arg_m))));
3405 } else {
3406 assign(res, binop(Iop_Or64, mkexpr(arg_n),
3407 unop(Iop_Not64, mkexpr(arg_m))));
3409 DIP("vorn %c%u, %c%u, %c%u\n",
3410 reg_t, dreg, reg_t, nreg, reg_t, mreg);
3411 break;
3413 default:
3414 vassert(0);
3416 } else {
3417 switch(C) {
3418 case 0:
3419 /* VEOR (XOR) */
3420 if (Q) {
3421 assign(res, binop(Iop_XorV128, mkexpr(arg_n),
3422 mkexpr(arg_m)));
3423 } else {
3424 assign(res, binop(Iop_Xor64, mkexpr(arg_n),
3425 mkexpr(arg_m)));
3427 DIP("veor %c%u, %c%u, %c%u\n", Q ? 'q' : 'd', dreg,
3428 Q ? 'q' : 'd', nreg, Q ? 'q' : 'd', mreg);
3429 break;
3430 case 1:
3431 /* VBSL */
3432 if (Q) {
3433 IRTemp reg_d = newTemp(Ity_V128);
3434 assign(reg_d, getQReg(dreg));
3435 assign(res,
3436 binop(Iop_OrV128,
3437 binop(Iop_AndV128, mkexpr(arg_n),
3438 mkexpr(reg_d)),
3439 binop(Iop_AndV128,
3440 mkexpr(arg_m),
3441 unop(Iop_NotV128,
3442 mkexpr(reg_d)) ) ) );
3443 } else {
3444 IRTemp reg_d = newTemp(Ity_I64);
3445 assign(reg_d, getDRegI64(dreg));
3446 assign(res,
3447 binop(Iop_Or64,
3448 binop(Iop_And64, mkexpr(arg_n),
3449 mkexpr(reg_d)),
3450 binop(Iop_And64,
3451 mkexpr(arg_m),
3452 unop(Iop_Not64, mkexpr(reg_d)))));
3454 DIP("vbsl %c%u, %c%u, %c%u\n",
3455 Q ? 'q' : 'd', dreg,
3456 Q ? 'q' : 'd', nreg, Q ? 'q' : 'd', mreg);
3457 break;
3458 case 2:
3459 /* VBIT */
3460 if (Q) {
3461 IRTemp reg_d = newTemp(Ity_V128);
3462 assign(reg_d, getQReg(dreg));
3463 assign(res,
3464 binop(Iop_OrV128,
3465 binop(Iop_AndV128, mkexpr(arg_n),
3466 mkexpr(arg_m)),
3467 binop(Iop_AndV128,
3468 mkexpr(reg_d),
3469 unop(Iop_NotV128, mkexpr(arg_m)))));
3470 } else {
3471 IRTemp reg_d = newTemp(Ity_I64);
3472 assign(reg_d, getDRegI64(dreg));
3473 assign(res,
3474 binop(Iop_Or64,
3475 binop(Iop_And64, mkexpr(arg_n),
3476 mkexpr(arg_m)),
3477 binop(Iop_And64,
3478 mkexpr(reg_d),
3479 unop(Iop_Not64, mkexpr(arg_m)))));
3481 DIP("vbit %c%u, %c%u, %c%u\n",
3482 Q ? 'q' : 'd', dreg,
3483 Q ? 'q' : 'd', nreg, Q ? 'q' : 'd', mreg);
3484 break;
3485 case 3:
3486 /* VBIF */
3487 if (Q) {
3488 IRTemp reg_d = newTemp(Ity_V128);
3489 assign(reg_d, getQReg(dreg));
3490 assign(res,
3491 binop(Iop_OrV128,
3492 binop(Iop_AndV128, mkexpr(reg_d),
3493 mkexpr(arg_m)),
3494 binop(Iop_AndV128,
3495 mkexpr(arg_n),
3496 unop(Iop_NotV128, mkexpr(arg_m)))));
3497 } else {
3498 IRTemp reg_d = newTemp(Ity_I64);
3499 assign(reg_d, getDRegI64(dreg));
3500 assign(res,
3501 binop(Iop_Or64,
3502 binop(Iop_And64, mkexpr(reg_d),
3503 mkexpr(arg_m)),
3504 binop(Iop_And64,
3505 mkexpr(arg_n),
3506 unop(Iop_Not64, mkexpr(arg_m)))));
3508 DIP("vbif %c%u, %c%u, %c%u\n",
3509 Q ? 'q' : 'd', dreg,
3510 Q ? 'q' : 'd', nreg, Q ? 'q' : 'd', mreg);
3511 break;
3512 default:
3513 vassert(0);
3517 break;
3518 case 2:
3519 if (B == 0) {
3520 /* VHSUB */
3521 /* (A >> 1) - (B >> 1) - (NOT (A) & B & 1) */
3522 ULong imm = 0;
3523 IRExpr *imm_val;
3524 IROp subOp;
3525 IROp notOp;
3526 IROp andOp;
3527 IROp shOp;
3528 if (size == 3)
3529 return False;
3530 switch(size) {
3531 case 0: imm = 0x101010101010101LL; break;
3532 case 1: imm = 0x1000100010001LL; break;
3533 case 2: imm = 0x100000001LL; break;
3534 default: vassert(0);
3536 if (Q) {
3537 imm_val = binop(Iop_64HLtoV128, mkU64(imm), mkU64(imm));
3538 andOp = Iop_AndV128;
3539 notOp = Iop_NotV128;
3540 } else {
3541 imm_val = mkU64(imm);
3542 andOp = Iop_And64;
3543 notOp = Iop_Not64;
3545 if (U) {
3546 switch(size) {
3547 case 0:
3548 subOp = Q ? Iop_Sub8x16 : Iop_Sub8x8;
3549 shOp = Q ? Iop_ShrN8x16 : Iop_ShrN8x8;
3550 break;
3551 case 1:
3552 subOp = Q ? Iop_Sub16x8 : Iop_Sub16x4;
3553 shOp = Q ? Iop_ShrN16x8 : Iop_ShrN16x4;
3554 break;
3555 case 2:
3556 subOp = Q ? Iop_Sub32x4 : Iop_Sub32x2;
3557 shOp = Q ? Iop_ShrN32x4 : Iop_ShrN32x2;
3558 break;
3559 default:
3560 vassert(0);
3562 } else {
3563 switch(size) {
3564 case 0:
3565 subOp = Q ? Iop_Sub8x16 : Iop_Sub8x8;
3566 shOp = Q ? Iop_SarN8x16 : Iop_SarN8x8;
3567 break;
3568 case 1:
3569 subOp = Q ? Iop_Sub16x8 : Iop_Sub16x4;
3570 shOp = Q ? Iop_SarN16x8 : Iop_SarN16x4;
3571 break;
3572 case 2:
3573 subOp = Q ? Iop_Sub32x4 : Iop_Sub32x2;
3574 shOp = Q ? Iop_SarN32x4 : Iop_SarN32x2;
3575 break;
3576 default:
3577 vassert(0);
3580 assign(res,
3581 binop(subOp,
3582 binop(subOp,
3583 binop(shOp, mkexpr(arg_n), mkU8(1)),
3584 binop(shOp, mkexpr(arg_m), mkU8(1))),
3585 binop(andOp,
3586 binop(andOp,
3587 unop(notOp, mkexpr(arg_n)),
3588 mkexpr(arg_m)),
3589 imm_val)));
3590 DIP("vhsub.%c%d %c%u, %c%u, %c%u\n",
3591 U ? 'u' : 's', 8 << size,
3592 Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', nreg, Q ? 'q' : 'd',
3593 mreg);
3594 } else {
3595 /* VQSUB */
3596 IROp op, op2;
3597 IRTemp tmp;
3598 if (Q) {
3599 switch (size) {
3600 case 0:
3601 op = U ? Iop_QSub8Ux16 : Iop_QSub8Sx16;
3602 op2 = Iop_Sub8x16;
3603 break;
3604 case 1:
3605 op = U ? Iop_QSub16Ux8 : Iop_QSub16Sx8;
3606 op2 = Iop_Sub16x8;
3607 break;
3608 case 2:
3609 op = U ? Iop_QSub32Ux4 : Iop_QSub32Sx4;
3610 op2 = Iop_Sub32x4;
3611 break;
3612 case 3:
3613 op = U ? Iop_QSub64Ux2 : Iop_QSub64Sx2;
3614 op2 = Iop_Sub64x2;
3615 break;
3616 default:
3617 vassert(0);
3619 } else {
3620 switch (size) {
3621 case 0:
3622 op = U ? Iop_QSub8Ux8 : Iop_QSub8Sx8;
3623 op2 = Iop_Sub8x8;
3624 break;
3625 case 1:
3626 op = U ? Iop_QSub16Ux4 : Iop_QSub16Sx4;
3627 op2 = Iop_Sub16x4;
3628 break;
3629 case 2:
3630 op = U ? Iop_QSub32Ux2 : Iop_QSub32Sx2;
3631 op2 = Iop_Sub32x2;
3632 break;
3633 case 3:
3634 op = U ? Iop_QSub64Ux1 : Iop_QSub64Sx1;
3635 op2 = Iop_Sub64;
3636 break;
3637 default:
3638 vassert(0);
3641 if (Q)
3642 tmp = newTemp(Ity_V128);
3643 else
3644 tmp = newTemp(Ity_I64);
3645 assign(res, binop(op, mkexpr(arg_n), mkexpr(arg_m)));
3646 assign(tmp, binop(op2, mkexpr(arg_n), mkexpr(arg_m)));
3647 setFlag_QC(mkexpr(res), mkexpr(tmp), Q, condT);
3648 DIP("vqsub.%c%d %c%u, %c%u, %c%u\n",
3649 U ? 'u' : 's', 8 << size,
3650 Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', nreg, Q ? 'q' : 'd',
3651 mreg);
3653 break;
3654 case 3: {
3655 IROp op;
3656 if (Q) {
3657 switch (size) {
3658 case 0: op = U ? Iop_CmpGT8Ux16 : Iop_CmpGT8Sx16; break;
3659 case 1: op = U ? Iop_CmpGT16Ux8 : Iop_CmpGT16Sx8; break;
3660 case 2: op = U ? Iop_CmpGT32Ux4 : Iop_CmpGT32Sx4; break;
3661 case 3: return False;
3662 default: vassert(0);
3664 } else {
3665 switch (size) {
3666 case 0: op = U ? Iop_CmpGT8Ux8 : Iop_CmpGT8Sx8; break;
3667 case 1: op = U ? Iop_CmpGT16Ux4 : Iop_CmpGT16Sx4; break;
3668 case 2: op = U ? Iop_CmpGT32Ux2: Iop_CmpGT32Sx2; break;
3669 case 3: return False;
3670 default: vassert(0);
3673 if (B == 0) {
3674 /* VCGT */
3675 assign(res, binop(op, mkexpr(arg_n), mkexpr(arg_m)));
3676 DIP("vcgt.%c%d %c%u, %c%u, %c%u\n",
3677 U ? 'u' : 's', 8 << size,
3678 Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', nreg, Q ? 'q' : 'd',
3679 mreg);
3680 } else {
3681 /* VCGE */
3682 /* VCGE res, argn, argm
3683 is equal to
3684 VCGT tmp, argm, argn
3685 VNOT res, tmp */
3686 assign(res,
3687 unop(Q ? Iop_NotV128 : Iop_Not64,
3688 binop(op, mkexpr(arg_m), mkexpr(arg_n))));
3689 DIP("vcge.%c%d %c%u, %c%u, %c%u\n",
3690 U ? 'u' : 's', 8 << size,
3691 Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', nreg, Q ? 'q' : 'd',
3692 mreg);
3695 break;
3696 case 4:
3697 if (B == 0) {
3698 /* VSHL */
3699 IROp op = Iop_INVALID, sub_op = Iop_INVALID;
3700 IRTemp tmp = IRTemp_INVALID;
3701 if (U) {
3702 switch (size) {
3703 case 0: op = Q ? Iop_Shl8x16 : Iop_Shl8x8; break;
3704 case 1: op = Q ? Iop_Shl16x8 : Iop_Shl16x4; break;
3705 case 2: op = Q ? Iop_Shl32x4 : Iop_Shl32x2; break;
3706 case 3: op = Q ? Iop_Shl64x2 : Iop_Shl64; break;
3707 default: vassert(0);
3709 } else {
3710 tmp = newTemp(Q ? Ity_V128 : Ity_I64);
3711 switch (size) {
3712 case 0:
3713 op = Q ? Iop_Sar8x16 : Iop_Sar8x8;
3714 sub_op = Q ? Iop_Sub8x16 : Iop_Sub8x8;
3715 break;
3716 case 1:
3717 op = Q ? Iop_Sar16x8 : Iop_Sar16x4;
3718 sub_op = Q ? Iop_Sub16x8 : Iop_Sub16x4;
3719 break;
3720 case 2:
3721 op = Q ? Iop_Sar32x4 : Iop_Sar32x2;
3722 sub_op = Q ? Iop_Sub32x4 : Iop_Sub32x2;
3723 break;
3724 case 3:
3725 op = Q ? Iop_Sar64x2 : Iop_Sar64;
3726 sub_op = Q ? Iop_Sub64x2 : Iop_Sub64;
3727 break;
3728 default:
3729 vassert(0);
3732 if (U) {
3733 if (!Q && (size == 3))
3734 assign(res, binop(op, mkexpr(arg_m),
3735 unop(Iop_64to8, mkexpr(arg_n))));
3736 else
3737 assign(res, binop(op, mkexpr(arg_m), mkexpr(arg_n)));
3738 } else {
3739 if (Q)
3740 assign(tmp, binop(sub_op,
3741 binop(Iop_64HLtoV128, mkU64(0), mkU64(0)),
3742 mkexpr(arg_n)));
3743 else
3744 assign(tmp, binop(sub_op, mkU64(0), mkexpr(arg_n)));
3745 if (!Q && (size == 3))
3746 assign(res, binop(op, mkexpr(arg_m),
3747 unop(Iop_64to8, mkexpr(tmp))));
3748 else
3749 assign(res, binop(op, mkexpr(arg_m), mkexpr(tmp)));
3751 DIP("vshl.%c%d %c%u, %c%u, %c%u\n",
3752 U ? 'u' : 's', 8 << size,
3753 Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', mreg, Q ? 'q' : 'd',
3754 nreg);
3755 } else {
3756 /* VQSHL */
3757 IROp op, op_rev, op_shrn, op_shln, cmp_neq, cmp_gt;
3758 IRTemp tmp, shval, mask, old_shval;
3759 UInt i;
3760 ULong esize;
3761 cmp_neq = Q ? Iop_CmpNEZ8x16 : Iop_CmpNEZ8x8;
3762 cmp_gt = Q ? Iop_CmpGT8Sx16 : Iop_CmpGT8Sx8;
3763 if (U) {
3764 switch (size) {
3765 case 0:
3766 op = Q ? Iop_QShl8x16 : Iop_QShl8x8;
3767 op_rev = Q ? Iop_Shr8x16 : Iop_Shr8x8;
3768 op_shrn = Q ? Iop_ShrN8x16 : Iop_ShrN8x8;
3769 op_shln = Q ? Iop_ShlN8x16 : Iop_ShlN8x8;
3770 break;
3771 case 1:
3772 op = Q ? Iop_QShl16x8 : Iop_QShl16x4;
3773 op_rev = Q ? Iop_Shr16x8 : Iop_Shr16x4;
3774 op_shrn = Q ? Iop_ShrN16x8 : Iop_ShrN16x4;
3775 op_shln = Q ? Iop_ShlN16x8 : Iop_ShlN16x4;
3776 break;
3777 case 2:
3778 op = Q ? Iop_QShl32x4 : Iop_QShl32x2;
3779 op_rev = Q ? Iop_Shr32x4 : Iop_Shr32x2;
3780 op_shrn = Q ? Iop_ShrN32x4 : Iop_ShrN32x2;
3781 op_shln = Q ? Iop_ShlN32x4 : Iop_ShlN32x2;
3782 break;
3783 case 3:
3784 op = Q ? Iop_QShl64x2 : Iop_QShl64x1;
3785 op_rev = Q ? Iop_Shr64x2 : Iop_Shr64;
3786 op_shrn = Q ? Iop_ShrN64x2 : Iop_Shr64;
3787 op_shln = Q ? Iop_ShlN64x2 : Iop_Shl64;
3788 break;
3789 default:
3790 vassert(0);
3792 } else {
3793 switch (size) {
3794 case 0:
3795 op = Q ? Iop_QSal8x16 : Iop_QSal8x8;
3796 op_rev = Q ? Iop_Sar8x16 : Iop_Sar8x8;
3797 op_shrn = Q ? Iop_ShrN8x16 : Iop_ShrN8x8;
3798 op_shln = Q ? Iop_ShlN8x16 : Iop_ShlN8x8;
3799 break;
3800 case 1:
3801 op = Q ? Iop_QSal16x8 : Iop_QSal16x4;
3802 op_rev = Q ? Iop_Sar16x8 : Iop_Sar16x4;
3803 op_shrn = Q ? Iop_ShrN16x8 : Iop_ShrN16x4;
3804 op_shln = Q ? Iop_ShlN16x8 : Iop_ShlN16x4;
3805 break;
3806 case 2:
3807 op = Q ? Iop_QSal32x4 : Iop_QSal32x2;
3808 op_rev = Q ? Iop_Sar32x4 : Iop_Sar32x2;
3809 op_shrn = Q ? Iop_ShrN32x4 : Iop_ShrN32x2;
3810 op_shln = Q ? Iop_ShlN32x4 : Iop_ShlN32x2;
3811 break;
3812 case 3:
3813 op = Q ? Iop_QSal64x2 : Iop_QSal64x1;
3814 op_rev = Q ? Iop_Sar64x2 : Iop_Sar64;
3815 op_shrn = Q ? Iop_ShrN64x2 : Iop_Shr64;
3816 op_shln = Q ? Iop_ShlN64x2 : Iop_Shl64;
3817 break;
3818 default:
3819 vassert(0);
3822 if (Q) {
3823 tmp = newTemp(Ity_V128);
3824 shval = newTemp(Ity_V128);
3825 mask = newTemp(Ity_V128);
3826 } else {
3827 tmp = newTemp(Ity_I64);
3828 shval = newTemp(Ity_I64);
3829 mask = newTemp(Ity_I64);
3831 assign(res, binop(op, mkexpr(arg_m), mkexpr(arg_n)));
3832 /* Only least significant byte from second argument is used.
3833 Copy this byte to the whole vector element. */
3834 assign(shval, binop(op_shrn,
3835 binop(op_shln,
3836 mkexpr(arg_n),
3837 mkU8((8 << size) - 8)),
3838 mkU8((8 << size) - 8)));
3839 for(i = 0; i < size; i++) {
3840 old_shval = shval;
3841 shval = newTemp(Q ? Ity_V128 : Ity_I64);
3842 assign(shval, binop(Q ? Iop_OrV128 : Iop_Or64,
3843 mkexpr(old_shval),
3844 binop(op_shln,
3845 mkexpr(old_shval),
3846 mkU8(8 << i))));
3848 /* If shift is greater or equal to the element size and
3849 element is non-zero, then QC flag should be set. */
3850 esize = (8 << size) - 1;
3851 esize = (esize << 8) | esize;
3852 esize = (esize << 16) | esize;
3853 esize = (esize << 32) | esize;
3854 setFlag_QC(binop(Q ? Iop_AndV128 : Iop_And64,
3855 binop(cmp_gt, mkexpr(shval),
3856 Q ? mkU128(esize) : mkU64(esize)),
3857 unop(cmp_neq, mkexpr(arg_m))),
3858 Q ? mkU128(0) : mkU64(0),
3859 Q, condT);
3860 /* Othervise QC flag should be set if shift value is positive and
3861 result beign rightshifted the same value is not equal to left
3862 argument. */
3863 assign(mask, binop(cmp_gt, mkexpr(shval),
3864 Q ? mkU128(0) : mkU64(0)));
3865 if (!Q && size == 3)
3866 assign(tmp, binop(op_rev, mkexpr(res),
3867 unop(Iop_64to8, mkexpr(arg_n))));
3868 else
3869 assign(tmp, binop(op_rev, mkexpr(res), mkexpr(arg_n)));
3870 setFlag_QC(binop(Q ? Iop_AndV128 : Iop_And64,
3871 mkexpr(tmp), mkexpr(mask)),
3872 binop(Q ? Iop_AndV128 : Iop_And64,
3873 mkexpr(arg_m), mkexpr(mask)),
3874 Q, condT);
3875 DIP("vqshl.%c%d %c%u, %c%u, %c%u\n",
3876 U ? 'u' : 's', 8 << size,
3877 Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', mreg, Q ? 'q' : 'd',
3878 nreg);
3880 break;
3881 case 5:
3882 if (B == 0) {
3883 /* VRSHL */
3884 IROp op, op_shrn, op_shln, cmp_gt, op_add;
3885 IRTemp shval, old_shval, imm_val, round;
3886 UInt i;
3887 ULong imm;
3888 cmp_gt = Q ? Iop_CmpGT8Sx16 : Iop_CmpGT8Sx8;
3889 imm = 1L;
3890 switch (size) {
3891 case 0: imm = (imm << 8) | imm; /* fall through */
3892 case 1: imm = (imm << 16) | imm; /* fall through */
3893 case 2: imm = (imm << 32) | imm; /* fall through */
3894 case 3: break;
3895 default: vassert(0);
3897 imm_val = newTemp(Q ? Ity_V128 : Ity_I64);
3898 round = newTemp(Q ? Ity_V128 : Ity_I64);
3899 assign(imm_val, Q ? mkU128(imm) : mkU64(imm));
3900 if (U) {
3901 switch (size) {
3902 case 0:
3903 op = Q ? Iop_Shl8x16 : Iop_Shl8x8;
3904 op_add = Q ? Iop_Add8x16 : Iop_Add8x8;
3905 op_shrn = Q ? Iop_ShrN8x16 : Iop_ShrN8x8;
3906 op_shln = Q ? Iop_ShlN8x16 : Iop_ShlN8x8;
3907 break;
3908 case 1:
3909 op = Q ? Iop_Shl16x8 : Iop_Shl16x4;
3910 op_add = Q ? Iop_Add16x8 : Iop_Add16x4;
3911 op_shrn = Q ? Iop_ShrN16x8 : Iop_ShrN16x4;
3912 op_shln = Q ? Iop_ShlN16x8 : Iop_ShlN16x4;
3913 break;
3914 case 2:
3915 op = Q ? Iop_Shl32x4 : Iop_Shl32x2;
3916 op_add = Q ? Iop_Add32x4 : Iop_Add32x2;
3917 op_shrn = Q ? Iop_ShrN32x4 : Iop_ShrN32x2;
3918 op_shln = Q ? Iop_ShlN32x4 : Iop_ShlN32x2;
3919 break;
3920 case 3:
3921 op = Q ? Iop_Shl64x2 : Iop_Shl64;
3922 op_add = Q ? Iop_Add64x2 : Iop_Add64;
3923 op_shrn = Q ? Iop_ShrN64x2 : Iop_Shr64;
3924 op_shln = Q ? Iop_ShlN64x2 : Iop_Shl64;
3925 break;
3926 default:
3927 vassert(0);
3929 } else {
3930 switch (size) {
3931 case 0:
3932 op = Q ? Iop_Sal8x16 : Iop_Sal8x8;
3933 op_add = Q ? Iop_Add8x16 : Iop_Add8x8;
3934 op_shrn = Q ? Iop_ShrN8x16 : Iop_ShrN8x8;
3935 op_shln = Q ? Iop_ShlN8x16 : Iop_ShlN8x8;
3936 break;
3937 case 1:
3938 op = Q ? Iop_Sal16x8 : Iop_Sal16x4;
3939 op_add = Q ? Iop_Add16x8 : Iop_Add16x4;
3940 op_shrn = Q ? Iop_ShrN16x8 : Iop_ShrN16x4;
3941 op_shln = Q ? Iop_ShlN16x8 : Iop_ShlN16x4;
3942 break;
3943 case 2:
3944 op = Q ? Iop_Sal32x4 : Iop_Sal32x2;
3945 op_add = Q ? Iop_Add32x4 : Iop_Add32x2;
3946 op_shrn = Q ? Iop_ShrN32x4 : Iop_ShrN32x2;
3947 op_shln = Q ? Iop_ShlN32x4 : Iop_ShlN32x2;
3948 break;
3949 case 3:
3950 op = Q ? Iop_Sal64x2 : Iop_Sal64x1;
3951 op_add = Q ? Iop_Add64x2 : Iop_Add64;
3952 op_shrn = Q ? Iop_ShrN64x2 : Iop_Shr64;
3953 op_shln = Q ? Iop_ShlN64x2 : Iop_Shl64;
3954 break;
3955 default:
3956 vassert(0);
3959 if (Q) {
3960 shval = newTemp(Ity_V128);
3961 } else {
3962 shval = newTemp(Ity_I64);
3964 /* Only least significant byte from second argument is used.
3965 Copy this byte to the whole vector element. */
3966 assign(shval, binop(op_shrn,
3967 binop(op_shln,
3968 mkexpr(arg_n),
3969 mkU8((8 << size) - 8)),
3970 mkU8((8 << size) - 8)));
3971 for (i = 0; i < size; i++) {
3972 old_shval = shval;
3973 shval = newTemp(Q ? Ity_V128 : Ity_I64);
3974 assign(shval, binop(Q ? Iop_OrV128 : Iop_Or64,
3975 mkexpr(old_shval),
3976 binop(op_shln,
3977 mkexpr(old_shval),
3978 mkU8(8 << i))));
3980 /* Compute the result */
3981 if (!Q && size == 3 && U) {
3982 assign(round, binop(Q ? Iop_AndV128 : Iop_And64,
3983 binop(op,
3984 mkexpr(arg_m),
3985 unop(Iop_64to8,
3986 binop(op_add,
3987 mkexpr(arg_n),
3988 mkexpr(imm_val)))),
3989 binop(Q ? Iop_AndV128 : Iop_And64,
3990 mkexpr(imm_val),
3991 binop(cmp_gt,
3992 Q ? mkU128(0) : mkU64(0),
3993 mkexpr(arg_n)))));
3994 assign(res, binop(op_add,
3995 binop(op,
3996 mkexpr(arg_m),
3997 unop(Iop_64to8, mkexpr(arg_n))),
3998 mkexpr(round)));
3999 } else {
4000 assign(round, binop(Q ? Iop_AndV128 : Iop_And64,
4001 binop(op,
4002 mkexpr(arg_m),
4003 binop(op_add,
4004 mkexpr(arg_n),
4005 mkexpr(imm_val))),
4006 binop(Q ? Iop_AndV128 : Iop_And64,
4007 mkexpr(imm_val),
4008 binop(cmp_gt,
4009 Q ? mkU128(0) : mkU64(0),
4010 mkexpr(arg_n)))));
4011 assign(res, binop(op_add,
4012 binop(op, mkexpr(arg_m), mkexpr(arg_n)),
4013 mkexpr(round)));
4015 DIP("vrshl.%c%d %c%u, %c%u, %c%u\n",
4016 U ? 'u' : 's', 8 << size,
4017 Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', mreg, Q ? 'q' : 'd',
4018 nreg);
4019 } else {
4020 /* VQRSHL */
4021 IROp op, op_rev, op_shrn, op_shln, cmp_neq, cmp_gt, op_add;
4022 IRTemp tmp, shval, mask, old_shval, imm_val, round;
4023 UInt i;
4024 ULong esize, imm;
4025 cmp_neq = Q ? Iop_CmpNEZ8x16 : Iop_CmpNEZ8x8;
4026 cmp_gt = Q ? Iop_CmpGT8Sx16 : Iop_CmpGT8Sx8;
4027 imm = 1L;
4028 switch (size) {
4029 case 0: imm = (imm << 8) | imm; /* fall through */
4030 case 1: imm = (imm << 16) | imm; /* fall through */
4031 case 2: imm = (imm << 32) | imm; /* fall through */
4032 case 3: break;
4033 default: vassert(0);
4035 imm_val = newTemp(Q ? Ity_V128 : Ity_I64);
4036 round = newTemp(Q ? Ity_V128 : Ity_I64);
4037 assign(imm_val, Q ? mkU128(imm) : mkU64(imm));
4038 if (U) {
4039 switch (size) {
4040 case 0:
4041 op = Q ? Iop_QShl8x16 : Iop_QShl8x8;
4042 op_add = Q ? Iop_Add8x16 : Iop_Add8x8;
4043 op_rev = Q ? Iop_Shr8x16 : Iop_Shr8x8;
4044 op_shrn = Q ? Iop_ShrN8x16 : Iop_ShrN8x8;
4045 op_shln = Q ? Iop_ShlN8x16 : Iop_ShlN8x8;
4046 break;
4047 case 1:
4048 op = Q ? Iop_QShl16x8 : Iop_QShl16x4;
4049 op_add = Q ? Iop_Add16x8 : Iop_Add16x4;
4050 op_rev = Q ? Iop_Shr16x8 : Iop_Shr16x4;
4051 op_shrn = Q ? Iop_ShrN16x8 : Iop_ShrN16x4;
4052 op_shln = Q ? Iop_ShlN16x8 : Iop_ShlN16x4;
4053 break;
4054 case 2:
4055 op = Q ? Iop_QShl32x4 : Iop_QShl32x2;
4056 op_add = Q ? Iop_Add32x4 : Iop_Add32x2;
4057 op_rev = Q ? Iop_Shr32x4 : Iop_Shr32x2;
4058 op_shrn = Q ? Iop_ShrN32x4 : Iop_ShrN32x2;
4059 op_shln = Q ? Iop_ShlN32x4 : Iop_ShlN32x2;
4060 break;
4061 case 3:
4062 op = Q ? Iop_QShl64x2 : Iop_QShl64x1;
4063 op_add = Q ? Iop_Add64x2 : Iop_Add64;
4064 op_rev = Q ? Iop_Shr64x2 : Iop_Shr64;
4065 op_shrn = Q ? Iop_ShrN64x2 : Iop_Shr64;
4066 op_shln = Q ? Iop_ShlN64x2 : Iop_Shl64;
4067 break;
4068 default:
4069 vassert(0);
4071 } else {
4072 switch (size) {
4073 case 0:
4074 op = Q ? Iop_QSal8x16 : Iop_QSal8x8;
4075 op_add = Q ? Iop_Add8x16 : Iop_Add8x8;
4076 op_rev = Q ? Iop_Sar8x16 : Iop_Sar8x8;
4077 op_shrn = Q ? Iop_ShrN8x16 : Iop_ShrN8x8;
4078 op_shln = Q ? Iop_ShlN8x16 : Iop_ShlN8x8;
4079 break;
4080 case 1:
4081 op = Q ? Iop_QSal16x8 : Iop_QSal16x4;
4082 op_add = Q ? Iop_Add16x8 : Iop_Add16x4;
4083 op_rev = Q ? Iop_Sar16x8 : Iop_Sar16x4;
4084 op_shrn = Q ? Iop_ShrN16x8 : Iop_ShrN16x4;
4085 op_shln = Q ? Iop_ShlN16x8 : Iop_ShlN16x4;
4086 break;
4087 case 2:
4088 op = Q ? Iop_QSal32x4 : Iop_QSal32x2;
4089 op_add = Q ? Iop_Add32x4 : Iop_Add32x2;
4090 op_rev = Q ? Iop_Sar32x4 : Iop_Sar32x2;
4091 op_shrn = Q ? Iop_ShrN32x4 : Iop_ShrN32x2;
4092 op_shln = Q ? Iop_ShlN32x4 : Iop_ShlN32x2;
4093 break;
4094 case 3:
4095 op = Q ? Iop_QSal64x2 : Iop_QSal64x1;
4096 op_add = Q ? Iop_Add64x2 : Iop_Add64;
4097 op_rev = Q ? Iop_Sar64x2 : Iop_Sar64;
4098 op_shrn = Q ? Iop_ShrN64x2 : Iop_Shr64;
4099 op_shln = Q ? Iop_ShlN64x2 : Iop_Shl64;
4100 break;
4101 default:
4102 vassert(0);
4105 if (Q) {
4106 tmp = newTemp(Ity_V128);
4107 shval = newTemp(Ity_V128);
4108 mask = newTemp(Ity_V128);
4109 } else {
4110 tmp = newTemp(Ity_I64);
4111 shval = newTemp(Ity_I64);
4112 mask = newTemp(Ity_I64);
4114 /* Only least significant byte from second argument is used.
4115 Copy this byte to the whole vector element. */
4116 assign(shval, binop(op_shrn,
4117 binop(op_shln,
4118 mkexpr(arg_n),
4119 mkU8((8 << size) - 8)),
4120 mkU8((8 << size) - 8)));
4121 for (i = 0; i < size; i++) {
4122 old_shval = shval;
4123 shval = newTemp(Q ? Ity_V128 : Ity_I64);
4124 assign(shval, binop(Q ? Iop_OrV128 : Iop_Or64,
4125 mkexpr(old_shval),
4126 binop(op_shln,
4127 mkexpr(old_shval),
4128 mkU8(8 << i))));
4130 /* Compute the result */
4131 assign(round, binop(Q ? Iop_AndV128 : Iop_And64,
4132 binop(op,
4133 mkexpr(arg_m),
4134 binop(op_add,
4135 mkexpr(arg_n),
4136 mkexpr(imm_val))),
4137 binop(Q ? Iop_AndV128 : Iop_And64,
4138 mkexpr(imm_val),
4139 binop(cmp_gt,
4140 Q ? mkU128(0) : mkU64(0),
4141 mkexpr(arg_n)))));
4142 assign(res, binop(op_add,
4143 binop(op, mkexpr(arg_m), mkexpr(arg_n)),
4144 mkexpr(round)));
4145 /* If shift is greater or equal to the element size and element is
4146 non-zero, then QC flag should be set. */
4147 esize = (8 << size) - 1;
4148 esize = (esize << 8) | esize;
4149 esize = (esize << 16) | esize;
4150 esize = (esize << 32) | esize;
4151 setFlag_QC(binop(Q ? Iop_AndV128 : Iop_And64,
4152 binop(cmp_gt, mkexpr(shval),
4153 Q ? mkU128(esize) : mkU64(esize)),
4154 unop(cmp_neq, mkexpr(arg_m))),
4155 Q ? mkU128(0) : mkU64(0),
4156 Q, condT);
4157 /* Othervise QC flag should be set if shift value is positive and
4158 result beign rightshifted the same value is not equal to left
4159 argument. */
4160 assign(mask, binop(cmp_gt, mkexpr(shval),
4161 Q ? mkU128(0) : mkU64(0)));
4162 if (!Q && size == 3)
4163 assign(tmp, binop(op_rev, mkexpr(res),
4164 unop(Iop_64to8, mkexpr(arg_n))));
4165 else
4166 assign(tmp, binop(op_rev, mkexpr(res), mkexpr(arg_n)));
4167 setFlag_QC(binop(Q ? Iop_AndV128 : Iop_And64,
4168 mkexpr(tmp), mkexpr(mask)),
4169 binop(Q ? Iop_AndV128 : Iop_And64,
4170 mkexpr(arg_m), mkexpr(mask)),
4171 Q, condT);
4172 DIP("vqrshl.%c%d %c%u, %c%u, %c%u\n",
4173 U ? 'u' : 's', 8 << size,
4174 Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', mreg, Q ? 'q' : 'd',
4175 nreg);
4177 break;
4178 case 6:
4179 /* VMAX, VMIN */
4180 if (B == 0) {
4181 /* VMAX */
4182 IROp op;
4183 if (U == 0) {
4184 switch (size) {
4185 case 0: op = Q ? Iop_Max8Sx16 : Iop_Max8Sx8; break;
4186 case 1: op = Q ? Iop_Max16Sx8 : Iop_Max16Sx4; break;
4187 case 2: op = Q ? Iop_Max32Sx4 : Iop_Max32Sx2; break;
4188 case 3: return False;
4189 default: vassert(0);
4191 } else {
4192 switch (size) {
4193 case 0: op = Q ? Iop_Max8Ux16 : Iop_Max8Ux8; break;
4194 case 1: op = Q ? Iop_Max16Ux8 : Iop_Max16Ux4; break;
4195 case 2: op = Q ? Iop_Max32Ux4 : Iop_Max32Ux2; break;
4196 case 3: return False;
4197 default: vassert(0);
4200 assign(res, binop(op, mkexpr(arg_n), mkexpr(arg_m)));
4201 DIP("vmax.%c%d %c%u, %c%u, %c%u\n",
4202 U ? 'u' : 's', 8 << size,
4203 Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', nreg, Q ? 'q' : 'd',
4204 mreg);
4205 } else {
4206 /* VMIN */
4207 IROp op;
4208 if (U == 0) {
4209 switch (size) {
4210 case 0: op = Q ? Iop_Min8Sx16 : Iop_Min8Sx8; break;
4211 case 1: op = Q ? Iop_Min16Sx8 : Iop_Min16Sx4; break;
4212 case 2: op = Q ? Iop_Min32Sx4 : Iop_Min32Sx2; break;
4213 case 3: return False;
4214 default: vassert(0);
4216 } else {
4217 switch (size) {
4218 case 0: op = Q ? Iop_Min8Ux16 : Iop_Min8Ux8; break;
4219 case 1: op = Q ? Iop_Min16Ux8 : Iop_Min16Ux4; break;
4220 case 2: op = Q ? Iop_Min32Ux4 : Iop_Min32Ux2; break;
4221 case 3: return False;
4222 default: vassert(0);
4225 assign(res, binop(op, mkexpr(arg_n), mkexpr(arg_m)));
4226 DIP("vmin.%c%d %c%u, %c%u, %c%u\n",
4227 U ? 'u' : 's', 8 << size,
4228 Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', nreg, Q ? 'q' : 'd',
4229 mreg);
4231 break;
4232 case 7:
4233 if (B == 0) {
4234 /* VABD */
4235 IROp op_cmp, op_sub;
4236 IRTemp cond;
4237 if ((theInstr >> 23) & 1) {
4238 vpanic("VABDL should not be in dis_neon_data_3same\n");
4240 if (Q) {
4241 switch (size) {
4242 case 0:
4243 op_cmp = U ? Iop_CmpGT8Ux16 : Iop_CmpGT8Sx16;
4244 op_sub = Iop_Sub8x16;
4245 break;
4246 case 1:
4247 op_cmp = U ? Iop_CmpGT16Ux8 : Iop_CmpGT16Sx8;
4248 op_sub = Iop_Sub16x8;
4249 break;
4250 case 2:
4251 op_cmp = U ? Iop_CmpGT32Ux4 : Iop_CmpGT32Sx4;
4252 op_sub = Iop_Sub32x4;
4253 break;
4254 case 3:
4255 return False;
4256 default:
4257 vassert(0);
4259 } else {
4260 switch (size) {
4261 case 0:
4262 op_cmp = U ? Iop_CmpGT8Ux8 : Iop_CmpGT8Sx8;
4263 op_sub = Iop_Sub8x8;
4264 break;
4265 case 1:
4266 op_cmp = U ? Iop_CmpGT16Ux4 : Iop_CmpGT16Sx4;
4267 op_sub = Iop_Sub16x4;
4268 break;
4269 case 2:
4270 op_cmp = U ? Iop_CmpGT32Ux2 : Iop_CmpGT32Sx2;
4271 op_sub = Iop_Sub32x2;
4272 break;
4273 case 3:
4274 return False;
4275 default:
4276 vassert(0);
4279 if (Q) {
4280 cond = newTemp(Ity_V128);
4281 } else {
4282 cond = newTemp(Ity_I64);
4284 assign(cond, binop(op_cmp, mkexpr(arg_n), mkexpr(arg_m)));
4285 assign(res, binop(Q ? Iop_OrV128 : Iop_Or64,
4286 binop(Q ? Iop_AndV128 : Iop_And64,
4287 binop(op_sub, mkexpr(arg_n),
4288 mkexpr(arg_m)),
4289 mkexpr(cond)),
4290 binop(Q ? Iop_AndV128 : Iop_And64,
4291 binop(op_sub, mkexpr(arg_m),
4292 mkexpr(arg_n)),
4293 unop(Q ? Iop_NotV128 : Iop_Not64,
4294 mkexpr(cond)))));
4295 DIP("vabd.%c%d %c%u, %c%u, %c%u\n",
4296 U ? 'u' : 's', 8 << size,
4297 Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', nreg, Q ? 'q' : 'd',
4298 mreg);
4299 } else {
4300 /* VABA */
4301 IROp op_cmp, op_sub, op_add;
4302 IRTemp cond, acc, tmp;
4303 if ((theInstr >> 23) & 1) {
4304 vpanic("VABAL should not be in dis_neon_data_3same");
4306 if (Q) {
4307 switch (size) {
4308 case 0:
4309 op_cmp = U ? Iop_CmpGT8Ux16 : Iop_CmpGT8Sx16;
4310 op_sub = Iop_Sub8x16;
4311 op_add = Iop_Add8x16;
4312 break;
4313 case 1:
4314 op_cmp = U ? Iop_CmpGT16Ux8 : Iop_CmpGT16Sx8;
4315 op_sub = Iop_Sub16x8;
4316 op_add = Iop_Add16x8;
4317 break;
4318 case 2:
4319 op_cmp = U ? Iop_CmpGT32Ux4 : Iop_CmpGT32Sx4;
4320 op_sub = Iop_Sub32x4;
4321 op_add = Iop_Add32x4;
4322 break;
4323 case 3:
4324 return False;
4325 default:
4326 vassert(0);
4328 } else {
4329 switch (size) {
4330 case 0:
4331 op_cmp = U ? Iop_CmpGT8Ux8 : Iop_CmpGT8Sx8;
4332 op_sub = Iop_Sub8x8;
4333 op_add = Iop_Add8x8;
4334 break;
4335 case 1:
4336 op_cmp = U ? Iop_CmpGT16Ux4 : Iop_CmpGT16Sx4;
4337 op_sub = Iop_Sub16x4;
4338 op_add = Iop_Add16x4;
4339 break;
4340 case 2:
4341 op_cmp = U ? Iop_CmpGT32Ux2 : Iop_CmpGT32Sx2;
4342 op_sub = Iop_Sub32x2;
4343 op_add = Iop_Add32x2;
4344 break;
4345 case 3:
4346 return False;
4347 default:
4348 vassert(0);
4351 if (Q) {
4352 cond = newTemp(Ity_V128);
4353 acc = newTemp(Ity_V128);
4354 tmp = newTemp(Ity_V128);
4355 assign(acc, getQReg(dreg));
4356 } else {
4357 cond = newTemp(Ity_I64);
4358 acc = newTemp(Ity_I64);
4359 tmp = newTemp(Ity_I64);
4360 assign(acc, getDRegI64(dreg));
4362 assign(cond, binop(op_cmp, mkexpr(arg_n), mkexpr(arg_m)));
4363 assign(tmp, binop(Q ? Iop_OrV128 : Iop_Or64,
4364 binop(Q ? Iop_AndV128 : Iop_And64,
4365 binop(op_sub, mkexpr(arg_n),
4366 mkexpr(arg_m)),
4367 mkexpr(cond)),
4368 binop(Q ? Iop_AndV128 : Iop_And64,
4369 binop(op_sub, mkexpr(arg_m),
4370 mkexpr(arg_n)),
4371 unop(Q ? Iop_NotV128 : Iop_Not64,
4372 mkexpr(cond)))));
4373 assign(res, binop(op_add, mkexpr(acc), mkexpr(tmp)));
4374 DIP("vaba.%c%d %c%u, %c%u, %c%u\n",
4375 U ? 'u' : 's', 8 << size,
4376 Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', nreg, Q ? 'q' : 'd',
4377 mreg);
4379 break;
4380 case 8:
4381 if (B == 0) {
4382 IROp op;
4383 if (U == 0) {
4384 /* VADD */
4385 switch (size) {
4386 case 0: op = Q ? Iop_Add8x16 : Iop_Add8x8; break;
4387 case 1: op = Q ? Iop_Add16x8 : Iop_Add16x4; break;
4388 case 2: op = Q ? Iop_Add32x4 : Iop_Add32x2; break;
4389 case 3: op = Q ? Iop_Add64x2 : Iop_Add64; break;
4390 default: vassert(0);
4392 DIP("vadd.i%d %c%u, %c%u, %c%u\n",
4393 8 << size, Q ? 'q' : 'd',
4394 dreg, Q ? 'q' : 'd', nreg, Q ? 'q' : 'd', mreg);
4395 } else {
4396 /* VSUB */
4397 switch (size) {
4398 case 0: op = Q ? Iop_Sub8x16 : Iop_Sub8x8; break;
4399 case 1: op = Q ? Iop_Sub16x8 : Iop_Sub16x4; break;
4400 case 2: op = Q ? Iop_Sub32x4 : Iop_Sub32x2; break;
4401 case 3: op = Q ? Iop_Sub64x2 : Iop_Sub64; break;
4402 default: vassert(0);
4404 DIP("vsub.i%d %c%u, %c%u, %c%u\n",
4405 8 << size, Q ? 'q' : 'd',
4406 dreg, Q ? 'q' : 'd', nreg, Q ? 'q' : 'd', mreg);
4408 assign(res, binop(op, mkexpr(arg_n), mkexpr(arg_m)));
4409 } else {
4410 IROp op;
4411 switch (size) {
4412 case 0: op = Q ? Iop_CmpNEZ8x16 : Iop_CmpNEZ8x8; break;
4413 case 1: op = Q ? Iop_CmpNEZ16x8 : Iop_CmpNEZ16x4; break;
4414 case 2: op = Q ? Iop_CmpNEZ32x4 : Iop_CmpNEZ32x2; break;
4415 case 3: op = Q ? Iop_CmpNEZ64x2 : Iop_CmpwNEZ64; break;
4416 default: vassert(0);
4418 if (U == 0) {
4419 /* VTST */
4420 assign(res, unop(op, binop(Q ? Iop_AndV128 : Iop_And64,
4421 mkexpr(arg_n),
4422 mkexpr(arg_m))));
4423 DIP("vtst.%d %c%u, %c%u, %c%u\n",
4424 8 << size, Q ? 'q' : 'd',
4425 dreg, Q ? 'q' : 'd', nreg, Q ? 'q' : 'd', mreg);
4426 } else {
4427 /* VCEQ */
4428 assign(res, unop(Q ? Iop_NotV128 : Iop_Not64,
4429 unop(op,
4430 binop(Q ? Iop_XorV128 : Iop_Xor64,
4431 mkexpr(arg_n),
4432 mkexpr(arg_m)))));
4433 DIP("vceq.i%d %c%u, %c%u, %c%u\n",
4434 8 << size, Q ? 'q' : 'd',
4435 dreg, Q ? 'q' : 'd', nreg, Q ? 'q' : 'd', mreg);
4438 break;
4439 case 9:
4440 if (B == 0) {
4441 /* VMLA, VMLS (integer) */
4442 IROp op, op2;
4443 UInt P = (theInstr >> 24) & 1;
4444 if (P) {
4445 switch (size) {
4446 case 0:
4447 op = Q ? Iop_Mul8x16 : Iop_Mul8x8;
4448 op2 = Q ? Iop_Sub8x16 : Iop_Sub8x8;
4449 break;
4450 case 1:
4451 op = Q ? Iop_Mul16x8 : Iop_Mul16x4;
4452 op2 = Q ? Iop_Sub16x8 : Iop_Sub16x4;
4453 break;
4454 case 2:
4455 op = Q ? Iop_Mul32x4 : Iop_Mul32x2;
4456 op2 = Q ? Iop_Sub32x4 : Iop_Sub32x2;
4457 break;
4458 case 3:
4459 return False;
4460 default:
4461 vassert(0);
4463 } else {
4464 switch (size) {
4465 case 0:
4466 op = Q ? Iop_Mul8x16 : Iop_Mul8x8;
4467 op2 = Q ? Iop_Add8x16 : Iop_Add8x8;
4468 break;
4469 case 1:
4470 op = Q ? Iop_Mul16x8 : Iop_Mul16x4;
4471 op2 = Q ? Iop_Add16x8 : Iop_Add16x4;
4472 break;
4473 case 2:
4474 op = Q ? Iop_Mul32x4 : Iop_Mul32x2;
4475 op2 = Q ? Iop_Add32x4 : Iop_Add32x2;
4476 break;
4477 case 3:
4478 return False;
4479 default:
4480 vassert(0);
4483 assign(res, binop(op2,
4484 Q ? getQReg(dreg) : getDRegI64(dreg),
4485 binop(op, mkexpr(arg_n), mkexpr(arg_m))));
4486 DIP("vml%c.i%d %c%u, %c%u, %c%u\n",
4487 P ? 's' : 'a', 8 << size,
4488 Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', nreg, Q ? 'q' : 'd',
4489 mreg);
4490 } else {
4491 /* VMUL */
4492 IROp op;
4493 UInt P = (theInstr >> 24) & 1;
4494 if (P) {
4495 switch (size) {
4496 case 0:
4497 op = Q ? Iop_PolynomialMul8x16 : Iop_PolynomialMul8x8;
4498 break;
4499 case 1: case 2: case 3: return False;
4500 default: vassert(0);
4502 } else {
4503 switch (size) {
4504 case 0: op = Q ? Iop_Mul8x16 : Iop_Mul8x8; break;
4505 case 1: op = Q ? Iop_Mul16x8 : Iop_Mul16x4; break;
4506 case 2: op = Q ? Iop_Mul32x4 : Iop_Mul32x2; break;
4507 case 3: return False;
4508 default: vassert(0);
4511 assign(res, binop(op, mkexpr(arg_n), mkexpr(arg_m)));
4512 DIP("vmul.%c%d %c%u, %c%u, %c%u\n",
4513 P ? 'p' : 'i', 8 << size,
4514 Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', nreg, Q ? 'q' : 'd',
4515 mreg);
4517 break;
4518 case 10: {
4519 /* VPMAX, VPMIN */
4520 UInt P = (theInstr >> 4) & 1;
4521 IROp op;
4522 if (Q)
4523 return False;
4524 if (P) {
4525 switch (size) {
4526 case 0: op = U ? Iop_PwMin8Ux8 : Iop_PwMin8Sx8; break;
4527 case 1: op = U ? Iop_PwMin16Ux4 : Iop_PwMin16Sx4; break;
4528 case 2: op = U ? Iop_PwMin32Ux2 : Iop_PwMin32Sx2; break;
4529 case 3: return False;
4530 default: vassert(0);
4532 } else {
4533 switch (size) {
4534 case 0: op = U ? Iop_PwMax8Ux8 : Iop_PwMax8Sx8; break;
4535 case 1: op = U ? Iop_PwMax16Ux4 : Iop_PwMax16Sx4; break;
4536 case 2: op = U ? Iop_PwMax32Ux2 : Iop_PwMax32Sx2; break;
4537 case 3: return False;
4538 default: vassert(0);
4541 assign(res, binop(op, mkexpr(arg_n), mkexpr(arg_m)));
4542 DIP("vp%s.%c%d %c%u, %c%u, %c%u\n",
4543 P ? "min" : "max", U ? 'u' : 's',
4544 8 << size, Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', nreg,
4545 Q ? 'q' : 'd', mreg);
4546 break;
4548 case 11:
4549 if (B == 0) {
4550 if (U == 0) {
4551 /* VQDMULH */
4552 IROp op ,op2;
4553 ULong imm;
4554 switch (size) {
4555 case 0: case 3:
4556 return False;
4557 case 1:
4558 op = Q ? Iop_QDMulHi16Sx8 : Iop_QDMulHi16Sx4;
4559 op2 = Q ? Iop_CmpEQ16x8 : Iop_CmpEQ16x4;
4560 imm = 1LL << 15;
4561 imm = (imm << 16) | imm;
4562 imm = (imm << 32) | imm;
4563 break;
4564 case 2:
4565 op = Q ? Iop_QDMulHi32Sx4 : Iop_QDMulHi32Sx2;
4566 op2 = Q ? Iop_CmpEQ32x4 : Iop_CmpEQ32x2;
4567 imm = 1LL << 31;
4568 imm = (imm << 32) | imm;
4569 break;
4570 default:
4571 vassert(0);
4573 assign(res, binop(op, mkexpr(arg_n), mkexpr(arg_m)));
4574 setFlag_QC(binop(Q ? Iop_AndV128 : Iop_And64,
4575 binop(op2, mkexpr(arg_n),
4576 Q ? mkU128(imm) : mkU64(imm)),
4577 binop(op2, mkexpr(arg_m),
4578 Q ? mkU128(imm) : mkU64(imm))),
4579 Q ? mkU128(0) : mkU64(0),
4580 Q, condT);
4581 DIP("vqdmulh.s%d %c%u, %c%u, %c%u\n",
4582 8 << size, Q ? 'q' : 'd',
4583 dreg, Q ? 'q' : 'd', nreg, Q ? 'q' : 'd', mreg);
4584 } else {
4585 /* VQRDMULH */
4586 IROp op ,op2;
4587 ULong imm;
4588 switch(size) {
4589 case 0: case 3:
4590 return False;
4591 case 1:
4592 imm = 1LL << 15;
4593 imm = (imm << 16) | imm;
4594 imm = (imm << 32) | imm;
4595 op = Q ? Iop_QRDMulHi16Sx8 : Iop_QRDMulHi16Sx4;
4596 op2 = Q ? Iop_CmpEQ16x8 : Iop_CmpEQ16x4;
4597 break;
4598 case 2:
4599 imm = 1LL << 31;
4600 imm = (imm << 32) | imm;
4601 op = Q ? Iop_QRDMulHi32Sx4 : Iop_QRDMulHi32Sx2;
4602 op2 = Q ? Iop_CmpEQ32x4 : Iop_CmpEQ32x2;
4603 break;
4604 default:
4605 vassert(0);
4607 assign(res, binop(op, mkexpr(arg_n), mkexpr(arg_m)));
4608 setFlag_QC(binop(Q ? Iop_AndV128 : Iop_And64,
4609 binop(op2, mkexpr(arg_n),
4610 Q ? mkU128(imm) : mkU64(imm)),
4611 binop(op2, mkexpr(arg_m),
4612 Q ? mkU128(imm) : mkU64(imm))),
4613 Q ? mkU128(0) : mkU64(0),
4614 Q, condT);
4615 DIP("vqrdmulh.s%d %c%u, %c%u, %c%u\n",
4616 8 << size, Q ? 'q' : 'd',
4617 dreg, Q ? 'q' : 'd', nreg, Q ? 'q' : 'd', mreg);
4619 } else {
4620 if (U == 0) {
4621 /* VPADD */
4622 IROp op;
4623 if (Q)
4624 return False;
4625 switch (size) {
4626 case 0: op = Q ? Iop_PwAdd8x16 : Iop_PwAdd8x8; break;
4627 case 1: op = Q ? Iop_PwAdd16x8 : Iop_PwAdd16x4; break;
4628 case 2: op = Q ? Iop_PwAdd32x4 : Iop_PwAdd32x2; break;
4629 case 3: return False;
4630 default: vassert(0);
4632 assign(res, binop(op, mkexpr(arg_n), mkexpr(arg_m)));
4633 DIP("vpadd.i%d %c%u, %c%u, %c%u\n",
4634 8 << size, Q ? 'q' : 'd',
4635 dreg, Q ? 'q' : 'd', nreg, Q ? 'q' : 'd', mreg);
4636 } else {
4637 return False;
4640 break;
4641 case 12: {
4642 return False;
4644 /* Starting from here these are FP SIMD cases */
4645 case 13:
4646 if (B == 0) {
4647 IROp op;
4648 if (U == 0) {
4649 if ((C >> 1) == 0) {
4650 /* VADD */
4651 op = Q ? Iop_Add32Fx4 : Iop_Add32Fx2 ;
4652 DIP("vadd.f32 %c%u, %c%u, %c%u\n",
4653 Q ? 'q' : 'd', dreg,
4654 Q ? 'q' : 'd', nreg, Q ? 'q' : 'd', mreg);
4655 } else {
4656 /* VSUB */
4657 op = Q ? Iop_Sub32Fx4 : Iop_Sub32Fx2 ;
4658 DIP("vsub.f32 %c%u, %c%u, %c%u\n",
4659 Q ? 'q' : 'd', dreg,
4660 Q ? 'q' : 'd', nreg, Q ? 'q' : 'd', mreg);
4662 } else {
4663 if ((C >> 1) == 0) {
4664 /* VPADD */
4665 if (Q)
4666 return False;
4667 op = Iop_PwAdd32Fx2;
4668 DIP("vpadd.f32 d%u, d%u, d%u\n", dreg, nreg, mreg);
4669 } else {
4670 /* VABD */
4671 if (Q) {
4672 assign(res, unop(Iop_Abs32Fx4,
4673 triop(Iop_Sub32Fx4,
4674 get_FAKE_roundingmode(),
4675 mkexpr(arg_n),
4676 mkexpr(arg_m))));
4677 } else {
4678 assign(res, unop(Iop_Abs32Fx2,
4679 binop(Iop_Sub32Fx2,
4680 mkexpr(arg_n),
4681 mkexpr(arg_m))));
4683 DIP("vabd.f32 %c%u, %c%u, %c%u\n",
4684 Q ? 'q' : 'd', dreg,
4685 Q ? 'q' : 'd', nreg, Q ? 'q' : 'd', mreg);
4686 break;
4689 assign(res, binop_w_fake_RM(op, mkexpr(arg_n), mkexpr(arg_m)));
4690 } else {
4691 if (U == 0) {
4692 /* VMLA, VMLS */
4693 IROp op, op2;
4694 UInt P = (theInstr >> 21) & 1;
4695 if (P) {
4696 switch (size & 1) {
4697 case 0:
4698 op = Q ? Iop_Mul32Fx4 : Iop_Mul32Fx2;
4699 op2 = Q ? Iop_Sub32Fx4 : Iop_Sub32Fx2;
4700 break;
4701 case 1: return False;
4702 default: vassert(0);
4704 } else {
4705 switch (size & 1) {
4706 case 0:
4707 op = Q ? Iop_Mul32Fx4 : Iop_Mul32Fx2;
4708 op2 = Q ? Iop_Add32Fx4 : Iop_Add32Fx2;
4709 break;
4710 case 1: return False;
4711 default: vassert(0);
4714 assign(res, binop_w_fake_RM(
4715 op2,
4716 Q ? getQReg(dreg) : getDRegI64(dreg),
4717 binop_w_fake_RM(op, mkexpr(arg_n),
4718 mkexpr(arg_m))));
4720 DIP("vml%c.f32 %c%u, %c%u, %c%u\n",
4721 P ? 's' : 'a', Q ? 'q' : 'd',
4722 dreg, Q ? 'q' : 'd', nreg, Q ? 'q' : 'd', mreg);
4723 } else {
4724 /* VMUL */
4725 IROp op;
4726 if ((C >> 1) != 0)
4727 return False;
4728 op = Q ? Iop_Mul32Fx4 : Iop_Mul32Fx2 ;
4729 assign(res, binop_w_fake_RM(op, mkexpr(arg_n), mkexpr(arg_m)));
4730 DIP("vmul.f32 %c%u, %c%u, %c%u\n",
4731 Q ? 'q' : 'd', dreg,
4732 Q ? 'q' : 'd', nreg, Q ? 'q' : 'd', mreg);
4735 break;
4736 case 14:
4737 if (B == 0) {
4738 if (U == 0) {
4739 if ((C >> 1) == 0) {
4740 /* VCEQ */
4741 IROp op;
4742 if ((theInstr >> 20) & 1)
4743 return False;
4744 op = Q ? Iop_CmpEQ32Fx4 : Iop_CmpEQ32Fx2;
4745 assign(res, binop(op, mkexpr(arg_n), mkexpr(arg_m)));
4746 DIP("vceq.f32 %c%u, %c%u, %c%u\n",
4747 Q ? 'q' : 'd', dreg,
4748 Q ? 'q' : 'd', nreg, Q ? 'q' : 'd', mreg);
4749 } else {
4750 return False;
4752 } else {
4753 if ((C >> 1) == 0) {
4754 /* VCGE */
4755 IROp op;
4756 if ((theInstr >> 20) & 1)
4757 return False;
4758 op = Q ? Iop_CmpGE32Fx4 : Iop_CmpGE32Fx2;
4759 assign(res, binop(op, mkexpr(arg_n), mkexpr(arg_m)));
4760 DIP("vcge.f32 %c%u, %c%u, %c%u\n",
4761 Q ? 'q' : 'd', dreg,
4762 Q ? 'q' : 'd', nreg, Q ? 'q' : 'd', mreg);
4763 } else {
4764 /* VCGT */
4765 IROp op;
4766 if ((theInstr >> 20) & 1)
4767 return False;
4768 op = Q ? Iop_CmpGT32Fx4 : Iop_CmpGT32Fx2;
4769 assign(res, binop(op, mkexpr(arg_n), mkexpr(arg_m)));
4770 DIP("vcgt.f32 %c%u, %c%u, %c%u\n",
4771 Q ? 'q' : 'd', dreg,
4772 Q ? 'q' : 'd', nreg, Q ? 'q' : 'd', mreg);
4775 } else {
4776 if (U == 1) {
4777 /* VACGE, VACGT */
4778 UInt op_bit = (theInstr >> 21) & 1;
4779 IROp op, op2;
4780 op2 = Q ? Iop_Abs32Fx4 : Iop_Abs32Fx2;
4781 if (op_bit) {
4782 op = Q ? Iop_CmpGT32Fx4 : Iop_CmpGT32Fx2;
4783 assign(res, binop(op,
4784 unop(op2, mkexpr(arg_n)),
4785 unop(op2, mkexpr(arg_m))));
4786 } else {
4787 op = Q ? Iop_CmpGE32Fx4 : Iop_CmpGE32Fx2;
4788 assign(res, binop(op,
4789 unop(op2, mkexpr(arg_n)),
4790 unop(op2, mkexpr(arg_m))));
4792 DIP("vacg%c.f32 %c%u, %c%u, %c%u\n", op_bit ? 't' : 'e',
4793 Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', nreg,
4794 Q ? 'q' : 'd', mreg);
4795 } else {
4796 return False;
4799 break;
4800 case 15:
4801 if (B == 0) {
4802 if (U == 0) {
4803 /* VMAX, VMIN */
4804 IROp op;
4805 if ((theInstr >> 20) & 1)
4806 return False;
4807 if ((theInstr >> 21) & 1) {
4808 op = Q ? Iop_Min32Fx4 : Iop_Min32Fx2;
4809 DIP("vmin.f32 %c%u, %c%u, %c%u\n", Q ? 'q' : 'd', dreg,
4810 Q ? 'q' : 'd', nreg, Q ? 'q' : 'd', mreg);
4811 } else {
4812 op = Q ? Iop_Max32Fx4 : Iop_Max32Fx2;
4813 DIP("vmax.f32 %c%u, %c%u, %c%u\n", Q ? 'q' : 'd', dreg,
4814 Q ? 'q' : 'd', nreg, Q ? 'q' : 'd', mreg);
4816 assign(res, binop(op, mkexpr(arg_n), mkexpr(arg_m)));
4817 } else {
4818 /* VPMAX, VPMIN */
4819 IROp op;
4820 if (Q)
4821 return False;
4822 if ((theInstr >> 20) & 1)
4823 return False;
4824 if ((theInstr >> 21) & 1) {
4825 op = Iop_PwMin32Fx2;
4826 DIP("vpmin.f32 d%u, d%u, d%u\n", dreg, nreg, mreg);
4827 } else {
4828 op = Iop_PwMax32Fx2;
4829 DIP("vpmax.f32 d%u, d%u, d%u\n", dreg, nreg, mreg);
4831 assign(res, binop(op, mkexpr(arg_n), mkexpr(arg_m)));
4833 } else {
4834 if (U == 0) {
4835 if ((C >> 1) == 0) {
4836 /* VRECPS */
4837 if ((theInstr >> 20) & 1)
4838 return False;
4839 assign(res, binop(Q ? Iop_RecipStep32Fx4
4840 : Iop_RecipStep32Fx2,
4841 mkexpr(arg_n),
4842 mkexpr(arg_m)));
4843 DIP("vrecps.f32 %c%u, %c%u, %c%u\n", Q ? 'q' : 'd', dreg,
4844 Q ? 'q' : 'd', nreg, Q ? 'q' : 'd', mreg);
4845 } else {
4846 /* VRSQRTS */
4847 if ((theInstr >> 20) & 1)
4848 return False;
4849 assign(res, binop(Q ? Iop_RSqrtStep32Fx4
4850 : Iop_RSqrtStep32Fx2,
4851 mkexpr(arg_n),
4852 mkexpr(arg_m)));
4853 DIP("vrsqrts.f32 %c%u, %c%u, %c%u\n", Q ? 'q' : 'd', dreg,
4854 Q ? 'q' : 'd', nreg, Q ? 'q' : 'd', mreg);
4856 } else {
4857 return False;
4860 break;
4861 default:
4862 /*NOTREACHED*/
4863 vassert(0);
4866 if (Q) {
4867 putQReg(dreg, mkexpr(res), condT);
4868 } else {
4869 putDRegI64(dreg, mkexpr(res), condT);
4872 return True;
4875 /* A7.4.2 Three registers of different length */
4876 static
4877 Bool dis_neon_data_3diff ( UInt theInstr, IRTemp condT )
4879 /* In paths where this returns False, indicating a non-decodable
4880 instruction, there may still be some IR assignments to temporaries
4881 generated. This is inconvenient but harmless, and the post-front-end
4882 IR optimisation pass will just remove them anyway. So there's no
4883 effort made here to tidy it up.
4885 UInt A = (theInstr >> 8) & 0xf;
4886 UInt B = (theInstr >> 20) & 3;
4887 UInt U = (theInstr >> 24) & 1;
4888 UInt P = (theInstr >> 9) & 1;
4889 UInt mreg = get_neon_m_regno(theInstr);
4890 UInt nreg = get_neon_n_regno(theInstr);
4891 UInt dreg = get_neon_d_regno(theInstr);
4892 UInt size = B;
4893 ULong imm;
4894 IRTemp res, arg_m, arg_n, cond, tmp;
4895 IROp cvt, cvt2, cmp, op, op2, sh, add;
4896 switch (A) {
4897 case 0: case 1: case 2: case 3:
4898 /* VADDL, VADDW, VSUBL, VSUBW */
4899 if (dreg & 1)
4900 return False;
4901 dreg >>= 1;
4902 size = B;
4903 switch (size) {
4904 case 0:
4905 cvt = U ? Iop_Widen8Uto16x8 : Iop_Widen8Sto16x8;
4906 op = (A & 2) ? Iop_Sub16x8 : Iop_Add16x8;
4907 break;
4908 case 1:
4909 cvt = U ? Iop_Widen16Uto32x4 : Iop_Widen16Sto32x4;
4910 op = (A & 2) ? Iop_Sub32x4 : Iop_Add32x4;
4911 break;
4912 case 2:
4913 cvt = U ? Iop_Widen32Uto64x2 : Iop_Widen32Sto64x2;
4914 op = (A & 2) ? Iop_Sub64x2 : Iop_Add64x2;
4915 break;
4916 case 3:
4917 return False;
4918 default:
4919 vassert(0);
4921 arg_n = newTemp(Ity_V128);
4922 arg_m = newTemp(Ity_V128);
4923 if (A & 1) {
4924 if (nreg & 1)
4925 return False;
4926 nreg >>= 1;
4927 assign(arg_n, getQReg(nreg));
4928 } else {
4929 assign(arg_n, unop(cvt, getDRegI64(nreg)));
4931 assign(arg_m, unop(cvt, getDRegI64(mreg)));
4932 putQReg(dreg, binop(op, mkexpr(arg_n), mkexpr(arg_m)),
4933 condT);
4934 DIP("v%s%c.%c%d q%u, %c%u, d%u\n", (A & 2) ? "sub" : "add",
4935 (A & 1) ? 'w' : 'l', U ? 'u' : 's', 8 << size, dreg,
4936 (A & 1) ? 'q' : 'd', nreg, mreg);
4937 return True;
4938 case 4:
4939 /* VADDHN, VRADDHN */
4940 if (mreg & 1)
4941 return False;
4942 mreg >>= 1;
4943 if (nreg & 1)
4944 return False;
4945 nreg >>= 1;
4946 size = B;
4947 switch (size) {
4948 case 0:
4949 op = Iop_Add16x8;
4950 cvt = Iop_NarrowUn16to8x8;
4951 sh = Iop_ShrN16x8;
4952 imm = 1U << 7;
4953 imm = (imm << 16) | imm;
4954 imm = (imm << 32) | imm;
4955 break;
4956 case 1:
4957 op = Iop_Add32x4;
4958 cvt = Iop_NarrowUn32to16x4;
4959 sh = Iop_ShrN32x4;
4960 imm = 1U << 15;
4961 imm = (imm << 32) | imm;
4962 break;
4963 case 2:
4964 op = Iop_Add64x2;
4965 cvt = Iop_NarrowUn64to32x2;
4966 sh = Iop_ShrN64x2;
4967 imm = 1U << 31;
4968 break;
4969 case 3:
4970 return False;
4971 default:
4972 vassert(0);
4974 tmp = newTemp(Ity_V128);
4975 res = newTemp(Ity_V128);
4976 assign(tmp, binop(op, getQReg(nreg), getQReg(mreg)));
4977 if (U) {
4978 /* VRADDHN */
4979 assign(res, binop(op, mkexpr(tmp),
4980 binop(Iop_64HLtoV128, mkU64(imm), mkU64(imm))));
4981 } else {
4982 assign(res, mkexpr(tmp));
4984 putDRegI64(dreg, unop(cvt, binop(sh, mkexpr(res), mkU8(8 << size))),
4985 condT);
4986 DIP("v%saddhn.i%d d%u, q%u, q%u\n", U ? "r" : "", 16 << size, dreg,
4987 nreg, mreg);
4988 return True;
4989 case 5:
4990 /* VABAL */
4991 if (!((theInstr >> 23) & 1)) {
4992 vpanic("VABA should not be in dis_neon_data_3diff\n");
4994 if (dreg & 1)
4995 return False;
4996 dreg >>= 1;
4997 switch (size) {
4998 case 0:
4999 cmp = U ? Iop_CmpGT8Ux8 : Iop_CmpGT8Sx8;
5000 cvt = U ? Iop_Widen8Uto16x8 : Iop_Widen8Sto16x8;
5001 cvt2 = Iop_Widen8Sto16x8;
5002 op = Iop_Sub16x8;
5003 op2 = Iop_Add16x8;
5004 break;
5005 case 1:
5006 cmp = U ? Iop_CmpGT16Ux4 : Iop_CmpGT16Sx4;
5007 cvt = U ? Iop_Widen16Uto32x4 : Iop_Widen16Sto32x4;
5008 cvt2 = Iop_Widen16Sto32x4;
5009 op = Iop_Sub32x4;
5010 op2 = Iop_Add32x4;
5011 break;
5012 case 2:
5013 cmp = U ? Iop_CmpGT32Ux2 : Iop_CmpGT32Sx2;
5014 cvt = U ? Iop_Widen32Uto64x2 : Iop_Widen32Sto64x2;
5015 cvt2 = Iop_Widen32Sto64x2;
5016 op = Iop_Sub64x2;
5017 op2 = Iop_Add64x2;
5018 break;
5019 case 3:
5020 return False;
5021 default:
5022 vassert(0);
5024 arg_n = newTemp(Ity_V128);
5025 arg_m = newTemp(Ity_V128);
5026 cond = newTemp(Ity_V128);
5027 res = newTemp(Ity_V128);
5028 assign(arg_n, unop(cvt, getDRegI64(nreg)));
5029 assign(arg_m, unop(cvt, getDRegI64(mreg)));
5030 assign(cond, unop(cvt2, binop(cmp, getDRegI64(nreg),
5031 getDRegI64(mreg))));
5032 assign(res, binop(op2,
5033 binop(Iop_OrV128,
5034 binop(Iop_AndV128,
5035 binop(op, mkexpr(arg_n), mkexpr(arg_m)),
5036 mkexpr(cond)),
5037 binop(Iop_AndV128,
5038 binop(op, mkexpr(arg_m), mkexpr(arg_n)),
5039 unop(Iop_NotV128, mkexpr(cond)))),
5040 getQReg(dreg)));
5041 putQReg(dreg, mkexpr(res), condT);
5042 DIP("vabal.%c%d q%u, d%u, d%u\n", U ? 'u' : 's', 8 << size, dreg,
5043 nreg, mreg);
5044 return True;
5045 case 6:
5046 /* VSUBHN, VRSUBHN */
5047 if (mreg & 1)
5048 return False;
5049 mreg >>= 1;
5050 if (nreg & 1)
5051 return False;
5052 nreg >>= 1;
5053 size = B;
5054 switch (size) {
5055 case 0:
5056 op = Iop_Sub16x8;
5057 op2 = Iop_Add16x8;
5058 cvt = Iop_NarrowUn16to8x8;
5059 sh = Iop_ShrN16x8;
5060 imm = 1U << 7;
5061 imm = (imm << 16) | imm;
5062 imm = (imm << 32) | imm;
5063 break;
5064 case 1:
5065 op = Iop_Sub32x4;
5066 op2 = Iop_Add32x4;
5067 cvt = Iop_NarrowUn32to16x4;
5068 sh = Iop_ShrN32x4;
5069 imm = 1U << 15;
5070 imm = (imm << 32) | imm;
5071 break;
5072 case 2:
5073 op = Iop_Sub64x2;
5074 op2 = Iop_Add64x2;
5075 cvt = Iop_NarrowUn64to32x2;
5076 sh = Iop_ShrN64x2;
5077 imm = 1U << 31;
5078 break;
5079 case 3:
5080 return False;
5081 default:
5082 vassert(0);
5084 tmp = newTemp(Ity_V128);
5085 res = newTemp(Ity_V128);
5086 assign(tmp, binop(op, getQReg(nreg), getQReg(mreg)));
5087 if (U) {
5088 /* VRSUBHN */
5089 assign(res, binop(op2, mkexpr(tmp),
5090 binop(Iop_64HLtoV128, mkU64(imm), mkU64(imm))));
5091 } else {
5092 assign(res, mkexpr(tmp));
5094 putDRegI64(dreg, unop(cvt, binop(sh, mkexpr(res), mkU8(8 << size))),
5095 condT);
5096 DIP("v%ssubhn.i%d d%u, q%u, q%u\n", U ? "r" : "", 16 << size, dreg,
5097 nreg, mreg);
5098 return True;
5099 case 7:
5100 /* VABDL */
5101 if (!((theInstr >> 23) & 1)) {
5102 vpanic("VABL should not be in dis_neon_data_3diff\n");
5104 if (dreg & 1)
5105 return False;
5106 dreg >>= 1;
5107 switch (size) {
5108 case 0:
5109 cmp = U ? Iop_CmpGT8Ux8 : Iop_CmpGT8Sx8;
5110 cvt = U ? Iop_Widen8Uto16x8 : Iop_Widen8Sto16x8;
5111 cvt2 = Iop_Widen8Sto16x8;
5112 op = Iop_Sub16x8;
5113 break;
5114 case 1:
5115 cmp = U ? Iop_CmpGT16Ux4 : Iop_CmpGT16Sx4;
5116 cvt = U ? Iop_Widen16Uto32x4 : Iop_Widen16Sto32x4;
5117 cvt2 = Iop_Widen16Sto32x4;
5118 op = Iop_Sub32x4;
5119 break;
5120 case 2:
5121 cmp = U ? Iop_CmpGT32Ux2 : Iop_CmpGT32Sx2;
5122 cvt = U ? Iop_Widen32Uto64x2 : Iop_Widen32Sto64x2;
5123 cvt2 = Iop_Widen32Sto64x2;
5124 op = Iop_Sub64x2;
5125 break;
5126 case 3:
5127 return False;
5128 default:
5129 vassert(0);
5131 arg_n = newTemp(Ity_V128);
5132 arg_m = newTemp(Ity_V128);
5133 cond = newTemp(Ity_V128);
5134 res = newTemp(Ity_V128);
5135 assign(arg_n, unop(cvt, getDRegI64(nreg)));
5136 assign(arg_m, unop(cvt, getDRegI64(mreg)));
5137 assign(cond, unop(cvt2, binop(cmp, getDRegI64(nreg),
5138 getDRegI64(mreg))));
5139 assign(res, binop(Iop_OrV128,
5140 binop(Iop_AndV128,
5141 binop(op, mkexpr(arg_n), mkexpr(arg_m)),
5142 mkexpr(cond)),
5143 binop(Iop_AndV128,
5144 binop(op, mkexpr(arg_m), mkexpr(arg_n)),
5145 unop(Iop_NotV128, mkexpr(cond)))));
5146 putQReg(dreg, mkexpr(res), condT);
5147 DIP("vabdl.%c%d q%u, d%u, d%u\n", U ? 'u' : 's', 8 << size, dreg,
5148 nreg, mreg);
5149 return True;
5150 case 8:
5151 case 10:
5152 /* VMLAL, VMLSL (integer) */
5153 if (dreg & 1)
5154 return False;
5155 dreg >>= 1;
5156 size = B;
5157 switch (size) {
5158 case 0:
5159 op = U ? Iop_Mull8Ux8 : Iop_Mull8Sx8;
5160 op2 = P ? Iop_Sub16x8 : Iop_Add16x8;
5161 break;
5162 case 1:
5163 op = U ? Iop_Mull16Ux4 : Iop_Mull16Sx4;
5164 op2 = P ? Iop_Sub32x4 : Iop_Add32x4;
5165 break;
5166 case 2:
5167 op = U ? Iop_Mull32Ux2 : Iop_Mull32Sx2;
5168 op2 = P ? Iop_Sub64x2 : Iop_Add64x2;
5169 break;
5170 case 3:
5171 return False;
5172 default:
5173 vassert(0);
5175 res = newTemp(Ity_V128);
5176 assign(res, binop(op, getDRegI64(nreg),getDRegI64(mreg)));
5177 putQReg(dreg, binop(op2, getQReg(dreg), mkexpr(res)), condT);
5178 DIP("vml%cl.%c%d q%u, d%u, d%u\n", P ? 's' : 'a', U ? 'u' : 's',
5179 8 << size, dreg, nreg, mreg);
5180 return True;
5181 case 9:
5182 case 11:
5183 /* VQDMLAL, VQDMLSL */
5184 if (U)
5185 return False;
5186 if (dreg & 1)
5187 return False;
5188 dreg >>= 1;
5189 size = B;
5190 switch (size) {
5191 case 0: case 3:
5192 return False;
5193 case 1:
5194 op = Iop_QDMull16Sx4;
5195 cmp = Iop_CmpEQ16x4;
5196 add = P ? Iop_QSub32Sx4 : Iop_QAdd32Sx4;
5197 op2 = P ? Iop_Sub32x4 : Iop_Add32x4;
5198 imm = 1LL << 15;
5199 imm = (imm << 16) | imm;
5200 imm = (imm << 32) | imm;
5201 break;
5202 case 2:
5203 op = Iop_QDMull32Sx2;
5204 cmp = Iop_CmpEQ32x2;
5205 add = P ? Iop_QSub64Sx2 : Iop_QAdd64Sx2;
5206 op2 = P ? Iop_Sub64x2 : Iop_Add64x2;
5207 imm = 1LL << 31;
5208 imm = (imm << 32) | imm;
5209 break;
5210 default:
5211 vassert(0);
5213 res = newTemp(Ity_V128);
5214 tmp = newTemp(Ity_V128);
5215 assign(res, binop(op, getDRegI64(nreg), getDRegI64(mreg)));
5216 assign(tmp, binop(op2, getQReg(dreg), mkexpr(res)));
5217 setFlag_QC(mkexpr(tmp), binop(add, getQReg(dreg), mkexpr(res)),
5218 True, condT);
5219 setFlag_QC(binop(Iop_And64,
5220 binop(cmp, getDRegI64(nreg), mkU64(imm)),
5221 binop(cmp, getDRegI64(mreg), mkU64(imm))),
5222 mkU64(0),
5223 False, condT);
5224 putQReg(dreg, binop(add, getQReg(dreg), mkexpr(res)), condT);
5225 DIP("vqdml%cl.s%d q%u, d%u, d%u\n", P ? 's' : 'a', 8 << size, dreg,
5226 nreg, mreg);
5227 return True;
5228 case 12:
5229 case 14:
5230 /* VMULL (integer or polynomial) */
5231 if (dreg & 1)
5232 return False;
5233 dreg >>= 1;
5234 size = B;
5235 switch (size) {
5236 case 0:
5237 op = (U) ? Iop_Mull8Ux8 : Iop_Mull8Sx8;
5238 if (P)
5239 op = Iop_PolynomialMull8x8;
5240 break;
5241 case 1:
5242 if (P) return False;
5243 op = (U) ? Iop_Mull16Ux4 : Iop_Mull16Sx4;
5244 break;
5245 case 2:
5246 if (P) return False;
5247 op = (U) ? Iop_Mull32Ux2 : Iop_Mull32Sx2;
5248 break;
5249 case 3:
5250 return False;
5251 default:
5252 vassert(0);
5254 putQReg(dreg, binop(op, getDRegI64(nreg),
5255 getDRegI64(mreg)), condT);
5256 DIP("vmull.%c%d q%u, d%u, d%u\n", P ? 'p' : (U ? 'u' : 's'),
5257 8 << size, dreg, nreg, mreg);
5258 return True;
5259 case 13:
5260 /* VQDMULL */
5261 if (U)
5262 return False;
5263 if (dreg & 1)
5264 return False;
5265 dreg >>= 1;
5266 size = B;
5267 switch (size) {
5268 case 0:
5269 case 3:
5270 return False;
5271 case 1:
5272 op = Iop_QDMull16Sx4;
5273 op2 = Iop_CmpEQ16x4;
5274 imm = 1LL << 15;
5275 imm = (imm << 16) | imm;
5276 imm = (imm << 32) | imm;
5277 break;
5278 case 2:
5279 op = Iop_QDMull32Sx2;
5280 op2 = Iop_CmpEQ32x2;
5281 imm = 1LL << 31;
5282 imm = (imm << 32) | imm;
5283 break;
5284 default:
5285 vassert(0);
5287 putQReg(dreg, binop(op, getDRegI64(nreg), getDRegI64(mreg)),
5288 condT);
5289 setFlag_QC(binop(Iop_And64,
5290 binop(op2, getDRegI64(nreg), mkU64(imm)),
5291 binop(op2, getDRegI64(mreg), mkU64(imm))),
5292 mkU64(0),
5293 False, condT);
5294 DIP("vqdmull.s%d q%u, d%u, d%u\n", 8 << size, dreg, nreg, mreg);
5295 return True;
5296 default:
5297 return False;
5299 return False;
5302 /* A7.4.3 Two registers and a scalar */
5303 static
5304 Bool dis_neon_data_2reg_and_scalar ( UInt theInstr, IRTemp condT )
5306 # define INSN(_bMax,_bMin) SLICE_UInt(theInstr, (_bMax), (_bMin))
5307 UInt U = INSN(24,24);
5308 UInt dreg = get_neon_d_regno(theInstr & ~(1 << 6));
5309 UInt nreg = get_neon_n_regno(theInstr & ~(1 << 6));
5310 UInt mreg = get_neon_m_regno(theInstr & ~(1 << 6));
5311 UInt size = INSN(21,20);
5312 UInt index;
5313 UInt Q = INSN(24,24);
5315 if (INSN(27,25) != 1 || INSN(23,23) != 1
5316 || INSN(6,6) != 1 || INSN(4,4) != 0)
5317 return False;
5319 /* VMLA, VMLS (scalar) */
5320 if ((INSN(11,8) & BITS4(1,0,1,0)) == BITS4(0,0,0,0)) {
5321 IRTemp res, arg_m, arg_n;
5322 IROp dup, get, op, op2, add, sub;
5323 if (Q) {
5324 if ((dreg & 1) || (nreg & 1))
5325 return False;
5326 dreg >>= 1;
5327 nreg >>= 1;
5328 res = newTemp(Ity_V128);
5329 arg_m = newTemp(Ity_V128);
5330 arg_n = newTemp(Ity_V128);
5331 assign(arg_n, getQReg(nreg));
5332 switch(size) {
5333 case 1:
5334 dup = Iop_Dup16x8;
5335 get = Iop_GetElem16x4;
5336 index = mreg >> 3;
5337 mreg &= 7;
5338 break;
5339 case 2:
5340 dup = Iop_Dup32x4;
5341 get = Iop_GetElem32x2;
5342 index = mreg >> 4;
5343 mreg &= 0xf;
5344 break;
5345 case 0:
5346 case 3:
5347 return False;
5348 default:
5349 vassert(0);
5351 assign(arg_m, unop(dup, binop(get, getDRegI64(mreg), mkU8(index))));
5352 } else {
5353 res = newTemp(Ity_I64);
5354 arg_m = newTemp(Ity_I64);
5355 arg_n = newTemp(Ity_I64);
5356 assign(arg_n, getDRegI64(nreg));
5357 switch(size) {
5358 case 1:
5359 dup = Iop_Dup16x4;
5360 get = Iop_GetElem16x4;
5361 index = mreg >> 3;
5362 mreg &= 7;
5363 break;
5364 case 2:
5365 dup = Iop_Dup32x2;
5366 get = Iop_GetElem32x2;
5367 index = mreg >> 4;
5368 mreg &= 0xf;
5369 break;
5370 case 0:
5371 case 3:
5372 return False;
5373 default:
5374 vassert(0);
5376 assign(arg_m, unop(dup, binop(get, getDRegI64(mreg), mkU8(index))));
5378 if (INSN(8,8)) {
5379 switch (size) {
5380 case 2:
5381 op = Q ? Iop_Mul32Fx4 : Iop_Mul32Fx2;
5382 add = Q ? Iop_Add32Fx4 : Iop_Add32Fx2;
5383 sub = Q ? Iop_Sub32Fx4 : Iop_Sub32Fx2;
5384 break;
5385 case 0:
5386 case 1:
5387 case 3:
5388 return False;
5389 default:
5390 vassert(0);
5392 } else {
5393 switch (size) {
5394 case 1:
5395 op = Q ? Iop_Mul16x8 : Iop_Mul16x4;
5396 add = Q ? Iop_Add16x8 : Iop_Add16x4;
5397 sub = Q ? Iop_Sub16x8 : Iop_Sub16x4;
5398 break;
5399 case 2:
5400 op = Q ? Iop_Mul32x4 : Iop_Mul32x2;
5401 add = Q ? Iop_Add32x4 : Iop_Add32x2;
5402 sub = Q ? Iop_Sub32x4 : Iop_Sub32x2;
5403 break;
5404 case 0:
5405 case 3:
5406 return False;
5407 default:
5408 vassert(0);
5411 op2 = INSN(10,10) ? sub : add;
5412 assign(res, binop_w_fake_RM(op, mkexpr(arg_n), mkexpr(arg_m)));
5413 if (Q)
5414 putQReg(dreg, binop_w_fake_RM(op2, getQReg(dreg), mkexpr(res)),
5415 condT);
5416 else
5417 putDRegI64(dreg, binop(op2, getDRegI64(dreg), mkexpr(res)),
5418 condT);
5419 DIP("vml%c.%c%d %c%u, %c%u, d%u[%u]\n", INSN(10,10) ? 's' : 'a',
5420 INSN(8,8) ? 'f' : 'i', 8 << size,
5421 Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', nreg, mreg, index);
5422 return True;
5425 /* VMLAL, VMLSL (scalar) */
5426 if ((INSN(11,8) & BITS4(1,0,1,1)) == BITS4(0,0,1,0)) {
5427 IRTemp res, arg_m, arg_n;
5428 IROp dup, get, op, op2, add, sub;
5429 if (dreg & 1)
5430 return False;
5431 dreg >>= 1;
5432 res = newTemp(Ity_V128);
5433 arg_m = newTemp(Ity_I64);
5434 arg_n = newTemp(Ity_I64);
5435 assign(arg_n, getDRegI64(nreg));
5436 switch(size) {
5437 case 1:
5438 dup = Iop_Dup16x4;
5439 get = Iop_GetElem16x4;
5440 index = mreg >> 3;
5441 mreg &= 7;
5442 break;
5443 case 2:
5444 dup = Iop_Dup32x2;
5445 get = Iop_GetElem32x2;
5446 index = mreg >> 4;
5447 mreg &= 0xf;
5448 break;
5449 case 0:
5450 case 3:
5451 return False;
5452 default:
5453 vassert(0);
5455 assign(arg_m, unop(dup, binop(get, getDRegI64(mreg), mkU8(index))));
5456 switch (size) {
5457 case 1:
5458 op = U ? Iop_Mull16Ux4 : Iop_Mull16Sx4;
5459 add = Iop_Add32x4;
5460 sub = Iop_Sub32x4;
5461 break;
5462 case 2:
5463 op = U ? Iop_Mull32Ux2 : Iop_Mull32Sx2;
5464 add = Iop_Add64x2;
5465 sub = Iop_Sub64x2;
5466 break;
5467 case 0:
5468 case 3:
5469 return False;
5470 default:
5471 vassert(0);
5473 op2 = INSN(10,10) ? sub : add;
5474 assign(res, binop(op, mkexpr(arg_n), mkexpr(arg_m)));
5475 putQReg(dreg, binop(op2, getQReg(dreg), mkexpr(res)), condT);
5476 DIP("vml%cl.%c%d q%u, d%u, d%u[%u]\n",
5477 INSN(10,10) ? 's' : 'a', U ? 'u' : 's',
5478 8 << size, dreg, nreg, mreg, index);
5479 return True;
5482 /* VQDMLAL, VQDMLSL (scalar) */
5483 if ((INSN(11,8) & BITS4(1,0,1,1)) == BITS4(0,0,1,1) && !U) {
5484 IRTemp res, arg_m, arg_n, tmp;
5485 IROp dup, get, op, op2, add, cmp;
5486 UInt P = INSN(10,10);
5487 ULong imm;
5488 if (dreg & 1)
5489 return False;
5490 dreg >>= 1;
5491 res = newTemp(Ity_V128);
5492 arg_m = newTemp(Ity_I64);
5493 arg_n = newTemp(Ity_I64);
5494 assign(arg_n, getDRegI64(nreg));
5495 switch(size) {
5496 case 1:
5497 dup = Iop_Dup16x4;
5498 get = Iop_GetElem16x4;
5499 index = mreg >> 3;
5500 mreg &= 7;
5501 break;
5502 case 2:
5503 dup = Iop_Dup32x2;
5504 get = Iop_GetElem32x2;
5505 index = mreg >> 4;
5506 mreg &= 0xf;
5507 break;
5508 case 0:
5509 case 3:
5510 return False;
5511 default:
5512 vassert(0);
5514 assign(arg_m, unop(dup, binop(get, getDRegI64(mreg), mkU8(index))));
5515 switch (size) {
5516 case 0:
5517 case 3:
5518 return False;
5519 case 1:
5520 op = Iop_QDMull16Sx4;
5521 cmp = Iop_CmpEQ16x4;
5522 add = P ? Iop_QSub32Sx4 : Iop_QAdd32Sx4;
5523 op2 = P ? Iop_Sub32x4 : Iop_Add32x4;
5524 imm = 1LL << 15;
5525 imm = (imm << 16) | imm;
5526 imm = (imm << 32) | imm;
5527 break;
5528 case 2:
5529 op = Iop_QDMull32Sx2;
5530 cmp = Iop_CmpEQ32x2;
5531 add = P ? Iop_QSub64Sx2 : Iop_QAdd64Sx2;
5532 op2 = P ? Iop_Sub64x2 : Iop_Add64x2;
5533 imm = 1LL << 31;
5534 imm = (imm << 32) | imm;
5535 break;
5536 default:
5537 vassert(0);
5539 res = newTemp(Ity_V128);
5540 tmp = newTemp(Ity_V128);
5541 assign(res, binop(op, mkexpr(arg_n), mkexpr(arg_m)));
5542 assign(tmp, binop(op2, getQReg(dreg), mkexpr(res)));
5543 setFlag_QC(binop(Iop_And64,
5544 binop(cmp, mkexpr(arg_n), mkU64(imm)),
5545 binop(cmp, mkexpr(arg_m), mkU64(imm))),
5546 mkU64(0),
5547 False, condT);
5548 setFlag_QC(mkexpr(tmp), binop(add, getQReg(dreg), mkexpr(res)),
5549 True, condT);
5550 putQReg(dreg, binop(add, getQReg(dreg), mkexpr(res)), condT);
5551 DIP("vqdml%cl.s%d q%u, d%u, d%u[%u]\n", P ? 's' : 'a', 8 << size,
5552 dreg, nreg, mreg, index);
5553 return True;
5556 /* VMUL (by scalar) */
5557 if ((INSN(11,8) & BITS4(1,1,1,0)) == BITS4(1,0,0,0)) {
5558 IRTemp res, arg_m, arg_n;
5559 IROp dup, get, op;
5560 if (Q) {
5561 if ((dreg & 1) || (nreg & 1))
5562 return False;
5563 dreg >>= 1;
5564 nreg >>= 1;
5565 res = newTemp(Ity_V128);
5566 arg_m = newTemp(Ity_V128);
5567 arg_n = newTemp(Ity_V128);
5568 assign(arg_n, getQReg(nreg));
5569 switch(size) {
5570 case 1:
5571 dup = Iop_Dup16x8;
5572 get = Iop_GetElem16x4;
5573 index = mreg >> 3;
5574 mreg &= 7;
5575 break;
5576 case 2:
5577 dup = Iop_Dup32x4;
5578 get = Iop_GetElem32x2;
5579 index = mreg >> 4;
5580 mreg &= 0xf;
5581 break;
5582 case 0:
5583 case 3:
5584 return False;
5585 default:
5586 vassert(0);
5588 assign(arg_m, unop(dup, binop(get, getDRegI64(mreg), mkU8(index))));
5589 } else {
5590 res = newTemp(Ity_I64);
5591 arg_m = newTemp(Ity_I64);
5592 arg_n = newTemp(Ity_I64);
5593 assign(arg_n, getDRegI64(nreg));
5594 switch(size) {
5595 case 1:
5596 dup = Iop_Dup16x4;
5597 get = Iop_GetElem16x4;
5598 index = mreg >> 3;
5599 mreg &= 7;
5600 break;
5601 case 2:
5602 dup = Iop_Dup32x2;
5603 get = Iop_GetElem32x2;
5604 index = mreg >> 4;
5605 mreg &= 0xf;
5606 break;
5607 case 0:
5608 case 3:
5609 return False;
5610 default:
5611 vassert(0);
5613 assign(arg_m, unop(dup, binop(get, getDRegI64(mreg), mkU8(index))));
5615 if (INSN(8,8)) {
5616 switch (size) {
5617 case 2:
5618 op = Q ? Iop_Mul32Fx4 : Iop_Mul32Fx2;
5619 break;
5620 case 0:
5621 case 1:
5622 case 3:
5623 return False;
5624 default:
5625 vassert(0);
5627 } else {
5628 switch (size) {
5629 case 1:
5630 op = Q ? Iop_Mul16x8 : Iop_Mul16x4;
5631 break;
5632 case 2:
5633 op = Q ? Iop_Mul32x4 : Iop_Mul32x2;
5634 break;
5635 case 0:
5636 case 3:
5637 return False;
5638 default:
5639 vassert(0);
5642 assign(res, binop_w_fake_RM(op, mkexpr(arg_n), mkexpr(arg_m)));
5643 if (Q)
5644 putQReg(dreg, mkexpr(res), condT);
5645 else
5646 putDRegI64(dreg, mkexpr(res), condT);
5647 DIP("vmul.%c%d %c%u, %c%u, d%u[%u]\n", INSN(8,8) ? 'f' : 'i',
5648 8 << size, Q ? 'q' : 'd', dreg,
5649 Q ? 'q' : 'd', nreg, mreg, index);
5650 return True;
5653 /* VMULL (scalar) */
5654 if (INSN(11,8) == BITS4(1,0,1,0)) {
5655 IRTemp res, arg_m, arg_n;
5656 IROp dup, get, op;
5657 if (dreg & 1)
5658 return False;
5659 dreg >>= 1;
5660 res = newTemp(Ity_V128);
5661 arg_m = newTemp(Ity_I64);
5662 arg_n = newTemp(Ity_I64);
5663 assign(arg_n, getDRegI64(nreg));
5664 switch(size) {
5665 case 1:
5666 dup = Iop_Dup16x4;
5667 get = Iop_GetElem16x4;
5668 index = mreg >> 3;
5669 mreg &= 7;
5670 break;
5671 case 2:
5672 dup = Iop_Dup32x2;
5673 get = Iop_GetElem32x2;
5674 index = mreg >> 4;
5675 mreg &= 0xf;
5676 break;
5677 case 0:
5678 case 3:
5679 return False;
5680 default:
5681 vassert(0);
5683 assign(arg_m, unop(dup, binop(get, getDRegI64(mreg), mkU8(index))));
5684 switch (size) {
5685 case 1: op = U ? Iop_Mull16Ux4 : Iop_Mull16Sx4; break;
5686 case 2: op = U ? Iop_Mull32Ux2 : Iop_Mull32Sx2; break;
5687 case 0: case 3: return False;
5688 default: vassert(0);
5690 assign(res, binop(op, mkexpr(arg_n), mkexpr(arg_m)));
5691 putQReg(dreg, mkexpr(res), condT);
5692 DIP("vmull.%c%d q%u, d%u, d%u[%u]\n", U ? 'u' : 's', 8 << size, dreg,
5693 nreg, mreg, index);
5694 return True;
5697 /* VQDMULL */
5698 if (INSN(11,8) == BITS4(1,0,1,1) && !U) {
5699 IROp op ,op2, dup, get;
5700 ULong imm;
5701 IRTemp arg_m, arg_n;
5702 if (dreg & 1)
5703 return False;
5704 dreg >>= 1;
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);
5727 assign(arg_m, unop(dup, binop(get, getDRegI64(mreg), mkU8(index))));
5728 switch (size) {
5729 case 0:
5730 case 3:
5731 return False;
5732 case 1:
5733 op = Iop_QDMull16Sx4;
5734 op2 = Iop_CmpEQ16x4;
5735 imm = 1LL << 15;
5736 imm = (imm << 16) | imm;
5737 imm = (imm << 32) | imm;
5738 break;
5739 case 2:
5740 op = Iop_QDMull32Sx2;
5741 op2 = Iop_CmpEQ32x2;
5742 imm = 1LL << 31;
5743 imm = (imm << 32) | imm;
5744 break;
5745 default:
5746 vassert(0);
5748 putQReg(dreg, binop(op, mkexpr(arg_n), mkexpr(arg_m)),
5749 condT);
5750 setFlag_QC(binop(Iop_And64,
5751 binop(op2, mkexpr(arg_n), mkU64(imm)),
5752 binop(op2, mkexpr(arg_m), mkU64(imm))),
5753 mkU64(0),
5754 False, condT);
5755 DIP("vqdmull.s%d q%u, d%u, d%u[%u]\n", 8 << size, dreg, nreg, mreg,
5756 index);
5757 return True;
5760 /* VQDMULH */
5761 if (INSN(11,8) == BITS4(1,1,0,0)) {
5762 IROp op ,op2, dup, get;
5763 ULong imm;
5764 IRTemp res, arg_m, arg_n;
5765 if (Q) {
5766 if ((dreg & 1) || (nreg & 1))
5767 return False;
5768 dreg >>= 1;
5769 nreg >>= 1;
5770 res = newTemp(Ity_V128);
5771 arg_m = newTemp(Ity_V128);
5772 arg_n = newTemp(Ity_V128);
5773 assign(arg_n, getQReg(nreg));
5774 switch(size) {
5775 case 1:
5776 dup = Iop_Dup16x8;
5777 get = Iop_GetElem16x4;
5778 index = mreg >> 3;
5779 mreg &= 7;
5780 break;
5781 case 2:
5782 dup = Iop_Dup32x4;
5783 get = Iop_GetElem32x2;
5784 index = mreg >> 4;
5785 mreg &= 0xf;
5786 break;
5787 case 0:
5788 case 3:
5789 return False;
5790 default:
5791 vassert(0);
5793 assign(arg_m, unop(dup, binop(get, getDRegI64(mreg), mkU8(index))));
5794 } else {
5795 res = newTemp(Ity_I64);
5796 arg_m = newTemp(Ity_I64);
5797 arg_n = newTemp(Ity_I64);
5798 assign(arg_n, getDRegI64(nreg));
5799 switch(size) {
5800 case 1:
5801 dup = Iop_Dup16x4;
5802 get = Iop_GetElem16x4;
5803 index = mreg >> 3;
5804 mreg &= 7;
5805 break;
5806 case 2:
5807 dup = Iop_Dup32x2;
5808 get = Iop_GetElem32x2;
5809 index = mreg >> 4;
5810 mreg &= 0xf;
5811 break;
5812 case 0:
5813 case 3:
5814 return False;
5815 default:
5816 vassert(0);
5818 assign(arg_m, unop(dup, binop(get, getDRegI64(mreg), mkU8(index))));
5820 switch (size) {
5821 case 0:
5822 case 3:
5823 return False;
5824 case 1:
5825 op = Q ? Iop_QDMulHi16Sx8 : Iop_QDMulHi16Sx4;
5826 op2 = Q ? Iop_CmpEQ16x8 : Iop_CmpEQ16x4;
5827 imm = 1LL << 15;
5828 imm = (imm << 16) | imm;
5829 imm = (imm << 32) | imm;
5830 break;
5831 case 2:
5832 op = Q ? Iop_QDMulHi32Sx4 : Iop_QDMulHi32Sx2;
5833 op2 = Q ? Iop_CmpEQ32x4 : Iop_CmpEQ32x2;
5834 imm = 1LL << 31;
5835 imm = (imm << 32) | imm;
5836 break;
5837 default:
5838 vassert(0);
5840 assign(res, binop(op, mkexpr(arg_n), mkexpr(arg_m)));
5841 setFlag_QC(binop(Q ? Iop_AndV128 : Iop_And64,
5842 binop(op2, mkexpr(arg_n),
5843 Q ? mkU128(imm) : mkU64(imm)),
5844 binop(op2, mkexpr(arg_m),
5845 Q ? mkU128(imm) : mkU64(imm))),
5846 Q ? mkU128(0) : mkU64(0),
5847 Q, condT);
5848 if (Q)
5849 putQReg(dreg, mkexpr(res), condT);
5850 else
5851 putDRegI64(dreg, mkexpr(res), condT);
5852 DIP("vqdmulh.s%d %c%u, %c%u, d%u[%u]\n",
5853 8 << size, Q ? 'q' : 'd', dreg,
5854 Q ? 'q' : 'd', nreg, mreg, index);
5855 return True;
5858 /* VQRDMULH (scalar) */
5859 if (INSN(11,8) == BITS4(1,1,0,1)) {
5860 IROp op ,op2, dup, get;
5861 ULong imm;
5862 IRTemp res, arg_m, arg_n;
5863 if (Q) {
5864 if ((dreg & 1) || (nreg & 1))
5865 return False;
5866 dreg >>= 1;
5867 nreg >>= 1;
5868 res = newTemp(Ity_V128);
5869 arg_m = newTemp(Ity_V128);
5870 arg_n = newTemp(Ity_V128);
5871 assign(arg_n, getQReg(nreg));
5872 switch(size) {
5873 case 1:
5874 dup = Iop_Dup16x8;
5875 get = Iop_GetElem16x4;
5876 index = mreg >> 3;
5877 mreg &= 7;
5878 break;
5879 case 2:
5880 dup = Iop_Dup32x4;
5881 get = Iop_GetElem32x2;
5882 index = mreg >> 4;
5883 mreg &= 0xf;
5884 break;
5885 case 0:
5886 case 3:
5887 return False;
5888 default:
5889 vassert(0);
5891 assign(arg_m, unop(dup, binop(get, getDRegI64(mreg), mkU8(index))));
5892 } else {
5893 res = newTemp(Ity_I64);
5894 arg_m = newTemp(Ity_I64);
5895 arg_n = newTemp(Ity_I64);
5896 assign(arg_n, getDRegI64(nreg));
5897 switch(size) {
5898 case 1:
5899 dup = Iop_Dup16x4;
5900 get = Iop_GetElem16x4;
5901 index = mreg >> 3;
5902 mreg &= 7;
5903 break;
5904 case 2:
5905 dup = Iop_Dup32x2;
5906 get = Iop_GetElem32x2;
5907 index = mreg >> 4;
5908 mreg &= 0xf;
5909 break;
5910 case 0:
5911 case 3:
5912 return False;
5913 default:
5914 vassert(0);
5916 assign(arg_m, unop(dup, binop(get, getDRegI64(mreg), mkU8(index))));
5918 switch (size) {
5919 case 0:
5920 case 3:
5921 return False;
5922 case 1:
5923 op = Q ? Iop_QRDMulHi16Sx8 : Iop_QRDMulHi16Sx4;
5924 op2 = Q ? Iop_CmpEQ16x8 : Iop_CmpEQ16x4;
5925 imm = 1LL << 15;
5926 imm = (imm << 16) | imm;
5927 imm = (imm << 32) | imm;
5928 break;
5929 case 2:
5930 op = Q ? Iop_QRDMulHi32Sx4 : Iop_QRDMulHi32Sx2;
5931 op2 = Q ? Iop_CmpEQ32x4 : Iop_CmpEQ32x2;
5932 imm = 1LL << 31;
5933 imm = (imm << 32) | imm;
5934 break;
5935 default:
5936 vassert(0);
5938 assign(res, binop(op, mkexpr(arg_n), mkexpr(arg_m)));
5939 setFlag_QC(binop(Q ? Iop_AndV128 : Iop_And64,
5940 binop(op2, mkexpr(arg_n),
5941 Q ? mkU128(imm) : mkU64(imm)),
5942 binop(op2, mkexpr(arg_m),
5943 Q ? mkU128(imm) : mkU64(imm))),
5944 Q ? mkU128(0) : mkU64(0),
5945 Q, condT);
5946 if (Q)
5947 putQReg(dreg, mkexpr(res), condT);
5948 else
5949 putDRegI64(dreg, mkexpr(res), condT);
5950 DIP("vqrdmulh.s%d %c%u, %c%u, d%u[%u]\n",
5951 8 << size, Q ? 'q' : 'd', dreg,
5952 Q ? 'q' : 'd', nreg, mreg, index);
5953 return True;
5956 return False;
5957 # undef INSN
5960 /* A7.4.4 Two registers and a shift amount */
5961 static
5962 Bool dis_neon_data_2reg_and_shift ( UInt theInstr, IRTemp condT )
5964 UInt A = (theInstr >> 8) & 0xf;
5965 UInt B = (theInstr >> 6) & 1;
5966 UInt L = (theInstr >> 7) & 1;
5967 UInt U = (theInstr >> 24) & 1;
5968 UInt Q = B;
5969 UInt imm6 = (theInstr >> 16) & 0x3f;
5970 UInt shift_imm;
5971 UInt size = 4;
5972 UInt tmp;
5973 UInt mreg = get_neon_m_regno(theInstr);
5974 UInt dreg = get_neon_d_regno(theInstr);
5975 ULong imm = 0;
5976 IROp op, cvt, add = Iop_INVALID, cvt2, op_rev;
5977 IRTemp reg_m, res, mask;
5979 if (L == 0 && ((theInstr >> 19) & 7) == 0)
5980 /* It is one reg and immediate */
5981 return False;
5983 tmp = (L << 6) | imm6;
5984 if (tmp & 0x40) {
5985 size = 3;
5986 shift_imm = 64 - imm6;
5987 } else if (tmp & 0x20) {
5988 size = 2;
5989 shift_imm = 64 - imm6;
5990 } else if (tmp & 0x10) {
5991 size = 1;
5992 shift_imm = 32 - imm6;
5993 } else if (tmp & 0x8) {
5994 size = 0;
5995 shift_imm = 16 - imm6;
5996 } else {
5997 return False;
6000 switch (A) {
6001 case 3:
6002 case 2:
6003 /* VRSHR, VRSRA */
6004 if (shift_imm > 0) {
6005 IRExpr *imm_val;
6006 imm = 1L;
6007 switch (size) {
6008 case 0:
6009 imm = (imm << 8) | imm;
6010 /* fall through */
6011 case 1:
6012 imm = (imm << 16) | imm;
6013 /* fall through */
6014 case 2:
6015 imm = (imm << 32) | imm;
6016 /* fall through */
6017 case 3:
6018 break;
6019 default:
6020 vassert(0);
6022 if (Q) {
6023 reg_m = newTemp(Ity_V128);
6024 res = newTemp(Ity_V128);
6025 imm_val = binop(Iop_64HLtoV128, mkU64(imm), mkU64(imm));
6026 assign(reg_m, getQReg(mreg));
6027 switch (size) {
6028 case 0:
6029 add = Iop_Add8x16;
6030 op = U ? Iop_ShrN8x16 : Iop_SarN8x16;
6031 break;
6032 case 1:
6033 add = Iop_Add16x8;
6034 op = U ? Iop_ShrN16x8 : Iop_SarN16x8;
6035 break;
6036 case 2:
6037 add = Iop_Add32x4;
6038 op = U ? Iop_ShrN32x4 : Iop_SarN32x4;
6039 break;
6040 case 3:
6041 add = Iop_Add64x2;
6042 op = U ? Iop_ShrN64x2 : Iop_SarN64x2;
6043 break;
6044 default:
6045 vassert(0);
6047 } else {
6048 reg_m = newTemp(Ity_I64);
6049 res = newTemp(Ity_I64);
6050 imm_val = mkU64(imm);
6051 assign(reg_m, getDRegI64(mreg));
6052 switch (size) {
6053 case 0:
6054 add = Iop_Add8x8;
6055 op = U ? Iop_ShrN8x8 : Iop_SarN8x8;
6056 break;
6057 case 1:
6058 add = Iop_Add16x4;
6059 op = U ? Iop_ShrN16x4 : Iop_SarN16x4;
6060 break;
6061 case 2:
6062 add = Iop_Add32x2;
6063 op = U ? Iop_ShrN32x2 : Iop_SarN32x2;
6064 break;
6065 case 3:
6066 add = Iop_Add64;
6067 op = U ? Iop_Shr64 : Iop_Sar64;
6068 break;
6069 default:
6070 vassert(0);
6073 assign(res,
6074 binop(add,
6075 binop(op,
6076 mkexpr(reg_m),
6077 mkU8(shift_imm)),
6078 binop(Q ? Iop_AndV128 : Iop_And64,
6079 binop(op,
6080 mkexpr(reg_m),
6081 mkU8(shift_imm - 1)),
6082 imm_val)));
6083 } else {
6084 if (Q) {
6085 res = newTemp(Ity_V128);
6086 assign(res, getQReg(mreg));
6087 } else {
6088 res = newTemp(Ity_I64);
6089 assign(res, getDRegI64(mreg));
6092 if (A == 3) {
6093 if (Q) {
6094 putQReg(dreg, binop(add, mkexpr(res), getQReg(dreg)),
6095 condT);
6096 } else {
6097 putDRegI64(dreg, binop(add, mkexpr(res), getDRegI64(dreg)),
6098 condT);
6100 DIP("vrsra.%c%d %c%u, %c%u, #%u\n",
6101 U ? 'u' : 's', 8 << size,
6102 Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', mreg, shift_imm);
6103 } else {
6104 if (Q) {
6105 putQReg(dreg, mkexpr(res), condT);
6106 } else {
6107 putDRegI64(dreg, mkexpr(res), condT);
6109 DIP("vrshr.%c%d %c%u, %c%u, #%u\n", U ? 'u' : 's', 8 << size,
6110 Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', mreg, shift_imm);
6112 return True;
6113 case 1:
6114 case 0:
6115 /* VSHR, VSRA */
6116 if (Q) {
6117 reg_m = newTemp(Ity_V128);
6118 assign(reg_m, getQReg(mreg));
6119 res = newTemp(Ity_V128);
6120 } else {
6121 reg_m = newTemp(Ity_I64);
6122 assign(reg_m, getDRegI64(mreg));
6123 res = newTemp(Ity_I64);
6125 if (Q) {
6126 switch (size) {
6127 case 0:
6128 op = U ? Iop_ShrN8x16 : Iop_SarN8x16;
6129 add = Iop_Add8x16;
6130 break;
6131 case 1:
6132 op = U ? Iop_ShrN16x8 : Iop_SarN16x8;
6133 add = Iop_Add16x8;
6134 break;
6135 case 2:
6136 op = U ? Iop_ShrN32x4 : Iop_SarN32x4;
6137 add = Iop_Add32x4;
6138 break;
6139 case 3:
6140 op = U ? Iop_ShrN64x2 : Iop_SarN64x2;
6141 add = Iop_Add64x2;
6142 break;
6143 default:
6144 vassert(0);
6146 } else {
6147 switch (size) {
6148 case 0:
6149 op = U ? Iop_ShrN8x8 : Iop_SarN8x8;
6150 add = Iop_Add8x8;
6151 break;
6152 case 1:
6153 op = U ? Iop_ShrN16x4 : Iop_SarN16x4;
6154 add = Iop_Add16x4;
6155 break;
6156 case 2:
6157 op = U ? Iop_ShrN32x2 : Iop_SarN32x2;
6158 add = Iop_Add32x2;
6159 break;
6160 case 3:
6161 op = U ? Iop_Shr64 : Iop_Sar64;
6162 add = Iop_Add64;
6163 break;
6164 default:
6165 vassert(0);
6168 assign(res, binop(op, mkexpr(reg_m), mkU8(shift_imm)));
6169 if (A == 1) {
6170 if (Q) {
6171 putQReg(dreg, binop(add, mkexpr(res), getQReg(dreg)),
6172 condT);
6173 } else {
6174 putDRegI64(dreg, binop(add, mkexpr(res), getDRegI64(dreg)),
6175 condT);
6177 DIP("vsra.%c%d %c%u, %c%u, #%u\n", U ? 'u' : 's', 8 << size,
6178 Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', mreg, shift_imm);
6179 } else {
6180 if (Q) {
6181 putQReg(dreg, mkexpr(res), condT);
6182 } else {
6183 putDRegI64(dreg, mkexpr(res), condT);
6185 DIP("vshr.%c%d %c%u, %c%u, #%u\n", U ? 'u' : 's', 8 << size,
6186 Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', mreg, shift_imm);
6188 return True;
6189 case 4:
6190 /* VSRI */
6191 if (!U)
6192 return False;
6193 if (Q) {
6194 res = newTemp(Ity_V128);
6195 mask = newTemp(Ity_V128);
6196 } else {
6197 res = newTemp(Ity_I64);
6198 mask = newTemp(Ity_I64);
6200 switch (size) {
6201 case 0: op = Q ? Iop_ShrN8x16 : Iop_ShrN8x8; break;
6202 case 1: op = Q ? Iop_ShrN16x8 : Iop_ShrN16x4; break;
6203 case 2: op = Q ? Iop_ShrN32x4 : Iop_ShrN32x2; break;
6204 case 3: op = Q ? Iop_ShrN64x2 : Iop_Shr64; break;
6205 default: vassert(0);
6207 if (Q) {
6208 assign(mask, binop(op, binop(Iop_64HLtoV128,
6209 mkU64(0xFFFFFFFFFFFFFFFFLL),
6210 mkU64(0xFFFFFFFFFFFFFFFFLL)),
6211 mkU8(shift_imm)));
6212 assign(res, binop(Iop_OrV128,
6213 binop(Iop_AndV128,
6214 getQReg(dreg),
6215 unop(Iop_NotV128,
6216 mkexpr(mask))),
6217 binop(op,
6218 getQReg(mreg),
6219 mkU8(shift_imm))));
6220 putQReg(dreg, mkexpr(res), condT);
6221 } else {
6222 assign(mask, binop(op, mkU64(0xFFFFFFFFFFFFFFFFLL),
6223 mkU8(shift_imm)));
6224 assign(res, binop(Iop_Or64,
6225 binop(Iop_And64,
6226 getDRegI64(dreg),
6227 unop(Iop_Not64,
6228 mkexpr(mask))),
6229 binop(op,
6230 getDRegI64(mreg),
6231 mkU8(shift_imm))));
6232 putDRegI64(dreg, mkexpr(res), condT);
6234 DIP("vsri.%d %c%u, %c%u, #%u\n",
6235 8 << size, Q ? 'q' : 'd', dreg,
6236 Q ? 'q' : 'd', mreg, shift_imm);
6237 return True;
6238 case 5:
6239 if (U) {
6240 /* VSLI */
6241 shift_imm = 8 * (1 << size) - shift_imm;
6242 if (Q) {
6243 res = newTemp(Ity_V128);
6244 mask = newTemp(Ity_V128);
6245 } else {
6246 res = newTemp(Ity_I64);
6247 mask = newTemp(Ity_I64);
6249 switch (size) {
6250 case 0: op = Q ? Iop_ShlN8x16 : Iop_ShlN8x8; break;
6251 case 1: op = Q ? Iop_ShlN16x8 : Iop_ShlN16x4; break;
6252 case 2: op = Q ? Iop_ShlN32x4 : Iop_ShlN32x2; break;
6253 case 3: op = Q ? Iop_ShlN64x2 : Iop_Shl64; break;
6254 default: vassert(0);
6256 if (Q) {
6257 assign(mask, binop(op, binop(Iop_64HLtoV128,
6258 mkU64(0xFFFFFFFFFFFFFFFFLL),
6259 mkU64(0xFFFFFFFFFFFFFFFFLL)),
6260 mkU8(shift_imm)));
6261 assign(res, binop(Iop_OrV128,
6262 binop(Iop_AndV128,
6263 getQReg(dreg),
6264 unop(Iop_NotV128,
6265 mkexpr(mask))),
6266 binop(op,
6267 getQReg(mreg),
6268 mkU8(shift_imm))));
6269 putQReg(dreg, mkexpr(res), condT);
6270 } else {
6271 assign(mask, binop(op, mkU64(0xFFFFFFFFFFFFFFFFLL),
6272 mkU8(shift_imm)));
6273 assign(res, binop(Iop_Or64,
6274 binop(Iop_And64,
6275 getDRegI64(dreg),
6276 unop(Iop_Not64,
6277 mkexpr(mask))),
6278 binop(op,
6279 getDRegI64(mreg),
6280 mkU8(shift_imm))));
6281 putDRegI64(dreg, mkexpr(res), condT);
6283 DIP("vsli.%d %c%u, %c%u, #%u\n",
6284 8 << size, Q ? 'q' : 'd', dreg,
6285 Q ? 'q' : 'd', mreg, shift_imm);
6286 return True;
6287 } else {
6288 /* VSHL #imm */
6289 shift_imm = 8 * (1 << size) - shift_imm;
6290 if (Q) {
6291 res = newTemp(Ity_V128);
6292 } else {
6293 res = newTemp(Ity_I64);
6295 switch (size) {
6296 case 0: op = Q ? Iop_ShlN8x16 : Iop_ShlN8x8; break;
6297 case 1: op = Q ? Iop_ShlN16x8 : Iop_ShlN16x4; break;
6298 case 2: op = Q ? Iop_ShlN32x4 : Iop_ShlN32x2; break;
6299 case 3: op = Q ? Iop_ShlN64x2 : Iop_Shl64; break;
6300 default: vassert(0);
6302 assign(res, binop(op, Q ? getQReg(mreg) : getDRegI64(mreg),
6303 mkU8(shift_imm)));
6304 if (Q) {
6305 putQReg(dreg, mkexpr(res), condT);
6306 } else {
6307 putDRegI64(dreg, mkexpr(res), condT);
6309 DIP("vshl.i%d %c%u, %c%u, #%u\n",
6310 8 << size, Q ? 'q' : 'd', dreg,
6311 Q ? 'q' : 'd', mreg, shift_imm);
6312 return True;
6314 break;
6315 case 6:
6316 case 7:
6317 /* VQSHL, VQSHLU */
6318 shift_imm = 8 * (1 << size) - shift_imm;
6319 if (U) {
6320 if (A & 1) {
6321 switch (size) {
6322 case 0:
6323 op = Q ? Iop_QShlNsatUU8x16 : Iop_QShlNsatUU8x8;
6324 op_rev = Q ? Iop_ShrN8x16 : Iop_ShrN8x8;
6325 break;
6326 case 1:
6327 op = Q ? Iop_QShlNsatUU16x8 : Iop_QShlNsatUU16x4;
6328 op_rev = Q ? Iop_ShrN16x8 : Iop_ShrN16x4;
6329 break;
6330 case 2:
6331 op = Q ? Iop_QShlNsatUU32x4 : Iop_QShlNsatUU32x2;
6332 op_rev = Q ? Iop_ShrN32x4 : Iop_ShrN32x2;
6333 break;
6334 case 3:
6335 op = Q ? Iop_QShlNsatUU64x2 : Iop_QShlNsatUU64x1;
6336 op_rev = Q ? Iop_ShrN64x2 : Iop_Shr64;
6337 break;
6338 default:
6339 vassert(0);
6341 DIP("vqshl.u%d %c%u, %c%u, #%u\n",
6342 8 << size,
6343 Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', mreg, shift_imm);
6344 } else {
6345 switch (size) {
6346 case 0:
6347 op = Q ? Iop_QShlNsatSU8x16 : Iop_QShlNsatSU8x8;
6348 op_rev = Q ? Iop_ShrN8x16 : Iop_ShrN8x8;
6349 break;
6350 case 1:
6351 op = Q ? Iop_QShlNsatSU16x8 : Iop_QShlNsatSU16x4;
6352 op_rev = Q ? Iop_ShrN16x8 : Iop_ShrN16x4;
6353 break;
6354 case 2:
6355 op = Q ? Iop_QShlNsatSU32x4 : Iop_QShlNsatSU32x2;
6356 op_rev = Q ? Iop_ShrN32x4 : Iop_ShrN32x2;
6357 break;
6358 case 3:
6359 op = Q ? Iop_QShlNsatSU64x2 : Iop_QShlNsatSU64x1;
6360 op_rev = Q ? Iop_ShrN64x2 : Iop_Shr64;
6361 break;
6362 default:
6363 vassert(0);
6365 DIP("vqshlu.s%d %c%u, %c%u, #%u\n",
6366 8 << size,
6367 Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', mreg, shift_imm);
6369 } else {
6370 if (!(A & 1))
6371 return False;
6372 switch (size) {
6373 case 0:
6374 op = Q ? Iop_QShlNsatSS8x16 : Iop_QShlNsatSS8x8;
6375 op_rev = Q ? Iop_SarN8x16 : Iop_SarN8x8;
6376 break;
6377 case 1:
6378 op = Q ? Iop_QShlNsatSS16x8 : Iop_QShlNsatSS16x4;
6379 op_rev = Q ? Iop_SarN16x8 : Iop_SarN16x4;
6380 break;
6381 case 2:
6382 op = Q ? Iop_QShlNsatSS32x4 : Iop_QShlNsatSS32x2;
6383 op_rev = Q ? Iop_SarN32x4 : Iop_SarN32x2;
6384 break;
6385 case 3:
6386 op = Q ? Iop_QShlNsatSS64x2 : Iop_QShlNsatSS64x1;
6387 op_rev = Q ? Iop_SarN64x2 : Iop_Sar64;
6388 break;
6389 default:
6390 vassert(0);
6392 DIP("vqshl.s%d %c%u, %c%u, #%u\n",
6393 8 << size,
6394 Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', mreg, shift_imm);
6396 if (Q) {
6397 tmp = newTemp(Ity_V128);
6398 res = newTemp(Ity_V128);
6399 reg_m = newTemp(Ity_V128);
6400 assign(reg_m, getQReg(mreg));
6401 } else {
6402 tmp = newTemp(Ity_I64);
6403 res = newTemp(Ity_I64);
6404 reg_m = newTemp(Ity_I64);
6405 assign(reg_m, getDRegI64(mreg));
6407 assign(res, binop(op, mkexpr(reg_m), mkU8(shift_imm)));
6408 assign(tmp, binop(op_rev, mkexpr(res), mkU8(shift_imm)));
6409 setFlag_QC(mkexpr(tmp), mkexpr(reg_m), Q, condT);
6410 if (Q)
6411 putQReg(dreg, mkexpr(res), condT);
6412 else
6413 putDRegI64(dreg, mkexpr(res), condT);
6414 return True;
6415 case 8:
6416 if (!U) {
6417 if (L == 1)
6418 return False;
6419 size++;
6420 dreg = ((theInstr >> 18) & 0x10) | ((theInstr >> 12) & 0xF);
6421 mreg = ((theInstr >> 1) & 0x10) | (theInstr & 0xF);
6422 if (mreg & 1)
6423 return False;
6424 mreg >>= 1;
6425 if (!B) {
6426 /* VSHRN*/
6427 IROp narOp;
6428 reg_m = newTemp(Ity_V128);
6429 assign(reg_m, getQReg(mreg));
6430 res = newTemp(Ity_I64);
6431 switch (size) {
6432 case 1:
6433 op = Iop_ShrN16x8;
6434 narOp = Iop_NarrowUn16to8x8;
6435 break;
6436 case 2:
6437 op = Iop_ShrN32x4;
6438 narOp = Iop_NarrowUn32to16x4;
6439 break;
6440 case 3:
6441 op = Iop_ShrN64x2;
6442 narOp = Iop_NarrowUn64to32x2;
6443 break;
6444 default:
6445 vassert(0);
6447 assign(res, unop(narOp,
6448 binop(op,
6449 mkexpr(reg_m),
6450 mkU8(shift_imm))));
6451 putDRegI64(dreg, mkexpr(res), condT);
6452 DIP("vshrn.i%d d%u, q%u, #%u\n", 8 << size, dreg, mreg,
6453 shift_imm);
6454 return True;
6455 } else {
6456 /* VRSHRN */
6457 IROp addOp, shOp, narOp;
6458 IRExpr *imm_val;
6459 reg_m = newTemp(Ity_V128);
6460 assign(reg_m, getQReg(mreg));
6461 res = newTemp(Ity_I64);
6462 imm = 1L;
6463 switch (size) {
6464 case 0: imm = (imm << 8) | imm; /* fall through */
6465 case 1: imm = (imm << 16) | imm; /* fall through */
6466 case 2: imm = (imm << 32) | imm; /* fall through */
6467 case 3: break;
6468 default: vassert(0);
6470 imm_val = binop(Iop_64HLtoV128, mkU64(imm), mkU64(imm));
6471 switch (size) {
6472 case 1:
6473 addOp = Iop_Add16x8;
6474 shOp = Iop_ShrN16x8;
6475 narOp = Iop_NarrowUn16to8x8;
6476 break;
6477 case 2:
6478 addOp = Iop_Add32x4;
6479 shOp = Iop_ShrN32x4;
6480 narOp = Iop_NarrowUn32to16x4;
6481 break;
6482 case 3:
6483 addOp = Iop_Add64x2;
6484 shOp = Iop_ShrN64x2;
6485 narOp = Iop_NarrowUn64to32x2;
6486 break;
6487 default:
6488 vassert(0);
6490 assign(res, unop(narOp,
6491 binop(addOp,
6492 binop(shOp,
6493 mkexpr(reg_m),
6494 mkU8(shift_imm)),
6495 binop(Iop_AndV128,
6496 binop(shOp,
6497 mkexpr(reg_m),
6498 mkU8(shift_imm - 1)),
6499 imm_val))));
6500 putDRegI64(dreg, mkexpr(res), condT);
6501 if (shift_imm == 0) {
6502 DIP("vmov%d d%u, q%u, #%u\n", 8 << size, dreg, mreg,
6503 shift_imm);
6504 } else {
6505 DIP("vrshrn.i%d d%u, q%u, #%u\n", 8 << size, dreg, mreg,
6506 shift_imm);
6508 return True;
6510 } else {
6511 /* fall through */
6513 case 9:
6514 dreg = ((theInstr >> 18) & 0x10) | ((theInstr >> 12) & 0xF);
6515 mreg = ((theInstr >> 1) & 0x10) | (theInstr & 0xF);
6516 if (mreg & 1)
6517 return False;
6518 mreg >>= 1;
6519 size++;
6520 if ((theInstr >> 8) & 1) {
6521 switch (size) {
6522 case 1:
6523 op = U ? Iop_ShrN16x8 : Iop_SarN16x8;
6524 cvt = U ? Iop_QNarrowUn16Uto8Ux8 : Iop_QNarrowUn16Sto8Sx8;
6525 cvt2 = U ? Iop_Widen8Uto16x8 : Iop_Widen8Sto16x8;
6526 break;
6527 case 2:
6528 op = U ? Iop_ShrN32x4 : Iop_SarN32x4;
6529 cvt = U ? Iop_QNarrowUn32Uto16Ux4 : Iop_QNarrowUn32Sto16Sx4;
6530 cvt2 = U ? Iop_Widen16Uto32x4 : Iop_Widen16Sto32x4;
6531 break;
6532 case 3:
6533 op = U ? Iop_ShrN64x2 : Iop_SarN64x2;
6534 cvt = U ? Iop_QNarrowUn64Uto32Ux2 : Iop_QNarrowUn64Sto32Sx2;
6535 cvt2 = U ? Iop_Widen32Uto64x2 : Iop_Widen32Sto64x2;
6536 break;
6537 default:
6538 vassert(0);
6540 DIP("vq%sshrn.%c%d d%u, q%u, #%u\n", B ? "r" : "",
6541 U ? 'u' : 's', 8 << size, dreg, mreg, shift_imm);
6542 } else {
6543 vassert(U);
6544 switch (size) {
6545 case 1:
6546 op = Iop_SarN16x8;
6547 cvt = Iop_QNarrowUn16Sto8Ux8;
6548 cvt2 = Iop_Widen8Uto16x8;
6549 break;
6550 case 2:
6551 op = Iop_SarN32x4;
6552 cvt = Iop_QNarrowUn32Sto16Ux4;
6553 cvt2 = Iop_Widen16Uto32x4;
6554 break;
6555 case 3:
6556 op = Iop_SarN64x2;
6557 cvt = Iop_QNarrowUn64Sto32Ux2;
6558 cvt2 = Iop_Widen32Uto64x2;
6559 break;
6560 default:
6561 vassert(0);
6563 DIP("vq%sshrun.s%d d%u, q%u, #%u\n", B ? "r" : "",
6564 8 << size, dreg, mreg, shift_imm);
6566 if (B) {
6567 if (shift_imm > 0) {
6568 imm = 1;
6569 switch (size) {
6570 case 1: imm = (imm << 16) | imm; /* fall through */
6571 case 2: imm = (imm << 32) | imm; /* fall through */
6572 case 3: break;
6573 case 0: default: vassert(0);
6575 switch (size) {
6576 case 1: add = Iop_Add16x8; break;
6577 case 2: add = Iop_Add32x4; break;
6578 case 3: add = Iop_Add64x2; break;
6579 case 0: default: vassert(0);
6583 reg_m = newTemp(Ity_V128);
6584 res = newTemp(Ity_V128);
6585 assign(reg_m, getQReg(mreg));
6586 if (B) {
6587 /* VQRSHRN, VQRSHRUN */
6588 assign(res, binop(add,
6589 binop(op, mkexpr(reg_m), mkU8(shift_imm)),
6590 binop(Iop_AndV128,
6591 binop(op,
6592 mkexpr(reg_m),
6593 mkU8(shift_imm - 1)),
6594 mkU128(imm))));
6595 } else {
6596 /* VQSHRN, VQSHRUN */
6597 assign(res, binop(op, mkexpr(reg_m), mkU8(shift_imm)));
6599 setFlag_QC(unop(cvt2, unop(cvt, mkexpr(res))), mkexpr(res),
6600 True, condT);
6601 putDRegI64(dreg, unop(cvt, mkexpr(res)), condT);
6602 return True;
6603 case 10:
6604 /* VSHLL
6605 VMOVL ::= VSHLL #0 */
6606 if (B)
6607 return False;
6608 if (dreg & 1)
6609 return False;
6610 dreg >>= 1;
6611 shift_imm = (8 << size) - shift_imm;
6612 res = newTemp(Ity_V128);
6613 switch (size) {
6614 case 0:
6615 op = Iop_ShlN16x8;
6616 cvt = U ? Iop_Widen8Uto16x8 : Iop_Widen8Sto16x8;
6617 break;
6618 case 1:
6619 op = Iop_ShlN32x4;
6620 cvt = U ? Iop_Widen16Uto32x4 : Iop_Widen16Sto32x4;
6621 break;
6622 case 2:
6623 op = Iop_ShlN64x2;
6624 cvt = U ? Iop_Widen32Uto64x2 : Iop_Widen32Sto64x2;
6625 break;
6626 case 3:
6627 return False;
6628 default:
6629 vassert(0);
6631 assign(res, binop(op, unop(cvt, getDRegI64(mreg)), mkU8(shift_imm)));
6632 putQReg(dreg, mkexpr(res), condT);
6633 if (shift_imm == 0) {
6634 DIP("vmovl.%c%d q%u, d%u\n", U ? 'u' : 's', 8 << size,
6635 dreg, mreg);
6636 } else {
6637 DIP("vshll.%c%d q%u, d%u, #%u\n", U ? 'u' : 's', 8 << size,
6638 dreg, mreg, shift_imm);
6640 return True;
6641 case 14:
6642 case 15:
6643 /* VCVT floating-point <-> fixed-point */
6644 if ((theInstr >> 8) & 1) {
6645 if (U) {
6646 op = Q ? Iop_F32ToFixed32Ux4_RZ : Iop_F32ToFixed32Ux2_RZ;
6647 } else {
6648 op = Q ? Iop_F32ToFixed32Sx4_RZ : Iop_F32ToFixed32Sx2_RZ;
6650 DIP("vcvt.%c32.f32 %c%u, %c%u, #%u\n", U ? 'u' : 's',
6651 Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', mreg,
6652 64 - ((theInstr >> 16) & 0x3f));
6653 } else {
6654 if (U) {
6655 op = Q ? Iop_Fixed32UToF32x4_RN : Iop_Fixed32UToF32x2_RN;
6656 } else {
6657 op = Q ? Iop_Fixed32SToF32x4_RN : Iop_Fixed32SToF32x2_RN;
6659 DIP("vcvt.f32.%c32 %c%u, %c%u, #%u\n", U ? 'u' : 's',
6660 Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', mreg,
6661 64 - ((theInstr >> 16) & 0x3f));
6663 if (((theInstr >> 21) & 1) == 0)
6664 return False;
6665 if (Q) {
6666 putQReg(dreg, binop(op, getQReg(mreg),
6667 mkU8(64 - ((theInstr >> 16) & 0x3f))), condT);
6668 } else {
6669 putDRegI64(dreg, binop(op, getDRegI64(mreg),
6670 mkU8(64 - ((theInstr >> 16) & 0x3f))), condT);
6672 return True;
6673 default:
6674 return False;
6677 return False;
6680 /* A7.4.5 Two registers, miscellaneous */
6681 static
6682 Bool dis_neon_data_2reg_misc ( UInt theInstr, IRTemp condT )
6684 UInt A = (theInstr >> 16) & 3;
6685 UInt B = (theInstr >> 6) & 0x1f;
6686 UInt Q = (theInstr >> 6) & 1;
6687 UInt U = (theInstr >> 24) & 1;
6688 UInt size = (theInstr >> 18) & 3;
6689 UInt dreg = get_neon_d_regno(theInstr);
6690 UInt mreg = get_neon_m_regno(theInstr);
6691 UInt F = (theInstr >> 10) & 1;
6692 IRTemp arg_d = IRTemp_INVALID;
6693 IRTemp arg_m = IRTemp_INVALID;
6694 IRTemp res = IRTemp_INVALID;
6695 switch (A) {
6696 case 0:
6697 if (Q) {
6698 arg_m = newTemp(Ity_V128);
6699 res = newTemp(Ity_V128);
6700 assign(arg_m, getQReg(mreg));
6701 } else {
6702 arg_m = newTemp(Ity_I64);
6703 res = newTemp(Ity_I64);
6704 assign(arg_m, getDRegI64(mreg));
6706 switch (B >> 1) {
6707 case 0: {
6708 /* VREV64 */
6709 IROp op;
6710 switch (size) {
6711 case 0:
6712 op = Q ? Iop_Reverse8sIn64_x2 : Iop_Reverse8sIn64_x1;
6713 break;
6714 case 1:
6715 op = Q ? Iop_Reverse16sIn64_x2 : Iop_Reverse16sIn64_x1;
6716 break;
6717 case 2:
6718 op = Q ? Iop_Reverse32sIn64_x2 : Iop_Reverse32sIn64_x1;
6719 break;
6720 case 3:
6721 return False;
6722 default:
6723 vassert(0);
6725 assign(res, unop(op, mkexpr(arg_m)));
6726 DIP("vrev64.%d %c%u, %c%u\n", 8 << size,
6727 Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', mreg);
6728 break;
6730 case 1: {
6731 /* VREV32 */
6732 IROp op;
6733 switch (size) {
6734 case 0:
6735 op = Q ? Iop_Reverse8sIn32_x4 : Iop_Reverse8sIn32_x2;
6736 break;
6737 case 1:
6738 op = Q ? Iop_Reverse16sIn32_x4 : Iop_Reverse16sIn32_x2;
6739 break;
6740 case 2:
6741 case 3:
6742 return False;
6743 default:
6744 vassert(0);
6746 assign(res, unop(op, mkexpr(arg_m)));
6747 DIP("vrev32.%d %c%u, %c%u\n", 8 << size,
6748 Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', mreg);
6749 break;
6751 case 2: {
6752 /* VREV16 */
6753 IROp op;
6754 switch (size) {
6755 case 0:
6756 op = Q ? Iop_Reverse8sIn16_x8 : Iop_Reverse8sIn16_x4;
6757 break;
6758 case 1:
6759 case 2:
6760 case 3:
6761 return False;
6762 default:
6763 vassert(0);
6765 assign(res, unop(op, mkexpr(arg_m)));
6766 DIP("vrev16.%d %c%u, %c%u\n", 8 << size,
6767 Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', mreg);
6768 break;
6770 case 3:
6771 return False;
6772 case 4:
6773 case 5: {
6774 /* VPADDL */
6775 IROp op;
6776 U = (theInstr >> 7) & 1;
6777 if (Q) {
6778 switch (size) {
6779 case 0: op = U ? Iop_PwAddL8Ux16 : Iop_PwAddL8Sx16; break;
6780 case 1: op = U ? Iop_PwAddL16Ux8 : Iop_PwAddL16Sx8; break;
6781 case 2: op = U ? Iop_PwAddL32Ux4 : Iop_PwAddL32Sx4; break;
6782 case 3: return False;
6783 default: vassert(0);
6785 } else {
6786 switch (size) {
6787 case 0: op = U ? Iop_PwAddL8Ux8 : Iop_PwAddL8Sx8; break;
6788 case 1: op = U ? Iop_PwAddL16Ux4 : Iop_PwAddL16Sx4; break;
6789 case 2: op = U ? Iop_PwAddL32Ux2 : Iop_PwAddL32Sx2; break;
6790 case 3: return False;
6791 default: vassert(0);
6794 assign(res, unop(op, mkexpr(arg_m)));
6795 DIP("vpaddl.%c%d %c%u, %c%u\n", U ? 'u' : 's', 8 << size,
6796 Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', mreg);
6797 break;
6799 case 6:
6800 case 7:
6801 return False;
6802 case 8: {
6803 /* VCLS */
6804 IROp op;
6805 switch (size) {
6806 case 0: op = Q ? Iop_Cls8x16 : Iop_Cls8x8; break;
6807 case 1: op = Q ? Iop_Cls16x8 : Iop_Cls16x4; break;
6808 case 2: op = Q ? Iop_Cls32x4 : Iop_Cls32x2; break;
6809 case 3: return False;
6810 default: vassert(0);
6812 assign(res, unop(op, mkexpr(arg_m)));
6813 DIP("vcls.s%d %c%u, %c%u\n", 8 << size, Q ? 'q' : 'd', dreg,
6814 Q ? 'q' : 'd', mreg);
6815 break;
6817 case 9: {
6818 /* VCLZ */
6819 IROp op;
6820 switch (size) {
6821 case 0: op = Q ? Iop_Clz8x16 : Iop_Clz8x8; break;
6822 case 1: op = Q ? Iop_Clz16x8 : Iop_Clz16x4; break;
6823 case 2: op = Q ? Iop_Clz32x4 : Iop_Clz32x2; break;
6824 case 3: return False;
6825 default: vassert(0);
6827 assign(res, unop(op, mkexpr(arg_m)));
6828 DIP("vclz.i%d %c%u, %c%u\n", 8 << size, Q ? 'q' : 'd', dreg,
6829 Q ? 'q' : 'd', mreg);
6830 break;
6832 case 10:
6833 /* VCNT */
6834 assign(res, unop(Q ? Iop_Cnt8x16 : Iop_Cnt8x8, mkexpr(arg_m)));
6835 DIP("vcnt.8 %c%u, %c%u\n", Q ? 'q' : 'd', dreg, Q ? 'q' : 'd',
6836 mreg);
6837 break;
6838 case 11:
6839 /* VMVN */
6840 if (Q)
6841 assign(res, unop(Iop_NotV128, mkexpr(arg_m)));
6842 else
6843 assign(res, unop(Iop_Not64, mkexpr(arg_m)));
6844 DIP("vmvn %c%u, %c%u\n", Q ? 'q' : 'd', dreg, Q ? 'q' : 'd',
6845 mreg);
6846 break;
6847 case 12:
6848 case 13: {
6849 /* VPADAL */
6850 IROp op, add_op;
6851 U = (theInstr >> 7) & 1;
6852 if (Q) {
6853 switch (size) {
6854 case 0:
6855 op = U ? Iop_PwAddL8Ux16 : Iop_PwAddL8Sx16;
6856 add_op = Iop_Add16x8;
6857 break;
6858 case 1:
6859 op = U ? Iop_PwAddL16Ux8 : Iop_PwAddL16Sx8;
6860 add_op = Iop_Add32x4;
6861 break;
6862 case 2:
6863 op = U ? Iop_PwAddL32Ux4 : Iop_PwAddL32Sx4;
6864 add_op = Iop_Add64x2;
6865 break;
6866 case 3:
6867 return False;
6868 default:
6869 vassert(0);
6871 } else {
6872 switch (size) {
6873 case 0:
6874 op = U ? Iop_PwAddL8Ux8 : Iop_PwAddL8Sx8;
6875 add_op = Iop_Add16x4;
6876 break;
6877 case 1:
6878 op = U ? Iop_PwAddL16Ux4 : Iop_PwAddL16Sx4;
6879 add_op = Iop_Add32x2;
6880 break;
6881 case 2:
6882 op = U ? Iop_PwAddL32Ux2 : Iop_PwAddL32Sx2;
6883 add_op = Iop_Add64;
6884 break;
6885 case 3:
6886 return False;
6887 default:
6888 vassert(0);
6891 if (Q) {
6892 arg_d = newTemp(Ity_V128);
6893 assign(arg_d, getQReg(dreg));
6894 } else {
6895 arg_d = newTemp(Ity_I64);
6896 assign(arg_d, getDRegI64(dreg));
6898 assign(res, binop(add_op, unop(op, mkexpr(arg_m)),
6899 mkexpr(arg_d)));
6900 DIP("vpadal.%c%d %c%u, %c%u\n", U ? 'u' : 's', 8 << size,
6901 Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', mreg);
6902 break;
6904 case 14: {
6905 /* VQABS */
6906 IROp op_sub, op_qsub, op_cmp;
6907 IRTemp mask, tmp;
6908 IRExpr *zero1, *zero2;
6909 IRExpr *neg, *neg2;
6910 if (Q) {
6911 zero1 = binop(Iop_64HLtoV128, mkU64(0), mkU64(0));
6912 zero2 = binop(Iop_64HLtoV128, mkU64(0), mkU64(0));
6913 mask = newTemp(Ity_V128);
6914 tmp = newTemp(Ity_V128);
6915 } else {
6916 zero1 = mkU64(0);
6917 zero2 = mkU64(0);
6918 mask = newTemp(Ity_I64);
6919 tmp = newTemp(Ity_I64);
6921 switch (size) {
6922 case 0:
6923 op_sub = Q ? Iop_Sub8x16 : Iop_Sub8x8;
6924 op_qsub = Q ? Iop_QSub8Sx16 : Iop_QSub8Sx8;
6925 op_cmp = Q ? Iop_CmpGT8Sx16 : Iop_CmpGT8Sx8;
6926 break;
6927 case 1:
6928 op_sub = Q ? Iop_Sub16x8 : Iop_Sub16x4;
6929 op_qsub = Q ? Iop_QSub16Sx8 : Iop_QSub16Sx4;
6930 op_cmp = Q ? Iop_CmpGT16Sx8 : Iop_CmpGT16Sx4;
6931 break;
6932 case 2:
6933 op_sub = Q ? Iop_Sub32x4 : Iop_Sub32x2;
6934 op_qsub = Q ? Iop_QSub32Sx4 : Iop_QSub32Sx2;
6935 op_cmp = Q ? Iop_CmpGT32Sx4 : Iop_CmpGT32Sx2;
6936 break;
6937 case 3:
6938 return False;
6939 default:
6940 vassert(0);
6942 assign(mask, binop(op_cmp, mkexpr(arg_m), zero1));
6943 neg = binop(op_qsub, zero2, mkexpr(arg_m));
6944 neg2 = binop(op_sub, zero2, mkexpr(arg_m));
6945 assign(res, binop(Q ? Iop_OrV128 : Iop_Or64,
6946 binop(Q ? Iop_AndV128 : Iop_And64,
6947 mkexpr(mask),
6948 mkexpr(arg_m)),
6949 binop(Q ? Iop_AndV128 : Iop_And64,
6950 unop(Q ? Iop_NotV128 : Iop_Not64,
6951 mkexpr(mask)),
6952 neg)));
6953 assign(tmp, binop(Q ? Iop_OrV128 : Iop_Or64,
6954 binop(Q ? Iop_AndV128 : Iop_And64,
6955 mkexpr(mask),
6956 mkexpr(arg_m)),
6957 binop(Q ? Iop_AndV128 : Iop_And64,
6958 unop(Q ? Iop_NotV128 : Iop_Not64,
6959 mkexpr(mask)),
6960 neg2)));
6961 setFlag_QC(mkexpr(res), mkexpr(tmp), Q, condT);
6962 DIP("vqabs.s%d %c%u, %c%u\n", 8 << size, Q ? 'q' : 'd', dreg,
6963 Q ? 'q' : 'd', mreg);
6964 break;
6966 case 15: {
6967 /* VQNEG */
6968 IROp op, op2;
6969 IRExpr *zero;
6970 if (Q) {
6971 zero = binop(Iop_64HLtoV128, mkU64(0), mkU64(0));
6972 } else {
6973 zero = mkU64(0);
6975 switch (size) {
6976 case 0:
6977 op = Q ? Iop_QSub8Sx16 : Iop_QSub8Sx8;
6978 op2 = Q ? Iop_Sub8x16 : Iop_Sub8x8;
6979 break;
6980 case 1:
6981 op = Q ? Iop_QSub16Sx8 : Iop_QSub16Sx4;
6982 op2 = Q ? Iop_Sub16x8 : Iop_Sub16x4;
6983 break;
6984 case 2:
6985 op = Q ? Iop_QSub32Sx4 : Iop_QSub32Sx2;
6986 op2 = Q ? Iop_Sub32x4 : Iop_Sub32x2;
6987 break;
6988 case 3:
6989 return False;
6990 default:
6991 vassert(0);
6993 assign(res, binop(op, zero, mkexpr(arg_m)));
6994 setFlag_QC(mkexpr(res), binop(op2, zero, mkexpr(arg_m)),
6995 Q, condT);
6996 DIP("vqneg.s%d %c%u, %c%u\n", 8 << size, Q ? 'q' : 'd', dreg,
6997 Q ? 'q' : 'd', mreg);
6998 break;
7000 default:
7001 vassert(0);
7003 if (Q) {
7004 putQReg(dreg, mkexpr(res), condT);
7005 } else {
7006 putDRegI64(dreg, mkexpr(res), condT);
7008 return True;
7009 case 1:
7010 if (Q) {
7011 arg_m = newTemp(Ity_V128);
7012 res = newTemp(Ity_V128);
7013 assign(arg_m, getQReg(mreg));
7014 } else {
7015 arg_m = newTemp(Ity_I64);
7016 res = newTemp(Ity_I64);
7017 assign(arg_m, getDRegI64(mreg));
7019 switch ((B >> 1) & 0x7) {
7020 case 0: {
7021 /* VCGT #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);
7029 if (F) {
7030 switch (size) {
7031 case 0: case 1: case 3: return False;
7032 case 2: op = Q ? Iop_CmpGT32Fx4 : Iop_CmpGT32Fx2; break;
7033 default: vassert(0);
7035 } else {
7036 switch (size) {
7037 case 0: op = Q ? Iop_CmpGT8Sx16 : Iop_CmpGT8Sx8; break;
7038 case 1: op = Q ? Iop_CmpGT16Sx8 : Iop_CmpGT16Sx4; break;
7039 case 2: op = Q ? Iop_CmpGT32Sx4 : Iop_CmpGT32Sx2; break;
7040 case 3: return False;
7041 default: vassert(0);
7044 assign(res, binop(op, mkexpr(arg_m), zero));
7045 DIP("vcgt.%c%d %c%u, %c%u, #0\n", F ? 'f' : 's', 8 << size,
7046 Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', mreg);
7047 break;
7049 case 1: {
7050 /* VCGE #0 */
7051 IROp op;
7052 IRExpr *zero;
7053 if (Q) {
7054 zero = binop(Iop_64HLtoV128, mkU64(0), mkU64(0));
7055 } else {
7056 zero = mkU64(0);
7058 if (F) {
7059 switch (size) {
7060 case 0: case 1: case 3: return False;
7061 case 2: op = Q ? Iop_CmpGE32Fx4 : Iop_CmpGE32Fx2; break;
7062 default: vassert(0);
7064 assign(res, binop(op, mkexpr(arg_m), zero));
7065 } else {
7066 switch (size) {
7067 case 0: op = Q ? Iop_CmpGT8Sx16 : Iop_CmpGT8Sx8; break;
7068 case 1: op = Q ? Iop_CmpGT16Sx8 : Iop_CmpGT16Sx4; break;
7069 case 2: op = Q ? Iop_CmpGT32Sx4 : Iop_CmpGT32Sx2; break;
7070 case 3: return False;
7071 default: vassert(0);
7073 assign(res, unop(Q ? Iop_NotV128 : Iop_Not64,
7074 binop(op, zero, mkexpr(arg_m))));
7076 DIP("vcge.%c%d %c%u, %c%u, #0\n", F ? 'f' : 's', 8 << size,
7077 Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', mreg);
7078 break;
7080 case 2: {
7081 /* VCEQ #0 */
7082 IROp op;
7083 IRExpr *zero;
7084 if (F) {
7085 if (Q) {
7086 zero = binop(Iop_64HLtoV128, mkU64(0), mkU64(0));
7087 } else {
7088 zero = mkU64(0);
7090 switch (size) {
7091 case 0: case 1: case 3: return False;
7092 case 2: op = Q ? Iop_CmpEQ32Fx4 : Iop_CmpEQ32Fx2; break;
7093 default: vassert(0);
7095 assign(res, binop(op, zero, mkexpr(arg_m)));
7096 } else {
7097 switch (size) {
7098 case 0: op = Q ? Iop_CmpNEZ8x16 : Iop_CmpNEZ8x8; break;
7099 case 1: op = Q ? Iop_CmpNEZ16x8 : Iop_CmpNEZ16x4; break;
7100 case 2: op = Q ? Iop_CmpNEZ32x4 : Iop_CmpNEZ32x2; break;
7101 case 3: return False;
7102 default: vassert(0);
7104 assign(res, unop(Q ? Iop_NotV128 : Iop_Not64,
7105 unop(op, mkexpr(arg_m))));
7107 DIP("vceq.%c%d %c%u, %c%u, #0\n", F ? 'f' : 'i', 8 << size,
7108 Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', mreg);
7109 break;
7111 case 3: {
7112 /* VCLE #0 */
7113 IRExpr *zero;
7114 IROp op;
7115 if (Q) {
7116 zero = binop(Iop_64HLtoV128, mkU64(0), mkU64(0));
7117 } else {
7118 zero = mkU64(0);
7120 if (F) {
7121 switch (size) {
7122 case 0: case 1: case 3: return False;
7123 case 2: op = Q ? Iop_CmpGE32Fx4 : Iop_CmpGE32Fx2; break;
7124 default: vassert(0);
7126 assign(res, binop(op, zero, mkexpr(arg_m)));
7127 } else {
7128 switch (size) {
7129 case 0: op = Q ? Iop_CmpGT8Sx16 : Iop_CmpGT8Sx8; break;
7130 case 1: op = Q ? Iop_CmpGT16Sx8 : Iop_CmpGT16Sx4; break;
7131 case 2: op = Q ? Iop_CmpGT32Sx4 : Iop_CmpGT32Sx2; break;
7132 case 3: return False;
7133 default: vassert(0);
7135 assign(res, unop(Q ? Iop_NotV128 : Iop_Not64,
7136 binop(op, mkexpr(arg_m), zero)));
7138 DIP("vcle.%c%d %c%u, %c%u, #0\n", F ? 'f' : 's', 8 << size,
7139 Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', mreg);
7140 break;
7142 case 4: {
7143 /* VCLT #0 */
7144 IROp op;
7145 IRExpr *zero;
7146 if (Q) {
7147 zero = binop(Iop_64HLtoV128, mkU64(0), mkU64(0));
7148 } else {
7149 zero = mkU64(0);
7151 if (F) {
7152 switch (size) {
7153 case 0: case 1: case 3: return False;
7154 case 2: op = Q ? Iop_CmpGT32Fx4 : Iop_CmpGT32Fx2; break;
7155 default: vassert(0);
7157 assign(res, binop(op, zero, mkexpr(arg_m)));
7158 } else {
7159 switch (size) {
7160 case 0: op = Q ? Iop_CmpGT8Sx16 : Iop_CmpGT8Sx8; break;
7161 case 1: op = Q ? Iop_CmpGT16Sx8 : Iop_CmpGT16Sx4; break;
7162 case 2: op = Q ? Iop_CmpGT32Sx4 : Iop_CmpGT32Sx2; break;
7163 case 3: return False;
7164 default: vassert(0);
7166 assign(res, binop(op, zero, mkexpr(arg_m)));
7168 DIP("vclt.%c%d %c%u, %c%u, #0\n", F ? 'f' : 's', 8 << size,
7169 Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', mreg);
7170 break;
7172 case 5:
7173 return False;
7174 case 6: {
7175 /* VABS */
7176 if (!F) {
7177 IROp op;
7178 switch(size) {
7179 case 0: op = Q ? Iop_Abs8x16 : Iop_Abs8x8; break;
7180 case 1: op = Q ? Iop_Abs16x8 : Iop_Abs16x4; break;
7181 case 2: op = Q ? Iop_Abs32x4 : Iop_Abs32x2; break;
7182 case 3: return False;
7183 default: vassert(0);
7185 assign(res, unop(op, mkexpr(arg_m)));
7186 } else {
7187 assign(res, unop(Q ? Iop_Abs32Fx4 : Iop_Abs32Fx2,
7188 mkexpr(arg_m)));
7190 DIP("vabs.%c%d %c%u, %c%u\n",
7191 F ? 'f' : 's', 8 << size, Q ? 'q' : 'd', dreg,
7192 Q ? 'q' : 'd', mreg);
7193 break;
7195 case 7: {
7196 /* VNEG */
7197 IROp op;
7198 IRExpr *zero;
7199 if (F) {
7200 switch (size) {
7201 case 0: case 1: case 3: return False;
7202 case 2: op = Q ? Iop_Neg32Fx4 : Iop_Neg32Fx2; break;
7203 default: vassert(0);
7205 assign(res, unop(op, mkexpr(arg_m)));
7206 } else {
7207 if (Q) {
7208 zero = binop(Iop_64HLtoV128, mkU64(0), mkU64(0));
7209 } else {
7210 zero = mkU64(0);
7212 switch (size) {
7213 case 0: op = Q ? Iop_Sub8x16 : Iop_Sub8x8; break;
7214 case 1: op = Q ? Iop_Sub16x8 : Iop_Sub16x4; break;
7215 case 2: op = Q ? Iop_Sub32x4 : Iop_Sub32x2; break;
7216 case 3: return False;
7217 default: vassert(0);
7219 assign(res, binop(op, zero, mkexpr(arg_m)));
7221 DIP("vneg.%c%d %c%u, %c%u\n",
7222 F ? 'f' : 's', 8 << size, Q ? 'q' : 'd', dreg,
7223 Q ? 'q' : 'd', mreg);
7224 break;
7226 default:
7227 vassert(0);
7229 if (Q) {
7230 putQReg(dreg, mkexpr(res), condT);
7231 } else {
7232 putDRegI64(dreg, mkexpr(res), condT);
7234 return True;
7235 case 2:
7236 if ((B >> 1) == 0) {
7237 /* VSWP */
7238 if (Q) {
7239 arg_m = newTemp(Ity_V128);
7240 assign(arg_m, getQReg(mreg));
7241 putQReg(mreg, getQReg(dreg), condT);
7242 putQReg(dreg, mkexpr(arg_m), condT);
7243 } else {
7244 arg_m = newTemp(Ity_I64);
7245 assign(arg_m, getDRegI64(mreg));
7246 putDRegI64(mreg, getDRegI64(dreg), condT);
7247 putDRegI64(dreg, mkexpr(arg_m), condT);
7249 DIP("vswp %c%u, %c%u\n",
7250 Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', mreg);
7251 return True;
7252 } else if ((B >> 1) == 1) {
7253 /* VTRN */
7254 IROp op_odd = Iop_INVALID, op_even = Iop_INVALID;
7255 IRTemp old_m, old_d, new_d, new_m;
7256 if (Q) {
7257 old_m = newTemp(Ity_V128);
7258 old_d = newTemp(Ity_V128);
7259 new_m = newTemp(Ity_V128);
7260 new_d = newTemp(Ity_V128);
7261 assign(old_m, getQReg(mreg));
7262 assign(old_d, getQReg(dreg));
7263 } else {
7264 old_m = newTemp(Ity_I64);
7265 old_d = newTemp(Ity_I64);
7266 new_m = newTemp(Ity_I64);
7267 new_d = newTemp(Ity_I64);
7268 assign(old_m, getDRegI64(mreg));
7269 assign(old_d, getDRegI64(dreg));
7271 if (Q) {
7272 switch (size) {
7273 case 0:
7274 op_odd = Iop_InterleaveOddLanes8x16;
7275 op_even = Iop_InterleaveEvenLanes8x16;
7276 break;
7277 case 1:
7278 op_odd = Iop_InterleaveOddLanes16x8;
7279 op_even = Iop_InterleaveEvenLanes16x8;
7280 break;
7281 case 2:
7282 op_odd = Iop_InterleaveOddLanes32x4;
7283 op_even = Iop_InterleaveEvenLanes32x4;
7284 break;
7285 case 3:
7286 return False;
7287 default:
7288 vassert(0);
7290 } else {
7291 switch (size) {
7292 case 0:
7293 op_odd = Iop_InterleaveOddLanes8x8;
7294 op_even = Iop_InterleaveEvenLanes8x8;
7295 break;
7296 case 1:
7297 op_odd = Iop_InterleaveOddLanes16x4;
7298 op_even = Iop_InterleaveEvenLanes16x4;
7299 break;
7300 case 2:
7301 op_odd = Iop_InterleaveHI32x2;
7302 op_even = Iop_InterleaveLO32x2;
7303 break;
7304 case 3:
7305 return False;
7306 default:
7307 vassert(0);
7310 assign(new_d, binop(op_even, mkexpr(old_m), mkexpr(old_d)));
7311 assign(new_m, binop(op_odd, mkexpr(old_m), mkexpr(old_d)));
7312 if (Q) {
7313 putQReg(dreg, mkexpr(new_d), condT);
7314 putQReg(mreg, mkexpr(new_m), condT);
7315 } else {
7316 putDRegI64(dreg, mkexpr(new_d), condT);
7317 putDRegI64(mreg, mkexpr(new_m), condT);
7319 DIP("vtrn.%d %c%u, %c%u\n",
7320 8 << size, Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', mreg);
7321 return True;
7322 } else if ((B >> 1) == 2) {
7323 /* VUZP */
7324 IROp op_even, op_odd;
7325 IRTemp old_m, old_d, new_m, new_d;
7326 if (!Q && size == 2)
7327 return False;
7328 if (Q) {
7329 old_m = newTemp(Ity_V128);
7330 old_d = newTemp(Ity_V128);
7331 new_m = newTemp(Ity_V128);
7332 new_d = newTemp(Ity_V128);
7333 assign(old_m, getQReg(mreg));
7334 assign(old_d, getQReg(dreg));
7335 } else {
7336 old_m = newTemp(Ity_I64);
7337 old_d = newTemp(Ity_I64);
7338 new_m = newTemp(Ity_I64);
7339 new_d = newTemp(Ity_I64);
7340 assign(old_m, getDRegI64(mreg));
7341 assign(old_d, getDRegI64(dreg));
7343 switch (size) {
7344 case 0:
7345 op_odd = Q ? Iop_CatOddLanes8x16 : Iop_CatOddLanes8x8;
7346 op_even = Q ? Iop_CatEvenLanes8x16 : Iop_CatEvenLanes8x8;
7347 break;
7348 case 1:
7349 op_odd = Q ? Iop_CatOddLanes16x8 : Iop_CatOddLanes16x4;
7350 op_even = Q ? Iop_CatEvenLanes16x8 : Iop_CatEvenLanes16x4;
7351 break;
7352 case 2:
7353 op_odd = Iop_CatOddLanes32x4;
7354 op_even = Iop_CatEvenLanes32x4;
7355 break;
7356 case 3:
7357 return False;
7358 default:
7359 vassert(0);
7361 assign(new_d, binop(op_even, mkexpr(old_m), mkexpr(old_d)));
7362 assign(new_m, binop(op_odd, mkexpr(old_m), mkexpr(old_d)));
7363 if (Q) {
7364 putQReg(dreg, mkexpr(new_d), condT);
7365 putQReg(mreg, mkexpr(new_m), condT);
7366 } else {
7367 putDRegI64(dreg, mkexpr(new_d), condT);
7368 putDRegI64(mreg, mkexpr(new_m), condT);
7370 DIP("vuzp.%d %c%u, %c%u\n",
7371 8 << size, Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', mreg);
7372 return True;
7373 } else if ((B >> 1) == 3) {
7374 /* VZIP */
7375 IROp op_lo, op_hi;
7376 IRTemp old_m, old_d, new_m, new_d;
7377 if (!Q && size == 2)
7378 return False;
7379 if (Q) {
7380 old_m = newTemp(Ity_V128);
7381 old_d = newTemp(Ity_V128);
7382 new_m = newTemp(Ity_V128);
7383 new_d = newTemp(Ity_V128);
7384 assign(old_m, getQReg(mreg));
7385 assign(old_d, getQReg(dreg));
7386 } else {
7387 old_m = newTemp(Ity_I64);
7388 old_d = newTemp(Ity_I64);
7389 new_m = newTemp(Ity_I64);
7390 new_d = newTemp(Ity_I64);
7391 assign(old_m, getDRegI64(mreg));
7392 assign(old_d, getDRegI64(dreg));
7394 switch (size) {
7395 case 0:
7396 op_hi = Q ? Iop_InterleaveHI8x16 : Iop_InterleaveHI8x8;
7397 op_lo = Q ? Iop_InterleaveLO8x16 : Iop_InterleaveLO8x8;
7398 break;
7399 case 1:
7400 op_hi = Q ? Iop_InterleaveHI16x8 : Iop_InterleaveHI16x4;
7401 op_lo = Q ? Iop_InterleaveLO16x8 : Iop_InterleaveLO16x4;
7402 break;
7403 case 2:
7404 op_hi = Iop_InterleaveHI32x4;
7405 op_lo = Iop_InterleaveLO32x4;
7406 break;
7407 case 3:
7408 return False;
7409 default:
7410 vassert(0);
7412 assign(new_d, binop(op_lo, mkexpr(old_m), mkexpr(old_d)));
7413 assign(new_m, binop(op_hi, mkexpr(old_m), mkexpr(old_d)));
7414 if (Q) {
7415 putQReg(dreg, mkexpr(new_d), condT);
7416 putQReg(mreg, mkexpr(new_m), condT);
7417 } else {
7418 putDRegI64(dreg, mkexpr(new_d), condT);
7419 putDRegI64(mreg, mkexpr(new_m), condT);
7421 DIP("vzip.%d %c%u, %c%u\n",
7422 8 << size, Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', mreg);
7423 return True;
7424 } else if (B == 8) {
7425 /* VMOVN */
7426 IROp op;
7427 mreg >>= 1;
7428 switch (size) {
7429 case 0: op = Iop_NarrowUn16to8x8; break;
7430 case 1: op = Iop_NarrowUn32to16x4; break;
7431 case 2: op = Iop_NarrowUn64to32x2; break;
7432 case 3: return False;
7433 default: vassert(0);
7435 putDRegI64(dreg, unop(op, getQReg(mreg)), condT);
7436 DIP("vmovn.i%d d%u, q%u\n", 16 << size, dreg, mreg);
7437 return True;
7438 } else if (B == 9 || (B >> 1) == 5) {
7439 /* VQMOVN, VQMOVUN */
7440 IROp op, op2;
7441 IRTemp tmp;
7442 dreg = ((theInstr >> 18) & 0x10) | ((theInstr >> 12) & 0xF);
7443 mreg = ((theInstr >> 1) & 0x10) | (theInstr & 0xF);
7444 if (mreg & 1)
7445 return False;
7446 mreg >>= 1;
7447 switch (size) {
7448 case 0: op2 = Iop_NarrowUn16to8x8; break;
7449 case 1: op2 = Iop_NarrowUn32to16x4; break;
7450 case 2: op2 = Iop_NarrowUn64to32x2; break;
7451 case 3: return False;
7452 default: vassert(0);
7454 switch (B & 3) {
7455 case 0:
7456 vassert(0);
7457 case 1:
7458 switch (size) {
7459 case 0: op = Iop_QNarrowUn16Sto8Ux8; break;
7460 case 1: op = Iop_QNarrowUn32Sto16Ux4; break;
7461 case 2: op = Iop_QNarrowUn64Sto32Ux2; break;
7462 case 3: return False;
7463 default: vassert(0);
7465 DIP("vqmovun.s%d d%u, q%u\n", 16 << size, dreg, mreg);
7466 break;
7467 case 2:
7468 switch (size) {
7469 case 0: op = Iop_QNarrowUn16Sto8Sx8; break;
7470 case 1: op = Iop_QNarrowUn32Sto16Sx4; break;
7471 case 2: op = Iop_QNarrowUn64Sto32Sx2; break;
7472 case 3: return False;
7473 default: vassert(0);
7475 DIP("vqmovn.s%d d%u, q%u\n", 16 << size, dreg, mreg);
7476 break;
7477 case 3:
7478 switch (size) {
7479 case 0: op = Iop_QNarrowUn16Uto8Ux8; break;
7480 case 1: op = Iop_QNarrowUn32Uto16Ux4; break;
7481 case 2: op = Iop_QNarrowUn64Uto32Ux2; break;
7482 case 3: return False;
7483 default: vassert(0);
7485 DIP("vqmovn.u%d d%u, q%u\n", 16 << size, dreg, mreg);
7486 break;
7487 default:
7488 vassert(0);
7490 res = newTemp(Ity_I64);
7491 tmp = newTemp(Ity_I64);
7492 assign(res, unop(op, getQReg(mreg)));
7493 assign(tmp, unop(op2, getQReg(mreg)));
7494 setFlag_QC(mkexpr(res), mkexpr(tmp), False, condT);
7495 putDRegI64(dreg, mkexpr(res), condT);
7496 return True;
7497 } else if (B == 12) {
7498 /* VSHLL (maximum shift) */
7499 IROp op, cvt;
7500 UInt shift_imm;
7501 if (Q)
7502 return False;
7503 if (dreg & 1)
7504 return False;
7505 dreg >>= 1;
7506 shift_imm = 8 << size;
7507 res = newTemp(Ity_V128);
7508 switch (size) {
7509 case 0: op = Iop_ShlN16x8; cvt = Iop_Widen8Uto16x8; break;
7510 case 1: op = Iop_ShlN32x4; cvt = Iop_Widen16Uto32x4; break;
7511 case 2: op = Iop_ShlN64x2; cvt = Iop_Widen32Uto64x2; break;
7512 case 3: return False;
7513 default: vassert(0);
7515 assign(res, binop(op, unop(cvt, getDRegI64(mreg)),
7516 mkU8(shift_imm)));
7517 putQReg(dreg, mkexpr(res), condT);
7518 DIP("vshll.i%d q%u, d%u, #%d\n", 8 << size, dreg, mreg, 8 << size);
7519 return True;
7520 } else if ((B >> 3) == 3 && (B & 3) == 0) {
7521 /* VCVT (half<->single) */
7522 /* Half-precision extensions are needed to run this */
7523 vassert(0); // ATC
7524 if (((theInstr >> 18) & 3) != 1)
7525 return False;
7526 if ((theInstr >> 8) & 1) {
7527 if (dreg & 1)
7528 return False;
7529 dreg >>= 1;
7530 putQReg(dreg, unop(Iop_F16toF32x4, getDRegI64(mreg)),
7531 condT);
7532 DIP("vcvt.f32.f16 q%u, d%u\n", dreg, mreg);
7533 } else {
7534 if (mreg & 1)
7535 return False;
7536 mreg >>= 1;
7537 putDRegI64(dreg, unop(Iop_F32toF16x4, getQReg(mreg)),
7538 condT);
7539 DIP("vcvt.f16.f32 d%u, q%u\n", dreg, mreg);
7541 return True;
7542 } else {
7543 return False;
7545 vassert(0);
7546 return True;
7547 case 3:
7548 if (((B >> 1) & BITS4(1,1,0,1)) == BITS4(1,0,0,0)) {
7549 /* VRECPE */
7550 IROp op;
7551 F = (theInstr >> 8) & 1;
7552 if (size != 2)
7553 return False;
7554 if (Q) {
7555 op = F ? Iop_RecipEst32Fx4 : Iop_RecipEst32Ux4;
7556 putQReg(dreg, unop(op, getQReg(mreg)), condT);
7557 DIP("vrecpe.%c32 q%u, q%u\n", F ? 'f' : 'u', dreg, mreg);
7558 } else {
7559 op = F ? Iop_RecipEst32Fx2 : Iop_RecipEst32Ux2;
7560 putDRegI64(dreg, unop(op, getDRegI64(mreg)), condT);
7561 DIP("vrecpe.%c32 d%u, d%u\n", F ? 'f' : 'u', dreg, mreg);
7563 return True;
7564 } else if (((B >> 1) & BITS4(1,1,0,1)) == BITS4(1,0,0,1)) {
7565 /* VRSQRTE */
7566 IROp op;
7567 F = (B >> 2) & 1;
7568 if (size != 2)
7569 return False;
7570 if (F) {
7571 /* fp */
7572 op = Q ? Iop_RSqrtEst32Fx4 : Iop_RSqrtEst32Fx2;
7573 } else {
7574 /* unsigned int */
7575 op = Q ? Iop_RSqrtEst32Ux4 : Iop_RSqrtEst32Ux2;
7577 if (Q) {
7578 putQReg(dreg, unop(op, getQReg(mreg)), condT);
7579 DIP("vrsqrte.%c32 q%u, q%u\n", F ? 'f' : 'u', dreg, mreg);
7580 } else {
7581 putDRegI64(dreg, unop(op, getDRegI64(mreg)), condT);
7582 DIP("vrsqrte.%c32 d%u, d%u\n", F ? 'f' : 'u', dreg, mreg);
7584 return True;
7585 } else if ((B >> 3) == 3) {
7586 /* VCVT (fp<->integer) */
7587 IROp op;
7588 if (size != 2)
7589 return False;
7590 switch ((B >> 1) & 3) {
7591 case 0:
7592 op = Q ? Iop_I32StoFx4 : Iop_I32StoFx2;
7593 DIP("vcvt.f32.s32 %c%u, %c%u\n",
7594 Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', mreg);
7595 break;
7596 case 1:
7597 op = Q ? Iop_I32UtoFx4 : Iop_I32UtoFx2;
7598 DIP("vcvt.f32.u32 %c%u, %c%u\n",
7599 Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', mreg);
7600 break;
7601 case 2:
7602 op = Q ? Iop_FtoI32Sx4_RZ : Iop_FtoI32Sx2_RZ;
7603 DIP("vcvt.s32.f32 %c%u, %c%u\n",
7604 Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', mreg);
7605 break;
7606 case 3:
7607 op = Q ? Iop_FtoI32Ux4_RZ : Iop_FtoI32Ux2_RZ;
7608 DIP("vcvt.u32.f32 %c%u, %c%u\n",
7609 Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', mreg);
7610 break;
7611 default:
7612 vassert(0);
7614 if (Q) {
7615 putQReg(dreg, unop(op, getQReg(mreg)), condT);
7616 } else {
7617 putDRegI64(dreg, unop(op, getDRegI64(mreg)), condT);
7619 return True;
7620 } else {
7621 return False;
7623 vassert(0);
7624 return True;
7625 default:
7626 vassert(0);
7628 return False;
7631 /* A7.4.6 One register and a modified immediate value */
7632 static
7633 void ppNeonImm(UInt imm, UInt cmode, UInt op)
7635 int i;
7636 switch (cmode) {
7637 case 0: case 1: case 8: case 9:
7638 vex_printf("0x%x", imm);
7639 break;
7640 case 2: case 3: case 10: case 11:
7641 vex_printf("0x%x00", imm);
7642 break;
7643 case 4: case 5:
7644 vex_printf("0x%x0000", imm);
7645 break;
7646 case 6: case 7:
7647 vex_printf("0x%x000000", imm);
7648 break;
7649 case 12:
7650 vex_printf("0x%xff", imm);
7651 break;
7652 case 13:
7653 vex_printf("0x%xffff", imm);
7654 break;
7655 case 14:
7656 if (op) {
7657 vex_printf("0x");
7658 for (i = 7; i >= 0; i--)
7659 vex_printf("%s", (imm & (1 << i)) ? "ff" : "00");
7660 } else {
7661 vex_printf("0x%x", imm);
7663 break;
7664 case 15:
7665 vex_printf("0x%x", imm);
7666 break;
7670 static
7671 const char *ppNeonImmType(UInt cmode, UInt op)
7673 switch (cmode) {
7674 case 0 ... 7:
7675 case 12: case 13:
7676 return "i32";
7677 case 8 ... 11:
7678 return "i16";
7679 case 14:
7680 if (op)
7681 return "i64";
7682 else
7683 return "i8";
7684 case 15:
7685 if (op)
7686 vassert(0);
7687 else
7688 return "f32";
7689 default:
7690 vassert(0);
7694 static
7695 void DIPimm(UInt imm, UInt cmode, UInt op,
7696 const char *instr, UInt Q, UInt dreg)
7698 if (vex_traceflags & VEX_TRACE_FE) {
7699 vex_printf("%s.%s %c%u, #", instr,
7700 ppNeonImmType(cmode, op), Q ? 'q' : 'd', dreg);
7701 ppNeonImm(imm, cmode, op);
7702 vex_printf("\n");
7706 static
7707 Bool dis_neon_data_1reg_and_imm ( UInt theInstr, IRTemp condT )
7709 UInt dreg = get_neon_d_regno(theInstr);
7710 ULong imm_raw = ((theInstr >> 17) & 0x80) | ((theInstr >> 12) & 0x70) |
7711 (theInstr & 0xf);
7712 ULong imm_raw_pp = imm_raw;
7713 UInt cmode = (theInstr >> 8) & 0xf;
7714 UInt op_bit = (theInstr >> 5) & 1;
7715 ULong imm = 0;
7716 UInt Q = (theInstr >> 6) & 1;
7717 int i, j;
7718 UInt tmp;
7719 IRExpr *imm_val;
7720 IRExpr *expr;
7721 IRTemp tmp_var;
7722 switch(cmode) {
7723 case 7: case 6:
7724 imm_raw = imm_raw << 8;
7725 /* fallthrough */
7726 case 5: case 4:
7727 imm_raw = imm_raw << 8;
7728 /* fallthrough */
7729 case 3: case 2:
7730 imm_raw = imm_raw << 8;
7731 /* fallthrough */
7732 case 0: case 1:
7733 imm = (imm_raw << 32) | imm_raw;
7734 break;
7735 case 11: case 10:
7736 imm_raw = imm_raw << 8;
7737 /* fallthrough */
7738 case 9: case 8:
7739 imm_raw = (imm_raw << 16) | imm_raw;
7740 imm = (imm_raw << 32) | imm_raw;
7741 break;
7742 case 13:
7743 imm_raw = (imm_raw << 8) | 0xff;
7744 /* fallthrough */
7745 case 12:
7746 imm_raw = (imm_raw << 8) | 0xff;
7747 imm = (imm_raw << 32) | imm_raw;
7748 break;
7749 case 14:
7750 if (! op_bit) {
7751 for(i = 0; i < 8; i++) {
7752 imm = (imm << 8) | imm_raw;
7754 } else {
7755 for(i = 7; i >= 0; i--) {
7756 tmp = 0;
7757 for(j = 0; j < 8; j++) {
7758 tmp = (tmp << 1) | ((imm_raw >> i) & 1);
7760 imm = (imm << 8) | tmp;
7763 break;
7764 case 15:
7765 imm = (imm_raw & 0x80) << 5;
7766 imm |= ((~imm_raw & 0x40) << 5);
7767 for(i = 1; i <= 4; i++)
7768 imm |= (imm_raw & 0x40) << i;
7769 imm |= (imm_raw & 0x7f);
7770 imm = imm << 19;
7771 imm = (imm << 32) | imm;
7772 break;
7773 default:
7774 return False;
7776 if (Q) {
7777 imm_val = binop(Iop_64HLtoV128, mkU64(imm), mkU64(imm));
7778 } else {
7779 imm_val = mkU64(imm);
7781 if (((op_bit == 0) &&
7782 (((cmode & 9) == 0) || ((cmode & 13) == 8) || ((cmode & 12) == 12))) ||
7783 ((op_bit == 1) && (cmode == 14))) {
7784 /* VMOV (immediate) */
7785 if (Q) {
7786 putQReg(dreg, imm_val, condT);
7787 } else {
7788 putDRegI64(dreg, imm_val, condT);
7790 DIPimm(imm_raw_pp, cmode, op_bit, "vmov", Q, dreg);
7791 return True;
7793 if ((op_bit == 1) &&
7794 (((cmode & 9) == 0) || ((cmode & 13) == 8) || ((cmode & 14) == 12))) {
7795 /* VMVN (immediate) */
7796 if (Q) {
7797 putQReg(dreg, unop(Iop_NotV128, imm_val), condT);
7798 } else {
7799 putDRegI64(dreg, unop(Iop_Not64, imm_val), condT);
7801 DIPimm(imm_raw_pp, cmode, op_bit, "vmvn", Q, dreg);
7802 return True;
7804 if (Q) {
7805 tmp_var = newTemp(Ity_V128);
7806 assign(tmp_var, getQReg(dreg));
7807 } else {
7808 tmp_var = newTemp(Ity_I64);
7809 assign(tmp_var, getDRegI64(dreg));
7811 if ((op_bit == 0) && (((cmode & 9) == 1) || ((cmode & 13) == 9))) {
7812 /* VORR (immediate) */
7813 if (Q)
7814 expr = binop(Iop_OrV128, mkexpr(tmp_var), imm_val);
7815 else
7816 expr = binop(Iop_Or64, mkexpr(tmp_var), imm_val);
7817 DIPimm(imm_raw_pp, cmode, op_bit, "vorr", Q, dreg);
7818 } else if ((op_bit == 1) && (((cmode & 9) == 1) || ((cmode & 13) == 9))) {
7819 /* VBIC (immediate) */
7820 if (Q)
7821 expr = binop(Iop_AndV128, mkexpr(tmp_var),
7822 unop(Iop_NotV128, imm_val));
7823 else
7824 expr = binop(Iop_And64, mkexpr(tmp_var), unop(Iop_Not64, imm_val));
7825 DIPimm(imm_raw_pp, cmode, op_bit, "vbic", Q, dreg);
7826 } else {
7827 return False;
7829 if (Q)
7830 putQReg(dreg, expr, condT);
7831 else
7832 putDRegI64(dreg, expr, condT);
7833 return True;
7836 /* A7.4 Advanced SIMD data-processing instructions */
7837 static
7838 Bool dis_neon_data_processing ( UInt theInstr, IRTemp condT )
7840 UInt A = (theInstr >> 19) & 0x1F;
7841 UInt B = (theInstr >> 8) & 0xF;
7842 UInt C = (theInstr >> 4) & 0xF;
7843 UInt U = (theInstr >> 24) & 0x1;
7845 if (! (A & 0x10)) {
7846 return dis_neon_data_3same(theInstr, condT);
7848 if (((A & 0x17) == 0x10) && ((C & 0x9) == 0x1)) {
7849 return dis_neon_data_1reg_and_imm(theInstr, condT);
7851 if ((C & 1) == 1) {
7852 return dis_neon_data_2reg_and_shift(theInstr, condT);
7854 if (((C & 5) == 0) && (((A & 0x14) == 0x10) || ((A & 0x16) == 0x14))) {
7855 return dis_neon_data_3diff(theInstr, condT);
7857 if (((C & 5) == 4) && (((A & 0x14) == 0x10) || ((A & 0x16) == 0x14))) {
7858 return dis_neon_data_2reg_and_scalar(theInstr, condT);
7860 if ((A & 0x16) == 0x16) {
7861 if ((U == 0) && ((C & 1) == 0)) {
7862 return dis_neon_vext(theInstr, condT);
7864 if ((U != 1) || ((C & 1) == 1))
7865 return False;
7866 if ((B & 8) == 0) {
7867 return dis_neon_data_2reg_misc(theInstr, condT);
7869 if ((B & 12) == 8) {
7870 return dis_neon_vtb(theInstr, condT);
7872 if ((B == 12) && ((C & 9) == 0)) {
7873 return dis_neon_vdup(theInstr, condT);
7876 return False;
7880 /*------------------------------------------------------------*/
7881 /*--- NEON loads and stores ---*/
7882 /*------------------------------------------------------------*/
7884 /* For NEON memory operations, we use the standard scheme to handle
7885 conditionalisation: generate a jump around the instruction if the
7886 condition is false. That's only necessary in Thumb mode, however,
7887 since in ARM mode NEON instructions are unconditional. */
7889 /* A helper function for what follows. It assumes we already went
7890 uncond as per comments at the top of this section. */
7891 static
7892 void mk_neon_elem_load_to_one_lane( UInt rD, UInt inc, UInt index,
7893 UInt N, UInt size, IRTemp addr )
7895 UInt i;
7896 switch (size) {
7897 case 0:
7898 putDRegI64(rD, triop(Iop_SetElem8x8, getDRegI64(rD), mkU8(index),
7899 loadLE(Ity_I8, mkexpr(addr))), IRTemp_INVALID);
7900 break;
7901 case 1:
7902 putDRegI64(rD, triop(Iop_SetElem16x4, getDRegI64(rD), mkU8(index),
7903 loadLE(Ity_I16, mkexpr(addr))), IRTemp_INVALID);
7904 break;
7905 case 2:
7906 putDRegI64(rD, triop(Iop_SetElem32x2, getDRegI64(rD), mkU8(index),
7907 loadLE(Ity_I32, mkexpr(addr))), IRTemp_INVALID);
7908 break;
7909 default:
7910 vassert(0);
7912 for (i = 1; i <= N; i++) {
7913 switch (size) {
7914 case 0:
7915 putDRegI64(rD + i * inc,
7916 triop(Iop_SetElem8x8,
7917 getDRegI64(rD + i * inc),
7918 mkU8(index),
7919 loadLE(Ity_I8, binop(Iop_Add32,
7920 mkexpr(addr),
7921 mkU32(i * 1)))),
7922 IRTemp_INVALID);
7923 break;
7924 case 1:
7925 putDRegI64(rD + i * inc,
7926 triop(Iop_SetElem16x4,
7927 getDRegI64(rD + i * inc),
7928 mkU8(index),
7929 loadLE(Ity_I16, binop(Iop_Add32,
7930 mkexpr(addr),
7931 mkU32(i * 2)))),
7932 IRTemp_INVALID);
7933 break;
7934 case 2:
7935 putDRegI64(rD + i * inc,
7936 triop(Iop_SetElem32x2,
7937 getDRegI64(rD + i * inc),
7938 mkU8(index),
7939 loadLE(Ity_I32, binop(Iop_Add32,
7940 mkexpr(addr),
7941 mkU32(i * 4)))),
7942 IRTemp_INVALID);
7943 break;
7944 default:
7945 vassert(0);
7950 /* A(nother) helper function for what follows. It assumes we already
7951 went uncond as per comments at the top of this section. */
7952 static
7953 void mk_neon_elem_store_from_one_lane( UInt rD, UInt inc, UInt index,
7954 UInt N, UInt size, IRTemp addr )
7956 UInt i;
7957 switch (size) {
7958 case 0:
7959 storeLE(mkexpr(addr),
7960 binop(Iop_GetElem8x8, getDRegI64(rD), mkU8(index)));
7961 break;
7962 case 1:
7963 storeLE(mkexpr(addr),
7964 binop(Iop_GetElem16x4, getDRegI64(rD), mkU8(index)));
7965 break;
7966 case 2:
7967 storeLE(mkexpr(addr),
7968 binop(Iop_GetElem32x2, getDRegI64(rD), mkU8(index)));
7969 break;
7970 default:
7971 vassert(0);
7973 for (i = 1; i <= N; i++) {
7974 switch (size) {
7975 case 0:
7976 storeLE(binop(Iop_Add32, mkexpr(addr), mkU32(i * 1)),
7977 binop(Iop_GetElem8x8, getDRegI64(rD + i * inc),
7978 mkU8(index)));
7979 break;
7980 case 1:
7981 storeLE(binop(Iop_Add32, mkexpr(addr), mkU32(i * 2)),
7982 binop(Iop_GetElem16x4, getDRegI64(rD + i * inc),
7983 mkU8(index)));
7984 break;
7985 case 2:
7986 storeLE(binop(Iop_Add32, mkexpr(addr), mkU32(i * 4)),
7987 binop(Iop_GetElem32x2, getDRegI64(rD + i * inc),
7988 mkU8(index)));
7989 break;
7990 default:
7991 vassert(0);
7996 /* Generate 2x64 -> 2x64 deinterleave code, for VLD2. Caller must
7997 make *u0 and *u1 be valid IRTemps before the call. */
7998 static void math_DEINTERLEAVE_2 (/*OUT*/IRTemp* u0, /*OUT*/IRTemp* u1,
7999 IRTemp i0, IRTemp i1, Int laneszB)
8001 /* The following assumes that the guest is little endian, and hence
8002 that the memory-side (interleaved) data is stored
8003 little-endianly. */
8004 vassert(u0 && u1);
8005 /* This is pretty easy, since we have primitives directly to
8006 hand. */
8007 if (laneszB == 4) {
8008 // memLE(128 bits) == A0 B0 A1 B1
8009 // i0 == B0 A0, i1 == B1 A1
8010 // u0 == A1 A0, u1 == B1 B0
8011 assign(*u0, binop(Iop_InterleaveLO32x2, mkexpr(i1), mkexpr(i0)));
8012 assign(*u1, binop(Iop_InterleaveHI32x2, mkexpr(i1), mkexpr(i0)));
8013 } else if (laneszB == 2) {
8014 // memLE(128 bits) == A0 B0 A1 B1 A2 B2 A3 B3
8015 // i0 == B1 A1 B0 A0, i1 == B3 A3 B2 A2
8016 // u0 == A3 A2 A1 A0, u1 == B3 B2 B1 B0
8017 assign(*u0, binop(Iop_CatEvenLanes16x4, mkexpr(i1), mkexpr(i0)));
8018 assign(*u1, binop(Iop_CatOddLanes16x4, mkexpr(i1), mkexpr(i0)));
8019 } else if (laneszB == 1) {
8020 // memLE(128 bits) == A0 B0 A1 B1 A2 B2 A3 B3 A4 B4 A5 B5 A6 B6 A7 B7
8021 // i0 == B3 A3 B2 A2 B1 A1 B0 A0, i1 == B7 A7 B6 A6 B5 A5 B4 A4
8022 // u0 == A7 A6 A5 A4 A3 A2 A1 A0, u1 == B7 B6 B5 B4 B3 B2 B1 B0
8023 assign(*u0, binop(Iop_CatEvenLanes8x8, mkexpr(i1), mkexpr(i0)));
8024 assign(*u1, binop(Iop_CatOddLanes8x8, mkexpr(i1), mkexpr(i0)));
8025 } else {
8026 // Can never happen, since VLD2 only has valid lane widths of 32,
8027 // 16 or 8 bits.
8028 vpanic("math_DEINTERLEAVE_2");
8032 /* Generate 2x64 -> 2x64 interleave code, for VST2. Caller must make
8033 *u0 and *u1 be valid IRTemps before the call. */
8034 static void math_INTERLEAVE_2 (/*OUT*/IRTemp* i0, /*OUT*/IRTemp* i1,
8035 IRTemp u0, IRTemp u1, Int laneszB)
8037 /* The following assumes that the guest is little endian, and hence
8038 that the memory-side (interleaved) data is stored
8039 little-endianly. */
8040 vassert(i0 && i1);
8041 /* This is pretty easy, since we have primitives directly to
8042 hand. */
8043 if (laneszB == 4) {
8044 // memLE(128 bits) == A0 B0 A1 B1
8045 // i0 == B0 A0, i1 == B1 A1
8046 // u0 == A1 A0, u1 == B1 B0
8047 assign(*i0, binop(Iop_InterleaveLO32x2, mkexpr(u1), mkexpr(u0)));
8048 assign(*i1, binop(Iop_InterleaveHI32x2, mkexpr(u1), mkexpr(u0)));
8049 } else if (laneszB == 2) {
8050 // memLE(128 bits) == A0 B0 A1 B1 A2 B2 A3 B3
8051 // i0 == B1 A1 B0 A0, i1 == B3 A3 B2 A2
8052 // u0 == A3 A2 A1 A0, u1 == B3 B2 B1 B0
8053 assign(*i0, binop(Iop_InterleaveLO16x4, mkexpr(u1), mkexpr(u0)));
8054 assign(*i1, binop(Iop_InterleaveHI16x4, mkexpr(u1), mkexpr(u0)));
8055 } else if (laneszB == 1) {
8056 // memLE(128 bits) == A0 B0 A1 B1 A2 B2 A3 B3 A4 B4 A5 B5 A6 B6 A7 B7
8057 // i0 == B3 A3 B2 A2 B1 A1 B0 A0, i1 == B7 A7 B6 A6 B5 A5 B4 A4
8058 // u0 == A7 A6 A5 A4 A3 A2 A1 A0, u1 == B7 B6 B5 B4 B3 B2 B1 B0
8059 assign(*i0, binop(Iop_InterleaveLO8x8, mkexpr(u1), mkexpr(u0)));
8060 assign(*i1, binop(Iop_InterleaveHI8x8, mkexpr(u1), mkexpr(u0)));
8061 } else {
8062 // Can never happen, since VST2 only has valid lane widths of 32,
8063 // 16 or 8 bits.
8064 vpanic("math_INTERLEAVE_2");
8068 // Helper function for generating arbitrary slicing 'n' dicing of
8069 // 3 8x8 vectors, as needed for VLD3.8 and VST3.8.
8070 static IRExpr* math_PERM_8x8x3(const UChar* desc,
8071 IRTemp s0, IRTemp s1, IRTemp s2)
8073 // desc is an array of 8 pairs, encoded as 16 bytes,
8074 // that describe how to assemble the result lanes, starting with
8075 // lane 7. Each pair is: first component (0..2) says which of
8076 // s0/s1/s2 to use. Second component (0..7) is the lane number
8077 // in the source to use.
8078 UInt si;
8079 for (si = 0; si < 7; si++) {
8080 vassert(desc[2 * si + 0] <= 2);
8081 vassert(desc[2 * si + 1] <= 7);
8083 IRTemp h3 = newTemp(Ity_I64);
8084 IRTemp h2 = newTemp(Ity_I64);
8085 IRTemp h1 = newTemp(Ity_I64);
8086 IRTemp h0 = newTemp(Ity_I64);
8087 IRTemp srcs[3] = {s0, s1, s2};
8088 # define SRC_VEC(_lane) mkexpr(srcs[desc[2 * (7-(_lane)) + 0]])
8089 # define SRC_SHIFT(_lane) mkU8(56-8*(desc[2 * (7-(_lane)) + 1]))
8090 assign(h3, binop(Iop_InterleaveHI8x8,
8091 binop(Iop_Shl64, SRC_VEC(7), SRC_SHIFT(7)),
8092 binop(Iop_Shl64, SRC_VEC(6), SRC_SHIFT(6))));
8093 assign(h2, binop(Iop_InterleaveHI8x8,
8094 binop(Iop_Shl64, SRC_VEC(5), SRC_SHIFT(5)),
8095 binop(Iop_Shl64, SRC_VEC(4), SRC_SHIFT(4))));
8096 assign(h1, binop(Iop_InterleaveHI8x8,
8097 binop(Iop_Shl64, SRC_VEC(3), SRC_SHIFT(3)),
8098 binop(Iop_Shl64, SRC_VEC(2), SRC_SHIFT(2))));
8099 assign(h0, binop(Iop_InterleaveHI8x8,
8100 binop(Iop_Shl64, SRC_VEC(1), SRC_SHIFT(1)),
8101 binop(Iop_Shl64, SRC_VEC(0), SRC_SHIFT(0))));
8102 # undef SRC_VEC
8103 # undef SRC_SHIFT
8104 // Now h3..h0 are 64 bit vectors with useful information only
8105 // in the top 16 bits. We now concatentate those four 16-bit
8106 // groups so as to produce the final result.
8107 IRTemp w1 = newTemp(Ity_I64);
8108 IRTemp w0 = newTemp(Ity_I64);
8109 assign(w1, binop(Iop_InterleaveHI16x4, mkexpr(h3), mkexpr(h2)));
8110 assign(w0, binop(Iop_InterleaveHI16x4, mkexpr(h1), mkexpr(h0)));
8111 return binop(Iop_InterleaveHI32x2, mkexpr(w1), mkexpr(w0));
8114 /* Generate 3x64 -> 3x64 deinterleave code, for VLD3. Caller must
8115 make *u0, *u1 and *u2 be valid IRTemps before the call. */
8116 static void math_DEINTERLEAVE_3 (
8117 /*OUT*/IRTemp* u0, /*OUT*/IRTemp* u1, /*OUT*/IRTemp* u2,
8118 IRTemp i0, IRTemp i1, IRTemp i2, Int laneszB
8121 # define IHI32x2(_e1, _e2) binop(Iop_InterleaveHI32x2, (_e1), (_e2))
8122 # define IHI16x4(_e1, _e2) binop(Iop_InterleaveHI16x4, (_e1), (_e2))
8123 # define SHL64(_tmp, _amt) binop(Iop_Shl64, mkexpr(_tmp), mkU8(_amt))
8124 /* The following assumes that the guest is little endian, and hence
8125 that the memory-side (interleaved) data is stored
8126 little-endianly. */
8127 vassert(u0 && u1 && u2);
8128 if (laneszB == 4) {
8129 // memLE(192 bits) == A0 B0 C0 A1 B1 C1
8130 // i0 == B0 A0, i1 == A1 C0, i2 == C1 B1
8131 // u0 == A1 A0, u1 == B1 B0, u2 == C1 C0
8132 assign(*u0, IHI32x2(SHL64(i1, 0), SHL64(i0, 32)));
8133 assign(*u1, IHI32x2(SHL64(i2, 32), SHL64(i0, 0)));
8134 assign(*u2, IHI32x2(SHL64(i2, 0), SHL64(i1, 32)));
8135 } else if (laneszB == 2) {
8136 // memLE(192 bits) == A0 B0 C0 A1, B1 C1 A2 B2, C2 A3 B3 C3
8137 // i0 == A1 C0 B0 A0, i1 == B2 A2 C1 B1, i2 == C3 B3 A3 C2
8138 // u0 == A3 A2 A1 A0, u1 == B3 B2 B1 B0, u2 == C3 C2 C1 C0
8139 # define XXX(_tmp3,_la3,_tmp2,_la2,_tmp1,_la1,_tmp0,_la0) \
8140 IHI32x2( \
8141 IHI16x4(SHL64((_tmp3),48-16*(_la3)), \
8142 SHL64((_tmp2),48-16*(_la2))), \
8143 IHI16x4(SHL64((_tmp1),48-16*(_la1)), \
8144 SHL64((_tmp0),48-16*(_la0))))
8145 assign(*u0, XXX(i2,1, i1,2, i0,3, i0,0));
8146 assign(*u1, XXX(i2,2, i1,3, i1,0, i0,1));
8147 assign(*u2, XXX(i2,3, i2,0, i1,1, i0,2));
8148 # undef XXX
8149 } else if (laneszB == 1) {
8150 // These describe how the result vectors [7..0] are
8151 // assembled from the source vectors. Each pair is
8152 // (source vector number, lane number).
8153 static const UChar de0[16] = {2,5, 2,2, 1,7, 1,4, 1,1, 0,6, 0,3, 0,0};
8154 static const UChar de1[16] = {2,6, 2,3, 2,0, 1,5, 1,2, 0,7, 0,4, 0,1};
8155 static const UChar de2[16] = {2,7, 2,4, 2,1, 1,6, 1,3, 1,0, 0,5, 0,2};
8156 assign(*u0, math_PERM_8x8x3(de0, i0, i1, i2));
8157 assign(*u1, math_PERM_8x8x3(de1, i0, i1, i2));
8158 assign(*u2, math_PERM_8x8x3(de2, i0, i1, i2));
8159 } else {
8160 // Can never happen, since VLD3 only has valid lane widths of 32,
8161 // 16 or 8 bits.
8162 vpanic("math_DEINTERLEAVE_3");
8164 # undef SHL64
8165 # undef IHI16x4
8166 # undef IHI32x2
8169 /* Generate 3x64 -> 3x64 interleave code, for VST3. Caller must
8170 make *i0, *i1 and *i2 be valid IRTemps before the call. */
8171 static void math_INTERLEAVE_3 (
8172 /*OUT*/IRTemp* i0, /*OUT*/IRTemp* i1, /*OUT*/IRTemp* i2,
8173 IRTemp u0, IRTemp u1, IRTemp u2, Int laneszB
8176 # define IHI32x2(_e1, _e2) binop(Iop_InterleaveHI32x2, (_e1), (_e2))
8177 # define IHI16x4(_e1, _e2) binop(Iop_InterleaveHI16x4, (_e1), (_e2))
8178 # define SHL64(_tmp, _amt) binop(Iop_Shl64, mkexpr(_tmp), mkU8(_amt))
8179 /* The following assumes that the guest is little endian, and hence
8180 that the memory-side (interleaved) data is stored
8181 little-endianly. */
8182 vassert(i0 && i1 && i2);
8183 if (laneszB == 4) {
8184 // memLE(192 bits) == A0 B0 C0 A1 B1 C1
8185 // i0 == B0 A0, i1 == A1 C0, i2 == C1 B1
8186 // u0 == A1 A0, u1 == B1 B0, u2 == C1 C0
8187 assign(*i0, IHI32x2(SHL64(u1, 32), SHL64(u0, 32)));
8188 assign(*i1, IHI32x2(SHL64(u0, 0), SHL64(u2, 32)));
8189 assign(*i2, IHI32x2(SHL64(u2, 0), SHL64(u1, 0)));
8190 } else if (laneszB == 2) {
8191 // memLE(192 bits) == A0 B0 C0 A1, B1 C1 A2 B2, C2 A3 B3 C3
8192 // i0 == A1 C0 B0 A0, i1 == B2 A2 C1 B1, i2 == C3 B3 A3 C2
8193 // u0 == A3 A2 A1 A0, u1 == B3 B2 B1 B0, u2 == C3 C2 C1 C0
8194 # define XXX(_tmp3,_la3,_tmp2,_la2,_tmp1,_la1,_tmp0,_la0) \
8195 IHI32x2( \
8196 IHI16x4(SHL64((_tmp3),48-16*(_la3)), \
8197 SHL64((_tmp2),48-16*(_la2))), \
8198 IHI16x4(SHL64((_tmp1),48-16*(_la1)), \
8199 SHL64((_tmp0),48-16*(_la0))))
8200 assign(*i0, XXX(u0,1, u2,0, u1,0, u0,0));
8201 assign(*i1, XXX(u1,2, u0,2, u2,1, u1,1));
8202 assign(*i2, XXX(u2,3, u1,3, u0,3, u2,2));
8203 # undef XXX
8204 } else if (laneszB == 1) {
8205 // These describe how the result vectors [7..0] are
8206 // assembled from the source vectors. Each pair is
8207 // (source vector number, lane number).
8208 static const UChar in0[16] = {1,2, 0,2, 2,1, 1,1, 0,1, 2,0, 1,0, 0,0};
8209 static const UChar in1[16] = {0,5, 2,4, 1,4, 0,4, 2,3, 1,3, 0,3, 2,2};
8210 static const UChar in2[16] = {2,7, 1,7, 0,7, 2,6, 1,6, 0,6, 2,5, 1,5};
8211 assign(*i0, math_PERM_8x8x3(in0, u0, u1, u2));
8212 assign(*i1, math_PERM_8x8x3(in1, u0, u1, u2));
8213 assign(*i2, math_PERM_8x8x3(in2, u0, u1, u2));
8214 } else {
8215 // Can never happen, since VST3 only has valid lane widths of 32,
8216 // 16 or 8 bits.
8217 vpanic("math_INTERLEAVE_3");
8219 # undef SHL64
8220 # undef IHI16x4
8221 # undef IHI32x2
8224 /* Generate 4x64 -> 4x64 deinterleave code, for VLD4. Caller must
8225 make *u0, *u1, *u2 and *u3 be valid IRTemps before the call. */
8226 static void math_DEINTERLEAVE_4 (
8227 /*OUT*/IRTemp* u0, /*OUT*/IRTemp* u1,
8228 /*OUT*/IRTemp* u2, /*OUT*/IRTemp* u3,
8229 IRTemp i0, IRTemp i1, IRTemp i2, IRTemp i3, Int laneszB
8232 # define IHI32x2(_t1, _t2) \
8233 binop(Iop_InterleaveHI32x2, mkexpr(_t1), mkexpr(_t2))
8234 # define ILO32x2(_t1, _t2) \
8235 binop(Iop_InterleaveLO32x2, mkexpr(_t1), mkexpr(_t2))
8236 # define IHI16x4(_t1, _t2) \
8237 binop(Iop_InterleaveHI16x4, mkexpr(_t1), mkexpr(_t2))
8238 # define ILO16x4(_t1, _t2) \
8239 binop(Iop_InterleaveLO16x4, mkexpr(_t1), mkexpr(_t2))
8240 # define IHI8x8(_t1, _e2) \
8241 binop(Iop_InterleaveHI8x8, mkexpr(_t1), _e2)
8242 # define SHL64(_tmp, _amt) \
8243 binop(Iop_Shl64, mkexpr(_tmp), mkU8(_amt))
8244 /* The following assumes that the guest is little endian, and hence
8245 that the memory-side (interleaved) data is stored
8246 little-endianly. */
8247 vassert(u0 && u1 && u2 && u3);
8248 if (laneszB == 4) {
8249 assign(*u0, ILO32x2(i2, i0));
8250 assign(*u1, IHI32x2(i2, i0));
8251 assign(*u2, ILO32x2(i3, i1));
8252 assign(*u3, IHI32x2(i3, i1));
8253 } else if (laneszB == 2) {
8254 IRTemp b1b0a1a0 = newTemp(Ity_I64);
8255 IRTemp b3b2a3a2 = newTemp(Ity_I64);
8256 IRTemp d1d0c1c0 = newTemp(Ity_I64);
8257 IRTemp d3d2c3c2 = newTemp(Ity_I64);
8258 assign(b1b0a1a0, ILO16x4(i1, i0));
8259 assign(b3b2a3a2, ILO16x4(i3, i2));
8260 assign(d1d0c1c0, IHI16x4(i1, i0));
8261 assign(d3d2c3c2, IHI16x4(i3, i2));
8262 // And now do what we did for the 32-bit case.
8263 assign(*u0, ILO32x2(b3b2a3a2, b1b0a1a0));
8264 assign(*u1, IHI32x2(b3b2a3a2, b1b0a1a0));
8265 assign(*u2, ILO32x2(d3d2c3c2, d1d0c1c0));
8266 assign(*u3, IHI32x2(d3d2c3c2, d1d0c1c0));
8267 } else if (laneszB == 1) {
8268 // Deinterleave into 16-bit chunks, then do as the 16-bit case.
8269 IRTemp i0x = newTemp(Ity_I64);
8270 IRTemp i1x = newTemp(Ity_I64);
8271 IRTemp i2x = newTemp(Ity_I64);
8272 IRTemp i3x = newTemp(Ity_I64);
8273 assign(i0x, IHI8x8(i0, SHL64(i0, 32)));
8274 assign(i1x, IHI8x8(i1, SHL64(i1, 32)));
8275 assign(i2x, IHI8x8(i2, SHL64(i2, 32)));
8276 assign(i3x, IHI8x8(i3, SHL64(i3, 32)));
8277 // From here on is like the 16 bit case.
8278 IRTemp b1b0a1a0 = newTemp(Ity_I64);
8279 IRTemp b3b2a3a2 = newTemp(Ity_I64);
8280 IRTemp d1d0c1c0 = newTemp(Ity_I64);
8281 IRTemp d3d2c3c2 = newTemp(Ity_I64);
8282 assign(b1b0a1a0, ILO16x4(i1x, i0x));
8283 assign(b3b2a3a2, ILO16x4(i3x, i2x));
8284 assign(d1d0c1c0, IHI16x4(i1x, i0x));
8285 assign(d3d2c3c2, IHI16x4(i3x, i2x));
8286 // And now do what we did for the 32-bit case.
8287 assign(*u0, ILO32x2(b3b2a3a2, b1b0a1a0));
8288 assign(*u1, IHI32x2(b3b2a3a2, b1b0a1a0));
8289 assign(*u2, ILO32x2(d3d2c3c2, d1d0c1c0));
8290 assign(*u3, IHI32x2(d3d2c3c2, d1d0c1c0));
8291 } else {
8292 // Can never happen, since VLD4 only has valid lane widths of 32,
8293 // 16 or 8 bits.
8294 vpanic("math_DEINTERLEAVE_4");
8296 # undef SHL64
8297 # undef IHI8x8
8298 # undef ILO16x4
8299 # undef IHI16x4
8300 # undef ILO32x2
8301 # undef IHI32x2
8304 /* Generate 4x64 -> 4x64 interleave code, for VST4. Caller must
8305 make *i0, *i1, *i2 and *i3 be valid IRTemps before the call. */
8306 static void math_INTERLEAVE_4 (
8307 /*OUT*/IRTemp* i0, /*OUT*/IRTemp* i1,
8308 /*OUT*/IRTemp* i2, /*OUT*/IRTemp* i3,
8309 IRTemp u0, IRTemp u1, IRTemp u2, IRTemp u3, Int laneszB
8312 # define IHI32x2(_t1, _t2) \
8313 binop(Iop_InterleaveHI32x2, mkexpr(_t1), mkexpr(_t2))
8314 # define ILO32x2(_t1, _t2) \
8315 binop(Iop_InterleaveLO32x2, mkexpr(_t1), mkexpr(_t2))
8316 # define CEV16x4(_t1, _t2) \
8317 binop(Iop_CatEvenLanes16x4, mkexpr(_t1), mkexpr(_t2))
8318 # define COD16x4(_t1, _t2) \
8319 binop(Iop_CatOddLanes16x4, mkexpr(_t1), mkexpr(_t2))
8320 # define COD8x8(_t1, _e2) \
8321 binop(Iop_CatOddLanes8x8, mkexpr(_t1), _e2)
8322 # define SHL64(_tmp, _amt) \
8323 binop(Iop_Shl64, mkexpr(_tmp), mkU8(_amt))
8324 /* The following assumes that the guest is little endian, and hence
8325 that the memory-side (interleaved) data is stored
8326 little-endianly. */
8327 vassert(u0 && u1 && u2 && u3);
8328 if (laneszB == 4) {
8329 assign(*i0, ILO32x2(u1, u0));
8330 assign(*i1, ILO32x2(u3, u2));
8331 assign(*i2, IHI32x2(u1, u0));
8332 assign(*i3, IHI32x2(u3, u2));
8333 } else if (laneszB == 2) {
8334 // First, interleave at the 32-bit lane size.
8335 IRTemp b1b0a1a0 = newTemp(Ity_I64);
8336 IRTemp b3b2a3a2 = newTemp(Ity_I64);
8337 IRTemp d1d0c1c0 = newTemp(Ity_I64);
8338 IRTemp d3d2c3c2 = newTemp(Ity_I64);
8339 assign(b1b0a1a0, ILO32x2(u1, u0));
8340 assign(b3b2a3a2, IHI32x2(u1, u0));
8341 assign(d1d0c1c0, ILO32x2(u3, u2));
8342 assign(d3d2c3c2, IHI32x2(u3, u2));
8343 // And interleave (cat) at the 16 bit size.
8344 assign(*i0, CEV16x4(d1d0c1c0, b1b0a1a0));
8345 assign(*i1, COD16x4(d1d0c1c0, b1b0a1a0));
8346 assign(*i2, CEV16x4(d3d2c3c2, b3b2a3a2));
8347 assign(*i3, COD16x4(d3d2c3c2, b3b2a3a2));
8348 } else if (laneszB == 1) {
8349 // First, interleave at the 32-bit lane size.
8350 IRTemp b1b0a1a0 = newTemp(Ity_I64);
8351 IRTemp b3b2a3a2 = newTemp(Ity_I64);
8352 IRTemp d1d0c1c0 = newTemp(Ity_I64);
8353 IRTemp d3d2c3c2 = newTemp(Ity_I64);
8354 assign(b1b0a1a0, ILO32x2(u1, u0));
8355 assign(b3b2a3a2, IHI32x2(u1, u0));
8356 assign(d1d0c1c0, ILO32x2(u3, u2));
8357 assign(d3d2c3c2, IHI32x2(u3, u2));
8358 // And interleave (cat) at the 16 bit size.
8359 IRTemp i0x = newTemp(Ity_I64);
8360 IRTemp i1x = newTemp(Ity_I64);
8361 IRTemp i2x = newTemp(Ity_I64);
8362 IRTemp i3x = newTemp(Ity_I64);
8363 assign(i0x, CEV16x4(d1d0c1c0, b1b0a1a0));
8364 assign(i1x, COD16x4(d1d0c1c0, b1b0a1a0));
8365 assign(i2x, CEV16x4(d3d2c3c2, b3b2a3a2));
8366 assign(i3x, COD16x4(d3d2c3c2, b3b2a3a2));
8367 // And rearrange within each word, to get the right 8 bit lanes.
8368 assign(*i0, COD8x8(i0x, SHL64(i0x, 8)));
8369 assign(*i1, COD8x8(i1x, SHL64(i1x, 8)));
8370 assign(*i2, COD8x8(i2x, SHL64(i2x, 8)));
8371 assign(*i3, COD8x8(i3x, SHL64(i3x, 8)));
8372 } else {
8373 // Can never happen, since VLD4 only has valid lane widths of 32,
8374 // 16 or 8 bits.
8375 vpanic("math_DEINTERLEAVE_4");
8377 # undef SHL64
8378 # undef COD8x8
8379 # undef COD16x4
8380 # undef CEV16x4
8381 # undef ILO32x2
8382 # undef IHI32x2
8385 /* A7.7 Advanced SIMD element or structure load/store instructions */
8386 static
8387 Bool dis_neon_load_or_store ( UInt theInstr,
8388 Bool isT, IRTemp condT )
8390 # define INSN(_bMax,_bMin) SLICE_UInt(theInstr, (_bMax), (_bMin))
8391 UInt bA = INSN(23,23);
8392 UInt fB = INSN(11,8);
8393 UInt bL = INSN(21,21);
8394 UInt rD = (INSN(22,22) << 4) | INSN(15,12);
8395 UInt rN = INSN(19,16);
8396 UInt rM = INSN(3,0);
8397 UInt N, size, i, j;
8398 UInt inc;
8399 UInt regs = 1;
8401 if (isT) {
8402 vassert(condT != IRTemp_INVALID);
8403 } else {
8404 vassert(condT == IRTemp_INVALID);
8406 /* So now, if condT is not IRTemp_INVALID, we know we're
8407 dealing with Thumb code. */
8409 if (INSN(20,20) != 0)
8410 return False;
8412 IRTemp initialRn = newTemp(Ity_I32);
8413 assign(initialRn, isT ? getIRegT(rN) : getIRegA(rN));
8415 IRTemp initialRm = newTemp(Ity_I32);
8416 assign(initialRm, isT ? getIRegT(rM) : getIRegA(rM));
8418 /* There are 3 cases:
8419 (1) VSTn / VLDn (n-element structure from/to one lane)
8420 (2) VLDn (single element to all lanes)
8421 (3) VSTn / VLDn (multiple n-element structures)
8423 if (bA) {
8424 N = fB & 3;
8425 if ((fB >> 2) < 3) {
8426 /* ------------ Case (1) ------------
8427 VSTn / VLDn (n-element structure from/to one lane) */
8429 size = fB >> 2;
8431 switch (size) {
8432 case 0: i = INSN(7,5); inc = 1; break;
8433 case 1: i = INSN(7,6); inc = INSN(5,5) ? 2 : 1; break;
8434 case 2: i = INSN(7,7); inc = INSN(6,6) ? 2 : 1; break;
8435 case 3: return False;
8436 default: vassert(0);
8439 IRTemp addr = newTemp(Ity_I32);
8440 assign(addr, mkexpr(initialRn));
8442 // go uncond
8443 if (condT != IRTemp_INVALID)
8444 mk_skip_over_T32_if_cond_is_false(condT);
8445 // now uncond
8447 if (bL)
8448 mk_neon_elem_load_to_one_lane(rD, inc, i, N, size, addr);
8449 else
8450 mk_neon_elem_store_from_one_lane(rD, inc, i, N, size, addr);
8451 DIP("v%s%u.%d {", bL ? "ld" : "st", N + 1, 8 << size);
8452 for (j = 0; j <= N; j++) {
8453 if (j)
8454 DIP(", ");
8455 DIP("d%u[%u]", rD + j * inc, i);
8457 DIP("}, [r%u]", rN);
8458 if (rM != 13 && rM != 15) {
8459 DIP(", r%u\n", rM);
8460 } else {
8461 DIP("%s\n", (rM != 15) ? "!" : "");
8463 } else {
8464 /* ------------ Case (2) ------------
8465 VLDn (single element to all lanes) */
8466 UInt r;
8467 if (bL == 0)
8468 return False;
8470 inc = INSN(5,5) + 1;
8471 size = INSN(7,6);
8473 /* size == 3 and size == 2 cases differ in alignment constraints */
8474 if (size == 3 && N == 3 && INSN(4,4) == 1)
8475 size = 2;
8477 if (size == 0 && N == 0 && INSN(4,4) == 1)
8478 return False;
8479 if (N == 2 && INSN(4,4) == 1)
8480 return False;
8481 if (size == 3)
8482 return False;
8484 // go uncond
8485 if (condT != IRTemp_INVALID)
8486 mk_skip_over_T32_if_cond_is_false(condT);
8487 // now uncond
8489 IRTemp addr = newTemp(Ity_I32);
8490 assign(addr, mkexpr(initialRn));
8492 if (N == 0 && INSN(5,5))
8493 regs = 2;
8495 for (r = 0; r < regs; r++) {
8496 switch (size) {
8497 case 0:
8498 putDRegI64(rD + r, unop(Iop_Dup8x8,
8499 loadLE(Ity_I8, mkexpr(addr))),
8500 IRTemp_INVALID);
8501 break;
8502 case 1:
8503 putDRegI64(rD + r, unop(Iop_Dup16x4,
8504 loadLE(Ity_I16, mkexpr(addr))),
8505 IRTemp_INVALID);
8506 break;
8507 case 2:
8508 putDRegI64(rD + r, unop(Iop_Dup32x2,
8509 loadLE(Ity_I32, mkexpr(addr))),
8510 IRTemp_INVALID);
8511 break;
8512 default:
8513 vassert(0);
8515 for (i = 1; i <= N; i++) {
8516 switch (size) {
8517 case 0:
8518 putDRegI64(rD + r + i * inc,
8519 unop(Iop_Dup8x8,
8520 loadLE(Ity_I8, binop(Iop_Add32,
8521 mkexpr(addr),
8522 mkU32(i * 1)))),
8523 IRTemp_INVALID);
8524 break;
8525 case 1:
8526 putDRegI64(rD + r + i * inc,
8527 unop(Iop_Dup16x4,
8528 loadLE(Ity_I16, binop(Iop_Add32,
8529 mkexpr(addr),
8530 mkU32(i * 2)))),
8531 IRTemp_INVALID);
8532 break;
8533 case 2:
8534 putDRegI64(rD + r + i * inc,
8535 unop(Iop_Dup32x2,
8536 loadLE(Ity_I32, binop(Iop_Add32,
8537 mkexpr(addr),
8538 mkU32(i * 4)))),
8539 IRTemp_INVALID);
8540 break;
8541 default:
8542 vassert(0);
8546 DIP("vld%u.%d {", N + 1, 8 << size);
8547 for (r = 0; r < regs; r++) {
8548 for (i = 0; i <= N; i++) {
8549 if (i || r)
8550 DIP(", ");
8551 DIP("d%u[]", rD + r + i * inc);
8554 DIP("}, [r%u]", rN);
8555 if (rM != 13 && rM != 15) {
8556 DIP(", r%u\n", rM);
8557 } else {
8558 DIP("%s\n", (rM != 15) ? "!" : "");
8561 /* Writeback. We're uncond here, so no condT-ing. */
8562 if (rM != 15) {
8563 if (rM == 13) {
8564 IRExpr* e = binop(Iop_Add32,
8565 mkexpr(initialRn),
8566 mkU32((1 << size) * (N + 1)));
8567 if (isT)
8568 putIRegT(rN, e, IRTemp_INVALID);
8569 else
8570 putIRegA(rN, e, IRTemp_INVALID, Ijk_Boring);
8571 } else {
8572 IRExpr* e = binop(Iop_Add32,
8573 mkexpr(initialRn),
8574 mkexpr(initialRm));
8575 if (isT)
8576 putIRegT(rN, e, IRTemp_INVALID);
8577 else
8578 putIRegA(rN, e, IRTemp_INVALID, Ijk_Boring);
8581 return True;
8582 } else {
8583 /* ------------ Case (3) ------------
8584 VSTn / VLDn (multiple n-element structures) */
8585 inc = (fB & 1) + 1;
8587 if (fB == BITS4(0,0,1,0) // Dd, Dd+1, Dd+2, Dd+3 inc = 1 regs = 4
8588 || fB == BITS4(0,1,1,0) // Dd, Dd+1, Dd+2 inc = 1 regs = 3
8589 || fB == BITS4(0,1,1,1) // Dd inc = 2 regs = 1
8590 || fB == BITS4(1,0,1,0)) { // Dd, Dd+1 inc = 1 regs = 2
8591 N = 0; // VLD1/VST1. 'inc' does not appear to have any
8592 // meaning for the VLD1/VST1 cases. 'regs' is the number of
8593 // registers involved.
8594 if (rD + regs > 32) return False;
8596 else
8597 if (fB == BITS4(0,0,1,1) // Dd, Dd+1, Dd+2, Dd+3 inc=2 regs = 2
8598 || fB == BITS4(1,0,0,0) // Dd, Dd+1 inc=1 regs = 1
8599 || fB == BITS4(1,0,0,1)) { // Dd, Dd+2 inc=2 regs = 1
8600 N = 1; // VLD2/VST2. 'regs' is the number of register-pairs involved
8601 if (regs == 1 && inc == 1 && rD + 1 >= 32) return False;
8602 if (regs == 1 && inc == 2 && rD + 2 >= 32) return False;
8603 if (regs == 2 && inc == 2 && rD + 3 >= 32) return False;
8604 } else if (fB == BITS4(0,1,0,0) || fB == BITS4(0,1,0,1)) {
8605 N = 2; // VLD3/VST3
8606 if (inc == 1 && rD + 2 >= 32) return False;
8607 if (inc == 2 && rD + 4 >= 32) return False;
8608 } else if (fB == BITS4(0,0,0,0) || fB == BITS4(0,0,0,1)) {
8609 N = 3; // VLD4/VST4
8610 if (inc == 1 && rD + 3 >= 32) return False;
8611 if (inc == 2 && rD + 6 >= 32) return False;
8612 } else {
8613 return False;
8616 if (N == 1 && fB == BITS4(0,0,1,1)) {
8617 regs = 2;
8618 } else if (N == 0) {
8619 if (fB == BITS4(1,0,1,0)) {
8620 regs = 2;
8621 } else if (fB == BITS4(0,1,1,0)) {
8622 regs = 3;
8623 } else if (fB == BITS4(0,0,1,0)) {
8624 regs = 4;
8628 size = INSN(7,6);
8629 if (N == 0 && size == 3)
8630 size = 2;
8631 if (size == 3)
8632 return False;
8634 // go uncond
8635 if (condT != IRTemp_INVALID)
8636 mk_skip_over_T32_if_cond_is_false(condT);
8637 // now uncond
8639 IRTemp addr = newTemp(Ity_I32);
8640 assign(addr, mkexpr(initialRn));
8642 if (N == 0 /* No interleaving -- VLD1/VST1 */) {
8643 UInt r;
8644 vassert(regs == 1 || regs == 2 || regs == 3 || regs == 4);
8645 /* inc has no relevance here */
8646 for (r = 0; r < regs; r++) {
8647 if (bL)
8648 putDRegI64(rD+r, loadLE(Ity_I64, mkexpr(addr)), IRTemp_INVALID);
8649 else
8650 storeLE(mkexpr(addr), getDRegI64(rD+r));
8651 IRTemp tmp = newTemp(Ity_I32);
8652 assign(tmp, binop(Iop_Add32, mkexpr(addr), mkU32(8)));
8653 addr = tmp;
8656 else
8657 if (N == 1 /* 2-interleaving -- VLD2/VST2 */) {
8658 vassert( (regs == 1 && (inc == 1 || inc == 2))
8659 || (regs == 2 && inc == 2) );
8660 // Make 'nregs' be the number of registers and 'regstep'
8661 // equal the actual register-step. The ARM encoding, using 'regs'
8662 // and 'inc', is bizarre. After this, we have:
8663 // Dd, Dd+1 regs = 1, inc = 1, nregs = 2, regstep = 1
8664 // Dd, Dd+2 regs = 1, inc = 2, nregs = 2, regstep = 2
8665 // Dd, Dd+1, Dd+2, Dd+3 regs = 2, inc = 2, nregs = 4, regstep = 1
8666 UInt nregs = 2;
8667 UInt regstep = 1;
8668 if (regs == 1 && inc == 1) {
8669 /* nothing */
8670 } else if (regs == 1 && inc == 2) {
8671 regstep = 2;
8672 } else if (regs == 2 && inc == 2) {
8673 nregs = 4;
8674 } else {
8675 vassert(0);
8677 // 'a' is address,
8678 // 'di' is interleaved data, 'du' is uninterleaved data
8679 if (nregs == 2) {
8680 IRExpr* a0 = binop(Iop_Add32, mkexpr(addr), mkU32(0));
8681 IRExpr* a1 = binop(Iop_Add32, mkexpr(addr), mkU32(8));
8682 IRTemp di0 = newTemp(Ity_I64);
8683 IRTemp di1 = newTemp(Ity_I64);
8684 IRTemp du0 = newTemp(Ity_I64);
8685 IRTemp du1 = newTemp(Ity_I64);
8686 if (bL) {
8687 assign(di0, loadLE(Ity_I64, a0));
8688 assign(di1, loadLE(Ity_I64, a1));
8689 math_DEINTERLEAVE_2(&du0, &du1, di0, di1, 1 << size);
8690 putDRegI64(rD + 0 * regstep, mkexpr(du0), IRTemp_INVALID);
8691 putDRegI64(rD + 1 * regstep, mkexpr(du1), IRTemp_INVALID);
8692 } else {
8693 assign(du0, getDRegI64(rD + 0 * regstep));
8694 assign(du1, getDRegI64(rD + 1 * regstep));
8695 math_INTERLEAVE_2(&di0, &di1, du0, du1, 1 << size);
8696 storeLE(a0, mkexpr(di0));
8697 storeLE(a1, mkexpr(di1));
8699 IRTemp tmp = newTemp(Ity_I32);
8700 assign(tmp, binop(Iop_Add32, mkexpr(addr), mkU32(16)));
8701 addr = tmp;
8702 } else {
8703 vassert(nregs == 4);
8704 vassert(regstep == 1);
8705 IRExpr* a0 = binop(Iop_Add32, mkexpr(addr), mkU32(0));
8706 IRExpr* a1 = binop(Iop_Add32, mkexpr(addr), mkU32(8));
8707 IRExpr* a2 = binop(Iop_Add32, mkexpr(addr), mkU32(16));
8708 IRExpr* a3 = binop(Iop_Add32, mkexpr(addr), mkU32(24));
8709 IRTemp di0 = newTemp(Ity_I64);
8710 IRTemp di1 = newTemp(Ity_I64);
8711 IRTemp di2 = newTemp(Ity_I64);
8712 IRTemp di3 = newTemp(Ity_I64);
8713 IRTemp du0 = newTemp(Ity_I64);
8714 IRTemp du1 = newTemp(Ity_I64);
8715 IRTemp du2 = newTemp(Ity_I64);
8716 IRTemp du3 = newTemp(Ity_I64);
8717 if (bL) {
8718 assign(di0, loadLE(Ity_I64, a0));
8719 assign(di1, loadLE(Ity_I64, a1));
8720 assign(di2, loadLE(Ity_I64, a2));
8721 assign(di3, loadLE(Ity_I64, a3));
8722 // Note spooky interleaving: du0, du2, di0, di1 etc
8723 math_DEINTERLEAVE_2(&du0, &du2, di0, di1, 1 << size);
8724 math_DEINTERLEAVE_2(&du1, &du3, di2, di3, 1 << size);
8725 putDRegI64(rD + 0 * regstep, mkexpr(du0), IRTemp_INVALID);
8726 putDRegI64(rD + 1 * regstep, mkexpr(du1), IRTemp_INVALID);
8727 putDRegI64(rD + 2 * regstep, mkexpr(du2), IRTemp_INVALID);
8728 putDRegI64(rD + 3 * regstep, mkexpr(du3), IRTemp_INVALID);
8729 } else {
8730 assign(du0, getDRegI64(rD + 0 * regstep));
8731 assign(du1, getDRegI64(rD + 1 * regstep));
8732 assign(du2, getDRegI64(rD + 2 * regstep));
8733 assign(du3, getDRegI64(rD + 3 * regstep));
8734 // Note spooky interleaving: du0, du2, di0, di1 etc
8735 math_INTERLEAVE_2(&di0, &di1, du0, du2, 1 << size);
8736 math_INTERLEAVE_2(&di2, &di3, du1, du3, 1 << size);
8737 storeLE(a0, mkexpr(di0));
8738 storeLE(a1, mkexpr(di1));
8739 storeLE(a2, mkexpr(di2));
8740 storeLE(a3, mkexpr(di3));
8743 IRTemp tmp = newTemp(Ity_I32);
8744 assign(tmp, binop(Iop_Add32, mkexpr(addr), mkU32(32)));
8745 addr = tmp;
8748 else
8749 if (N == 2 /* 3-interleaving -- VLD3/VST3 */) {
8750 // Dd, Dd+1, Dd+2 regs = 1, inc = 1
8751 // Dd, Dd+2, Dd+4 regs = 1, inc = 2
8752 vassert(regs == 1 && (inc == 1 || inc == 2));
8753 IRExpr* a0 = binop(Iop_Add32, mkexpr(addr), mkU32(0));
8754 IRExpr* a1 = binop(Iop_Add32, mkexpr(addr), mkU32(8));
8755 IRExpr* a2 = binop(Iop_Add32, mkexpr(addr), mkU32(16));
8756 IRTemp di0 = newTemp(Ity_I64);
8757 IRTemp di1 = newTemp(Ity_I64);
8758 IRTemp di2 = newTemp(Ity_I64);
8759 IRTemp du0 = newTemp(Ity_I64);
8760 IRTemp du1 = newTemp(Ity_I64);
8761 IRTemp du2 = newTemp(Ity_I64);
8762 if (bL) {
8763 assign(di0, loadLE(Ity_I64, a0));
8764 assign(di1, loadLE(Ity_I64, a1));
8765 assign(di2, loadLE(Ity_I64, a2));
8766 math_DEINTERLEAVE_3(&du0, &du1, &du2, di0, di1, di2, 1 << size);
8767 putDRegI64(rD + 0 * inc, mkexpr(du0), IRTemp_INVALID);
8768 putDRegI64(rD + 1 * inc, mkexpr(du1), IRTemp_INVALID);
8769 putDRegI64(rD + 2 * inc, mkexpr(du2), IRTemp_INVALID);
8770 } else {
8771 assign(du0, getDRegI64(rD + 0 * inc));
8772 assign(du1, getDRegI64(rD + 1 * inc));
8773 assign(du2, getDRegI64(rD + 2 * inc));
8774 math_INTERLEAVE_3(&di0, &di1, &di2, du0, du1, du2, 1 << size);
8775 storeLE(a0, mkexpr(di0));
8776 storeLE(a1, mkexpr(di1));
8777 storeLE(a2, mkexpr(di2));
8779 IRTemp tmp = newTemp(Ity_I32);
8780 assign(tmp, binop(Iop_Add32, mkexpr(addr), mkU32(24)));
8781 addr = tmp;
8783 else
8784 if (N == 3 /* 4-interleaving -- VLD4/VST4 */) {
8785 // Dd, Dd+1, Dd+2, Dd+3 regs = 1, inc = 1
8786 // Dd, Dd+2, Dd+4, Dd+6 regs = 1, inc = 2
8787 vassert(regs == 1 && (inc == 1 || inc == 2));
8788 IRExpr* a0 = binop(Iop_Add32, mkexpr(addr), mkU32(0));
8789 IRExpr* a1 = binop(Iop_Add32, mkexpr(addr), mkU32(8));
8790 IRExpr* a2 = binop(Iop_Add32, mkexpr(addr), mkU32(16));
8791 IRExpr* a3 = binop(Iop_Add32, mkexpr(addr), mkU32(24));
8792 IRTemp di0 = newTemp(Ity_I64);
8793 IRTemp di1 = newTemp(Ity_I64);
8794 IRTemp di2 = newTemp(Ity_I64);
8795 IRTemp di3 = newTemp(Ity_I64);
8796 IRTemp du0 = newTemp(Ity_I64);
8797 IRTemp du1 = newTemp(Ity_I64);
8798 IRTemp du2 = newTemp(Ity_I64);
8799 IRTemp du3 = newTemp(Ity_I64);
8800 if (bL) {
8801 assign(di0, loadLE(Ity_I64, a0));
8802 assign(di1, loadLE(Ity_I64, a1));
8803 assign(di2, loadLE(Ity_I64, a2));
8804 assign(di3, loadLE(Ity_I64, a3));
8805 math_DEINTERLEAVE_4(&du0, &du1, &du2, &du3,
8806 di0, di1, di2, di3, 1 << size);
8807 putDRegI64(rD + 0 * inc, mkexpr(du0), IRTemp_INVALID);
8808 putDRegI64(rD + 1 * inc, mkexpr(du1), IRTemp_INVALID);
8809 putDRegI64(rD + 2 * inc, mkexpr(du2), IRTemp_INVALID);
8810 putDRegI64(rD + 3 * inc, mkexpr(du3), IRTemp_INVALID);
8811 } else {
8812 assign(du0, getDRegI64(rD + 0 * inc));
8813 assign(du1, getDRegI64(rD + 1 * inc));
8814 assign(du2, getDRegI64(rD + 2 * inc));
8815 assign(du3, getDRegI64(rD + 3 * inc));
8816 math_INTERLEAVE_4(&di0, &di1, &di2, &di3,
8817 du0, du1, du2, du3, 1 << size);
8818 storeLE(a0, mkexpr(di0));
8819 storeLE(a1, mkexpr(di1));
8820 storeLE(a2, mkexpr(di2));
8821 storeLE(a3, mkexpr(di3));
8823 IRTemp tmp = newTemp(Ity_I32);
8824 assign(tmp, binop(Iop_Add32, mkexpr(addr), mkU32(32)));
8825 addr = tmp;
8827 else {
8828 vassert(0);
8831 /* Writeback */
8832 if (rM != 15) {
8833 IRExpr* e;
8834 if (rM == 13) {
8835 e = binop(Iop_Add32, mkexpr(initialRn),
8836 mkU32(8 * (N + 1) * regs));
8837 } else {
8838 e = binop(Iop_Add32, mkexpr(initialRn),
8839 mkexpr(initialRm));
8841 if (isT)
8842 putIRegT(rN, e, IRTemp_INVALID);
8843 else
8844 putIRegA(rN, e, IRTemp_INVALID, Ijk_Boring);
8847 DIP("v%s%u.%d {", bL ? "ld" : "st", N + 1, 8 << INSN(7,6));
8848 if ((inc == 1 && regs * (N + 1) > 1)
8849 || (inc == 2 && regs > 1 && N > 0)) {
8850 DIP("d%u-d%u", rD, rD + regs * (N + 1) - 1);
8851 } else {
8852 UInt r;
8853 for (r = 0; r < regs; r++) {
8854 for (i = 0; i <= N; i++) {
8855 if (i || r)
8856 DIP(", ");
8857 DIP("d%u", rD + r + i * inc);
8861 DIP("}, [r%u]", rN);
8862 if (rM != 13 && rM != 15) {
8863 DIP(", r%u\n", rM);
8864 } else {
8865 DIP("%s\n", (rM != 15) ? "!" : "");
8867 return True;
8869 # undef INSN
8873 /*------------------------------------------------------------*/
8874 /*--- NEON, top level control ---*/
8875 /*------------------------------------------------------------*/
8877 /* Both ARM and Thumb */
8879 /* Translate a NEON instruction. If successful, returns
8880 True and *dres may or may not be updated. If failure, returns
8881 False and doesn't change *dres nor create any IR.
8883 The Thumb and ARM encodings are similar for the 24 bottom bits, but
8884 the top 8 bits are slightly different. In both cases, the caller
8885 must pass the entire 32 bits. Callers may pass any instruction;
8886 this ignores non-NEON ones.
8888 Caller must supply an IRTemp 'condT' holding the gating condition,
8889 or IRTemp_INVALID indicating the insn is always executed. In ARM
8890 code, this must always be IRTemp_INVALID because NEON insns are
8891 unconditional for ARM.
8893 Finally, the caller must indicate whether this occurs in ARM or in
8894 Thumb code.
8896 This only handles NEON for ARMv7 and below. The NEON extensions
8897 for v8 are handled by decode_V8_instruction.
8899 static Bool decode_NEON_instruction_ARMv7_and_below (
8900 /*MOD*/DisResult* dres,
8901 UInt insn32,
8902 IRTemp condT,
8903 Bool isT
8906 # define INSN(_bMax,_bMin) SLICE_UInt(insn32, (_bMax), (_bMin))
8908 /* There are two kinds of instruction to deal with: load/store and
8909 data processing. In each case, in ARM mode we merely identify
8910 the kind, and pass it on to the relevant sub-handler. In Thumb
8911 mode we identify the kind, swizzle the bits around to make it
8912 have the same encoding as in ARM, and hand it on to the
8913 sub-handler.
8916 /* In ARM mode, NEON instructions can't be conditional. */
8917 if (!isT)
8918 vassert(condT == IRTemp_INVALID);
8920 /* Data processing:
8921 Thumb: 111U 1111 AAAA Axxx xxxx BBBB CCCC xxxx
8922 ARM: 1111 001U AAAA Axxx xxxx BBBB CCCC xxxx
8924 if (!isT && INSN(31,25) == BITS7(1,1,1,1,0,0,1)) {
8925 // ARM, DP
8926 return dis_neon_data_processing(INSN(31,0), condT);
8928 if (isT && INSN(31,29) == BITS3(1,1,1)
8929 && INSN(27,24) == BITS4(1,1,1,1)) {
8930 // Thumb, DP
8931 UInt reformatted = INSN(23,0);
8932 reformatted |= (((UInt)INSN(28,28)) << 24); // U bit
8933 reformatted |= (((UInt)BITS7(1,1,1,1,0,0,1)) << 25);
8934 return dis_neon_data_processing(reformatted, condT);
8937 /* Load/store:
8938 Thumb: 1111 1001 AxL0 xxxx xxxx BBBB xxxx xxxx
8939 ARM: 1111 0100 AxL0 xxxx xxxx BBBB xxxx xxxx
8941 if (!isT && INSN(31,24) == BITS8(1,1,1,1,0,1,0,0)) {
8942 // ARM, memory
8943 return dis_neon_load_or_store(INSN(31,0), isT, condT);
8945 if (isT && INSN(31,24) == BITS8(1,1,1,1,1,0,0,1)) {
8946 UInt reformatted = INSN(23,0);
8947 reformatted |= (((UInt)BITS8(1,1,1,1,0,1,0,0)) << 24);
8948 return dis_neon_load_or_store(reformatted, isT, condT);
8951 /* Doesn't match. */
8952 return False;
8954 # undef INSN
8958 /*------------------------------------------------------------*/
8959 /*--- V6 MEDIA instructions ---*/
8960 /*------------------------------------------------------------*/
8962 /* Both ARM and Thumb */
8964 /* Translate a V6 media instruction. If successful, returns
8965 True and *dres may or may not be updated. If failure, returns
8966 False and doesn't change *dres nor create any IR.
8968 The Thumb and ARM encodings are completely different. In Thumb
8969 mode, the caller must pass the entire 32 bits. In ARM mode it must
8970 pass the lower 28 bits. Apart from that, callers may pass any
8971 instruction; this function ignores anything it doesn't recognise.
8973 Caller must supply an IRTemp 'condT' holding the gating condition,
8974 or IRTemp_INVALID indicating the insn is always executed.
8976 Caller must also supply an ARMCondcode 'conq'. This is only used
8977 for debug printing, no other purpose. For ARM, this is simply the
8978 top 4 bits of the original instruction. For Thumb, the condition
8979 is not (really) known until run time, and so ARMCondAL should be
8980 passed, only so that printing of these instructions does not show
8981 any condition.
8983 Finally, the caller must indicate whether this occurs in ARM or in
8984 Thumb code.
8986 static Bool decode_V6MEDIA_instruction (
8987 /*MOD*/DisResult* dres,
8988 UInt insnv6m,
8989 IRTemp condT,
8990 ARMCondcode conq,
8991 Bool isT
8994 # define INSNA(_bMax,_bMin) SLICE_UInt(insnv6m, (_bMax), (_bMin))
8995 # define INSNT0(_bMax,_bMin) SLICE_UInt( ((insnv6m >> 16) & 0xFFFF), \
8996 (_bMax), (_bMin) )
8997 # define INSNT1(_bMax,_bMin) SLICE_UInt( ((insnv6m >> 0) & 0xFFFF), \
8998 (_bMax), (_bMin) )
8999 HChar dis_buf[128];
9000 dis_buf[0] = 0;
9002 if (isT) {
9003 vassert(conq == ARMCondAL);
9004 } else {
9005 vassert(INSNA(31,28) == BITS4(0,0,0,0)); // caller's obligation
9006 vassert(conq >= ARMCondEQ && conq <= ARMCondAL);
9009 /* ----------- smulbb, smulbt, smultb, smultt ----------- */
9011 UInt regD = 99, regM = 99, regN = 99, bitM = 0, bitN = 0;
9012 Bool gate = False;
9014 if (isT) {
9015 if (INSNT0(15,4) == 0xFB1 && INSNT1(15,12) == BITS4(1,1,1,1)
9016 && INSNT1(7,6) == BITS2(0,0)) {
9017 regD = INSNT1(11,8);
9018 regM = INSNT1(3,0);
9019 regN = INSNT0(3,0);
9020 bitM = INSNT1(4,4);
9021 bitN = INSNT1(5,5);
9022 if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
9023 gate = True;
9025 } else {
9026 if (BITS8(0,0,0,1,0,1,1,0) == INSNA(27,20) &&
9027 BITS4(0,0,0,0) == INSNA(15,12) &&
9028 BITS4(1,0,0,0) == (INSNA(7,4) & BITS4(1,0,0,1)) ) {
9029 regD = INSNA(19,16);
9030 regM = INSNA(11,8);
9031 regN = INSNA(3,0);
9032 bitM = INSNA(6,6);
9033 bitN = INSNA(5,5);
9034 if (regD != 15 && regN != 15 && regM != 15)
9035 gate = True;
9039 if (gate) {
9040 IRTemp srcN = newTemp(Ity_I32);
9041 IRTemp srcM = newTemp(Ity_I32);
9042 IRTemp res = newTemp(Ity_I32);
9044 assign( srcN, binop(Iop_Sar32,
9045 binop(Iop_Shl32,
9046 isT ? getIRegT(regN) : getIRegA(regN),
9047 mkU8(bitN ? 0 : 16)), mkU8(16)) );
9048 assign( srcM, binop(Iop_Sar32,
9049 binop(Iop_Shl32,
9050 isT ? getIRegT(regM) : getIRegA(regM),
9051 mkU8(bitM ? 0 : 16)), mkU8(16)) );
9052 assign( res, binop(Iop_Mul32, mkexpr(srcN), mkexpr(srcM)) );
9054 if (isT)
9055 putIRegT( regD, mkexpr(res), condT );
9056 else
9057 putIRegA( regD, mkexpr(res), condT, Ijk_Boring );
9059 DIP( "smul%c%c%s r%u, r%u, r%u\n", bitN ? 't' : 'b', bitM ? 't' : 'b',
9060 nCC(conq), regD, regN, regM );
9061 return True;
9063 /* fall through */
9066 /* ------------ smulwb<y><c> <Rd>,<Rn>,<Rm> ------------- */
9067 /* ------------ smulwt<y><c> <Rd>,<Rn>,<Rm> ------------- */
9069 UInt regD = 99, regN = 99, regM = 99, bitM = 0;
9070 Bool gate = False;
9072 if (isT) {
9073 if (INSNT0(15,4) == 0xFB3 && INSNT1(15,12) == BITS4(1,1,1,1)
9074 && INSNT1(7,5) == BITS3(0,0,0)) {
9075 regN = INSNT0(3,0);
9076 regD = INSNT1(11,8);
9077 regM = INSNT1(3,0);
9078 bitM = INSNT1(4,4);
9079 if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
9080 gate = True;
9082 } else {
9083 if (INSNA(27,20) == BITS8(0,0,0,1,0,0,1,0) &&
9084 INSNA(15,12) == BITS4(0,0,0,0) &&
9085 (INSNA(7,4) & BITS4(1,0,1,1)) == BITS4(1,0,1,0)) {
9086 regD = INSNA(19,16);
9087 regN = INSNA(3,0);
9088 regM = INSNA(11,8);
9089 bitM = INSNA(6,6);
9090 if (regD != 15 && regN != 15 && regM != 15)
9091 gate = True;
9095 if (gate) {
9096 IRTemp irt_prod = newTemp(Ity_I64);
9098 assign( irt_prod,
9099 binop(Iop_MullS32,
9100 isT ? getIRegT(regN) : getIRegA(regN),
9101 binop(Iop_Sar32,
9102 binop(Iop_Shl32,
9103 isT ? getIRegT(regM) : getIRegA(regM),
9104 mkU8(bitM ? 0 : 16)),
9105 mkU8(16))) );
9107 IRExpr* ire_result = binop(Iop_Or32,
9108 binop( Iop_Shl32,
9109 unop(Iop_64HIto32, mkexpr(irt_prod)),
9110 mkU8(16) ),
9111 binop( Iop_Shr32,
9112 unop(Iop_64to32, mkexpr(irt_prod)),
9113 mkU8(16) ) );
9115 if (isT)
9116 putIRegT( regD, ire_result, condT );
9117 else
9118 putIRegA( regD, ire_result, condT, Ijk_Boring );
9120 DIP("smulw%c%s r%u, r%u, r%u\n",
9121 bitM ? 't' : 'b', nCC(conq),regD,regN,regM);
9122 return True;
9124 /* fall through */
9127 /* ------------ pkhbt<c> Rd, Rn, Rm {,LSL #imm} ------------- */
9128 /* ------------ pkhtb<c> Rd, Rn, Rm {,ASR #imm} ------------- */
9130 UInt regD = 99, regN = 99, regM = 99, imm5 = 99, shift_type = 99;
9131 Bool tbform = False;
9132 Bool gate = False;
9134 if (isT) {
9135 if (INSNT0(15,4) == 0xEAC
9136 && INSNT1(15,15) == 0 && INSNT1(4,4) == 0) {
9137 regN = INSNT0(3,0);
9138 regD = INSNT1(11,8);
9139 regM = INSNT1(3,0);
9140 imm5 = (INSNT1(14,12) << 2) | INSNT1(7,6);
9141 shift_type = (INSNT1(5,5) << 1) | 0;
9142 tbform = (INSNT1(5,5) == 0) ? False : True;
9143 if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
9144 gate = True;
9146 } else {
9147 if (INSNA(27,20) == BITS8(0,1,1,0,1,0,0,0) &&
9148 INSNA(5,4) == BITS2(0,1) /* &&
9149 (INSNA(6,6) == 0 || INSNA(6,6) == 1)
9150 This last bit with INSNA(6,6) is correct, but gcc 8 complains
9151 (correctly) that it is always true. So I commented it out
9152 to keep gcc quiet. */ ) {
9153 regD = INSNA(15,12);
9154 regN = INSNA(19,16);
9155 regM = INSNA(3,0);
9156 imm5 = INSNA(11,7);
9157 shift_type = (INSNA(6,6) << 1) | 0;
9158 tbform = (INSNA(6,6) == 0) ? False : True;
9159 if (regD != 15 && regN != 15 && regM != 15)
9160 gate = True;
9164 if (gate) {
9165 IRTemp irt_regM = newTemp(Ity_I32);
9166 IRTemp irt_regM_shift = newTemp(Ity_I32);
9167 assign( irt_regM, isT ? getIRegT(regM) : getIRegA(regM) );
9168 compute_result_and_C_after_shift_by_imm5(
9169 dis_buf, &irt_regM_shift, NULL, irt_regM, shift_type, imm5, regM );
9171 UInt mask = (tbform == True) ? 0x0000FFFF : 0xFFFF0000;
9172 IRExpr* ire_result
9173 = binop( Iop_Or32,
9174 binop(Iop_And32, mkexpr(irt_regM_shift), mkU32(mask)),
9175 binop(Iop_And32, isT ? getIRegT(regN) : getIRegA(regN),
9176 unop(Iop_Not32, mkU32(mask))) );
9178 if (isT)
9179 putIRegT( regD, ire_result, condT );
9180 else
9181 putIRegA( regD, ire_result, condT, Ijk_Boring );
9183 DIP( "pkh%s%s r%u, r%u, r%u %s\n", tbform ? "tb" : "bt",
9184 nCC(conq), regD, regN, regM, dis_buf );
9186 return True;
9188 /* fall through */
9191 /* ---------- usat<c> <Rd>,#<imm5>,<Rn>{,<shift>} ----------- */
9193 UInt regD = 99, regN = 99, shift_type = 99, imm5 = 99, sat_imm = 99;
9194 Bool gate = False;
9196 if (isT) {
9197 if (INSNT0(15,6) == BITS10(1,1,1,1,0,0,1,1,1,0)
9198 && INSNT0(4,4) == 0
9199 && INSNT1(15,15) == 0 && INSNT1(5,5) == 0) {
9200 regD = INSNT1(11,8);
9201 regN = INSNT0(3,0);
9202 shift_type = (INSNT0(5,5) << 1) | 0;
9203 imm5 = (INSNT1(14,12) << 2) | INSNT1(7,6);
9204 sat_imm = INSNT1(4,0);
9205 if (!isBadRegT(regD) && !isBadRegT(regN))
9206 gate = True;
9207 if (shift_type == BITS2(1,0) && imm5 == 0)
9208 gate = False;
9210 } else {
9211 if (INSNA(27,21) == BITS7(0,1,1,0,1,1,1) &&
9212 INSNA(5,4) == BITS2(0,1)) {
9213 regD = INSNA(15,12);
9214 regN = INSNA(3,0);
9215 shift_type = (INSNA(6,6) << 1) | 0;
9216 imm5 = INSNA(11,7);
9217 sat_imm = INSNA(20,16);
9218 if (regD != 15 && regN != 15)
9219 gate = True;
9223 if (gate) {
9224 IRTemp irt_regN = newTemp(Ity_I32);
9225 IRTemp irt_regN_shift = newTemp(Ity_I32);
9226 IRTemp irt_sat_Q = newTemp(Ity_I32);
9227 IRTemp irt_result = newTemp(Ity_I32);
9229 assign( irt_regN, isT ? getIRegT(regN) : getIRegA(regN) );
9230 compute_result_and_C_after_shift_by_imm5(
9231 dis_buf, &irt_regN_shift, NULL,
9232 irt_regN, shift_type, imm5, regN );
9234 armUnsignedSatQ( &irt_result, &irt_sat_Q, irt_regN_shift, sat_imm );
9235 or_into_QFLAG32( mkexpr(irt_sat_Q), condT );
9237 if (isT)
9238 putIRegT( regD, mkexpr(irt_result), condT );
9239 else
9240 putIRegA( regD, mkexpr(irt_result), condT, Ijk_Boring );
9242 DIP("usat%s r%u, #0x%04x, %s\n",
9243 nCC(conq), regD, imm5, dis_buf);
9244 return True;
9246 /* fall through */
9249 /* ----------- ssat<c> <Rd>,#<imm5>,<Rn>{,<shift>} ----------- */
9251 UInt regD = 99, regN = 99, shift_type = 99, imm5 = 99, sat_imm = 99;
9252 Bool gate = False;
9254 if (isT) {
9255 if (INSNT0(15,6) == BITS10(1,1,1,1,0,0,1,1,0,0)
9256 && INSNT0(4,4) == 0
9257 && INSNT1(15,15) == 0 && INSNT1(5,5) == 0) {
9258 regD = INSNT1(11,8);
9259 regN = INSNT0(3,0);
9260 shift_type = (INSNT0(5,5) << 1) | 0;
9261 imm5 = (INSNT1(14,12) << 2) | INSNT1(7,6);
9262 sat_imm = INSNT1(4,0) + 1;
9263 if (!isBadRegT(regD) && !isBadRegT(regN))
9264 gate = True;
9265 if (shift_type == BITS2(1,0) && imm5 == 0)
9266 gate = False;
9268 } else {
9269 if (INSNA(27,21) == BITS7(0,1,1,0,1,0,1) &&
9270 INSNA(5,4) == BITS2(0,1)) {
9271 regD = INSNA(15,12);
9272 regN = INSNA(3,0);
9273 shift_type = (INSNA(6,6) << 1) | 0;
9274 imm5 = INSNA(11,7);
9275 sat_imm = INSNA(20,16) + 1;
9276 if (regD != 15 && regN != 15)
9277 gate = True;
9281 if (gate) {
9282 IRTemp irt_regN = newTemp(Ity_I32);
9283 IRTemp irt_regN_shift = newTemp(Ity_I32);
9284 IRTemp irt_sat_Q = newTemp(Ity_I32);
9285 IRTemp irt_result = newTemp(Ity_I32);
9287 assign( irt_regN, isT ? getIRegT(regN) : getIRegA(regN) );
9288 compute_result_and_C_after_shift_by_imm5(
9289 dis_buf, &irt_regN_shift, NULL,
9290 irt_regN, shift_type, imm5, regN );
9292 armSignedSatQ( irt_regN_shift, sat_imm, &irt_result, &irt_sat_Q );
9293 or_into_QFLAG32( mkexpr(irt_sat_Q), condT );
9295 if (isT)
9296 putIRegT( regD, mkexpr(irt_result), condT );
9297 else
9298 putIRegA( regD, mkexpr(irt_result), condT, Ijk_Boring );
9300 DIP( "ssat%s r%u, #0x%04x, %s\n",
9301 nCC(conq), regD, imm5, dis_buf);
9302 return True;
9304 /* fall through */
9307 /* ----------- ssat16<c> <Rd>,#<imm>,<Rn> ----------- */
9309 UInt regD = 99, regN = 99, sat_imm = 99;
9310 Bool gate = False;
9312 if (isT) {
9313 if (INSNT0(15,6) == BITS10(1,1,1,1,0,0,1,1,0,0)
9314 && INSNT0(5,4) == BITS2(1,0)
9315 && INSNT1(15,12) == BITS4(0,0,0,0)
9316 && INSNT1(7,4) == BITS4(0,0,0,0)) {
9317 regD = INSNT1(11,8);
9318 regN = INSNT0(3,0);
9319 sat_imm = INSNT1(3,0) + 1;
9320 if (!isBadRegT(regD) && !isBadRegT(regN))
9321 gate = True;
9323 } else {
9324 if (INSNA(27,20) == BITS8(0,1,1,0,1,0,1,0) &&
9325 INSNA(11,4) == BITS8(1,1,1,1,0,0,1,1)) {
9326 regD = INSNA(15,12);
9327 regN = INSNA(3,0);
9328 sat_imm = INSNA(19,16) + 1;
9329 if (regD != 15 && regN != 15)
9330 gate = True;
9334 if (gate) {
9335 IRTemp irt_regN = newTemp(Ity_I32);
9336 IRTemp irt_regN_lo = newTemp(Ity_I32);
9337 IRTemp irt_regN_hi = newTemp(Ity_I32);
9338 IRTemp irt_Q_lo = newTemp(Ity_I32);
9339 IRTemp irt_Q_hi = newTemp(Ity_I32);
9340 IRTemp irt_res_lo = newTemp(Ity_I32);
9341 IRTemp irt_res_hi = newTemp(Ity_I32);
9343 assign( irt_regN, isT ? getIRegT(regN) : getIRegA(regN) );
9344 assign( irt_regN_lo,
9345 binop( Iop_Sar32,
9346 binop(Iop_Shl32, mkexpr(irt_regN), mkU8(16)),
9347 mkU8(16)) );
9348 assign( irt_regN_hi, binop(Iop_Sar32, mkexpr(irt_regN), mkU8(16)) );
9350 armSignedSatQ( irt_regN_lo, sat_imm, &irt_res_lo, &irt_Q_lo );
9351 or_into_QFLAG32( mkexpr(irt_Q_lo), condT );
9353 armSignedSatQ( irt_regN_hi, sat_imm, &irt_res_hi, &irt_Q_hi );
9354 or_into_QFLAG32( mkexpr(irt_Q_hi), condT );
9356 IRExpr* ire_result
9357 = binop(Iop_Or32,
9358 binop(Iop_And32, mkexpr(irt_res_lo), mkU32(0xFFFF)),
9359 binop(Iop_Shl32, mkexpr(irt_res_hi), mkU8(16)));
9360 if (isT)
9361 putIRegT( regD, ire_result, condT );
9362 else
9363 putIRegA( regD, ire_result, condT, Ijk_Boring );
9365 DIP( "ssat16%s r%u, #0x%04x, r%u\n", nCC(conq), regD, sat_imm, regN );
9366 return True;
9368 /* fall through */
9371 /* -------------- usat16<c> <Rd>,#<imm4>,<Rn> --------------- */
9373 UInt regD = 99, regN = 99, sat_imm = 99;
9374 Bool gate = False;
9376 if (isT) {
9377 if (INSNT0(15,4) == 0xF3A && (INSNT1(15,0) & 0xF0F0) == 0x0000) {
9378 regN = INSNT0(3,0);
9379 regD = INSNT1(11,8);
9380 sat_imm = INSNT1(3,0);
9381 if (!isBadRegT(regD) && !isBadRegT(regN))
9382 gate = True;
9384 } else {
9385 if (INSNA(27,20) == BITS8(0,1,1,0,1,1,1,0) &&
9386 INSNA(11,8) == BITS4(1,1,1,1) &&
9387 INSNA(7,4) == BITS4(0,0,1,1)) {
9388 regD = INSNA(15,12);
9389 regN = INSNA(3,0);
9390 sat_imm = INSNA(19,16);
9391 if (regD != 15 && regN != 15)
9392 gate = True;
9396 if (gate) {
9397 IRTemp irt_regN = newTemp(Ity_I32);
9398 IRTemp irt_regN_lo = newTemp(Ity_I32);
9399 IRTemp irt_regN_hi = newTemp(Ity_I32);
9400 IRTemp irt_Q_lo = newTemp(Ity_I32);
9401 IRTemp irt_Q_hi = newTemp(Ity_I32);
9402 IRTemp irt_res_lo = newTemp(Ity_I32);
9403 IRTemp irt_res_hi = newTemp(Ity_I32);
9405 assign( irt_regN, isT ? getIRegT(regN) : getIRegA(regN) );
9406 assign( irt_regN_lo, binop( Iop_Sar32,
9407 binop(Iop_Shl32, mkexpr(irt_regN), mkU8(16)),
9408 mkU8(16)) );
9409 assign( irt_regN_hi, binop(Iop_Sar32, mkexpr(irt_regN), mkU8(16)) );
9411 armUnsignedSatQ( &irt_res_lo, &irt_Q_lo, irt_regN_lo, sat_imm );
9412 or_into_QFLAG32( mkexpr(irt_Q_lo), condT );
9414 armUnsignedSatQ( &irt_res_hi, &irt_Q_hi, irt_regN_hi, sat_imm );
9415 or_into_QFLAG32( mkexpr(irt_Q_hi), condT );
9417 IRExpr* ire_result = binop( Iop_Or32,
9418 binop(Iop_Shl32, mkexpr(irt_res_hi), mkU8(16)),
9419 mkexpr(irt_res_lo) );
9421 if (isT)
9422 putIRegT( regD, ire_result, condT );
9423 else
9424 putIRegA( regD, ire_result, condT, Ijk_Boring );
9426 DIP( "usat16%s r%u, #0x%04x, r%u\n", nCC(conq), regD, sat_imm, regN );
9427 return True;
9429 /* fall through */
9432 /* -------------- uadd16<c> <Rd>,<Rn>,<Rm> -------------- */
9434 UInt regD = 99, regN = 99, regM = 99;
9435 Bool gate = False;
9437 if (isT) {
9438 if (INSNT0(15,4) == 0xFA9 && (INSNT1(15,0) & 0xF0F0) == 0xF040) {
9439 regN = INSNT0(3,0);
9440 regD = INSNT1(11,8);
9441 regM = INSNT1(3,0);
9442 if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
9443 gate = True;
9445 } else {
9446 if (INSNA(27,20) == BITS8(0,1,1,0,0,1,0,1) &&
9447 INSNA(11,8) == BITS4(1,1,1,1) &&
9448 INSNA(7,4) == BITS4(0,0,0,1)) {
9449 regD = INSNA(15,12);
9450 regN = INSNA(19,16);
9451 regM = INSNA(3,0);
9452 if (regD != 15 && regN != 15 && regM != 15)
9453 gate = True;
9457 if (gate) {
9458 IRTemp rNt = newTemp(Ity_I32);
9459 IRTemp rMt = newTemp(Ity_I32);
9460 IRTemp res = newTemp(Ity_I32);
9461 IRTemp reso = newTemp(Ity_I32);
9463 assign( rNt, isT ? getIRegT(regN) : getIRegA(regN) );
9464 assign( rMt, isT ? getIRegT(regM) : getIRegA(regM) );
9466 assign(res, binop(Iop_Add16x2, mkexpr(rNt), mkexpr(rMt)));
9467 if (isT)
9468 putIRegT( regD, mkexpr(res), condT );
9469 else
9470 putIRegA( regD, mkexpr(res), condT, Ijk_Boring );
9472 assign(reso, binop(Iop_HAdd16Ux2, mkexpr(rNt), mkexpr(rMt)));
9473 set_GE_32_10_from_bits_31_15(reso, condT);
9475 DIP("uadd16%s r%u, r%u, r%u\n", nCC(conq),regD,regN,regM);
9476 return True;
9478 /* fall through */
9481 /* -------------- sadd16<c> <Rd>,<Rn>,<Rm> -------------- */
9483 UInt regD = 99, regN = 99, regM = 99;
9484 Bool gate = False;
9486 if (isT) {
9487 if (INSNT0(15,4) == 0xFA9 && (INSNT1(15,0) & 0xF0F0) == 0xF000) {
9488 regN = INSNT0(3,0);
9489 regD = INSNT1(11,8);
9490 regM = INSNT1(3,0);
9491 if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
9492 gate = True;
9494 } else {
9495 if (INSNA(27,20) == BITS8(0,1,1,0,0,0,0,1) &&
9496 INSNA(11,8) == BITS4(1,1,1,1) &&
9497 INSNA(7,4) == BITS4(0,0,0,1)) {
9498 regD = INSNA(15,12);
9499 regN = INSNA(19,16);
9500 regM = INSNA(3,0);
9501 if (regD != 15 && regN != 15 && regM != 15)
9502 gate = True;
9506 if (gate) {
9507 IRTemp rNt = newTemp(Ity_I32);
9508 IRTemp rMt = newTemp(Ity_I32);
9509 IRTemp res = newTemp(Ity_I32);
9510 IRTemp reso = newTemp(Ity_I32);
9512 assign( rNt, isT ? getIRegT(regN) : getIRegA(regN) );
9513 assign( rMt, isT ? getIRegT(regM) : getIRegA(regM) );
9515 assign(res, binop(Iop_Add16x2, mkexpr(rNt), mkexpr(rMt)));
9516 if (isT)
9517 putIRegT( regD, mkexpr(res), condT );
9518 else
9519 putIRegA( regD, mkexpr(res), condT, Ijk_Boring );
9521 assign(reso, unop(Iop_Not32,
9522 binop(Iop_HAdd16Sx2, mkexpr(rNt), mkexpr(rMt))));
9523 set_GE_32_10_from_bits_31_15(reso, condT);
9525 DIP("sadd16%s r%u, r%u, r%u\n", nCC(conq),regD,regN,regM);
9526 return True;
9528 /* fall through */
9531 /* ---------------- usub16<c> <Rd>,<Rn>,<Rm> ---------------- */
9533 UInt regD = 99, regN = 99, regM = 99;
9534 Bool gate = False;
9536 if (isT) {
9537 if (INSNT0(15,4) == 0xFAD && (INSNT1(15,0) & 0xF0F0) == 0xF040) {
9538 regN = INSNT0(3,0);
9539 regD = INSNT1(11,8);
9540 regM = INSNT1(3,0);
9541 if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
9542 gate = True;
9544 } else {
9545 if (INSNA(27,20) == BITS8(0,1,1,0,0,1,0,1) &&
9546 INSNA(11,8) == BITS4(1,1,1,1) &&
9547 INSNA(7,4) == BITS4(0,1,1,1)) {
9548 regD = INSNA(15,12);
9549 regN = INSNA(19,16);
9550 regM = INSNA(3,0);
9551 if (regD != 15 && regN != 15 && regM != 15)
9552 gate = True;
9556 if (gate) {
9557 IRTemp rNt = newTemp(Ity_I32);
9558 IRTemp rMt = newTemp(Ity_I32);
9559 IRTemp res = newTemp(Ity_I32);
9560 IRTemp reso = newTemp(Ity_I32);
9562 assign( rNt, isT ? getIRegT(regN) : getIRegA(regN) );
9563 assign( rMt, isT ? getIRegT(regM) : getIRegA(regM) );
9565 assign(res, binop(Iop_Sub16x2, mkexpr(rNt), mkexpr(rMt)));
9566 if (isT)
9567 putIRegT( regD, mkexpr(res), condT );
9568 else
9569 putIRegA( regD, mkexpr(res), condT, Ijk_Boring );
9571 assign(reso, unop(Iop_Not32,
9572 binop(Iop_HSub16Ux2, mkexpr(rNt), mkexpr(rMt))));
9573 set_GE_32_10_from_bits_31_15(reso, condT);
9575 DIP("usub16%s r%u, r%u, r%u\n", nCC(conq),regD,regN,regM);
9576 return True;
9578 /* fall through */
9581 /* -------------- ssub16<c> <Rd>,<Rn>,<Rm> -------------- */
9583 UInt regD = 99, regN = 99, regM = 99;
9584 Bool gate = False;
9586 if (isT) {
9587 if (INSNT0(15,4) == 0xFAD && (INSNT1(15,0) & 0xF0F0) == 0xF000) {
9588 regN = INSNT0(3,0);
9589 regD = INSNT1(11,8);
9590 regM = INSNT1(3,0);
9591 if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
9592 gate = True;
9594 } else {
9595 if (INSNA(27,20) == BITS8(0,1,1,0,0,0,0,1) &&
9596 INSNA(11,8) == BITS4(1,1,1,1) &&
9597 INSNA(7,4) == BITS4(0,1,1,1)) {
9598 regD = INSNA(15,12);
9599 regN = INSNA(19,16);
9600 regM = INSNA(3,0);
9601 if (regD != 15 && regN != 15 && regM != 15)
9602 gate = True;
9606 if (gate) {
9607 IRTemp rNt = newTemp(Ity_I32);
9608 IRTemp rMt = newTemp(Ity_I32);
9609 IRTemp res = newTemp(Ity_I32);
9610 IRTemp reso = newTemp(Ity_I32);
9612 assign( rNt, isT ? getIRegT(regN) : getIRegA(regN) );
9613 assign( rMt, isT ? getIRegT(regM) : getIRegA(regM) );
9615 assign(res, binop(Iop_Sub16x2, mkexpr(rNt), mkexpr(rMt)));
9616 if (isT)
9617 putIRegT( regD, mkexpr(res), condT );
9618 else
9619 putIRegA( regD, mkexpr(res), condT, Ijk_Boring );
9621 assign(reso, unop(Iop_Not32,
9622 binop(Iop_HSub16Sx2, mkexpr(rNt), mkexpr(rMt))));
9623 set_GE_32_10_from_bits_31_15(reso, condT);
9625 DIP("ssub16%s r%u, r%u, r%u\n", nCC(conq),regD,regN,regM);
9626 return True;
9628 /* fall through */
9631 /* ----------------- uadd8<c> <Rd>,<Rn>,<Rm> ---------------- */
9633 UInt regD = 99, regN = 99, regM = 99;
9634 Bool gate = False;
9636 if (isT) {
9637 if (INSNT0(15,4) == 0xFA8 && (INSNT1(15,0) & 0xF0F0) == 0xF040) {
9638 regN = INSNT0(3,0);
9639 regD = INSNT1(11,8);
9640 regM = INSNT1(3,0);
9641 if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
9642 gate = True;
9644 } else {
9645 if (INSNA(27,20) == BITS8(0,1,1,0,0,1,0,1) &&
9646 INSNA(11,8) == BITS4(1,1,1,1) &&
9647 (INSNA(7,4) == BITS4(1,0,0,1))) {
9648 regD = INSNA(15,12);
9649 regN = INSNA(19,16);
9650 regM = INSNA(3,0);
9651 if (regD != 15 && regN != 15 && regM != 15)
9652 gate = True;
9656 if (gate) {
9657 IRTemp rNt = newTemp(Ity_I32);
9658 IRTemp rMt = newTemp(Ity_I32);
9659 IRTemp res = newTemp(Ity_I32);
9660 IRTemp reso = newTemp(Ity_I32);
9662 assign( rNt, isT ? getIRegT(regN) : getIRegA(regN) );
9663 assign( rMt, isT ? getIRegT(regM) : getIRegA(regM) );
9665 assign(res, binop(Iop_Add8x4, mkexpr(rNt), mkexpr(rMt)));
9666 if (isT)
9667 putIRegT( regD, mkexpr(res), condT );
9668 else
9669 putIRegA( regD, mkexpr(res), condT, Ijk_Boring );
9671 assign(reso, binop(Iop_HAdd8Ux4, mkexpr(rNt), mkexpr(rMt)));
9672 set_GE_3_2_1_0_from_bits_31_23_15_7(reso, condT);
9674 DIP("uadd8%s r%u, r%u, r%u\n", nCC(conq),regD,regN,regM);
9675 return True;
9677 /* fall through */
9680 /* ------------------- sadd8<c> <Rd>,<Rn>,<Rm> ------------------ */
9682 UInt regD = 99, regN = 99, regM = 99;
9683 Bool gate = False;
9685 if (isT) {
9686 if (INSNT0(15,4) == 0xFA8 && (INSNT1(15,0) & 0xF0F0) == 0xF000) {
9687 regN = INSNT0(3,0);
9688 regD = INSNT1(11,8);
9689 regM = INSNT1(3,0);
9690 if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
9691 gate = True;
9693 } else {
9694 if (INSNA(27,20) == BITS8(0,1,1,0,0,0,0,1) &&
9695 INSNA(11,8) == BITS4(1,1,1,1) &&
9696 (INSNA(7,4) == BITS4(1,0,0,1))) {
9697 regD = INSNA(15,12);
9698 regN = INSNA(19,16);
9699 regM = INSNA(3,0);
9700 if (regD != 15 && regN != 15 && regM != 15)
9701 gate = True;
9705 if (gate) {
9706 IRTemp rNt = newTemp(Ity_I32);
9707 IRTemp rMt = newTemp(Ity_I32);
9708 IRTemp res = newTemp(Ity_I32);
9709 IRTemp reso = newTemp(Ity_I32);
9711 assign( rNt, isT ? getIRegT(regN) : getIRegA(regN) );
9712 assign( rMt, isT ? getIRegT(regM) : getIRegA(regM) );
9714 assign(res, binop(Iop_Add8x4, mkexpr(rNt), mkexpr(rMt)));
9715 if (isT)
9716 putIRegT( regD, mkexpr(res), condT );
9717 else
9718 putIRegA( regD, mkexpr(res), condT, Ijk_Boring );
9720 assign(reso, unop(Iop_Not32,
9721 binop(Iop_HAdd8Sx4, mkexpr(rNt), mkexpr(rMt))));
9722 set_GE_3_2_1_0_from_bits_31_23_15_7(reso, condT);
9724 DIP("sadd8%s r%u, r%u, r%u\n", nCC(conq),regD,regN,regM);
9725 return True;
9727 /* fall through */
9730 /* ------------------- usub8<c> <Rd>,<Rn>,<Rm> ------------------ */
9732 UInt regD = 99, regN = 99, regM = 99;
9733 Bool gate = False;
9735 if (isT) {
9736 if (INSNT0(15,4) == 0xFAC && (INSNT1(15,0) & 0xF0F0) == 0xF040) {
9737 regN = INSNT0(3,0);
9738 regD = INSNT1(11,8);
9739 regM = INSNT1(3,0);
9740 if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
9741 gate = True;
9743 } else {
9744 if (INSNA(27,20) == BITS8(0,1,1,0,0,1,0,1) &&
9745 INSNA(11,8) == BITS4(1,1,1,1) &&
9746 (INSNA(7,4) == BITS4(1,1,1,1))) {
9747 regD = INSNA(15,12);
9748 regN = INSNA(19,16);
9749 regM = INSNA(3,0);
9750 if (regD != 15 && regN != 15 && regM != 15)
9751 gate = True;
9755 if (gate) {
9756 IRTemp rNt = newTemp(Ity_I32);
9757 IRTemp rMt = newTemp(Ity_I32);
9758 IRTemp res = newTemp(Ity_I32);
9759 IRTemp reso = newTemp(Ity_I32);
9761 assign( rNt, isT ? getIRegT(regN) : getIRegA(regN) );
9762 assign( rMt, isT ? getIRegT(regM) : getIRegA(regM) );
9764 assign(res, binop(Iop_Sub8x4, mkexpr(rNt), mkexpr(rMt)));
9765 if (isT)
9766 putIRegT( regD, mkexpr(res), condT );
9767 else
9768 putIRegA( regD, mkexpr(res), condT, Ijk_Boring );
9770 assign(reso, unop(Iop_Not32,
9771 binop(Iop_HSub8Ux4, mkexpr(rNt), mkexpr(rMt))));
9772 set_GE_3_2_1_0_from_bits_31_23_15_7(reso, condT);
9774 DIP("usub8%s r%u, r%u, r%u\n", nCC(conq),regD,regN,regM);
9775 return True;
9777 /* fall through */
9780 /* ------------------- ssub8<c> <Rd>,<Rn>,<Rm> ------------------ */
9782 UInt regD = 99, regN = 99, regM = 99;
9783 Bool gate = False;
9785 if (isT) {
9786 if (INSNT0(15,4) == 0xFAC && (INSNT1(15,0) & 0xF0F0) == 0xF000) {
9787 regN = INSNT0(3,0);
9788 regD = INSNT1(11,8);
9789 regM = INSNT1(3,0);
9790 if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
9791 gate = True;
9793 } else {
9794 if (INSNA(27,20) == BITS8(0,1,1,0,0,0,0,1) &&
9795 INSNA(11,8) == BITS4(1,1,1,1) &&
9796 INSNA(7,4) == BITS4(1,1,1,1)) {
9797 regD = INSNA(15,12);
9798 regN = INSNA(19,16);
9799 regM = INSNA(3,0);
9800 if (regD != 15 && regN != 15 && regM != 15)
9801 gate = True;
9805 if (gate) {
9806 IRTemp rNt = newTemp(Ity_I32);
9807 IRTemp rMt = newTemp(Ity_I32);
9808 IRTemp res = newTemp(Ity_I32);
9809 IRTemp reso = newTemp(Ity_I32);
9811 assign( rNt, isT ? getIRegT(regN) : getIRegA(regN) );
9812 assign( rMt, isT ? getIRegT(regM) : getIRegA(regM) );
9814 assign(res, binop(Iop_Sub8x4, mkexpr(rNt), mkexpr(rMt)));
9815 if (isT)
9816 putIRegT( regD, mkexpr(res), condT );
9817 else
9818 putIRegA( regD, mkexpr(res), condT, Ijk_Boring );
9820 assign(reso, unop(Iop_Not32,
9821 binop(Iop_HSub8Sx4, mkexpr(rNt), mkexpr(rMt))));
9822 set_GE_3_2_1_0_from_bits_31_23_15_7(reso, condT);
9824 DIP("ssub8%s r%u, r%u, r%u\n", nCC(conq),regD,regN,regM);
9825 return True;
9827 /* fall through */
9830 /* ------------------ qadd8<c> <Rd>,<Rn>,<Rm> ------------------- */
9832 UInt regD = 99, regN = 99, regM = 99;
9833 Bool gate = False;
9835 if (isT) {
9836 if (INSNT0(15,4) == 0xFA8 && (INSNT1(15,0) & 0xF0F0) == 0xF010) {
9837 regN = INSNT0(3,0);
9838 regD = INSNT1(11,8);
9839 regM = INSNT1(3,0);
9840 if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
9841 gate = True;
9843 } else {
9844 if (INSNA(27,20) == BITS8(0,1,1,0,0,0,1,0) &&
9845 INSNA(11,8) == BITS4(1,1,1,1) &&
9846 INSNA(7,4) == BITS4(1,0,0,1)) {
9847 regD = INSNA(15,12);
9848 regN = INSNA(19,16);
9849 regM = INSNA(3,0);
9850 if (regD != 15 && regN != 15 && regM != 15)
9851 gate = True;
9855 if (gate) {
9856 IRTemp rNt = newTemp(Ity_I32);
9857 IRTemp rMt = newTemp(Ity_I32);
9858 IRTemp res_q = newTemp(Ity_I32);
9860 assign( rNt, isT ? getIRegT(regN) : getIRegA(regN) );
9861 assign( rMt, isT ? getIRegT(regM) : getIRegA(regM) );
9863 assign(res_q, binop(Iop_QAdd8Sx4, mkexpr(rNt), mkexpr(rMt)));
9864 if (isT)
9865 putIRegT( regD, mkexpr(res_q), condT );
9866 else
9867 putIRegA( regD, mkexpr(res_q), condT, Ijk_Boring );
9869 DIP("qadd8%s r%u, r%u, r%u\n", nCC(conq),regD,regN,regM);
9870 return True;
9872 /* fall through */
9875 /* ------------------ qsub8<c> <Rd>,<Rn>,<Rm> ------------------- */
9877 UInt regD = 99, regN = 99, regM = 99;
9878 Bool gate = False;
9880 if (isT) {
9881 if (INSNT0(15,4) == 0xFAC && (INSNT1(15,0) & 0xF0F0) == 0xF010) {
9882 regN = INSNT0(3,0);
9883 regD = INSNT1(11,8);
9884 regM = INSNT1(3,0);
9885 if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
9886 gate = True;
9888 } else {
9889 if (INSNA(27,20) == BITS8(0,1,1,0,0,0,1,0) &&
9890 INSNA(11,8) == BITS4(1,1,1,1) &&
9891 INSNA(7,4) == BITS4(1,1,1,1)) {
9892 regD = INSNA(15,12);
9893 regN = INSNA(19,16);
9894 regM = INSNA(3,0);
9895 if (regD != 15 && regN != 15 && regM != 15)
9896 gate = True;
9900 if (gate) {
9901 IRTemp rNt = newTemp(Ity_I32);
9902 IRTemp rMt = newTemp(Ity_I32);
9903 IRTemp res_q = newTemp(Ity_I32);
9905 assign( rNt, isT ? getIRegT(regN) : getIRegA(regN) );
9906 assign( rMt, isT ? getIRegT(regM) : getIRegA(regM) );
9908 assign(res_q, binop(Iop_QSub8Sx4, mkexpr(rNt), mkexpr(rMt)));
9909 if (isT)
9910 putIRegT( regD, mkexpr(res_q), condT );
9911 else
9912 putIRegA( regD, mkexpr(res_q), condT, Ijk_Boring );
9914 DIP("qsub8%s r%u, r%u, r%u\n", nCC(conq),regD,regN,regM);
9915 return True;
9917 /* fall through */
9920 /* ------------------ uqadd8<c> <Rd>,<Rn>,<Rm> ------------------ */
9922 UInt regD = 99, regN = 99, regM = 99;
9923 Bool gate = False;
9925 if (isT) {
9926 if (INSNT0(15,4) == 0xFA8 && (INSNT1(15,0) & 0xF0F0) == 0xF050) {
9927 regN = INSNT0(3,0);
9928 regD = INSNT1(11,8);
9929 regM = INSNT1(3,0);
9930 if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
9931 gate = True;
9933 } else {
9934 if (INSNA(27,20) == BITS8(0,1,1,0,0,1,1,0) &&
9935 INSNA(11,8) == BITS4(1,1,1,1) &&
9936 (INSNA(7,4) == BITS4(1,0,0,1))) {
9937 regD = INSNA(15,12);
9938 regN = INSNA(19,16);
9939 regM = INSNA(3,0);
9940 if (regD != 15 && regN != 15 && regM != 15)
9941 gate = True;
9945 if (gate) {
9946 IRTemp rNt = newTemp(Ity_I32);
9947 IRTemp rMt = newTemp(Ity_I32);
9948 IRTemp res_q = newTemp(Ity_I32);
9950 assign( rNt, isT ? getIRegT(regN) : getIRegA(regN) );
9951 assign( rMt, isT ? getIRegT(regM) : getIRegA(regM) );
9953 assign(res_q, binop(Iop_QAdd8Ux4, mkexpr(rNt), mkexpr(rMt)));
9954 if (isT)
9955 putIRegT( regD, mkexpr(res_q), condT );
9956 else
9957 putIRegA( regD, mkexpr(res_q), condT, Ijk_Boring );
9959 DIP("uqadd8%s r%u, r%u, r%u\n", nCC(conq),regD,regN,regM);
9960 return True;
9962 /* fall through */
9965 /* ------------------ uqsub8<c> <Rd>,<Rn>,<Rm> ------------------ */
9967 UInt regD = 99, regN = 99, regM = 99;
9968 Bool gate = False;
9970 if (isT) {
9971 if (INSNT0(15,4) == 0xFAC && (INSNT1(15,0) & 0xF0F0) == 0xF050) {
9972 regN = INSNT0(3,0);
9973 regD = INSNT1(11,8);
9974 regM = INSNT1(3,0);
9975 if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
9976 gate = True;
9978 } else {
9979 if (INSNA(27,20) == BITS8(0,1,1,0,0,1,1,0) &&
9980 INSNA(11,8) == BITS4(1,1,1,1) &&
9981 (INSNA(7,4) == BITS4(1,1,1,1))) {
9982 regD = INSNA(15,12);
9983 regN = INSNA(19,16);
9984 regM = INSNA(3,0);
9985 if (regD != 15 && regN != 15 && regM != 15)
9986 gate = True;
9990 if (gate) {
9991 IRTemp rNt = newTemp(Ity_I32);
9992 IRTemp rMt = newTemp(Ity_I32);
9993 IRTemp res_q = newTemp(Ity_I32);
9995 assign( rNt, isT ? getIRegT(regN) : getIRegA(regN) );
9996 assign( rMt, isT ? getIRegT(regM) : getIRegA(regM) );
9998 assign(res_q, binop(Iop_QSub8Ux4, mkexpr(rNt), mkexpr(rMt)));
9999 if (isT)
10000 putIRegT( regD, mkexpr(res_q), condT );
10001 else
10002 putIRegA( regD, mkexpr(res_q), condT, Ijk_Boring );
10004 DIP("uqsub8%s r%u, r%u, r%u\n", nCC(conq),regD,regN,regM);
10005 return True;
10007 /* fall through */
10010 /* ----------------- uhadd8<c> <Rd>,<Rn>,<Rm> ------------------- */
10012 UInt regD = 99, regN = 99, regM = 99;
10013 Bool gate = False;
10015 if (isT) {
10016 if (INSNT0(15,4) == 0xFA8 && (INSNT1(15,0) & 0xF0F0) == 0xF060) {
10017 regN = INSNT0(3,0);
10018 regD = INSNT1(11,8);
10019 regM = INSNT1(3,0);
10020 if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
10021 gate = True;
10023 } else {
10024 if (INSNA(27,20) == BITS8(0,1,1,0,0,1,1,1) &&
10025 INSNA(11,8) == BITS4(1,1,1,1) &&
10026 INSNA(7,4) == BITS4(1,0,0,1)) {
10027 regD = INSNA(15,12);
10028 regN = INSNA(19,16);
10029 regM = INSNA(3,0);
10030 if (regD != 15 && regN != 15 && regM != 15)
10031 gate = True;
10035 if (gate) {
10036 IRTemp rNt = newTemp(Ity_I32);
10037 IRTemp rMt = newTemp(Ity_I32);
10038 IRTemp res_q = newTemp(Ity_I32);
10040 assign( rNt, isT ? getIRegT(regN) : getIRegA(regN) );
10041 assign( rMt, isT ? getIRegT(regM) : getIRegA(regM) );
10043 assign(res_q, binop(Iop_HAdd8Ux4, mkexpr(rNt), mkexpr(rMt)));
10044 if (isT)
10045 putIRegT( regD, mkexpr(res_q), condT );
10046 else
10047 putIRegA( regD, mkexpr(res_q), condT, Ijk_Boring );
10049 DIP("uhadd8%s r%u, r%u, r%u\n", nCC(conq),regD,regN,regM);
10050 return True;
10052 /* fall through */
10055 /* ----------------- uhadd16<c> <Rd>,<Rn>,<Rm> ------------------- */
10057 UInt regD = 99, regN = 99, regM = 99;
10058 Bool gate = False;
10060 if (isT) {
10061 if (INSNT0(15,4) == 0xFA9 && (INSNT1(15,0) & 0xF0F0) == 0xF060) {
10062 regN = INSNT0(3,0);
10063 regD = INSNT1(11,8);
10064 regM = INSNT1(3,0);
10065 if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
10066 gate = True;
10068 } else {
10069 if (INSNA(27,20) == BITS8(0,1,1,0,0,1,1,1) &&
10070 INSNA(11,8) == BITS4(1,1,1,1) &&
10071 INSNA(7,4) == BITS4(0,0,0,1)) {
10072 regD = INSNA(15,12);
10073 regN = INSNA(19,16);
10074 regM = INSNA(3,0);
10075 if (regD != 15 && regN != 15 && regM != 15)
10076 gate = True;
10080 if (gate) {
10081 IRTemp rNt = newTemp(Ity_I32);
10082 IRTemp rMt = newTemp(Ity_I32);
10083 IRTemp res_q = newTemp(Ity_I32);
10085 assign( rNt, isT ? getIRegT(regN) : getIRegA(regN) );
10086 assign( rMt, isT ? getIRegT(regM) : getIRegA(regM) );
10088 assign(res_q, binop(Iop_HAdd16Ux2, mkexpr(rNt), mkexpr(rMt)));
10089 if (isT)
10090 putIRegT( regD, mkexpr(res_q), condT );
10091 else
10092 putIRegA( regD, mkexpr(res_q), condT, Ijk_Boring );
10094 DIP("uhadd16%s r%u, r%u, r%u\n", nCC(conq),regD,regN,regM);
10095 return True;
10097 /* fall through */
10100 /* ----------------- shadd8<c> <Rd>,<Rn>,<Rm> ------------------- */
10102 UInt regD = 99, regN = 99, regM = 99;
10103 Bool gate = False;
10105 if (isT) {
10106 if (INSNT0(15,4) == 0xFA8 && (INSNT1(15,0) & 0xF0F0) == 0xF020) {
10107 regN = INSNT0(3,0);
10108 regD = INSNT1(11,8);
10109 regM = INSNT1(3,0);
10110 if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
10111 gate = True;
10113 } else {
10114 if (INSNA(27,20) == BITS8(0,1,1,0,0,0,1,1) &&
10115 INSNA(11,8) == BITS4(1,1,1,1) &&
10116 INSNA(7,4) == BITS4(1,0,0,1)) {
10117 regD = INSNA(15,12);
10118 regN = INSNA(19,16);
10119 regM = INSNA(3,0);
10120 if (regD != 15 && regN != 15 && regM != 15)
10121 gate = True;
10125 if (gate) {
10126 IRTemp rNt = newTemp(Ity_I32);
10127 IRTemp rMt = newTemp(Ity_I32);
10128 IRTemp res_q = newTemp(Ity_I32);
10130 assign( rNt, isT ? getIRegT(regN) : getIRegA(regN) );
10131 assign( rMt, isT ? getIRegT(regM) : getIRegA(regM) );
10133 assign(res_q, binop(Iop_HAdd8Sx4, mkexpr(rNt), mkexpr(rMt)));
10134 if (isT)
10135 putIRegT( regD, mkexpr(res_q), condT );
10136 else
10137 putIRegA( regD, mkexpr(res_q), condT, Ijk_Boring );
10139 DIP("shadd8%s r%u, r%u, r%u\n", nCC(conq),regD,regN,regM);
10140 return True;
10142 /* fall through */
10145 /* ------------------ qadd16<c> <Rd>,<Rn>,<Rm> ------------------ */
10147 UInt regD = 99, regN = 99, regM = 99;
10148 Bool gate = False;
10150 if (isT) {
10151 if (INSNT0(15,4) == 0xFA9 && (INSNT1(15,0) & 0xF0F0) == 0xF010) {
10152 regN = INSNT0(3,0);
10153 regD = INSNT1(11,8);
10154 regM = INSNT1(3,0);
10155 if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
10156 gate = True;
10158 } else {
10159 if (INSNA(27,20) == BITS8(0,1,1,0,0,0,1,0) &&
10160 INSNA(11,8) == BITS4(1,1,1,1) &&
10161 INSNA(7,4) == BITS4(0,0,0,1)) {
10162 regD = INSNA(15,12);
10163 regN = INSNA(19,16);
10164 regM = INSNA(3,0);
10165 if (regD != 15 && regN != 15 && regM != 15)
10166 gate = True;
10170 if (gate) {
10171 IRTemp rNt = newTemp(Ity_I32);
10172 IRTemp rMt = newTemp(Ity_I32);
10173 IRTemp res_q = newTemp(Ity_I32);
10175 assign( rNt, isT ? getIRegT(regN) : getIRegA(regN) );
10176 assign( rMt, isT ? getIRegT(regM) : getIRegA(regM) );
10178 assign(res_q, binop(Iop_QAdd16Sx2, mkexpr(rNt), mkexpr(rMt)));
10179 if (isT)
10180 putIRegT( regD, mkexpr(res_q), condT );
10181 else
10182 putIRegA( regD, mkexpr(res_q), condT, Ijk_Boring );
10184 DIP("qadd16%s r%u, r%u, r%u\n", nCC(conq),regD,regN,regM);
10185 return True;
10187 /* fall through */
10190 /* ------------------ qsub16<c> <Rd>,<Rn>,<Rm> ------------------ */
10192 UInt regD = 99, regN = 99, regM = 99;
10193 Bool gate = False;
10195 if (isT) {
10196 if (INSNT0(15,4) == 0xFAD && (INSNT1(15,0) & 0xF0F0) == 0xF010) {
10197 regN = INSNT0(3,0);
10198 regD = INSNT1(11,8);
10199 regM = INSNT1(3,0);
10200 if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
10201 gate = True;
10203 } else {
10204 if (INSNA(27,20) == BITS8(0,1,1,0,0,0,1,0) &&
10205 INSNA(11,8) == BITS4(1,1,1,1) &&
10206 INSNA(7,4) == BITS4(0,1,1,1)) {
10207 regD = INSNA(15,12);
10208 regN = INSNA(19,16);
10209 regM = INSNA(3,0);
10210 if (regD != 15 && regN != 15 && regM != 15)
10211 gate = True;
10215 if (gate) {
10216 IRTemp rNt = newTemp(Ity_I32);
10217 IRTemp rMt = newTemp(Ity_I32);
10218 IRTemp res_q = newTemp(Ity_I32);
10220 assign( rNt, isT ? getIRegT(regN) : getIRegA(regN) );
10221 assign( rMt, isT ? getIRegT(regM) : getIRegA(regM) );
10223 assign(res_q, binop(Iop_QSub16Sx2, mkexpr(rNt), mkexpr(rMt)));
10224 if (isT)
10225 putIRegT( regD, mkexpr(res_q), condT );
10226 else
10227 putIRegA( regD, mkexpr(res_q), condT, Ijk_Boring );
10229 DIP("qsub16%s r%u, r%u, r%u\n", nCC(conq),regD,regN,regM);
10230 return True;
10232 /* fall through */
10235 /* ------------------- qsax<c> <Rd>,<Rn>,<Rm> ------------------- */
10236 /* note: the hardware seems to construct the result differently
10237 from wot the manual says. */
10239 UInt regD = 99, regN = 99, regM = 99;
10240 Bool gate = False;
10242 if (isT) {
10243 if (INSNT0(15,4) == 0xFAE && (INSNT1(15,0) & 0xF0F0) == 0xF010) {
10244 regN = INSNT0(3,0);
10245 regD = INSNT1(11,8);
10246 regM = INSNT1(3,0);
10247 if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
10248 gate = True;
10250 } else {
10251 if (INSNA(27,20) == BITS8(0,1,1,0,0,0,1,0) &&
10252 INSNA(11,8) == BITS4(1,1,1,1) &&
10253 INSNA(7,4) == BITS4(0,1,0,1)) {
10254 regD = INSNA(15,12);
10255 regN = INSNA(19,16);
10256 regM = INSNA(3,0);
10257 if (regD != 15 && regN != 15 && regM != 15)
10258 gate = True;
10262 if (gate) {
10263 IRTemp irt_regN = newTemp(Ity_I32);
10264 IRTemp irt_regM = newTemp(Ity_I32);
10265 IRTemp irt_sum = newTemp(Ity_I32);
10266 IRTemp irt_diff = newTemp(Ity_I32);
10267 IRTemp irt_sum_res = newTemp(Ity_I32);
10268 IRTemp irt_diff_res = newTemp(Ity_I32);
10270 assign( irt_regN, isT ? getIRegT(regN) : getIRegA(regN) );
10271 assign( irt_regM, isT ? getIRegT(regM) : getIRegA(regM) );
10273 assign( irt_diff,
10274 binop( Iop_Sub32,
10275 binop( Iop_Sar32, mkexpr(irt_regN), mkU8(16) ),
10276 binop( Iop_Sar32,
10277 binop(Iop_Shl32, mkexpr(irt_regM), mkU8(16)),
10278 mkU8(16) ) ) );
10279 armSignedSatQ( irt_diff, 0x10, &irt_diff_res, NULL);
10281 assign( irt_sum,
10282 binop( Iop_Add32,
10283 binop( Iop_Sar32,
10284 binop( Iop_Shl32, mkexpr(irt_regN), mkU8(16) ),
10285 mkU8(16) ),
10286 binop( Iop_Sar32, mkexpr(irt_regM), mkU8(16) )) );
10287 armSignedSatQ( irt_sum, 0x10, &irt_sum_res, NULL );
10289 IRExpr* ire_result = binop( Iop_Or32,
10290 binop( Iop_Shl32, mkexpr(irt_diff_res),
10291 mkU8(16) ),
10292 binop( Iop_And32, mkexpr(irt_sum_res),
10293 mkU32(0xFFFF)) );
10295 if (isT)
10296 putIRegT( regD, ire_result, condT );
10297 else
10298 putIRegA( regD, ire_result, condT, Ijk_Boring );
10300 DIP( "qsax%s r%u, r%u, r%u\n", nCC(conq), regD, regN, regM );
10301 return True;
10303 /* fall through */
10306 /* ------------------- qasx<c> <Rd>,<Rn>,<Rm> ------------------- */
10308 UInt regD = 99, regN = 99, regM = 99;
10309 Bool gate = False;
10311 if (isT) {
10312 if (INSNT0(15,4) == 0xFAA && (INSNT1(15,0) & 0xF0F0) == 0xF010) {
10313 regN = INSNT0(3,0);
10314 regD = INSNT1(11,8);
10315 regM = INSNT1(3,0);
10316 if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
10317 gate = True;
10319 } else {
10320 if (INSNA(27,20) == BITS8(0,1,1,0,0,0,1,0) &&
10321 INSNA(11,8) == BITS4(1,1,1,1) &&
10322 INSNA(7,4) == BITS4(0,0,1,1)) {
10323 regD = INSNA(15,12);
10324 regN = INSNA(19,16);
10325 regM = INSNA(3,0);
10326 if (regD != 15 && regN != 15 && regM != 15)
10327 gate = True;
10331 if (gate) {
10332 IRTemp irt_regN = newTemp(Ity_I32);
10333 IRTemp irt_regM = newTemp(Ity_I32);
10334 IRTemp irt_sum = newTemp(Ity_I32);
10335 IRTemp irt_diff = newTemp(Ity_I32);
10336 IRTemp irt_res_sum = newTemp(Ity_I32);
10337 IRTemp irt_res_diff = newTemp(Ity_I32);
10339 assign( irt_regN, isT ? getIRegT(regN) : getIRegA(regN) );
10340 assign( irt_regM, isT ? getIRegT(regM) : getIRegA(regM) );
10342 assign( irt_diff,
10343 binop( Iop_Sub32,
10344 binop( Iop_Sar32,
10345 binop( Iop_Shl32, mkexpr(irt_regN), mkU8(16) ),
10346 mkU8(16) ),
10347 binop( Iop_Sar32, mkexpr(irt_regM), mkU8(16) ) ) );
10348 armSignedSatQ( irt_diff, 0x10, &irt_res_diff, NULL );
10350 assign( irt_sum,
10351 binop( Iop_Add32,
10352 binop( Iop_Sar32, mkexpr(irt_regN), mkU8(16) ),
10353 binop( Iop_Sar32,
10354 binop( Iop_Shl32, mkexpr(irt_regM), mkU8(16) ),
10355 mkU8(16) ) ) );
10356 armSignedSatQ( irt_sum, 0x10, &irt_res_sum, NULL );
10358 IRExpr* ire_result
10359 = binop( Iop_Or32,
10360 binop( Iop_Shl32, mkexpr(irt_res_sum), mkU8(16) ),
10361 binop( Iop_And32, mkexpr(irt_res_diff), mkU32(0xFFFF) ) );
10363 if (isT)
10364 putIRegT( regD, ire_result, condT );
10365 else
10366 putIRegA( regD, ire_result, condT, Ijk_Boring );
10368 DIP( "qasx%s r%u, r%u, r%u\n", nCC(conq), regD, regN, regM );
10369 return True;
10371 /* fall through */
10374 /* ------------------- sasx<c> <Rd>,<Rn>,<Rm> ------------------- */
10376 UInt regD = 99, regN = 99, regM = 99;
10377 Bool gate = False;
10379 if (isT) {
10380 if (INSNT0(15,4) == 0xFAA && (INSNT1(15,0) & 0xF0F0) == 0xF000) {
10381 regN = INSNT0(3,0);
10382 regD = INSNT1(11,8);
10383 regM = INSNT1(3,0);
10384 if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
10385 gate = True;
10387 } else {
10388 if (INSNA(27,20) == BITS8(0,1,1,0,0,0,0,1) &&
10389 INSNA(11,8) == BITS4(1,1,1,1) &&
10390 INSNA(7,4) == BITS4(0,0,1,1)) {
10391 regD = INSNA(15,12);
10392 regN = INSNA(19,16);
10393 regM = INSNA(3,0);
10394 if (regD != 15 && regN != 15 && regM != 15)
10395 gate = True;
10399 if (gate) {
10400 IRTemp irt_regN = newTemp(Ity_I32);
10401 IRTemp irt_regM = newTemp(Ity_I32);
10402 IRTemp irt_sum = newTemp(Ity_I32);
10403 IRTemp irt_diff = newTemp(Ity_I32);
10405 assign( irt_regN, isT ? getIRegT(regN) : getIRegA(regN) );
10406 assign( irt_regM, isT ? getIRegT(regM) : getIRegA(regM) );
10408 assign( irt_diff,
10409 binop( Iop_Sub32,
10410 binop( Iop_Sar32,
10411 binop( Iop_Shl32, mkexpr(irt_regN), mkU8(16) ),
10412 mkU8(16) ),
10413 binop( Iop_Sar32, mkexpr(irt_regM), mkU8(16) ) ) );
10415 assign( irt_sum,
10416 binop( Iop_Add32,
10417 binop( Iop_Sar32, mkexpr(irt_regN), mkU8(16) ),
10418 binop( Iop_Sar32,
10419 binop( Iop_Shl32, mkexpr(irt_regM), mkU8(16) ),
10420 mkU8(16) ) ) );
10422 IRExpr* ire_result
10423 = binop( Iop_Or32,
10424 binop( Iop_Shl32, mkexpr(irt_sum), mkU8(16) ),
10425 binop( Iop_And32, mkexpr(irt_diff), mkU32(0xFFFF) ) );
10427 IRTemp ge10 = newTemp(Ity_I32);
10428 assign(ge10, unop(Iop_Not32, mkexpr(irt_diff)));
10429 put_GEFLAG32( 0, 31, mkexpr(ge10), condT );
10430 put_GEFLAG32( 1, 31, mkexpr(ge10), condT );
10432 IRTemp ge32 = newTemp(Ity_I32);
10433 assign(ge32, unop(Iop_Not32, mkexpr(irt_sum)));
10434 put_GEFLAG32( 2, 31, mkexpr(ge32), condT );
10435 put_GEFLAG32( 3, 31, mkexpr(ge32), condT );
10437 if (isT)
10438 putIRegT( regD, ire_result, condT );
10439 else
10440 putIRegA( regD, ire_result, condT, Ijk_Boring );
10442 DIP( "sasx%s r%u, r%u, r%u\n", nCC(conq), regD, regN, regM );
10443 return True;
10445 /* fall through */
10448 /* --------------- smuad, smuadx<c><Rd>,<Rn>,<Rm> --------------- */
10449 /* --------------- smsad, smsadx<c><Rd>,<Rn>,<Rm> --------------- */
10451 UInt regD = 99, regN = 99, regM = 99, bitM = 99;
10452 Bool gate = False, isAD = False;
10454 if (isT) {
10455 if ((INSNT0(15,4) == 0xFB2 || INSNT0(15,4) == 0xFB4)
10456 && (INSNT1(15,0) & 0xF0E0) == 0xF000) {
10457 regN = INSNT0(3,0);
10458 regD = INSNT1(11,8);
10459 regM = INSNT1(3,0);
10460 bitM = INSNT1(4,4);
10461 isAD = INSNT0(15,4) == 0xFB2;
10462 if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
10463 gate = True;
10465 } else {
10466 if (INSNA(27,20) == BITS8(0,1,1,1,0,0,0,0) &&
10467 INSNA(15,12) == BITS4(1,1,1,1) &&
10468 (INSNA(7,4) & BITS4(1,0,0,1)) == BITS4(0,0,0,1) ) {
10469 regD = INSNA(19,16);
10470 regN = INSNA(3,0);
10471 regM = INSNA(11,8);
10472 bitM = INSNA(5,5);
10473 isAD = INSNA(6,6) == 0;
10474 if (regD != 15 && regN != 15 && regM != 15)
10475 gate = True;
10479 if (gate) {
10480 IRTemp irt_regN = newTemp(Ity_I32);
10481 IRTemp irt_regM = newTemp(Ity_I32);
10482 IRTemp irt_prod_lo = newTemp(Ity_I32);
10483 IRTemp irt_prod_hi = newTemp(Ity_I32);
10484 IRTemp tmpM = newTemp(Ity_I32);
10486 assign( irt_regN, isT ? getIRegT(regN) : getIRegA(regN) );
10488 assign( tmpM, isT ? getIRegT(regM) : getIRegA(regM) );
10489 assign( irt_regM, genROR32(tmpM, (bitM & 1) ? 16 : 0) );
10491 assign( irt_prod_lo,
10492 binop( Iop_Mul32,
10493 binop( Iop_Sar32,
10494 binop(Iop_Shl32, mkexpr(irt_regN), mkU8(16)),
10495 mkU8(16) ),
10496 binop( Iop_Sar32,
10497 binop(Iop_Shl32, mkexpr(irt_regM), mkU8(16)),
10498 mkU8(16) ) ) );
10499 assign( irt_prod_hi, binop(Iop_Mul32,
10500 binop(Iop_Sar32, mkexpr(irt_regN), mkU8(16)),
10501 binop(Iop_Sar32, mkexpr(irt_regM), mkU8(16))) );
10502 IRExpr* ire_result
10503 = binop( isAD ? Iop_Add32 : Iop_Sub32,
10504 mkexpr(irt_prod_lo), mkexpr(irt_prod_hi) );
10506 if (isT)
10507 putIRegT( regD, ire_result, condT );
10508 else
10509 putIRegA( regD, ire_result, condT, Ijk_Boring );
10511 if (isAD) {
10512 or_into_QFLAG32(
10513 signed_overflow_after_Add32( ire_result,
10514 irt_prod_lo, irt_prod_hi ),
10515 condT
10519 DIP("smu%cd%s%s r%u, r%u, r%u\n",
10520 isAD ? 'a' : 's',
10521 bitM ? "x" : "", nCC(conq), regD, regN, regM);
10522 return True;
10524 /* fall through */
10527 /* --------------- smlad{X}<c> <Rd>,<Rn>,<Rm>,<Ra> -------------- */
10528 /* --------------- smlsd{X}<c> <Rd>,<Rn>,<Rm>,<Ra> -------------- */
10530 UInt regD = 99, regN = 99, regM = 99, regA = 99, bitM = 99;
10531 Bool gate = False, isAD = False;
10533 if (isT) {
10534 if ((INSNT0(15,4) == 0xFB2 || INSNT0(15,4) == 0xFB4)
10535 && INSNT1(7,5) == BITS3(0,0,0)) {
10536 regN = INSNT0(3,0);
10537 regD = INSNT1(11,8);
10538 regM = INSNT1(3,0);
10539 regA = INSNT1(15,12);
10540 bitM = INSNT1(4,4);
10541 isAD = INSNT0(15,4) == 0xFB2;
10542 if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM)
10543 && !isBadRegT(regA))
10544 gate = True;
10546 } else {
10547 if (INSNA(27,20) == BITS8(0,1,1,1,0,0,0,0) &&
10548 (INSNA(7,4) & BITS4(1,0,0,1)) == BITS4(0,0,0,1)) {
10549 regD = INSNA(19,16);
10550 regA = INSNA(15,12);
10551 regN = INSNA(3,0);
10552 regM = INSNA(11,8);
10553 bitM = INSNA(5,5);
10554 isAD = INSNA(6,6) == 0;
10555 if (regD != 15 && regN != 15 && regM != 15 && regA != 15)
10556 gate = True;
10560 if (gate) {
10561 IRTemp irt_regN = newTemp(Ity_I32);
10562 IRTemp irt_regM = newTemp(Ity_I32);
10563 IRTemp irt_regA = newTemp(Ity_I32);
10564 IRTemp irt_prod_lo = newTemp(Ity_I32);
10565 IRTemp irt_prod_hi = newTemp(Ity_I32);
10566 IRTemp irt_sum = newTemp(Ity_I32);
10567 IRTemp tmpM = newTemp(Ity_I32);
10569 assign( irt_regN, isT ? getIRegT(regN) : getIRegA(regN) );
10570 assign( irt_regA, isT ? getIRegT(regA) : getIRegA(regA) );
10572 assign( tmpM, isT ? getIRegT(regM) : getIRegA(regM) );
10573 assign( irt_regM, genROR32(tmpM, (bitM & 1) ? 16 : 0) );
10575 assign( irt_prod_lo,
10576 binop(Iop_Mul32,
10577 binop(Iop_Sar32,
10578 binop( Iop_Shl32, mkexpr(irt_regN), mkU8(16) ),
10579 mkU8(16)),
10580 binop(Iop_Sar32,
10581 binop( Iop_Shl32, mkexpr(irt_regM), mkU8(16) ),
10582 mkU8(16))) );
10583 assign( irt_prod_hi,
10584 binop( Iop_Mul32,
10585 binop( Iop_Sar32, mkexpr(irt_regN), mkU8(16) ),
10586 binop( Iop_Sar32, mkexpr(irt_regM), mkU8(16) ) ) );
10587 assign( irt_sum, binop( isAD ? Iop_Add32 : Iop_Sub32,
10588 mkexpr(irt_prod_lo), mkexpr(irt_prod_hi) ) );
10590 IRExpr* ire_result = binop(Iop_Add32, mkexpr(irt_sum), mkexpr(irt_regA));
10592 if (isT)
10593 putIRegT( regD, ire_result, condT );
10594 else
10595 putIRegA( regD, ire_result, condT, Ijk_Boring );
10597 if (isAD) {
10598 or_into_QFLAG32(
10599 signed_overflow_after_Add32( mkexpr(irt_sum),
10600 irt_prod_lo, irt_prod_hi ),
10601 condT
10605 or_into_QFLAG32(
10606 signed_overflow_after_Add32( ire_result, irt_sum, irt_regA ),
10607 condT
10610 DIP("sml%cd%s%s r%u, r%u, r%u, r%u\n",
10611 isAD ? 'a' : 's',
10612 bitM ? "x" : "", nCC(conq), regD, regN, regM, regA);
10613 return True;
10615 /* fall through */
10618 /* ----- smlabb, smlabt, smlatb, smlatt <Rd>,<Rn>,<Rm>,<Ra> ----- */
10620 UInt regD = 99, regN = 99, regM = 99, regA = 99, bitM = 99, bitN = 99;
10621 Bool gate = False;
10623 if (isT) {
10624 if (INSNT0(15,4) == 0xFB1 && INSNT1(7,6) == BITS2(0,0)) {
10625 regN = INSNT0(3,0);
10626 regD = INSNT1(11,8);
10627 regM = INSNT1(3,0);
10628 regA = INSNT1(15,12);
10629 bitM = INSNT1(4,4);
10630 bitN = INSNT1(5,5);
10631 if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM)
10632 && !isBadRegT(regA))
10633 gate = True;
10635 } else {
10636 if (INSNA(27,20) == BITS8(0,0,0,1,0,0,0,0) &&
10637 (INSNA(7,4) & BITS4(1,0,0,1)) == BITS4(1,0,0,0)) {
10638 regD = INSNA(19,16);
10639 regN = INSNA(3,0);
10640 regM = INSNA(11,8);
10641 regA = INSNA(15,12);
10642 bitM = INSNA(6,6);
10643 bitN = INSNA(5,5);
10644 if (regD != 15 && regN != 15 && regM != 15 && regA != 15)
10645 gate = True;
10649 if (gate) {
10650 IRTemp irt_regA = newTemp(Ity_I32);
10651 IRTemp irt_prod = newTemp(Ity_I32);
10653 assign( irt_prod,
10654 binop(Iop_Mul32,
10655 binop(Iop_Sar32,
10656 binop(Iop_Shl32,
10657 isT ? getIRegT(regN) : getIRegA(regN),
10658 mkU8(bitN ? 0 : 16)),
10659 mkU8(16)),
10660 binop(Iop_Sar32,
10661 binop(Iop_Shl32,
10662 isT ? getIRegT(regM) : getIRegA(regM),
10663 mkU8(bitM ? 0 : 16)),
10664 mkU8(16))) );
10666 assign( irt_regA, isT ? getIRegT(regA) : getIRegA(regA) );
10668 IRExpr* ire_result = binop(Iop_Add32, mkexpr(irt_prod), mkexpr(irt_regA));
10670 if (isT)
10671 putIRegT( regD, ire_result, condT );
10672 else
10673 putIRegA( regD, ire_result, condT, Ijk_Boring );
10675 or_into_QFLAG32(
10676 signed_overflow_after_Add32( ire_result, irt_prod, irt_regA ),
10677 condT
10680 DIP( "smla%c%c%s r%u, r%u, r%u, r%u\n",
10681 bitN ? 't' : 'b', bitM ? 't' : 'b',
10682 nCC(conq), regD, regN, regM, regA );
10683 return True;
10685 /* fall through */
10688 /* ----- smlalbb, smlalbt, smlaltb, smlaltt <Rd>,<Rn>,<Rm>,<Ra> ----- */
10690 UInt regDHi = 99, regN = 99, regM = 99, regDLo = 99, bitM = 99, bitN = 99;
10691 Bool gate = False;
10693 if (isT) {
10694 if (INSNT0(15,4) == 0xFBC && INSNT1(7,6) == BITS2(1,0)) {
10695 regN = INSNT0(3,0);
10696 regDHi = INSNT1(11,8);
10697 regM = INSNT1(3,0);
10698 regDLo = INSNT1(15,12);
10699 bitM = INSNT1(4,4);
10700 bitN = INSNT1(5,5);
10701 if (!isBadRegT(regDHi) && !isBadRegT(regN) && !isBadRegT(regM)
10702 && !isBadRegT(regDLo) && regDHi != regDLo)
10703 gate = True;
10705 } else {
10706 if (INSNA(27,20) == BITS8(0,0,0,1,0,1,0,0) &&
10707 (INSNA(7,4) & BITS4(1,0,0,1)) == BITS4(1,0,0,0)) {
10708 regDHi = INSNA(19,16);
10709 regN = INSNA(3,0);
10710 regM = INSNA(11,8);
10711 regDLo = INSNA(15,12);
10712 bitM = INSNA(6,6);
10713 bitN = INSNA(5,5);
10714 if (regDHi != 15 && regN != 15 && regM != 15 && regDLo != 15 &&
10715 regDHi != regDLo)
10716 gate = True;
10720 if (gate) {
10721 IRTemp irt_regD = newTemp(Ity_I64);
10722 IRTemp irt_prod = newTemp(Ity_I64);
10723 IRTemp irt_res = newTemp(Ity_I64);
10724 IRTemp irt_resHi = newTemp(Ity_I32);
10725 IRTemp irt_resLo = newTemp(Ity_I32);
10727 assign( irt_prod,
10728 binop(Iop_MullS32,
10729 binop(Iop_Sar32,
10730 binop(Iop_Shl32,
10731 isT ? getIRegT(regN) : getIRegA(regN),
10732 mkU8(bitN ? 0 : 16)),
10733 mkU8(16)),
10734 binop(Iop_Sar32,
10735 binop(Iop_Shl32,
10736 isT ? getIRegT(regM) : getIRegA(regM),
10737 mkU8(bitM ? 0 : 16)),
10738 mkU8(16))) );
10740 assign( irt_regD, binop(Iop_32HLto64,
10741 isT ? getIRegT(regDHi) : getIRegA(regDHi),
10742 isT ? getIRegT(regDLo) : getIRegA(regDLo)) );
10743 assign( irt_res, binop(Iop_Add64, mkexpr(irt_regD), mkexpr(irt_prod)) );
10744 assign( irt_resHi, unop(Iop_64HIto32, mkexpr(irt_res)) );
10745 assign( irt_resLo, unop(Iop_64to32, mkexpr(irt_res)) );
10747 if (isT) {
10748 putIRegT( regDHi, mkexpr(irt_resHi), condT );
10749 putIRegT( regDLo, mkexpr(irt_resLo), condT );
10750 } else {
10751 putIRegA( regDHi, mkexpr(irt_resHi), condT, Ijk_Boring );
10752 putIRegA( regDLo, mkexpr(irt_resLo), condT, Ijk_Boring );
10755 DIP( "smlal%c%c%s r%u, r%u, r%u, r%u\n",
10756 bitN ? 't' : 'b', bitM ? 't' : 'b',
10757 nCC(conq), regDHi, regN, regM, regDLo );
10758 return True;
10760 /* fall through */
10763 /* ----- smlawb, smlawt <Rd>,<Rn>,<Rm>,<Ra> ----- */
10765 UInt regD = 99, regN = 99, regM = 99, regA = 99, bitM = 99;
10766 Bool gate = False;
10768 if (isT) {
10769 if (INSNT0(15,4) == 0xFB3 && INSNT1(7,5) == BITS3(0,0,0)) {
10770 regN = INSNT0(3,0);
10771 regD = INSNT1(11,8);
10772 regM = INSNT1(3,0);
10773 regA = INSNT1(15,12);
10774 bitM = INSNT1(4,4);
10775 if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM)
10776 && !isBadRegT(regA))
10777 gate = True;
10779 } else {
10780 if (INSNA(27,20) == BITS8(0,0,0,1,0,0,1,0) &&
10781 (INSNA(7,4) & BITS4(1,0,1,1)) == BITS4(1,0,0,0)) {
10782 regD = INSNA(19,16);
10783 regN = INSNA(3,0);
10784 regM = INSNA(11,8);
10785 regA = INSNA(15,12);
10786 bitM = INSNA(6,6);
10787 if (regD != 15 && regN != 15 && regM != 15 && regA != 15)
10788 gate = True;
10792 if (gate) {
10793 IRTemp irt_regA = newTemp(Ity_I32);
10794 IRTemp irt_prod = newTemp(Ity_I64);
10796 assign( irt_prod,
10797 binop(Iop_MullS32,
10798 isT ? getIRegT(regN) : getIRegA(regN),
10799 binop(Iop_Sar32,
10800 binop(Iop_Shl32,
10801 isT ? getIRegT(regM) : getIRegA(regM),
10802 mkU8(bitM ? 0 : 16)),
10803 mkU8(16))) );
10805 assign( irt_regA, isT ? getIRegT(regA) : getIRegA(regA) );
10807 IRTemp prod32 = newTemp(Ity_I32);
10808 assign(prod32,
10809 binop(Iop_Or32,
10810 binop(Iop_Shl32, unop(Iop_64HIto32, mkexpr(irt_prod)), mkU8(16)),
10811 binop(Iop_Shr32, unop(Iop_64to32, mkexpr(irt_prod)), mkU8(16))
10814 IRExpr* ire_result = binop(Iop_Add32, mkexpr(prod32), mkexpr(irt_regA));
10816 if (isT)
10817 putIRegT( regD, ire_result, condT );
10818 else
10819 putIRegA( regD, ire_result, condT, Ijk_Boring );
10821 or_into_QFLAG32(
10822 signed_overflow_after_Add32( ire_result, prod32, irt_regA ),
10823 condT
10826 DIP( "smlaw%c%s r%u, r%u, r%u, r%u\n",
10827 bitM ? 't' : 'b',
10828 nCC(conq), regD, regN, regM, regA );
10829 return True;
10831 /* fall through */
10834 /* ------------------- sel<c> <Rd>,<Rn>,<Rm> -------------------- */
10835 /* fixme: fix up the test in v6media.c so that we can pass the ge
10836 flags as part of the test. */
10838 UInt regD = 99, regN = 99, regM = 99;
10839 Bool gate = False;
10841 if (isT) {
10842 if (INSNT0(15,4) == 0xFAA && (INSNT1(15,0) & 0xF0F0) == 0xF080) {
10843 regN = INSNT0(3,0);
10844 regD = INSNT1(11,8);
10845 regM = INSNT1(3,0);
10846 if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
10847 gate = True;
10849 } else {
10850 if (INSNA(27,20) == BITS8(0,1,1,0,1,0,0,0) &&
10851 INSNA(11,8) == BITS4(1,1,1,1) &&
10852 INSNA(7,4) == BITS4(1,0,1,1)) {
10853 regD = INSNA(15,12);
10854 regN = INSNA(19,16);
10855 regM = INSNA(3,0);
10856 if (regD != 15 && regN != 15 && regM != 15)
10857 gate = True;
10861 if (gate) {
10862 IRTemp irt_ge_flag0 = newTemp(Ity_I32);
10863 IRTemp irt_ge_flag1 = newTemp(Ity_I32);
10864 IRTemp irt_ge_flag2 = newTemp(Ity_I32);
10865 IRTemp irt_ge_flag3 = newTemp(Ity_I32);
10867 assign( irt_ge_flag0, get_GEFLAG32(0) );
10868 assign( irt_ge_flag1, get_GEFLAG32(1) );
10869 assign( irt_ge_flag2, get_GEFLAG32(2) );
10870 assign( irt_ge_flag3, get_GEFLAG32(3) );
10872 IRExpr* ire_ge_flag0_or
10873 = binop(Iop_Or32, mkexpr(irt_ge_flag0),
10874 binop(Iop_Sub32, mkU32(0), mkexpr(irt_ge_flag0)));
10875 IRExpr* ire_ge_flag1_or
10876 = binop(Iop_Or32, mkexpr(irt_ge_flag1),
10877 binop(Iop_Sub32, mkU32(0), mkexpr(irt_ge_flag1)));
10878 IRExpr* ire_ge_flag2_or
10879 = binop(Iop_Or32, mkexpr(irt_ge_flag2),
10880 binop(Iop_Sub32, mkU32(0), mkexpr(irt_ge_flag2)));
10881 IRExpr* ire_ge_flag3_or
10882 = binop(Iop_Or32, mkexpr(irt_ge_flag3),
10883 binop(Iop_Sub32, mkU32(0), mkexpr(irt_ge_flag3)));
10885 IRExpr* ire_ge_flags
10886 = binop( Iop_Or32,
10887 binop(Iop_Or32,
10888 binop(Iop_And32,
10889 binop(Iop_Sar32, ire_ge_flag0_or, mkU8(31)),
10890 mkU32(0x000000ff)),
10891 binop(Iop_And32,
10892 binop(Iop_Sar32, ire_ge_flag1_or, mkU8(31)),
10893 mkU32(0x0000ff00))),
10894 binop(Iop_Or32,
10895 binop(Iop_And32,
10896 binop(Iop_Sar32, ire_ge_flag2_or, mkU8(31)),
10897 mkU32(0x00ff0000)),
10898 binop(Iop_And32,
10899 binop(Iop_Sar32, ire_ge_flag3_or, mkU8(31)),
10900 mkU32(0xff000000))) );
10902 IRExpr* ire_result
10903 = binop(Iop_Or32,
10904 binop(Iop_And32,
10905 isT ? getIRegT(regN) : getIRegA(regN),
10906 ire_ge_flags ),
10907 binop(Iop_And32,
10908 isT ? getIRegT(regM) : getIRegA(regM),
10909 unop(Iop_Not32, ire_ge_flags)));
10911 if (isT)
10912 putIRegT( regD, ire_result, condT );
10913 else
10914 putIRegA( regD, ire_result, condT, Ijk_Boring );
10916 DIP("sel%s r%u, r%u, r%u\n", nCC(conq), regD, regN, regM );
10917 return True;
10919 /* fall through */
10922 /* ----------------- uxtab16<c> Rd,Rn,Rm{,rot} ------------------ */
10924 UInt regD = 99, regN = 99, regM = 99, rotate = 99;
10925 Bool gate = False;
10927 if (isT) {
10928 if (INSNT0(15,4) == 0xFA3 && (INSNT1(15,0) & 0xF0C0) == 0xF080) {
10929 regN = INSNT0(3,0);
10930 regD = INSNT1(11,8);
10931 regM = INSNT1(3,0);
10932 rotate = INSNT1(5,4);
10933 if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
10934 gate = True;
10936 } else {
10937 if (INSNA(27,20) == BITS8(0,1,1,0,1,1,0,0) &&
10938 INSNA(9,4) == BITS6(0,0,0,1,1,1) ) {
10939 regD = INSNA(15,12);
10940 regN = INSNA(19,16);
10941 regM = INSNA(3,0);
10942 rotate = INSNA(11,10);
10943 if (regD != 15 && regN != 15 && regM != 15)
10944 gate = True;
10948 if (gate) {
10949 IRTemp irt_regN = newTemp(Ity_I32);
10950 assign( irt_regN, isT ? getIRegT(regN) : getIRegA(regN) );
10952 IRTemp irt_regM = newTemp(Ity_I32);
10953 assign( irt_regM, isT ? getIRegT(regM) : getIRegA(regM) );
10955 IRTemp irt_rot = newTemp(Ity_I32);
10956 assign( irt_rot, binop(Iop_And32,
10957 genROR32(irt_regM, 8 * rotate),
10958 mkU32(0x00FF00FF)) );
10960 IRExpr* resLo
10961 = binop(Iop_And32,
10962 binop(Iop_Add32, mkexpr(irt_regN), mkexpr(irt_rot)),
10963 mkU32(0x0000FFFF));
10965 IRExpr* resHi
10966 = binop(Iop_Add32,
10967 binop(Iop_And32, mkexpr(irt_regN), mkU32(0xFFFF0000)),
10968 binop(Iop_And32, mkexpr(irt_rot), mkU32(0xFFFF0000)));
10970 IRExpr* ire_result
10971 = binop( Iop_Or32, resHi, resLo );
10973 if (isT)
10974 putIRegT( regD, ire_result, condT );
10975 else
10976 putIRegA( regD, ire_result, condT, Ijk_Boring );
10978 DIP( "uxtab16%s r%u, r%u, r%u, ROR #%u\n",
10979 nCC(conq), regD, regN, regM, 8 * rotate );
10980 return True;
10982 /* fall through */
10985 /* --------------- usad8 Rd,Rn,Rm ---------------- */
10986 /* --------------- usada8 Rd,Rn,Rm,Ra ---------------- */
10988 UInt rD = 99, rN = 99, rM = 99, rA = 99;
10989 Bool gate = False;
10991 if (isT) {
10992 if (INSNT0(15,4) == 0xFB7 && INSNT1(7,4) == BITS4(0,0,0,0)) {
10993 rN = INSNT0(3,0);
10994 rA = INSNT1(15,12);
10995 rD = INSNT1(11,8);
10996 rM = INSNT1(3,0);
10997 if (!isBadRegT(rD) && !isBadRegT(rN) && !isBadRegT(rM) && rA != 13)
10998 gate = True;
11000 } else {
11001 if (INSNA(27,20) == BITS8(0,1,1,1,1,0,0,0) &&
11002 INSNA(7,4) == BITS4(0,0,0,1) ) {
11003 rD = INSNA(19,16);
11004 rA = INSNA(15,12);
11005 rM = INSNA(11,8);
11006 rN = INSNA(3,0);
11007 if (rD != 15 && rN != 15 && rM != 15 /* but rA can be 15 */)
11008 gate = True;
11011 /* We allow rA == 15, to denote the usad8 (no accumulator) case. */
11013 if (gate) {
11014 IRExpr* rNe = isT ? getIRegT(rN) : getIRegA(rN);
11015 IRExpr* rMe = isT ? getIRegT(rM) : getIRegA(rM);
11016 IRExpr* rAe = rA == 15 ? mkU32(0)
11017 : (isT ? getIRegT(rA) : getIRegA(rA));
11018 IRExpr* res = binop(Iop_Add32,
11019 binop(Iop_Sad8Ux4, rNe, rMe),
11020 rAe);
11021 if (isT)
11022 putIRegT( rD, res, condT );
11023 else
11024 putIRegA( rD, res, condT, Ijk_Boring );
11026 if (rA == 15) {
11027 DIP( "usad8%s r%u, r%u, r%u\n",
11028 nCC(conq), rD, rN, rM );
11029 } else {
11030 DIP( "usada8%s r%u, r%u, r%u, r%u\n",
11031 nCC(conq), rD, rN, rM, rA );
11033 return True;
11035 /* fall through */
11038 /* ------------------ qadd<c> <Rd>,<Rn>,<Rm> ------------------- */
11040 UInt regD = 99, regN = 99, regM = 99;
11041 Bool gate = False;
11043 if (isT) {
11044 if (INSNT0(15,4) == 0xFA8 && (INSNT1(15,0) & 0xF0F0) == 0xF080) {
11045 regN = INSNT0(3,0);
11046 regD = INSNT1(11,8);
11047 regM = INSNT1(3,0);
11048 if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
11049 gate = True;
11051 } else {
11052 if (INSNA(27,20) == BITS8(0,0,0,1,0,0,0,0) &&
11053 INSNA(11,8) == BITS4(0,0,0,0) &&
11054 INSNA(7,4) == BITS4(0,1,0,1)) {
11055 regD = INSNA(15,12);
11056 regN = INSNA(19,16);
11057 regM = INSNA(3,0);
11058 if (regD != 15 && regN != 15 && regM != 15)
11059 gate = True;
11063 if (gate) {
11064 IRTemp rNt = newTemp(Ity_I32);
11065 IRTemp rMt = newTemp(Ity_I32);
11066 IRTemp res_q = newTemp(Ity_I32);
11068 assign( rNt, isT ? getIRegT(regN) : getIRegA(regN) );
11069 assign( rMt, isT ? getIRegT(regM) : getIRegA(regM) );
11071 assign(res_q, binop(Iop_QAdd32S, mkexpr(rMt), mkexpr(rNt)));
11072 if (isT)
11073 putIRegT( regD, mkexpr(res_q), condT );
11074 else
11075 putIRegA( regD, mkexpr(res_q), condT, Ijk_Boring );
11077 or_into_QFLAG32(
11078 signed_overflow_after_Add32(
11079 binop(Iop_Add32, mkexpr(rMt), mkexpr(rNt)), rMt, rNt),
11080 condT
11083 DIP("qadd%s r%u, r%u, r%u\n", nCC(conq),regD,regM,regN);
11084 return True;
11086 /* fall through */
11089 /* ------------------ qdadd<c> <Rd>,<Rm>,<Rn> ------------------- */
11091 UInt regD = 99, regN = 99, regM = 99;
11092 Bool gate = False;
11094 if (isT) {
11095 if (INSNT0(15,4) == 0xFA8 && (INSNT1(15,0) & 0xF0F0) == 0xF090) {
11096 regN = INSNT0(3,0);
11097 regD = INSNT1(11,8);
11098 regM = INSNT1(3,0);
11099 if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
11100 gate = True;
11102 } else {
11103 if (INSNA(27,20) == BITS8(0,0,0,1,0,1,0,0) &&
11104 INSNA(11,8) == BITS4(0,0,0,0) &&
11105 INSNA(7,4) == BITS4(0,1,0,1)) {
11106 regD = INSNA(15,12);
11107 regN = INSNA(19,16);
11108 regM = INSNA(3,0);
11109 if (regD != 15 && regN != 15 && regM != 15)
11110 gate = True;
11114 if (gate) {
11115 IRTemp rNt = newTemp(Ity_I32);
11116 IRTemp rMt = newTemp(Ity_I32);
11117 IRTemp rN_d = newTemp(Ity_I32);
11118 IRTemp res_q = newTemp(Ity_I32);
11120 assign( rNt, isT ? getIRegT(regN) : getIRegA(regN) );
11121 assign( rMt, isT ? getIRegT(regM) : getIRegA(regM) );
11123 or_into_QFLAG32(
11124 signed_overflow_after_Add32(
11125 binop(Iop_Add32, mkexpr(rNt), mkexpr(rNt)), rNt, rNt),
11126 condT
11129 assign(rN_d, binop(Iop_QAdd32S, mkexpr(rNt), mkexpr(rNt)));
11130 assign(res_q, binop(Iop_QAdd32S, mkexpr(rMt), mkexpr(rN_d)));
11131 if (isT)
11132 putIRegT( regD, mkexpr(res_q), condT );
11133 else
11134 putIRegA( regD, mkexpr(res_q), condT, Ijk_Boring );
11136 or_into_QFLAG32(
11137 signed_overflow_after_Add32(
11138 binop(Iop_Add32, mkexpr(rMt), mkexpr(rN_d)), rMt, rN_d),
11139 condT
11142 DIP("qdadd%s r%u, r%u, r%u\n", nCC(conq),regD,regM,regN);
11143 return True;
11145 /* fall through */
11148 /* ------------------ qsub<c> <Rd>,<Rn>,<Rm> ------------------- */
11150 UInt regD = 99, regN = 99, regM = 99;
11151 Bool gate = False;
11153 if (isT) {
11154 if (INSNT0(15,4) == 0xFA8 && (INSNT1(15,0) & 0xF0F0) == 0xF0A0) {
11155 regN = INSNT0(3,0);
11156 regD = INSNT1(11,8);
11157 regM = INSNT1(3,0);
11158 if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
11159 gate = True;
11161 } else {
11162 if (INSNA(27,20) == BITS8(0,0,0,1,0,0,1,0) &&
11163 INSNA(11,8) == BITS4(0,0,0,0) &&
11164 INSNA(7,4) == BITS4(0,1,0,1)) {
11165 regD = INSNA(15,12);
11166 regN = INSNA(19,16);
11167 regM = INSNA(3,0);
11168 if (regD != 15 && regN != 15 && regM != 15)
11169 gate = True;
11173 if (gate) {
11174 IRTemp rNt = newTemp(Ity_I32);
11175 IRTemp rMt = newTemp(Ity_I32);
11176 IRTemp res_q = newTemp(Ity_I32);
11178 assign( rNt, isT ? getIRegT(regN) : getIRegA(regN) );
11179 assign( rMt, isT ? getIRegT(regM) : getIRegA(regM) );
11181 assign(res_q, binop(Iop_QSub32S, mkexpr(rMt), mkexpr(rNt)));
11182 if (isT)
11183 putIRegT( regD, mkexpr(res_q), condT );
11184 else
11185 putIRegA( regD, mkexpr(res_q), condT, Ijk_Boring );
11187 or_into_QFLAG32(
11188 signed_overflow_after_Sub32(
11189 binop(Iop_Sub32, mkexpr(rMt), mkexpr(rNt)), rMt, rNt),
11190 condT
11193 DIP("qsub%s r%u, r%u, r%u\n", nCC(conq),regD,regM,regN);
11194 return True;
11196 /* fall through */
11199 /* ------------------ qdsub<c> <Rd>,<Rm>,<Rn> ------------------- */
11201 UInt regD = 99, regN = 99, regM = 99;
11202 Bool gate = False;
11204 if (isT) {
11205 if (INSNT0(15,4) == 0xFA8 && (INSNT1(15,0) & 0xF0F0) == 0xF0B0) {
11206 regN = INSNT0(3,0);
11207 regD = INSNT1(11,8);
11208 regM = INSNT1(3,0);
11209 if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
11210 gate = True;
11212 } else {
11213 if (INSNA(27,20) == BITS8(0,0,0,1,0,1,1,0) &&
11214 INSNA(11,8) == BITS4(0,0,0,0) &&
11215 INSNA(7,4) == BITS4(0,1,0,1)) {
11216 regD = INSNA(15,12);
11217 regN = INSNA(19,16);
11218 regM = INSNA(3,0);
11219 if (regD != 15 && regN != 15 && regM != 15)
11220 gate = True;
11224 if (gate) {
11225 IRTemp rNt = newTemp(Ity_I32);
11226 IRTemp rMt = newTemp(Ity_I32);
11227 IRTemp rN_d = newTemp(Ity_I32);
11228 IRTemp res_q = newTemp(Ity_I32);
11230 assign( rNt, isT ? getIRegT(regN) : getIRegA(regN) );
11231 assign( rMt, isT ? getIRegT(regM) : getIRegA(regM) );
11233 or_into_QFLAG32(
11234 signed_overflow_after_Add32(
11235 binop(Iop_Add32, mkexpr(rNt), mkexpr(rNt)), rNt, rNt),
11236 condT
11239 assign(rN_d, binop(Iop_QAdd32S, mkexpr(rNt), mkexpr(rNt)));
11240 assign(res_q, binop(Iop_QSub32S, mkexpr(rMt), mkexpr(rN_d)));
11241 if (isT)
11242 putIRegT( regD, mkexpr(res_q), condT );
11243 else
11244 putIRegA( regD, mkexpr(res_q), condT, Ijk_Boring );
11246 or_into_QFLAG32(
11247 signed_overflow_after_Sub32(
11248 binop(Iop_Sub32, mkexpr(rMt), mkexpr(rN_d)), rMt, rN_d),
11249 condT
11252 DIP("qdsub%s r%u, r%u, r%u\n", nCC(conq),regD,regM,regN);
11253 return True;
11255 /* fall through */
11258 /* ------------------ uqsub16<c> <Rd>,<Rn>,<Rm> ------------------ */
11260 UInt regD = 99, regN = 99, regM = 99;
11261 Bool gate = False;
11263 if (isT) {
11264 if (INSNT0(15,4) == 0xFAD && (INSNT1(15,0) & 0xF0F0) == 0xF050) {
11265 regN = INSNT0(3,0);
11266 regD = INSNT1(11,8);
11267 regM = INSNT1(3,0);
11268 if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
11269 gate = True;
11271 } else {
11272 if (INSNA(27,20) == BITS8(0,1,1,0,0,1,1,0) &&
11273 INSNA(11,8) == BITS4(1,1,1,1) &&
11274 INSNA(7,4) == BITS4(0,1,1,1)) {
11275 regD = INSNA(15,12);
11276 regN = INSNA(19,16);
11277 regM = INSNA(3,0);
11278 if (regD != 15 && regN != 15 && regM != 15)
11279 gate = True;
11283 if (gate) {
11284 IRTemp rNt = newTemp(Ity_I32);
11285 IRTemp rMt = newTemp(Ity_I32);
11286 IRTemp res_q = newTemp(Ity_I32);
11288 assign( rNt, isT ? getIRegT(regN) : getIRegA(regN) );
11289 assign( rMt, isT ? getIRegT(regM) : getIRegA(regM) );
11291 assign(res_q, binop(Iop_QSub16Ux2, mkexpr(rNt), mkexpr(rMt)));
11292 if (isT)
11293 putIRegT( regD, mkexpr(res_q), condT );
11294 else
11295 putIRegA( regD, mkexpr(res_q), condT, Ijk_Boring );
11297 DIP("uqsub16%s r%u, r%u, r%u\n", nCC(conq),regD,regN,regM);
11298 return True;
11300 /* fall through */
11303 /* ----------------- shadd16<c> <Rd>,<Rn>,<Rm> ------------------- */
11305 UInt regD = 99, regN = 99, regM = 99;
11306 Bool gate = False;
11308 if (isT) {
11309 if (INSNT0(15,4) == 0xFA9 && (INSNT1(15,0) & 0xF0F0) == 0xF020) {
11310 regN = INSNT0(3,0);
11311 regD = INSNT1(11,8);
11312 regM = INSNT1(3,0);
11313 if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
11314 gate = True;
11316 } else {
11317 if (INSNA(27,20) == BITS8(0,1,1,0,0,0,1,1) &&
11318 INSNA(11,8) == BITS4(1,1,1,1) &&
11319 INSNA(7,4) == BITS4(0,0,0,1)) {
11320 regD = INSNA(15,12);
11321 regN = INSNA(19,16);
11322 regM = INSNA(3,0);
11323 if (regD != 15 && regN != 15 && regM != 15)
11324 gate = True;
11328 if (gate) {
11329 IRTemp rNt = newTemp(Ity_I32);
11330 IRTemp rMt = newTemp(Ity_I32);
11331 IRTemp res_q = newTemp(Ity_I32);
11333 assign( rNt, isT ? getIRegT(regN) : getIRegA(regN) );
11334 assign( rMt, isT ? getIRegT(regM) : getIRegA(regM) );
11336 assign(res_q, binop(Iop_HAdd16Sx2, mkexpr(rNt), mkexpr(rMt)));
11337 if (isT)
11338 putIRegT( regD, mkexpr(res_q), condT );
11339 else
11340 putIRegA( regD, mkexpr(res_q), condT, Ijk_Boring );
11342 DIP("shadd16%s r%u, r%u, r%u\n", nCC(conq),regD,regN,regM);
11343 return True;
11345 /* fall through */
11348 /* ----------------- uhsub8<c> <Rd>,<Rn>,<Rm> ------------------- */
11350 UInt regD = 99, regN = 99, regM = 99;
11351 Bool gate = False;
11353 if (isT) {
11354 if (INSNT0(15,4) == 0xFAC && (INSNT1(15,0) & 0xF0F0) == 0xF060) {
11355 regN = INSNT0(3,0);
11356 regD = INSNT1(11,8);
11357 regM = INSNT1(3,0);
11358 if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
11359 gate = True;
11361 } else {
11362 if (INSNA(27,20) == BITS8(0,1,1,0,0,1,1,1) &&
11363 INSNA(11,8) == BITS4(1,1,1,1) &&
11364 INSNA(7,4) == BITS4(1,1,1,1)) {
11365 regD = INSNA(15,12);
11366 regN = INSNA(19,16);
11367 regM = INSNA(3,0);
11368 if (regD != 15 && regN != 15 && regM != 15)
11369 gate = True;
11373 if (gate) {
11374 IRTemp rNt = newTemp(Ity_I32);
11375 IRTemp rMt = newTemp(Ity_I32);
11376 IRTemp res_q = newTemp(Ity_I32);
11378 assign( rNt, isT ? getIRegT(regN) : getIRegA(regN) );
11379 assign( rMt, isT ? getIRegT(regM) : getIRegA(regM) );
11381 assign(res_q, binop(Iop_HSub8Ux4, mkexpr(rNt), mkexpr(rMt)));
11382 if (isT)
11383 putIRegT( regD, mkexpr(res_q), condT );
11384 else
11385 putIRegA( regD, mkexpr(res_q), condT, Ijk_Boring );
11387 DIP("uhsub8%s r%u, r%u, r%u\n", nCC(conq),regD,regN,regM);
11388 return True;
11390 /* fall through */
11393 /* ----------------- uhsub16<c> <Rd>,<Rn>,<Rm> ------------------- */
11395 UInt regD = 99, regN = 99, regM = 99;
11396 Bool gate = False;
11398 if (isT) {
11399 if (INSNT0(15,4) == 0xFAD && (INSNT1(15,0) & 0xF0F0) == 0xF060) {
11400 regN = INSNT0(3,0);
11401 regD = INSNT1(11,8);
11402 regM = INSNT1(3,0);
11403 if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
11404 gate = True;
11406 } else {
11407 if (INSNA(27,20) == BITS8(0,1,1,0,0,1,1,1) &&
11408 INSNA(11,8) == BITS4(1,1,1,1) &&
11409 INSNA(7,4) == BITS4(0,1,1,1)) {
11410 regD = INSNA(15,12);
11411 regN = INSNA(19,16);
11412 regM = INSNA(3,0);
11413 if (regD != 15 && regN != 15 && regM != 15)
11414 gate = True;
11418 if (gate) {
11419 IRTemp rNt = newTemp(Ity_I32);
11420 IRTemp rMt = newTemp(Ity_I32);
11421 IRTemp res_q = newTemp(Ity_I32);
11423 assign( rNt, isT ? getIRegT(regN) : getIRegA(regN) );
11424 assign( rMt, isT ? getIRegT(regM) : getIRegA(regM) );
11426 assign(res_q, binop(Iop_HSub16Ux2, mkexpr(rNt), mkexpr(rMt)));
11427 if (isT)
11428 putIRegT( regD, mkexpr(res_q), condT );
11429 else
11430 putIRegA( regD, mkexpr(res_q), condT, Ijk_Boring );
11432 DIP("uhsub16%s r%u, r%u, r%u\n", nCC(conq),regD,regN,regM);
11433 return True;
11435 /* fall through */
11438 /* ------------------ uqadd16<c> <Rd>,<Rn>,<Rm> ------------------ */
11440 UInt regD = 99, regN = 99, regM = 99;
11441 Bool gate = False;
11443 if (isT) {
11444 if (INSNT0(15,4) == 0xFA9 && (INSNT1(15,0) & 0xF0F0) == 0xF050) {
11445 regN = INSNT0(3,0);
11446 regD = INSNT1(11,8);
11447 regM = INSNT1(3,0);
11448 if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
11449 gate = True;
11451 } else {
11452 if (INSNA(27,20) == BITS8(0,1,1,0,0,1,1,0) &&
11453 INSNA(11,8) == BITS4(1,1,1,1) &&
11454 INSNA(7,4) == BITS4(0,0,0,1)) {
11455 regD = INSNA(15,12);
11456 regN = INSNA(19,16);
11457 regM = INSNA(3,0);
11458 if (regD != 15 && regN != 15 && regM != 15)
11459 gate = True;
11463 if (gate) {
11464 IRTemp rNt = newTemp(Ity_I32);
11465 IRTemp rMt = newTemp(Ity_I32);
11466 IRTemp res_q = newTemp(Ity_I32);
11468 assign( rNt, isT ? getIRegT(regN) : getIRegA(regN) );
11469 assign( rMt, isT ? getIRegT(regM) : getIRegA(regM) );
11471 assign(res_q, binop(Iop_QAdd16Ux2, mkexpr(rNt), mkexpr(rMt)));
11472 if (isT)
11473 putIRegT( regD, mkexpr(res_q), condT );
11474 else
11475 putIRegA( regD, mkexpr(res_q), condT, Ijk_Boring );
11477 DIP("uqadd16%s r%u, r%u, r%u\n", nCC(conq),regD,regN,regM);
11478 return True;
11480 /* fall through */
11483 /* ------------------- uqsax<c> <Rd>,<Rn>,<Rm> ------------------- */
11485 UInt regD = 99, regN = 99, regM = 99;
11486 Bool gate = False;
11488 if (isT) {
11489 if (INSNT0(15,4) == 0xFAE && (INSNT1(15,0) & 0xF0F0) == 0xF050) {
11490 regN = INSNT0(3,0);
11491 regD = INSNT1(11,8);
11492 regM = INSNT1(3,0);
11493 if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
11494 gate = True;
11496 } else {
11497 if (INSNA(27,20) == BITS8(0,1,1,0,0,1,1,0) &&
11498 INSNA(11,8) == BITS4(1,1,1,1) &&
11499 INSNA(7,4) == BITS4(0,1,0,1)) {
11500 regD = INSNA(15,12);
11501 regN = INSNA(19,16);
11502 regM = INSNA(3,0);
11503 if (regD != 15 && regN != 15 && regM != 15)
11504 gate = True;
11508 if (gate) {
11509 IRTemp irt_regN = newTemp(Ity_I32);
11510 IRTemp irt_regM = newTemp(Ity_I32);
11511 IRTemp irt_sum = newTemp(Ity_I32);
11512 IRTemp irt_diff = newTemp(Ity_I32);
11513 IRTemp irt_sum_res = newTemp(Ity_I32);
11514 IRTemp irt_diff_res = newTemp(Ity_I32);
11516 assign( irt_regN, isT ? getIRegT(regN) : getIRegA(regN) );
11517 assign( irt_regM, isT ? getIRegT(regM) : getIRegA(regM) );
11519 assign( irt_diff,
11520 binop( Iop_Sub32,
11521 binop( Iop_Shr32, mkexpr(irt_regN), mkU8(16) ),
11522 binop( Iop_Shr32,
11523 binop(Iop_Shl32, mkexpr(irt_regM), mkU8(16)),
11524 mkU8(16) ) ) );
11525 armUnsignedSatQ( &irt_diff_res, NULL, irt_diff, 0x10);
11527 assign( irt_sum,
11528 binop( Iop_Add32,
11529 binop( Iop_Shr32,
11530 binop( Iop_Shl32, mkexpr(irt_regN), mkU8(16) ),
11531 mkU8(16) ),
11532 binop( Iop_Shr32, mkexpr(irt_regM), mkU8(16) )) );
11533 armUnsignedSatQ( &irt_sum_res, NULL, irt_sum, 0x10 );
11535 IRExpr* ire_result = binop( Iop_Or32,
11536 binop( Iop_Shl32, mkexpr(irt_diff_res),
11537 mkU8(16) ),
11538 binop( Iop_And32, mkexpr(irt_sum_res),
11539 mkU32(0xFFFF)) );
11541 if (isT)
11542 putIRegT( regD, ire_result, condT );
11543 else
11544 putIRegA( regD, ire_result, condT, Ijk_Boring );
11546 DIP( "uqsax%s r%u, r%u, r%u\n", nCC(conq), regD, regN, regM );
11547 return True;
11549 /* fall through */
11552 /* ------------------- uqasx<c> <Rd>,<Rn>,<Rm> ------------------- */
11554 UInt regD = 99, regN = 99, regM = 99;
11555 Bool gate = False;
11557 if (isT) {
11558 if (INSNT0(15,4) == 0xFAA && (INSNT1(15,0) & 0xF0F0) == 0xF050) {
11559 regN = INSNT0(3,0);
11560 regD = INSNT1(11,8);
11561 regM = INSNT1(3,0);
11562 if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
11563 gate = True;
11565 } else {
11566 if (INSNA(27,20) == BITS8(0,1,1,0,0,1,1,0) &&
11567 INSNA(11,8) == BITS4(1,1,1,1) &&
11568 INSNA(7,4) == BITS4(0,0,1,1)) {
11569 regD = INSNA(15,12);
11570 regN = INSNA(19,16);
11571 regM = INSNA(3,0);
11572 if (regD != 15 && regN != 15 && regM != 15)
11573 gate = True;
11577 if (gate) {
11578 IRTemp irt_regN = newTemp(Ity_I32);
11579 IRTemp irt_regM = newTemp(Ity_I32);
11580 IRTemp irt_sum = newTemp(Ity_I32);
11581 IRTemp irt_diff = newTemp(Ity_I32);
11582 IRTemp irt_res_sum = newTemp(Ity_I32);
11583 IRTemp irt_res_diff = newTemp(Ity_I32);
11585 assign( irt_regN, isT ? getIRegT(regN) : getIRegA(regN) );
11586 assign( irt_regM, isT ? getIRegT(regM) : getIRegA(regM) );
11588 assign( irt_diff,
11589 binop( Iop_Sub32,
11590 binop( Iop_Shr32,
11591 binop( Iop_Shl32, mkexpr(irt_regN), mkU8(16) ),
11592 mkU8(16) ),
11593 binop( Iop_Shr32, mkexpr(irt_regM), mkU8(16) ) ) );
11594 armUnsignedSatQ( &irt_res_diff, NULL, irt_diff, 0x10 );
11596 assign( irt_sum,
11597 binop( Iop_Add32,
11598 binop( Iop_Shr32, mkexpr(irt_regN), mkU8(16) ),
11599 binop( Iop_Shr32,
11600 binop( Iop_Shl32, mkexpr(irt_regM), mkU8(16) ),
11601 mkU8(16) ) ) );
11602 armUnsignedSatQ( &irt_res_sum, NULL, irt_sum, 0x10 );
11604 IRExpr* ire_result
11605 = binop( Iop_Or32,
11606 binop( Iop_Shl32, mkexpr(irt_res_sum), mkU8(16) ),
11607 binop( Iop_And32, mkexpr(irt_res_diff), mkU32(0xFFFF) ) );
11609 if (isT)
11610 putIRegT( regD, ire_result, condT );
11611 else
11612 putIRegA( regD, ire_result, condT, Ijk_Boring );
11614 DIP( "uqasx%s r%u, r%u, r%u\n", nCC(conq), regD, regN, regM );
11615 return True;
11617 /* fall through */
11620 /* ------------------- usax<c> <Rd>,<Rn>,<Rm> ------------------- */
11622 UInt regD = 99, regN = 99, regM = 99;
11623 Bool gate = False;
11625 if (isT) {
11626 if (INSNT0(15,4) == 0xFAE && (INSNT1(15,0) & 0xF0F0) == 0xF040) {
11627 regN = INSNT0(3,0);
11628 regD = INSNT1(11,8);
11629 regM = INSNT1(3,0);
11630 if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
11631 gate = True;
11633 } else {
11634 if (INSNA(27,20) == BITS8(0,1,1,0,0,1,0,1) &&
11635 INSNA(11,8) == BITS4(1,1,1,1) &&
11636 INSNA(7,4) == BITS4(0,1,0,1)) {
11637 regD = INSNA(15,12);
11638 regN = INSNA(19,16);
11639 regM = INSNA(3,0);
11640 if (regD != 15 && regN != 15 && regM != 15)
11641 gate = True;
11645 if (gate) {
11646 IRTemp irt_regN = newTemp(Ity_I32);
11647 IRTemp irt_regM = newTemp(Ity_I32);
11648 IRTemp irt_sum = newTemp(Ity_I32);
11649 IRTemp irt_diff = newTemp(Ity_I32);
11651 assign( irt_regN, isT ? getIRegT(regN) : getIRegA(regN) );
11652 assign( irt_regM, isT ? getIRegT(regM) : getIRegA(regM) );
11654 assign( irt_sum,
11655 binop( Iop_Add32,
11656 unop( Iop_16Uto32,
11657 unop( Iop_32to16, mkexpr(irt_regN) )
11659 binop( Iop_Shr32, mkexpr(irt_regM), mkU8(16) ) ) );
11661 assign( irt_diff,
11662 binop( Iop_Sub32,
11663 binop( Iop_Shr32, mkexpr(irt_regN), mkU8(16) ),
11664 unop( Iop_16Uto32,
11665 unop( Iop_32to16, mkexpr(irt_regM) )
11670 IRExpr* ire_result
11671 = binop( Iop_Or32,
11672 binop( Iop_Shl32, mkexpr(irt_diff), mkU8(16) ),
11673 binop( Iop_And32, mkexpr(irt_sum), mkU32(0xFFFF) ) );
11675 IRTemp ge10 = newTemp(Ity_I32);
11676 assign( ge10, IRExpr_ITE( binop( Iop_CmpLE32U,
11677 mkU32(0x10000), mkexpr(irt_sum) ),
11678 mkU32(1), mkU32(0) ) );
11679 put_GEFLAG32( 0, 0, mkexpr(ge10), condT );
11680 put_GEFLAG32( 1, 0, mkexpr(ge10), condT );
11682 IRTemp ge32 = newTemp(Ity_I32);
11683 assign(ge32, unop(Iop_Not32, mkexpr(irt_diff)));
11684 put_GEFLAG32( 2, 31, mkexpr(ge32), condT );
11685 put_GEFLAG32( 3, 31, mkexpr(ge32), condT );
11687 if (isT)
11688 putIRegT( regD, ire_result, condT );
11689 else
11690 putIRegA( regD, ire_result, condT, Ijk_Boring );
11692 DIP( "usax%s r%u, r%u, r%u\n", nCC(conq), regD, regN, regM );
11693 return True;
11695 /* fall through */
11698 /* ------------------- uasx<c> <Rd>,<Rn>,<Rm> ------------------- */
11700 UInt regD = 99, regN = 99, regM = 99;
11701 Bool gate = False;
11703 if (isT) {
11704 if (INSNT0(15,4) == 0xFAA && (INSNT1(15,0) & 0xF0F0) == 0xF040) {
11705 regN = INSNT0(3,0);
11706 regD = INSNT1(11,8);
11707 regM = INSNT1(3,0);
11708 if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
11709 gate = True;
11711 } else {
11712 if (INSNA(27,20) == BITS8(0,1,1,0,0,1,0,1) &&
11713 INSNA(11,8) == BITS4(1,1,1,1) &&
11714 INSNA(7,4) == BITS4(0,0,1,1)) {
11715 regD = INSNA(15,12);
11716 regN = INSNA(19,16);
11717 regM = INSNA(3,0);
11718 if (regD != 15 && regN != 15 && regM != 15)
11719 gate = True;
11723 if (gate) {
11724 IRTemp irt_regN = newTemp(Ity_I32);
11725 IRTemp irt_regM = newTemp(Ity_I32);
11726 IRTemp irt_sum = newTemp(Ity_I32);
11727 IRTemp irt_diff = newTemp(Ity_I32);
11729 assign( irt_regN, isT ? getIRegT(regN) : getIRegA(regN) );
11730 assign( irt_regM, isT ? getIRegT(regM) : getIRegA(regM) );
11732 assign( irt_diff,
11733 binop( Iop_Sub32,
11734 unop( Iop_16Uto32,
11735 unop( Iop_32to16, mkexpr(irt_regN) )
11737 binop( Iop_Shr32, mkexpr(irt_regM), mkU8(16) ) ) );
11739 assign( irt_sum,
11740 binop( Iop_Add32,
11741 binop( Iop_Shr32, mkexpr(irt_regN), mkU8(16) ),
11742 unop( Iop_16Uto32,
11743 unop( Iop_32to16, mkexpr(irt_regM) )
11744 ) ) );
11746 IRExpr* ire_result
11747 = binop( Iop_Or32,
11748 binop( Iop_Shl32, mkexpr(irt_sum), mkU8(16) ),
11749 binop( Iop_And32, mkexpr(irt_diff), mkU32(0xFFFF) ) );
11751 IRTemp ge10 = newTemp(Ity_I32);
11752 assign(ge10, unop(Iop_Not32, mkexpr(irt_diff)));
11753 put_GEFLAG32( 0, 31, mkexpr(ge10), condT );
11754 put_GEFLAG32( 1, 31, mkexpr(ge10), condT );
11756 IRTemp ge32 = newTemp(Ity_I32);
11757 assign( ge32, IRExpr_ITE( binop( Iop_CmpLE32U,
11758 mkU32(0x10000), mkexpr(irt_sum) ),
11759 mkU32(1), mkU32(0) ) );
11760 put_GEFLAG32( 2, 0, mkexpr(ge32), condT );
11761 put_GEFLAG32( 3, 0, mkexpr(ge32), condT );
11763 if (isT)
11764 putIRegT( regD, ire_result, condT );
11765 else
11766 putIRegA( regD, ire_result, condT, Ijk_Boring );
11768 DIP( "uasx%s r%u, r%u, r%u\n", nCC(conq), regD, regN, regM );
11769 return True;
11771 /* fall through */
11774 /* ------------------- ssax<c> <Rd>,<Rn>,<Rm> ------------------- */
11776 UInt regD = 99, regN = 99, regM = 99;
11777 Bool gate = False;
11779 if (isT) {
11780 if (INSNT0(15,4) == 0xFAE && (INSNT1(15,0) & 0xF0F0) == 0xF000) {
11781 regN = INSNT0(3,0);
11782 regD = INSNT1(11,8);
11783 regM = INSNT1(3,0);
11784 if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
11785 gate = True;
11787 } else {
11788 if (INSNA(27,20) == BITS8(0,1,1,0,0,0,0,1) &&
11789 INSNA(11,8) == BITS4(1,1,1,1) &&
11790 INSNA(7,4) == BITS4(0,1,0,1)) {
11791 regD = INSNA(15,12);
11792 regN = INSNA(19,16);
11793 regM = INSNA(3,0);
11794 if (regD != 15 && regN != 15 && regM != 15)
11795 gate = True;
11799 if (gate) {
11800 IRTemp irt_regN = newTemp(Ity_I32);
11801 IRTemp irt_regM = newTemp(Ity_I32);
11802 IRTemp irt_sum = newTemp(Ity_I32);
11803 IRTemp irt_diff = newTemp(Ity_I32);
11805 assign( irt_regN, isT ? getIRegT(regN) : getIRegA(regN) );
11806 assign( irt_regM, isT ? getIRegT(regM) : getIRegA(regM) );
11808 assign( irt_sum,
11809 binop( Iop_Add32,
11810 binop( Iop_Sar32,
11811 binop( Iop_Shl32, mkexpr(irt_regN), mkU8(16) ),
11812 mkU8(16) ),
11813 binop( Iop_Sar32, mkexpr(irt_regM), mkU8(16) ) ) );
11815 assign( irt_diff,
11816 binop( Iop_Sub32,
11817 binop( Iop_Sar32, mkexpr(irt_regN), mkU8(16) ),
11818 binop( Iop_Sar32,
11819 binop( Iop_Shl32, mkexpr(irt_regM), mkU8(16) ),
11820 mkU8(16) ) ) );
11822 IRExpr* ire_result
11823 = binop( Iop_Or32,
11824 binop( Iop_Shl32, mkexpr(irt_diff), mkU8(16) ),
11825 binop( Iop_And32, mkexpr(irt_sum), mkU32(0xFFFF) ) );
11827 IRTemp ge10 = newTemp(Ity_I32);
11828 assign(ge10, unop(Iop_Not32, mkexpr(irt_sum)));
11829 put_GEFLAG32( 0, 31, mkexpr(ge10), condT );
11830 put_GEFLAG32( 1, 31, mkexpr(ge10), condT );
11832 IRTemp ge32 = newTemp(Ity_I32);
11833 assign(ge32, unop(Iop_Not32, mkexpr(irt_diff)));
11834 put_GEFLAG32( 2, 31, mkexpr(ge32), condT );
11835 put_GEFLAG32( 3, 31, mkexpr(ge32), condT );
11837 if (isT)
11838 putIRegT( regD, ire_result, condT );
11839 else
11840 putIRegA( regD, ire_result, condT, Ijk_Boring );
11842 DIP( "ssax%s r%u, r%u, r%u\n", nCC(conq), regD, regN, regM );
11843 return True;
11845 /* fall through */
11848 /* ----------------- shsub8<c> <Rd>,<Rn>,<Rm> ------------------- */
11850 UInt regD = 99, regN = 99, regM = 99;
11851 Bool gate = False;
11853 if (isT) {
11854 if (INSNT0(15,4) == 0xFAC && (INSNT1(15,0) & 0xF0F0) == 0xF020) {
11855 regN = INSNT0(3,0);
11856 regD = INSNT1(11,8);
11857 regM = INSNT1(3,0);
11858 if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
11859 gate = True;
11861 } else {
11862 if (INSNA(27,20) == BITS8(0,1,1,0,0,0,1,1) &&
11863 INSNA(11,8) == BITS4(1,1,1,1) &&
11864 INSNA(7,4) == BITS4(1,1,1,1)) {
11865 regD = INSNA(15,12);
11866 regN = INSNA(19,16);
11867 regM = INSNA(3,0);
11868 if (regD != 15 && regN != 15 && regM != 15)
11869 gate = True;
11873 if (gate) {
11874 IRTemp rNt = newTemp(Ity_I32);
11875 IRTemp rMt = newTemp(Ity_I32);
11876 IRTemp res_q = newTemp(Ity_I32);
11878 assign( rNt, isT ? getIRegT(regN) : getIRegA(regN) );
11879 assign( rMt, isT ? getIRegT(regM) : getIRegA(regM) );
11881 assign(res_q, binop(Iop_HSub8Sx4, mkexpr(rNt), mkexpr(rMt)));
11882 if (isT)
11883 putIRegT( regD, mkexpr(res_q), condT );
11884 else
11885 putIRegA( regD, mkexpr(res_q), condT, Ijk_Boring );
11887 DIP("shsub8%s r%u, r%u, r%u\n", nCC(conq),regD,regN,regM);
11888 return True;
11890 /* fall through */
11893 /* ----------------- sxtab16<c> Rd,Rn,Rm{,rot} ------------------ */
11895 UInt regD = 99, regN = 99, regM = 99, rotate = 99;
11896 Bool gate = False;
11898 if (isT) {
11899 if (INSNT0(15,4) == 0xFA2 && (INSNT1(15,0) & 0xF0C0) == 0xF080) {
11900 regN = INSNT0(3,0);
11901 regD = INSNT1(11,8);
11902 regM = INSNT1(3,0);
11903 rotate = INSNT1(5,4);
11904 if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
11905 gate = True;
11907 } else {
11908 if (INSNA(27,20) == BITS8(0,1,1,0,1,0,0,0) &&
11909 INSNA(9,4) == BITS6(0,0,0,1,1,1) ) {
11910 regD = INSNA(15,12);
11911 regN = INSNA(19,16);
11912 regM = INSNA(3,0);
11913 rotate = INSNA(11,10);
11914 if (regD != 15 && regN != 15 && regM != 15)
11915 gate = True;
11919 if (gate) {
11920 IRTemp irt_regN = newTemp(Ity_I32);
11921 assign( irt_regN, isT ? getIRegT(regN) : getIRegA(regN) );
11923 IRTemp irt_regM = newTemp(Ity_I32);
11924 assign( irt_regM, isT ? getIRegT(regM) : getIRegA(regM) );
11926 IRTemp irt_rot = newTemp(Ity_I32);
11927 assign( irt_rot, genROR32(irt_regM, 8 * rotate) );
11929 /* FIXME Maybe we can write this arithmetic in shorter form. */
11930 IRExpr* resLo
11931 = binop(Iop_And32,
11932 binop(Iop_Add32,
11933 mkexpr(irt_regN),
11934 unop(Iop_16Uto32,
11935 unop(Iop_8Sto16,
11936 unop(Iop_32to8, mkexpr(irt_rot))))),
11937 mkU32(0x0000FFFF));
11939 IRExpr* resHi
11940 = binop(Iop_And32,
11941 binop(Iop_Add32,
11942 mkexpr(irt_regN),
11943 binop(Iop_Shl32,
11944 unop(Iop_16Uto32,
11945 unop(Iop_8Sto16,
11946 unop(Iop_32to8,
11947 binop(Iop_Shr32,
11948 mkexpr(irt_rot),
11949 mkU8(16))))),
11950 mkU8(16))),
11951 mkU32(0xFFFF0000));
11953 IRExpr* ire_result
11954 = binop( Iop_Or32, resHi, resLo );
11956 if (isT)
11957 putIRegT( regD, ire_result, condT );
11958 else
11959 putIRegA( regD, ire_result, condT, Ijk_Boring );
11961 DIP( "sxtab16%s r%u, r%u, r%u, ROR #%u\n",
11962 nCC(conq), regD, regN, regM, 8 * rotate );
11963 return True;
11965 /* fall through */
11968 /* ----------------- shasx<c> <Rd>,<Rn>,<Rm> ------------------- */
11970 UInt regD = 99, regN = 99, regM = 99;
11971 Bool gate = False;
11973 if (isT) {
11974 if (INSNT0(15,4) == 0xFAA && (INSNT1(15,0) & 0xF0F0) == 0xF020) {
11975 regN = INSNT0(3,0);
11976 regD = INSNT1(11,8);
11977 regM = INSNT1(3,0);
11978 if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
11979 gate = True;
11981 } else {
11982 if (INSNA(27,20) == BITS8(0,1,1,0,0,0,1,1) &&
11983 INSNA(11,8) == BITS4(1,1,1,1) &&
11984 INSNA(7,4) == BITS4(0,0,1,1)) {
11985 regD = INSNA(15,12);
11986 regN = INSNA(19,16);
11987 regM = INSNA(3,0);
11988 if (regD != 15 && regN != 15 && regM != 15)
11989 gate = True;
11993 if (gate) {
11994 IRTemp rNt = newTemp(Ity_I32);
11995 IRTemp rMt = newTemp(Ity_I32);
11996 IRTemp irt_diff = newTemp(Ity_I32);
11997 IRTemp irt_sum = newTemp(Ity_I32);
11998 IRTemp res_q = newTemp(Ity_I32);
12000 assign( rNt, isT ? getIRegT(regN) : getIRegA(regN) );
12001 assign( rMt, isT ? getIRegT(regM) : getIRegA(regM) );
12003 assign( irt_diff,
12004 binop(Iop_Sub32,
12005 unop(Iop_16Sto32,
12006 unop(Iop_32to16,
12007 mkexpr(rNt)
12010 unop(Iop_16Sto32,
12011 unop(Iop_32to16,
12012 binop(Iop_Shr32,
12013 mkexpr(rMt), mkU8(16)
12020 assign( irt_sum,
12021 binop(Iop_Add32,
12022 unop(Iop_16Sto32,
12023 unop(Iop_32to16,
12024 binop(Iop_Shr32,
12025 mkexpr(rNt), mkU8(16)
12029 unop(Iop_16Sto32,
12030 unop(Iop_32to16, mkexpr(rMt)
12036 assign( res_q,
12037 binop(Iop_Or32,
12038 unop(Iop_16Uto32,
12039 unop(Iop_32to16,
12040 binop(Iop_Shr32,
12041 mkexpr(irt_diff), mkU8(1)
12045 binop(Iop_Shl32,
12046 binop(Iop_Shr32,
12047 mkexpr(irt_sum), mkU8(1)
12049 mkU8(16)
12054 if (isT)
12055 putIRegT( regD, mkexpr(res_q), condT );
12056 else
12057 putIRegA( regD, mkexpr(res_q), condT, Ijk_Boring );
12059 DIP("shasx%s r%u, r%u, r%u\n", nCC(conq),regD,regN,regM);
12060 return True;
12062 /* fall through */
12065 /* ----------------- uhasx<c> <Rd>,<Rn>,<Rm> ------------------- */
12067 UInt regD = 99, regN = 99, regM = 99;
12068 Bool gate = False;
12070 if (isT) {
12071 if (INSNT0(15,4) == 0xFAA && (INSNT1(15,0) & 0xF0F0) == 0xF060) {
12072 regN = INSNT0(3,0);
12073 regD = INSNT1(11,8);
12074 regM = INSNT1(3,0);
12075 if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
12076 gate = True;
12078 } else {
12079 if (INSNA(27,20) == BITS8(0,1,1,0,0,1,1,1) &&
12080 INSNA(11,8) == BITS4(1,1,1,1) &&
12081 INSNA(7,4) == BITS4(0,0,1,1)) {
12082 regD = INSNA(15,12);
12083 regN = INSNA(19,16);
12084 regM = INSNA(3,0);
12085 if (regD != 15 && regN != 15 && regM != 15)
12086 gate = True;
12090 if (gate) {
12091 IRTemp rNt = newTemp(Ity_I32);
12092 IRTemp rMt = newTemp(Ity_I32);
12093 IRTemp irt_diff = newTemp(Ity_I32);
12094 IRTemp irt_sum = newTemp(Ity_I32);
12095 IRTemp res_q = newTemp(Ity_I32);
12097 assign( rNt, isT ? getIRegT(regN) : getIRegA(regN) );
12098 assign( rMt, isT ? getIRegT(regM) : getIRegA(regM) );
12100 assign( irt_diff,
12101 binop(Iop_Sub32,
12102 unop(Iop_16Uto32,
12103 unop(Iop_32to16,
12104 mkexpr(rNt)
12107 unop(Iop_16Uto32,
12108 unop(Iop_32to16,
12109 binop(Iop_Shr32,
12110 mkexpr(rMt), mkU8(16)
12117 assign( irt_sum,
12118 binop(Iop_Add32,
12119 unop(Iop_16Uto32,
12120 unop(Iop_32to16,
12121 binop(Iop_Shr32,
12122 mkexpr(rNt), mkU8(16)
12126 unop(Iop_16Uto32,
12127 unop(Iop_32to16, mkexpr(rMt)
12133 assign( res_q,
12134 binop(Iop_Or32,
12135 unop(Iop_16Uto32,
12136 unop(Iop_32to16,
12137 binop(Iop_Shr32,
12138 mkexpr(irt_diff), mkU8(1)
12142 binop(Iop_Shl32,
12143 binop(Iop_Shr32,
12144 mkexpr(irt_sum), mkU8(1)
12146 mkU8(16)
12151 if (isT)
12152 putIRegT( regD, mkexpr(res_q), condT );
12153 else
12154 putIRegA( regD, mkexpr(res_q), condT, Ijk_Boring );
12156 DIP("uhasx%s r%u, r%u, r%u\n", nCC(conq),regD,regN,regM);
12157 return True;
12159 /* fall through */
12162 /* ----------------- shsax<c> <Rd>,<Rn>,<Rm> ------------------- */
12164 UInt regD = 99, regN = 99, regM = 99;
12165 Bool gate = False;
12167 if (isT) {
12168 if (INSNT0(15,4) == 0xFAE && (INSNT1(15,0) & 0xF0F0) == 0xF020) {
12169 regN = INSNT0(3,0);
12170 regD = INSNT1(11,8);
12171 regM = INSNT1(3,0);
12172 if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
12173 gate = True;
12175 } else {
12176 if (INSNA(27,20) == BITS8(0,1,1,0,0,0,1,1) &&
12177 INSNA(11,8) == BITS4(1,1,1,1) &&
12178 INSNA(7,4) == BITS4(0,1,0,1)) {
12179 regD = INSNA(15,12);
12180 regN = INSNA(19,16);
12181 regM = INSNA(3,0);
12182 if (regD != 15 && regN != 15 && regM != 15)
12183 gate = True;
12187 if (gate) {
12188 IRTemp rNt = newTemp(Ity_I32);
12189 IRTemp rMt = newTemp(Ity_I32);
12190 IRTemp irt_diff = newTemp(Ity_I32);
12191 IRTemp irt_sum = newTemp(Ity_I32);
12192 IRTemp res_q = newTemp(Ity_I32);
12194 assign( rNt, isT ? getIRegT(regN) : getIRegA(regN) );
12195 assign( rMt, isT ? getIRegT(regM) : getIRegA(regM) );
12197 assign( irt_sum,
12198 binop(Iop_Add32,
12199 unop(Iop_16Sto32,
12200 unop(Iop_32to16,
12201 mkexpr(rNt)
12204 unop(Iop_16Sto32,
12205 unop(Iop_32to16,
12206 binop(Iop_Shr32,
12207 mkexpr(rMt), mkU8(16)
12214 assign( irt_diff,
12215 binop(Iop_Sub32,
12216 unop(Iop_16Sto32,
12217 unop(Iop_32to16,
12218 binop(Iop_Shr32,
12219 mkexpr(rNt), mkU8(16)
12223 unop(Iop_16Sto32,
12224 unop(Iop_32to16, mkexpr(rMt)
12230 assign( res_q,
12231 binop(Iop_Or32,
12232 unop(Iop_16Uto32,
12233 unop(Iop_32to16,
12234 binop(Iop_Shr32,
12235 mkexpr(irt_sum), mkU8(1)
12239 binop(Iop_Shl32,
12240 binop(Iop_Shr32,
12241 mkexpr(irt_diff), mkU8(1)
12243 mkU8(16)
12248 if (isT)
12249 putIRegT( regD, mkexpr(res_q), condT );
12250 else
12251 putIRegA( regD, mkexpr(res_q), condT, Ijk_Boring );
12253 DIP("shsax%s r%u, r%u, r%u\n", nCC(conq),regD,regN,regM);
12254 return True;
12256 /* fall through */
12259 /* ----------------- uhsax<c> <Rd>,<Rn>,<Rm> ------------------- */
12261 UInt regD = 99, regN = 99, regM = 99;
12262 Bool gate = False;
12264 if (isT) {
12265 if (INSNT0(15,4) == 0xFAE && (INSNT1(15,0) & 0xF0F0) == 0xF060) {
12266 regN = INSNT0(3,0);
12267 regD = INSNT1(11,8);
12268 regM = INSNT1(3,0);
12269 if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
12270 gate = True;
12272 } else {
12273 if (INSNA(27,20) == BITS8(0,1,1,0,0,1,1,1) &&
12274 INSNA(11,8) == BITS4(1,1,1,1) &&
12275 INSNA(7,4) == BITS4(0,1,0,1)) {
12276 regD = INSNA(15,12);
12277 regN = INSNA(19,16);
12278 regM = INSNA(3,0);
12279 if (regD != 15 && regN != 15 && regM != 15)
12280 gate = True;
12284 if (gate) {
12285 IRTemp rNt = newTemp(Ity_I32);
12286 IRTemp rMt = newTemp(Ity_I32);
12287 IRTemp irt_diff = newTemp(Ity_I32);
12288 IRTemp irt_sum = newTemp(Ity_I32);
12289 IRTemp res_q = newTemp(Ity_I32);
12291 assign( rNt, isT ? getIRegT(regN) : getIRegA(regN) );
12292 assign( rMt, isT ? getIRegT(regM) : getIRegA(regM) );
12294 assign( irt_sum,
12295 binop(Iop_Add32,
12296 unop(Iop_16Uto32,
12297 unop(Iop_32to16,
12298 mkexpr(rNt)
12301 unop(Iop_16Uto32,
12302 unop(Iop_32to16,
12303 binop(Iop_Shr32,
12304 mkexpr(rMt), mkU8(16)
12311 assign( irt_diff,
12312 binop(Iop_Sub32,
12313 unop(Iop_16Uto32,
12314 unop(Iop_32to16,
12315 binop(Iop_Shr32,
12316 mkexpr(rNt), mkU8(16)
12320 unop(Iop_16Uto32,
12321 unop(Iop_32to16, mkexpr(rMt)
12327 assign( res_q,
12328 binop(Iop_Or32,
12329 unop(Iop_16Uto32,
12330 unop(Iop_32to16,
12331 binop(Iop_Shr32,
12332 mkexpr(irt_sum), mkU8(1)
12336 binop(Iop_Shl32,
12337 binop(Iop_Shr32,
12338 mkexpr(irt_diff), mkU8(1)
12340 mkU8(16)
12345 if (isT)
12346 putIRegT( regD, mkexpr(res_q), condT );
12347 else
12348 putIRegA( regD, mkexpr(res_q), condT, Ijk_Boring );
12350 DIP("uhsax%s r%u, r%u, r%u\n", nCC(conq),regD,regN,regM);
12351 return True;
12353 /* fall through */
12356 /* ----------------- shsub16<c> <Rd>,<Rn>,<Rm> ------------------- */
12358 UInt regD = 99, regN = 99, regM = 99;
12359 Bool gate = False;
12361 if (isT) {
12362 if (INSNT0(15,4) == 0xFAD && (INSNT1(15,0) & 0xF0F0) == 0xF020) {
12363 regN = INSNT0(3,0);
12364 regD = INSNT1(11,8);
12365 regM = INSNT1(3,0);
12366 if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
12367 gate = True;
12369 } else {
12370 if (INSNA(27,20) == BITS8(0,1,1,0,0,0,1,1) &&
12371 INSNA(11,8) == BITS4(1,1,1,1) &&
12372 INSNA(7,4) == BITS4(0,1,1,1)) {
12373 regD = INSNA(15,12);
12374 regN = INSNA(19,16);
12375 regM = INSNA(3,0);
12376 if (regD != 15 && regN != 15 && regM != 15)
12377 gate = True;
12381 if (gate) {
12382 IRTemp rNt = newTemp(Ity_I32);
12383 IRTemp rMt = newTemp(Ity_I32);
12384 IRTemp res_q = newTemp(Ity_I32);
12386 assign( rNt, isT ? getIRegT(regN) : getIRegA(regN) );
12387 assign( rMt, isT ? getIRegT(regM) : getIRegA(regM) );
12389 assign(res_q, binop(Iop_HSub16Sx2, mkexpr(rNt), mkexpr(rMt)));
12390 if (isT)
12391 putIRegT( regD, mkexpr(res_q), condT );
12392 else
12393 putIRegA( regD, mkexpr(res_q), condT, Ijk_Boring );
12395 DIP("shsub16%s r%u, r%u, r%u\n", nCC(conq),regD,regN,regM);
12396 return True;
12398 /* fall through */
12401 /* ----------------- smmls{r}<c> <Rd>,<Rn>,<Rm>,<Ra> ------------------- */
12403 UInt rD = 99, rN = 99, rM = 99, rA = 99;
12404 Bool round = False;
12405 Bool gate = False;
12407 if (isT) {
12408 if (INSNT0(15,7) == BITS9(1,1,1,1,1,0,1,1,0)
12409 && INSNT0(6,4) == BITS3(1,1,0)
12410 && INSNT1(7,5) == BITS3(0,0,0)) {
12411 round = INSNT1(4,4);
12412 rA = INSNT1(15,12);
12413 rD = INSNT1(11,8);
12414 rM = INSNT1(3,0);
12415 rN = INSNT0(3,0);
12416 if (!isBadRegT(rD)
12417 && !isBadRegT(rN) && !isBadRegT(rM) && !isBadRegT(rA))
12418 gate = True;
12420 } else {
12421 if (INSNA(27,20) == BITS8(0,1,1,1,0,1,0,1)
12422 && INSNA(15,12) != BITS4(1,1,1,1)
12423 && (INSNA(7,4) & BITS4(1,1,0,1)) == BITS4(1,1,0,1)) {
12424 round = INSNA(5,5);
12425 rD = INSNA(19,16);
12426 rA = INSNA(15,12);
12427 rM = INSNA(11,8);
12428 rN = INSNA(3,0);
12429 if (rD != 15 && rM != 15 && rN != 15)
12430 gate = True;
12433 if (gate) {
12434 IRTemp irt_rA = newTemp(Ity_I32);
12435 IRTemp irt_rN = newTemp(Ity_I32);
12436 IRTemp irt_rM = newTemp(Ity_I32);
12437 assign( irt_rA, isT ? getIRegT(rA) : getIRegA(rA) );
12438 assign( irt_rN, isT ? getIRegT(rN) : getIRegA(rN) );
12439 assign( irt_rM, isT ? getIRegT(rM) : getIRegA(rM) );
12440 IRExpr* res
12441 = unop(Iop_64HIto32,
12442 binop(Iop_Add64,
12443 binop(Iop_Sub64,
12444 binop(Iop_32HLto64, mkexpr(irt_rA), mkU32(0)),
12445 binop(Iop_MullS32, mkexpr(irt_rN), mkexpr(irt_rM))),
12446 mkU64(round ? 0x80000000ULL : 0ULL)));
12447 if (isT)
12448 putIRegT( rD, res, condT );
12449 else
12450 putIRegA(rD, res, condT, Ijk_Boring);
12451 DIP("smmls%s%s r%u, r%u, r%u, r%u\n",
12452 round ? "r" : "", nCC(conq), rD, rN, rM, rA);
12453 return True;
12455 /* fall through */
12458 /* -------------- smlald{x}<c> <RdLo>,<RdHi>,<Rn>,<Rm> ---------------- */
12460 UInt rN = 99, rDlo = 99, rDhi = 99, rM = 99;
12461 Bool m_swap = False;
12462 Bool gate = False;
12464 if (isT) {
12465 if (INSNT0(15,4) == 0xFBC &&
12466 (INSNT1(7,4) & BITS4(1,1,1,0)) == BITS4(1,1,0,0)) {
12467 rN = INSNT0(3,0);
12468 rDlo = INSNT1(15,12);
12469 rDhi = INSNT1(11,8);
12470 rM = INSNT1(3,0);
12471 m_swap = (INSNT1(4,4) & 1) == 1;
12472 if (!isBadRegT(rDlo) && !isBadRegT(rDhi) && !isBadRegT(rN)
12473 && !isBadRegT(rM) && rDhi != rDlo)
12474 gate = True;
12476 } else {
12477 if (INSNA(27,20) == BITS8(0,1,1,1,0,1,0,0)
12478 && (INSNA(7,4) & BITS4(1,1,0,1)) == BITS4(0,0,0,1)) {
12479 rN = INSNA(3,0);
12480 rDlo = INSNA(15,12);
12481 rDhi = INSNA(19,16);
12482 rM = INSNA(11,8);
12483 m_swap = ( INSNA(5,5) & 1 ) == 1;
12484 if (rDlo != 15 && rDhi != 15
12485 && rN != 15 && rM != 15 && rDlo != rDhi)
12486 gate = True;
12490 if (gate) {
12491 IRTemp irt_rM = newTemp(Ity_I32);
12492 IRTemp irt_rN = newTemp(Ity_I32);
12493 IRTemp irt_rDhi = newTemp(Ity_I32);
12494 IRTemp irt_rDlo = newTemp(Ity_I32);
12495 IRTemp op_2 = newTemp(Ity_I32);
12496 IRTemp pr_1 = newTemp(Ity_I64);
12497 IRTemp pr_2 = newTemp(Ity_I64);
12498 IRTemp result = newTemp(Ity_I64);
12499 IRTemp resHi = newTemp(Ity_I32);
12500 IRTemp resLo = newTemp(Ity_I32);
12501 assign( irt_rM, isT ? getIRegT(rM) : getIRegA(rM));
12502 assign( irt_rN, isT ? getIRegT(rN) : getIRegA(rN));
12503 assign( irt_rDhi, isT ? getIRegT(rDhi) : getIRegA(rDhi));
12504 assign( irt_rDlo, isT ? getIRegT(rDlo) : getIRegA(rDlo));
12505 assign( op_2, genROR32(irt_rM, m_swap ? 16 : 0) );
12506 assign( pr_1, binop(Iop_MullS32,
12507 unop(Iop_16Sto32,
12508 unop(Iop_32to16, mkexpr(irt_rN))
12510 unop(Iop_16Sto32,
12511 unop(Iop_32to16, mkexpr(op_2))
12515 assign( pr_2, binop(Iop_MullS32,
12516 binop(Iop_Sar32, mkexpr(irt_rN), mkU8(16)),
12517 binop(Iop_Sar32, mkexpr(op_2), mkU8(16))
12520 assign( result, binop(Iop_Add64,
12521 binop(Iop_Add64,
12522 mkexpr(pr_1),
12523 mkexpr(pr_2)
12525 binop(Iop_32HLto64,
12526 mkexpr(irt_rDhi),
12527 mkexpr(irt_rDlo)
12531 assign( resHi, unop(Iop_64HIto32, mkexpr(result)) );
12532 assign( resLo, unop(Iop_64to32, mkexpr(result)) );
12533 if (isT) {
12534 putIRegT( rDhi, mkexpr(resHi), condT );
12535 putIRegT( rDlo, mkexpr(resLo), condT );
12536 } else {
12537 putIRegA( rDhi, mkexpr(resHi), condT, Ijk_Boring );
12538 putIRegA( rDlo, mkexpr(resLo), condT, Ijk_Boring );
12540 DIP("smlald%c%s r%u, r%u, r%u, r%u\n",
12541 m_swap ? 'x' : ' ', nCC(conq), rDlo, rDhi, rN, rM);
12542 return True;
12544 /* fall through */
12547 /* -------------- smlsld{x}<c> <RdLo>,<RdHi>,<Rn>,<Rm> ---------------- */
12549 UInt rN = 99, rDlo = 99, rDhi = 99, rM = 99;
12550 Bool m_swap = False;
12551 Bool gate = False;
12553 if (isT) {
12554 if ((INSNT0(15,4) == 0xFBD &&
12555 (INSNT1(7,4) & BITS4(1,1,1,0)) == BITS4(1,1,0,0))) {
12556 rN = INSNT0(3,0);
12557 rDlo = INSNT1(15,12);
12558 rDhi = INSNT1(11,8);
12559 rM = INSNT1(3,0);
12560 m_swap = (INSNT1(4,4) & 1) == 1;
12561 if (!isBadRegT(rDlo) && !isBadRegT(rDhi) && !isBadRegT(rN) &&
12562 !isBadRegT(rM) && rDhi != rDlo)
12563 gate = True;
12565 } else {
12566 if (INSNA(27,20) == BITS8(0,1,1,1,0,1,0,0) &&
12567 (INSNA(7,4) & BITS4(1,1,0,1)) == BITS4(0,1,0,1)) {
12568 rN = INSNA(3,0);
12569 rDlo = INSNA(15,12);
12570 rDhi = INSNA(19,16);
12571 rM = INSNA(11,8);
12572 m_swap = (INSNA(5,5) & 1) == 1;
12573 if (rDlo != 15 && rDhi != 15 &&
12574 rN != 15 && rM != 15 && rDlo != rDhi)
12575 gate = True;
12578 if (gate) {
12579 IRTemp irt_rM = newTemp(Ity_I32);
12580 IRTemp irt_rN = newTemp(Ity_I32);
12581 IRTemp irt_rDhi = newTemp(Ity_I32);
12582 IRTemp irt_rDlo = newTemp(Ity_I32);
12583 IRTemp op_2 = newTemp(Ity_I32);
12584 IRTemp pr_1 = newTemp(Ity_I64);
12585 IRTemp pr_2 = newTemp(Ity_I64);
12586 IRTemp result = newTemp(Ity_I64);
12587 IRTemp resHi = newTemp(Ity_I32);
12588 IRTemp resLo = newTemp(Ity_I32);
12589 assign( irt_rM, isT ? getIRegT(rM) : getIRegA(rM) );
12590 assign( irt_rN, isT ? getIRegT(rN) : getIRegA(rN) );
12591 assign( irt_rDhi, isT ? getIRegT(rDhi) : getIRegA(rDhi) );
12592 assign( irt_rDlo, isT ? getIRegT(rDlo) : getIRegA(rDlo) );
12593 assign( op_2, genROR32(irt_rM, m_swap ? 16 : 0) );
12594 assign( pr_1, binop(Iop_MullS32,
12595 unop(Iop_16Sto32,
12596 unop(Iop_32to16, mkexpr(irt_rN))
12598 unop(Iop_16Sto32,
12599 unop(Iop_32to16, mkexpr(op_2))
12603 assign( pr_2, binop(Iop_MullS32,
12604 binop(Iop_Sar32, mkexpr(irt_rN), mkU8(16)),
12605 binop(Iop_Sar32, mkexpr(op_2), mkU8(16))
12608 assign( result, binop(Iop_Add64,
12609 binop(Iop_Sub64,
12610 mkexpr(pr_1),
12611 mkexpr(pr_2)
12613 binop(Iop_32HLto64,
12614 mkexpr(irt_rDhi),
12615 mkexpr(irt_rDlo)
12619 assign( resHi, unop(Iop_64HIto32, mkexpr(result)) );
12620 assign( resLo, unop(Iop_64to32, mkexpr(result)) );
12621 if (isT) {
12622 putIRegT( rDhi, mkexpr(resHi), condT );
12623 putIRegT( rDlo, mkexpr(resLo), condT );
12624 } else {
12625 putIRegA( rDhi, mkexpr(resHi), condT, Ijk_Boring );
12626 putIRegA( rDlo, mkexpr(resLo), condT, Ijk_Boring );
12628 DIP("smlsld%c%s r%u, r%u, r%u, r%u\n",
12629 m_swap ? 'x' : ' ', nCC(conq), rDlo, rDhi, rN, rM);
12630 return True;
12632 /* fall through */
12635 /* ---------- Doesn't match anything. ---------- */
12636 return False;
12638 # undef INSNA
12639 # undef INSNT0
12640 # undef INSNT1
12644 /*------------------------------------------------------------*/
12645 /*--- V8 instructions ---*/
12646 /*------------------------------------------------------------*/
12648 /* Break a V128-bit value up into four 32-bit ints. */
12650 static void breakupV128to32s ( IRTemp t128,
12651 /*OUTs*/
12652 IRTemp* t3, IRTemp* t2,
12653 IRTemp* t1, IRTemp* t0 )
12655 IRTemp hi64 = newTemp(Ity_I64);
12656 IRTemp lo64 = newTemp(Ity_I64);
12657 assign( hi64, unop(Iop_V128HIto64, mkexpr(t128)) );
12658 assign( lo64, unop(Iop_V128to64, mkexpr(t128)) );
12660 vassert(t0 && *t0 == IRTemp_INVALID);
12661 vassert(t1 && *t1 == IRTemp_INVALID);
12662 vassert(t2 && *t2 == IRTemp_INVALID);
12663 vassert(t3 && *t3 == IRTemp_INVALID);
12665 *t0 = newTemp(Ity_I32);
12666 *t1 = newTemp(Ity_I32);
12667 *t2 = newTemp(Ity_I32);
12668 *t3 = newTemp(Ity_I32);
12669 assign( *t0, unop(Iop_64to32, mkexpr(lo64)) );
12670 assign( *t1, unop(Iop_64HIto32, mkexpr(lo64)) );
12671 assign( *t2, unop(Iop_64to32, mkexpr(hi64)) );
12672 assign( *t3, unop(Iop_64HIto32, mkexpr(hi64)) );
12676 /* Both ARM and Thumb */
12678 /* Translate a V8 instruction. If successful, returns True and *dres
12679 may or may not be updated. If unsuccessful, returns False and
12680 doesn't change *dres nor create any IR.
12682 The Thumb and ARM encodings are potentially different. In both
12683 ARM and Thumb mode, the caller must pass the entire 32 bits of
12684 the instruction. Callers may pass any instruction; this function
12685 ignores anything it doesn't recognise.
12687 Caller must supply an IRTemp 'condT' holding the gating condition,
12688 or IRTemp_INVALID indicating the insn is always executed.
12690 If we are decoding an ARM instruction which is in the NV space
12691 then it is expected that condT will be IRTemp_INVALID, and that is
12692 asserted for. That condition is ensured by the logic near the top
12693 of disInstr_ARM_WRK, that sets up condT.
12695 When decoding for Thumb, the caller must pass the ITState pre/post
12696 this instruction, so that we can generate a SIGILL in the cases where
12697 the instruction may not be in an IT block. When decoding for ARM,
12698 both of these must be IRTemp_INVALID.
12700 Finally, the caller must indicate whether this occurs in ARM or in
12701 Thumb code.
12703 static Bool decode_V8_instruction (
12704 /*MOD*/DisResult* dres,
12705 UInt insnv8,
12706 IRTemp condT,
12707 Bool isT,
12708 IRTemp old_itstate,
12709 IRTemp new_itstate
12712 # define INSN(_bMax,_bMin) SLICE_UInt(insnv8, (_bMax), (_bMin))
12714 if (isT) {
12715 vassert(old_itstate != IRTemp_INVALID);
12716 vassert(new_itstate != IRTemp_INVALID);
12717 } else {
12718 vassert(old_itstate == IRTemp_INVALID);
12719 vassert(new_itstate == IRTemp_INVALID);
12722 /* ARMCondcode 'conq' is only used for debug printing and for no other
12723 purpose. For ARM, this is simply the top 4 bits of the instruction.
12724 For Thumb, the condition is not (really) known until run time, and so
12725 we set it to ARMCondAL in order that printing of these instructions
12726 does not show any condition. */
12727 ARMCondcode conq;
12728 if (isT) {
12729 conq = ARMCondAL;
12730 } else {
12731 conq = (ARMCondcode)INSN(31,28);
12732 if (conq == ARMCondNV || conq == ARMCondAL) {
12733 vassert(condT == IRTemp_INVALID);
12734 } else {
12735 vassert(condT != IRTemp_INVALID);
12737 vassert(conq >= ARMCondEQ && conq <= ARMCondNV);
12740 /* ----------- {AESD, AESE, AESMC, AESIMC}.8 q_q ----------- */
12741 /* 31 27 23 21 19 17 15 11 7 3
12742 T1: 1111 1111 1 D 11 sz 00 d 0011 00 M 0 m AESE Qd, Qm
12743 A1: 1111 0011 1 D 11 sz 00 d 0011 00 M 0 m AESE Qd, Qm
12745 T1: 1111 1111 1 D 11 sz 00 d 0011 01 M 0 m AESD Qd, Qm
12746 A1: 1111 0011 1 D 11 sz 00 d 0011 01 M 0 m AESD Qd, Qm
12748 T1: 1111 1111 1 D 11 sz 00 d 0011 10 M 0 m AESMC Qd, Qm
12749 A1: 1111 0011 1 D 11 sz 00 d 0011 10 M 0 m AESMC Qd, Qm
12751 T1: 1111 1111 1 D 11 sz 00 d 0011 11 M 0 m AESIMC Qd, Qm
12752 A1: 1111 0011 1 D 11 sz 00 d 0011 11 M 0 m AESIMC Qd, Qm
12754 sz must be 00
12755 ARM encoding is in NV space.
12756 In Thumb mode, we must not be in an IT block.
12759 UInt regD = 99, regM = 99, opc = 4/*invalid*/;
12760 Bool gate = True;
12762 UInt high9 = isT ? BITS9(1,1,1,1,1,1,1,1,1) : BITS9(1,1,1,1,0,0,1,1,1);
12763 if (INSN(31,23) == high9 && INSN(21,16) == BITS6(1,1,0,0,0,0)
12764 && INSN(11,8) == BITS4(0,0,1,1) && INSN(4,4) == 0) {
12765 UInt bitD = INSN(22,22);
12766 UInt fldD = INSN(15,12);
12767 UInt bitM = INSN(5,5);
12768 UInt fldM = INSN(3,0);
12769 opc = INSN(7,6);
12770 regD = (bitD << 4) | fldD;
12771 regM = (bitM << 4) | fldM;
12773 if ((regD & 1) == 1 || (regM & 1) == 1)
12774 gate = False;
12776 if (gate) {
12777 if (isT) {
12778 gen_SIGILL_T_if_in_ITBlock(old_itstate, new_itstate);
12780 /* In ARM mode, this is statically unconditional. In Thumb mode,
12781 this must be dynamically unconditional, and we've SIGILLd if not.
12782 In either case we can create unconditional IR. */
12783 IRTemp op1 = newTemp(Ity_V128);
12784 IRTemp op2 = newTemp(Ity_V128);
12785 IRTemp src = newTemp(Ity_V128);
12786 IRTemp res = newTemp(Ity_V128);
12787 assign(op1, getQReg(regD >> 1));
12788 assign(op2, getQReg(regM >> 1));
12789 assign(src, opc == BITS2(0,0) || opc == BITS2(0,1)
12790 ? binop(Iop_XorV128, mkexpr(op1), mkexpr(op2))
12791 : mkexpr(op2));
12793 void* helpers[4]
12794 = { &armg_dirtyhelper_AESE, &armg_dirtyhelper_AESD,
12795 &armg_dirtyhelper_AESMC, &armg_dirtyhelper_AESIMC };
12796 const HChar* hNames[4]
12797 = { "armg_dirtyhelper_AESE", "armg_dirtyhelper_AESD",
12798 "armg_dirtyhelper_AESMC", "armg_dirtyhelper_AESIMC" };
12799 const HChar* iNames[4]
12800 = { "aese", "aesd", "aesmc", "aesimc" };
12802 vassert(opc >= 0 && opc <= 3);
12803 void* helper = helpers[opc];
12804 const HChar* hname = hNames[opc];
12806 IRTemp w32_3, w32_2, w32_1, w32_0;
12807 w32_3 = w32_2 = w32_1 = w32_0 = IRTemp_INVALID;
12808 breakupV128to32s( src, &w32_3, &w32_2, &w32_1, &w32_0 );
12810 IRDirty* di
12811 = unsafeIRDirty_1_N( res, 0/*regparms*/, hname, helper,
12812 mkIRExprVec_5(
12813 IRExpr_VECRET(),
12814 mkexpr(w32_3), mkexpr(w32_2),
12815 mkexpr(w32_1), mkexpr(w32_0)) );
12816 stmt(IRStmt_Dirty(di));
12818 putQReg(regD >> 1, mkexpr(res), IRTemp_INVALID);
12819 DIP("%s.8 q%d, q%d\n", iNames[opc], regD >> 1, regM >> 1);
12820 return True;
12822 /* fall through */
12825 /* ----------- SHA 3-reg insns q_q_q ----------- */
12827 31 27 23 19 15 11 7 3
12828 T1: 1110 1111 0 D 00 n d 1100 N Q M 0 m SHA1C Qd, Qn, Qm ix=0
12829 A1: 1111 0010 ----------------------------
12831 T1: 1110 1111 0 D 01 n d 1100 N Q M 0 m SHA1P Qd, Qn, Qm ix=1
12832 A1: 1111 0010 ----------------------------
12834 T1: 1110 1111 0 D 10 n d 1100 N Q M 0 m SHA1M Qd, Qn, Qm ix=2
12835 A1: 1111 0010 ----------------------------
12837 T1: 1110 1111 0 D 11 n d 1100 N Q M 0 m SHA1SU0 Qd, Qn, Qm ix=3
12838 A1: 1111 0010 ----------------------------
12839 (that's a complete set of 4, based on insn[21,20])
12841 T1: 1111 1111 0 D 00 n d 1100 N Q M 0 m SHA256H Qd, Qn, Qm ix=4
12842 A1: 1111 0011 ----------------------------
12844 T1: 1111 1111 0 D 01 n d 1100 N Q M 0 m SHA256H2 Qd, Qn, Qm ix=5
12845 A1: 1111 0011 ----------------------------
12847 T1: 1111 1111 0 D 10 n d 1100 N Q M 0 m SHA256SU1 Qd, Qn, Qm ix=6
12848 A1: 1111 0011 ----------------------------
12849 (3/4 of a complete set of 4, based on insn[21,20])
12851 Q must be 1. Same comments about conditionalisation as for the AES
12852 group above apply.
12855 UInt ix = 8; /* invalid */
12856 Bool gate = False;
12858 UInt hi9_sha1 = isT ? BITS9(1,1,1,0,1,1,1,1,0)
12859 : BITS9(1,1,1,1,0,0,1,0,0);
12860 UInt hi9_sha256 = isT ? BITS9(1,1,1,1,1,1,1,1,0)
12861 : BITS9(1,1,1,1,0,0,1,1,0);
12862 if ((INSN(31,23) == hi9_sha1 || INSN(31,23) == hi9_sha256)
12863 && INSN(11,8) == BITS4(1,1,0,0)
12864 && INSN(6,6) == 1 && INSN(4,4) == 0) {
12865 ix = INSN(21,20);
12866 if (INSN(31,23) == hi9_sha256)
12867 ix |= 4;
12868 if (ix < 7)
12869 gate = True;
12872 UInt regN = (INSN(7,7) << 4) | INSN(19,16);
12873 UInt regD = (INSN(22,22) << 4) | INSN(15,12);
12874 UInt regM = (INSN(5,5) << 4) | INSN(3,0);
12875 if ((regD & 1) == 1 || (regM & 1) == 1 || (regN & 1) == 1)
12876 gate = False;
12878 if (gate) {
12879 vassert(ix >= 0 && ix < 7);
12880 const HChar* inames[7]
12881 = { "sha1c", "sha1p", "sha1m", "sha1su0",
12882 "sha256h", "sha256h2", "sha256su1" };
12883 void(*helpers[7])(V128*,UInt,UInt,UInt,UInt,UInt,UInt,
12884 UInt,UInt,UInt,UInt,UInt,UInt)
12885 = { &armg_dirtyhelper_SHA1C, &armg_dirtyhelper_SHA1P,
12886 &armg_dirtyhelper_SHA1M, &armg_dirtyhelper_SHA1SU0,
12887 &armg_dirtyhelper_SHA256H, &armg_dirtyhelper_SHA256H2,
12888 &armg_dirtyhelper_SHA256SU1 };
12889 const HChar* hnames[7]
12890 = { "armg_dirtyhelper_SHA1C", "armg_dirtyhelper_SHA1P",
12891 "armg_dirtyhelper_SHA1M", "armg_dirtyhelper_SHA1SU0",
12892 "armg_dirtyhelper_SHA256H", "armg_dirtyhelper_SHA256H2",
12893 "armg_dirtyhelper_SHA256SU1" };
12895 /* This is a really lame way to implement this, even worse than
12896 the arm64 version. But at least it works. */
12898 if (isT) {
12899 gen_SIGILL_T_if_in_ITBlock(old_itstate, new_itstate);
12902 IRTemp vD = newTemp(Ity_V128);
12903 IRTemp vN = newTemp(Ity_V128);
12904 IRTemp vM = newTemp(Ity_V128);
12905 assign(vD, getQReg(regD >> 1));
12906 assign(vN, getQReg(regN >> 1));
12907 assign(vM, getQReg(regM >> 1));
12909 IRTemp d32_3, d32_2, d32_1, d32_0;
12910 d32_3 = d32_2 = d32_1 = d32_0 = IRTemp_INVALID;
12911 breakupV128to32s( vD, &d32_3, &d32_2, &d32_1, &d32_0 );
12913 IRTemp n32_3_pre, n32_2_pre, n32_1_pre, n32_0_pre;
12914 n32_3_pre = n32_2_pre = n32_1_pre = n32_0_pre = IRTemp_INVALID;
12915 breakupV128to32s( vN, &n32_3_pre, &n32_2_pre, &n32_1_pre, &n32_0_pre );
12917 IRTemp m32_3, m32_2, m32_1, m32_0;
12918 m32_3 = m32_2 = m32_1 = m32_0 = IRTemp_INVALID;
12919 breakupV128to32s( vM, &m32_3, &m32_2, &m32_1, &m32_0 );
12921 IRTemp n32_3 = newTemp(Ity_I32);
12922 IRTemp n32_2 = newTemp(Ity_I32);
12923 IRTemp n32_1 = newTemp(Ity_I32);
12924 IRTemp n32_0 = newTemp(Ity_I32);
12926 /* Mask off any bits of the N register operand that aren't actually
12927 needed, so that Memcheck doesn't complain unnecessarily. */
12928 switch (ix) {
12929 case 0: case 1: case 2:
12930 assign(n32_3, mkU32(0));
12931 assign(n32_2, mkU32(0));
12932 assign(n32_1, mkU32(0));
12933 assign(n32_0, mkexpr(n32_0_pre));
12934 break;
12935 case 3: case 4: case 5: case 6:
12936 assign(n32_3, mkexpr(n32_3_pre));
12937 assign(n32_2, mkexpr(n32_2_pre));
12938 assign(n32_1, mkexpr(n32_1_pre));
12939 assign(n32_0, mkexpr(n32_0_pre));
12940 break;
12941 default:
12942 vassert(0);
12945 IRExpr** argvec
12946 = mkIRExprVec_13(
12947 IRExpr_VECRET(),
12948 mkexpr(d32_3), mkexpr(d32_2), mkexpr(d32_1), mkexpr(d32_0),
12949 mkexpr(n32_3), mkexpr(n32_2), mkexpr(n32_1), mkexpr(n32_0),
12950 mkexpr(m32_3), mkexpr(m32_2), mkexpr(m32_1), mkexpr(m32_0)
12953 IRTemp res = newTemp(Ity_V128);
12954 IRDirty* di = unsafeIRDirty_1_N( res, 0/*regparms*/,
12955 hnames[ix], helpers[ix], argvec );
12956 stmt(IRStmt_Dirty(di));
12957 putQReg(regD >> 1, mkexpr(res), IRTemp_INVALID);
12959 DIP("%s.8 q%u, q%u, q%u\n",
12960 inames[ix], regD >> 1, regN >> 1, regM >> 1);
12961 return True;
12963 /* fall through */
12966 /* ----------- SHA1SU1, SHA256SU0 ----------- */
12968 31 27 23 21 19 15 11 7 3
12969 T1: 1111 1111 1 D 11 1010 d 0011 10 M 0 m SHA1SU1 Qd, Qm
12970 A1: 1111 0011 ----------------------------
12972 T1: 1111 1111 1 D 11 1010 d 0011 11 M 0 m SHA256SU0 Qd, Qm
12973 A1: 1111 0011 ----------------------------
12975 Same comments about conditionalisation as for the AES group above apply.
12978 Bool gate = False;
12980 UInt hi9 = isT ? BITS9(1,1,1,1,1,1,1,1,1) : BITS9(1,1,1,1,0,0,1,1,1);
12981 if (INSN(31,23) == hi9 && INSN(21,16) == BITS6(1,1,1,0,1,0)
12982 && INSN(11,7) == BITS5(0,0,1,1,1) && INSN(4,4) == 0) {
12983 gate = True;
12986 UInt regD = (INSN(22,22) << 4) | INSN(15,12);
12987 UInt regM = (INSN(5,5) << 4) | INSN(3,0);
12988 if ((regD & 1) == 1 || (regM & 1) == 1)
12989 gate = False;
12991 Bool is_1SU1 = INSN(6,6) == 0;
12993 if (gate) {
12994 const HChar* iname
12995 = is_1SU1 ? "sha1su1" : "sha256su0";
12996 void (*helper)(V128*,UInt,UInt,UInt,UInt,UInt,UInt,UInt,UInt)
12997 = is_1SU1 ? &armg_dirtyhelper_SHA1SU1
12998 : *armg_dirtyhelper_SHA256SU0;
12999 const HChar* hname
13000 = is_1SU1 ? "armg_dirtyhelper_SHA1SU1"
13001 : "armg_dirtyhelper_SHA256SU0";
13003 if (isT) {
13004 gen_SIGILL_T_if_in_ITBlock(old_itstate, new_itstate);
13007 IRTemp vD = newTemp(Ity_V128);
13008 IRTemp vM = newTemp(Ity_V128);
13009 assign(vD, getQReg(regD >> 1));
13010 assign(vM, getQReg(regM >> 1));
13012 IRTemp d32_3, d32_2, d32_1, d32_0;
13013 d32_3 = d32_2 = d32_1 = d32_0 = IRTemp_INVALID;
13014 breakupV128to32s( vD, &d32_3, &d32_2, &d32_1, &d32_0 );
13016 IRTemp m32_3, m32_2, m32_1, m32_0;
13017 m32_3 = m32_2 = m32_1 = m32_0 = IRTemp_INVALID;
13018 breakupV128to32s( vM, &m32_3, &m32_2, &m32_1, &m32_0 );
13020 IRExpr** argvec
13021 = mkIRExprVec_9(
13022 IRExpr_VECRET(),
13023 mkexpr(d32_3), mkexpr(d32_2), mkexpr(d32_1), mkexpr(d32_0),
13024 mkexpr(m32_3), mkexpr(m32_2), mkexpr(m32_1), mkexpr(m32_0)
13027 IRTemp res = newTemp(Ity_V128);
13028 IRDirty* di = unsafeIRDirty_1_N( res, 0/*regparms*/,
13029 hname, helper, argvec );
13030 stmt(IRStmt_Dirty(di));
13031 putQReg(regD >> 1, mkexpr(res), IRTemp_INVALID);
13033 DIP("%s.8 q%u, q%u\n", iname, regD >> 1, regM >> 1);
13034 return True;
13036 /* fall through */
13039 /* ----------- SHA1H ----------- */
13041 31 27 23 21 19 15 11 7 3
13042 T1: 1111 1111 1 D 11 1001 d 0010 11 M 0 m SHA1H Qd, Qm
13043 A1: 1111 0011 ----------------------------
13045 Same comments about conditionalisation as for the AES group above apply.
13048 Bool gate = False;
13050 UInt hi9 = isT ? BITS9(1,1,1,1,1,1,1,1,1) : BITS9(1,1,1,1,0,0,1,1,1);
13051 if (INSN(31,23) == hi9 && INSN(21,16) == BITS6(1,1,1,0,0,1)
13052 && INSN(11,6) == BITS6(0,0,1,0,1,1) && INSN(4,4) == 0) {
13053 gate = True;
13056 UInt regD = (INSN(22,22) << 4) | INSN(15,12);
13057 UInt regM = (INSN(5,5) << 4) | INSN(3,0);
13058 if ((regD & 1) == 1 || (regM & 1) == 1)
13059 gate = False;
13061 if (gate) {
13062 const HChar* iname = "sha1h";
13063 void (*helper)(V128*,UInt,UInt,UInt,UInt) = &armg_dirtyhelper_SHA1H;
13064 const HChar* hname = "armg_dirtyhelper_SHA1H";
13066 if (isT) {
13067 gen_SIGILL_T_if_in_ITBlock(old_itstate, new_itstate);
13070 IRTemp vM = newTemp(Ity_V128);
13071 assign(vM, getQReg(regM >> 1));
13073 IRTemp m32_3, m32_2, m32_1, m32_0;
13074 m32_3 = m32_2 = m32_1 = m32_0 = IRTemp_INVALID;
13075 breakupV128to32s( vM, &m32_3, &m32_2, &m32_1, &m32_0 );
13076 /* m32_3, m32_2, m32_1 are just abandoned. No harm; iropt will
13077 remove them. */
13079 IRExpr* zero = mkU32(0);
13080 IRExpr** argvec = mkIRExprVec_5(IRExpr_VECRET(),
13081 zero, zero, zero, mkexpr(m32_0));
13083 IRTemp res = newTemp(Ity_V128);
13084 IRDirty* di = unsafeIRDirty_1_N( res, 0/*regparms*/,
13085 hname, helper, argvec );
13086 stmt(IRStmt_Dirty(di));
13087 putQReg(regD >> 1, mkexpr(res), IRTemp_INVALID);
13089 DIP("%s.8 q%u, q%u\n", iname, regD >> 1, regM >> 1);
13090 return True;
13092 /* fall through */
13095 /* ----------- VMULL.P64 ----------- */
13097 31 27 23 21 19 15 11 7 3
13098 T2: 1110 1111 1 D 10 n d 1110 N 0 M 0 m
13099 A2: 1111 0010 -------------------------
13101 The ARM documentation is pretty difficult to follow here.
13102 Same comments about conditionalisation as for the AES group above apply.
13105 Bool gate = False;
13107 UInt hi9 = isT ? BITS9(1,1,1,0,1,1,1,1,1) : BITS9(1,1,1,1,0,0,1,0,1);
13108 if (INSN(31,23) == hi9 && INSN(21,20) == BITS2(1,0)
13109 && INSN(11,8) == BITS4(1,1,1,0)
13110 && INSN(6,6) == 0 && INSN(4,4) == 0) {
13111 gate = True;
13114 UInt regN = (INSN(7,7) << 4) | INSN(19,16);
13115 UInt regD = (INSN(22,22) << 4) | INSN(15,12);
13116 UInt regM = (INSN(5,5) << 4) | INSN(3,0);
13118 if ((regD & 1) == 1)
13119 gate = False;
13121 if (gate) {
13122 const HChar* iname = "vmull";
13123 void (*helper)(V128*,UInt,UInt,UInt,UInt) = &armg_dirtyhelper_VMULLP64;
13124 const HChar* hname = "armg_dirtyhelper_VMULLP64";
13126 if (isT) {
13127 gen_SIGILL_T_if_in_ITBlock(old_itstate, new_itstate);
13130 IRTemp srcN = newTemp(Ity_I64);
13131 IRTemp srcM = newTemp(Ity_I64);
13132 assign(srcN, getDRegI64(regN));
13133 assign(srcM, getDRegI64(regM));
13135 IRExpr** argvec = mkIRExprVec_5(IRExpr_VECRET(),
13136 unop(Iop_64HIto32, mkexpr(srcN)),
13137 unop(Iop_64to32, mkexpr(srcN)),
13138 unop(Iop_64HIto32, mkexpr(srcM)),
13139 unop(Iop_64to32, mkexpr(srcM)));
13141 IRTemp res = newTemp(Ity_V128);
13142 IRDirty* di = unsafeIRDirty_1_N( res, 0/*regparms*/,
13143 hname, helper, argvec );
13144 stmt(IRStmt_Dirty(di));
13145 putQReg(regD >> 1, mkexpr(res), IRTemp_INVALID);
13147 DIP("%s.p64 q%u, q%u, w%u\n", iname, regD >> 1, regN, regM);
13148 return True;
13150 /* fall through */
13153 /* ----------- LDA{,B,H}, STL{,B,H} ----------- */
13154 /* 31 27 23 19 15 11 7 3
13155 A1: cond 0001 1001 n t 1100 1001 1111 LDA Rt, [Rn]
13156 A1: cond 0001 1111 n t 1100 1001 1111 LDAH Rt, [Rn]
13157 A1: cond 0001 1101 n t 1100 1001 1111 LDAB Rt, [Rn]
13159 A1: cond 0001 1000 n 1111 1100 1001 t STL Rt, [Rn]
13160 A1: cond 0001 1110 n 1111 1100 1001 t STLH Rt, [Rn]
13161 A1: cond 0001 1100 n 1111 1100 1001 t STLB Rt, [Rn]
13163 T1: 1110 1000 1101 n t 1111 1010 1111 LDA Rt, [Rn]
13164 T1: 1110 1000 1101 n t 1111 1001 1111 LDAH Rt, [Rn]
13165 T1: 1110 1000 1101 n t 1111 1000 1111 LDAB Rt, [Rn]
13167 T1: 1110 1000 1100 n t 1111 1010 1111 STL Rt, [Rn]
13168 T1: 1110 1000 1100 n t 1111 1001 1111 STLH Rt, [Rn]
13169 T1: 1110 1000 1100 n t 1111 1000 1111 STLB Rt, [Rn]
13172 UInt nn = 16; // invalid
13173 UInt tt = 16; // invalid
13174 UInt szBlg2 = 4; // invalid
13175 Bool isLoad = False;
13176 Bool gate = False;
13177 if (isT) {
13178 if (INSN(31,21) == BITS11(1,1,1,0,1,0,0,0,1,1,0)
13179 && INSN(11,6) == BITS6(1,1,1,1,1,0)
13180 && INSN(3,0) == BITS4(1,1,1,1)) {
13181 nn = INSN(19,16);
13182 tt = INSN(15,12);
13183 isLoad = INSN(20,20) == 1;
13184 szBlg2 = INSN(5,4); // 00:B 01:H 10:W 11:invalid
13185 gate = szBlg2 != BITS2(1,1) && tt != 15 && nn != 15;
13187 } else {
13188 if (INSN(27,23) == BITS5(0,0,0,1,1) && INSN(20,20) == 1
13189 && INSN(11,0) == BITS12(1,1,0,0,1,0,0,1,1,1,1,1)) {
13190 nn = INSN(19,16);
13191 tt = INSN(15,12);
13192 isLoad = True;
13193 szBlg2 = INSN(22,21); // 10:B 11:H 00:W 01:invalid
13194 gate = szBlg2 != BITS2(0,1) && tt != 15 && nn != 15;
13196 else
13197 if (INSN(27,23) == BITS5(0,0,0,1,1) && INSN(20,20) == 0
13198 && INSN(15,4) == BITS12(1,1,1,1,1,1,0,0,1,0,0,1)) {
13199 nn = INSN(19,16);
13200 tt = INSN(3,0);
13201 isLoad = False;
13202 szBlg2 = INSN(22,21); // 10:B 11:H 00:W 01:invalid
13203 gate = szBlg2 != BITS2(0,1) && tt != 15 && nn != 15;
13205 if (gate) {
13206 // Rearrange szBlg2 bits to be the same as the Thumb case
13207 switch (szBlg2) {
13208 case 2: szBlg2 = 0; break;
13209 case 3: szBlg2 = 1; break;
13210 case 0: szBlg2 = 2; break;
13211 default: /*NOTREACHED*/vassert(0);
13215 // For both encodings, the instruction is guarded by condT, which
13216 // is passed in by the caller. Note that the the loads and stores
13217 // are conditional, so we don't have to truncate the IRSB at this
13218 // point, but the fence is unconditional. There's no way to
13219 // represent a conditional fence without a side exit, but it
13220 // doesn't matter from a correctness standpoint that it is
13221 // unconditional -- it just loses a bit of performance in the
13222 // case where the condition doesn't hold.
13223 if (gate) {
13224 vassert(szBlg2 <= 2 && nn <= 14 && tt <= 14);
13225 IRExpr* ea = llGetIReg(nn);
13226 if (isLoad) {
13227 static IRLoadGOp cvt[3]
13228 = { ILGop_8Uto32, ILGop_16Uto32, ILGop_Ident32 };
13229 IRTemp data = newTemp(Ity_I32);
13230 loadGuardedLE(data, cvt[szBlg2], ea, mkU32(0)/*alt*/, condT);
13231 if (isT) {
13232 putIRegT(tt, mkexpr(data), condT);
13233 } else {
13234 putIRegA(tt, mkexpr(data), condT, Ijk_INVALID);
13236 stmt(IRStmt_MBE(Imbe_Fence));
13237 } else {
13238 stmt(IRStmt_MBE(Imbe_Fence));
13239 IRExpr* data = llGetIReg(tt);
13240 switch (szBlg2) {
13241 case 0: data = unop(Iop_32to8, data); break;
13242 case 1: data = unop(Iop_32to16, data); break;
13243 case 2: break;
13244 default: vassert(0);
13246 storeGuardedLE(ea, data, condT);
13248 const HChar* ldNames[3] = { "ldab", "ldah", "lda" };
13249 const HChar* stNames[3] = { "stlb", "stlh", "stl" };
13250 DIP("%s r%u, [r%u]", (isLoad ? ldNames : stNames)[szBlg2], tt, nn);
13251 return True;
13253 /* else fall through */
13256 /* ----------- LDAEX{,B,H,D}, STLEX{,B,H,D} ----------- */
13257 /* 31 27 23 19 15 11 7 3
13258 A1: cond 0001 1101 n t 1110 1001 1111 LDAEXB Rt, [Rn]
13259 A1: cond 0001 1111 n t 1110 1001 1111 LDAEXH Rt, [Rn]
13260 A1: cond 0001 1001 n t 1110 1001 1111 LDAEX Rt, [Rn]
13261 A1: cond 0001 1011 n t 1110 1001 1111 LDAEXD Rt, Rt+1, [Rn]
13263 A1: cond 0001 1100 n d 1110 1001 t STLEXB Rd, Rt, [Rn]
13264 A1: cond 0001 1110 n d 1110 1001 t STLEXH Rd, Rt, [Rn]
13265 A1: cond 0001 1000 n d 1110 1001 t STLEX Rd, Rt, [Rn]
13266 A1: cond 0001 1010 n d 1110 1001 t STLEXD Rd, Rt, Rt+1, [Rn]
13268 31 28 24 19 15 11 7 3
13269 T1: 111 0100 01101 n t 1111 1100 1111 LDAEXB Rt, [Rn]
13270 T1: 111 0100 01101 n t 1111 1101 1111 LDAEXH Rt, [Rn]
13271 T1: 111 0100 01101 n t 1111 1110 1111 LDAEX Rt, [Rn]
13272 T1: 111 0100 01101 n t t2 1111 1111 LDAEXD Rt, Rt2, [Rn]
13274 T1: 111 0100 01100 n t 1111 1100 d STLEXB Rd, Rt, [Rn]
13275 T1: 111 0100 01100 n t 1111 1101 d STLEXH Rd, Rt, [Rn]
13276 T1: 111 0100 01100 n t 1111 1110 d STLEX Rd, Rt, [Rn]
13277 T1: 111 0100 01100 n t t2 1111 d STLEXD Rd, Rt, Rt2, [Rn]
13280 UInt nn = 16; // invalid
13281 UInt tt = 16; // invalid
13282 UInt tt2 = 16; // invalid
13283 UInt dd = 16; // invalid
13284 UInt szBlg2 = 4; // invalid
13285 Bool isLoad = False;
13286 Bool gate = False;
13287 if (isT) {
13288 if (INSN(31,21) == BITS11(1,1,1,0,1,0,0,0,1,1,0)
13289 && INSN(7,6) == BITS2(1,1)) {
13290 isLoad = INSN(20,20) == 1;
13291 nn = INSN(19,16);
13292 tt = INSN(15,12);
13293 tt2 = INSN(11,8);
13294 szBlg2 = INSN(5,4);
13295 dd = INSN(3,0);
13296 gate = True;
13297 if (szBlg2 < BITS2(1,1) && tt2 != BITS4(1,1,1,1)) gate = False;
13298 if (isLoad && dd != BITS4(1,1,1,1)) gate = False;
13299 // re-set not-used register values to invalid
13300 if (szBlg2 < BITS2(1,1)) tt2 = 16;
13301 if (isLoad) dd = 16;
13303 } else {
13304 /* ARM encoding. Do the load and store cases separately as
13305 the register numbers are in different places and a combined decode
13306 is too confusing. */
13307 if (INSN(27,23) == BITS5(0,0,0,1,1) && INSN(20,20) == 1
13308 && INSN(11,0) == BITS12(1,1,1,0,1,0,0,1,1,1,1,1)) {
13309 szBlg2 = INSN(22,21);
13310 isLoad = True;
13311 nn = INSN(19,16);
13312 tt = INSN(15,12);
13313 gate = True;
13315 else
13316 if (INSN(27,23) == BITS5(0,0,0,1,1) && INSN(20,20) == 0
13317 && INSN(11,4) == BITS8(1,1,1,0,1,0,0,1)) {
13318 szBlg2 = INSN(22,21);
13319 isLoad = False;
13320 nn = INSN(19,16);
13321 dd = INSN(15,12);
13322 tt = INSN(3,0);
13323 gate = True;
13325 if (gate) {
13326 // Rearrange szBlg2 bits to be the same as the Thumb case
13327 switch (szBlg2) {
13328 case 2: szBlg2 = 0; break;
13329 case 3: szBlg2 = 1; break;
13330 case 0: szBlg2 = 2; break;
13331 case 1: szBlg2 = 3; break;
13332 default: /*NOTREACHED*/vassert(0);
13336 // Perform further checks on register numbers
13337 if (gate) {
13338 /**/ if (isT && isLoad) {
13339 // Thumb load
13340 if (szBlg2 < 3) {
13341 if (! (tt != 13 && tt != 15 && nn != 15)) gate = False;
13342 } else {
13343 if (! (tt != 13 && tt != 15 && tt2 != 13 && tt2 != 15
13344 && tt != tt2 && nn != 15)) gate = False;
13347 else if (isT && !isLoad) {
13348 // Thumb store
13349 if (szBlg2 < 3) {
13350 if (! (dd != 13 && dd != 15 && tt != 13 && tt != 15
13351 && nn != 15 && dd != nn && dd != tt)) gate = False;
13352 } else {
13353 if (! (dd != 13 && dd != 15 && tt != 13 && tt != 15
13354 && tt2 != 13 && tt2 != 15 && nn != 15 && dd != nn
13355 && dd != tt && dd != tt2)) gate = False;
13358 else if (!isT && isLoad) {
13359 // ARM Load
13360 if (szBlg2 < 3) {
13361 if (! (tt != 15 && nn != 15)) gate = False;
13362 } else {
13363 if (! ((tt & 1) == 0 && tt != 14 && nn != 15)) gate = False;
13364 vassert(tt2 == 16/*invalid*/);
13365 tt2 = tt + 1;
13368 else if (!isT && !isLoad) {
13369 // ARM Store
13370 if (szBlg2 < 3) {
13371 if (! (dd != 15 && tt != 15 && nn != 15
13372 && dd != nn && dd != tt)) gate = False;
13373 } else {
13374 if (! (dd != 15 && (tt & 1) == 0 && tt != 14 && nn != 15
13375 && dd != nn && dd != tt && dd != tt+1)) gate = False;
13376 vassert(tt2 == 16/*invalid*/);
13377 tt2 = tt + 1;
13380 else /*NOTREACHED*/vassert(0);
13382 if (gate) {
13383 // Paranoia ..
13384 vassert(szBlg2 <= 3);
13385 if (szBlg2 < 3) { vassert(tt2 == 16/*invalid*/); }
13386 else { vassert(tt2 <= 14); }
13387 if (isLoad) { vassert(dd == 16/*invalid*/); }
13388 else { vassert(dd <= 14); }
13390 // If we're still good even after all that, generate the IR.
13391 if (gate) {
13392 /* First, go unconditional. Staying in-line is too complex. */
13393 if (isT) {
13394 vassert(condT != IRTemp_INVALID);
13395 mk_skip_over_T32_if_cond_is_false( condT );
13396 } else {
13397 if (condT != IRTemp_INVALID) {
13398 mk_skip_over_A32_if_cond_is_false( condT );
13399 condT = IRTemp_INVALID;
13402 /* Now the load or store. */
13403 IRType ty = Ity_INVALID; /* the type of the transferred data */
13404 const HChar* nm = NULL;
13405 switch (szBlg2) {
13406 case 0: nm = "b"; ty = Ity_I8; break;
13407 case 1: nm = "h"; ty = Ity_I16; break;
13408 case 2: nm = ""; ty = Ity_I32; break;
13409 case 3: nm = "d"; ty = Ity_I64; break;
13410 default: vassert(0);
13412 IRExpr* ea = isT ? getIRegT(nn) : getIRegA(nn);
13413 if (isLoad) {
13414 // LOAD. Transaction, then fence.
13415 IROp widen = Iop_INVALID;
13416 switch (szBlg2) {
13417 case 0: widen = Iop_8Uto32; break;
13418 case 1: widen = Iop_16Uto32; break;
13419 case 2: case 3: break;
13420 default: vassert(0);
13422 IRTemp res = newTemp(ty);
13423 // FIXME: assumes little-endian guest
13424 stmt( IRStmt_LLSC(Iend_LE, res, ea, NULL/*this is a load*/) );
13426 # define PUT_IREG(_nnz, _eez) \
13427 do { vassert((_nnz) <= 14); /* no writes to the PC */ \
13428 if (isT) { putIRegT((_nnz), (_eez), IRTemp_INVALID); } \
13429 else { putIRegA((_nnz), (_eez), \
13430 IRTemp_INVALID, Ijk_Boring); } } while(0)
13431 if (ty == Ity_I64) {
13432 // FIXME: assumes little-endian guest
13433 PUT_IREG(tt, unop(Iop_64to32, mkexpr(res)));
13434 PUT_IREG(tt2, unop(Iop_64HIto32, mkexpr(res)));
13435 } else {
13436 PUT_IREG(tt, widen == Iop_INVALID
13437 ? mkexpr(res) : unop(widen, mkexpr(res)));
13439 stmt(IRStmt_MBE(Imbe_Fence));
13440 if (ty == Ity_I64) {
13441 DIP("ldrex%s%s r%u, r%u, [r%u]\n",
13442 nm, isT ? "" : nCC(conq), tt, tt2, nn);
13443 } else {
13444 DIP("ldrex%s%s r%u, [r%u]\n", nm, isT ? "" : nCC(conq), tt, nn);
13446 # undef PUT_IREG
13447 } else {
13448 // STORE. Fence, then transaction.
13449 IRTemp resSC1, resSC32, data;
13450 IROp narrow = Iop_INVALID;
13451 switch (szBlg2) {
13452 case 0: narrow = Iop_32to8; break;
13453 case 1: narrow = Iop_32to16; break;
13454 case 2: case 3: break;
13455 default: vassert(0);
13457 stmt(IRStmt_MBE(Imbe_Fence));
13458 data = newTemp(ty);
13459 # define GET_IREG(_nnz) (isT ? getIRegT(_nnz) : getIRegA(_nnz))
13460 assign(data,
13461 ty == Ity_I64
13462 // FIXME: assumes little-endian guest
13463 ? binop(Iop_32HLto64, GET_IREG(tt2), GET_IREG(tt))
13464 : narrow == Iop_INVALID
13465 ? GET_IREG(tt)
13466 : unop(narrow, GET_IREG(tt)));
13467 # undef GET_IREG
13468 resSC1 = newTemp(Ity_I1);
13469 // FIXME: assumes little-endian guest
13470 stmt( IRStmt_LLSC(Iend_LE, resSC1, ea, mkexpr(data)) );
13472 /* Set rDD to 1 on failure, 0 on success. Currently we have
13473 resSC1 == 0 on failure, 1 on success. */
13474 resSC32 = newTemp(Ity_I32);
13475 assign(resSC32,
13476 unop(Iop_1Uto32, unop(Iop_Not1, mkexpr(resSC1))));
13477 vassert(dd <= 14); /* no writes to the PC */
13478 if (isT) {
13479 putIRegT(dd, mkexpr(resSC32), IRTemp_INVALID);
13480 } else {
13481 putIRegA(dd, mkexpr(resSC32), IRTemp_INVALID, Ijk_Boring);
13483 if (ty == Ity_I64) {
13484 DIP("strex%s%s r%u, r%u, r%u, [r%u]\n",
13485 nm, isT ? "" : nCC(conq), dd, tt, tt2, nn);
13486 } else {
13487 DIP("strex%s%s r%u, r%u, [r%u]\n",
13488 nm, isT ? "" : nCC(conq), dd, tt, nn);
13490 } /* if (isLoad) */
13491 return True;
13492 } /* if (gate) */
13493 /* else fall through */
13496 /* ----------- VSEL<c>.F64 d_d_d, VSEL<c>.F32 s_s_s ----------- */
13497 /* 31 27 22 21 19 15 11 8 7 6 5 4 3
13498 T1/A1: 1111 11100 D cc n d 101 1 N 0 M 0 m VSEL<c>.F64 Dd, Dn, Dm
13499 T1/A1: 1111 11100 D cc n d 101 0 N 0 M 0 m VSEL<c>.F32 Sd, Sn, Sm
13501 ARM encoding is in NV space.
13502 In Thumb mode, we must not be in an IT block.
13504 if (INSN(31,23) == BITS9(1,1,1,1,1,1,1,0,0) && INSN(11,9) == BITS3(1,0,1)
13505 && INSN(6,6) == 0 && INSN(4,4) == 0) {
13506 UInt bit_D = INSN(22,22);
13507 UInt fld_cc = INSN(21,20);
13508 UInt fld_n = INSN(19,16);
13509 UInt fld_d = INSN(15,12);
13510 Bool isF64 = INSN(8,8) == 1;
13511 UInt bit_N = INSN(7,7);
13512 UInt bit_M = INSN(5,5);
13513 UInt fld_m = INSN(3,0);
13515 UInt dd = isF64 ? ((bit_D << 4) | fld_d) : ((fld_d << 1) | bit_D);
13516 UInt nn = isF64 ? ((bit_N << 4) | fld_n) : ((fld_n << 1) | bit_N);
13517 UInt mm = isF64 ? ((bit_M << 4) | fld_m) : ((fld_m << 1) | bit_M);
13519 UInt cc_1 = (fld_cc >> 1) & 1;
13520 UInt cc_0 = (fld_cc >> 0) & 1;
13521 UInt cond = (fld_cc << 2) | ((cc_1 ^ cc_0) << 1) | 0;
13523 if (isT) {
13524 gen_SIGILL_T_if_in_ITBlock(old_itstate, new_itstate);
13526 /* In ARM mode, this is statically unconditional. In Thumb mode,
13527 this must be dynamically unconditional, and we've SIGILLd if not.
13528 In either case we can create unconditional IR. */
13530 IRTemp guard = newTemp(Ity_I32);
13531 assign(guard, mk_armg_calculate_condition(cond));
13532 IRExpr* srcN = (isF64 ? llGetDReg : llGetFReg)(nn);
13533 IRExpr* srcM = (isF64 ? llGetDReg : llGetFReg)(mm);
13534 IRExpr* res = IRExpr_ITE(unop(Iop_32to1, mkexpr(guard)), srcN, srcM);
13535 (isF64 ? llPutDReg : llPutFReg)(dd, res);
13537 UChar rch = isF64 ? 'd' : 'f';
13538 DIP("vsel%s.%s %c%u, %c%u, %c%u\n",
13539 nCC(cond), isF64 ? "f64" : "f32", rch, dd, rch, nn, rch, mm);
13540 return True;
13543 /* -------- VRINT{A,N,P,M}.F64 d_d, VRINT{A,N,P,M}.F32 s_s -------- */
13544 /* 31 22 21 17 15 11 8 7 5 4 3
13545 T1/A1: 111111101 D 1110 rm Vd 101 1 01 M 0 Vm VRINT{A,N,P,M}.F64 Dd, Dm
13546 T1/A1: 111111101 D 1110 rm Vd 101 0 01 M 0 Vm VRINT{A,N,P,M}.F32 Sd, Sm
13548 ARM encoding is in NV space.
13549 In Thumb mode, we must not be in an IT block.
13551 if (INSN(31,23) == BITS9(1,1,1,1,1,1,1,0,1)
13552 && INSN(21,18) == BITS4(1,1,1,0) && INSN(11,9) == BITS3(1,0,1)
13553 && INSN(7,6) == BITS2(0,1) && INSN(4,4) == 0) {
13554 UInt bit_D = INSN(22,22);
13555 UInt fld_rm = INSN(17,16);
13556 UInt fld_d = INSN(15,12);
13557 Bool isF64 = INSN(8,8) == 1;
13558 UInt bit_M = INSN(5,5);
13559 UInt fld_m = INSN(3,0);
13561 UInt dd = isF64 ? ((bit_D << 4) | fld_d) : ((fld_d << 1) | bit_D);
13562 UInt mm = isF64 ? ((bit_M << 4) | fld_m) : ((fld_m << 1) | bit_M);
13564 if (isT) {
13565 gen_SIGILL_T_if_in_ITBlock(old_itstate, new_itstate);
13567 /* In ARM mode, this is statically unconditional. In Thumb mode,
13568 this must be dynamically unconditional, and we've SIGILLd if not.
13569 In either case we can create unconditional IR. */
13571 UChar c = '?';
13572 IRRoundingMode rm = Irrm_NEAREST;
13573 switch (fld_rm) {
13574 /* The use of NEAREST for both the 'a' and 'n' cases is a bit of a
13575 kludge since it doesn't take into account the nearest-even vs
13576 nearest-away semantics. */
13577 case BITS2(0,0): c = 'a'; rm = Irrm_NEAREST; break;
13578 case BITS2(0,1): c = 'n'; rm = Irrm_NEAREST; break;
13579 case BITS2(1,0): c = 'p'; rm = Irrm_PosINF; break;
13580 case BITS2(1,1): c = 'm'; rm = Irrm_NegINF; break;
13581 default: vassert(0);
13584 IRExpr* srcM = (isF64 ? llGetDReg : llGetFReg)(mm);
13585 IRExpr* res = binop(isF64 ? Iop_RoundF64toInt : Iop_RoundF32toInt,
13586 mkU32((UInt)rm), srcM);
13587 (isF64 ? llPutDReg : llPutFReg)(dd, res);
13589 UChar rch = isF64 ? 'd' : 'f';
13590 DIP("vrint%c.%s.%s %c%u, %c%u\n",
13591 c, isF64 ? "f64" : "f32", isF64 ? "f64" : "f32", rch, dd, rch, mm);
13592 return True;
13595 /* -------- VRINT{Z,R}.F64.F64 d_d, VRINT{Z,R}.F32.F32 s_s -------- */
13596 /* 31 27 22 21 15 11 7 6 5 4 3
13597 T1: 1110 11101 D 110110 Vd 1011 op 1 M 0 Vm VRINT<r><c>.F64.F64 Dd, Dm
13598 A1: cond 11101 D 110110 Vd 1011 op 1 M 0 Vm
13600 T1: 1110 11101 D 110110 Vd 1010 op 1 M 0 Vm VRINT<r><c>.F32.F32 Sd, Sm
13601 A1: cond 11101 D 110110 Vd 1010 op 1 M 0 Vm
13603 In contrast to the VRINT variants just above, this can be conditional.
13605 if ((isT ? (INSN(31,28) == BITS4(1,1,1,0)) : True)
13606 && INSN(27,23) == BITS5(1,1,1,0,1) && INSN(21,16) == BITS6(1,1,0,1,1,0)
13607 && INSN(11,9) == BITS3(1,0,1) && INSN(6,6) == 1 && INSN(4,4) == 0) {
13608 UInt bit_D = INSN(22,22);
13609 UInt fld_Vd = INSN(15,12);
13610 Bool isF64 = INSN(8,8) == 1;
13611 Bool rToZero = INSN(7,7) == 1;
13612 UInt bit_M = INSN(5,5);
13613 UInt fld_Vm = INSN(3,0);
13614 UInt dd = isF64 ? ((bit_D << 4) | fld_Vd) : ((fld_Vd << 1) | bit_D);
13615 UInt mm = isF64 ? ((bit_M << 4) | fld_Vm) : ((fld_Vm << 1) | bit_M);
13617 if (isT) vassert(condT != IRTemp_INVALID);
13618 IRType ty = isF64 ? Ity_F64 : Ity_F32;
13619 IRTemp src = newTemp(ty);
13620 IRTemp res = newTemp(ty);
13621 assign(src, (isF64 ? getDReg : getFReg)(mm));
13623 IRTemp rm = newTemp(Ity_I32);
13624 assign(rm, rToZero ? mkU32(Irrm_ZERO)
13625 : mkexpr(mk_get_IR_rounding_mode()));
13626 assign(res, binop(isF64 ? Iop_RoundF64toInt : Iop_RoundF32toInt,
13627 mkexpr(rm), mkexpr(src)));
13628 (isF64 ? putDReg : putFReg)(dd, mkexpr(res), condT);
13630 UChar rch = isF64 ? 'd' : 'f';
13631 DIP("vrint%c.%s.%s %c%u, %c%u\n",
13632 rToZero ? 'z' : 'r',
13633 isF64 ? "f64" : "f32", isF64 ? "f64" : "f32", rch, dd, rch, mm);
13634 return True;
13637 /* ----------- VCVT{A,N,P,M}{.S32,.U32}{.F64,.F32} ----------- */
13638 /* 31 27 22 21 17 15 11 8 7 6 5 4 3
13639 T1/A1: 1111 11101 D 1111 rm Vd 101 sz op 1 M 0 Vm
13640 VCVT{A,N,P,M}{.S32,.U32}.F64 Sd, Dm
13641 VCVT{A,N,P,M}{.S32,.U32}.F32 Sd, Sm
13643 ARM encoding is in NV space.
13644 In Thumb mode, we must not be in an IT block.
13646 if (INSN(31,23) == BITS9(1,1,1,1,1,1,1,0,1) && INSN(21,18) == BITS4(1,1,1,1)
13647 && INSN(11,9) == BITS3(1,0,1) && INSN(6,6) == 1 && INSN(4,4) == 0) {
13648 UInt bit_D = INSN(22,22);
13649 UInt fld_rm = INSN(17,16);
13650 UInt fld_Vd = INSN(15,12);
13651 Bool isF64 = INSN(8,8) == 1;
13652 Bool isU = INSN(7,7) == 0;
13653 UInt bit_M = INSN(5,5);
13654 UInt fld_Vm = INSN(3,0);
13656 UInt dd = (fld_Vd << 1) | bit_D;
13657 UInt mm = isF64 ? ((bit_M << 4) | fld_Vm) : ((fld_Vm << 1) | bit_M);
13659 if (isT) {
13660 gen_SIGILL_T_if_in_ITBlock(old_itstate, new_itstate);
13662 /* In ARM mode, this is statically unconditional. In Thumb mode,
13663 this must be dynamically unconditional, and we've SIGILLd if not.
13664 In either case we can create unconditional IR. */
13666 UChar c = '?';
13667 IRRoundingMode rm = Irrm_NEAREST;
13668 switch (fld_rm) {
13669 /* The use of NEAREST for both the 'a' and 'n' cases is a bit of a
13670 kludge since it doesn't take into account the nearest-even vs
13671 nearest-away semantics. */
13672 case BITS2(0,0): c = 'a'; rm = Irrm_NEAREST; break;
13673 case BITS2(0,1): c = 'n'; rm = Irrm_NEAREST; break;
13674 case BITS2(1,0): c = 'p'; rm = Irrm_PosINF; break;
13675 case BITS2(1,1): c = 'm'; rm = Irrm_NegINF; break;
13676 default: vassert(0);
13679 IRExpr* srcM = (isF64 ? llGetDReg : llGetFReg)(mm);
13680 IRTemp res = newTemp(Ity_I32);
13682 /* The arm back end doesn't support use of Iop_F32toI32U or
13683 Iop_F32toI32S, so for those cases we widen the F32 to F64
13684 and then follow the F64 route. */
13685 if (!isF64) {
13686 srcM = unop(Iop_F32toF64, srcM);
13688 assign(res, binop(isU ? Iop_F64toI32U : Iop_F64toI32S,
13689 mkU32((UInt)rm), srcM));
13691 llPutFReg(dd, unop(Iop_ReinterpI32asF32, mkexpr(res)));
13693 UChar rch = isF64 ? 'd' : 'f';
13694 DIP("vcvt%c.%s.%s %c%u, %c%u\n",
13695 c, isU ? "u32" : "s32", isF64 ? "f64" : "f32", 's', dd, rch, mm);
13696 return True;
13699 /* ----------- V{MAX,MIN}NM{.F64 d_d_d, .F32 s_s_s} ----------- */
13700 /* 31 27 22 21 19 15 11 8 7 6 5 4 3
13701 1111 11101 D 00 Vn Vd 101 1 N op M 0 Vm V{MIN,MAX}NM.F64 Dd, Dn, Dm
13702 1111 11101 D 00 Vn Vd 101 0 N op M 0 Vm V{MIN,MAX}NM.F32 Sd, Sn, Sm
13704 ARM encoding is in NV space.
13705 In Thumb mode, we must not be in an IT block.
13707 if (INSN(31,23) == BITS9(1,1,1,1,1,1,1,0,1) && INSN(21,20) == BITS2(0,0)
13708 && INSN(11,9) == BITS3(1,0,1) && INSN(4,4) == 0) {
13709 UInt bit_D = INSN(22,22);
13710 UInt fld_Vn = INSN(19,16);
13711 UInt fld_Vd = INSN(15,12);
13712 Bool isF64 = INSN(8,8) == 1;
13713 UInt bit_N = INSN(7,7);
13714 Bool isMAX = INSN(6,6) == 0;
13715 UInt bit_M = INSN(5,5);
13716 UInt fld_Vm = INSN(3,0);
13718 UInt dd = isF64 ? ((bit_D << 4) | fld_Vd) : ((fld_Vd << 1) | bit_D);
13719 UInt nn = isF64 ? ((bit_N << 4) | fld_Vn) : ((fld_Vn << 1) | bit_N);
13720 UInt mm = isF64 ? ((bit_M << 4) | fld_Vm) : ((fld_Vm << 1) | bit_M);
13722 if (isT) {
13723 gen_SIGILL_T_if_in_ITBlock(old_itstate, new_itstate);
13725 /* In ARM mode, this is statically unconditional. In Thumb mode,
13726 this must be dynamically unconditional, and we've SIGILLd if not.
13727 In either case we can create unconditional IR. */
13729 IROp op = isF64 ? (isMAX ? Iop_MaxNumF64 : Iop_MinNumF64)
13730 : (isMAX ? Iop_MaxNumF32 : Iop_MinNumF32);
13731 IRExpr* srcN = (isF64 ? llGetDReg : llGetFReg)(nn);
13732 IRExpr* srcM = (isF64 ? llGetDReg : llGetFReg)(mm);
13733 IRExpr* res = binop(op, srcN, srcM);
13734 (isF64 ? llPutDReg : llPutFReg)(dd, res);
13736 UChar rch = isF64 ? 'd' : 'f';
13737 DIP("v%snm.%s %c%u, %c%u, %c%u\n",
13738 isMAX ? "max" : "min", isF64 ? "f64" : "f32",
13739 rch, dd, rch, nn, rch, mm);
13740 return True;
13743 /* ----------- VRINTX.F64.F64 d_d, VRINTX.F32.F32 s_s ----------- */
13744 /* 31 27 22 21 15 11 8 7 5 4 3
13745 T1: 1110 11101 D 110111 Vd 101 1 01 M 0 Vm VRINTX<c>.F64.F64 Dd, Dm
13746 A1: cond 11101 D 110111 Vd 101 1 01 M 0 Vm
13748 T1: 1110 11101 D 110111 Vd 101 0 01 M 0 Vm VRINTX<c>.F32.F32 Dd, Dm
13749 A1: cond 11101 D 110111 Vd 101 0 01 M 0 Vm
13751 Like VRINT{Z,R}{.F64.F64, .F32.F32} just above, this can be conditional.
13752 This produces the same code as the VRINTR case since we ignore the
13753 requirement to signal inexactness.
13755 if ((isT ? (INSN(31,28) == BITS4(1,1,1,0)) : True)
13756 && INSN(27,23) == BITS5(1,1,1,0,1) && INSN(21,16) == BITS6(1,1,0,1,1,1)
13757 && INSN(11,9) == BITS3(1,0,1) && INSN(7,6) == BITS2(0,1)
13758 && INSN(4,4) == 0) {
13759 UInt bit_D = INSN(22,22);
13760 UInt fld_Vd = INSN(15,12);
13761 Bool isF64 = INSN(8,8) == 1;
13762 UInt bit_M = INSN(5,5);
13763 UInt fld_Vm = INSN(3,0);
13764 UInt dd = isF64 ? ((bit_D << 4) | fld_Vd) : ((fld_Vd << 1) | bit_D);
13765 UInt mm = isF64 ? ((bit_M << 4) | fld_Vm) : ((fld_Vm << 1) | bit_M);
13767 if (isT) vassert(condT != IRTemp_INVALID);
13768 IRType ty = isF64 ? Ity_F64 : Ity_F32;
13769 IRTemp src = newTemp(ty);
13770 IRTemp res = newTemp(ty);
13771 assign(src, (isF64 ? getDReg : getFReg)(mm));
13773 IRTemp rm = newTemp(Ity_I32);
13774 assign(rm, mkexpr(mk_get_IR_rounding_mode()));
13775 assign(res, binop(isF64 ? Iop_RoundF64toInt : Iop_RoundF32toInt,
13776 mkexpr(rm), mkexpr(src)));
13777 (isF64 ? putDReg : putFReg)(dd, mkexpr(res), condT);
13779 UChar rch = isF64 ? 'd' : 'f';
13780 DIP("vrint%c.%s.%s %c%u, %c%u\n",
13781 'x',
13782 isF64 ? "f64" : "f32", isF64 ? "f64" : "f32", rch, dd, rch, mm);
13783 return True;
13786 /* ----------- V{MAX,MIN}NM{.F32 d_d_d, .F32 q_q_q} ----------- */
13787 /* 31 27 22 21 20 19 15 11 7 6 5 4 3
13788 T1: 1111 11110 D op 0 Vn Vd 1111 N 1 M 1 Vm V{MIN,MAX}NM.F32 Qd,Qn,Qm
13789 A1: 1111 00110 D op 0 Vn Vd 1111 N 1 M 1 Vm
13791 T1: 1111 11110 D op 0 Vn Vd 1111 N 0 M 1 Vm V{MIN,MAX}NM.F32 Dd,Dn,Dm
13792 A1: 1111 00110 D op 0 Vn Vd 1111 N 0 M 1 Vm
13794 ARM encoding is in NV space.
13795 In Thumb mode, we must not be in an IT block.
13797 if (INSN(31,23) == (isT ? BITS9(1,1,1,1,1,1,1,1,0)
13798 : BITS9(1,1,1,1,0,0,1,1,0))
13799 && INSN(20,20) == 0 && INSN(11,8) == BITS4(1,1,1,1) && INSN(4,4) == 1) {
13800 UInt bit_D = INSN(22,22);
13801 Bool isMax = INSN(21,21) == 0;
13802 UInt fld_Vn = INSN(19,16);
13803 UInt fld_Vd = INSN(15,12);
13804 UInt bit_N = INSN(7,7);
13805 Bool isQ = INSN(6,6) == 1;
13806 UInt bit_M = INSN(5,5);
13807 UInt fld_Vm = INSN(3,0);
13809 /* dd, nn, mm are D-register numbers. */
13810 UInt dd = (bit_D << 4) | fld_Vd;
13811 UInt nn = (bit_N << 4) | fld_Vn;
13812 UInt mm = (bit_M << 4) | fld_Vm;
13814 if (! (isQ && ((dd & 1) == 1 || (nn & 1) == 1 || (mm & 1) == 1))) {
13815 /* Do this piecewise on f regs. This is a bit tricky
13816 though because we are dealing with the full 16 x Q == 32 x D
13817 register set, so the implied F reg numbers are 0 to 63. But
13818 ll{Get,Put}FReg only allow the 0 .. 31 as those are the only
13819 architected F regs. */
13820 UInt ddF = dd << 1;
13821 UInt nnF = nn << 1;
13822 UInt mmF = mm << 1;
13824 if (isT) {
13825 gen_SIGILL_T_if_in_ITBlock(old_itstate, new_itstate);
13827 /* In ARM mode, this is statically unconditional. In Thumb mode,
13828 this must be dynamically unconditional, and we've SIGILLd if not.
13829 In either case we can create unconditional IR. */
13831 IROp op = isMax ? Iop_MaxNumF32 : Iop_MinNumF32;
13833 IRTemp r0 = newTemp(Ity_F32);
13834 IRTemp r1 = newTemp(Ity_F32);
13835 IRTemp r2 = isQ ? newTemp(Ity_F32) : IRTemp_INVALID;
13836 IRTemp r3 = isQ ? newTemp(Ity_F32) : IRTemp_INVALID;
13838 assign(r0, binop(op, llGetFReg_up_to_64(nnF+0),
13839 llGetFReg_up_to_64(mmF+0)));
13840 assign(r1, binop(op, llGetFReg_up_to_64(nnF+1),
13841 llGetFReg_up_to_64(mmF+1)));
13842 if (isQ) {
13843 assign(r2, binop(op, llGetFReg_up_to_64(nnF+2),
13844 llGetFReg_up_to_64(mmF+2)));
13845 assign(r3, binop(op, llGetFReg_up_to_64(nnF+3),
13846 llGetFReg_up_to_64(mmF+3)));
13848 llPutFReg_up_to_64(ddF+0, mkexpr(r0));
13849 llPutFReg_up_to_64(ddF+1, mkexpr(r1));
13850 if (isQ) {
13851 llPutFReg_up_to_64(ddF+2, mkexpr(r2));
13852 llPutFReg_up_to_64(ddF+3, mkexpr(r3));
13855 HChar rch = isQ ? 'q' : 'd';
13856 UInt sh = isQ ? 1 : 0;
13857 DIP("v%snm.f32 %c%u, %c%u, %c%u\n",
13858 isMax ? "max" : "min", rch,
13859 dd >> sh, rch, nn >> sh, rch, mm >> sh);
13860 return True;
13862 /* else fall through */
13865 /* ----------- VCVT{A,N,P,M}{.F32 d_d, .F32 q_q} ----------- */
13866 /* 31 27 22 21 15 11 9 7 6 5 4 3
13867 T1: 1111 11111 D 111011 Vd 00 rm op Q M 0 Vm
13868 A1: 1111 00111 D 111011 Vd 00 rm op Q M 0 Vm
13870 ARM encoding is in NV space.
13871 In Thumb mode, we must not be in an IT block.
13873 if (INSN(31,23) == (isT ? BITS9(1,1,1,1,1,1,1,1,1)
13874 : BITS9(1,1,1,1,0,0,1,1,1))
13875 && INSN(21,16) == BITS6(1,1,1,0,1,1) && INSN(11,10) == BITS2(0,0)
13876 && INSN(4,4) == 0) {
13877 UInt bit_D = INSN(22,22);
13878 UInt fld_Vd = INSN(15,12);
13879 UInt fld_rm = INSN(9,8);
13880 Bool isU = INSN(7,7) == 1;
13881 Bool isQ = INSN(6,6) == 1;
13882 UInt bit_M = INSN(5,5);
13883 UInt fld_Vm = INSN(3,0);
13885 /* dd, nn, mm are D-register numbers. */
13886 UInt dd = (bit_D << 4) | fld_Vd;
13887 UInt mm = (bit_M << 4) | fld_Vm;
13889 if (! (isQ && ((dd & 1) == 1 || (mm & 1) == 1))) {
13890 /* Do this piecewise on f regs. */
13891 UInt ddF = dd << 1;
13892 UInt mmF = mm << 1;
13894 if (isT) {
13895 gen_SIGILL_T_if_in_ITBlock(old_itstate, new_itstate);
13897 /* In ARM mode, this is statically unconditional. In Thumb mode,
13898 this must be dynamically unconditional, and we've SIGILLd if not.
13899 In either case we can create unconditional IR. */
13901 UChar cvtc = '?';
13902 IRRoundingMode rm = Irrm_NEAREST;
13903 switch (fld_rm) {
13904 /* The use of NEAREST for both the 'a' and 'n' cases is a bit of a
13905 kludge since it doesn't take into account the nearest-even vs
13906 nearest-away semantics. */
13907 case BITS2(0,0): cvtc = 'a'; rm = Irrm_NEAREST; break;
13908 case BITS2(0,1): cvtc = 'n'; rm = Irrm_NEAREST; break;
13909 case BITS2(1,0): cvtc = 'p'; rm = Irrm_PosINF; break;
13910 case BITS2(1,1): cvtc = 'm'; rm = Irrm_NegINF; break;
13911 default: vassert(0);
13914 IROp cvt = isU ? Iop_F64toI32U : Iop_F64toI32S;
13916 IRTemp r0 = newTemp(Ity_F32);
13917 IRTemp r1 = newTemp(Ity_F32);
13918 IRTemp r2 = isQ ? newTemp(Ity_F32) : IRTemp_INVALID;
13919 IRTemp r3 = isQ ? newTemp(Ity_F32) : IRTemp_INVALID;
13921 IRExpr* rmE = mkU32((UInt)rm);
13923 assign(r0, unop(Iop_ReinterpI32asF32,
13924 binop(cvt, rmE, unop(Iop_F32toF64,
13925 llGetFReg_up_to_64(mmF+0)))));
13926 assign(r1, unop(Iop_ReinterpI32asF32,
13927 binop(cvt, rmE, unop(Iop_F32toF64,
13928 llGetFReg_up_to_64(mmF+1)))));
13929 if (isQ) {
13930 assign(r2, unop(Iop_ReinterpI32asF32,
13931 binop(cvt, rmE, unop(Iop_F32toF64,
13932 llGetFReg_up_to_64(mmF+2)))));
13933 assign(r3, unop(Iop_ReinterpI32asF32,
13934 binop(cvt, rmE, unop(Iop_F32toF64,
13935 llGetFReg_up_to_64(mmF+3)))));
13938 llPutFReg_up_to_64(ddF+0, mkexpr(r0));
13939 llPutFReg_up_to_64(ddF+1, mkexpr(r1));
13940 if (isQ) {
13941 llPutFReg_up_to_64(ddF+2, mkexpr(r2));
13942 llPutFReg_up_to_64(ddF+3, mkexpr(r3));
13945 HChar rch = isQ ? 'q' : 'd';
13946 UInt sh = isQ ? 1 : 0;
13947 DIP("vcvt%c.%c32.f32 %c%u, %c%u\n",
13948 cvtc, isU ? 'u' : 's', rch, dd >> sh, rch, mm >> sh);
13949 return True;
13951 /* else fall through */
13954 /* ----------- VRINT{A,N,P,M,X,Z}{.F32 d_d, .F32 q_q} ----------- */
13955 /* 31 27 22 21 15 11 9 6 5 4 3
13956 T1: 1111 11111 D 111010 Vd 01 op Q M 0 Vm
13957 A1: 1111 00111 D 111010 Vd 01 op Q M 0 Vm
13959 ARM encoding is in NV space.
13960 In Thumb mode, we must not be in an IT block.
13962 if (INSN(31,23) == (isT ? BITS9(1,1,1,1,1,1,1,1,1)
13963 : BITS9(1,1,1,1,0,0,1,1,1))
13964 && INSN(21,16) == BITS6(1,1,1,0,1,0) && INSN(11,10) == BITS2(0,1)
13965 && INSN(4,4) == 0) {
13966 UInt bit_D = INSN(22,22);
13967 UInt fld_Vd = INSN(15,12);
13968 UInt fld_op = INSN(9,7);
13969 Bool isQ = INSN(6,6) == 1;
13970 UInt bit_M = INSN(5,5);
13971 UInt fld_Vm = INSN(3,0);
13973 /* dd, nn, mm are D-register numbers. */
13974 UInt dd = (bit_D << 4) | fld_Vd;
13975 UInt mm = (bit_M << 4) | fld_Vm;
13977 if (! (fld_op == BITS3(1,0,0) || fld_op == BITS3(1,1,0))
13978 && ! (isQ && ((dd & 1) == 1 || (mm & 1) == 1))) {
13979 /* Do this piecewise on f regs. */
13980 UInt ddF = dd << 1;
13981 UInt mmF = mm << 1;
13983 if (isT) {
13984 gen_SIGILL_T_if_in_ITBlock(old_itstate, new_itstate);
13986 /* In ARM mode, this is statically unconditional. In Thumb mode,
13987 this must be dynamically unconditional, and we've SIGILLd if not.
13988 In either case we can create unconditional IR. */
13990 UChar cvtc = '?';
13991 IRRoundingMode rm = Irrm_NEAREST;
13992 switch (fld_op) {
13993 /* Various kludges:
13994 - The use of NEAREST for both the 'a' and 'n' cases,
13995 since it doesn't take into account the nearest-even vs
13996 nearest-away semantics.
13997 - For the 'x' case, we don't signal inexactness.
13999 case BITS3(0,1,0): cvtc = 'a'; rm = Irrm_NEAREST; break;
14000 case BITS3(0,0,0): cvtc = 'n'; rm = Irrm_NEAREST; break;
14001 case BITS3(1,1,1): cvtc = 'p'; rm = Irrm_PosINF; break;
14002 case BITS3(1,0,1): cvtc = 'm'; rm = Irrm_NegINF; break;
14003 case BITS3(0,1,1): cvtc = 'z'; rm = Irrm_ZERO; break;
14004 case BITS3(0,0,1): cvtc = 'x'; rm = Irrm_NEAREST; break;
14005 case BITS3(1,0,0):
14006 case BITS3(1,1,0):
14007 default: vassert(0);
14010 IRTemp r0 = newTemp(Ity_F32);
14011 IRTemp r1 = newTemp(Ity_F32);
14012 IRTemp r2 = isQ ? newTemp(Ity_F32) : IRTemp_INVALID;
14013 IRTemp r3 = isQ ? newTemp(Ity_F32) : IRTemp_INVALID;
14015 IRExpr* rmE = mkU32((UInt)rm);
14016 IROp rnd = Iop_RoundF32toInt;
14018 assign(r0, binop(rnd, rmE, llGetFReg_up_to_64(mmF+0)));
14019 assign(r1, binop(rnd, rmE, llGetFReg_up_to_64(mmF+1)));
14020 if (isQ) {
14021 assign(r2, binop(rnd, rmE, llGetFReg_up_to_64(mmF+2)));
14022 assign(r3, binop(rnd, rmE, llGetFReg_up_to_64(mmF+3)));
14025 llPutFReg_up_to_64(ddF+0, mkexpr(r0));
14026 llPutFReg_up_to_64(ddF+1, mkexpr(r1));
14027 if (isQ) {
14028 llPutFReg_up_to_64(ddF+2, mkexpr(r2));
14029 llPutFReg_up_to_64(ddF+3, mkexpr(r3));
14032 HChar rch = isQ ? 'q' : 'd';
14033 UInt sh = isQ ? 1 : 0;
14034 DIP("vrint%c.f32.f32 %c%u, %c%u\n",
14035 cvtc, rch, dd >> sh, rch, mm >> sh);
14036 return True;
14038 /* else fall through */
14041 /* ---------- Doesn't match anything. ---------- */
14042 return False;
14044 # undef INSN
14048 /*------------------------------------------------------------*/
14049 /*--- LDMxx/STMxx helper (both ARM and Thumb32) ---*/
14050 /*------------------------------------------------------------*/
14052 /* Generate IR for LDMxx and STMxx. This is complex. Assumes it's
14053 unconditional, so the caller must produce a jump-around before
14054 calling this, if the insn is to be conditional. Caller is
14055 responsible for all validation of parameters. For LDMxx, if PC is
14056 amongst the values loaded, caller is also responsible for
14057 generating the jump. */
14058 static void mk_ldm_stm ( Bool arm, /* True: ARM, False: Thumb */
14059 UInt rN, /* base reg */
14060 UInt bINC, /* 1: inc, 0: dec */
14061 UInt bBEFORE, /* 1: inc/dec before, 0: after */
14062 UInt bW, /* 1: writeback to Rn */
14063 UInt bL, /* 1: load, 0: store */
14064 UInt regList )
14066 Int i, r, m, nRegs;
14067 IRTemp jk = Ijk_Boring;
14069 /* Get hold of the old Rn value. We might need to write its value
14070 to memory during a store, and if it's also the writeback
14071 register then we need to get its value now. We can't treat it
14072 exactly like the other registers we're going to transfer,
14073 because for xxMDA and xxMDB writeback forms, the generated IR
14074 updates Rn in the guest state before any transfers take place.
14075 We have to do this as per comments below, in order that if Rn is
14076 the stack pointer then it always has a value is below or equal
14077 to any of the transfer addresses. Ick. */
14078 IRTemp oldRnT = newTemp(Ity_I32);
14079 assign(oldRnT, arm ? getIRegA(rN) : getIRegT(rN));
14081 IRTemp anchorT = newTemp(Ity_I32);
14082 /* The old (Addison-Wesley) ARM ARM seems to say that LDMxx/STMxx
14083 ignore the bottom two bits of the address. However, Cortex-A8
14084 doesn't seem to care. Hence: */
14085 /* No .. don't force alignment .. */
14086 /* assign(anchorT, binop(Iop_And32, mkexpr(oldRnT), mkU32(~3U))); */
14087 /* Instead, use the potentially misaligned address directly. */
14088 assign(anchorT, mkexpr(oldRnT));
14090 IROp opADDorSUB = bINC ? Iop_Add32 : Iop_Sub32;
14091 // bINC == 1: xxMIA, xxMIB
14092 // bINC == 0: xxMDA, xxMDB
14094 // For xxMDA and xxMDB, update Rn first if necessary. We have
14095 // to do this first so that, for the common idiom of the transfers
14096 // faulting because we're pushing stuff onto a stack and the stack
14097 // is growing down onto allocate-on-fault pages (as Valgrind simulates),
14098 // we need to have the SP up-to-date "covering" (pointing below) the
14099 // transfer area. For the same reason, if we are doing xxMIA or xxMIB,
14100 // do the transfer first, and then update rN afterwards.
14101 nRegs = 0;
14102 for (i = 0; i < 16; i++) {
14103 if ((regList & (1 << i)) != 0)
14104 nRegs++;
14106 if (bW == 1 && !bINC) {
14107 IRExpr* e = binop(opADDorSUB, mkexpr(oldRnT), mkU32(4*nRegs));
14108 if (arm)
14109 putIRegA( rN, e, IRTemp_INVALID, Ijk_Boring );
14110 else
14111 putIRegT( rN, e, IRTemp_INVALID );
14114 // Make up a list of the registers to transfer, and their offsets
14115 // in memory relative to the anchor. If the base reg (Rn) is part
14116 // of the transfer, then do it last for a load and first for a store.
14117 UInt xReg[16], xOff[16];
14118 Int nX = 0;
14119 m = 0;
14120 for (i = 0; i < 16; i++) {
14121 r = bINC ? i : (15-i);
14122 if (0 == (regList & (1<<r)))
14123 continue;
14124 if (bBEFORE)
14125 m++;
14126 /* paranoia: check we aren't transferring the writeback
14127 register during a load. Should be assured by decode-point
14128 check above. */
14129 if (bW == 1 && bL == 1)
14130 vassert(r != rN);
14132 xOff[nX] = 4 * m;
14133 xReg[nX] = r;
14134 nX++;
14136 if (!bBEFORE)
14137 m++;
14139 vassert(m == nRegs);
14140 vassert(nX == nRegs);
14141 vassert(nX <= 16);
14143 if (bW == 0 && (regList & (1<<rN)) != 0) {
14144 /* Non-writeback, and basereg is to be transferred. Do its
14145 transfer last for a load and first for a store. Requires
14146 reordering xOff/xReg. */
14147 if (0) {
14148 vex_printf("\nREG_LIST_PRE: (rN=%u)\n", rN);
14149 for (i = 0; i < nX; i++)
14150 vex_printf("reg %u off %u\n", xReg[i], xOff[i]);
14151 vex_printf("\n");
14154 vassert(nX > 0);
14155 for (i = 0; i < nX; i++) {
14156 if (xReg[i] == rN)
14157 break;
14159 vassert(i < nX); /* else we didn't find it! */
14160 UInt tReg = xReg[i];
14161 UInt tOff = xOff[i];
14162 if (bL == 1) {
14163 /* load; make this transfer happen last */
14164 if (i < nX-1) {
14165 for (m = i+1; m < nX; m++) {
14166 xReg[m-1] = xReg[m];
14167 xOff[m-1] = xOff[m];
14169 vassert(m == nX);
14170 xReg[m-1] = tReg;
14171 xOff[m-1] = tOff;
14173 } else {
14174 /* store; make this transfer happen first */
14175 if (i > 0) {
14176 for (m = i-1; m >= 0; m--) {
14177 xReg[m+1] = xReg[m];
14178 xOff[m+1] = xOff[m];
14180 vassert(m == -1);
14181 xReg[0] = tReg;
14182 xOff[0] = tOff;
14186 if (0) {
14187 vex_printf("REG_LIST_POST:\n");
14188 for (i = 0; i < nX; i++)
14189 vex_printf("reg %u off %u\n", xReg[i], xOff[i]);
14190 vex_printf("\n");
14194 /* According to the Cortex A8 TRM Sec. 5.2.1, LDM(1) with r13 as the base
14195 register and PC in the register list is a return for purposes of branch
14196 prediction.
14197 The ARM ARM Sec. C9.10.1 further specifies that writeback must be enabled
14198 to be counted in event 0x0E (Procedure return).*/
14199 if (rN == 13 && bL == 1 && bINC && !bBEFORE && bW == 1) {
14200 jk = Ijk_Ret;
14203 /* Actually generate the transfers */
14204 for (i = 0; i < nX; i++) {
14205 r = xReg[i];
14206 if (bL == 1) {
14207 IRExpr* e = loadLE(Ity_I32,
14208 binop(opADDorSUB, mkexpr(anchorT),
14209 mkU32(xOff[i])));
14210 if (arm) {
14211 putIRegA( r, e, IRTemp_INVALID, jk );
14212 } else {
14213 // no: putIRegT( r, e, IRTemp_INVALID );
14214 // putIRegT refuses to write to R15. But that might happen.
14215 // Since this is uncond, and we need to be able to
14216 // write the PC, just use the low level put:
14217 llPutIReg( r, e );
14219 } else {
14220 /* if we're storing Rn, make sure we use the correct
14221 value, as per extensive comments above */
14222 storeLE( binop(opADDorSUB, mkexpr(anchorT), mkU32(xOff[i])),
14223 r == rN ? mkexpr(oldRnT)
14224 : (arm ? getIRegA(r) : getIRegT(r) ) );
14228 // If we are doing xxMIA or xxMIB,
14229 // do the transfer first, and then update rN afterwards.
14230 if (bW == 1 && bINC) {
14231 IRExpr* e = binop(opADDorSUB, mkexpr(oldRnT), mkU32(4*nRegs));
14232 if (arm)
14233 putIRegA( rN, e, IRTemp_INVALID, Ijk_Boring );
14234 else
14235 putIRegT( rN, e, IRTemp_INVALID );
14240 /*------------------------------------------------------------*/
14241 /*--- VFP (CP 10 and 11) instructions ---*/
14242 /*------------------------------------------------------------*/
14244 /* Both ARM and Thumb */
14246 /* Translate a CP10 or CP11 instruction. If successful, returns
14247 True and *dres may or may not be updated. If failure, returns
14248 False and doesn't change *dres nor create any IR.
14250 The ARM and Thumb encodings are identical for the low 28 bits of
14251 the insn (yay!) and that's what the caller must supply, iow, imm28
14252 has the top 4 bits masked out. Caller is responsible for
14253 determining whether the masked-out bits are valid for a CP10/11
14254 insn. The rules for the top 4 bits are:
14256 ARM: 0000 to 1110 allowed, and this is the gating condition.
14257 1111 (NV) is not allowed.
14259 Thumb: must be 1110. The gating condition is taken from
14260 ITSTATE in the normal way.
14262 Conditionalisation:
14264 Caller must supply an IRTemp 'condT' holding the gating condition,
14265 or IRTemp_INVALID indicating the insn is always executed.
14267 Caller must also supply an ARMCondcode 'cond'. This is only used
14268 for debug printing, no other purpose. For ARM, this is simply the
14269 top 4 bits of the original instruction. For Thumb, the condition
14270 is not (really) known until run time, and so ARMCondAL should be
14271 passed, only so that printing of these instructions does not show
14272 any condition.
14274 Finally, the caller must indicate whether this occurs in ARM or
14275 Thumb code.
14277 static Bool decode_CP10_CP11_instruction (
14278 /*MOD*/DisResult* dres,
14279 UInt insn28,
14280 IRTemp condT,
14281 ARMCondcode conq,
14282 Bool isT
14285 # define INSN(_bMax,_bMin) SLICE_UInt(insn28, (_bMax), (_bMin))
14287 vassert(INSN(31,28) == BITS4(0,0,0,0)); // caller's obligation
14289 if (isT) {
14290 vassert(conq == ARMCondAL);
14291 } else {
14292 vassert(conq >= ARMCondEQ && conq <= ARMCondAL);
14295 /* ----------------------------------------------------------- */
14296 /* -- VFP instructions -- double precision (mostly) -- */
14297 /* ----------------------------------------------------------- */
14299 /* --------------------- fldmx, fstmx --------------------- */
14301 31 27 23 19 15 11 7 0
14302 P U WL
14303 C4-100, C5-26 1 FSTMX cond 1100 1000 Rn Dd 1011 offset
14304 C4-100, C5-28 2 FSTMIAX cond 1100 1010 Rn Dd 1011 offset
14305 C4-100, C5-30 3 FSTMDBX cond 1101 0010 Rn Dd 1011 offset
14307 C4-42, C5-26 1 FLDMX cond 1100 1001 Rn Dd 1011 offset
14308 C4-42, C5-28 2 FLDMIAX cond 1100 1011 Rn Dd 1011 offset
14309 C4-42, C5-30 3 FLDMDBX cond 1101 0011 Rn Dd 1011 offset
14311 Regs transferred: Dd .. D(d + (offset-3)/2)
14312 offset must be odd, must not imply a reg > 15
14313 IA/DB: Rn is changed by (4 + 8 x # regs transferred)
14315 case coding:
14316 1 at-Rn (access at Rn)
14317 2 ia-Rn (access at Rn, then Rn += 4+8n)
14318 3 db-Rn (Rn -= 4+8n, then access at Rn)
14320 if (BITS8(1,1,0,0,0,0,0,0) == (INSN(27,20) & BITS8(1,1,1,0,0,0,0,0))
14321 && INSN(11,8) == BITS4(1,0,1,1)) {
14322 UInt bP = (insn28 >> 24) & 1;
14323 UInt bU = (insn28 >> 23) & 1;
14324 UInt bW = (insn28 >> 21) & 1;
14325 UInt bL = (insn28 >> 20) & 1;
14326 UInt offset = (insn28 >> 0) & 0xFF;
14327 UInt rN = INSN(19,16);
14328 UInt dD = (INSN(22,22) << 4) | INSN(15,12);
14329 UInt nRegs = (offset - 1) / 2;
14330 UInt summary = 0;
14331 Int i;
14333 /**/ if (bP == 0 && bU == 1 && bW == 0) {
14334 summary = 1;
14336 else if (bP == 0 && bU == 1 && bW == 1) {
14337 summary = 2;
14339 else if (bP == 1 && bU == 0 && bW == 1) {
14340 summary = 3;
14342 else goto after_vfp_fldmx_fstmx;
14344 /* no writebacks to r15 allowed. No use of r15 in thumb mode. */
14345 if (rN == 15 && (summary == 2 || summary == 3 || isT))
14346 goto after_vfp_fldmx_fstmx;
14348 /* offset must be odd, and specify at least one register */
14349 if (0 == (offset & 1) || offset < 3)
14350 goto after_vfp_fldmx_fstmx;
14352 /* can't transfer regs after D15 */
14353 if (dD + nRegs - 1 >= 32)
14354 goto after_vfp_fldmx_fstmx;
14356 /* Now, we can't do a conditional load or store, since that very
14357 likely will generate an exception. So we have to take a side
14358 exit at this point if the condition is false. */
14359 if (condT != IRTemp_INVALID) {
14360 if (isT)
14361 mk_skip_over_T32_if_cond_is_false( condT );
14362 else
14363 mk_skip_over_A32_if_cond_is_false( condT );
14364 condT = IRTemp_INVALID;
14366 /* Ok, now we're unconditional. Do the load or store. */
14368 /* get the old Rn value */
14369 IRTemp rnT = newTemp(Ity_I32);
14370 assign(rnT, align4if(isT ? getIRegT(rN) : getIRegA(rN),
14371 rN == 15));
14373 /* make a new value for Rn, post-insn */
14374 IRTemp rnTnew = IRTemp_INVALID;
14375 if (summary == 2 || summary == 3) {
14376 rnTnew = newTemp(Ity_I32);
14377 assign(rnTnew, binop(summary == 2 ? Iop_Add32 : Iop_Sub32,
14378 mkexpr(rnT),
14379 mkU32(4 + 8 * nRegs)));
14382 /* decide on the base transfer address */
14383 IRTemp taT = newTemp(Ity_I32);
14384 assign(taT, summary == 3 ? mkexpr(rnTnew) : mkexpr(rnT));
14386 /* update Rn if necessary -- in case 3, we're moving it down, so
14387 update before any memory reference, in order to keep Memcheck
14388 and V's stack-extending logic (on linux) happy */
14389 if (summary == 3) {
14390 if (isT)
14391 putIRegT(rN, mkexpr(rnTnew), IRTemp_INVALID);
14392 else
14393 putIRegA(rN, mkexpr(rnTnew), IRTemp_INVALID, Ijk_Boring);
14396 /* generate the transfers */
14397 for (i = 0; i < nRegs; i++) {
14398 IRExpr* addr = binop(Iop_Add32, mkexpr(taT), mkU32(8*i));
14399 if (bL) {
14400 putDReg(dD + i, loadLE(Ity_F64, addr), IRTemp_INVALID);
14401 } else {
14402 storeLE(addr, getDReg(dD + i));
14406 /* update Rn if necessary -- in case 2, we're moving it up, so
14407 update after any memory reference, in order to keep Memcheck
14408 and V's stack-extending logic (on linux) happy */
14409 if (summary == 2) {
14410 if (isT)
14411 putIRegT(rN, mkexpr(rnTnew), IRTemp_INVALID);
14412 else
14413 putIRegA(rN, mkexpr(rnTnew), IRTemp_INVALID, Ijk_Boring);
14416 const HChar* nm = bL==1 ? "ld" : "st";
14417 switch (summary) {
14418 case 1: DIP("f%smx%s r%u, {d%u-d%u}\n",
14419 nm, nCC(conq), rN, dD, dD + nRegs - 1);
14420 break;
14421 case 2: DIP("f%smiax%s r%u!, {d%u-d%u}\n",
14422 nm, nCC(conq), rN, dD, dD + nRegs - 1);
14423 break;
14424 case 3: DIP("f%smdbx%s r%u!, {d%u-d%u}\n",
14425 nm, nCC(conq), rN, dD, dD + nRegs - 1);
14426 break;
14427 default: vassert(0);
14430 goto decode_success_vfp;
14431 /* FIXME alignment constraints? */
14434 after_vfp_fldmx_fstmx:
14436 /* --------------------- fldmd, fstmd --------------------- */
14438 31 27 23 19 15 11 7 0
14439 P U WL
14440 C4-96, C5-26 1 FSTMD cond 1100 1000 Rn Dd 1011 offset
14441 C4-96, C5-28 2 FSTMDIA cond 1100 1010 Rn Dd 1011 offset
14442 C4-96, C5-30 3 FSTMDDB cond 1101 0010 Rn Dd 1011 offset
14444 C4-38, C5-26 1 FLDMD cond 1100 1001 Rn Dd 1011 offset
14445 C4-38, C5-28 2 FLDMIAD cond 1100 1011 Rn Dd 1011 offset
14446 C4-38, C5-30 3 FLDMDBD cond 1101 0011 Rn Dd 1011 offset
14448 Regs transferred: Dd .. D(d + (offset-2)/2)
14449 offset must be even, must not imply a reg > 15
14450 IA/DB: Rn is changed by (8 x # regs transferred)
14452 case coding:
14453 1 at-Rn (access at Rn)
14454 2 ia-Rn (access at Rn, then Rn += 8n)
14455 3 db-Rn (Rn -= 8n, then access at Rn)
14457 if (BITS8(1,1,0,0,0,0,0,0) == (INSN(27,20) & BITS8(1,1,1,0,0,0,0,0))
14458 && INSN(11,8) == BITS4(1,0,1,1)) {
14459 UInt bP = (insn28 >> 24) & 1;
14460 UInt bU = (insn28 >> 23) & 1;
14461 UInt bW = (insn28 >> 21) & 1;
14462 UInt bL = (insn28 >> 20) & 1;
14463 UInt offset = (insn28 >> 0) & 0xFF;
14464 UInt rN = INSN(19,16);
14465 UInt dD = (INSN(22,22) << 4) | INSN(15,12);
14466 UInt nRegs = offset / 2;
14467 UInt summary = 0;
14468 Int i;
14470 /**/ if (bP == 0 && bU == 1 && bW == 0) {
14471 summary = 1;
14473 else if (bP == 0 && bU == 1 && bW == 1) {
14474 summary = 2;
14476 else if (bP == 1 && bU == 0 && bW == 1) {
14477 summary = 3;
14479 else goto after_vfp_fldmd_fstmd;
14481 /* no writebacks to r15 allowed. No use of r15 in thumb mode. */
14482 if (rN == 15 && (summary == 2 || summary == 3 || isT))
14483 goto after_vfp_fldmd_fstmd;
14485 /* offset must be even, and specify at least one register */
14486 if (1 == (offset & 1) || offset < 2)
14487 goto after_vfp_fldmd_fstmd;
14489 /* can't transfer regs after D15 */
14490 if (dD + nRegs - 1 >= 32)
14491 goto after_vfp_fldmd_fstmd;
14493 /* Now, we can't do a conditional load or store, since that very
14494 likely will generate an exception. So we have to take a side
14495 exit at this point if the condition is false. */
14496 if (condT != IRTemp_INVALID) {
14497 if (isT)
14498 mk_skip_over_T32_if_cond_is_false( condT );
14499 else
14500 mk_skip_over_A32_if_cond_is_false( condT );
14501 condT = IRTemp_INVALID;
14503 /* Ok, now we're unconditional. Do the load or store. */
14505 /* get the old Rn value */
14506 IRTemp rnT = newTemp(Ity_I32);
14507 assign(rnT, align4if(isT ? getIRegT(rN) : getIRegA(rN),
14508 rN == 15));
14510 /* make a new value for Rn, post-insn */
14511 IRTemp rnTnew = IRTemp_INVALID;
14512 if (summary == 2 || summary == 3) {
14513 rnTnew = newTemp(Ity_I32);
14514 assign(rnTnew, binop(summary == 2 ? Iop_Add32 : Iop_Sub32,
14515 mkexpr(rnT),
14516 mkU32(8 * nRegs)));
14519 /* decide on the base transfer address */
14520 IRTemp taT = newTemp(Ity_I32);
14521 assign(taT, summary == 3 ? mkexpr(rnTnew) : mkexpr(rnT));
14523 /* update Rn if necessary -- in case 3, we're moving it down, so
14524 update before any memory reference, in order to keep Memcheck
14525 and V's stack-extending logic (on linux) happy */
14526 if (summary == 3) {
14527 if (isT)
14528 putIRegT(rN, mkexpr(rnTnew), IRTemp_INVALID);
14529 else
14530 putIRegA(rN, mkexpr(rnTnew), IRTemp_INVALID, Ijk_Boring);
14533 /* generate the transfers */
14534 for (i = 0; i < nRegs; i++) {
14535 IRExpr* addr = binop(Iop_Add32, mkexpr(taT), mkU32(8*i));
14536 if (bL) {
14537 putDReg(dD + i, loadLE(Ity_F64, addr), IRTemp_INVALID);
14538 } else {
14539 storeLE(addr, getDReg(dD + i));
14543 /* update Rn if necessary -- in case 2, we're moving it up, so
14544 update after any memory reference, in order to keep Memcheck
14545 and V's stack-extending logic (on linux) happy */
14546 if (summary == 2) {
14547 if (isT)
14548 putIRegT(rN, mkexpr(rnTnew), IRTemp_INVALID);
14549 else
14550 putIRegA(rN, mkexpr(rnTnew), IRTemp_INVALID, Ijk_Boring);
14553 const HChar* nm = bL==1 ? "ld" : "st";
14554 switch (summary) {
14555 case 1: DIP("f%smd%s r%u, {d%u-d%u}\n",
14556 nm, nCC(conq), rN, dD, dD + nRegs - 1);
14557 break;
14558 case 2: DIP("f%smiad%s r%u!, {d%u-d%u}\n",
14559 nm, nCC(conq), rN, dD, dD + nRegs - 1);
14560 break;
14561 case 3: DIP("f%smdbd%s r%u!, {d%u-d%u}\n",
14562 nm, nCC(conq), rN, dD, dD + nRegs - 1);
14563 break;
14564 default: vassert(0);
14567 goto decode_success_vfp;
14568 /* FIXME alignment constraints? */
14571 after_vfp_fldmd_fstmd:
14573 /* ------------------- fmrx, fmxr ------------------- */
14574 if (BITS8(1,1,1,0,1,1,1,1) == INSN(27,20)
14575 && BITS4(1,0,1,0) == INSN(11,8)
14576 && BITS8(0,0,0,1,0,0,0,0) == (insn28 & 0xFF)) {
14577 UInt rD = INSN(15,12);
14578 UInt reg = INSN(19,16);
14579 if (reg == BITS4(0,0,0,1)) {
14580 if (rD == 15) {
14581 IRTemp nzcvT = newTemp(Ity_I32);
14582 /* When rD is 15, we are copying the top 4 bits of FPSCR
14583 into CPSR. That is, set the flags thunk to COPY and
14584 install FPSCR[31:28] as the value to copy. */
14585 assign(nzcvT, binop(Iop_And32,
14586 IRExpr_Get(OFFB_FPSCR, Ity_I32),
14587 mkU32(0xF0000000)));
14588 setFlags_D1(ARMG_CC_OP_COPY, nzcvT, condT);
14589 DIP("fmstat%s\n", nCC(conq));
14590 } else {
14591 /* Otherwise, merely transfer FPSCR to r0 .. r14. */
14592 IRExpr* e = IRExpr_Get(OFFB_FPSCR, Ity_I32);
14593 if (isT)
14594 putIRegT(rD, e, condT);
14595 else
14596 putIRegA(rD, e, condT, Ijk_Boring);
14597 DIP("fmrx%s r%u, fpscr\n", nCC(conq), rD);
14599 goto decode_success_vfp;
14601 /* fall through */
14604 if (BITS8(1,1,1,0,1,1,1,0) == INSN(27,20)
14605 && BITS4(1,0,1,0) == INSN(11,8)
14606 && BITS8(0,0,0,1,0,0,0,0) == (insn28 & 0xFF)) {
14607 UInt rD = INSN(15,12);
14608 UInt reg = INSN(19,16);
14609 if (reg == BITS4(0,0,0,1)) {
14610 putMiscReg32(OFFB_FPSCR,
14611 isT ? getIRegT(rD) : getIRegA(rD), condT);
14612 DIP("fmxr%s fpscr, r%u\n", nCC(conq), rD);
14613 goto decode_success_vfp;
14615 /* fall through */
14618 /* --------------------- vmov --------------------- */
14619 // VMOV dM, rD, rN
14620 if (0x0C400B10 == (insn28 & 0x0FF00FD0)) {
14621 UInt dM = INSN(3,0) | (INSN(5,5) << 4);
14622 UInt rD = INSN(15,12); /* lo32 */
14623 UInt rN = INSN(19,16); /* hi32 */
14624 if (rD == 15 || rN == 15 || (isT && (rD == 13 || rN == 13))) {
14625 /* fall through */
14626 } else {
14627 putDReg(dM,
14628 unop(Iop_ReinterpI64asF64,
14629 binop(Iop_32HLto64,
14630 isT ? getIRegT(rN) : getIRegA(rN),
14631 isT ? getIRegT(rD) : getIRegA(rD))),
14632 condT);
14633 DIP("vmov%s d%u, r%u, r%u\n", nCC(conq), dM, rD, rN);
14634 goto decode_success_vfp;
14636 /* fall through */
14639 // VMOV rD, rN, dM
14640 if (0x0C500B10 == (insn28 & 0x0FF00FD0)) {
14641 UInt dM = INSN(3,0) | (INSN(5,5) << 4);
14642 UInt rD = INSN(15,12); /* lo32 */
14643 UInt rN = INSN(19,16); /* hi32 */
14644 if (rD == 15 || rN == 15 || (isT && (rD == 13 || rN == 13))
14645 || rD == rN) {
14646 /* fall through */
14647 } else {
14648 IRTemp i64 = newTemp(Ity_I64);
14649 assign(i64, unop(Iop_ReinterpF64asI64, getDReg(dM)));
14650 IRExpr* hi32 = unop(Iop_64HIto32, mkexpr(i64));
14651 IRExpr* lo32 = unop(Iop_64to32, mkexpr(i64));
14652 if (isT) {
14653 putIRegT(rN, hi32, condT);
14654 putIRegT(rD, lo32, condT);
14655 } else {
14656 putIRegA(rN, hi32, condT, Ijk_Boring);
14657 putIRegA(rD, lo32, condT, Ijk_Boring);
14659 DIP("vmov%s r%u, r%u, d%u\n", nCC(conq), rD, rN, dM);
14660 goto decode_success_vfp;
14662 /* fall through */
14665 // VMOV sD, sD+1, rN, rM
14666 if (0x0C400A10 == (insn28 & 0x0FF00FD0)) {
14667 UInt sD = (INSN(3,0) << 1) | INSN(5,5);
14668 UInt rN = INSN(15,12);
14669 UInt rM = INSN(19,16);
14670 if (rM == 15 || rN == 15 || (isT && (rM == 13 || rN == 13))
14671 || sD == 31) {
14672 /* fall through */
14673 } else {
14674 putFReg(sD,
14675 unop(Iop_ReinterpI32asF32, isT ? getIRegT(rN) : getIRegA(rN)),
14676 condT);
14677 putFReg(sD+1,
14678 unop(Iop_ReinterpI32asF32, isT ? getIRegT(rM) : getIRegA(rM)),
14679 condT);
14680 DIP("vmov%s, s%u, s%u, r%u, r%u\n",
14681 nCC(conq), sD, sD + 1, rN, rM);
14682 goto decode_success_vfp;
14686 // VMOV rN, rM, sD, sD+1
14687 if (0x0C500A10 == (insn28 & 0x0FF00FD0)) {
14688 UInt sD = (INSN(3,0) << 1) | INSN(5,5);
14689 UInt rN = INSN(15,12);
14690 UInt rM = INSN(19,16);
14691 if (rM == 15 || rN == 15 || (isT && (rM == 13 || rN == 13))
14692 || sD == 31 || rN == rM) {
14693 /* fall through */
14694 } else {
14695 IRExpr* res0 = unop(Iop_ReinterpF32asI32, getFReg(sD));
14696 IRExpr* res1 = unop(Iop_ReinterpF32asI32, getFReg(sD+1));
14697 if (isT) {
14698 putIRegT(rN, res0, condT);
14699 putIRegT(rM, res1, condT);
14700 } else {
14701 putIRegA(rN, res0, condT, Ijk_Boring);
14702 putIRegA(rM, res1, condT, Ijk_Boring);
14704 DIP("vmov%s, r%u, r%u, s%u, s%u\n",
14705 nCC(conq), rN, rM, sD, sD + 1);
14706 goto decode_success_vfp;
14710 // VMOV rD[x], rT (ARM core register to scalar)
14711 if (0x0E000B10 == (insn28 & 0x0F900F1F)) {
14712 UInt rD = (INSN(7,7) << 4) | INSN(19,16);
14713 UInt rT = INSN(15,12);
14714 UInt opc = (INSN(22,21) << 2) | INSN(6,5);
14715 UInt index;
14716 if (rT == 15 || (isT && rT == 13)) {
14717 /* fall through */
14718 } else {
14719 if ((opc & BITS4(1,0,0,0)) == BITS4(1,0,0,0)) {
14720 index = opc & 7;
14721 putDRegI64(rD, triop(Iop_SetElem8x8,
14722 getDRegI64(rD),
14723 mkU8(index),
14724 unop(Iop_32to8,
14725 isT ? getIRegT(rT) : getIRegA(rT))),
14726 condT);
14727 DIP("vmov%s.8 d%u[%u], r%u\n", nCC(conq), rD, index, rT);
14728 goto decode_success_vfp;
14730 else if ((opc & BITS4(1,0,0,1)) == BITS4(0,0,0,1)) {
14731 index = (opc >> 1) & 3;
14732 putDRegI64(rD, triop(Iop_SetElem16x4,
14733 getDRegI64(rD),
14734 mkU8(index),
14735 unop(Iop_32to16,
14736 isT ? getIRegT(rT) : getIRegA(rT))),
14737 condT);
14738 DIP("vmov%s.16 d%u[%u], r%u\n", nCC(conq), rD, index, rT);
14739 goto decode_success_vfp;
14741 else if ((opc & BITS4(1,0,1,1)) == BITS4(0,0,0,0)) {
14742 index = (opc >> 2) & 1;
14743 putDRegI64(rD, triop(Iop_SetElem32x2,
14744 getDRegI64(rD),
14745 mkU8(index),
14746 isT ? getIRegT(rT) : getIRegA(rT)),
14747 condT);
14748 DIP("vmov%s.32 d%u[%u], r%u\n", nCC(conq), rD, index, rT);
14749 goto decode_success_vfp;
14750 } else {
14751 /* fall through */
14756 // VMOV (scalar to ARM core register)
14757 // VMOV rT, rD[x]
14758 if (0x0E100B10 == (insn28 & 0x0F100F1F)) {
14759 UInt rN = (INSN(7,7) << 4) | INSN(19,16);
14760 UInt rT = INSN(15,12);
14761 UInt U = INSN(23,23);
14762 UInt opc = (INSN(22,21) << 2) | INSN(6,5);
14763 UInt index;
14764 if (rT == 15 || (isT && rT == 13)) {
14765 /* fall through */
14766 } else {
14767 if ((opc & BITS4(1,0,0,0)) == BITS4(1,0,0,0)) {
14768 index = opc & 7;
14769 IRExpr* e = unop(U ? Iop_8Uto32 : Iop_8Sto32,
14770 binop(Iop_GetElem8x8,
14771 getDRegI64(rN),
14772 mkU8(index)));
14773 if (isT)
14774 putIRegT(rT, e, condT);
14775 else
14776 putIRegA(rT, e, condT, Ijk_Boring);
14777 DIP("vmov%s.%c8 r%u, d%u[%u]\n", nCC(conq), U ? 'u' : 's',
14778 rT, rN, index);
14779 goto decode_success_vfp;
14781 else if ((opc & BITS4(1,0,0,1)) == BITS4(0,0,0,1)) {
14782 index = (opc >> 1) & 3;
14783 IRExpr* e = unop(U ? Iop_16Uto32 : Iop_16Sto32,
14784 binop(Iop_GetElem16x4,
14785 getDRegI64(rN),
14786 mkU8(index)));
14787 if (isT)
14788 putIRegT(rT, e, condT);
14789 else
14790 putIRegA(rT, e, condT, Ijk_Boring);
14791 DIP("vmov%s.%c16 r%u, d%u[%u]\n", nCC(conq), U ? 'u' : 's',
14792 rT, rN, index);
14793 goto decode_success_vfp;
14795 else if ((opc & BITS4(1,0,1,1)) == BITS4(0,0,0,0) && U == 0) {
14796 index = (opc >> 2) & 1;
14797 IRExpr* e = binop(Iop_GetElem32x2, getDRegI64(rN), mkU8(index));
14798 if (isT)
14799 putIRegT(rT, e, condT);
14800 else
14801 putIRegA(rT, e, condT, Ijk_Boring);
14802 DIP("vmov%s.32 r%u, d%u[%u]\n", nCC(conq), rT, rN, index);
14803 goto decode_success_vfp;
14804 } else {
14805 /* fall through */
14810 // VMOV.F32 sD, #imm
14811 // FCONSTS sD, #imm
14812 if (BITS8(1,1,1,0,1,0,1,1) == (INSN(27,20) & BITS8(1,1,1,1,1,0,1,1))
14813 && BITS4(0,0,0,0) == INSN(7,4) && INSN(11,8) == BITS4(1,0,1,0)) {
14814 UInt rD = (INSN(15,12) << 1) | INSN(22,22);
14815 UInt imm8 = (INSN(19,16) << 4) | INSN(3,0);
14816 UInt b = (imm8 >> 6) & 1;
14817 UInt imm;
14818 imm = (BITS8((imm8 >> 7) & 1,(~b) & 1,b,b,b,b,b,(imm8 >> 5) & 1) << 8)
14819 | ((imm8 & 0x1f) << 3);
14820 imm <<= 16;
14821 putFReg(rD, unop(Iop_ReinterpI32asF32, mkU32(imm)), condT);
14822 DIP("fconsts%s s%u #%u", nCC(conq), rD, imm8);
14823 goto decode_success_vfp;
14826 // VMOV.F64 dD, #imm
14827 // FCONSTD dD, #imm
14828 if (BITS8(1,1,1,0,1,0,1,1) == (INSN(27,20) & BITS8(1,1,1,1,1,0,1,1))
14829 && BITS4(0,0,0,0) == INSN(7,4) && INSN(11,8) == BITS4(1,0,1,1)) {
14830 UInt rD = INSN(15,12) | (INSN(22,22) << 4);
14831 UInt imm8 = (INSN(19,16) << 4) | INSN(3,0);
14832 UInt b = (imm8 >> 6) & 1;
14833 ULong imm;
14834 imm = (BITS8((imm8 >> 7) & 1,(~b) & 1,b,b,b,b,b,b) << 8)
14835 | BITS8(b,b,0,0,0,0,0,0) | (imm8 & 0x3f);
14836 imm <<= 48;
14837 putDReg(rD, unop(Iop_ReinterpI64asF64, mkU64(imm)), condT);
14838 DIP("fconstd%s d%u #%u", nCC(conq), rD, imm8);
14839 goto decode_success_vfp;
14842 /* ---------------------- vdup ------------------------- */
14843 // VDUP dD, rT
14844 // VDUP qD, rT
14845 if (BITS8(1,1,1,0,1,0,0,0) == (INSN(27,20) & BITS8(1,1,1,1,1,0,0,1))
14846 && BITS4(1,0,1,1) == INSN(11,8) && INSN(6,6) == 0 && INSN(4,4) == 1) {
14847 UInt rD = (INSN(7,7) << 4) | INSN(19,16);
14848 UInt rT = INSN(15,12);
14849 UInt Q = INSN(21,21);
14850 UInt size = (INSN(22,22) << 1) | INSN(5,5);
14851 if (rT == 15 || (isT && rT == 13) || size == 3 || (Q && (rD & 1))) {
14852 /* fall through */
14853 } else {
14854 IRExpr* e = isT ? getIRegT(rT) : getIRegA(rT);
14855 if (Q) {
14856 rD >>= 1;
14857 switch (size) {
14858 case 0:
14859 putQReg(rD, unop(Iop_Dup32x4, e), condT);
14860 break;
14861 case 1:
14862 putQReg(rD, unop(Iop_Dup16x8, unop(Iop_32to16, e)),
14863 condT);
14864 break;
14865 case 2:
14866 putQReg(rD, unop(Iop_Dup8x16, unop(Iop_32to8, e)),
14867 condT);
14868 break;
14869 default:
14870 vassert(0);
14872 DIP("vdup.%d q%u, r%u\n", 32 / (1<<size), rD, rT);
14873 } else {
14874 switch (size) {
14875 case 0:
14876 putDRegI64(rD, unop(Iop_Dup32x2, e), condT);
14877 break;
14878 case 1:
14879 putDRegI64(rD, unop(Iop_Dup16x4, unop(Iop_32to16, e)),
14880 condT);
14881 break;
14882 case 2:
14883 putDRegI64(rD, unop(Iop_Dup8x8, unop(Iop_32to8, e)),
14884 condT);
14885 break;
14886 default:
14887 vassert(0);
14889 DIP("vdup.%d d%u, r%u\n", 32 / (1<<size), rD, rT);
14891 goto decode_success_vfp;
14895 /* --------------------- f{ld,st}d --------------------- */
14896 // FLDD, FSTD
14897 if (BITS8(1,1,0,1,0,0,0,0) == (INSN(27,20) & BITS8(1,1,1,1,0,0,1,0))
14898 && BITS4(1,0,1,1) == INSN(11,8)) {
14899 UInt dD = INSN(15,12) | (INSN(22,22) << 4);
14900 UInt rN = INSN(19,16);
14901 UInt offset = (insn28 & 0xFF) << 2;
14902 UInt bU = (insn28 >> 23) & 1; /* 1: +offset 0: -offset */
14903 UInt bL = (insn28 >> 20) & 1; /* 1: load 0: store */
14904 /* make unconditional */
14905 if (condT != IRTemp_INVALID) {
14906 if (isT)
14907 mk_skip_over_T32_if_cond_is_false( condT );
14908 else
14909 mk_skip_over_A32_if_cond_is_false( condT );
14910 condT = IRTemp_INVALID;
14912 IRTemp ea = newTemp(Ity_I32);
14913 assign(ea, binop(bU ? Iop_Add32 : Iop_Sub32,
14914 align4if(isT ? getIRegT(rN) : getIRegA(rN),
14915 rN == 15),
14916 mkU32(offset)));
14917 if (bL) {
14918 putDReg(dD, loadLE(Ity_F64,mkexpr(ea)), IRTemp_INVALID);
14919 } else {
14920 storeLE(mkexpr(ea), getDReg(dD));
14922 DIP("f%sd%s d%u, [r%u, %c#%u]\n",
14923 bL ? "ld" : "st", nCC(conq), dD, rN,
14924 bU ? '+' : '-', offset);
14925 goto decode_success_vfp;
14928 /* --------------------- dp insns (D) --------------------- */
14929 if (BITS8(1,1,1,0,0,0,0,0) == (INSN(27,20) & BITS8(1,1,1,1,0,0,0,0))
14930 && BITS4(1,0,1,1) == INSN(11,8)
14931 && BITS4(0,0,0,0) == (INSN(7,4) & BITS4(0,0,0,1))) {
14932 UInt dM = INSN(3,0) | (INSN(5,5) << 4); /* argR */
14933 UInt dD = INSN(15,12) | (INSN(22,22) << 4); /* dst/acc */
14934 UInt dN = INSN(19,16) | (INSN(7,7) << 4); /* argL */
14935 UInt bP = (insn28 >> 23) & 1;
14936 UInt bQ = (insn28 >> 21) & 1;
14937 UInt bR = (insn28 >> 20) & 1;
14938 UInt bS = (insn28 >> 6) & 1;
14939 UInt opc = (bP << 3) | (bQ << 2) | (bR << 1) | bS;
14940 IRExpr* rm = get_FAKE_roundingmode(); /* XXXROUNDINGFIXME */
14941 switch (opc) {
14942 case BITS4(0,0,0,0): /* MAC: d + n * m */
14943 putDReg(dD, triop(Iop_AddF64, rm,
14944 getDReg(dD),
14945 triop(Iop_MulF64, rm, getDReg(dN),
14946 getDReg(dM))),
14947 condT);
14948 DIP("fmacd%s d%u, d%u, d%u\n", nCC(conq), dD, dN, dM);
14949 goto decode_success_vfp;
14950 case BITS4(0,0,0,1): /* NMAC: d + -(n * m) */
14951 putDReg(dD, triop(Iop_AddF64, rm,
14952 getDReg(dD),
14953 unop(Iop_NegF64,
14954 triop(Iop_MulF64, rm, getDReg(dN),
14955 getDReg(dM)))),
14956 condT);
14957 DIP("fnmacd%s d%u, d%u, d%u\n", nCC(conq), dD, dN, dM);
14958 goto decode_success_vfp;
14959 case BITS4(0,0,1,0): /* MSC: - d + n * m */
14960 putDReg(dD, triop(Iop_AddF64, rm,
14961 unop(Iop_NegF64, getDReg(dD)),
14962 triop(Iop_MulF64, rm, getDReg(dN),
14963 getDReg(dM))),
14964 condT);
14965 DIP("fmscd%s d%u, d%u, d%u\n", nCC(conq), dD, dN, dM);
14966 goto decode_success_vfp;
14967 case BITS4(0,0,1,1): /* NMSC: - d + -(n * m) */
14968 putDReg(dD, triop(Iop_AddF64, rm,
14969 unop(Iop_NegF64, getDReg(dD)),
14970 unop(Iop_NegF64,
14971 triop(Iop_MulF64, rm, getDReg(dN),
14972 getDReg(dM)))),
14973 condT);
14974 DIP("fnmscd%s d%u, d%u, d%u\n", nCC(conq), dD, dN, dM);
14975 goto decode_success_vfp;
14976 case BITS4(0,1,0,0): /* MUL: n * m */
14977 putDReg(dD, triop(Iop_MulF64, rm, getDReg(dN), getDReg(dM)),
14978 condT);
14979 DIP("fmuld%s d%u, d%u, d%u\n", nCC(conq), dD, dN, dM);
14980 goto decode_success_vfp;
14981 case BITS4(0,1,0,1): /* NMUL: - n * m */
14982 putDReg(dD, unop(Iop_NegF64,
14983 triop(Iop_MulF64, rm, getDReg(dN),
14984 getDReg(dM))),
14985 condT);
14986 DIP("fnmuld%s d%u, d%u, d%u\n", nCC(conq), dD, dN, dM);
14987 goto decode_success_vfp;
14988 case BITS4(0,1,1,0): /* ADD: n + m */
14989 putDReg(dD, triop(Iop_AddF64, rm, getDReg(dN), getDReg(dM)),
14990 condT);
14991 DIP("faddd%s d%u, d%u, d%u\n", nCC(conq), dD, dN, dM);
14992 goto decode_success_vfp;
14993 case BITS4(0,1,1,1): /* SUB: n - m */
14994 putDReg(dD, triop(Iop_SubF64, rm, getDReg(dN), getDReg(dM)),
14995 condT);
14996 DIP("fsubd%s d%u, d%u, d%u\n", nCC(conq), dD, dN, dM);
14997 goto decode_success_vfp;
14998 case BITS4(1,0,0,0): /* DIV: n / m */
14999 putDReg(dD, triop(Iop_DivF64, rm, getDReg(dN), getDReg(dM)),
15000 condT);
15001 DIP("fdivd%s d%u, d%u, d%u\n", nCC(conq), dD, dN, dM);
15002 goto decode_success_vfp;
15003 case BITS4(1,0,1,0): /* VNFMS: -(d - n * m) (fused) */
15004 /* XXXROUNDINGFIXME look up ARM reference for fused
15005 multiply-add rounding */
15006 putDReg(dD, triop(Iop_AddF64, rm,
15007 unop(Iop_NegF64, getDReg(dD)),
15008 triop(Iop_MulF64, rm,
15009 getDReg(dN),
15010 getDReg(dM))),
15011 condT);
15012 DIP("vfnmsd%s d%u, d%u, d%u\n", nCC(conq), dD, dN, dM);
15013 goto decode_success_vfp;
15014 case BITS4(1,0,1,1): /* VNFMA: -(d + n * m) (fused) */
15015 /* XXXROUNDINGFIXME look up ARM reference for fused
15016 multiply-add rounding */
15017 putDReg(dD, triop(Iop_AddF64, rm,
15018 unop(Iop_NegF64, getDReg(dD)),
15019 triop(Iop_MulF64, rm,
15020 unop(Iop_NegF64, getDReg(dN)),
15021 getDReg(dM))),
15022 condT);
15023 DIP("vfnmad%s d%u, d%u, d%u\n", nCC(conq), dD, dN, dM);
15024 goto decode_success_vfp;
15025 case BITS4(1,1,0,0): /* VFMA: d + n * m (fused) */
15026 /* XXXROUNDINGFIXME look up ARM reference for fused
15027 multiply-add rounding */
15028 putDReg(dD, triop(Iop_AddF64, rm,
15029 getDReg(dD),
15030 triop(Iop_MulF64, rm, getDReg(dN),
15031 getDReg(dM))),
15032 condT);
15033 DIP("vfmad%s d%u, d%u, d%u\n", nCC(conq), dD, dN, dM);
15034 goto decode_success_vfp;
15035 case BITS4(1,1,0,1): /* VFMS: d + (-n * m) (fused) */
15036 /* XXXROUNDINGFIXME look up ARM reference for fused
15037 multiply-add rounding */
15038 putDReg(dD, triop(Iop_AddF64, rm,
15039 getDReg(dD),
15040 triop(Iop_MulF64, rm,
15041 unop(Iop_NegF64, getDReg(dN)),
15042 getDReg(dM))),
15043 condT);
15044 DIP("vfmsd%s d%u, d%u, d%u\n", nCC(conq), dD, dN, dM);
15045 goto decode_success_vfp;
15046 default:
15047 break;
15051 /* --------------------- compares (D) --------------------- */
15052 /* 31 27 23 19 15 11 7 3
15053 28 24 20 16 12 8 4 0
15054 FCMPD cond 1110 1D11 0100 Dd 1011 0100 Dm
15055 FCMPED cond 1110 1D11 0100 Dd 1011 1100 Dm
15056 FCMPZD cond 1110 1D11 0101 Dd 1011 0100 0000
15057 FCMPZED cond 1110 1D11 0101 Dd 1011 1100 0000
15060 Z=0 Compare Dd vs Dm and set FPSCR 31:28 accordingly
15061 Z=1 Compare Dd vs zero
15063 N=1 generates Invalid Operation exn if either arg is any kind of NaN
15064 N=0 generates Invalid Operation exn if either arg is a signalling NaN
15065 (Not that we pay any attention to N here)
15067 if (BITS8(1,1,1,0,1,0,1,1) == (INSN(27,20) & BITS8(1,1,1,1,1,0,1,1))
15068 && BITS4(0,1,0,0) == (INSN(19,16) & BITS4(1,1,1,0))
15069 && BITS4(1,0,1,1) == INSN(11,8)
15070 && BITS4(0,1,0,0) == (INSN(7,4) & BITS4(0,1,0,1))) {
15071 UInt bZ = (insn28 >> 16) & 1;
15072 UInt bN = (insn28 >> 7) & 1;
15073 UInt dD = INSN(15,12) | (INSN(22,22) << 4);
15074 UInt dM = INSN(3,0) | (INSN(5,5) << 4);
15075 if (bZ && INSN(3,0) != 0) {
15076 /* does not decode; fall through */
15077 } else {
15078 IRTemp argL = newTemp(Ity_F64);
15079 IRTemp argR = newTemp(Ity_F64);
15080 IRTemp irRes = newTemp(Ity_I32);
15081 assign(argL, getDReg(dD));
15082 assign(argR, bZ ? IRExpr_Const(IRConst_F64i(0)) : getDReg(dM));
15083 assign(irRes, binop(Iop_CmpF64, mkexpr(argL), mkexpr(argR)));
15085 IRTemp nzcv = IRTemp_INVALID;
15086 IRTemp oldFPSCR = newTemp(Ity_I32);
15087 IRTemp newFPSCR = newTemp(Ity_I32);
15089 /* This is where the fun starts. We have to convert 'irRes'
15090 from an IR-convention return result (IRCmpF64Result) to an
15091 ARM-encoded (N,Z,C,V) group. The final result is in the
15092 bottom 4 bits of 'nzcv'. */
15093 /* Map compare result from IR to ARM(nzcv) */
15095 FP cmp result | IR | ARM(nzcv)
15096 --------------------------------
15097 UN 0x45 0011
15098 LT 0x01 1000
15099 GT 0x00 0010
15100 EQ 0x40 0110
15102 nzcv = mk_convert_IRCmpF64Result_to_NZCV(irRes);
15104 /* And update FPSCR accordingly */
15105 assign(oldFPSCR, IRExpr_Get(OFFB_FPSCR, Ity_I32));
15106 assign(newFPSCR,
15107 binop(Iop_Or32,
15108 binop(Iop_And32, mkexpr(oldFPSCR), mkU32(0x0FFFFFFF)),
15109 binop(Iop_Shl32, mkexpr(nzcv), mkU8(28))));
15111 putMiscReg32(OFFB_FPSCR, mkexpr(newFPSCR), condT);
15113 if (bZ) {
15114 DIP("fcmpz%sd%s d%u\n", bN ? "e" : "", nCC(conq), dD);
15115 } else {
15116 DIP("fcmp%sd%s d%u, d%u\n", bN ? "e" : "", nCC(conq), dD, dM);
15118 goto decode_success_vfp;
15120 /* fall through */
15123 /* --------------------- unary (D) --------------------- */
15124 if (BITS8(1,1,1,0,1,0,1,1) == (INSN(27,20) & BITS8(1,1,1,1,1,0,1,1))
15125 && BITS4(0,0,0,0) == (INSN(19,16) & BITS4(1,1,1,0))
15126 && BITS4(1,0,1,1) == INSN(11,8)
15127 && BITS4(0,1,0,0) == (INSN(7,4) & BITS4(0,1,0,1))) {
15128 UInt dD = INSN(15,12) | (INSN(22,22) << 4);
15129 UInt dM = INSN(3,0) | (INSN(5,5) << 4);
15130 UInt b16 = (insn28 >> 16) & 1;
15131 UInt b7 = (insn28 >> 7) & 1;
15132 /**/ if (b16 == 0 && b7 == 0) {
15133 // FCPYD
15134 putDReg(dD, getDReg(dM), condT);
15135 DIP("fcpyd%s d%u, d%u\n", nCC(conq), dD, dM);
15136 goto decode_success_vfp;
15138 else if (b16 == 0 && b7 == 1) {
15139 // FABSD
15140 putDReg(dD, unop(Iop_AbsF64, getDReg(dM)), condT);
15141 DIP("fabsd%s d%u, d%u\n", nCC(conq), dD, dM);
15142 goto decode_success_vfp;
15144 else if (b16 == 1 && b7 == 0) {
15145 // FNEGD
15146 putDReg(dD, unop(Iop_NegF64, getDReg(dM)), condT);
15147 DIP("fnegd%s d%u, d%u\n", nCC(conq), dD, dM);
15148 goto decode_success_vfp;
15150 else if (b16 == 1 && b7 == 1) {
15151 // FSQRTD
15152 IRExpr* rm = get_FAKE_roundingmode(); /* XXXROUNDINGFIXME */
15153 putDReg(dD, binop(Iop_SqrtF64, rm, getDReg(dM)), condT);
15154 DIP("fsqrtd%s d%u, d%u\n", nCC(conq), dD, dM);
15155 goto decode_success_vfp;
15157 else
15158 vassert(0);
15160 /* fall through */
15163 /* ----------------- I <-> D conversions ----------------- */
15165 // F{S,U}ITOD dD, fM
15166 if (BITS8(1,1,1,0,1,0,1,1) == (INSN(27,20) & BITS8(1,1,1,1,1,0,1,1))
15167 && BITS4(1,0,0,0) == (INSN(19,16) & BITS4(1,1,1,1))
15168 && BITS4(1,0,1,1) == INSN(11,8)
15169 && BITS4(0,1,0,0) == (INSN(7,4) & BITS4(0,1,0,1))) {
15170 UInt bM = (insn28 >> 5) & 1;
15171 UInt fM = (INSN(3,0) << 1) | bM;
15172 UInt dD = INSN(15,12) | (INSN(22,22) << 4);
15173 UInt syned = (insn28 >> 7) & 1;
15174 if (syned) {
15175 // FSITOD
15176 putDReg(dD, unop(Iop_I32StoF64,
15177 unop(Iop_ReinterpF32asI32, getFReg(fM))),
15178 condT);
15179 DIP("fsitod%s d%u, s%u\n", nCC(conq), dD, fM);
15180 } else {
15181 // FUITOD
15182 putDReg(dD, unop(Iop_I32UtoF64,
15183 unop(Iop_ReinterpF32asI32, getFReg(fM))),
15184 condT);
15185 DIP("fuitod%s d%u, s%u\n", nCC(conq), dD, fM);
15187 goto decode_success_vfp;
15190 // FTO{S,U}ID fD, dM
15191 if (BITS8(1,1,1,0,1,0,1,1) == (INSN(27,20) & BITS8(1,1,1,1,1,0,1,1))
15192 && BITS4(1,1,0,0) == (INSN(19,16) & BITS4(1,1,1,0))
15193 && BITS4(1,0,1,1) == INSN(11,8)
15194 && BITS4(0,1,0,0) == (INSN(7,4) & BITS4(0,1,0,1))) {
15195 UInt bD = (insn28 >> 22) & 1;
15196 UInt fD = (INSN(15,12) << 1) | bD;
15197 UInt dM = INSN(3,0) | (INSN(5,5) << 4);
15198 UInt bZ = (insn28 >> 7) & 1;
15199 UInt syned = (insn28 >> 16) & 1;
15200 IRTemp rmode = newTemp(Ity_I32);
15201 assign(rmode, bZ ? mkU32(Irrm_ZERO)
15202 : mkexpr(mk_get_IR_rounding_mode()));
15203 if (syned) {
15204 // FTOSID
15205 putFReg(fD, unop(Iop_ReinterpI32asF32,
15206 binop(Iop_F64toI32S, mkexpr(rmode),
15207 getDReg(dM))),
15208 condT);
15209 DIP("ftosi%sd%s s%u, d%u\n", bZ ? "z" : "",
15210 nCC(conq), fD, dM);
15211 } else {
15212 // FTOUID
15213 putFReg(fD, unop(Iop_ReinterpI32asF32,
15214 binop(Iop_F64toI32U, mkexpr(rmode),
15215 getDReg(dM))),
15216 condT);
15217 DIP("ftoui%sd%s s%u, d%u\n", bZ ? "z" : "",
15218 nCC(conq), fD, dM);
15220 goto decode_success_vfp;
15223 /* ----------------------------------------------------------- */
15224 /* -- VFP instructions -- single precision -- */
15225 /* ----------------------------------------------------------- */
15227 /* --------------------- fldms, fstms --------------------- */
15229 31 27 23 19 15 11 7 0
15230 P UDWL
15231 C4-98, C5-26 1 FSTMD cond 1100 1x00 Rn Fd 1010 offset
15232 C4-98, C5-28 2 FSTMDIA cond 1100 1x10 Rn Fd 1010 offset
15233 C4-98, C5-30 3 FSTMDDB cond 1101 0x10 Rn Fd 1010 offset
15235 C4-40, C5-26 1 FLDMD cond 1100 1x01 Rn Fd 1010 offset
15236 C4-40, C5-26 2 FLDMIAD cond 1100 1x11 Rn Fd 1010 offset
15237 C4-40, C5-26 3 FLDMDBD cond 1101 0x11 Rn Fd 1010 offset
15239 Regs transferred: F(Fd:D) .. F(Fd:d + offset)
15240 offset must not imply a reg > 15
15241 IA/DB: Rn is changed by (4 x # regs transferred)
15243 case coding:
15244 1 at-Rn (access at Rn)
15245 2 ia-Rn (access at Rn, then Rn += 4n)
15246 3 db-Rn (Rn -= 4n, then access at Rn)
15248 if (BITS8(1,1,0,0,0,0,0,0) == (INSN(27,20) & BITS8(1,1,1,0,0,0,0,0))
15249 && INSN(11,8) == BITS4(1,0,1,0)) {
15250 UInt bP = (insn28 >> 24) & 1;
15251 UInt bU = (insn28 >> 23) & 1;
15252 UInt bW = (insn28 >> 21) & 1;
15253 UInt bL = (insn28 >> 20) & 1;
15254 UInt bD = (insn28 >> 22) & 1;
15255 UInt offset = (insn28 >> 0) & 0xFF;
15256 UInt rN = INSN(19,16);
15257 UInt fD = (INSN(15,12) << 1) | bD;
15258 UInt nRegs = offset;
15259 UInt summary = 0;
15260 Int i;
15262 /**/ if (bP == 0 && bU == 1 && bW == 0) {
15263 summary = 1;
15265 else if (bP == 0 && bU == 1 && bW == 1) {
15266 summary = 2;
15268 else if (bP == 1 && bU == 0 && bW == 1) {
15269 summary = 3;
15271 else goto after_vfp_fldms_fstms;
15273 /* no writebacks to r15 allowed. No use of r15 in thumb mode. */
15274 if (rN == 15 && (summary == 2 || summary == 3 || isT))
15275 goto after_vfp_fldms_fstms;
15277 /* offset must specify at least one register */
15278 if (offset < 1)
15279 goto after_vfp_fldms_fstms;
15281 /* can't transfer regs after S31 */
15282 if (fD + nRegs - 1 >= 32)
15283 goto after_vfp_fldms_fstms;
15285 /* Now, we can't do a conditional load or store, since that very
15286 likely will generate an exception. So we have to take a side
15287 exit at this point if the condition is false. */
15288 if (condT != IRTemp_INVALID) {
15289 if (isT)
15290 mk_skip_over_T32_if_cond_is_false( condT );
15291 else
15292 mk_skip_over_A32_if_cond_is_false( condT );
15293 condT = IRTemp_INVALID;
15295 /* Ok, now we're unconditional. Do the load or store. */
15297 /* get the old Rn value */
15298 IRTemp rnT = newTemp(Ity_I32);
15299 assign(rnT, align4if(isT ? getIRegT(rN) : getIRegA(rN),
15300 rN == 15));
15302 /* make a new value for Rn, post-insn */
15303 IRTemp rnTnew = IRTemp_INVALID;
15304 if (summary == 2 || summary == 3) {
15305 rnTnew = newTemp(Ity_I32);
15306 assign(rnTnew, binop(summary == 2 ? Iop_Add32 : Iop_Sub32,
15307 mkexpr(rnT),
15308 mkU32(4 * nRegs)));
15311 /* decide on the base transfer address */
15312 IRTemp taT = newTemp(Ity_I32);
15313 assign(taT, summary == 3 ? mkexpr(rnTnew) : mkexpr(rnT));
15315 /* update Rn if necessary -- in case 3, we're moving it down, so
15316 update before any memory reference, in order to keep Memcheck
15317 and V's stack-extending logic (on linux) happy */
15318 if (summary == 3) {
15319 if (isT)
15320 putIRegT(rN, mkexpr(rnTnew), IRTemp_INVALID);
15321 else
15322 putIRegA(rN, mkexpr(rnTnew), IRTemp_INVALID, Ijk_Boring);
15325 /* generate the transfers */
15326 for (i = 0; i < nRegs; i++) {
15327 IRExpr* addr = binop(Iop_Add32, mkexpr(taT), mkU32(4*i));
15328 if (bL) {
15329 putFReg(fD + i, loadLE(Ity_F32, addr), IRTemp_INVALID);
15330 } else {
15331 storeLE(addr, getFReg(fD + i));
15335 /* update Rn if necessary -- in case 2, we're moving it up, so
15336 update after any memory reference, in order to keep Memcheck
15337 and V's stack-extending logic (on linux) happy */
15338 if (summary == 2) {
15339 if (isT)
15340 putIRegT(rN, mkexpr(rnTnew), IRTemp_INVALID);
15341 else
15342 putIRegA(rN, mkexpr(rnTnew), IRTemp_INVALID, Ijk_Boring);
15345 const HChar* nm = bL==1 ? "ld" : "st";
15346 switch (summary) {
15347 case 1: DIP("f%sms%s r%u, {s%u-s%u}\n",
15348 nm, nCC(conq), rN, fD, fD + nRegs - 1);
15349 break;
15350 case 2: DIP("f%smias%s r%u!, {s%u-s%u}\n",
15351 nm, nCC(conq), rN, fD, fD + nRegs - 1);
15352 break;
15353 case 3: DIP("f%smdbs%s r%u!, {s%u-s%u}\n",
15354 nm, nCC(conq), rN, fD, fD + nRegs - 1);
15355 break;
15356 default: vassert(0);
15359 goto decode_success_vfp;
15360 /* FIXME alignment constraints? */
15363 after_vfp_fldms_fstms:
15365 /* --------------------- fmsr, fmrs --------------------- */
15366 if (BITS8(1,1,1,0,0,0,0,0) == (INSN(27,20) & BITS8(1,1,1,1,1,1,1,0))
15367 && BITS4(1,0,1,0) == INSN(11,8)
15368 && BITS4(0,0,0,0) == INSN(3,0)
15369 && BITS4(0,0,0,1) == (INSN(7,4) & BITS4(0,1,1,1))) {
15370 UInt rD = INSN(15,12);
15371 UInt b7 = (insn28 >> 7) & 1;
15372 UInt fN = (INSN(19,16) << 1) | b7;
15373 UInt b20 = (insn28 >> 20) & 1;
15374 if (rD == 15) {
15375 /* fall through */
15376 /* Let's assume that no sane person would want to do
15377 floating-point transfers to or from the program counter,
15378 and simply decline to decode the instruction. The ARM ARM
15379 doesn't seem to explicitly disallow this case, though. */
15380 } else {
15381 if (b20) {
15382 IRExpr* res = unop(Iop_ReinterpF32asI32, getFReg(fN));
15383 if (isT)
15384 putIRegT(rD, res, condT);
15385 else
15386 putIRegA(rD, res, condT, Ijk_Boring);
15387 DIP("fmrs%s r%u, s%u\n", nCC(conq), rD, fN);
15388 } else {
15389 putFReg(fN, unop(Iop_ReinterpI32asF32,
15390 isT ? getIRegT(rD) : getIRegA(rD)),
15391 condT);
15392 DIP("fmsr%s s%u, r%u\n", nCC(conq), fN, rD);
15394 goto decode_success_vfp;
15396 /* fall through */
15399 /* --------------------- f{ld,st}s --------------------- */
15400 // FLDS, FSTS
15401 if (BITS8(1,1,0,1,0,0,0,0) == (INSN(27,20) & BITS8(1,1,1,1,0,0,1,0))
15402 && BITS4(1,0,1,0) == INSN(11,8)) {
15403 UInt bD = (insn28 >> 22) & 1;
15404 UInt fD = (INSN(15,12) << 1) | bD;
15405 UInt rN = INSN(19,16);
15406 UInt offset = (insn28 & 0xFF) << 2;
15407 UInt bU = (insn28 >> 23) & 1; /* 1: +offset 0: -offset */
15408 UInt bL = (insn28 >> 20) & 1; /* 1: load 0: store */
15409 /* make unconditional */
15410 if (condT != IRTemp_INVALID) {
15411 if (isT)
15412 mk_skip_over_T32_if_cond_is_false( condT );
15413 else
15414 mk_skip_over_A32_if_cond_is_false( condT );
15415 condT = IRTemp_INVALID;
15417 IRTemp ea = newTemp(Ity_I32);
15418 assign(ea, binop(bU ? Iop_Add32 : Iop_Sub32,
15419 align4if(isT ? getIRegT(rN) : getIRegA(rN),
15420 rN == 15),
15421 mkU32(offset)));
15422 if (bL) {
15423 putFReg(fD, loadLE(Ity_F32,mkexpr(ea)), IRTemp_INVALID);
15424 } else {
15425 storeLE(mkexpr(ea), getFReg(fD));
15427 DIP("f%ss%s s%u, [r%u, %c#%u]\n",
15428 bL ? "ld" : "st", nCC(conq), fD, rN,
15429 bU ? '+' : '-', offset);
15430 goto decode_success_vfp;
15433 /* --------------------- dp insns (F) --------------------- */
15434 if (BITS8(1,1,1,0,0,0,0,0) == (INSN(27,20) & BITS8(1,1,1,1,0,0,0,0))
15435 && BITS4(1,0,1,0) == (INSN(11,8) & BITS4(1,1,1,0))
15436 && BITS4(0,0,0,0) == (INSN(7,4) & BITS4(0,0,0,1))) {
15437 UInt bM = (insn28 >> 5) & 1;
15438 UInt bD = (insn28 >> 22) & 1;
15439 UInt bN = (insn28 >> 7) & 1;
15440 UInt fM = (INSN(3,0) << 1) | bM; /* argR */
15441 UInt fD = (INSN(15,12) << 1) | bD; /* dst/acc */
15442 UInt fN = (INSN(19,16) << 1) | bN; /* argL */
15443 UInt bP = (insn28 >> 23) & 1;
15444 UInt bQ = (insn28 >> 21) & 1;
15445 UInt bR = (insn28 >> 20) & 1;
15446 UInt bS = (insn28 >> 6) & 1;
15447 UInt opc = (bP << 3) | (bQ << 2) | (bR << 1) | bS;
15448 IRExpr* rm = get_FAKE_roundingmode(); /* XXXROUNDINGFIXME */
15449 switch (opc) {
15450 case BITS4(0,0,0,0): /* MAC: d + n * m */
15451 putFReg(fD, triop(Iop_AddF32, rm,
15452 getFReg(fD),
15453 triop(Iop_MulF32, rm, getFReg(fN), getFReg(fM))),
15454 condT);
15455 DIP("fmacs%s s%u, s%u, s%u\n", nCC(conq), fD, fN, fM);
15456 goto decode_success_vfp;
15457 case BITS4(0,0,0,1): /* NMAC: d + -(n * m) */
15458 putFReg(fD, triop(Iop_AddF32, rm,
15459 getFReg(fD),
15460 unop(Iop_NegF32,
15461 triop(Iop_MulF32, rm, getFReg(fN),
15462 getFReg(fM)))),
15463 condT);
15464 DIP("fnmacs%s s%u, s%u, s%u\n", nCC(conq), fD, fN, fM);
15465 goto decode_success_vfp;
15466 case BITS4(0,0,1,0): /* MSC: - d + n * m */
15467 putFReg(fD, triop(Iop_AddF32, rm,
15468 unop(Iop_NegF32, getFReg(fD)),
15469 triop(Iop_MulF32, rm, getFReg(fN), getFReg(fM))),
15470 condT);
15471 DIP("fmscs%s s%u, s%u, s%u\n", nCC(conq), fD, fN, fM);
15472 goto decode_success_vfp;
15473 case BITS4(0,0,1,1): /* NMSC: - d + -(n * m) */
15474 putFReg(fD, triop(Iop_AddF32, rm,
15475 unop(Iop_NegF32, getFReg(fD)),
15476 unop(Iop_NegF32,
15477 triop(Iop_MulF32, rm,
15478 getFReg(fN),
15479 getFReg(fM)))),
15480 condT);
15481 DIP("fnmscs%s s%u, s%u, s%u\n", nCC(conq), fD, fN, fM);
15482 goto decode_success_vfp;
15483 case BITS4(0,1,0,0): /* MUL: n * m */
15484 putFReg(fD, triop(Iop_MulF32, rm, getFReg(fN), getFReg(fM)),
15485 condT);
15486 DIP("fmuls%s s%u, s%u, s%u\n", nCC(conq), fD, fN, fM);
15487 goto decode_success_vfp;
15488 case BITS4(0,1,0,1): /* NMUL: - n * m */
15489 putFReg(fD, unop(Iop_NegF32,
15490 triop(Iop_MulF32, rm, getFReg(fN),
15491 getFReg(fM))),
15492 condT);
15493 DIP("fnmuls%s s%u, s%u, s%u\n", nCC(conq), fD, fN, fM);
15494 goto decode_success_vfp;
15495 case BITS4(0,1,1,0): /* ADD: n + m */
15496 putFReg(fD, triop(Iop_AddF32, rm, getFReg(fN), getFReg(fM)),
15497 condT);
15498 DIP("fadds%s s%u, s%u, s%u\n", nCC(conq), fD, fN, fM);
15499 goto decode_success_vfp;
15500 case BITS4(0,1,1,1): /* SUB: n - m */
15501 putFReg(fD, triop(Iop_SubF32, rm, getFReg(fN), getFReg(fM)),
15502 condT);
15503 DIP("fsubs%s s%u, s%u, s%u\n", nCC(conq), fD, fN, fM);
15504 goto decode_success_vfp;
15505 case BITS4(1,0,0,0): /* DIV: n / m */
15506 putFReg(fD, triop(Iop_DivF32, rm, getFReg(fN), getFReg(fM)),
15507 condT);
15508 DIP("fdivs%s s%u, s%u, s%u\n", nCC(conq), fD, fN, fM);
15509 goto decode_success_vfp;
15510 case BITS4(1,0,1,0): /* VNFMS: -(d - n * m) (fused) */
15511 /* XXXROUNDINGFIXME look up ARM reference for fused
15512 multiply-add rounding */
15513 putFReg(fD, triop(Iop_AddF32, rm,
15514 unop(Iop_NegF32, getFReg(fD)),
15515 triop(Iop_MulF32, rm,
15516 getFReg(fN),
15517 getFReg(fM))),
15518 condT);
15519 DIP("vfnmss%s s%u, s%u, s%u\n", nCC(conq), fD, fN, fM);
15520 goto decode_success_vfp;
15521 case BITS4(1,0,1,1): /* VNFMA: -(d + n * m) (fused) */
15522 /* XXXROUNDINGFIXME look up ARM reference for fused
15523 multiply-add rounding */
15524 putFReg(fD, triop(Iop_AddF32, rm,
15525 unop(Iop_NegF32, getFReg(fD)),
15526 triop(Iop_MulF32, rm,
15527 unop(Iop_NegF32, getFReg(fN)),
15528 getFReg(fM))),
15529 condT);
15530 DIP("vfnmas%s s%u, s%u, s%u\n", nCC(conq), fD, fN, fM);
15531 goto decode_success_vfp;
15532 case BITS4(1,1,0,0): /* VFMA: d + n * m (fused) */
15533 /* XXXROUNDINGFIXME look up ARM reference for fused
15534 multiply-add rounding */
15535 putFReg(fD, triop(Iop_AddF32, rm,
15536 getFReg(fD),
15537 triop(Iop_MulF32, rm, getFReg(fN),
15538 getFReg(fM))),
15539 condT);
15540 DIP("vfmas%s s%u, s%u, s%u\n", nCC(conq), fD, fN, fM);
15541 goto decode_success_vfp;
15542 case BITS4(1,1,0,1): /* VFMS: d + (-n * m) (fused) */
15543 /* XXXROUNDINGFIXME look up ARM reference for fused
15544 multiply-add rounding */
15545 putFReg(fD, triop(Iop_AddF32, rm,
15546 getFReg(fD),
15547 triop(Iop_MulF32, rm,
15548 unop(Iop_NegF32, getFReg(fN)),
15549 getFReg(fM))),
15550 condT);
15551 DIP("vfmss%s s%u, s%u, s%u\n", nCC(conq), fD, fN, fM);
15552 goto decode_success_vfp;
15553 default:
15554 break;
15558 /* --------------------- compares (S) --------------------- */
15559 /* 31 27 23 19 15 11 7 3
15560 28 24 20 16 12 8 4 0
15561 FCMPS cond 1110 1D11 0100 Fd 1010 01M0 Fm
15562 FCMPES cond 1110 1D11 0100 Fd 1010 11M0 Fm
15563 FCMPZS cond 1110 1D11 0101 Fd 1010 0100 0000
15564 FCMPZED cond 1110 1D11 0101 Fd 1010 1100 0000
15567 Z=0 Compare Fd:D vs Fm:M and set FPSCR 31:28 accordingly
15568 Z=1 Compare Fd:D vs zero
15570 N=1 generates Invalid Operation exn if either arg is any kind of NaN
15571 N=0 generates Invalid Operation exn if either arg is a signalling NaN
15572 (Not that we pay any attention to N here)
15574 if (BITS8(1,1,1,0,1,0,1,1) == (INSN(27,20) & BITS8(1,1,1,1,1,0,1,1))
15575 && BITS4(0,1,0,0) == (INSN(19,16) & BITS4(1,1,1,0))
15576 && BITS4(1,0,1,0) == INSN(11,8)
15577 && BITS4(0,1,0,0) == (INSN(7,4) & BITS4(0,1,0,1))) {
15578 UInt bZ = (insn28 >> 16) & 1;
15579 UInt bN = (insn28 >> 7) & 1;
15580 UInt bD = (insn28 >> 22) & 1;
15581 UInt bM = (insn28 >> 5) & 1;
15582 UInt fD = (INSN(15,12) << 1) | bD;
15583 UInt fM = (INSN(3,0) << 1) | bM;
15584 if (bZ && (INSN(3,0) != 0 || (INSN(7,4) & 3) != 0)) {
15585 /* does not decode; fall through */
15586 } else {
15587 IRTemp argL = newTemp(Ity_F64);
15588 IRTemp argR = newTemp(Ity_F64);
15589 IRTemp irRes = newTemp(Ity_I32);
15591 assign(argL, unop(Iop_F32toF64, getFReg(fD)));
15592 assign(argR, bZ ? IRExpr_Const(IRConst_F64i(0))
15593 : unop(Iop_F32toF64, getFReg(fM)));
15594 assign(irRes, binop(Iop_CmpF64, mkexpr(argL), mkexpr(argR)));
15596 IRTemp nzcv = IRTemp_INVALID;
15597 IRTemp oldFPSCR = newTemp(Ity_I32);
15598 IRTemp newFPSCR = newTemp(Ity_I32);
15600 /* This is where the fun starts. We have to convert 'irRes'
15601 from an IR-convention return result (IRCmpF64Result) to an
15602 ARM-encoded (N,Z,C,V) group. The final result is in the
15603 bottom 4 bits of 'nzcv'. */
15604 /* Map compare result from IR to ARM(nzcv) */
15606 FP cmp result | IR | ARM(nzcv)
15607 --------------------------------
15608 UN 0x45 0011
15609 LT 0x01 1000
15610 GT 0x00 0010
15611 EQ 0x40 0110
15613 nzcv = mk_convert_IRCmpF64Result_to_NZCV(irRes);
15615 /* And update FPSCR accordingly */
15616 assign(oldFPSCR, IRExpr_Get(OFFB_FPSCR, Ity_I32));
15617 assign(newFPSCR,
15618 binop(Iop_Or32,
15619 binop(Iop_And32, mkexpr(oldFPSCR), mkU32(0x0FFFFFFF)),
15620 binop(Iop_Shl32, mkexpr(nzcv), mkU8(28))));
15622 putMiscReg32(OFFB_FPSCR, mkexpr(newFPSCR), condT);
15624 if (bZ) {
15625 DIP("fcmpz%ss%s s%u\n", bN ? "e" : "", nCC(conq), fD);
15626 } else {
15627 DIP("fcmp%ss%s s%u, s%u\n", bN ? "e" : "",
15628 nCC(conq), fD, fM);
15630 goto decode_success_vfp;
15632 /* fall through */
15635 /* --------------------- unary (S) --------------------- */
15636 if (BITS8(1,1,1,0,1,0,1,1) == (INSN(27,20) & BITS8(1,1,1,1,1,0,1,1))
15637 && BITS4(0,0,0,0) == (INSN(19,16) & BITS4(1,1,1,0))
15638 && BITS4(1,0,1,0) == INSN(11,8)
15639 && BITS4(0,1,0,0) == (INSN(7,4) & BITS4(0,1,0,1))) {
15640 UInt bD = (insn28 >> 22) & 1;
15641 UInt bM = (insn28 >> 5) & 1;
15642 UInt fD = (INSN(15,12) << 1) | bD;
15643 UInt fM = (INSN(3,0) << 1) | bM;
15644 UInt b16 = (insn28 >> 16) & 1;
15645 UInt b7 = (insn28 >> 7) & 1;
15646 /**/ if (b16 == 0 && b7 == 0) {
15647 // FCPYS
15648 putFReg(fD, getFReg(fM), condT);
15649 DIP("fcpys%s s%u, s%u\n", nCC(conq), fD, fM);
15650 goto decode_success_vfp;
15652 else if (b16 == 0 && b7 == 1) {
15653 // FABSS
15654 putFReg(fD, unop(Iop_AbsF32, getFReg(fM)), condT);
15655 DIP("fabss%s s%u, s%u\n", nCC(conq), fD, fM);
15656 goto decode_success_vfp;
15658 else if (b16 == 1 && b7 == 0) {
15659 // FNEGS
15660 putFReg(fD, unop(Iop_NegF32, getFReg(fM)), condT);
15661 DIP("fnegs%s s%u, s%u\n", nCC(conq), fD, fM);
15662 goto decode_success_vfp;
15664 else if (b16 == 1 && b7 == 1) {
15665 // FSQRTS
15666 IRExpr* rm = get_FAKE_roundingmode(); /* XXXROUNDINGFIXME */
15667 putFReg(fD, binop(Iop_SqrtF32, rm, getFReg(fM)), condT);
15668 DIP("fsqrts%s s%u, s%u\n", nCC(conq), fD, fM);
15669 goto decode_success_vfp;
15671 else
15672 vassert(0);
15674 /* fall through */
15677 /* ----------------- I <-> S conversions ----------------- */
15679 // F{S,U}ITOS fD, fM
15680 /* These are more complex than FSITOD/FUITOD. In the D cases, a 32
15681 bit int will always fit within the 53 bit mantissa, so there's
15682 no possibility of a loss of precision, but that's obviously not
15683 the case here. Hence this case possibly requires rounding, and
15684 so it drags in the current rounding mode. */
15685 if (BITS8(1,1,1,0,1,0,1,1) == (INSN(27,20) & BITS8(1,1,1,1,1,0,1,1))
15686 && BITS4(1,0,0,0) == INSN(19,16)
15687 && BITS4(1,0,1,0) == (INSN(11,8) & BITS4(1,1,1,0))
15688 && BITS4(0,1,0,0) == (INSN(7,4) & BITS4(0,1,0,1))) {
15689 UInt bM = (insn28 >> 5) & 1;
15690 UInt bD = (insn28 >> 22) & 1;
15691 UInt fM = (INSN(3,0) << 1) | bM;
15692 UInt fD = (INSN(15,12) << 1) | bD;
15693 UInt syned = (insn28 >> 7) & 1;
15694 IRTemp rmode = newTemp(Ity_I32);
15695 assign(rmode, mkexpr(mk_get_IR_rounding_mode()));
15696 if (syned) {
15697 // FSITOS
15698 putFReg(fD, binop(Iop_F64toF32,
15699 mkexpr(rmode),
15700 unop(Iop_I32StoF64,
15701 unop(Iop_ReinterpF32asI32, getFReg(fM)))),
15702 condT);
15703 DIP("fsitos%s s%u, s%u\n", nCC(conq), fD, fM);
15704 } else {
15705 // FUITOS
15706 putFReg(fD, binop(Iop_F64toF32,
15707 mkexpr(rmode),
15708 unop(Iop_I32UtoF64,
15709 unop(Iop_ReinterpF32asI32, getFReg(fM)))),
15710 condT);
15711 DIP("fuitos%s s%u, s%u\n", nCC(conq), fD, fM);
15713 goto decode_success_vfp;
15716 // FTO{S,U}IS fD, fM
15717 if (BITS8(1,1,1,0,1,0,1,1) == (INSN(27,20) & BITS8(1,1,1,1,1,0,1,1))
15718 && BITS4(1,1,0,0) == (INSN(19,16) & BITS4(1,1,1,0))
15719 && BITS4(1,0,1,0) == INSN(11,8)
15720 && BITS4(0,1,0,0) == (INSN(7,4) & BITS4(0,1,0,1))) {
15721 UInt bM = (insn28 >> 5) & 1;
15722 UInt bD = (insn28 >> 22) & 1;
15723 UInt fD = (INSN(15,12) << 1) | bD;
15724 UInt fM = (INSN(3,0) << 1) | bM;
15725 UInt bZ = (insn28 >> 7) & 1;
15726 UInt syned = (insn28 >> 16) & 1;
15727 IRTemp rmode = newTemp(Ity_I32);
15728 assign(rmode, bZ ? mkU32(Irrm_ZERO)
15729 : mkexpr(mk_get_IR_rounding_mode()));
15730 if (syned) {
15731 // FTOSIS
15732 putFReg(fD, unop(Iop_ReinterpI32asF32,
15733 binop(Iop_F64toI32S, mkexpr(rmode),
15734 unop(Iop_F32toF64, getFReg(fM)))),
15735 condT);
15736 DIP("ftosi%ss%s s%u, d%u\n", bZ ? "z" : "",
15737 nCC(conq), fD, fM);
15738 goto decode_success_vfp;
15739 } else {
15740 // FTOUIS
15741 putFReg(fD, unop(Iop_ReinterpI32asF32,
15742 binop(Iop_F64toI32U, mkexpr(rmode),
15743 unop(Iop_F32toF64, getFReg(fM)))),
15744 condT);
15745 DIP("ftoui%ss%s s%u, d%u\n", bZ ? "z" : "",
15746 nCC(conq), fD, fM);
15747 goto decode_success_vfp;
15751 /* ----------------- S <-> D conversions ----------------- */
15753 // FCVTDS
15754 if (BITS8(1,1,1,0,1,0,1,1) == (INSN(27,20) & BITS8(1,1,1,1,1,0,1,1))
15755 && BITS4(0,1,1,1) == INSN(19,16)
15756 && BITS4(1,0,1,0) == INSN(11,8)
15757 && BITS4(1,1,0,0) == (INSN(7,4) & BITS4(1,1,0,1))) {
15758 UInt dD = INSN(15,12) | (INSN(22,22) << 4);
15759 UInt bM = (insn28 >> 5) & 1;
15760 UInt fM = (INSN(3,0) << 1) | bM;
15761 putDReg(dD, unop(Iop_F32toF64, getFReg(fM)), condT);
15762 DIP("fcvtds%s d%u, s%u\n", nCC(conq), dD, fM);
15763 goto decode_success_vfp;
15766 // FCVTSD
15767 if (BITS8(1,1,1,0,1,0,1,1) == (INSN(27,20) & BITS8(1,1,1,1,1,0,1,1))
15768 && BITS4(0,1,1,1) == INSN(19,16)
15769 && BITS4(1,0,1,1) == INSN(11,8)
15770 && BITS4(1,1,0,0) == (INSN(7,4) & BITS4(1,1,0,1))) {
15771 UInt bD = (insn28 >> 22) & 1;
15772 UInt fD = (INSN(15,12) << 1) | bD;
15773 UInt dM = INSN(3,0) | (INSN(5,5) << 4);
15774 IRTemp rmode = newTemp(Ity_I32);
15775 assign(rmode, mkexpr(mk_get_IR_rounding_mode()));
15776 putFReg(fD, binop(Iop_F64toF32, mkexpr(rmode), getDReg(dM)),
15777 condT);
15778 DIP("fcvtsd%s s%u, d%u\n", nCC(conq), fD, dM);
15779 goto decode_success_vfp;
15782 /* --------------- VCVT fixed<->floating, VFP --------------- */
15783 /* 31 27 23 19 15 11 7 3
15784 28 24 20 16 12 8 4 0
15786 cond 1110 1D11 1p1U Vd 101f x1i0 imm4
15788 VCVT<c>.<Td>.F64 <Dd>, <Dd>, #fbits
15789 VCVT<c>.<Td>.F32 <Dd>, <Dd>, #fbits
15790 VCVT<c>.F64.<Td> <Dd>, <Dd>, #fbits
15791 VCVT<c>.F32.<Td> <Dd>, <Dd>, #fbits
15792 are of this form. We only handle a subset of the cases though.
15794 if (BITS8(1,1,1,0,1,0,1,1) == (INSN(27,20) & BITS8(1,1,1,1,1,0,1,1))
15795 && BITS4(1,0,1,0) == (INSN(19,16) & BITS4(1,0,1,0))
15796 && BITS3(1,0,1) == INSN(11,9)
15797 && BITS3(1,0,0) == (INSN(6,4) & BITS3(1,0,1))) {
15798 UInt bD = INSN(22,22);
15799 UInt bOP = INSN(18,18);
15800 UInt bU = INSN(16,16);
15801 UInt Vd = INSN(15,12);
15802 UInt bSF = INSN(8,8);
15803 UInt bSX = INSN(7,7);
15804 UInt bI = INSN(5,5);
15805 UInt imm4 = INSN(3,0);
15806 Bool to_fixed = bOP == 1;
15807 Bool dp_op = bSF == 1;
15808 Bool unsyned = bU == 1;
15809 UInt size = bSX == 0 ? 16 : 32;
15810 Int frac_bits = size - ((imm4 << 1) | bI);
15811 UInt d = dp_op ? ((bD << 4) | Vd) : ((Vd << 1) | bD);
15813 IRExpr* rm = mkU32(Irrm_NEAREST);
15814 IRTemp scale = newTemp(Ity_F64);
15815 assign(scale, unop(Iop_I32UtoF64, mkU32( ((UInt)1) << (frac_bits-1) )));
15817 if (frac_bits >= 1 && frac_bits <= 32 && !to_fixed && !dp_op
15818 && size == 32) {
15819 /* VCVT.F32.{S,U}32 S[d], S[d], #frac_bits */
15820 /* This generates really horrible code. We could potentially
15821 do much better. */
15822 IRTemp rmode = newTemp(Ity_I32);
15823 assign(rmode, mkU32(Irrm_NEAREST)); // per the spec
15824 IRTemp src32 = newTemp(Ity_I32);
15825 assign(src32, unop(Iop_ReinterpF32asI32, getFReg(d)));
15826 IRExpr* as_F64 = unop( unsyned ? Iop_I32UtoF64 : Iop_I32StoF64,
15827 mkexpr(src32 ) );
15828 IRExpr* resF64 = triop(Iop_DivF64,
15829 rm, as_F64,
15830 triop(Iop_AddF64, rm, mkexpr(scale),
15831 mkexpr(scale)));
15832 IRExpr* resF32 = binop(Iop_F64toF32, mkexpr(rmode), resF64);
15833 putFReg(d, resF32, condT);
15834 DIP("vcvt.f32.%c32, s%u, s%u, #%d\n",
15835 unsyned ? 'u' : 's', d, d, frac_bits);
15836 goto decode_success_vfp;
15838 if (frac_bits >= 1 && frac_bits <= 32 && !to_fixed && dp_op
15839 && size == 32) {
15840 /* VCVT.F64.{S,U}32 D[d], D[d], #frac_bits */
15841 /* This generates really horrible code. We could potentially
15842 do much better. */
15843 IRTemp src32 = newTemp(Ity_I32);
15844 assign(src32, unop(Iop_64to32, getDRegI64(d)));
15845 IRExpr* as_F64 = unop( unsyned ? Iop_I32UtoF64 : Iop_I32StoF64,
15846 mkexpr(src32 ) );
15847 IRExpr* resF64 = triop(Iop_DivF64,
15848 rm, as_F64,
15849 triop(Iop_AddF64, rm, mkexpr(scale),
15850 mkexpr(scale)));
15851 putDReg(d, resF64, condT);
15852 DIP("vcvt.f64.%c32, d%u, d%u, #%d\n",
15853 unsyned ? 'u' : 's', d, d, frac_bits);
15854 goto decode_success_vfp;
15856 if (frac_bits >= 1 && frac_bits <= 32 && to_fixed && dp_op
15857 && size == 32) {
15858 /* VCVT.{S,U}32.F64 D[d], D[d], #frac_bits */
15859 IRTemp srcF64 = newTemp(Ity_F64);
15860 assign(srcF64, getDReg(d));
15861 IRTemp scaledF64 = newTemp(Ity_F64);
15862 assign(scaledF64, triop(Iop_MulF64,
15863 rm, mkexpr(srcF64),
15864 triop(Iop_AddF64, rm, mkexpr(scale),
15865 mkexpr(scale))));
15866 IRTemp rmode = newTemp(Ity_I32);
15867 assign(rmode, mkU32(Irrm_ZERO)); // as per the spec
15868 IRTemp asI32 = newTemp(Ity_I32);
15869 assign(asI32, binop(unsyned ? Iop_F64toI32U : Iop_F64toI32S,
15870 mkexpr(rmode), mkexpr(scaledF64)));
15871 putDRegI64(d, unop(unsyned ? Iop_32Uto64 : Iop_32Sto64,
15872 mkexpr(asI32)), condT);
15874 DIP("vcvt.%c32.f64, d%u, d%u, #%d\n",
15875 unsyned ? 'u' : 's', d, d, frac_bits);
15876 goto decode_success_vfp;
15878 if (frac_bits >= 1 && frac_bits <= 32 && to_fixed && !dp_op
15879 && size == 32) {
15880 /* VCVT.{S,U}32.F32 S[d], S[d], #frac_bits */
15881 IRTemp srcF32 = newTemp(Ity_F32);
15882 assign(srcF32, getFReg(d));
15883 IRTemp scaledF64 = newTemp(Ity_F64);
15884 assign(scaledF64, triop(Iop_MulF64,
15885 rm, unop(Iop_F32toF64, mkexpr(srcF32)),
15886 triop(Iop_AddF64, rm, mkexpr(scale),
15887 mkexpr(scale))));
15888 IRTemp rmode = newTemp(Ity_I32);
15889 assign(rmode, mkU32(Irrm_ZERO)); // as per the spec
15890 IRTemp asI32 = newTemp(Ity_I32);
15891 assign(asI32, binop(unsyned ? Iop_F64toI32U : Iop_F64toI32S,
15892 mkexpr(rmode), mkexpr(scaledF64)));
15893 putFReg(d, unop(Iop_ReinterpI32asF32, mkexpr(asI32)), condT);
15894 DIP("vcvt.%c32.f32, d%u, d%u, #%d\n",
15895 unsyned ? 'u' : 's', d, d, frac_bits);
15896 goto decode_success_vfp;
15898 /* fall through */
15901 /* FAILURE */
15902 return False;
15904 decode_success_vfp:
15905 /* Check that any accepted insn really is a CP10 or CP11 insn, iow,
15906 assert that we aren't accepting, in this fn, insns that actually
15907 should be handled somewhere else. */
15908 vassert(INSN(11,9) == BITS3(1,0,1)); // 11:8 = 1010 or 1011
15909 return True;
15911 # undef INSN
15915 /*------------------------------------------------------------*/
15916 /*--- Instructions in NV (never) space ---*/
15917 /*------------------------------------------------------------*/
15919 /* ARM only */
15920 /* Translate a NV space instruction. If successful, returns True and
15921 *dres may or may not be updated. If failure, returns False and
15922 doesn't change *dres nor create any IR.
15924 Note that all NEON instructions (in ARM mode) up to and including
15925 ARMv7, but not later, are handled through here, since they are all
15926 in NV space.
15928 static Bool decode_NV_instruction_ARMv7_and_below
15929 ( /*MOD*/DisResult* dres,
15930 const VexArchInfo* archinfo,
15931 UInt insn )
15933 # define INSN(_bMax,_bMin) SLICE_UInt(insn, (_bMax), (_bMin))
15934 # define INSN_COND SLICE_UInt(insn, 31, 28)
15936 HChar dis_buf[128];
15938 // Should only be called for NV instructions
15939 vassert(BITS4(1,1,1,1) == INSN_COND);
15941 /* ------------------------ pld{w} ------------------------ */
15942 if (BITS8(0,1,0,1, 0,0, 0,1) == (INSN(27,20) & BITS8(1,1,1,1, 0,0, 1,1))
15943 && BITS4(1,1,1,1) == INSN(15,12)) {
15944 UInt rN = INSN(19,16);
15945 UInt imm12 = INSN(11,0);
15946 UInt bU = INSN(23,23);
15947 UInt bR = INSN(22,22);
15948 DIP("pld%c [r%u, #%c%u]\n", bR ? ' ' : 'w', rN, bU ? '+' : '-', imm12);
15949 return True;
15952 if (BITS8(0,1,1,1, 0,0, 0,1) == (INSN(27,20) & BITS8(1,1,1,1, 0,0, 1,1))
15953 && BITS4(1,1,1,1) == INSN(15,12)
15954 && 0 == INSN(4,4)) {
15955 UInt rN = INSN(19,16);
15956 UInt rM = INSN(3,0);
15957 UInt imm5 = INSN(11,7);
15958 UInt sh2 = INSN(6,5);
15959 UInt bU = INSN(23,23);
15960 UInt bR = INSN(22,22);
15961 if (rM != 15 && (rN != 15 || bR)) {
15962 IRExpr* eaE = mk_EA_reg_plusminus_shifted_reg(rN, bU, rM,
15963 sh2, imm5, dis_buf);
15964 IRTemp eaT = newTemp(Ity_I32);
15965 /* Bind eaE to a temp merely for debugging-vex purposes, so we
15966 can check it's a plausible decoding. It will get removed
15967 by iropt a little later on. */
15968 vassert(eaE);
15969 assign(eaT, eaE);
15970 DIP("pld%c %s\n", bR ? ' ' : 'w', dis_buf);
15971 return True;
15973 /* fall through */
15976 /* ------------------------ pli ------------------------ */
15977 if (BITS8(0,1,0,0, 0, 1,0,1) == (INSN(27,20) & BITS8(1,1,1,1,0,1,1,1))
15978 && BITS4(1,1,1,1) == INSN(15,12)) {
15979 UInt rN = INSN(19,16);
15980 UInt imm12 = INSN(11,0);
15981 UInt bU = INSN(23,23);
15982 DIP("pli [r%u, #%c%u]\n", rN, bU ? '+' : '-', imm12);
15983 return True;
15986 /* --------------------- Interworking branches --------------------- */
15988 // BLX (1), viz, unconditional branch and link to R15+simm24
15989 // and set CPSR.T = 1, that is, switch to Thumb mode
15990 if (INSN(31,25) == BITS7(1,1,1,1,1,0,1)) {
15991 UInt bitH = INSN(24,24);
15992 UInt uimm24 = INSN(23,0); uimm24 <<= 8;
15993 Int simm24 = (Int)uimm24; simm24 >>= 8;
15994 simm24 = (((UInt)simm24) << 2) + (bitH << 1);
15995 /* Now this is a bit tricky. Since we're decoding an ARM insn,
15996 it is implies that CPSR.T == 0. Hence the current insn's
15997 address is guaranteed to be of the form X--(30)--X00. So, no
15998 need to mask any bits off it. But need to set the lowest bit
15999 to 1 to denote we're in Thumb mode after this, since
16000 guest_R15T has CPSR.T as the lowest bit. And we can't chase
16001 into the call, so end the block at this point. */
16002 UInt dst = guest_R15_curr_instr_notENC + 8 + (simm24 | 1);
16003 putIRegA( 14, mkU32(guest_R15_curr_instr_notENC + 4),
16004 IRTemp_INVALID/*because AL*/, Ijk_Boring );
16005 llPutIReg(15, mkU32(dst));
16006 dres->jk_StopHere = Ijk_Call;
16007 dres->whatNext = Dis_StopHere;
16008 DIP("blx 0x%x (and switch to Thumb mode)\n", dst - 1);
16009 return True;
16012 /* ------------------- v7 barrier insns ------------------- */
16013 switch (insn) {
16014 case 0xF57FF06F: /* ISB */
16015 stmt( IRStmt_MBE(Imbe_Fence) );
16016 DIP("ISB\n");
16017 return True;
16018 case 0xF57FF04F: /* DSB sy */
16019 case 0xF57FF04E: /* DSB st */
16020 case 0xF57FF04B: /* DSB ish */
16021 case 0xF57FF04A: /* DSB ishst */
16022 case 0xF57FF047: /* DSB nsh */
16023 case 0xF57FF046: /* DSB nshst */
16024 case 0xF57FF043: /* DSB osh */
16025 case 0xF57FF042: /* DSB oshst */
16026 stmt( IRStmt_MBE(Imbe_Fence) );
16027 DIP("DSB\n");
16028 return True;
16029 case 0xF57FF05F: /* DMB sy */
16030 case 0xF57FF05E: /* DMB st */
16031 case 0xF57FF05B: /* DMB ish */
16032 case 0xF57FF05A: /* DMB ishst */
16033 case 0xF57FF057: /* DMB nsh */
16034 case 0xF57FF056: /* DMB nshst */
16035 case 0xF57FF053: /* DMB osh */
16036 case 0xF57FF052: /* DMB oshst */
16037 stmt( IRStmt_MBE(Imbe_Fence) );
16038 DIP("DMB\n");
16039 return True;
16040 default:
16041 break;
16044 /* ------------------- CLREX ------------------ */
16045 if (insn == 0xF57FF01F) {
16046 /* AFAICS, this simply cancels a (all?) reservations made by a
16047 (any?) preceding LDREX(es). Arrange to hand it through to
16048 the back end. */
16049 stmt( IRStmt_MBE(Imbe_CancelReservation) );
16050 DIP("clrex\n");
16051 return True;
16054 /* ------------------- NEON ------------------- */
16055 if (archinfo->hwcaps & VEX_HWCAPS_ARM_NEON) {
16056 Bool ok_neon = decode_NEON_instruction_ARMv7_and_below(
16057 dres, insn, IRTemp_INVALID/*unconditional*/,
16058 False/*!isT*/
16060 if (ok_neon)
16061 return True;
16064 // unrecognised
16065 return False;
16067 # undef INSN_COND
16068 # undef INSN
16072 /*------------------------------------------------------------*/
16073 /*--- Disassemble a single ARM instruction ---*/
16074 /*------------------------------------------------------------*/
16076 /* Disassemble a single ARM instruction into IR. The instruction is
16077 located in host memory at guest_instr, and has (decoded) guest IP
16078 of guest_R15_curr_instr_notENC, which will have been set before the
16079 call here. */
16081 static
16082 DisResult disInstr_ARM_WRK (
16083 Bool (*resteerOkFn) ( /*opaque*/void*, Addr ),
16084 Bool resteerCisOk,
16085 void* callback_opaque,
16086 const UChar* guest_instr,
16087 const VexArchInfo* archinfo,
16088 const VexAbiInfo* abiinfo,
16089 Bool sigill_diag
16092 // A macro to fish bits out of 'insn'.
16093 # define INSN(_bMax,_bMin) SLICE_UInt(insn, (_bMax), (_bMin))
16094 # define INSN_COND SLICE_UInt(insn, 31, 28)
16096 DisResult dres;
16097 UInt insn;
16098 IRTemp condT; /* :: Ity_I32 */
16099 UInt summary;
16100 HChar dis_buf[128]; // big enough to hold LDMIA etc text
16102 /* Set result defaults. */
16103 dres.whatNext = Dis_Continue;
16104 dres.len = 4;
16105 dres.continueAt = 0;
16106 dres.jk_StopHere = Ijk_INVALID;
16107 dres.hint = Dis_HintNone;
16109 /* Set default actions for post-insn handling of writes to r15, if
16110 required. */
16111 r15written = False;
16112 r15guard = IRTemp_INVALID; /* unconditional */
16113 r15kind = Ijk_Boring;
16115 /* At least this is simple on ARM: insns are all 4 bytes long, and
16116 4-aligned. So just fish the whole thing out of memory right now
16117 and have done. */
16118 insn = getUIntLittleEndianly( guest_instr );
16120 if (0) vex_printf("insn: 0x%x\n", insn);
16122 DIP("\t(arm) 0x%x: ", (UInt)guest_R15_curr_instr_notENC);
16124 vassert(0 == (guest_R15_curr_instr_notENC & 3));
16126 /* ----------------------------------------------------------- */
16128 /* Spot "Special" instructions (see comment at top of file). */
16130 const UChar* code = guest_instr;
16131 /* Spot the 16-byte preamble:
16133 e1a0c1ec mov r12, r12, ROR #3
16134 e1a0c6ec mov r12, r12, ROR #13
16135 e1a0ceec mov r12, r12, ROR #29
16136 e1a0c9ec mov r12, r12, ROR #19
16138 UInt word1 = 0xE1A0C1EC;
16139 UInt word2 = 0xE1A0C6EC;
16140 UInt word3 = 0xE1A0CEEC;
16141 UInt word4 = 0xE1A0C9EC;
16142 if (getUIntLittleEndianly(code+ 0) == word1 &&
16143 getUIntLittleEndianly(code+ 4) == word2 &&
16144 getUIntLittleEndianly(code+ 8) == word3 &&
16145 getUIntLittleEndianly(code+12) == word4) {
16146 /* Got a "Special" instruction preamble. Which one is it? */
16147 if (getUIntLittleEndianly(code+16) == 0xE18AA00A
16148 /* orr r10,r10,r10 */) {
16149 /* R3 = client_request ( R4 ) */
16150 DIP("r3 = client_request ( %%r4 )\n");
16151 llPutIReg(15, mkU32( guest_R15_curr_instr_notENC + 20 ));
16152 dres.jk_StopHere = Ijk_ClientReq;
16153 dres.whatNext = Dis_StopHere;
16154 goto decode_success;
16156 else
16157 if (getUIntLittleEndianly(code+16) == 0xE18BB00B
16158 /* orr r11,r11,r11 */) {
16159 /* R3 = guest_NRADDR */
16160 DIP("r3 = guest_NRADDR\n");
16161 dres.len = 20;
16162 llPutIReg(3, IRExpr_Get( OFFB_NRADDR, Ity_I32 ));
16163 goto decode_success;
16165 else
16166 if (getUIntLittleEndianly(code+16) == 0xE18CC00C
16167 /* orr r12,r12,r12 */) {
16168 /* branch-and-link-to-noredir R4 */
16169 DIP("branch-and-link-to-noredir r4\n");
16170 llPutIReg(14, mkU32( guest_R15_curr_instr_notENC + 20) );
16171 llPutIReg(15, llGetIReg(4));
16172 dres.jk_StopHere = Ijk_NoRedir;
16173 dres.whatNext = Dis_StopHere;
16174 goto decode_success;
16176 else
16177 if (getUIntLittleEndianly(code+16) == 0xE1899009
16178 /* orr r9,r9,r9 */) {
16179 /* IR injection */
16180 DIP("IR injection\n");
16181 vex_inject_ir(irsb, Iend_LE);
16182 // Invalidate the current insn. The reason is that the IRop we're
16183 // injecting here can change. In which case the translation has to
16184 // be redone. For ease of handling, we simply invalidate all the
16185 // time.
16186 stmt(IRStmt_Put(OFFB_CMSTART, mkU32(guest_R15_curr_instr_notENC)));
16187 stmt(IRStmt_Put(OFFB_CMLEN, mkU32(20)));
16188 llPutIReg(15, mkU32( guest_R15_curr_instr_notENC + 20 ));
16189 dres.whatNext = Dis_StopHere;
16190 dres.jk_StopHere = Ijk_InvalICache;
16191 goto decode_success;
16193 /* We don't know what it is. Set opc1/opc2 so decode_failure
16194 can print the insn following the Special-insn preamble. */
16195 insn = getUIntLittleEndianly(code+16);
16196 goto decode_failure;
16197 /*NOTREACHED*/
16202 /* ----------------------------------------------------------- */
16204 /* Main ARM instruction decoder starts here. */
16206 /* Deal with the condition. Strategy is to merely generate a
16207 condition temporary at this point (or IRTemp_INVALID, meaning
16208 unconditional). We leave it to lower-level instruction decoders
16209 to decide whether they can generate straight-line code, or
16210 whether they must generate a side exit before the instruction.
16211 condT :: Ity_I32 and is always either zero or one. */
16212 condT = IRTemp_INVALID;
16213 switch ( (ARMCondcode)INSN_COND ) {
16214 case ARMCondNV: {
16215 // Illegal instruction prior to v5 (see ARM ARM A3-5), but
16216 // some cases are acceptable
16217 Bool ok
16218 = decode_NV_instruction_ARMv7_and_below(&dres, archinfo, insn);
16219 if (ok)
16220 goto decode_success;
16221 else
16222 goto after_v7_decoder;
16224 case ARMCondAL: // Always executed
16225 break;
16226 case ARMCondEQ: case ARMCondNE: case ARMCondHS: case ARMCondLO:
16227 case ARMCondMI: case ARMCondPL: case ARMCondVS: case ARMCondVC:
16228 case ARMCondHI: case ARMCondLS: case ARMCondGE: case ARMCondLT:
16229 case ARMCondGT: case ARMCondLE:
16230 condT = newTemp(Ity_I32);
16231 assign( condT, mk_armg_calculate_condition( INSN_COND ));
16232 break;
16235 /* ----------------------------------------------------------- */
16236 /* -- ARMv5 integer instructions -- */
16237 /* ----------------------------------------------------------- */
16239 /* ---------------- Data processing ops ------------------- */
16241 if (0 == (INSN(27,20) & BITS8(1,1,0,0,0,0,0,0))
16242 && !(INSN(25,25) == 0 && INSN(7,7) == 1 && INSN(4,4) == 1)) {
16243 IRTemp shop = IRTemp_INVALID; /* shifter operand */
16244 IRTemp shco = IRTemp_INVALID; /* shifter carry out */
16245 UInt rD = (insn >> 12) & 0xF; /* 15:12 */
16246 UInt rN = (insn >> 16) & 0xF; /* 19:16 */
16247 UInt bitS = (insn >> 20) & 1; /* 20:20 */
16248 IRTemp rNt = IRTemp_INVALID;
16249 IRTemp res = IRTemp_INVALID;
16250 IRTemp oldV = IRTemp_INVALID;
16251 IRTemp oldC = IRTemp_INVALID;
16252 const HChar* name = NULL;
16253 IROp op = Iop_INVALID;
16254 Bool ok;
16256 switch (INSN(24,21)) {
16258 /* --------- ADD, SUB, AND, OR --------- */
16259 case BITS4(0,1,0,0): /* ADD: Rd = Rn + shifter_operand */
16260 name = "add"; op = Iop_Add32; goto rd_eq_rn_op_SO;
16261 case BITS4(0,0,1,0): /* SUB: Rd = Rn - shifter_operand */
16262 name = "sub"; op = Iop_Sub32; goto rd_eq_rn_op_SO;
16263 case BITS4(0,0,1,1): /* RSB: Rd = shifter_operand - Rn */
16264 name = "rsb"; op = Iop_Sub32; goto rd_eq_rn_op_SO;
16265 case BITS4(0,0,0,0): /* AND: Rd = Rn & shifter_operand */
16266 name = "and"; op = Iop_And32; goto rd_eq_rn_op_SO;
16267 case BITS4(1,1,0,0): /* OR: Rd = Rn | shifter_operand */
16268 name = "orr"; op = Iop_Or32; goto rd_eq_rn_op_SO;
16269 case BITS4(0,0,0,1): /* EOR: Rd = Rn ^ shifter_operand */
16270 name = "eor"; op = Iop_Xor32; goto rd_eq_rn_op_SO;
16271 case BITS4(1,1,1,0): /* BIC: Rd = Rn & ~shifter_operand */
16272 name = "bic"; op = Iop_And32; goto rd_eq_rn_op_SO;
16273 rd_eq_rn_op_SO: {
16274 Bool isRSB = False;
16275 Bool isBIC = False;
16276 switch (INSN(24,21)) {
16277 case BITS4(0,0,1,1):
16278 vassert(op == Iop_Sub32); isRSB = True; break;
16279 case BITS4(1,1,1,0):
16280 vassert(op == Iop_And32); isBIC = True; break;
16281 default:
16282 break;
16284 rNt = newTemp(Ity_I32);
16285 assign(rNt, getIRegA(rN));
16286 ok = mk_shifter_operand(
16287 INSN(25,25), INSN(11,0),
16288 &shop, bitS ? &shco : NULL, dis_buf
16290 if (!ok)
16291 break;
16292 res = newTemp(Ity_I32);
16293 // compute the main result
16294 if (isRSB) {
16295 // reverse-subtract: shifter_operand - Rn
16296 vassert(op == Iop_Sub32);
16297 assign(res, binop(op, mkexpr(shop), mkexpr(rNt)) );
16298 } else if (isBIC) {
16299 // andn: shifter_operand & ~Rn
16300 vassert(op == Iop_And32);
16301 assign(res, binop(op, mkexpr(rNt),
16302 unop(Iop_Not32, mkexpr(shop))) );
16303 } else {
16304 // normal: Rn op shifter_operand
16305 assign(res, binop(op, mkexpr(rNt), mkexpr(shop)) );
16307 // but don't commit it until after we've finished
16308 // all necessary reads from the guest state
16309 if (bitS
16310 && (op == Iop_And32 || op == Iop_Or32 || op == Iop_Xor32)) {
16311 oldV = newTemp(Ity_I32);
16312 assign( oldV, mk_armg_calculate_flag_v() );
16314 // can't safely read guest state after here
16315 // now safe to put the main result
16316 putIRegA( rD, mkexpr(res), condT, Ijk_Boring );
16317 // XXXX!! not safe to read any guest state after
16318 // this point (I think the code below doesn't do that).
16319 if (!bitS)
16320 vassert(shco == IRTemp_INVALID);
16321 /* Update the flags thunk if necessary */
16322 if (bitS) {
16323 vassert(shco != IRTemp_INVALID);
16324 switch (op) {
16325 case Iop_Add32:
16326 setFlags_D1_D2( ARMG_CC_OP_ADD, rNt, shop, condT );
16327 break;
16328 case Iop_Sub32:
16329 if (isRSB) {
16330 setFlags_D1_D2( ARMG_CC_OP_SUB, shop, rNt, condT );
16331 } else {
16332 setFlags_D1_D2( ARMG_CC_OP_SUB, rNt, shop, condT );
16334 break;
16335 case Iop_And32: /* BIC and AND set the flags the same */
16336 case Iop_Or32:
16337 case Iop_Xor32:
16338 // oldV has been read just above
16339 setFlags_D1_D2_ND( ARMG_CC_OP_LOGIC,
16340 res, shco, oldV, condT );
16341 break;
16342 default:
16343 vassert(0);
16346 DIP("%s%s%s r%u, r%u, %s\n",
16347 name, nCC(INSN_COND), bitS ? "s" : "", rD, rN, dis_buf );
16348 goto decode_success;
16351 /* --------- MOV, MVN --------- */
16352 case BITS4(1,1,0,1): /* MOV: Rd = shifter_operand */
16353 case BITS4(1,1,1,1): { /* MVN: Rd = not(shifter_operand) */
16354 Bool isMVN = INSN(24,21) == BITS4(1,1,1,1);
16355 IRTemp jk = Ijk_Boring;
16356 if (rN != 0)
16357 break; /* rN must be zero */
16358 ok = mk_shifter_operand(
16359 INSN(25,25), INSN(11,0),
16360 &shop, bitS ? &shco : NULL, dis_buf
16362 if (!ok)
16363 break;
16364 res = newTemp(Ity_I32);
16365 assign( res, isMVN ? unop(Iop_Not32, mkexpr(shop))
16366 : mkexpr(shop) );
16367 if (bitS) {
16368 vassert(shco != IRTemp_INVALID);
16369 oldV = newTemp(Ity_I32);
16370 assign( oldV, mk_armg_calculate_flag_v() );
16371 } else {
16372 vassert(shco == IRTemp_INVALID);
16374 /* According to the Cortex A8 TRM Sec. 5.2.1, MOV PC, r14 is a
16375 return for purposes of branch prediction. */
16376 if (!isMVN && INSN(11,0) == 14) {
16377 jk = Ijk_Ret;
16379 // can't safely read guest state after here
16380 putIRegA( rD, mkexpr(res), condT, jk );
16381 /* Update the flags thunk if necessary */
16382 if (bitS) {
16383 setFlags_D1_D2_ND( ARMG_CC_OP_LOGIC,
16384 res, shco, oldV, condT );
16386 DIP("%s%s%s r%u, %s\n",
16387 isMVN ? "mvn" : "mov",
16388 nCC(INSN_COND), bitS ? "s" : "", rD, dis_buf );
16389 goto decode_success;
16392 /* --------- CMP --------- */
16393 case BITS4(1,0,1,0): /* CMP: (void) Rn - shifter_operand */
16394 case BITS4(1,0,1,1): { /* CMN: (void) Rn + shifter_operand */
16395 Bool isCMN = INSN(24,21) == BITS4(1,0,1,1);
16396 if (rD != 0)
16397 break; /* rD must be zero */
16398 if (bitS == 0)
16399 break; /* if S (bit 20) is not set, it's not CMP/CMN */
16400 rNt = newTemp(Ity_I32);
16401 assign(rNt, getIRegA(rN));
16402 ok = mk_shifter_operand(
16403 INSN(25,25), INSN(11,0),
16404 &shop, NULL, dis_buf
16406 if (!ok)
16407 break;
16408 // can't safely read guest state after here
16409 /* Update the flags thunk. */
16410 setFlags_D1_D2( isCMN ? ARMG_CC_OP_ADD : ARMG_CC_OP_SUB,
16411 rNt, shop, condT );
16412 DIP("%s%s r%u, %s\n",
16413 isCMN ? "cmn" : "cmp",
16414 nCC(INSN_COND), rN, dis_buf );
16415 goto decode_success;
16418 /* --------- TST --------- */
16419 case BITS4(1,0,0,0): /* TST: (void) Rn & shifter_operand */
16420 case BITS4(1,0,0,1): { /* TEQ: (void) Rn ^ shifter_operand */
16421 Bool isTEQ = INSN(24,21) == BITS4(1,0,0,1);
16422 if (rD != 0)
16423 break; /* rD must be zero */
16424 if (bitS == 0)
16425 break; /* if S (bit 20) is not set, it's not TST/TEQ */
16426 rNt = newTemp(Ity_I32);
16427 assign(rNt, getIRegA(rN));
16428 ok = mk_shifter_operand(
16429 INSN(25,25), INSN(11,0),
16430 &shop, &shco, dis_buf
16432 if (!ok)
16433 break;
16434 /* Update the flags thunk. */
16435 res = newTemp(Ity_I32);
16436 assign( res, binop(isTEQ ? Iop_Xor32 : Iop_And32,
16437 mkexpr(rNt), mkexpr(shop)) );
16438 oldV = newTemp(Ity_I32);
16439 assign( oldV, mk_armg_calculate_flag_v() );
16440 // can't safely read guest state after here
16441 setFlags_D1_D2_ND( ARMG_CC_OP_LOGIC,
16442 res, shco, oldV, condT );
16443 DIP("%s%s r%u, %s\n",
16444 isTEQ ? "teq" : "tst",
16445 nCC(INSN_COND), rN, dis_buf );
16446 goto decode_success;
16449 /* --------- ADC, SBC, RSC --------- */
16450 case BITS4(0,1,0,1): /* ADC: Rd = Rn + shifter_operand + oldC */
16451 name = "adc"; goto rd_eq_rn_op_SO_op_oldC;
16452 case BITS4(0,1,1,0): /* SBC: Rd = Rn - shifter_operand - (oldC ^ 1) */
16453 name = "sbc"; goto rd_eq_rn_op_SO_op_oldC;
16454 case BITS4(0,1,1,1): /* RSC: Rd = shifter_operand - Rn - (oldC ^ 1) */
16455 name = "rsc"; goto rd_eq_rn_op_SO_op_oldC;
16456 rd_eq_rn_op_SO_op_oldC: {
16457 // FIXME: shco isn't used for anything. Get rid of it.
16458 rNt = newTemp(Ity_I32);
16459 assign(rNt, getIRegA(rN));
16460 ok = mk_shifter_operand(
16461 INSN(25,25), INSN(11,0),
16462 &shop, bitS ? &shco : NULL, dis_buf
16464 if (!ok)
16465 break;
16466 oldC = newTemp(Ity_I32);
16467 assign( oldC, mk_armg_calculate_flag_c() );
16468 res = newTemp(Ity_I32);
16469 // compute the main result
16470 switch (INSN(24,21)) {
16471 case BITS4(0,1,0,1): /* ADC */
16472 assign(res,
16473 binop(Iop_Add32,
16474 binop(Iop_Add32, mkexpr(rNt), mkexpr(shop)),
16475 mkexpr(oldC) ));
16476 break;
16477 case BITS4(0,1,1,0): /* SBC */
16478 assign(res,
16479 binop(Iop_Sub32,
16480 binop(Iop_Sub32, mkexpr(rNt), mkexpr(shop)),
16481 binop(Iop_Xor32, mkexpr(oldC), mkU32(1)) ));
16482 break;
16483 case BITS4(0,1,1,1): /* RSC */
16484 assign(res,
16485 binop(Iop_Sub32,
16486 binop(Iop_Sub32, mkexpr(shop), mkexpr(rNt)),
16487 binop(Iop_Xor32, mkexpr(oldC), mkU32(1)) ));
16488 break;
16489 default:
16490 vassert(0);
16492 // but don't commit it until after we've finished
16493 // all necessary reads from the guest state
16494 // now safe to put the main result
16495 putIRegA( rD, mkexpr(res), condT, Ijk_Boring );
16496 // XXXX!! not safe to read any guest state after
16497 // this point (I think the code below doesn't do that).
16498 if (!bitS)
16499 vassert(shco == IRTemp_INVALID);
16500 /* Update the flags thunk if necessary */
16501 if (bitS) {
16502 vassert(shco != IRTemp_INVALID);
16503 switch (INSN(24,21)) {
16504 case BITS4(0,1,0,1): /* ADC */
16505 setFlags_D1_D2_ND( ARMG_CC_OP_ADC,
16506 rNt, shop, oldC, condT );
16507 break;
16508 case BITS4(0,1,1,0): /* SBC */
16509 setFlags_D1_D2_ND( ARMG_CC_OP_SBB,
16510 rNt, shop, oldC, condT );
16511 break;
16512 case BITS4(0,1,1,1): /* RSC */
16513 setFlags_D1_D2_ND( ARMG_CC_OP_SBB,
16514 shop, rNt, oldC, condT );
16515 break;
16516 default:
16517 vassert(0);
16520 DIP("%s%s%s r%u, r%u, %s\n",
16521 name, nCC(INSN_COND), bitS ? "s" : "", rD, rN, dis_buf );
16522 goto decode_success;
16525 default:
16526 vassert(0);
16528 } /* if (0 == (INSN(27,20) & BITS8(1,1,0,0,0,0,0,0)) */
16530 /* --------------------- Load/store (ubyte & word) -------- */
16531 // LDR STR LDRB STRB
16532 /* 31 27 23 19 15 11 6 4 3 # highest bit
16533 28 24 20 16 12
16534 A5-20 1 | 16 cond 0101 UB0L Rn Rd imm12
16535 A5-22 1 | 32 cond 0111 UBOL Rn Rd imm5 sh2 0 Rm
16536 A5-24 2 | 16 cond 0101 UB1L Rn Rd imm12
16537 A5-26 2 | 32 cond 0111 UB1L Rn Rd imm5 sh2 0 Rm
16538 A5-28 3 | 16 cond 0100 UB0L Rn Rd imm12
16539 A5-32 3 | 32 cond 0110 UB0L Rn Rd imm5 sh2 0 Rm
16541 /* case coding:
16542 1 at-ea (access at ea)
16543 2 at-ea-then-upd (access at ea, then Rn = ea)
16544 3 at-Rn-then-upd (access at Rn, then Rn = ea)
16545 ea coding
16546 16 Rn +/- imm12
16547 32 Rn +/- Rm sh2 imm5
16549 /* Quickly skip over all of this for hopefully most instructions */
16550 if ((INSN(27,24) & BITS4(1,1,0,0)) != BITS4(0,1,0,0))
16551 goto after_load_store_ubyte_or_word;
16553 summary = 0;
16555 /**/ if (INSN(27,24) == BITS4(0,1,0,1) && INSN(21,21) == 0) {
16556 summary = 1 | 16;
16558 else if (INSN(27,24) == BITS4(0,1,1,1) && INSN(21,21) == 0
16559 && INSN(4,4) == 0) {
16560 summary = 1 | 32;
16562 else if (INSN(27,24) == BITS4(0,1,0,1) && INSN(21,21) == 1) {
16563 summary = 2 | 16;
16565 else if (INSN(27,24) == BITS4(0,1,1,1) && INSN(21,21) == 1
16566 && INSN(4,4) == 0) {
16567 summary = 2 | 32;
16569 else if (INSN(27,24) == BITS4(0,1,0,0) && INSN(21,21) == 0) {
16570 summary = 3 | 16;
16572 else if (INSN(27,24) == BITS4(0,1,1,0) && INSN(21,21) == 0
16573 && INSN(4,4) == 0) {
16574 summary = 3 | 32;
16576 else goto after_load_store_ubyte_or_word;
16578 { UInt rN = (insn >> 16) & 0xF; /* 19:16 */
16579 UInt rD = (insn >> 12) & 0xF; /* 15:12 */
16580 UInt rM = (insn >> 0) & 0xF; /* 3:0 */
16581 UInt bU = (insn >> 23) & 1; /* 23 */
16582 UInt bB = (insn >> 22) & 1; /* 22 */
16583 UInt bL = (insn >> 20) & 1; /* 20 */
16584 UInt imm12 = (insn >> 0) & 0xFFF; /* 11:0 */
16585 UInt imm5 = (insn >> 7) & 0x1F; /* 11:7 */
16586 UInt sh2 = (insn >> 5) & 3; /* 6:5 */
16588 /* Skip some invalid cases, which would lead to two competing
16589 updates to the same register, or which are otherwise
16590 disallowed by the spec. */
16591 switch (summary) {
16592 case 1 | 16:
16593 break;
16594 case 1 | 32:
16595 if (rM == 15) goto after_load_store_ubyte_or_word;
16596 break;
16597 case 2 | 16: case 3 | 16:
16598 if (rN == 15) goto after_load_store_ubyte_or_word;
16599 if (bL == 1 && rN == rD) goto after_load_store_ubyte_or_word;
16600 break;
16601 case 2 | 32: case 3 | 32:
16602 if (rM == 15) goto after_load_store_ubyte_or_word;
16603 if (rN == 15) goto after_load_store_ubyte_or_word;
16604 if (rN == rM) goto after_load_store_ubyte_or_word;
16605 if (bL == 1 && rN == rD) goto after_load_store_ubyte_or_word;
16606 break;
16607 default:
16608 vassert(0);
16611 /* compute the effective address. Bind it to a tmp since we
16612 may need to use it twice. */
16613 IRExpr* eaE = NULL;
16614 switch (summary & 0xF0) {
16615 case 16:
16616 eaE = mk_EA_reg_plusminus_imm12( rN, bU, imm12, dis_buf );
16617 break;
16618 case 32:
16619 eaE = mk_EA_reg_plusminus_shifted_reg( rN, bU, rM, sh2, imm5,
16620 dis_buf );
16621 break;
16623 vassert(eaE);
16624 IRTemp eaT = newTemp(Ity_I32);
16625 assign(eaT, eaE);
16627 /* get the old Rn value */
16628 IRTemp rnT = newTemp(Ity_I32);
16629 assign(rnT, getIRegA(rN));
16631 /* decide on the transfer address */
16632 IRTemp taT = IRTemp_INVALID;
16633 switch (summary & 0x0F) {
16634 case 1: case 2: taT = eaT; break;
16635 case 3: taT = rnT; break;
16637 vassert(taT != IRTemp_INVALID);
16639 if (bL == 0) {
16640 /* Store. If necessary, update the base register before the
16641 store itself, so that the common idiom of "str rX, [sp,
16642 #-4]!" (store rX at sp-4, then do new sp = sp-4, a.k.a "push
16643 rX") doesn't cause Memcheck to complain that the access is
16644 below the stack pointer. Also, not updating sp before the
16645 store confuses Valgrind's dynamic stack-extending logic. So
16646 do it before the store. Hence we need to snarf the store
16647 data before doing the basereg update. */
16649 /* get hold of the data to be stored */
16650 IRTemp rDt = newTemp(Ity_I32);
16651 assign(rDt, getIRegA(rD));
16653 /* Update Rn if necessary. */
16654 switch (summary & 0x0F) {
16655 case 2: case 3:
16656 putIRegA( rN, mkexpr(eaT), condT, Ijk_Boring );
16657 break;
16660 /* generate the transfer */
16661 if (bB == 0) { // word store
16662 storeGuardedLE( mkexpr(taT), mkexpr(rDt), condT );
16663 } else { // byte store
16664 vassert(bB == 1);
16665 storeGuardedLE( mkexpr(taT), unop(Iop_32to8, mkexpr(rDt)), condT );
16668 } else {
16669 /* Load */
16670 vassert(bL == 1);
16672 /* generate the transfer */
16673 if (bB == 0) { // word load
16674 IRTemp jk = Ijk_Boring;
16675 /* According to the Cortex A8 TRM Sec. 5.2.1, LDR(1) with r13 as the
16676 base register and PC as the destination register is a return for
16677 purposes of branch prediction.
16678 The ARM ARM Sec. C9.10.1 further specifies that it must use a
16679 post-increment by immediate addressing mode to be counted in
16680 event 0x0E (Procedure return).*/
16681 if (rN == 13 && summary == (3 | 16) && bB == 0) {
16682 jk = Ijk_Ret;
16684 IRTemp tD = newTemp(Ity_I32);
16685 loadGuardedLE( tD, ILGop_Ident32,
16686 mkexpr(taT), llGetIReg(rD), condT );
16687 /* "rD == 15 ? condT : IRTemp_INVALID": simply
16688 IRTemp_INVALID would be correct in all cases here, and
16689 for the non-r15 case it generates better code, by
16690 avoiding two tests of the cond (since it is already
16691 tested by loadGuardedLE). However, the logic at the end
16692 of this function, that deals with writes to r15, has an
16693 optimisation which depends on seeing whether or not the
16694 write is conditional. Hence in this particular case we
16695 let it "see" the guard condition. */
16696 putIRegA( rD, mkexpr(tD),
16697 rD == 15 ? condT : IRTemp_INVALID, jk );
16698 } else { // byte load
16699 vassert(bB == 1);
16700 IRTemp tD = newTemp(Ity_I32);
16701 loadGuardedLE( tD, ILGop_8Uto32, mkexpr(taT), llGetIReg(rD), condT );
16702 /* No point in similar 3rd arg complexity here, since we
16703 can't sanely write anything to r15 like this. */
16704 putIRegA( rD, mkexpr(tD), IRTemp_INVALID, Ijk_Boring );
16707 /* Update Rn if necessary. */
16708 switch (summary & 0x0F) {
16709 case 2: case 3:
16710 // should be assured by logic above:
16711 if (bL == 1)
16712 vassert(rD != rN); /* since we just wrote rD */
16713 putIRegA( rN, mkexpr(eaT), condT, Ijk_Boring );
16714 break;
16718 switch (summary & 0x0F) {
16719 case 1: DIP("%sr%s%s r%u, %s\n",
16720 bL == 0 ? "st" : "ld",
16721 bB == 0 ? "" : "b", nCC(INSN_COND), rD, dis_buf);
16722 break;
16723 case 2: DIP("%sr%s%s r%u, %s! (at-EA-then-Rn=EA)\n",
16724 bL == 0 ? "st" : "ld",
16725 bB == 0 ? "" : "b", nCC(INSN_COND), rD, dis_buf);
16726 break;
16727 case 3: DIP("%sr%s%s r%u, %s! (at-Rn-then-Rn=EA)\n",
16728 bL == 0 ? "st" : "ld",
16729 bB == 0 ? "" : "b", nCC(INSN_COND), rD, dis_buf);
16730 break;
16731 default: vassert(0);
16734 /* XXX deal with alignment constraints */
16736 goto decode_success;
16738 /* Complications:
16740 For all loads: if the Amode specifies base register
16741 writeback, and the same register is specified for Rd and Rn,
16742 the results are UNPREDICTABLE.
16744 For all loads and stores: if R15 is written, branch to
16745 that address afterwards.
16747 STRB: straightforward
16748 LDRB: loaded data is zero extended
16749 STR: lowest 2 bits of address are ignored
16750 LDR: if the lowest 2 bits of the address are nonzero
16751 then the loaded value is rotated right by 8 * the lowest 2 bits
16755 after_load_store_ubyte_or_word:
16757 /* --------------------- Load/store (sbyte & hword) -------- */
16758 // LDRH LDRSH STRH LDRSB
16759 /* 31 27 23 19 15 11 7 3 # highest bit
16760 28 24 20 16 12 8 4 0
16761 A5-36 1 | 16 cond 0001 U10L Rn Rd im4h 1SH1 im4l
16762 A5-38 1 | 32 cond 0001 U00L Rn Rd 0000 1SH1 Rm
16763 A5-40 2 | 16 cond 0001 U11L Rn Rd im4h 1SH1 im4l
16764 A5-42 2 | 32 cond 0001 U01L Rn Rd 0000 1SH1 Rm
16765 A5-44 3 | 16 cond 0000 U10L Rn Rd im4h 1SH1 im4l
16766 A5-46 3 | 32 cond 0000 U00L Rn Rd 0000 1SH1 Rm
16768 /* case coding:
16769 1 at-ea (access at ea)
16770 2 at-ea-then-upd (access at ea, then Rn = ea)
16771 3 at-Rn-then-upd (access at Rn, then Rn = ea)
16772 ea coding
16773 16 Rn +/- imm8
16774 32 Rn +/- Rm
16776 /* Quickly skip over all of this for hopefully most instructions */
16777 if ((INSN(27,24) & BITS4(1,1,1,0)) != BITS4(0,0,0,0))
16778 goto after_load_store_sbyte_or_hword;
16780 /* Check the "1SH1" thing. */
16781 if ((INSN(7,4) & BITS4(1,0,0,1)) != BITS4(1,0,0,1))
16782 goto after_load_store_sbyte_or_hword;
16784 summary = 0;
16786 /**/ if (INSN(27,24) == BITS4(0,0,0,1) && INSN(22,21) == BITS2(1,0)) {
16787 summary = 1 | 16;
16789 else if (INSN(27,24) == BITS4(0,0,0,1) && INSN(22,21) == BITS2(0,0)) {
16790 summary = 1 | 32;
16792 else if (INSN(27,24) == BITS4(0,0,0,1) && INSN(22,21) == BITS2(1,1)) {
16793 summary = 2 | 16;
16795 else if (INSN(27,24) == BITS4(0,0,0,1) && INSN(22,21) == BITS2(0,1)) {
16796 summary = 2 | 32;
16798 else if (INSN(27,24) == BITS4(0,0,0,0) && INSN(22,21) == BITS2(1,0)) {
16799 summary = 3 | 16;
16801 else if (INSN(27,24) == BITS4(0,0,0,0) && INSN(22,21) == BITS2(0,0)) {
16802 summary = 3 | 32;
16804 else goto after_load_store_sbyte_or_hword;
16806 { UInt rN = (insn >> 16) & 0xF; /* 19:16 */
16807 UInt rD = (insn >> 12) & 0xF; /* 15:12 */
16808 UInt rM = (insn >> 0) & 0xF; /* 3:0 */
16809 UInt bU = (insn >> 23) & 1; /* 23 U=1 offset+, U=0 offset- */
16810 UInt bL = (insn >> 20) & 1; /* 20 L=1 load, L=0 store */
16811 UInt bH = (insn >> 5) & 1; /* H=1 halfword, H=0 byte */
16812 UInt bS = (insn >> 6) & 1; /* S=1 signed, S=0 unsigned */
16813 UInt imm8 = ((insn >> 4) & 0xF0) | (insn & 0xF); /* 11:8, 3:0 */
16815 /* Skip combinations that are either meaningless or already
16816 handled by main word-or-unsigned-byte load-store
16817 instructions. */
16818 if (bS == 0 && bH == 0) /* "unsigned byte" */
16819 goto after_load_store_sbyte_or_hword;
16820 if (bS == 1 && bL == 0) /* "signed store" */
16821 goto after_load_store_sbyte_or_hword;
16823 /* Require 11:8 == 0 for Rn +/- Rm cases */
16824 if ((summary & 32) != 0 && (imm8 & 0xF0) != 0)
16825 goto after_load_store_sbyte_or_hword;
16827 /* Skip some invalid cases, which would lead to two competing
16828 updates to the same register, or which are otherwise
16829 disallowed by the spec. */
16830 switch (summary) {
16831 case 1 | 16:
16832 break;
16833 case 1 | 32:
16834 if (rM == 15) goto after_load_store_sbyte_or_hword;
16835 break;
16836 case 2 | 16: case 3 | 16:
16837 if (rN == 15) goto after_load_store_sbyte_or_hword;
16838 if (bL == 1 && rN == rD) goto after_load_store_sbyte_or_hword;
16839 break;
16840 case 2 | 32: case 3 | 32:
16841 if (rM == 15) goto after_load_store_sbyte_or_hword;
16842 if (rN == 15) goto after_load_store_sbyte_or_hword;
16843 if (rN == rM) goto after_load_store_sbyte_or_hword;
16844 if (bL == 1 && rN == rD) goto after_load_store_sbyte_or_hword;
16845 break;
16846 default:
16847 vassert(0);
16850 /* If this is a branch, make it unconditional at this point.
16851 Doing conditional branches in-line is too complex (for now).
16852 Note that you'd have to be insane to use any of these loads to
16853 do a branch, since they only load 16 bits at most, but we
16854 handle it just in case. */
16855 if (bL == 1 && rD == 15 && condT != IRTemp_INVALID) {
16856 // go uncond
16857 mk_skip_over_A32_if_cond_is_false( condT );
16858 condT = IRTemp_INVALID;
16859 // now uncond
16862 /* compute the effective address. Bind it to a tmp since we
16863 may need to use it twice. */
16864 IRExpr* eaE = NULL;
16865 switch (summary & 0xF0) {
16866 case 16:
16867 eaE = mk_EA_reg_plusminus_imm8( rN, bU, imm8, dis_buf );
16868 break;
16869 case 32:
16870 eaE = mk_EA_reg_plusminus_reg( rN, bU, rM, dis_buf );
16871 break;
16873 vassert(eaE);
16874 IRTemp eaT = newTemp(Ity_I32);
16875 assign(eaT, eaE);
16877 /* get the old Rn value */
16878 IRTemp rnT = newTemp(Ity_I32);
16879 assign(rnT, getIRegA(rN));
16881 /* decide on the transfer address */
16882 IRTemp taT = IRTemp_INVALID;
16883 switch (summary & 0x0F) {
16884 case 1: case 2: taT = eaT; break;
16885 case 3: taT = rnT; break;
16887 vassert(taT != IRTemp_INVALID);
16889 /* ll previous value of rD, for dealing with conditional loads */
16890 IRTemp llOldRd = newTemp(Ity_I32);
16891 assign(llOldRd, llGetIReg(rD));
16893 /* halfword store H 1 L 0 S 0
16894 uhalf load H 1 L 1 S 0
16895 shalf load H 1 L 1 S 1
16896 sbyte load H 0 L 1 S 1
16898 const HChar* name = NULL;
16899 /* generate the transfer */
16900 /**/ if (bH == 1 && bL == 0 && bS == 0) { // halfword store
16901 storeGuardedLE( mkexpr(taT),
16902 unop(Iop_32to16, getIRegA(rD)), condT );
16903 name = "strh";
16905 else if (bH == 1 && bL == 1 && bS == 0) { // uhalf load
16906 IRTemp newRd = newTemp(Ity_I32);
16907 loadGuardedLE( newRd, ILGop_16Uto32,
16908 mkexpr(taT), mkexpr(llOldRd), condT );
16909 putIRegA( rD, mkexpr(newRd), IRTemp_INVALID, Ijk_Boring );
16910 name = "ldrh";
16912 else if (bH == 1 && bL == 1 && bS == 1) { // shalf load
16913 IRTemp newRd = newTemp(Ity_I32);
16914 loadGuardedLE( newRd, ILGop_16Sto32,
16915 mkexpr(taT), mkexpr(llOldRd), condT );
16916 putIRegA( rD, mkexpr(newRd), IRTemp_INVALID, Ijk_Boring );
16917 name = "ldrsh";
16919 else if (bH == 0 && bL == 1 && bS == 1) { // sbyte load
16920 IRTemp newRd = newTemp(Ity_I32);
16921 loadGuardedLE( newRd, ILGop_8Sto32,
16922 mkexpr(taT), mkexpr(llOldRd), condT );
16923 putIRegA( rD, mkexpr(newRd), IRTemp_INVALID, Ijk_Boring );
16924 name = "ldrsb";
16926 else
16927 vassert(0); // should be assured by logic above
16929 /* Update Rn if necessary. */
16930 switch (summary & 0x0F) {
16931 case 2: case 3:
16932 // should be assured by logic above:
16933 if (bL == 1)
16934 vassert(rD != rN); /* since we just wrote rD */
16935 putIRegA( rN, mkexpr(eaT), condT, Ijk_Boring );
16936 break;
16939 switch (summary & 0x0F) {
16940 case 1: DIP("%s%s r%u, %s\n", name, nCC(INSN_COND), rD, dis_buf);
16941 break;
16942 case 2: DIP("%s%s r%u, %s! (at-EA-then-Rn=EA)\n",
16943 name, nCC(INSN_COND), rD, dis_buf);
16944 break;
16945 case 3: DIP("%s%s r%u, %s! (at-Rn-then-Rn=EA)\n",
16946 name, nCC(INSN_COND), rD, dis_buf);
16947 break;
16948 default: vassert(0);
16951 /* XXX deal with alignment constraints */
16953 goto decode_success;
16955 /* Complications:
16957 For all loads: if the Amode specifies base register
16958 writeback, and the same register is specified for Rd and Rn,
16959 the results are UNPREDICTABLE.
16961 For all loads and stores: if R15 is written, branch to
16962 that address afterwards.
16964 Misaligned halfword stores => Unpredictable
16965 Misaligned halfword loads => Unpredictable
16969 after_load_store_sbyte_or_hword:
16971 /* --------------------- Load/store multiple -------------- */
16972 // LD/STMIA LD/STMIB LD/STMDA LD/STMDB
16973 // Remarkably complex and difficult to get right
16974 // match 27:20 as 100XX0WL
16975 if (BITS8(1,0,0,0,0,0,0,0) == (INSN(27,20) & BITS8(1,1,1,0,0,1,0,0))) {
16976 // A5-50 LD/STMIA cond 1000 10WL Rn RegList
16977 // A5-51 LD/STMIB cond 1001 10WL Rn RegList
16978 // A5-53 LD/STMDA cond 1000 00WL Rn RegList
16979 // A5-53 LD/STMDB cond 1001 00WL Rn RegList
16980 // 28 24 20 16 0
16982 UInt bINC = (insn >> 23) & 1;
16983 UInt bBEFORE = (insn >> 24) & 1;
16985 UInt bL = (insn >> 20) & 1; /* load=1, store=0 */
16986 UInt bW = (insn >> 21) & 1; /* Rn wback=1, no wback=0 */
16987 UInt rN = (insn >> 16) & 0xF;
16988 UInt regList = insn & 0xFFFF;
16989 /* Skip some invalid cases, which would lead to two competing
16990 updates to the same register, or which are otherwise
16991 disallowed by the spec. Note the test above has required
16992 that S == 0, since that looks like a kernel-mode only thing.
16993 Done by forcing the real pattern, viz 100XXSWL to actually be
16994 100XX0WL. */
16995 if (rN == 15) goto after_load_store_multiple;
16996 // reglist can't be empty
16997 if (regList == 0) goto after_load_store_multiple;
16998 // if requested to writeback Rn, and this is a load instruction,
16999 // then Rn can't appear in RegList, since we'd have two competing
17000 // new values for Rn. We do however accept this case for store
17001 // instructions.
17002 if (bW == 1 && bL == 1 && ((1 << rN) & regList) > 0)
17003 goto after_load_store_multiple;
17005 /* Now, we can't do a conditional load or store, since that very
17006 likely will generate an exception. So we have to take a side
17007 exit at this point if the condition is false. */
17008 if (condT != IRTemp_INVALID) {
17009 mk_skip_over_A32_if_cond_is_false( condT );
17010 condT = IRTemp_INVALID;
17013 /* Ok, now we're unconditional. Generate the IR. */
17014 mk_ldm_stm( True/*arm*/, rN, bINC, bBEFORE, bW, bL, regList );
17016 DIP("%sm%c%c%s r%u%s, {0x%04x}\n",
17017 bL == 1 ? "ld" : "st", bINC ? 'i' : 'd', bBEFORE ? 'b' : 'a',
17018 nCC(INSN_COND),
17019 rN, bW ? "!" : "", regList);
17021 goto decode_success;
17024 after_load_store_multiple:
17026 /* --------------------- Control flow --------------------- */
17027 // B, BL (Branch, or Branch-and-Link, to immediate offset)
17029 if (BITS8(1,0,1,0,0,0,0,0) == (INSN(27,20) & BITS8(1,1,1,0,0,0,0,0))) {
17030 UInt link = (insn >> 24) & 1;
17031 UInt uimm24 = insn & ((1<<24)-1); uimm24 <<= 8;
17032 Int simm24 = (Int)uimm24; simm24 >>= 8;
17033 UInt dst = guest_R15_curr_instr_notENC + 8 + (((UInt)simm24) << 2);
17034 IRJumpKind jk = link ? Ijk_Call : Ijk_Boring;
17035 if (link) {
17036 putIRegA(14, mkU32(guest_R15_curr_instr_notENC + 4),
17037 condT, Ijk_Boring);
17039 if (condT == IRTemp_INVALID) {
17040 /* unconditional transfer to 'dst'. See if we can simply
17041 continue tracing at the destination. */
17042 if (resteerOkFn( callback_opaque, dst )) {
17043 /* yes */
17044 dres.whatNext = Dis_ResteerU;
17045 dres.continueAt = dst;
17046 } else {
17047 /* no; terminate the SB at this point. */
17048 llPutIReg(15, mkU32(dst));
17049 dres.jk_StopHere = jk;
17050 dres.whatNext = Dis_StopHere;
17052 DIP("b%s 0x%x\n", link ? "l" : "", dst);
17053 } else {
17054 /* conditional transfer to 'dst' */
17055 const HChar* comment = "";
17057 /* First see if we can do some speculative chasing into one
17058 arm or the other. Be conservative and only chase if
17059 !link, that is, this is a normal conditional branch to a
17060 known destination. */
17061 if (!link
17062 && resteerCisOk
17063 && vex_control.guest_chase_cond
17064 && dst < guest_R15_curr_instr_notENC
17065 && resteerOkFn( callback_opaque, dst) ) {
17066 /* Speculation: assume this backward branch is taken. So
17067 we need to emit a side-exit to the insn following this
17068 one, on the negation of the condition, and continue at
17069 the branch target address (dst). */
17070 stmt( IRStmt_Exit( unop(Iop_Not1,
17071 unop(Iop_32to1, mkexpr(condT))),
17072 Ijk_Boring,
17073 IRConst_U32(guest_R15_curr_instr_notENC+4),
17074 OFFB_R15T ));
17075 dres.whatNext = Dis_ResteerC;
17076 dres.continueAt = (Addr32)dst;
17077 comment = "(assumed taken)";
17079 else
17080 if (!link
17081 && resteerCisOk
17082 && vex_control.guest_chase_cond
17083 && dst >= guest_R15_curr_instr_notENC
17084 && resteerOkFn( callback_opaque,
17085 guest_R15_curr_instr_notENC+4) ) {
17086 /* Speculation: assume this forward branch is not taken.
17087 So we need to emit a side-exit to dst (the dest) and
17088 continue disassembling at the insn immediately
17089 following this one. */
17090 stmt( IRStmt_Exit( unop(Iop_32to1, mkexpr(condT)),
17091 Ijk_Boring,
17092 IRConst_U32(dst),
17093 OFFB_R15T ));
17094 dres.whatNext = Dis_ResteerC;
17095 dres.continueAt = guest_R15_curr_instr_notENC+4;
17096 comment = "(assumed not taken)";
17098 else {
17099 /* Conservative default translation - end the block at
17100 this point. */
17101 stmt( IRStmt_Exit( unop(Iop_32to1, mkexpr(condT)),
17102 jk, IRConst_U32(dst), OFFB_R15T ));
17103 llPutIReg(15, mkU32(guest_R15_curr_instr_notENC + 4));
17104 dres.jk_StopHere = Ijk_Boring;
17105 dres.whatNext = Dis_StopHere;
17107 DIP("b%s%s 0x%x %s\n", link ? "l" : "", nCC(INSN_COND),
17108 dst, comment);
17110 goto decode_success;
17113 // B, BL (Branch, or Branch-and-Link, to a register)
17114 // NB: interworking branch
17115 if (INSN(27,20) == BITS8(0,0,0,1,0,0,1,0)
17116 && INSN(19,12) == BITS8(1,1,1,1,1,1,1,1)
17117 && (INSN(11,4) == BITS8(1,1,1,1,0,0,1,1)
17118 || INSN(11,4) == BITS8(1,1,1,1,0,0,0,1))) {
17119 IRTemp dst = newTemp(Ity_I32);
17120 UInt link = (INSN(11,4) >> 1) & 1;
17121 UInt rM = INSN(3,0);
17122 // we don't decode the case (link && rM == 15), as that's
17123 // Unpredictable.
17124 if (!(link && rM == 15)) {
17125 if (condT != IRTemp_INVALID) {
17126 mk_skip_over_A32_if_cond_is_false( condT );
17128 // rM contains an interworking address exactly as we require
17129 // (with continuation CPSR.T in bit 0), so we can use it
17130 // as-is, with no masking.
17131 assign( dst, getIRegA(rM) );
17132 if (link) {
17133 putIRegA( 14, mkU32(guest_R15_curr_instr_notENC + 4),
17134 IRTemp_INVALID/*because AL*/, Ijk_Boring );
17136 llPutIReg(15, mkexpr(dst));
17137 dres.jk_StopHere = link ? Ijk_Call
17138 : (rM == 14 ? Ijk_Ret : Ijk_Boring);
17139 dres.whatNext = Dis_StopHere;
17140 if (condT == IRTemp_INVALID) {
17141 DIP("b%sx r%u\n", link ? "l" : "", rM);
17142 } else {
17143 DIP("b%sx%s r%u\n", link ? "l" : "", nCC(INSN_COND), rM);
17145 goto decode_success;
17147 /* else: (link && rM == 15): just fall through */
17150 /* --- NB: ARM interworking branches are in NV space, hence
17151 are handled elsewhere by decode_NV_instruction_ARMv7_and_below.
17155 /* --------------------- Clz --------------------- */
17156 // CLZ
17157 if (INSN(27,20) == BITS8(0,0,0,1,0,1,1,0)
17158 && INSN(19,16) == BITS4(1,1,1,1)
17159 && INSN(11,4) == BITS8(1,1,1,1,0,0,0,1)) {
17160 UInt rD = INSN(15,12);
17161 UInt rM = INSN(3,0);
17162 IRTemp arg = newTemp(Ity_I32);
17163 IRTemp res = newTemp(Ity_I32);
17164 assign(arg, getIRegA(rM));
17165 assign(res, IRExpr_ITE(
17166 binop(Iop_CmpEQ32, mkexpr(arg), mkU32(0)),
17167 mkU32(32),
17168 unop(Iop_Clz32, mkexpr(arg))
17170 putIRegA(rD, mkexpr(res), condT, Ijk_Boring);
17171 DIP("clz%s r%u, r%u\n", nCC(INSN_COND), rD, rM);
17172 goto decode_success;
17175 /* --------------------- Mul etc --------------------- */
17176 // MUL
17177 if (BITS8(0,0,0,0,0,0,0,0) == (INSN(27,20) & BITS8(1,1,1,1,1,1,1,0))
17178 && INSN(15,12) == BITS4(0,0,0,0)
17179 && INSN(7,4) == BITS4(1,0,0,1)) {
17180 UInt bitS = (insn >> 20) & 1; /* 20:20 */
17181 UInt rD = INSN(19,16);
17182 UInt rS = INSN(11,8);
17183 UInt rM = INSN(3,0);
17184 if (rD == 15 || rM == 15 || rS == 15) {
17185 /* Unpredictable; don't decode; fall through */
17186 } else {
17187 IRTemp argL = newTemp(Ity_I32);
17188 IRTemp argR = newTemp(Ity_I32);
17189 IRTemp res = newTemp(Ity_I32);
17190 IRTemp oldC = IRTemp_INVALID;
17191 IRTemp oldV = IRTemp_INVALID;
17192 assign( argL, getIRegA(rM));
17193 assign( argR, getIRegA(rS));
17194 assign( res, binop(Iop_Mul32, mkexpr(argL), mkexpr(argR)) );
17195 if (bitS) {
17196 oldC = newTemp(Ity_I32);
17197 assign(oldC, mk_armg_calculate_flag_c());
17198 oldV = newTemp(Ity_I32);
17199 assign(oldV, mk_armg_calculate_flag_v());
17201 // now update guest state
17202 putIRegA( rD, mkexpr(res), condT, Ijk_Boring );
17203 if (bitS) {
17204 IRTemp pair = newTemp(Ity_I32);
17205 assign( pair, binop(Iop_Or32,
17206 binop(Iop_Shl32, mkexpr(oldC), mkU8(1)),
17207 mkexpr(oldV)) );
17208 setFlags_D1_ND( ARMG_CC_OP_MUL, res, pair, condT );
17210 DIP("mul%c%s r%u, r%u, r%u\n",
17211 bitS ? 's' : ' ', nCC(INSN_COND), rD, rM, rS);
17212 goto decode_success;
17214 /* fall through */
17217 /* --------------------- Integer Divides --------------------- */
17218 // SDIV
17219 if (BITS8(0,1,1,1,0,0,0,1) == INSN(27,20)
17220 && INSN(15,12) == BITS4(1,1,1,1)
17221 && INSN(7,4) == BITS4(0,0,0,1)) {
17222 UInt rD = INSN(19,16);
17223 UInt rM = INSN(11,8);
17224 UInt rN = INSN(3,0);
17225 if (rD == 15 || rM == 15 || rN == 15) {
17226 /* Unpredictable; don't decode; fall through */
17227 } else {
17228 IRTemp res = newTemp(Ity_I32);
17229 IRTemp argL = newTemp(Ity_I32);
17230 IRTemp argR = newTemp(Ity_I32);
17231 assign(argL, getIRegA(rN));
17232 assign(argR, getIRegA(rM));
17233 assign(res, binop(Iop_DivS32, mkexpr(argL), mkexpr(argR)));
17234 putIRegA(rD, mkexpr(res), condT, Ijk_Boring);
17235 DIP("sdiv r%u, r%u, r%u\n", rD, rN, rM);
17236 goto decode_success;
17240 // UDIV
17241 if (BITS8(0,1,1,1,0,0,1,1) == INSN(27,20)
17242 && INSN(15,12) == BITS4(1,1,1,1)
17243 && INSN(7,4) == BITS4(0,0,0,1)) {
17244 UInt rD = INSN(19,16);
17245 UInt rM = INSN(11,8);
17246 UInt rN = INSN(3,0);
17247 if (rD == 15 || rM == 15 || rN == 15) {
17248 /* Unpredictable; don't decode; fall through */
17249 } else {
17250 IRTemp res = newTemp(Ity_I32);
17251 IRTemp argL = newTemp(Ity_I32);
17252 IRTemp argR = newTemp(Ity_I32);
17253 assign(argL, getIRegA(rN));
17254 assign(argR, getIRegA(rM));
17255 assign(res, binop(Iop_DivU32, mkexpr(argL), mkexpr(argR)));
17256 putIRegA(rD, mkexpr(res), condT, Ijk_Boring);
17257 DIP("udiv r%u, r%u, r%u\n", rD, rN, rM);
17258 goto decode_success;
17262 // MLA, MLS
17263 if (BITS8(0,0,0,0,0,0,1,0) == (INSN(27,20) & BITS8(1,1,1,1,1,0,1,0))
17264 && INSN(7,4) == BITS4(1,0,0,1)) {
17265 UInt bitS = (insn >> 20) & 1; /* 20:20 */
17266 UInt isMLS = (insn >> 22) & 1; /* 22:22 */
17267 UInt rD = INSN(19,16);
17268 UInt rN = INSN(15,12);
17269 UInt rS = INSN(11,8);
17270 UInt rM = INSN(3,0);
17271 if (bitS == 1 && isMLS == 1) {
17272 /* This isn't allowed (MLS that sets flags). don't decode;
17273 fall through */
17275 else
17276 if (rD == 15 || rM == 15 || rS == 15 || rN == 15) {
17277 /* Unpredictable; don't decode; fall through */
17278 } else {
17279 IRTemp argL = newTemp(Ity_I32);
17280 IRTemp argR = newTemp(Ity_I32);
17281 IRTemp argP = newTemp(Ity_I32);
17282 IRTemp res = newTemp(Ity_I32);
17283 IRTemp oldC = IRTemp_INVALID;
17284 IRTemp oldV = IRTemp_INVALID;
17285 assign( argL, getIRegA(rM));
17286 assign( argR, getIRegA(rS));
17287 assign( argP, getIRegA(rN));
17288 assign( res, binop(isMLS ? Iop_Sub32 : Iop_Add32,
17289 mkexpr(argP),
17290 binop(Iop_Mul32, mkexpr(argL), mkexpr(argR)) ));
17291 if (bitS) {
17292 vassert(!isMLS); // guaranteed above
17293 oldC = newTemp(Ity_I32);
17294 assign(oldC, mk_armg_calculate_flag_c());
17295 oldV = newTemp(Ity_I32);
17296 assign(oldV, mk_armg_calculate_flag_v());
17298 // now update guest state
17299 putIRegA( rD, mkexpr(res), condT, Ijk_Boring );
17300 if (bitS) {
17301 IRTemp pair = newTemp(Ity_I32);
17302 assign( pair, binop(Iop_Or32,
17303 binop(Iop_Shl32, mkexpr(oldC), mkU8(1)),
17304 mkexpr(oldV)) );
17305 setFlags_D1_ND( ARMG_CC_OP_MUL, res, pair, condT );
17307 DIP("ml%c%c%s r%u, r%u, r%u, r%u\n",
17308 isMLS ? 's' : 'a', bitS ? 's' : ' ',
17309 nCC(INSN_COND), rD, rM, rS, rN);
17310 goto decode_success;
17312 /* fall through */
17315 // SMULL, UMULL
17316 if (BITS8(0,0,0,0,1,0,0,0) == (INSN(27,20) & BITS8(1,1,1,1,1,0,1,0))
17317 && INSN(7,4) == BITS4(1,0,0,1)) {
17318 UInt bitS = (insn >> 20) & 1; /* 20:20 */
17319 UInt rDhi = INSN(19,16);
17320 UInt rDlo = INSN(15,12);
17321 UInt rS = INSN(11,8);
17322 UInt rM = INSN(3,0);
17323 UInt isS = (INSN(27,20) >> 2) & 1; /* 22:22 */
17324 if (rDhi == 15 || rDlo == 15 || rM == 15 || rS == 15 || rDhi == rDlo) {
17325 /* Unpredictable; don't decode; fall through */
17326 } else {
17327 IRTemp argL = newTemp(Ity_I32);
17328 IRTemp argR = newTemp(Ity_I32);
17329 IRTemp res = newTemp(Ity_I64);
17330 IRTemp resHi = newTemp(Ity_I32);
17331 IRTemp resLo = newTemp(Ity_I32);
17332 IRTemp oldC = IRTemp_INVALID;
17333 IRTemp oldV = IRTemp_INVALID;
17334 IROp mulOp = isS ? Iop_MullS32 : Iop_MullU32;
17335 assign( argL, getIRegA(rM));
17336 assign( argR, getIRegA(rS));
17337 assign( res, binop(mulOp, mkexpr(argL), mkexpr(argR)) );
17338 assign( resHi, unop(Iop_64HIto32, mkexpr(res)) );
17339 assign( resLo, unop(Iop_64to32, mkexpr(res)) );
17340 if (bitS) {
17341 oldC = newTemp(Ity_I32);
17342 assign(oldC, mk_armg_calculate_flag_c());
17343 oldV = newTemp(Ity_I32);
17344 assign(oldV, mk_armg_calculate_flag_v());
17346 // now update guest state
17347 putIRegA( rDhi, mkexpr(resHi), condT, Ijk_Boring );
17348 putIRegA( rDlo, mkexpr(resLo), condT, Ijk_Boring );
17349 if (bitS) {
17350 IRTemp pair = newTemp(Ity_I32);
17351 assign( pair, binop(Iop_Or32,
17352 binop(Iop_Shl32, mkexpr(oldC), mkU8(1)),
17353 mkexpr(oldV)) );
17354 setFlags_D1_D2_ND( ARMG_CC_OP_MULL, resLo, resHi, pair, condT );
17356 DIP("%cmull%c%s r%u, r%u, r%u, r%u\n",
17357 isS ? 's' : 'u', bitS ? 's' : ' ',
17358 nCC(INSN_COND), rDlo, rDhi, rM, rS);
17359 goto decode_success;
17361 /* fall through */
17364 // SMLAL, UMLAL
17365 if (BITS8(0,0,0,0,1,0,1,0) == (INSN(27,20) & BITS8(1,1,1,1,1,0,1,0))
17366 && INSN(7,4) == BITS4(1,0,0,1)) {
17367 UInt bitS = (insn >> 20) & 1; /* 20:20 */
17368 UInt rDhi = INSN(19,16);
17369 UInt rDlo = INSN(15,12);
17370 UInt rS = INSN(11,8);
17371 UInt rM = INSN(3,0);
17372 UInt isS = (INSN(27,20) >> 2) & 1; /* 22:22 */
17373 if (rDhi == 15 || rDlo == 15 || rM == 15 || rS == 15 || rDhi == rDlo) {
17374 /* Unpredictable; don't decode; fall through */
17375 } else {
17376 IRTemp argL = newTemp(Ity_I32);
17377 IRTemp argR = newTemp(Ity_I32);
17378 IRTemp old = newTemp(Ity_I64);
17379 IRTemp res = newTemp(Ity_I64);
17380 IRTemp resHi = newTemp(Ity_I32);
17381 IRTemp resLo = newTemp(Ity_I32);
17382 IRTemp oldC = IRTemp_INVALID;
17383 IRTemp oldV = IRTemp_INVALID;
17384 IROp mulOp = isS ? Iop_MullS32 : Iop_MullU32;
17385 assign( argL, getIRegA(rM));
17386 assign( argR, getIRegA(rS));
17387 assign( old, binop(Iop_32HLto64, getIRegA(rDhi), getIRegA(rDlo)) );
17388 assign( res, binop(Iop_Add64,
17389 mkexpr(old),
17390 binop(mulOp, mkexpr(argL), mkexpr(argR))) );
17391 assign( resHi, unop(Iop_64HIto32, mkexpr(res)) );
17392 assign( resLo, unop(Iop_64to32, mkexpr(res)) );
17393 if (bitS) {
17394 oldC = newTemp(Ity_I32);
17395 assign(oldC, mk_armg_calculate_flag_c());
17396 oldV = newTemp(Ity_I32);
17397 assign(oldV, mk_armg_calculate_flag_v());
17399 // now update guest state
17400 putIRegA( rDhi, mkexpr(resHi), condT, Ijk_Boring );
17401 putIRegA( rDlo, mkexpr(resLo), condT, Ijk_Boring );
17402 if (bitS) {
17403 IRTemp pair = newTemp(Ity_I32);
17404 assign( pair, binop(Iop_Or32,
17405 binop(Iop_Shl32, mkexpr(oldC), mkU8(1)),
17406 mkexpr(oldV)) );
17407 setFlags_D1_D2_ND( ARMG_CC_OP_MULL, resLo, resHi, pair, condT );
17409 DIP("%cmlal%c%s r%u, r%u, r%u, r%u\n",
17410 isS ? 's' : 'u', bitS ? 's' : ' ', nCC(INSN_COND),
17411 rDlo, rDhi, rM, rS);
17412 goto decode_success;
17414 /* fall through */
17417 // UMAAL
17418 if (BITS8(0,0,0,0,0,1,0,0) == INSN(27,20) && INSN(7,4) == BITS4(1,0,0,1)) {
17419 UInt rDhi = INSN(19,16);
17420 UInt rDlo = INSN(15,12);
17421 UInt rM = INSN(11,8);
17422 UInt rN = INSN(3,0);
17423 if (rDlo == 15 || rDhi == 15 || rN == 15 || rM == 15 || rDhi == rDlo) {
17424 /* Unpredictable; don't decode; fall through */
17425 } else {
17426 IRTemp argN = newTemp(Ity_I32);
17427 IRTemp argM = newTemp(Ity_I32);
17428 IRTemp argDhi = newTemp(Ity_I32);
17429 IRTemp argDlo = newTemp(Ity_I32);
17430 IRTemp res = newTemp(Ity_I64);
17431 IRTemp resHi = newTemp(Ity_I32);
17432 IRTemp resLo = newTemp(Ity_I32);
17433 assign( argN, getIRegA(rN) );
17434 assign( argM, getIRegA(rM) );
17435 assign( argDhi, getIRegA(rDhi) );
17436 assign( argDlo, getIRegA(rDlo) );
17437 assign( res,
17438 binop(Iop_Add64,
17439 binop(Iop_Add64,
17440 binop(Iop_MullU32, mkexpr(argN), mkexpr(argM)),
17441 unop(Iop_32Uto64, mkexpr(argDhi))),
17442 unop(Iop_32Uto64, mkexpr(argDlo))) );
17443 assign( resHi, unop(Iop_64HIto32, mkexpr(res)) );
17444 assign( resLo, unop(Iop_64to32, mkexpr(res)) );
17445 // now update guest state
17446 putIRegA( rDhi, mkexpr(resHi), condT, Ijk_Boring );
17447 putIRegA( rDlo, mkexpr(resLo), condT, Ijk_Boring );
17448 DIP("umaal %s r%u, r%u, r%u, r%u\n",
17449 nCC(INSN_COND), rDlo, rDhi, rN, rM);
17450 goto decode_success;
17452 /* fall through */
17455 /* --------------------- Msr etc --------------------- */
17457 // MSR apsr, #imm
17458 if (INSN(27,20) == BITS8(0,0,1,1,0,0,1,0)
17459 && INSN(17,12) == BITS6(0,0,1,1,1,1)) {
17460 UInt write_ge = INSN(18,18);
17461 UInt write_nzcvq = INSN(19,19);
17462 if (write_nzcvq || write_ge) {
17463 UInt imm = (INSN(11,0) >> 0) & 0xFF;
17464 UInt rot = 2 * ((INSN(11,0) >> 8) & 0xF);
17465 IRTemp immT = newTemp(Ity_I32);
17466 vassert(rot <= 30);
17467 imm = ROR32(imm, rot);
17468 assign(immT, mkU32(imm));
17469 desynthesise_APSR( write_nzcvq, write_ge, immT, condT );
17470 DIP("msr%s cpsr%s%sf, #0x%08x\n", nCC(INSN_COND),
17471 write_nzcvq ? "f" : "", write_ge ? "g" : "", imm);
17472 goto decode_success;
17474 /* fall through */
17477 // MSR apsr, reg
17478 if (INSN(27,20) == BITS8(0,0,0,1,0,0,1,0)
17479 && INSN(17,12) == BITS6(0,0,1,1,1,1)
17480 && INSN(11,4) == BITS8(0,0,0,0,0,0,0,0)) {
17481 UInt rN = INSN(3,0);
17482 UInt write_ge = INSN(18,18);
17483 UInt write_nzcvq = INSN(19,19);
17484 if (rN != 15 && (write_nzcvq || write_ge)) {
17485 IRTemp rNt = newTemp(Ity_I32);
17486 assign(rNt, getIRegA(rN));
17487 desynthesise_APSR( write_nzcvq, write_ge, rNt, condT );
17488 DIP("msr%s cpsr_%s%s, r%u\n", nCC(INSN_COND),
17489 write_nzcvq ? "f" : "", write_ge ? "g" : "", rN);
17490 goto decode_success;
17492 /* fall through */
17495 // MRS rD, cpsr
17496 if ((insn & 0x0FFF0FFF) == 0x010F0000) {
17497 UInt rD = INSN(15,12);
17498 if (rD != 15) {
17499 IRTemp apsr = synthesise_APSR();
17500 putIRegA( rD, mkexpr(apsr), condT, Ijk_Boring );
17501 DIP("mrs%s r%u, cpsr\n", nCC(INSN_COND), rD);
17502 goto decode_success;
17504 /* fall through */
17507 /* --------------------- Svc --------------------- */
17508 if (BITS8(1,1,1,1,0,0,0,0) == (INSN(27,20) & BITS8(1,1,1,1,0,0,0,0))) {
17509 UInt imm24 = (insn >> 0) & 0xFFFFFF;
17510 if (imm24 == 0) {
17511 /* A syscall. We can't do this conditionally, hence: */
17512 if (condT != IRTemp_INVALID) {
17513 mk_skip_over_A32_if_cond_is_false( condT );
17515 // AL after here
17516 llPutIReg(15, mkU32( guest_R15_curr_instr_notENC + 4 ));
17517 dres.jk_StopHere = Ijk_Sys_syscall;
17518 dres.whatNext = Dis_StopHere;
17519 DIP("svc%s #0x%08x\n", nCC(INSN_COND), imm24);
17520 goto decode_success;
17522 /* fall through */
17525 /* ------------------------ swp ------------------------ */
17527 // SWP, SWPB
17528 if (BITS8(0,0,0,1,0,0,0,0) == (INSN(27,20) & BITS8(1,1,1,1,1,0,1,1))
17529 && BITS4(0,0,0,0) == INSN(11,8)
17530 && BITS4(1,0,0,1) == INSN(7,4)) {
17531 UInt rN = INSN(19,16);
17532 UInt rD = INSN(15,12);
17533 UInt rM = INSN(3,0);
17534 IRTemp tRn = newTemp(Ity_I32);
17535 IRTemp tNew = newTemp(Ity_I32);
17536 IRTemp tOld = IRTemp_INVALID;
17537 IRTemp tSC1 = newTemp(Ity_I1);
17538 UInt isB = (insn >> 22) & 1;
17540 if (rD == 15 || rN == 15 || rM == 15 || rN == rM || rN == rD) {
17541 /* undecodable; fall through */
17542 } else {
17543 /* make unconditional */
17544 if (condT != IRTemp_INVALID) {
17545 mk_skip_over_A32_if_cond_is_false( condT );
17546 condT = IRTemp_INVALID;
17548 /* Ok, now we're unconditional. Generate a LL-SC loop. */
17549 assign(tRn, getIRegA(rN));
17550 assign(tNew, getIRegA(rM));
17551 if (isB) {
17552 /* swpb */
17553 tOld = newTemp(Ity_I8);
17554 stmt( IRStmt_LLSC(Iend_LE, tOld, mkexpr(tRn),
17555 NULL/*=>isLL*/) );
17556 stmt( IRStmt_LLSC(Iend_LE, tSC1, mkexpr(tRn),
17557 unop(Iop_32to8, mkexpr(tNew))) );
17558 } else {
17559 /* swp */
17560 tOld = newTemp(Ity_I32);
17561 stmt( IRStmt_LLSC(Iend_LE, tOld, mkexpr(tRn),
17562 NULL/*=>isLL*/) );
17563 stmt( IRStmt_LLSC(Iend_LE, tSC1, mkexpr(tRn),
17564 mkexpr(tNew)) );
17566 stmt( IRStmt_Exit(unop(Iop_Not1, mkexpr(tSC1)),
17567 /*Ijk_NoRedir*/Ijk_Boring,
17568 IRConst_U32(guest_R15_curr_instr_notENC),
17569 OFFB_R15T ));
17570 putIRegA(rD, isB ? unop(Iop_8Uto32, mkexpr(tOld)) : mkexpr(tOld),
17571 IRTemp_INVALID, Ijk_Boring);
17572 DIP("swp%s%s r%u, r%u, [r%u]\n",
17573 isB ? "b" : "", nCC(INSN_COND), rD, rM, rN);
17574 goto decode_success;
17576 /* fall through */
17579 /* ----------------------------------------------------------- */
17580 /* -- ARMv6 instructions -- */
17581 /* ----------------------------------------------------------- */
17583 /* ------------------- {ldr,str}ex{,b,h,d} ------------------- */
17585 // LDREXD, LDREX, LDREXH, LDREXB
17586 if (0x01900F9F == (insn & 0x0F900FFF)) {
17587 UInt rT = INSN(15,12);
17588 UInt rN = INSN(19,16);
17589 IRType ty = Ity_INVALID;
17590 IROp widen = Iop_INVALID;
17591 const HChar* nm = NULL;
17592 Bool valid = True;
17593 switch (INSN(22,21)) {
17594 case 0: nm = ""; ty = Ity_I32; break;
17595 case 1: nm = "d"; ty = Ity_I64; break;
17596 case 2: nm = "b"; ty = Ity_I8; widen = Iop_8Uto32; break;
17597 case 3: nm = "h"; ty = Ity_I16; widen = Iop_16Uto32; break;
17598 default: vassert(0);
17600 if (ty == Ity_I32 || ty == Ity_I16 || ty == Ity_I8) {
17601 if (rT == 15 || rN == 15)
17602 valid = False;
17603 } else {
17604 vassert(ty == Ity_I64);
17605 if ((rT & 1) == 1 || rT == 14 || rN == 15)
17606 valid = False;
17608 if (valid) {
17609 IRTemp res;
17610 /* make unconditional */
17611 if (condT != IRTemp_INVALID) {
17612 mk_skip_over_A32_if_cond_is_false( condT );
17613 condT = IRTemp_INVALID;
17615 /* Ok, now we're unconditional. Do the load. */
17616 res = newTemp(ty);
17617 // FIXME: assumes little-endian guest
17618 stmt( IRStmt_LLSC(Iend_LE, res, getIRegA(rN),
17619 NULL/*this is a load*/) );
17620 if (ty == Ity_I64) {
17621 // FIXME: assumes little-endian guest
17622 putIRegA(rT+0, unop(Iop_64to32, mkexpr(res)),
17623 IRTemp_INVALID, Ijk_Boring);
17624 putIRegA(rT+1, unop(Iop_64HIto32, mkexpr(res)),
17625 IRTemp_INVALID, Ijk_Boring);
17626 DIP("ldrex%s%s r%u, r%u, [r%u]\n",
17627 nm, nCC(INSN_COND), rT+0, rT+1, rN);
17628 } else {
17629 putIRegA(rT, widen == Iop_INVALID
17630 ? mkexpr(res) : unop(widen, mkexpr(res)),
17631 IRTemp_INVALID, Ijk_Boring);
17632 DIP("ldrex%s%s r%u, [r%u]\n", nm, nCC(INSN_COND), rT, rN);
17634 goto decode_success;
17636 /* undecodable; fall through */
17639 // STREXD, STREX, STREXH, STREXB
17640 if (0x01800F90 == (insn & 0x0F900FF0)) {
17641 UInt rT = INSN(3,0);
17642 UInt rN = INSN(19,16);
17643 UInt rD = INSN(15,12);
17644 IRType ty = Ity_INVALID;
17645 IROp narrow = Iop_INVALID;
17646 const HChar* nm = NULL;
17647 Bool valid = True;
17648 switch (INSN(22,21)) {
17649 case 0: nm = ""; ty = Ity_I32; break;
17650 case 1: nm = "d"; ty = Ity_I64; break;
17651 case 2: nm = "b"; ty = Ity_I8; narrow = Iop_32to8; break;
17652 case 3: nm = "h"; ty = Ity_I16; narrow = Iop_32to16; break;
17653 default: vassert(0);
17655 if (ty == Ity_I32 || ty == Ity_I16 || ty == Ity_I8) {
17656 if (rD == 15 || rN == 15 || rT == 15
17657 || rD == rN || rD == rT)
17658 valid = False;
17659 } else {
17660 vassert(ty == Ity_I64);
17661 if (rD == 15 || (rT & 1) == 1 || rT == 14 || rN == 15
17662 || rD == rN || rD == rT || rD == rT+1)
17663 valid = False;
17665 if (valid) {
17666 IRTemp resSC1, resSC32, data;
17667 /* make unconditional */
17668 if (condT != IRTemp_INVALID) {
17669 mk_skip_over_A32_if_cond_is_false( condT );
17670 condT = IRTemp_INVALID;
17672 /* Ok, now we're unconditional. Do the store. */
17673 data = newTemp(ty);
17674 assign(data,
17675 ty == Ity_I64
17676 // FIXME: assumes little-endian guest
17677 ? binop(Iop_32HLto64, getIRegA(rT+1), getIRegA(rT+0))
17678 : narrow == Iop_INVALID
17679 ? getIRegA(rT)
17680 : unop(narrow, getIRegA(rT)));
17681 resSC1 = newTemp(Ity_I1);
17682 // FIXME: assumes little-endian guest
17683 stmt( IRStmt_LLSC(Iend_LE, resSC1, getIRegA(rN), mkexpr(data)) );
17685 /* Set rD to 1 on failure, 0 on success. Currently we have
17686 resSC1 == 0 on failure, 1 on success. */
17687 resSC32 = newTemp(Ity_I32);
17688 assign(resSC32,
17689 unop(Iop_1Uto32, unop(Iop_Not1, mkexpr(resSC1))));
17691 putIRegA(rD, mkexpr(resSC32),
17692 IRTemp_INVALID, Ijk_Boring);
17693 if (ty == Ity_I64) {
17694 DIP("strex%s%s r%u, r%u, r%u, [r%u]\n",
17695 nm, nCC(INSN_COND), rD, rT, rT+1, rN);
17696 } else {
17697 DIP("strex%s%s r%u, r%u, [r%u]\n",
17698 nm, nCC(INSN_COND), rD, rT, rN);
17700 goto decode_success;
17702 /* fall through */
17705 /* --------------------- movw, movt --------------------- */
17706 if (0x03000000 == (insn & 0x0FF00000)
17707 || 0x03400000 == (insn & 0x0FF00000)) /* pray for CSE */ {
17708 UInt rD = INSN(15,12);
17709 UInt imm16 = (insn & 0xFFF) | ((insn >> 4) & 0x0000F000);
17710 UInt isT = (insn >> 22) & 1;
17711 if (rD == 15) {
17712 /* forget it */
17713 } else {
17714 if (isT) {
17715 putIRegA(rD,
17716 binop(Iop_Or32,
17717 binop(Iop_And32, getIRegA(rD), mkU32(0xFFFF)),
17718 mkU32(imm16 << 16)),
17719 condT, Ijk_Boring);
17720 DIP("movt%s r%u, #0x%04x\n", nCC(INSN_COND), rD, imm16);
17721 goto decode_success;
17722 } else {
17723 putIRegA(rD, mkU32(imm16), condT, Ijk_Boring);
17724 DIP("movw%s r%u, #0x%04x\n", nCC(INSN_COND), rD, imm16);
17725 goto decode_success;
17728 /* fall through */
17731 /* ----------- uxtb, sxtb, uxth, sxth, uxtb16, sxtb16 ----------- */
17732 /* FIXME: this is an exact duplicate of the Thumb version. They
17733 should be commoned up. */
17734 if (BITS8(0,1,1,0,1, 0,0,0) == (INSN(27,20) & BITS8(1,1,1,1,1,0,0,0))
17735 && BITS4(1,1,1,1) == INSN(19,16)
17736 && BITS4(0,1,1,1) == INSN(7,4)
17737 && BITS4(0,0, 0,0) == (INSN(11,8) & BITS4(0,0,1,1))) {
17738 UInt subopc = INSN(27,20) & BITS8(0,0,0,0,0, 1,1,1);
17739 if (subopc != BITS4(0,0,0,1) && subopc != BITS4(0,1,0,1)) {
17740 Int rot = (INSN(11,8) >> 2) & 3;
17741 UInt rM = INSN(3,0);
17742 UInt rD = INSN(15,12);
17743 IRTemp srcT = newTemp(Ity_I32);
17744 IRTemp rotT = newTemp(Ity_I32);
17745 IRTemp dstT = newTemp(Ity_I32);
17746 const HChar* nm = "???";
17747 assign(srcT, getIRegA(rM));
17748 assign(rotT, genROR32(srcT, 8 * rot)); /* 0, 8, 16 or 24 only */
17749 switch (subopc) {
17750 case BITS4(0,1,1,0): // UXTB
17751 assign(dstT, unop(Iop_8Uto32, unop(Iop_32to8, mkexpr(rotT))));
17752 nm = "uxtb";
17753 break;
17754 case BITS4(0,0,1,0): // SXTB
17755 assign(dstT, unop(Iop_8Sto32, unop(Iop_32to8, mkexpr(rotT))));
17756 nm = "sxtb";
17757 break;
17758 case BITS4(0,1,1,1): // UXTH
17759 assign(dstT, unop(Iop_16Uto32, unop(Iop_32to16, mkexpr(rotT))));
17760 nm = "uxth";
17761 break;
17762 case BITS4(0,0,1,1): // SXTH
17763 assign(dstT, unop(Iop_16Sto32, unop(Iop_32to16, mkexpr(rotT))));
17764 nm = "sxth";
17765 break;
17766 case BITS4(0,1,0,0): // UXTB16
17767 assign(dstT, binop(Iop_And32, mkexpr(rotT), mkU32(0x00FF00FF)));
17768 nm = "uxtb16";
17769 break;
17770 case BITS4(0,0,0,0): { // SXTB16
17771 IRTemp lo32 = newTemp(Ity_I32);
17772 IRTemp hi32 = newTemp(Ity_I32);
17773 assign(lo32, binop(Iop_And32, mkexpr(rotT), mkU32(0xFF)));
17774 assign(hi32, binop(Iop_Shr32, mkexpr(rotT), mkU8(16)));
17775 assign(
17776 dstT,
17777 binop(Iop_Or32,
17778 binop(Iop_And32,
17779 unop(Iop_8Sto32,
17780 unop(Iop_32to8, mkexpr(lo32))),
17781 mkU32(0xFFFF)),
17782 binop(Iop_Shl32,
17783 unop(Iop_8Sto32,
17784 unop(Iop_32to8, mkexpr(hi32))),
17785 mkU8(16))
17787 nm = "sxtb16";
17788 break;
17790 default:
17791 vassert(0); // guarded by "if" above
17793 putIRegA(rD, mkexpr(dstT), condT, Ijk_Boring);
17794 DIP("%s%s r%u, r%u, ROR #%d\n", nm, nCC(INSN_COND), rD, rM, rot);
17795 goto decode_success;
17797 /* fall through */
17800 /* ------------------- bfi, bfc ------------------- */
17801 if (BITS8(0,1,1,1,1,1,0, 0) == (INSN(27,20) & BITS8(1,1,1,1,1,1,1,0))
17802 && BITS4(0, 0,0,1) == (INSN(7,4) & BITS4(0,1,1,1))) {
17803 UInt rD = INSN(15,12);
17804 UInt rN = INSN(3,0);
17805 UInt msb = (insn >> 16) & 0x1F; /* 20:16 */
17806 UInt lsb = (insn >> 7) & 0x1F; /* 11:7 */
17807 if (rD == 15 || msb < lsb) {
17808 /* undecodable; fall through */
17809 } else {
17810 IRTemp src = newTemp(Ity_I32);
17811 IRTemp olddst = newTemp(Ity_I32);
17812 IRTemp newdst = newTemp(Ity_I32);
17813 UInt mask = ((UInt)1) << (msb - lsb);
17814 mask = (mask - 1) + mask;
17815 vassert(mask != 0); // guaranteed by "msb < lsb" check above
17816 mask <<= lsb;
17818 assign(src, rN == 15 ? mkU32(0) : getIRegA(rN));
17819 assign(olddst, getIRegA(rD));
17820 assign(newdst,
17821 binop(Iop_Or32,
17822 binop(Iop_And32,
17823 binop(Iop_Shl32, mkexpr(src), mkU8(lsb)),
17824 mkU32(mask)),
17825 binop(Iop_And32,
17826 mkexpr(olddst),
17827 mkU32(~mask)))
17830 putIRegA(rD, mkexpr(newdst), condT, Ijk_Boring);
17832 if (rN == 15) {
17833 DIP("bfc%s r%u, #%u, #%u\n",
17834 nCC(INSN_COND), rD, lsb, msb-lsb+1);
17835 } else {
17836 DIP("bfi%s r%u, r%u, #%u, #%u\n",
17837 nCC(INSN_COND), rD, rN, lsb, msb-lsb+1);
17839 goto decode_success;
17841 /* fall through */
17844 /* ------------------- {u,s}bfx ------------------- */
17845 if (BITS8(0,1,1,1,1,0,1,0) == (INSN(27,20) & BITS8(1,1,1,1,1,0,1,0))
17846 && BITS4(0,1,0,1) == (INSN(7,4) & BITS4(0,1,1,1))) {
17847 UInt rD = INSN(15,12);
17848 UInt rN = INSN(3,0);
17849 UInt wm1 = (insn >> 16) & 0x1F; /* 20:16 */
17850 UInt lsb = (insn >> 7) & 0x1F; /* 11:7 */
17851 UInt msb = lsb + wm1;
17852 UInt isU = (insn >> 22) & 1; /* 22:22 */
17853 if (rD == 15 || rN == 15 || msb >= 32) {
17854 /* undecodable; fall through */
17855 } else {
17856 IRTemp src = newTemp(Ity_I32);
17857 IRTemp tmp = newTemp(Ity_I32);
17858 IRTemp res = newTemp(Ity_I32);
17859 UInt mask = ((1 << wm1) - 1) + (1 << wm1);
17860 vassert(msb >= 0 && msb <= 31);
17861 vassert(mask != 0); // guaranteed by msb being in 0 .. 31 inclusive
17863 assign(src, getIRegA(rN));
17864 assign(tmp, binop(Iop_And32,
17865 binop(Iop_Shr32, mkexpr(src), mkU8(lsb)),
17866 mkU32(mask)));
17867 assign(res, binop(isU ? Iop_Shr32 : Iop_Sar32,
17868 binop(Iop_Shl32, mkexpr(tmp), mkU8(31-wm1)),
17869 mkU8(31-wm1)));
17871 putIRegA(rD, mkexpr(res), condT, Ijk_Boring);
17873 DIP("%s%s r%u, r%u, #%u, #%u\n",
17874 isU ? "ubfx" : "sbfx",
17875 nCC(INSN_COND), rD, rN, lsb, wm1 + 1);
17876 goto decode_success;
17878 /* fall through */
17881 /* --------------------- Load/store doubleword ------------- */
17882 // LDRD STRD
17883 /* 31 27 23 19 15 11 7 3 # highest bit
17884 28 24 20 16 12 8 4 0
17885 A5-36 1 | 16 cond 0001 U100 Rn Rd im4h 11S1 im4l
17886 A5-38 1 | 32 cond 0001 U000 Rn Rd 0000 11S1 Rm
17887 A5-40 2 | 16 cond 0001 U110 Rn Rd im4h 11S1 im4l
17888 A5-42 2 | 32 cond 0001 U010 Rn Rd 0000 11S1 Rm
17889 A5-44 3 | 16 cond 0000 U100 Rn Rd im4h 11S1 im4l
17890 A5-46 3 | 32 cond 0000 U000 Rn Rd 0000 11S1 Rm
17892 /* case coding:
17893 1 at-ea (access at ea)
17894 2 at-ea-then-upd (access at ea, then Rn = ea)
17895 3 at-Rn-then-upd (access at Rn, then Rn = ea)
17896 ea coding
17897 16 Rn +/- imm8
17898 32 Rn +/- Rm
17900 /* Quickly skip over all of this for hopefully most instructions */
17901 if ((INSN(27,24) & BITS4(1,1,1,0)) != BITS4(0,0,0,0))
17902 goto after_load_store_doubleword;
17904 /* Check the "11S1" thing. */
17905 if ((INSN(7,4) & BITS4(1,1,0,1)) != BITS4(1,1,0,1))
17906 goto after_load_store_doubleword;
17908 summary = 0;
17910 /**/ if (INSN(27,24) == BITS4(0,0,0,1) && INSN(22,20) == BITS3(1,0,0)) {
17911 summary = 1 | 16;
17913 else if (INSN(27,24) == BITS4(0,0,0,1) && INSN(22,20) == BITS3(0,0,0)) {
17914 summary = 1 | 32;
17916 else if (INSN(27,24) == BITS4(0,0,0,1) && INSN(22,20) == BITS3(1,1,0)) {
17917 summary = 2 | 16;
17919 else if (INSN(27,24) == BITS4(0,0,0,1) && INSN(22,20) == BITS3(0,1,0)) {
17920 summary = 2 | 32;
17922 else if (INSN(27,24) == BITS4(0,0,0,0) && INSN(22,20) == BITS3(1,0,0)) {
17923 summary = 3 | 16;
17925 else if (INSN(27,24) == BITS4(0,0,0,0) && INSN(22,20) == BITS3(0,0,0)) {
17926 summary = 3 | 32;
17928 else goto after_load_store_doubleword;
17930 { UInt rN = (insn >> 16) & 0xF; /* 19:16 */
17931 UInt rD = (insn >> 12) & 0xF; /* 15:12 */
17932 UInt rM = (insn >> 0) & 0xF; /* 3:0 */
17933 UInt bU = (insn >> 23) & 1; /* 23 U=1 offset+, U=0 offset- */
17934 UInt bS = (insn >> 5) & 1; /* S=1 store, S=0 load */
17935 UInt imm8 = ((insn >> 4) & 0xF0) | (insn & 0xF); /* 11:8, 3:0 */
17937 /* Require rD to be an even numbered register */
17938 if ((rD & 1) != 0)
17939 goto after_load_store_doubleword;
17941 /* Require 11:8 == 0 for Rn +/- Rm cases */
17942 if ((summary & 32) != 0 && (imm8 & 0xF0) != 0)
17943 goto after_load_store_doubleword;
17945 /* Skip some invalid cases, which would lead to two competing
17946 updates to the same register, or which are otherwise
17947 disallowed by the spec. */
17948 switch (summary) {
17949 case 1 | 16:
17950 break;
17951 case 1 | 32:
17952 if (rM == 15) goto after_load_store_doubleword;
17953 break;
17954 case 2 | 16: case 3 | 16:
17955 if (rN == 15) goto after_load_store_doubleword;
17956 if (bS == 0 && (rN == rD || rN == rD+1))
17957 goto after_load_store_doubleword;
17958 break;
17959 case 2 | 32: case 3 | 32:
17960 if (rM == 15) goto after_load_store_doubleword;
17961 if (rN == 15) goto after_load_store_doubleword;
17962 if (rN == rM) goto after_load_store_doubleword;
17963 if (bS == 0 && (rN == rD || rN == rD+1))
17964 goto after_load_store_doubleword;
17965 break;
17966 default:
17967 vassert(0);
17970 /* If this is a branch, make it unconditional at this point.
17971 Doing conditional branches in-line is too complex (for
17972 now). */
17973 vassert((rD & 1) == 0); /* from tests above */
17974 if (bS == 0 && rD+1 == 15 && condT != IRTemp_INVALID) {
17975 // go uncond
17976 mk_skip_over_A32_if_cond_is_false( condT );
17977 condT = IRTemp_INVALID;
17978 // now uncond
17981 /* compute the effective address. Bind it to a tmp since we
17982 may need to use it twice. */
17983 IRExpr* eaE = NULL;
17984 switch (summary & 0xF0) {
17985 case 16:
17986 eaE = mk_EA_reg_plusminus_imm8( rN, bU, imm8, dis_buf );
17987 break;
17988 case 32:
17989 eaE = mk_EA_reg_plusminus_reg( rN, bU, rM, dis_buf );
17990 break;
17992 vassert(eaE);
17993 IRTemp eaT = newTemp(Ity_I32);
17994 assign(eaT, eaE);
17996 /* get the old Rn value */
17997 IRTemp rnT = newTemp(Ity_I32);
17998 assign(rnT, getIRegA(rN));
18000 /* decide on the transfer address */
18001 IRTemp taT = IRTemp_INVALID;
18002 switch (summary & 0x0F) {
18003 case 1: case 2: taT = eaT; break;
18004 case 3: taT = rnT; break;
18006 vassert(taT != IRTemp_INVALID);
18008 /* XXX deal with alignment constraints */
18009 /* XXX: but the A8 doesn't seem to trap for misaligned loads, so,
18010 ignore alignment issues for the time being. */
18012 /* For almost all cases, we do the writeback after the transfers.
18013 However, that leaves the stack "uncovered" in cases like:
18014 strd rD, [sp, #-8]
18015 strd rD, [sp, #-16]
18016 In which case, do the writeback to SP now, instead of later.
18017 This is bad in that it makes the insn non-restartable if the
18018 accesses fault, but at least keeps Memcheck happy. */
18019 Bool writeback_already_done = False;
18020 if (bS == 1 /*store*/ && summary == (2 | 16)
18021 && rN == 13 && rN != rD && rN != rD+1
18022 && bU == 0/*minus*/
18023 && (imm8 == 8 || imm8 == 16)) {
18024 putIRegA( rN, mkexpr(eaT), condT, Ijk_Boring );
18025 writeback_already_done = True;
18028 /* doubleword store S 1
18029 doubleword load S 0
18031 const HChar* name = NULL;
18032 /* generate the transfers */
18033 if (bS == 1) { // doubleword store
18034 storeGuardedLE( binop(Iop_Add32, mkexpr(taT), mkU32(0)),
18035 getIRegA(rD+0), condT );
18036 storeGuardedLE( binop(Iop_Add32, mkexpr(taT), mkU32(4)),
18037 getIRegA(rD+1), condT );
18038 name = "strd";
18039 } else { // doubleword load
18040 IRTemp oldRd0 = newTemp(Ity_I32);
18041 IRTemp oldRd1 = newTemp(Ity_I32);
18042 assign(oldRd0, llGetIReg(rD+0));
18043 assign(oldRd1, llGetIReg(rD+1));
18044 IRTemp newRd0 = newTemp(Ity_I32);
18045 IRTemp newRd1 = newTemp(Ity_I32);
18046 loadGuardedLE( newRd0, ILGop_Ident32,
18047 binop(Iop_Add32, mkexpr(taT), mkU32(0)),
18048 mkexpr(oldRd0), condT );
18049 putIRegA( rD+0, mkexpr(newRd0), IRTemp_INVALID, Ijk_Boring );
18050 loadGuardedLE( newRd1, ILGop_Ident32,
18051 binop(Iop_Add32, mkexpr(taT), mkU32(4)),
18052 mkexpr(oldRd1), condT );
18053 putIRegA( rD+1, mkexpr(newRd1), IRTemp_INVALID, Ijk_Boring );
18054 name = "ldrd";
18057 /* Update Rn if necessary. */
18058 switch (summary & 0x0F) {
18059 case 2: case 3:
18060 // should be assured by logic above:
18061 vassert(rN != 15); /* from checks above */
18062 if (bS == 0) {
18063 vassert(rD+0 != rN); /* since we just wrote rD+0 */
18064 vassert(rD+1 != rN); /* since we just wrote rD+1 */
18066 if (!writeback_already_done)
18067 putIRegA( rN, mkexpr(eaT), condT, Ijk_Boring );
18068 break;
18071 switch (summary & 0x0F) {
18072 case 1: DIP("%s%s r%u, %s\n", name, nCC(INSN_COND), rD, dis_buf);
18073 break;
18074 case 2: DIP("%s%s r%u, %s! (at-EA-then-Rn=EA)\n",
18075 name, nCC(INSN_COND), rD, dis_buf);
18076 break;
18077 case 3: DIP("%s%s r%u, %s! (at-Rn-then-Rn=EA)\n",
18078 name, nCC(INSN_COND), rD, dis_buf);
18079 break;
18080 default: vassert(0);
18083 goto decode_success;
18086 after_load_store_doubleword:
18088 /* ------------------- {s,u}xtab ------------- */
18089 if (BITS8(0,1,1,0,1,0,1,0) == (INSN(27,20) & BITS8(1,1,1,1,1,0,1,1))
18090 && BITS4(0,0,0,0) == (INSN(11,8) & BITS4(0,0,1,1))
18091 && BITS4(0,1,1,1) == INSN(7,4)) {
18092 UInt rN = INSN(19,16);
18093 UInt rD = INSN(15,12);
18094 UInt rM = INSN(3,0);
18095 UInt rot = (insn >> 10) & 3;
18096 UInt isU = INSN(22,22);
18097 if (rN == 15/*it's {S,U}XTB*/ || rD == 15 || rM == 15) {
18098 /* undecodable; fall through */
18099 } else {
18100 IRTemp srcL = newTemp(Ity_I32);
18101 IRTemp srcR = newTemp(Ity_I32);
18102 IRTemp res = newTemp(Ity_I32);
18103 assign(srcR, getIRegA(rM));
18104 assign(srcL, getIRegA(rN));
18105 assign(res, binop(Iop_Add32,
18106 mkexpr(srcL),
18107 unop(isU ? Iop_8Uto32 : Iop_8Sto32,
18108 unop(Iop_32to8,
18109 genROR32(srcR, 8 * rot)))));
18110 putIRegA(rD, mkexpr(res), condT, Ijk_Boring);
18111 DIP("%cxtab%s r%u, r%u, r%u, ror #%u\n",
18112 isU ? 'u' : 's', nCC(INSN_COND), rD, rN, rM, rot);
18113 goto decode_success;
18115 /* fall through */
18118 /* ------------------- {s,u}xtah ------------- */
18119 if (BITS8(0,1,1,0,1,0,1,1) == (INSN(27,20) & BITS8(1,1,1,1,1,0,1,1))
18120 && BITS4(0,0,0,0) == (INSN(11,8) & BITS4(0,0,1,1))
18121 && BITS4(0,1,1,1) == INSN(7,4)) {
18122 UInt rN = INSN(19,16);
18123 UInt rD = INSN(15,12);
18124 UInt rM = INSN(3,0);
18125 UInt rot = (insn >> 10) & 3;
18126 UInt isU = INSN(22,22);
18127 if (rN == 15/*it's {S,U}XTH*/ || rD == 15 || rM == 15) {
18128 /* undecodable; fall through */
18129 } else {
18130 IRTemp srcL = newTemp(Ity_I32);
18131 IRTemp srcR = newTemp(Ity_I32);
18132 IRTemp res = newTemp(Ity_I32);
18133 assign(srcR, getIRegA(rM));
18134 assign(srcL, getIRegA(rN));
18135 assign(res, binop(Iop_Add32,
18136 mkexpr(srcL),
18137 unop(isU ? Iop_16Uto32 : Iop_16Sto32,
18138 unop(Iop_32to16,
18139 genROR32(srcR, 8 * rot)))));
18140 putIRegA(rD, mkexpr(res), condT, Ijk_Boring);
18142 DIP("%cxtah%s r%u, r%u, r%u, ror #%u\n",
18143 isU ? 'u' : 's', nCC(INSN_COND), rD, rN, rM, rot);
18144 goto decode_success;
18146 /* fall through */
18149 /* ------------------- rev16, rev ------------------ */
18150 if (INSN(27,16) == 0x6BF
18151 && (INSN(11,4) == 0xFB/*rev16*/ || INSN(11,4) == 0xF3/*rev*/)) {
18152 Bool isREV = INSN(11,4) == 0xF3;
18153 UInt rM = INSN(3,0);
18154 UInt rD = INSN(15,12);
18155 if (rM != 15 && rD != 15) {
18156 IRTemp rMt = newTemp(Ity_I32);
18157 assign(rMt, getIRegA(rM));
18158 IRTemp res = isREV ? gen_REV(rMt) : gen_REV16(rMt);
18159 putIRegA(rD, mkexpr(res), condT, Ijk_Boring);
18160 DIP("rev%s%s r%u, r%u\n", isREV ? "" : "16",
18161 nCC(INSN_COND), rD, rM);
18162 goto decode_success;
18166 /* ------------------- revsh ----------------------- */
18167 if (INSN(27,16) == 0x6FF && INSN(11,4) == 0xFB) {
18168 UInt rM = INSN(3,0);
18169 UInt rD = INSN(15,12);
18170 if (rM != 15 && rD != 15) {
18171 IRTemp irt_rM = newTemp(Ity_I32);
18172 IRTemp irt_hi = newTemp(Ity_I32);
18173 IRTemp irt_low = newTemp(Ity_I32);
18174 IRTemp irt_res = newTemp(Ity_I32);
18175 assign(irt_rM, getIRegA(rM));
18176 assign(irt_hi,
18177 binop(Iop_Sar32,
18178 binop(Iop_Shl32, mkexpr(irt_rM), mkU8(24)),
18179 mkU8(16)
18182 assign(irt_low,
18183 binop(Iop_And32,
18184 binop(Iop_Shr32, mkexpr(irt_rM), mkU8(8)),
18185 mkU32(0xFF)
18188 assign(irt_res,
18189 binop(Iop_Or32, mkexpr(irt_hi), mkexpr(irt_low))
18191 putIRegA(rD, mkexpr(irt_res), condT, Ijk_Boring);
18192 DIP("revsh%s r%u, r%u\n", nCC(INSN_COND), rD, rM);
18193 goto decode_success;
18197 /* ------------------- rbit ------------------ */
18198 if (INSN(27,16) == 0x6FF && INSN(11,4) == 0xF3) {
18199 UInt rD = INSN(15,12);
18200 UInt rM = INSN(3,0);
18201 if (rD != 15 && rM != 15) {
18202 IRTemp arg = newTemp(Ity_I32);
18203 assign(arg, getIRegA(rM));
18204 IRTemp res = gen_BITREV(arg);
18205 putIRegA(rD, mkexpr(res), condT, Ijk_Boring);
18206 DIP("rbit r%u, r%u\n", rD, rM);
18207 goto decode_success;
18211 /* ------------------- smmul ------------------ */
18212 if (INSN(27,20) == BITS8(0,1,1,1,0,1,0,1)
18213 && INSN(15,12) == BITS4(1,1,1,1)
18214 && (INSN(7,4) & BITS4(1,1,0,1)) == BITS4(0,0,0,1)) {
18215 UInt bitR = INSN(5,5);
18216 UInt rD = INSN(19,16);
18217 UInt rM = INSN(11,8);
18218 UInt rN = INSN(3,0);
18219 if (rD != 15 && rM != 15 && rN != 15) {
18220 IRExpr* res
18221 = unop(Iop_64HIto32,
18222 binop(Iop_Add64,
18223 binop(Iop_MullS32, getIRegA(rN), getIRegA(rM)),
18224 mkU64(bitR ? 0x80000000ULL : 0ULL)));
18225 putIRegA(rD, res, condT, Ijk_Boring);
18226 DIP("smmul%s%s r%u, r%u, r%u\n",
18227 nCC(INSN_COND), bitR ? "r" : "", rD, rN, rM);
18228 goto decode_success;
18232 /* ------------------- smmla ------------------ */
18233 if (INSN(27,20) == BITS8(0,1,1,1,0,1,0,1)
18234 && INSN(15,12) != BITS4(1,1,1,1)
18235 && (INSN(7,4) & BITS4(1,1,0,1)) == BITS4(0,0,0,1)) {
18236 UInt bitR = INSN(5,5);
18237 UInt rD = INSN(19,16);
18238 UInt rA = INSN(15,12);
18239 UInt rM = INSN(11,8);
18240 UInt rN = INSN(3,0);
18241 if (rD != 15 && rM != 15 && rN != 15) {
18242 IRExpr* res
18243 = unop(Iop_64HIto32,
18244 binop(Iop_Add64,
18245 binop(Iop_Add64,
18246 binop(Iop_32HLto64, getIRegA(rA), mkU32(0)),
18247 binop(Iop_MullS32, getIRegA(rN), getIRegA(rM))),
18248 mkU64(bitR ? 0x80000000ULL : 0ULL)));
18249 putIRegA(rD, res, condT, Ijk_Boring);
18250 DIP("smmla%s%s r%u, r%u, r%u, r%u\n",
18251 nCC(INSN_COND), bitR ? "r" : "", rD, rN, rM, rA);
18252 goto decode_success;
18256 /* -------------- (A1) LDRT reg+/-#imm12 -------------- */
18257 /* Load Register Unprivileged:
18258 ldrt<c> Rt, [Rn] {, #+/-imm12}
18260 if ( (INSN(27,20) & BITS8(1,1,1,1,0,1,1,1)) == BITS8(0,1,0,0,0,0,1,1) ) {
18261 UInt rT = INSN(15,12);
18262 UInt rN = INSN(19,16);
18263 UInt imm12 = INSN(11,0);
18264 UInt bU = INSN(23,23);
18265 Bool valid = True;
18266 if (rT == 15 || rN == 15 || rN == rT) valid = False;
18267 if (valid) {
18268 IRTemp newRt = newTemp(Ity_I32);
18269 loadGuardedLE( newRt,
18270 ILGop_Ident32, getIRegA(rN), getIRegA(rT), condT );
18271 putIRegA(rT, mkexpr(newRt), IRTemp_INVALID, Ijk_Boring);
18272 IRExpr* erN = binop(bU ? Iop_Add32 : Iop_Sub32,
18273 getIRegA(rN), mkU32(imm12));
18274 putIRegA(rN, erN, condT, Ijk_Boring);
18275 DIP("ldrt%s r%u, [r%u], #%c%u\n",
18276 nCC(INSN_COND), rT, rN, bU ? '+' : '-', imm12);
18277 goto decode_success;
18281 /* -------------- (A2) LDRT reg+/-reg with shift -------------- */
18282 /* Load Register Unprivileged:
18283 ldrt<c> Rt, [Rn], +/-Rm{, shift}
18285 if ( (INSN(27,20) & BITS8(1,1,1,1,0,1,1,1)) == BITS8(0,1,1,0,0,0,1,1)
18286 && INSN(4,4) == 0 ) {
18287 UInt rT = INSN(15,12);
18288 UInt rN = INSN(19,16);
18289 UInt rM = INSN(3,0);
18290 UInt imm5 = INSN(11,7);
18291 UInt bU = INSN(23,23);
18292 UInt type = INSN(6,5);
18293 Bool valid = True;
18294 if (rT == 15 || rN == 15 || rN == rT || rM == 15
18295 /* || (ArchVersion() < 6 && rM == rN) */)
18296 valid = False;
18297 if (valid) {
18298 IRTemp newRt = newTemp(Ity_I32);
18299 loadGuardedLE( newRt,
18300 ILGop_Ident32, getIRegA(rN), getIRegA(rT), condT );
18301 putIRegA(rT, mkexpr(newRt), IRTemp_INVALID, Ijk_Boring);
18302 // dis_buf generated is slightly bogus, in fact.
18303 IRExpr* erN = mk_EA_reg_plusminus_shifted_reg(rN, bU, rM,
18304 type, imm5, dis_buf);
18305 putIRegA(rN, erN, condT, Ijk_Boring);
18306 DIP("ldrt%s r%u, %s\n", nCC(INSN_COND), rT, dis_buf);
18307 goto decode_success;
18311 /* -------------- (A1) LDRBT reg+/-#imm12 -------------- */
18312 /* Load Register Byte Unprivileged:
18313 ldrbt<c> Rt, [Rn], #+/-imm12
18315 if ( (INSN(27,20) & BITS8(1,1,1,1,0,1,1,1)) == BITS8(0,1,0,0,0,1,1,1) ) {
18316 UInt rT = INSN(15,12);
18317 UInt rN = INSN(19,16);
18318 UInt imm12 = INSN(11,0);
18319 UInt bU = INSN(23,23);
18320 Bool valid = True;
18321 if (rT == 15 || rN == 15 || rN == rT) valid = False;
18322 if (valid) {
18323 IRTemp newRt = newTemp(Ity_I32);
18324 loadGuardedLE( newRt,
18325 ILGop_8Uto32, getIRegA(rN), getIRegA(rT), condT );
18326 putIRegA(rT, mkexpr(newRt), IRTemp_INVALID, Ijk_Boring);
18327 IRExpr* erN = binop(bU ? Iop_Add32 : Iop_Sub32,
18328 getIRegA(rN), mkU32(imm12));
18329 putIRegA(rN, erN, condT, Ijk_Boring);
18330 DIP("ldrbt%s r%u, [r%u], #%c%u\n",
18331 nCC(INSN_COND), rT, rN, bU ? '+' : '-', imm12);
18332 goto decode_success;
18336 /* -------------- (A2) LDRBT reg+/-reg with shift -------------- */
18337 /* Load Register Byte Unprivileged:
18338 ldrbt<c> Rt, [Rn], +/-Rm{, shift}
18340 if ( (INSN(27,20) & BITS8(1,1,1,1,0,1,1,1)) == BITS8(0,1,1,0,0,1,1,1)
18341 && INSN(4,4) == 0 ) {
18342 UInt rT = INSN(15,12);
18343 UInt rN = INSN(19,16);
18344 UInt rM = INSN(3,0);
18345 UInt imm5 = INSN(11,7);
18346 UInt bU = INSN(23,23);
18347 UInt type = INSN(6,5);
18348 Bool valid = True;
18349 if (rT == 15 || rN == 15 || rN == rT || rM == 15
18350 /* || (ArchVersion() < 6 && rM == rN) */)
18351 valid = False;
18352 if (valid) {
18353 IRTemp newRt = newTemp(Ity_I32);
18354 loadGuardedLE( newRt,
18355 ILGop_8Uto32, getIRegA(rN), getIRegA(rT), condT );
18356 putIRegA(rT, mkexpr(newRt), IRTemp_INVALID, Ijk_Boring);
18357 // dis_buf generated is slightly bogus, in fact.
18358 IRExpr* erN = mk_EA_reg_plusminus_shifted_reg(rN, bU, rM,
18359 type, imm5, dis_buf);
18360 putIRegA(rN, erN, condT, Ijk_Boring);
18361 DIP("ldrbt%s r%u, %s\n", nCC(INSN_COND), rT, dis_buf);
18362 goto decode_success;
18366 /* -------------- (A1) LDRHT reg+#imm8 -------------- */
18367 /* Load Register Halfword Unprivileged:
18368 ldrht<c> Rt, [Rn] {, #+/-imm8}
18370 if ( (INSN(27,20) & BITS8(1,1,1,1,0,1,1,1)) == BITS8(0,0,0,0,0,1,1,1)
18371 && INSN(7,4) == BITS4(1,0,1,1) ) {
18372 UInt rT = INSN(15,12);
18373 UInt rN = INSN(19,16);
18374 UInt bU = INSN(23,23);
18375 UInt imm4H = INSN(11,8);
18376 UInt imm4L = INSN(3,0);
18377 UInt imm8 = (imm4H << 4) | imm4L;
18378 Bool valid = True;
18379 if (rT == 15 || rN == 15 || rN == rT)
18380 valid = False;
18381 if (valid) {
18382 IRTemp newRt = newTemp(Ity_I32);
18383 loadGuardedLE( newRt,
18384 ILGop_16Uto32, getIRegA(rN), getIRegA(rT), condT );
18385 putIRegA(rT, mkexpr(newRt), IRTemp_INVALID, Ijk_Boring);
18386 IRExpr* erN = binop(bU ? Iop_Add32 : Iop_Sub32,
18387 getIRegA(rN), mkU32(imm8));
18388 putIRegA(rN, erN, condT, Ijk_Boring);
18389 DIP("ldrht%s r%u, [r%u], #%c%u\n",
18390 nCC(INSN_COND), rT, rN, bU ? '+' : '-', imm8);
18391 goto decode_success;
18395 /* -------------- (A2) LDRHT reg+/-reg -------------- */
18396 /* Load Register Halfword Unprivileged:
18397 ldrht<c> Rt, [Rn], +/-Rm
18399 if ( (INSN(27,20) & BITS8(1,1,1,1,0,1,1,1)) == BITS8(0,0,0,0,0,0,1,1)
18400 && INSN(11,4) == BITS8(0,0,0,0,1,0,1,1) ) {
18401 UInt rT = INSN(15,12);
18402 UInt rN = INSN(19,16);
18403 UInt rM = INSN(3,0);
18404 UInt bU = INSN(23,23);
18405 Bool valid = True;
18406 if (rT == 15 || rN == 15 || rN == rT || rM == 15)
18407 valid = False;
18408 if (valid) {
18409 IRTemp newRt = newTemp(Ity_I32);
18410 loadGuardedLE( newRt,
18411 ILGop_16Uto32, getIRegA(rN), getIRegA(rT), condT );
18412 putIRegA(rT, mkexpr(newRt), IRTemp_INVALID, Ijk_Boring);
18413 IRExpr* erN = binop(bU ? Iop_Add32 : Iop_Sub32,
18414 getIRegA(rN), getIRegA(rM));
18415 putIRegA(rN, erN, condT, Ijk_Boring);
18416 DIP("ldrht%s r%u, [r%u], %cr%u\n",
18417 nCC(INSN_COND), rT, rN, bU ? '+' : '-', rM);
18418 goto decode_success;
18422 /* -------------- (A1) LDRSHT reg+#imm8 -------------- */
18423 /* Load Register Signed Halfword Unprivileged:
18424 ldrsht<c> Rt, [Rn] {, #+/-imm8}
18426 if ( (INSN(27,20) & BITS8(1,1,1,1,0,1,1,1)) == BITS8(0,0,0,0,0,1,1,1)
18427 && INSN(7,4) == BITS4(1,1,1,1)) {
18428 UInt rT = INSN(15,12);
18429 UInt rN = INSN(19,16);
18430 UInt bU = INSN(23,23);
18431 UInt imm4H = INSN(11,8);
18432 UInt imm4L = INSN(3,0);
18433 UInt imm8 = (imm4H << 4) | imm4L;
18434 Bool valid = True;
18435 if (rN == 15 || rT == 15 || rN == rT)
18436 valid = False;
18437 if (valid) {
18438 IRTemp newRt = newTemp(Ity_I32);
18439 loadGuardedLE( newRt,
18440 ILGop_16Sto32, getIRegA(rN), getIRegA(rT), condT );
18441 putIRegA(rT, mkexpr(newRt), IRTemp_INVALID, Ijk_Boring);
18442 IRExpr* erN = binop(bU ? Iop_Add32 : Iop_Sub32,
18443 getIRegA(rN), mkU32(imm8));
18444 putIRegA(rN, erN, condT, Ijk_Boring);
18445 DIP("ldrsht%s r%u, [r%u], #%c%u\n",
18446 nCC(INSN_COND), rT, rN, bU ? '+' : '-', imm8);
18447 goto decode_success;
18451 /* -------------- (A2) LDRSHT reg+/-reg -------------- */
18452 /* Load Register Signed Halfword Unprivileged:
18453 ldrsht<c> Rt, [Rn], +/-Rm
18455 if ( (INSN(27,20) & BITS8(1,1,1,1,0,1,1,1)) == BITS8(0,0,0,0,0,0,1,1)
18456 && INSN(11,4) == BITS8(0,0,0,0,1,1,1,1)) {
18457 UInt rT = INSN(15,12);
18458 UInt rN = INSN(19,16);
18459 UInt rM = INSN(3,0);
18460 UInt bU = INSN(23,23);
18461 Bool valid = True;
18462 if (rN == 15 || rT == 15 || rN == rT || rM == 15)
18463 valid = False;
18464 if (valid) {
18465 IRTemp newRt = newTemp(Ity_I32);
18466 loadGuardedLE( newRt,
18467 ILGop_16Sto32, getIRegA(rN), getIRegA(rT), condT );
18468 putIRegA(rT, mkexpr(newRt), IRTemp_INVALID, Ijk_Boring);
18469 IRExpr* erN = binop(bU ? Iop_Add32 : Iop_Sub32,
18470 getIRegA(rN), getIRegA(rM));
18471 putIRegA(rN, erN, condT, Ijk_Boring);
18472 DIP("ldrsht%s r%u, [r%u], %cr%u\n",
18473 nCC(INSN_COND), rT, rN, bU ? '+' : '-', rM);
18474 goto decode_success;
18478 /* -------------- (A1) LDRSBT reg+#imm8 -------------- */
18479 /* Load Register Signed Byte Unprivileged:
18480 ldrsbt<c> Rt, [Rn] {, #+/-imm8}
18482 if ( (INSN(27,20) & BITS8(1,1,1,1,0,1,1,1)) == BITS8(0,0,0,0,0,1,1,1)
18483 && INSN(7,4) == BITS4(1,1,0,1)) {
18484 UInt rT = INSN(15,12);
18485 UInt rN = INSN(19,16);
18486 UInt bU = INSN(23,23);
18487 UInt imm4H = INSN(11,8);
18488 UInt imm4L = INSN(3,0);
18489 UInt imm8 = (imm4H << 4) | imm4L;
18490 Bool valid = True;
18491 if (rT == 15 || rN == 15 || rN == rT)
18492 valid = False;
18493 if (valid) {
18494 IRTemp newRt = newTemp(Ity_I32);
18495 loadGuardedLE( newRt,
18496 ILGop_8Sto32, getIRegA(rN), getIRegA(rT), condT );
18497 putIRegA(rT, mkexpr(newRt), IRTemp_INVALID, Ijk_Boring);
18498 IRExpr* erN = binop(bU ? Iop_Add32 : Iop_Sub32,
18499 getIRegA(rN), mkU32(imm8));
18500 putIRegA(rN, erN, condT, Ijk_Boring);
18501 DIP("ldrsbt%s r%u, [r%u], #%c%u\n",
18502 nCC(INSN_COND), rT, rN, bU ? '+' : '-', imm8);
18503 goto decode_success;
18507 /* -------------- (A2) LDRSBT reg+/-reg -------------- */
18508 /* Load Register Signed Byte Unprivileged:
18509 ldrsbt<c> Rt, [Rn], +/-Rm
18511 if ( (INSN(27,20) & BITS8(1,1,1,1,0,1,1,1)) == BITS8(0,0,0,0,0,0,1,1)
18512 && INSN(11,4) == BITS8(0,0,0,0,1,1,0,1)) {
18513 UInt rT = INSN(15,12);
18514 UInt rN = INSN(19,16);
18515 UInt bU = INSN(23,23);
18516 UInt rM = INSN(3,0);
18517 Bool valid = True;
18518 if (rT == 15 || rN == 15 || rN == rT || rM == 15)
18519 valid = False;
18520 if (valid) {
18521 IRTemp newRt = newTemp(Ity_I32);
18522 loadGuardedLE( newRt,
18523 ILGop_8Sto32, getIRegA(rN), getIRegA(rT), condT );
18524 putIRegA(rT, mkexpr(newRt), IRTemp_INVALID, Ijk_Boring);
18525 IRExpr* erN = binop(bU ? Iop_Add32 : Iop_Sub32,
18526 getIRegA(rN), getIRegA(rM));
18527 putIRegA(rN, erN, condT, Ijk_Boring);
18528 DIP("ldrsbt%s r%u, [r%u], %cr%u\n",
18529 nCC(INSN_COND), rT, rN, bU ? '+' : '-', rM);
18530 goto decode_success;
18534 /* -------------- (A1) STRBT reg+#imm12 -------------- */
18535 /* Store Register Byte Unprivileged:
18536 strbt<c> Rt, [Rn], #+/-imm12
18538 if ( (INSN(27,20) & BITS8(1,1,1,1,0,1,1,1)) == BITS8(0,1,0,0,0,1,1,0) ) {
18539 UInt rT = INSN(15,12);
18540 UInt rN = INSN(19,16);
18541 UInt imm12 = INSN(11,0);
18542 UInt bU = INSN(23,23);
18543 Bool valid = True;
18544 if (rT == 15 || rN == 15 || rN == rT) valid = False;
18545 if (valid) {
18546 IRExpr* address = getIRegA(rN);
18547 IRExpr* data = unop(Iop_32to8, getIRegA(rT));
18548 storeGuardedLE( address, data, condT);
18549 IRExpr* newRn = binop(bU ? Iop_Add32 : Iop_Sub32,
18550 getIRegA(rN), mkU32(imm12));
18551 putIRegA(rN, newRn, condT, Ijk_Boring);
18552 DIP("strbt%s r%u, [r%u], #%c%u\n",
18553 nCC(INSN_COND), rT, rN, bU ? '+' : '-', imm12);
18554 goto decode_success;
18558 /* -------------- (A2) STRBT reg+/-reg -------------- */
18559 /* Store Register Byte Unprivileged:
18560 strbt<c> Rt, [Rn], +/-Rm{, shift}
18562 if ( (INSN(27,20) & BITS8(1,1,1,1,0,1,1,1)) == BITS8(0,1,1,0,0,1,1,0)
18563 && INSN(4,4) == 0) {
18564 UInt rT = INSN(15,12);
18565 UInt rN = INSN(19,16);
18566 UInt imm5 = INSN(11,7);
18567 UInt type = INSN(6,5);
18568 UInt rM = INSN(3,0);
18569 UInt bU = INSN(23,23);
18570 Bool valid = True;
18571 if (rT == 15 || rN == 15 || rN == rT || rM == 15) valid = False;
18572 if (valid) {
18573 IRExpr* address = getIRegA(rN);
18574 IRExpr* data = unop(Iop_32to8, getIRegA(rT));
18575 storeGuardedLE( address, data, condT);
18576 // dis_buf generated is slightly bogus, in fact.
18577 IRExpr* erN = mk_EA_reg_plusminus_shifted_reg(rN, bU, rM,
18578 type, imm5, dis_buf);
18579 putIRegA(rN, erN, condT, Ijk_Boring);
18580 DIP("strbt%s r%u, %s\n", nCC(INSN_COND), rT, dis_buf);
18581 goto decode_success;
18585 /* -------------- (A1) STRHT reg+#imm8 -------------- */
18586 /* Store Register Halfword Unprivileged:
18587 strht<c> Rt, [Rn], #+/-imm8
18589 if ( (INSN(27,20) & BITS8(1,1,1,1,0,1,1,1)) == BITS8(0,0,0,0,0,1,1,0)
18590 && INSN(7,4) == BITS4(1,0,1,1) ) {
18591 UInt rT = INSN(15,12);
18592 UInt rN = INSN(19,16);
18593 UInt imm4H = INSN(11,8);
18594 UInt imm4L = INSN(3,0);
18595 UInt imm8 = (imm4H << 4) | imm4L;
18596 UInt bU = INSN(23,23);
18597 Bool valid = True;
18598 if (rT == 15 || rN == 15 || rN == rT) valid = False;
18599 if (valid) {
18600 IRExpr* address = getIRegA(rN);
18601 IRExpr* data = unop(Iop_32to16, getIRegA(rT));
18602 storeGuardedLE( address, data, condT);
18603 IRExpr* newRn = binop(bU ? Iop_Add32 : Iop_Sub32,
18604 getIRegA(rN), mkU32(imm8));
18605 putIRegA(rN, newRn, condT, Ijk_Boring);
18606 DIP("strht%s r%u, [r%u], #%c%u\n",
18607 nCC(INSN_COND), rT, rN, bU ? '+' : '-', imm8);
18608 goto decode_success;
18612 /* -------------- (A2) STRHT reg+reg -------------- */
18613 /* Store Register Halfword Unprivileged:
18614 strht<c> Rt, [Rn], +/-Rm
18616 if ( (INSN(27,20) & BITS8(1,1,1,1,0,1,1,1)) == BITS8(0,0,0,0,0,0,1,0)
18617 && INSN(11,4) == BITS8(0,0,0,0,1,0,1,1) ) {
18618 UInt rT = INSN(15,12);
18619 UInt rN = INSN(19,16);
18620 UInt rM = INSN(3,0);
18621 UInt bU = INSN(23,23);
18622 Bool valid = True;
18623 if (rT == 15 || rN == 15 || rN == rT || rM == 15) valid = False;
18624 if (valid) {
18625 IRExpr* address = getIRegA(rN);
18626 IRExpr* data = unop(Iop_32to16, getIRegA(rT));
18627 storeGuardedLE( address, data, condT);
18628 IRExpr* newRn = binop(bU ? Iop_Add32 : Iop_Sub32,
18629 getIRegA(rN), getIRegA(rM));
18630 putIRegA(rN, newRn, condT, Ijk_Boring);
18631 DIP("strht%s r%u, [r%u], %cr%u\n",
18632 nCC(INSN_COND), rT, rN, bU ? '+' : '-', rM);
18633 goto decode_success;
18637 /* -------------- (A1) STRT reg+imm12 -------------- */
18638 /* Store Register Unprivileged:
18639 strt<c> Rt, [Rn], #+/-imm12
18641 if ( (INSN(27,20) & BITS8(1,1,1,1,0,1,1,1)) == BITS8(0,1,0,0,0,0,1,0) ) {
18642 UInt rT = INSN(15,12);
18643 UInt rN = INSN(19,16);
18644 UInt imm12 = INSN(11,0);
18645 UInt bU = INSN(23,23);
18646 Bool valid = True;
18647 if (rN == 15 || rN == rT) valid = False;
18648 if (valid) {
18649 IRExpr* address = getIRegA(rN);
18650 storeGuardedLE( address, getIRegA(rT), condT);
18651 IRExpr* newRn = binop(bU ? Iop_Add32 : Iop_Sub32,
18652 getIRegA(rN), mkU32(imm12));
18653 putIRegA(rN, newRn, condT, Ijk_Boring);
18654 DIP("strt%s r%u, [r%u], %c%u\n",
18655 nCC(INSN_COND), rT, rN, bU ? '+' : '-', imm12);
18656 goto decode_success;
18660 /* -------------- (A2) STRT reg+reg -------------- */
18661 /* Store Register Unprivileged:
18662 strt<c> Rt, [Rn], +/-Rm{, shift}
18664 if ( (INSN(27,20) & BITS8(1,1,1,1,0,1,1,1)) == BITS8(0,1,1,0,0,0,1,0)
18665 && INSN(4,4) == 0 ) {
18666 UInt rT = INSN(15,12);
18667 UInt rN = INSN(19,16);
18668 UInt rM = INSN(3,0);
18669 UInt type = INSN(6,5);
18670 UInt imm5 = INSN(11,7);
18671 UInt bU = INSN(23,23);
18672 Bool valid = True;
18673 if (rN == 15 || rN == rT || rM == 15) valid = False;
18674 /* FIXME We didn't do:
18675 if ArchVersion() < 6 && rM == rN then UNPREDICTABLE */
18676 if (valid) {
18677 storeGuardedLE( getIRegA(rN), getIRegA(rT), condT);
18678 // dis_buf generated is slightly bogus, in fact.
18679 IRExpr* erN = mk_EA_reg_plusminus_shifted_reg(rN, bU, rM,
18680 type, imm5, dis_buf);
18681 putIRegA(rN, erN, condT, Ijk_Boring);
18682 DIP("strt%s r%u, %s\n", nCC(INSN_COND), rT, dis_buf);
18683 goto decode_success;
18687 /* ----------------------------------------------------------- */
18688 /* -- ARMv7 instructions -- */
18689 /* ----------------------------------------------------------- */
18691 /* -------------- read CP15 TPIDRURO register ------------- */
18692 /* mrc p15, 0, r0, c13, c0, 3 up to
18693 mrc p15, 0, r14, c13, c0, 3
18695 /* I don't know whether this is really v7-only. But anyway, we
18696 have to support it since arm-linux uses TPIDRURO as a thread
18697 state register. */
18698 if (0x0E1D0F70 == (insn & 0x0FFF0FFF)) {
18699 UInt rD = INSN(15,12);
18700 if (rD <= 14) {
18701 /* skip r15, that's too stupid to handle */
18702 putIRegA(rD, IRExpr_Get(OFFB_TPIDRURO, Ity_I32),
18703 condT, Ijk_Boring);
18704 DIP("mrc%s p15,0, r%u, c13, c0, 3\n", nCC(INSN_COND), rD);
18705 goto decode_success;
18707 /* fall through */
18710 /* ------------ read/write CP15 TPIDRURW register ----------- */
18711 /* mcr p15, 0, r0, c13, c0, 2 (r->cr xfer) up to
18712 mcr p15, 0, r14, c13, c0, 2
18714 mrc p15, 0, r0, c13, c0, 2 (rc->r xfer) up to
18715 mrc p15, 0, r14, c13, c0, 2
18717 if (0x0E0D0F50 == (insn & 0x0FFF0FFF)) { // MCR
18718 UInt rS = INSN(15,12);
18719 if (rS <= 14) {
18720 /* skip r15, that's too stupid to handle */
18721 putMiscReg32(OFFB_TPIDRURW, getIRegA(rS), condT);
18722 DIP("mcr%s p15,0, r%u, c13, c0, 2\n", nCC(INSN_COND), rS);
18723 goto decode_success;
18725 /* fall through */
18727 if (0x0E1D0F50 == (insn & 0x0FFF0FFF)) { // MRC
18728 UInt rD = INSN(15,12);
18729 if (rD <= 14) {
18730 /* skip r15, that's too stupid to handle */
18731 putIRegA(rD, IRExpr_Get(OFFB_TPIDRURW, Ity_I32),
18732 condT, Ijk_Boring);
18733 DIP("mrc%s p15,0, r%u, c13, c0, 2\n", nCC(INSN_COND), rD);
18734 goto decode_success;
18736 /* fall through */
18739 /* -------------- read CP15 PMUSRENR register ------------- */
18740 /* mrc p15, 0, r0, c9, c14, 0 up to
18741 mrc p15, 0, r14, c9, c14, 0
18743 /* A program reading this register is really asking "which
18744 performance monitoring registes are available in user space?
18745 The simple answer here is to return zero, meaning "none". See
18746 #345984. */
18747 if (0x0E190F1E == (insn & 0x0FFF0FFF)) {
18748 UInt rD = INSN(15,12);
18749 if (rD <= 14) {
18750 /* skip r15, that's too stupid to handle */
18751 putIRegA(rD, mkU32(0), condT, Ijk_Boring);
18752 DIP("mrc%s p15,0, r%u, c9, c14, 0\n", nCC(INSN_COND), rD);
18753 goto decode_success;
18755 /* fall through */
18758 /* Handle various kinds of barriers. This is rather indiscriminate
18759 in the sense that they are all turned into an IR Fence, which
18760 means we don't know which they are, so the back end has to
18761 re-emit them all when it comes acrosss an IR Fence.
18763 /* v6 */ /* mcr 15, 0, rT, c7, c10, 5 */
18764 if (0xEE070FBA == (insn & 0xFFFF0FFF)) {
18765 UInt rT = INSN(15,12);
18766 if (rT <= 14) {
18767 /* mcr 15, 0, rT, c7, c10, 5 (v6) equiv to DMB (v7). Data
18768 Memory Barrier -- ensures ordering of memory accesses. */
18769 stmt( IRStmt_MBE(Imbe_Fence) );
18770 DIP("mcr 15, 0, r%u, c7, c10, 5 (data memory barrier)\n", rT);
18771 goto decode_success;
18773 /* fall through */
18775 /* other flavours of barrier */
18776 switch (insn) {
18777 case 0xEE070F9A: /* v6 */
18778 /* mcr 15, 0, r0, c7, c10, 4 (v6) equiv to DSB (v7). Data
18779 Synch Barrier -- ensures completion of memory accesses. */
18780 stmt( IRStmt_MBE(Imbe_Fence) );
18781 DIP("mcr 15, 0, r0, c7, c10, 4 (data synch barrier)\n");
18782 goto decode_success;
18783 case 0xEE070F95: /* v6 */
18784 /* mcr 15, 0, r0, c7, c5, 4 (v6) equiv to ISB (v7).
18785 Instruction Synchronisation Barrier (or Flush Prefetch
18786 Buffer) -- a pipe flush, I think. I suspect we could
18787 ignore those, but to be on the safe side emit a fence
18788 anyway. */
18789 stmt( IRStmt_MBE(Imbe_Fence) );
18790 DIP("mcr 15, 0, r0, c7, c5, 4 (insn synch barrier)\n");
18791 goto decode_success;
18792 default:
18793 break;
18796 /* ----------------------------------------------------------- */
18797 /* -- Hints -- */
18798 /* ----------------------------------------------------------- */
18800 switch (insn & 0x0FFFFFFF) {
18801 /* ------------------- NOP ------------------ */
18802 case 0x0320F000:
18803 DIP("nop%s\n", nCC(INSN_COND));
18804 goto decode_success;
18805 /* ------------------- YIELD ------------------ */
18806 case 0x0320F001:
18807 /* Continue after conditionally yielding. */
18808 DIP("yield%s\n", nCC(INSN_COND));
18809 stmt( IRStmt_Exit( unop(Iop_32to1,
18810 condT == IRTemp_INVALID
18811 ? mkU32(1) : mkexpr(condT)),
18812 Ijk_Yield,
18813 IRConst_U32(guest_R15_curr_instr_notENC + 4),
18814 OFFB_R15T ));
18815 goto decode_success;
18816 default:
18817 break;
18820 /* ----------------------------------------------------------- */
18821 /* -- VFP (CP 10, CP 11) instructions (in ARM mode) -- */
18822 /* ----------------------------------------------------------- */
18824 if (INSN_COND != ARMCondNV) {
18825 Bool ok_vfp = decode_CP10_CP11_instruction (
18826 &dres, INSN(27,0), condT, INSN_COND,
18827 False/*!isT*/
18829 if (ok_vfp)
18830 goto decode_success;
18833 /* ----------------------------------------------------------- */
18834 /* -- NEON instructions (in ARM mode) -- */
18835 /* ----------------------------------------------------------- */
18837 /* These are all in NV space, and so are taken care of (far) above,
18838 by a call from this function to
18839 decode_NV_instruction_ARMv7_and_below(). */
18841 /* ----------------------------------------------------------- */
18842 /* -- v6 media instructions (in ARM mode) -- */
18843 /* ----------------------------------------------------------- */
18845 { Bool ok_v6m = decode_V6MEDIA_instruction(
18846 &dres, INSN(27,0), condT, INSN_COND,
18847 False/*!isT*/
18849 if (ok_v6m)
18850 goto decode_success;
18853 /* ----------------------------------------------------------- */
18854 /* -- v8 instructions (in ARM mode) -- */
18855 /* ----------------------------------------------------------- */
18857 after_v7_decoder:
18859 /* If we get here, it means that all attempts to decode the
18860 instruction as ARMv7 or earlier have failed. So, if we're doing
18861 ARMv8 or later, here is the point to try for it. */
18863 if (VEX_ARM_ARCHLEVEL(archinfo->hwcaps) >= 8) {
18864 Bool ok_v8
18865 = decode_V8_instruction( &dres, insn, condT, False/*!isT*/,
18866 IRTemp_INVALID, IRTemp_INVALID );
18867 if (ok_v8)
18868 goto decode_success;
18871 /* ----------------------------------------------------------- */
18872 /* -- Undecodable -- */
18873 /* ----------------------------------------------------------- */
18875 goto decode_failure;
18876 /*NOTREACHED*/
18878 decode_failure:
18879 /* All decode failures end up here. */
18880 if (sigill_diag) {
18881 vex_printf("disInstr(arm): unhandled instruction: "
18882 "0x%x\n", insn);
18883 vex_printf(" cond=%d(0x%x) 27:20=%d(0x%02x) "
18884 "4:4=%d "
18885 "3:0=%d(0x%x)\n",
18886 (Int)INSN_COND, (UInt)INSN_COND,
18887 (Int)INSN(27,20), (UInt)INSN(27,20),
18888 (Int)INSN(4,4),
18889 (Int)INSN(3,0), (UInt)INSN(3,0) );
18892 /* Tell the dispatcher that this insn cannot be decoded, and so has
18893 not been executed, and (is currently) the next to be executed.
18894 R15 should be up-to-date since it made so at the start of each
18895 insn, but nevertheless be paranoid and update it again right
18896 now. */
18897 vassert(0 == (guest_R15_curr_instr_notENC & 3));
18898 llPutIReg( 15, mkU32(guest_R15_curr_instr_notENC) );
18899 dres.len = 0;
18900 dres.whatNext = Dis_StopHere;
18901 dres.jk_StopHere = Ijk_NoDecode;
18902 dres.continueAt = 0;
18903 return dres;
18905 decode_success:
18906 /* All decode successes end up here. */
18907 DIP("\n");
18909 vassert(dres.len == 4 || dres.len == 20);
18911 /* Now then. Do we have an implicit jump to r15 to deal with? */
18912 if (r15written) {
18913 /* If we get jump to deal with, we assume that there's been no
18914 other competing branch stuff previously generated for this
18915 insn. That's reasonable, in the sense that the ARM insn set
18916 appears to declare as "Unpredictable" any instruction which
18917 generates more than one possible new value for r15. Hence
18918 just assert. The decoders themselves should check against
18919 all such instructions which are thusly Unpredictable, and
18920 decline to decode them. Hence we should never get here if we
18921 have competing new values for r15, and hence it is safe to
18922 assert here. */
18923 vassert(dres.whatNext == Dis_Continue);
18924 vassert(irsb->next == NULL);
18925 vassert(irsb->jumpkind == Ijk_Boring);
18926 /* If r15 is unconditionally written, terminate the block by
18927 jumping to it. If it's conditionally written, still
18928 terminate the block (a shame, but we can't do side exits to
18929 arbitrary destinations), but first jump to the next
18930 instruction if the condition doesn't hold. */
18931 /* We can't use getIReg(15) to get the destination, since that
18932 will produce r15+8, which isn't what we want. Must use
18933 llGetIReg(15) instead. */
18934 if (r15guard == IRTemp_INVALID) {
18935 /* unconditional */
18936 } else {
18937 /* conditional */
18938 stmt( IRStmt_Exit(
18939 unop(Iop_32to1,
18940 binop(Iop_Xor32,
18941 mkexpr(r15guard), mkU32(1))),
18942 r15kind,
18943 IRConst_U32(guest_R15_curr_instr_notENC + 4),
18944 OFFB_R15T
18947 /* This seems crazy, but we're required to finish the insn with
18948 a write to the guest PC. As usual we rely on ir_opt to tidy
18949 up later. */
18950 llPutIReg(15, llGetIReg(15));
18951 dres.whatNext = Dis_StopHere;
18952 dres.jk_StopHere = r15kind;
18953 } else {
18954 /* Set up the end-state in the normal way. */
18955 switch (dres.whatNext) {
18956 case Dis_Continue:
18957 llPutIReg(15, mkU32(dres.len + guest_R15_curr_instr_notENC));
18958 break;
18959 case Dis_ResteerU:
18960 case Dis_ResteerC:
18961 llPutIReg(15, mkU32(dres.continueAt));
18962 break;
18963 case Dis_StopHere:
18964 break;
18965 default:
18966 vassert(0);
18970 return dres;
18972 # undef INSN_COND
18973 # undef INSN
18977 /*------------------------------------------------------------*/
18978 /*--- Disassemble a single Thumb2 instruction ---*/
18979 /*------------------------------------------------------------*/
18981 static const UChar it_length_table[256]; /* fwds */
18983 /* NB: in Thumb mode we do fetches of regs with getIRegT, which
18984 automagically adds 4 to fetches of r15. However, writes to regs
18985 are done with putIRegT, which disallows writes to r15. Hence any
18986 r15 writes and associated jumps have to be done "by hand". */
18988 /* Disassemble a single Thumb instruction into IR. The instruction is
18989 located in host memory at guest_instr, and has (decoded) guest IP
18990 of guest_R15_curr_instr_notENC, which will have been set before the
18991 call here. */
18993 static
18994 DisResult disInstr_THUMB_WRK (
18995 Bool (*resteerOkFn) ( /*opaque*/void*, Addr ),
18996 Bool resteerCisOk,
18997 void* callback_opaque,
18998 const UChar* guest_instr,
18999 const VexArchInfo* archinfo,
19000 const VexAbiInfo* abiinfo,
19001 Bool sigill_diag
19004 /* A macro to fish bits out of insn0. There's also INSN1, to fish
19005 bits out of insn1, but that's defined only after the end of the
19006 16-bit insn decoder, so as to stop it mistakenly being used
19007 therein. */
19008 # define INSN0(_bMax,_bMin) SLICE_UInt(((UInt)insn0), (_bMax), (_bMin))
19010 DisResult dres;
19011 UShort insn0; /* first 16 bits of the insn */
19012 UShort insn1; /* second 16 bits of the insn */
19013 HChar dis_buf[128]; // big enough to hold LDMIA etc text
19015 /* Summary result of the ITxxx backwards analysis: False == safe
19016 but suboptimal. */
19017 Bool guaranteedUnconditional = False;
19019 /* Set result defaults. */
19020 dres.whatNext = Dis_Continue;
19021 dres.len = 2;
19022 dres.continueAt = 0;
19023 dres.jk_StopHere = Ijk_INVALID;
19024 dres.hint = Dis_HintNone;
19026 /* Set default actions for post-insn handling of writes to r15, if
19027 required. */
19028 r15written = False;
19029 r15guard = IRTemp_INVALID; /* unconditional */
19030 r15kind = Ijk_Boring;
19032 /* Insns could be 2 or 4 bytes long. Just get the first 16 bits at
19033 this point. If we need the second 16, get them later. We can't
19034 get them both out immediately because it risks a fault (very
19035 unlikely, but ..) if the second 16 bits aren't actually
19036 necessary. */
19037 insn0 = getUShortLittleEndianly( guest_instr );
19038 insn1 = 0; /* We'll get it later, once we know we need it. */
19040 /* Similarly, will set this later. */
19041 IRTemp old_itstate = IRTemp_INVALID;
19043 if (0) vex_printf("insn: 0x%x\n", insn0);
19045 DIP("\t(thumb) 0x%x: ", (UInt)guest_R15_curr_instr_notENC);
19047 vassert(0 == (guest_R15_curr_instr_notENC & 1));
19049 /* ----------------------------------------------------------- */
19050 /* Spot "Special" instructions (see comment at top of file). */
19052 const UChar* code = guest_instr;
19053 /* Spot the 16-byte preamble:
19055 ea4f 0cfc mov.w ip, ip, ror #3
19056 ea4f 3c7c mov.w ip, ip, ror #13
19057 ea4f 7c7c mov.w ip, ip, ror #29
19058 ea4f 4cfc mov.w ip, ip, ror #19
19060 UInt word1 = 0x0CFCEA4F;
19061 UInt word2 = 0x3C7CEA4F;
19062 UInt word3 = 0x7C7CEA4F;
19063 UInt word4 = 0x4CFCEA4F;
19064 if (getUIntLittleEndianly(code+ 0) == word1 &&
19065 getUIntLittleEndianly(code+ 4) == word2 &&
19066 getUIntLittleEndianly(code+ 8) == word3 &&
19067 getUIntLittleEndianly(code+12) == word4) {
19068 /* Got a "Special" instruction preamble. Which one is it? */
19069 // 0x 0A 0A EA 4A
19070 if (getUIntLittleEndianly(code+16) == 0x0A0AEA4A
19071 /* orr.w r10,r10,r10 */) {
19072 /* R3 = client_request ( R4 ) */
19073 DIP("r3 = client_request ( %%r4 )\n");
19074 llPutIReg(15, mkU32( (guest_R15_curr_instr_notENC + 20) | 1 ));
19075 dres.jk_StopHere = Ijk_ClientReq;
19076 dres.whatNext = Dis_StopHere;
19077 goto decode_success;
19079 else
19080 // 0x 0B 0B EA 4B
19081 if (getUIntLittleEndianly(code+16) == 0x0B0BEA4B
19082 /* orr r11,r11,r11 */) {
19083 /* R3 = guest_NRADDR */
19084 DIP("r3 = guest_NRADDR\n");
19085 dres.len = 20;
19086 llPutIReg(3, IRExpr_Get( OFFB_NRADDR, Ity_I32 ));
19087 goto decode_success;
19089 else
19090 // 0x 0C 0C EA 4C
19091 if (getUIntLittleEndianly(code+16) == 0x0C0CEA4C
19092 /* orr r12,r12,r12 */) {
19093 /* branch-and-link-to-noredir R4 */
19094 DIP("branch-and-link-to-noredir r4\n");
19095 llPutIReg(14, mkU32( (guest_R15_curr_instr_notENC + 20) | 1 ));
19096 llPutIReg(15, getIRegT(4));
19097 dres.jk_StopHere = Ijk_NoRedir;
19098 dres.whatNext = Dis_StopHere;
19099 goto decode_success;
19101 else
19102 // 0x 09 09 EA 49
19103 if (getUIntLittleEndianly(code+16) == 0x0909EA49
19104 /* orr r9,r9,r9 */) {
19105 /* IR injection */
19106 DIP("IR injection\n");
19107 vex_inject_ir(irsb, Iend_LE);
19108 // Invalidate the current insn. The reason is that the IRop we're
19109 // injecting here can change. In which case the translation has to
19110 // be redone. For ease of handling, we simply invalidate all the
19111 // time.
19112 stmt(IRStmt_Put(OFFB_CMSTART, mkU32(guest_R15_curr_instr_notENC)));
19113 stmt(IRStmt_Put(OFFB_CMLEN, mkU32(20)));
19114 llPutIReg(15, mkU32( (guest_R15_curr_instr_notENC + 20) | 1 ));
19115 dres.whatNext = Dis_StopHere;
19116 dres.jk_StopHere = Ijk_InvalICache;
19117 goto decode_success;
19119 /* We don't know what it is. Set insn0 so decode_failure
19120 can print the insn following the Special-insn preamble. */
19121 insn0 = getUShortLittleEndianly(code+16);
19122 goto decode_failure;
19123 /*NOTREACHED*/
19128 /* ----------------------------------------------------------- */
19130 /* Main Thumb instruction decoder starts here. It's a series of
19131 switches which examine ever longer bit sequences at the MSB of
19132 the instruction word, first for 16-bit insns, then for 32-bit
19133 insns. */
19135 /* --- BEGIN ITxxx optimisation analysis --- */
19136 /* This is a crucial optimisation for the ITState boilerplate that
19137 follows. Examine the 9 halfwords preceding this instruction,
19138 and if we are absolutely sure that none of them constitute an
19139 'it' instruction, then we can be sure that this instruction is
19140 not under the control of any 'it' instruction, and so
19141 guest_ITSTATE must be zero. So write zero into ITSTATE right
19142 now, so that iropt can fold out almost all of the resulting
19143 junk.
19145 If we aren't sure, we can always safely skip this step. So be a
19146 bit conservative about it: only poke around in the same page as
19147 this instruction, lest we get a fault from the previous page
19148 that would not otherwise have happened. The saving grace is
19149 that such skipping is pretty rare -- it only happens,
19150 statistically, 18/4096ths of the time, so is judged unlikely to
19151 be a performance problems.
19153 FIXME: do better. Take into account the number of insns covered
19154 by any IT insns we find, to rule out cases where an IT clearly
19155 cannot cover this instruction. This would improve behaviour for
19156 branch targets immediately following an IT-guarded group that is
19157 not of full length. Eg, (and completely ignoring issues of 16-
19158 vs 32-bit insn length):
19160 ite cond
19161 insn1
19162 insn2
19163 label: insn3
19164 insn4
19166 The 'it' only conditionalises insn1 and insn2. However, the
19167 current analysis is conservative and considers insn3 and insn4
19168 also possibly guarded. Hence if 'label:' is the start of a hot
19169 loop we will get a big performance hit.
19172 /* Summary result of this analysis: False == safe but
19173 suboptimal. */
19174 vassert(guaranteedUnconditional == False);
19176 UInt pc = guest_R15_curr_instr_notENC;
19177 vassert(0 == (pc & 1));
19179 UInt pageoff = pc & 0xFFF;
19180 if (pageoff >= 18) {
19181 /* It's safe to poke about in the 9 halfwords preceding this
19182 insn. So, have a look at them. */
19183 guaranteedUnconditional = True; /* assume no 'it' insn found,
19184 till we do */
19185 UShort* hwp = (UShort*)(HWord)pc;
19186 Int i;
19187 for (i = -1; i >= -9; i--) {
19188 /* We're in the same page. (True, but commented out due
19189 to expense.) */
19191 vassert( ( ((UInt)(&hwp[i])) & 0xFFFFF000 )
19192 == ( pc & 0xFFFFF000 ) );
19194 /* All valid IT instructions must have the form 0xBFxy,
19195 where x can be anything, but y must be nonzero. Find
19196 the number of insns covered by it (1 .. 4) and check to
19197 see if it can possibly reach up to the instruction in
19198 question. Some (x,y) combinations mean UNPREDICTABLE,
19199 and the table is constructed to be conservative by
19200 returning 4 for those cases, so the analysis is safe
19201 even if the code uses unpredictable IT instructions (in
19202 which case its authors are nuts, but hey.) */
19203 UShort hwp_i = hwp[i];
19204 if (UNLIKELY((hwp_i & 0xFF00) == 0xBF00 && (hwp_i & 0xF) != 0)) {
19205 /* might be an 'it' insn. */
19206 /* # guarded insns */
19207 Int n_guarded = (Int)it_length_table[hwp_i & 0xFF];
19208 vassert(n_guarded >= 1 && n_guarded <= 4);
19209 if (n_guarded * 2 /* # guarded HWs, worst case */
19210 > (-(i+1))) /* -(i+1): # remaining HWs after the IT */
19211 /* -(i+0) also seems to work, even though I think
19212 it's wrong. I don't understand that. */
19213 guaranteedUnconditional = False;
19214 break;
19219 /* --- END ITxxx optimisation analysis --- */
19221 /* Generate the guarding condition for this insn, by examining
19222 ITSTATE. Assign it to condT. Also, generate new
19223 values for ITSTATE ready for stuffing back into the
19224 guest state, but don't actually do the Put yet, since it will
19225 need to stuffed back in only after the instruction gets to a
19226 point where it is sure to complete. Mostly we let the code at
19227 decode_success handle this, but in cases where the insn contains
19228 a side exit, we have to update them before the exit. */
19230 /* If the ITxxx optimisation analysis above could not prove that
19231 this instruction is guaranteed unconditional, we insert a
19232 lengthy IR preamble to compute the guarding condition at
19233 runtime. If it can prove it (which obviously we hope is the
19234 normal case) then we insert a minimal preamble, which is
19235 equivalent to setting guest_ITSTATE to zero and then folding
19236 that through the full preamble (which completely disappears). */
19238 IRTemp condT = IRTemp_INVALID;
19239 IRTemp cond_AND_notInIT_T = IRTemp_INVALID;
19241 IRTemp new_itstate = IRTemp_INVALID;
19242 vassert(old_itstate == IRTemp_INVALID);
19244 if (guaranteedUnconditional) {
19245 /* BEGIN "partial eval { ITSTATE = 0; STANDARD_PREAMBLE; }" */
19247 // ITSTATE = 0 :: I32
19248 IRTemp z32 = newTemp(Ity_I32);
19249 assign(z32, mkU32(0));
19250 put_ITSTATE(z32);
19252 // old_itstate = 0 :: I32
19254 // old_itstate = get_ITSTATE();
19255 old_itstate = z32; /* 0 :: I32 */
19257 // new_itstate = old_itstate >> 8
19258 // = 0 >> 8
19259 // = 0 :: I32
19261 // new_itstate = newTemp(Ity_I32);
19262 // assign(new_itstate,
19263 // binop(Iop_Shr32, mkexpr(old_itstate), mkU8(8)));
19264 new_itstate = z32;
19266 // ITSTATE = 0 :: I32(again)
19268 // put_ITSTATE(new_itstate);
19270 // condT1 = calc_cond_dyn( xor(and(old_istate,0xF0), 0xE0) )
19271 // = calc_cond_dyn( xor(0,0xE0) )
19272 // = calc_cond_dyn ( 0xE0 )
19273 // = 1 :: I32
19274 // Not that this matters, since the computed value is not used:
19275 // see condT folding below
19277 // IRTemp condT1 = newTemp(Ity_I32);
19278 // assign(condT1,
19279 // mk_armg_calculate_condition_dyn(
19280 // binop(Iop_Xor32,
19281 // binop(Iop_And32, mkexpr(old_itstate), mkU32(0xF0)),
19282 // mkU32(0xE0))
19283 // )
19284 // );
19286 // condT = 32to8(and32(old_itstate,0xF0)) == 0 ? 1 : condT1
19287 // = 32to8(and32(0,0xF0)) == 0 ? 1 : condT1
19288 // = 32to8(0) == 0 ? 1 : condT1
19289 // = 0 == 0 ? 1 : condT1
19290 // = 1
19292 // condT = newTemp(Ity_I32);
19293 // assign(condT, IRExpr_ITE(
19294 // unop(Iop_32to8, binop(Iop_And32,
19295 // mkexpr(old_itstate),
19296 // mkU32(0xF0))),
19297 // mkexpr(condT1),
19298 // mkU32(1))
19299 // ));
19300 condT = newTemp(Ity_I32);
19301 assign(condT, mkU32(1));
19303 // notInITt = xor32(and32(old_itstate, 1), 1)
19304 // = xor32(and32(0, 1), 1)
19305 // = xor32(0, 1)
19306 // = 1 :: I32
19308 // IRTemp notInITt = newTemp(Ity_I32);
19309 // assign(notInITt,
19310 // binop(Iop_Xor32,
19311 // binop(Iop_And32, mkexpr(old_itstate), mkU32(1)),
19312 // mkU32(1)));
19314 // cond_AND_notInIT_T = and32(notInITt, condT)
19315 // = and32(1, 1)
19316 // = 1
19318 // cond_AND_notInIT_T = newTemp(Ity_I32);
19319 // assign(cond_AND_notInIT_T,
19320 // binop(Iop_And32, mkexpr(notInITt), mkexpr(condT)));
19321 cond_AND_notInIT_T = condT; /* 1 :: I32 */
19323 /* END "partial eval { ITSTATE = 0; STANDARD_PREAMBLE; }" */
19324 } else {
19325 /* BEGIN { STANDARD PREAMBLE; } */
19327 old_itstate = get_ITSTATE();
19329 new_itstate = newTemp(Ity_I32);
19330 assign(new_itstate,
19331 binop(Iop_Shr32, mkexpr(old_itstate), mkU8(8)));
19333 put_ITSTATE(new_itstate);
19335 /* Same strategy as for ARM insns: generate a condition
19336 temporary at this point (or IRTemp_INVALID, meaning
19337 unconditional). We leave it to lower-level instruction
19338 decoders to decide whether they can generate straight-line
19339 code, or whether they must generate a side exit before the
19340 instruction. condT :: Ity_I32 and is always either zero or
19341 one. */
19342 IRTemp condT1 = newTemp(Ity_I32);
19343 assign(condT1,
19344 mk_armg_calculate_condition_dyn(
19345 binop(Iop_Xor32,
19346 binop(Iop_And32, mkexpr(old_itstate), mkU32(0xF0)),
19347 mkU32(0xE0))
19351 /* This is a bit complex, but needed to make Memcheck understand
19352 that, if the condition in old_itstate[7:4] denotes AL (that
19353 is, if this instruction is to be executed unconditionally),
19354 then condT does not depend on the results of calling the
19355 helper.
19357 We test explicitly for old_itstate[7:4] == AL ^ 0xE, and in
19358 that case set condT directly to 1. Else we use the results
19359 of the helper. Since old_itstate is always defined and
19360 because Memcheck does lazy V-bit propagation through ITE,
19361 this will cause condT to always be a defined 1 if the
19362 condition is 'AL'. From an execution semantics point of view
19363 this is irrelevant since we're merely duplicating part of the
19364 behaviour of the helper. But it makes it clear to Memcheck,
19365 in this case, that condT does not in fact depend on the
19366 contents of the condition code thunk. Without it, we get
19367 quite a lot of false errors.
19369 So, just to clarify: from a straight semantics point of view,
19370 we can simply do "assign(condT, mkexpr(condT1))", and the
19371 simulator still runs fine. It's just that we get loads of
19372 false errors from Memcheck. */
19373 condT = newTemp(Ity_I32);
19374 assign(condT, IRExpr_ITE(
19375 binop(Iop_CmpNE32, binop(Iop_And32,
19376 mkexpr(old_itstate),
19377 mkU32(0xF0)),
19378 mkU32(0)),
19379 mkexpr(condT1),
19380 mkU32(1)
19383 /* Something we don't have in ARM: generate a 0 or 1 value
19384 indicating whether or not we are in an IT block (NB: 0 = in
19385 IT block, 1 = not in IT block). This is used to gate
19386 condition code updates in 16-bit Thumb instructions. */
19387 IRTemp notInITt = newTemp(Ity_I32);
19388 assign(notInITt,
19389 binop(Iop_Xor32,
19390 binop(Iop_And32, mkexpr(old_itstate), mkU32(1)),
19391 mkU32(1)));
19393 /* Compute 'condT && notInITt' -- that is, the instruction is
19394 going to execute, and we're not in an IT block. This is the
19395 gating condition for updating condition codes in 16-bit Thumb
19396 instructions, except for CMP, CMN and TST. */
19397 cond_AND_notInIT_T = newTemp(Ity_I32);
19398 assign(cond_AND_notInIT_T,
19399 binop(Iop_And32, mkexpr(notInITt), mkexpr(condT)));
19400 /* END { STANDARD PREAMBLE; } */
19404 /* At this point:
19405 * ITSTATE has been updated
19406 * condT holds the guarding condition for this instruction (0 or 1),
19407 * notInITt is 1 if we're in "normal" code, 0 if in an IT block
19408 * cond_AND_notInIT_T is the AND of the above two.
19410 If the instruction proper can't trap, then there's nothing else
19411 to do w.r.t. ITSTATE -- just go and and generate IR for the
19412 insn, taking into account the guarding condition.
19414 If, however, the instruction might trap, then we must back up
19415 ITSTATE to the old value, and re-update it after the potentially
19416 trapping IR section. A trap can happen either via a memory
19417 reference or because we need to throw SIGILL.
19419 If an instruction has a side exit, we need to be sure that any
19420 ITSTATE backup is re-updated before the side exit.
19423 /* ----------------------------------------------------------- */
19424 /* -- -- */
19425 /* -- Thumb 16-bit integer instructions -- */
19426 /* -- -- */
19427 /* -- IMPORTANT: references to insn1 or INSN1 are -- */
19428 /* -- not allowed in this section -- */
19429 /* -- -- */
19430 /* ----------------------------------------------------------- */
19432 /* 16-bit instructions inside an IT block, apart from CMP, CMN and
19433 TST, do not set the condition codes. Hence we must dynamically
19434 test for this case for every condition code update. */
19436 IROp anOp = Iop_INVALID;
19437 const HChar* anOpNm = NULL;
19439 /* ================ 16-bit 15:6 cases ================ */
19441 switch (INSN0(15,6)) {
19443 case 0x10a: // CMP
19444 case 0x10b: { // CMN
19445 /* ---------------- CMP Rn, Rm ---------------- */
19446 Bool isCMN = INSN0(15,6) == 0x10b;
19447 UInt rN = INSN0(2,0);
19448 UInt rM = INSN0(5,3);
19449 IRTemp argL = newTemp(Ity_I32);
19450 IRTemp argR = newTemp(Ity_I32);
19451 assign( argL, getIRegT(rN) );
19452 assign( argR, getIRegT(rM) );
19453 /* Update flags regardless of whether in an IT block or not. */
19454 setFlags_D1_D2( isCMN ? ARMG_CC_OP_ADD : ARMG_CC_OP_SUB,
19455 argL, argR, condT );
19456 DIP("%s r%u, r%u\n", isCMN ? "cmn" : "cmp", rN, rM);
19457 goto decode_success;
19460 case 0x108: {
19461 /* ---------------- TST Rn, Rm ---------------- */
19462 UInt rN = INSN0(2,0);
19463 UInt rM = INSN0(5,3);
19464 IRTemp oldC = newTemp(Ity_I32);
19465 IRTemp oldV = newTemp(Ity_I32);
19466 IRTemp res = newTemp(Ity_I32);
19467 assign( oldC, mk_armg_calculate_flag_c() );
19468 assign( oldV, mk_armg_calculate_flag_v() );
19469 assign( res, binop(Iop_And32, getIRegT(rN), getIRegT(rM)) );
19470 /* Update flags regardless of whether in an IT block or not. */
19471 setFlags_D1_D2_ND( ARMG_CC_OP_LOGIC, res, oldC, oldV, condT );
19472 DIP("tst r%u, r%u\n", rN, rM);
19473 goto decode_success;
19476 case 0x109: {
19477 /* ---------------- NEGS Rd, Rm ---------------- */
19478 /* Rd = -Rm */
19479 UInt rM = INSN0(5,3);
19480 UInt rD = INSN0(2,0);
19481 IRTemp arg = newTemp(Ity_I32);
19482 IRTemp zero = newTemp(Ity_I32);
19483 assign(arg, getIRegT(rM));
19484 assign(zero, mkU32(0));
19485 // rD can never be r15
19486 putIRegT(rD, binop(Iop_Sub32, mkexpr(zero), mkexpr(arg)), condT);
19487 setFlags_D1_D2( ARMG_CC_OP_SUB, zero, arg, cond_AND_notInIT_T);
19488 DIP("negs r%u, r%u\n", rD, rM);
19489 goto decode_success;
19492 case 0x10F: {
19493 /* ---------------- MVNS Rd, Rm ---------------- */
19494 /* Rd = ~Rm */
19495 UInt rM = INSN0(5,3);
19496 UInt rD = INSN0(2,0);
19497 IRTemp oldV = newTemp(Ity_I32);
19498 IRTemp oldC = newTemp(Ity_I32);
19499 IRTemp res = newTemp(Ity_I32);
19500 assign( oldV, mk_armg_calculate_flag_v() );
19501 assign( oldC, mk_armg_calculate_flag_c() );
19502 assign(res, unop(Iop_Not32, getIRegT(rM)));
19503 // rD can never be r15
19504 putIRegT(rD, mkexpr(res), condT);
19505 setFlags_D1_D2_ND( ARMG_CC_OP_LOGIC, res, oldC, oldV,
19506 cond_AND_notInIT_T );
19507 DIP("mvns r%u, r%u\n", rD, rM);
19508 goto decode_success;
19511 case 0x10C:
19512 /* ---------------- ORRS Rd, Rm ---------------- */
19513 anOp = Iop_Or32; anOpNm = "orr"; goto and_orr_eor_mul;
19514 case 0x100:
19515 /* ---------------- ANDS Rd, Rm ---------------- */
19516 anOp = Iop_And32; anOpNm = "and"; goto and_orr_eor_mul;
19517 case 0x101:
19518 /* ---------------- EORS Rd, Rm ---------------- */
19519 anOp = Iop_Xor32; anOpNm = "eor"; goto and_orr_eor_mul;
19520 case 0x10d:
19521 /* ---------------- MULS Rd, Rm ---------------- */
19522 anOp = Iop_Mul32; anOpNm = "mul"; goto and_orr_eor_mul;
19523 and_orr_eor_mul: {
19524 /* Rd = Rd `op` Rm */
19525 UInt rM = INSN0(5,3);
19526 UInt rD = INSN0(2,0);
19527 IRTemp res = newTemp(Ity_I32);
19528 IRTemp oldV = newTemp(Ity_I32);
19529 IRTemp oldC = newTemp(Ity_I32);
19530 assign( oldV, mk_armg_calculate_flag_v() );
19531 assign( oldC, mk_armg_calculate_flag_c() );
19532 assign( res, binop(anOp, getIRegT(rD), getIRegT(rM) ));
19533 // not safe to read guest state after here
19534 // rD can never be r15
19535 putIRegT(rD, mkexpr(res), condT);
19536 setFlags_D1_D2_ND( ARMG_CC_OP_LOGIC, res, oldC, oldV,
19537 cond_AND_notInIT_T );
19538 DIP("%s r%u, r%u\n", anOpNm, rD, rM);
19539 goto decode_success;
19542 case 0x10E: {
19543 /* ---------------- BICS Rd, Rm ---------------- */
19544 /* Rd = Rd & ~Rm */
19545 UInt rM = INSN0(5,3);
19546 UInt rD = INSN0(2,0);
19547 IRTemp res = newTemp(Ity_I32);
19548 IRTemp oldV = newTemp(Ity_I32);
19549 IRTemp oldC = newTemp(Ity_I32);
19550 assign( oldV, mk_armg_calculate_flag_v() );
19551 assign( oldC, mk_armg_calculate_flag_c() );
19552 assign( res, binop(Iop_And32, getIRegT(rD),
19553 unop(Iop_Not32, getIRegT(rM) )));
19554 // not safe to read guest state after here
19555 // rD can never be r15
19556 putIRegT(rD, mkexpr(res), condT);
19557 setFlags_D1_D2_ND( ARMG_CC_OP_LOGIC, res, oldC, oldV,
19558 cond_AND_notInIT_T );
19559 DIP("bics r%u, r%u\n", rD, rM);
19560 goto decode_success;
19563 case 0x105: {
19564 /* ---------------- ADCS Rd, Rm ---------------- */
19565 /* Rd = Rd + Rm + oldC */
19566 UInt rM = INSN0(5,3);
19567 UInt rD = INSN0(2,0);
19568 IRTemp argL = newTemp(Ity_I32);
19569 IRTemp argR = newTemp(Ity_I32);
19570 IRTemp oldC = newTemp(Ity_I32);
19571 IRTemp res = newTemp(Ity_I32);
19572 assign(argL, getIRegT(rD));
19573 assign(argR, getIRegT(rM));
19574 assign(oldC, mk_armg_calculate_flag_c());
19575 assign(res, binop(Iop_Add32,
19576 binop(Iop_Add32, mkexpr(argL), mkexpr(argR)),
19577 mkexpr(oldC)));
19578 // rD can never be r15
19579 putIRegT(rD, mkexpr(res), condT);
19580 setFlags_D1_D2_ND( ARMG_CC_OP_ADC, argL, argR, oldC,
19581 cond_AND_notInIT_T );
19582 DIP("adcs r%u, r%u\n", rD, rM);
19583 goto decode_success;
19586 case 0x106: {
19587 /* ---------------- SBCS Rd, Rm ---------------- */
19588 /* Rd = Rd - Rm - (oldC ^ 1) */
19589 UInt rM = INSN0(5,3);
19590 UInt rD = INSN0(2,0);
19591 IRTemp argL = newTemp(Ity_I32);
19592 IRTemp argR = newTemp(Ity_I32);
19593 IRTemp oldC = newTemp(Ity_I32);
19594 IRTemp res = newTemp(Ity_I32);
19595 assign(argL, getIRegT(rD));
19596 assign(argR, getIRegT(rM));
19597 assign(oldC, mk_armg_calculate_flag_c());
19598 assign(res, binop(Iop_Sub32,
19599 binop(Iop_Sub32, mkexpr(argL), mkexpr(argR)),
19600 binop(Iop_Xor32, mkexpr(oldC), mkU32(1))));
19601 // rD can never be r15
19602 putIRegT(rD, mkexpr(res), condT);
19603 setFlags_D1_D2_ND( ARMG_CC_OP_SBB, argL, argR, oldC,
19604 cond_AND_notInIT_T );
19605 DIP("sbcs r%u, r%u\n", rD, rM);
19606 goto decode_success;
19609 case 0x2CB: {
19610 /* ---------------- UXTB Rd, Rm ---------------- */
19611 /* Rd = 8Uto32(Rm) */
19612 UInt rM = INSN0(5,3);
19613 UInt rD = INSN0(2,0);
19614 putIRegT(rD, binop(Iop_And32, getIRegT(rM), mkU32(0xFF)),
19615 condT);
19616 DIP("uxtb r%u, r%u\n", rD, rM);
19617 goto decode_success;
19620 case 0x2C9: {
19621 /* ---------------- SXTB Rd, Rm ---------------- */
19622 /* Rd = 8Sto32(Rm) */
19623 UInt rM = INSN0(5,3);
19624 UInt rD = INSN0(2,0);
19625 putIRegT(rD, binop(Iop_Sar32,
19626 binop(Iop_Shl32, getIRegT(rM), mkU8(24)),
19627 mkU8(24)),
19628 condT);
19629 DIP("sxtb r%u, r%u\n", rD, rM);
19630 goto decode_success;
19633 case 0x2CA: {
19634 /* ---------------- UXTH Rd, Rm ---------------- */
19635 /* Rd = 16Uto32(Rm) */
19636 UInt rM = INSN0(5,3);
19637 UInt rD = INSN0(2,0);
19638 putIRegT(rD, binop(Iop_And32, getIRegT(rM), mkU32(0xFFFF)),
19639 condT);
19640 DIP("uxth r%u, r%u\n", rD, rM);
19641 goto decode_success;
19644 case 0x2C8: {
19645 /* ---------------- SXTH Rd, Rm ---------------- */
19646 /* Rd = 16Sto32(Rm) */
19647 UInt rM = INSN0(5,3);
19648 UInt rD = INSN0(2,0);
19649 putIRegT(rD, binop(Iop_Sar32,
19650 binop(Iop_Shl32, getIRegT(rM), mkU8(16)),
19651 mkU8(16)),
19652 condT);
19653 DIP("sxth r%u, r%u\n", rD, rM);
19654 goto decode_success;
19657 case 0x102: // LSLS
19658 case 0x103: // LSRS
19659 case 0x104: // ASRS
19660 case 0x107: { // RORS
19661 /* ---------------- LSLS Rs, Rd ---------------- */
19662 /* ---------------- LSRS Rs, Rd ---------------- */
19663 /* ---------------- ASRS Rs, Rd ---------------- */
19664 /* ---------------- RORS Rs, Rd ---------------- */
19665 /* Rd = Rd `op` Rs, and set flags */
19666 UInt rS = INSN0(5,3);
19667 UInt rD = INSN0(2,0);
19668 IRTemp oldV = newTemp(Ity_I32);
19669 IRTemp rDt = newTemp(Ity_I32);
19670 IRTemp rSt = newTemp(Ity_I32);
19671 IRTemp res = newTemp(Ity_I32);
19672 IRTemp resC = newTemp(Ity_I32);
19673 const HChar* wot = "???";
19674 assign(rSt, getIRegT(rS));
19675 assign(rDt, getIRegT(rD));
19676 assign(oldV, mk_armg_calculate_flag_v());
19677 /* Does not appear to be the standard 'how' encoding. */
19678 switch (INSN0(15,6)) {
19679 case 0x102:
19680 compute_result_and_C_after_LSL_by_reg(
19681 dis_buf, &res, &resC, rDt, rSt, rD, rS
19683 wot = "lsl";
19684 break;
19685 case 0x103:
19686 compute_result_and_C_after_LSR_by_reg(
19687 dis_buf, &res, &resC, rDt, rSt, rD, rS
19689 wot = "lsr";
19690 break;
19691 case 0x104:
19692 compute_result_and_C_after_ASR_by_reg(
19693 dis_buf, &res, &resC, rDt, rSt, rD, rS
19695 wot = "asr";
19696 break;
19697 case 0x107:
19698 compute_result_and_C_after_ROR_by_reg(
19699 dis_buf, &res, &resC, rDt, rSt, rD, rS
19701 wot = "ror";
19702 break;
19703 default:
19704 /*NOTREACHED*/vassert(0);
19706 // not safe to read guest state after this point
19707 putIRegT(rD, mkexpr(res), condT);
19708 setFlags_D1_D2_ND( ARMG_CC_OP_LOGIC, res, resC, oldV,
19709 cond_AND_notInIT_T );
19710 DIP("%ss r%u, r%u\n", wot, rS, rD);
19711 goto decode_success;
19714 case 0x2E8: // REV
19715 case 0x2E9: { // REV16
19716 /* ---------------- REV Rd, Rm ---------------- */
19717 /* ---------------- REV16 Rd, Rm ---------------- */
19718 UInt rM = INSN0(5,3);
19719 UInt rD = INSN0(2,0);
19720 Bool isREV = INSN0(15,6) == 0x2E8;
19721 IRTemp arg = newTemp(Ity_I32);
19722 assign(arg, getIRegT(rM));
19723 IRTemp res = isREV ? gen_REV(arg) : gen_REV16(arg);
19724 putIRegT(rD, mkexpr(res), condT);
19725 DIP("rev%s r%u, r%u\n", isREV ? "" : "16", rD, rM);
19726 goto decode_success;
19729 case 0x2EB: { // REVSH
19730 /* ---------------- REVSH Rd, Rn ---------------- */
19731 UInt rM = INSN0(5,3);
19732 UInt rD = INSN0(2,0);
19733 IRTemp irt_rM = newTemp(Ity_I32);
19734 IRTemp irt_hi = newTemp(Ity_I32);
19735 IRTemp irt_low = newTemp(Ity_I32);
19736 IRTemp irt_res = newTemp(Ity_I32);
19737 assign(irt_rM, getIRegT(rM));
19738 assign(irt_hi,
19739 binop(Iop_Sar32,
19740 binop(Iop_Shl32, mkexpr(irt_rM), mkU8(24)),
19741 mkU8(16)
19744 assign(irt_low,
19745 binop(Iop_And32,
19746 binop(Iop_Shr32, mkexpr(irt_rM), mkU8(8)),
19747 mkU32(0xFF)
19750 assign(irt_res,
19751 binop(Iop_Or32, mkexpr(irt_hi), mkexpr(irt_low))
19753 putIRegT(rD, mkexpr(irt_res), condT);
19754 DIP("revsh r%u, r%u\n", rD, rM);
19755 goto decode_success;
19758 default:
19759 break; /* examine the next shortest prefix */
19764 /* ================ 16-bit 15:7 cases ================ */
19766 switch (INSN0(15,7)) {
19768 case BITS9(1,0,1,1,0,0,0,0,0): {
19769 /* ------------ ADD SP, #imm7 * 4 ------------ */
19770 UInt uimm7 = INSN0(6,0);
19771 putIRegT(13, binop(Iop_Add32, getIRegT(13), mkU32(uimm7 * 4)),
19772 condT);
19773 DIP("add sp, #%u\n", uimm7 * 4);
19774 goto decode_success;
19777 case BITS9(1,0,1,1,0,0,0,0,1): {
19778 /* ------------ SUB SP, #imm7 * 4 ------------ */
19779 UInt uimm7 = INSN0(6,0);
19780 putIRegT(13, binop(Iop_Sub32, getIRegT(13), mkU32(uimm7 * 4)),
19781 condT);
19782 DIP("sub sp, #%u\n", uimm7 * 4);
19783 goto decode_success;
19786 case BITS9(0,1,0,0,0,1,1,1,0): {
19787 /* ---------------- BX rM ---------------- */
19788 /* Branch to reg, and optionally switch modes. Reg contains a
19789 suitably encoded address therefore (w CPSR.T at the bottom).
19790 Have to special-case r15, as usual. */
19791 UInt rM = (INSN0(6,6) << 3) | INSN0(5,3);
19792 if (BITS3(0,0,0) == INSN0(2,0)) {
19793 IRTemp dst = newTemp(Ity_I32);
19794 gen_SIGILL_T_if_in_but_NLI_ITBlock(old_itstate, new_itstate);
19795 mk_skip_over_T16_if_cond_is_false(condT);
19796 condT = IRTemp_INVALID;
19797 // now uncond
19798 if (rM <= 14) {
19799 assign( dst, getIRegT(rM) );
19800 } else {
19801 vassert(rM == 15);
19802 assign( dst, mkU32(guest_R15_curr_instr_notENC + 4) );
19804 llPutIReg(15, mkexpr(dst));
19805 dres.jk_StopHere = rM == 14 ? Ijk_Ret : Ijk_Boring;
19806 dres.whatNext = Dis_StopHere;
19807 DIP("bx r%u (possibly switch to ARM mode)\n", rM);
19808 goto decode_success;
19810 break;
19813 /* ---------------- BLX rM ---------------- */
19814 /* Branch and link to interworking address in rM. */
19815 case BITS9(0,1,0,0,0,1,1,1,1): {
19816 if (BITS3(0,0,0) == INSN0(2,0)) {
19817 UInt rM = (INSN0(6,6) << 3) | INSN0(5,3);
19818 IRTemp dst = newTemp(Ity_I32);
19819 if (rM <= 14) {
19820 gen_SIGILL_T_if_in_but_NLI_ITBlock(old_itstate, new_itstate);
19821 mk_skip_over_T16_if_cond_is_false(condT);
19822 condT = IRTemp_INVALID;
19823 // now uncond
19824 /* We're returning to Thumb code, hence "| 1" */
19825 assign( dst, getIRegT(rM) );
19826 putIRegT( 14, mkU32( (guest_R15_curr_instr_notENC + 2) | 1 ),
19827 IRTemp_INVALID );
19828 llPutIReg(15, mkexpr(dst));
19829 dres.jk_StopHere = Ijk_Call;
19830 dres.whatNext = Dis_StopHere;
19831 DIP("blx r%u (possibly switch to ARM mode)\n", rM);
19832 goto decode_success;
19834 /* else unpredictable, fall through */
19836 break;
19839 default:
19840 break; /* examine the next shortest prefix */
19845 /* ================ 16-bit 15:8 cases ================ */
19847 switch (INSN0(15,8)) {
19849 case BITS8(1,1,0,1,1,1,1,1): {
19850 /* ---------------- SVC ---------------- */
19851 UInt imm8 = INSN0(7,0);
19852 if (imm8 == 0) {
19853 /* A syscall. We can't do this conditionally, hence: */
19854 mk_skip_over_T16_if_cond_is_false( condT );
19855 // FIXME: what if we have to back up and restart this insn?
19856 // then ITSTATE will be wrong (we'll have it as "used")
19857 // when it isn't. Correct is to save ITSTATE in a
19858 // stash pseudo-reg, and back up from that if we have to
19859 // restart.
19860 // uncond after here
19861 llPutIReg(15, mkU32( (guest_R15_curr_instr_notENC + 2) | 1 ));
19862 dres.jk_StopHere = Ijk_Sys_syscall;
19863 dres.whatNext = Dis_StopHere;
19864 DIP("svc #0x%08x\n", imm8);
19865 goto decode_success;
19867 /* else fall through */
19868 break;
19871 case BITS8(0,1,0,0,0,1,0,0): {
19872 /* ---------------- ADD(HI) Rd, Rm ---------------- */
19873 UInt h1 = INSN0(7,7);
19874 UInt h2 = INSN0(6,6);
19875 UInt rM = (h2 << 3) | INSN0(5,3);
19876 UInt rD = (h1 << 3) | INSN0(2,0);
19877 //if (h1 == 0 && h2 == 0) { // Original T1 was more restrictive
19878 if (rD == 15 && rM == 15) {
19879 // then it's invalid
19880 } else {
19881 IRTemp res = newTemp(Ity_I32);
19882 assign( res, binop(Iop_Add32, getIRegT(rD), getIRegT(rM) ));
19883 if (rD != 15) {
19884 putIRegT( rD, mkexpr(res), condT );
19885 } else {
19886 /* Only allowed outside or last-in IT block; SIGILL if not so. */
19887 gen_SIGILL_T_if_in_but_NLI_ITBlock(old_itstate, new_itstate);
19888 /* jump over insn if not selected */
19889 mk_skip_over_T16_if_cond_is_false(condT);
19890 condT = IRTemp_INVALID;
19891 // now uncond
19892 /* non-interworking branch */
19893 llPutIReg(15, binop(Iop_Or32, mkexpr(res), mkU32(1)));
19894 dres.jk_StopHere = Ijk_Boring;
19895 dres.whatNext = Dis_StopHere;
19897 DIP("add(hi) r%u, r%u\n", rD, rM);
19898 goto decode_success;
19900 break;
19903 case BITS8(0,1,0,0,0,1,0,1): {
19904 /* ---------------- CMP(HI) Rd, Rm ---------------- */
19905 UInt h1 = INSN0(7,7);
19906 UInt h2 = INSN0(6,6);
19907 UInt rM = (h2 << 3) | INSN0(5,3);
19908 UInt rN = (h1 << 3) | INSN0(2,0);
19909 if (h1 != 0 || h2 != 0) {
19910 IRTemp argL = newTemp(Ity_I32);
19911 IRTemp argR = newTemp(Ity_I32);
19912 assign( argL, getIRegT(rN) );
19913 assign( argR, getIRegT(rM) );
19914 /* Update flags regardless of whether in an IT block or not. */
19915 setFlags_D1_D2( ARMG_CC_OP_SUB, argL, argR, condT );
19916 DIP("cmphi r%u, r%u\n", rN, rM);
19917 goto decode_success;
19919 break;
19922 case BITS8(0,1,0,0,0,1,1,0): {
19923 /* ---------------- MOV(HI) Rd, Rm ---------------- */
19924 UInt h1 = INSN0(7,7);
19925 UInt h2 = INSN0(6,6);
19926 UInt rM = (h2 << 3) | INSN0(5,3);
19927 UInt rD = (h1 << 3) | INSN0(2,0);
19928 /* The old ARM ARM seems to disallow the case where both Rd and
19929 Rm are "low" registers, but newer versions allow it. */
19930 if (1 /*h1 != 0 || h2 != 0*/) {
19931 IRTemp val = newTemp(Ity_I32);
19932 assign( val, getIRegT(rM) );
19933 if (rD != 15) {
19934 putIRegT( rD, mkexpr(val), condT );
19935 } else {
19936 /* Only allowed outside or last-in IT block; SIGILL if not so. */
19937 gen_SIGILL_T_if_in_but_NLI_ITBlock(old_itstate, new_itstate);
19938 /* jump over insn if not selected */
19939 mk_skip_over_T16_if_cond_is_false(condT);
19940 condT = IRTemp_INVALID;
19941 // now uncond
19942 /* non-interworking branch */
19943 llPutIReg(15, binop(Iop_Or32, mkexpr(val), mkU32(1)));
19944 dres.jk_StopHere = rM == 14 ? Ijk_Ret : Ijk_Boring;
19945 dres.whatNext = Dis_StopHere;
19947 DIP("mov r%u, r%u\n", rD, rM);
19948 goto decode_success;
19950 break;
19953 case BITS8(1,0,1,1,1,1,1,1): {
19954 /* ---------------- IT (if-then) ---------------- */
19955 UInt firstcond = INSN0(7,4);
19956 UInt mask = INSN0(3,0);
19957 UInt newITSTATE = 0;
19958 /* This is the ITSTATE represented as described in
19959 libvex_guest_arm.h. It is not the ARM ARM representation. */
19960 HChar c1 = '.';
19961 HChar c2 = '.';
19962 HChar c3 = '.';
19963 Bool valid = compute_ITSTATE( &newITSTATE, &c1, &c2, &c3,
19964 firstcond, mask );
19965 if (valid && firstcond != 0xF/*NV*/) {
19966 /* Not allowed in an IT block; SIGILL if so. */
19967 gen_SIGILL_T_if_in_ITBlock(old_itstate, new_itstate);
19969 IRTemp t = newTemp(Ity_I32);
19970 assign(t, mkU32(newITSTATE));
19971 put_ITSTATE(t);
19973 DIP("it%c%c%c %s\n", c1, c2, c3, nCC(firstcond));
19974 goto decode_success;
19976 break;
19979 case BITS8(1,0,1,1,0,0,0,1):
19980 case BITS8(1,0,1,1,0,0,1,1):
19981 case BITS8(1,0,1,1,1,0,0,1):
19982 case BITS8(1,0,1,1,1,0,1,1): {
19983 /* ---------------- CB{N}Z ---------------- */
19984 UInt rN = INSN0(2,0);
19985 UInt bOP = INSN0(11,11);
19986 UInt imm32 = (INSN0(9,9) << 6) | (INSN0(7,3) << 1);
19987 gen_SIGILL_T_if_in_ITBlock(old_itstate, new_itstate);
19988 /* It's a conditional branch forward. */
19989 IRTemp kond = newTemp(Ity_I1);
19990 assign( kond, binop(bOP ? Iop_CmpNE32 : Iop_CmpEQ32,
19991 getIRegT(rN), mkU32(0)) );
19993 vassert(0 == (guest_R15_curr_instr_notENC & 1));
19994 /* Looks like the nearest insn we can branch to is the one after
19995 next. That makes sense, as there's no point in being able to
19996 encode a conditional branch to the next instruction. */
19997 UInt dst = (guest_R15_curr_instr_notENC + 4 + imm32) | 1;
19998 stmt(IRStmt_Exit( mkexpr(kond),
19999 Ijk_Boring,
20000 IRConst_U32(toUInt(dst)),
20001 OFFB_R15T ));
20002 DIP("cb%s r%u, 0x%x\n", bOP ? "nz" : "z", rN, dst - 1);
20003 goto decode_success;
20006 default:
20007 break; /* examine the next shortest prefix */
20012 /* ================ 16-bit 15:9 cases ================ */
20014 switch (INSN0(15,9)) {
20016 case BITS7(1,0,1,1,0,1,0): {
20017 /* ---------------- PUSH ---------------- */
20018 /* This is a bit like STMxx, but way simpler. Complications we
20019 don't have to deal with:
20020 * SP being one of the transferred registers
20021 * direction (increment vs decrement)
20022 * before-vs-after-ness
20024 Int i, nRegs;
20025 UInt bitR = INSN0(8,8);
20026 UInt regList = INSN0(7,0);
20027 if (bitR) regList |= (1 << 14);
20029 /* At least one register must be transferred, else result is
20030 UNPREDICTABLE. */
20031 if (regList != 0) {
20032 /* Since we can't generate a guaranteed non-trapping IR
20033 sequence, (1) jump over the insn if it is gated false, and
20034 (2) back out the ITSTATE update. */
20035 mk_skip_over_T16_if_cond_is_false(condT);
20036 condT = IRTemp_INVALID;
20037 put_ITSTATE(old_itstate);
20038 // now uncond
20040 nRegs = 0;
20041 for (i = 0; i < 16; i++) {
20042 if ((regList & (1 << i)) != 0)
20043 nRegs++;
20045 vassert(nRegs >= 1 && nRegs <= 9);
20047 /* Move SP down first of all, so we're "covered". And don't
20048 mess with its alignment. */
20049 IRTemp newSP = newTemp(Ity_I32);
20050 assign(newSP, binop(Iop_Sub32, getIRegT(13), mkU32(4 * nRegs)));
20051 putIRegT(13, mkexpr(newSP), IRTemp_INVALID);
20053 /* Generate a transfer base address as a forced-aligned
20054 version of the final SP value. */
20055 IRTemp base = newTemp(Ity_I32);
20056 assign(base, binop(Iop_And32, mkexpr(newSP), mkU32(~3)));
20058 /* Now the transfers */
20059 nRegs = 0;
20060 for (i = 0; i < 16; i++) {
20061 if ((regList & (1 << i)) != 0) {
20062 storeLE( binop(Iop_Add32, mkexpr(base), mkU32(4 * nRegs)),
20063 getIRegT(i) );
20064 nRegs++;
20068 /* Reinstate the ITSTATE update. */
20069 put_ITSTATE(new_itstate);
20071 DIP("push {%s0x%04x}\n", bitR ? "lr," : "", regList & 0xFF);
20072 goto decode_success;
20074 break;
20077 case BITS7(1,0,1,1,1,1,0): {
20078 /* ---------------- POP ---------------- */
20079 Int i, nRegs;
20080 UInt bitR = INSN0(8,8);
20081 UInt regList = INSN0(7,0);
20083 /* At least one register must be transferred, else result is
20084 UNPREDICTABLE. */
20085 if (regList != 0 || bitR) {
20086 /* Since we can't generate a guaranteed non-trapping IR
20087 sequence, (1) jump over the insn if it is gated false, and
20088 (2) back out the ITSTATE update. */
20089 mk_skip_over_T16_if_cond_is_false(condT);
20090 condT = IRTemp_INVALID;
20091 put_ITSTATE(old_itstate);
20092 // now uncond
20094 nRegs = 0;
20095 for (i = 0; i < 8; i++) {
20096 if ((regList & (1 << i)) != 0)
20097 nRegs++;
20099 vassert(nRegs >= 0 && nRegs <= 8);
20100 vassert(bitR == 0 || bitR == 1);
20102 IRTemp oldSP = newTemp(Ity_I32);
20103 assign(oldSP, getIRegT(13));
20105 /* Generate a transfer base address as a forced-aligned
20106 version of the original SP value. */
20107 IRTemp base = newTemp(Ity_I32);
20108 assign(base, binop(Iop_And32, mkexpr(oldSP), mkU32(~3)));
20110 /* Compute a new value for SP, but don't install it yet, so
20111 that we're "covered" until all the transfers are done.
20112 And don't mess with its alignment. */
20113 IRTemp newSP = newTemp(Ity_I32);
20114 assign(newSP, binop(Iop_Add32, mkexpr(oldSP),
20115 mkU32(4 * (nRegs + bitR))));
20117 /* Now the transfers, not including PC */
20118 nRegs = 0;
20119 for (i = 0; i < 8; i++) {
20120 if ((regList & (1 << i)) != 0) {
20121 putIRegT(i, loadLE( Ity_I32,
20122 binop(Iop_Add32, mkexpr(base),
20123 mkU32(4 * nRegs))),
20124 IRTemp_INVALID );
20125 nRegs++;
20129 IRTemp newPC = IRTemp_INVALID;
20130 if (bitR) {
20131 newPC = newTemp(Ity_I32);
20132 assign( newPC, loadLE( Ity_I32,
20133 binop(Iop_Add32, mkexpr(base),
20134 mkU32(4 * nRegs))));
20137 /* Now we can safely install the new SP value */
20138 putIRegT(13, mkexpr(newSP), IRTemp_INVALID);
20140 /* Reinstate the ITSTATE update. */
20141 put_ITSTATE(new_itstate);
20143 /* now, do we also have to do a branch? If so, it turns out
20144 that the new PC value is encoded exactly as we need it to
20145 be -- with CPSR.T in the bottom bit. So we can simply use
20146 it as is, no need to mess with it. Note, therefore, this
20147 is an interworking return. */
20148 if (bitR) {
20149 llPutIReg(15, mkexpr(newPC));
20150 dres.jk_StopHere = Ijk_Ret;
20151 dres.whatNext = Dis_StopHere;
20154 DIP("pop {%s0x%04x}\n", bitR ? "pc," : "", regList & 0xFF);
20155 goto decode_success;
20157 break;
20160 case BITS7(0,0,0,1,1,1,0): /* ADDS */
20161 case BITS7(0,0,0,1,1,1,1): { /* SUBS */
20162 /* ---------------- ADDS Rd, Rn, #uimm3 ---------------- */
20163 /* ---------------- SUBS Rd, Rn, #uimm3 ---------------- */
20164 UInt uimm3 = INSN0(8,6);
20165 UInt rN = INSN0(5,3);
20166 UInt rD = INSN0(2,0);
20167 UInt isSub = INSN0(9,9);
20168 IRTemp argL = newTemp(Ity_I32);
20169 IRTemp argR = newTemp(Ity_I32);
20170 assign( argL, getIRegT(rN) );
20171 assign( argR, mkU32(uimm3) );
20172 putIRegT(rD, binop(isSub ? Iop_Sub32 : Iop_Add32,
20173 mkexpr(argL), mkexpr(argR)),
20174 condT);
20175 setFlags_D1_D2( isSub ? ARMG_CC_OP_SUB : ARMG_CC_OP_ADD,
20176 argL, argR, cond_AND_notInIT_T );
20177 DIP("%s r%u, r%u, #%u\n", isSub ? "subs" : "adds", rD, rN, uimm3);
20178 goto decode_success;
20181 case BITS7(0,0,0,1,1,0,0): /* ADDS */
20182 case BITS7(0,0,0,1,1,0,1): { /* SUBS */
20183 /* ---------------- ADDS Rd, Rn, Rm ---------------- */
20184 /* ---------------- SUBS Rd, Rn, Rm ---------------- */
20185 UInt rM = INSN0(8,6);
20186 UInt rN = INSN0(5,3);
20187 UInt rD = INSN0(2,0);
20188 UInt isSub = INSN0(9,9);
20189 IRTemp argL = newTemp(Ity_I32);
20190 IRTemp argR = newTemp(Ity_I32);
20191 assign( argL, getIRegT(rN) );
20192 assign( argR, getIRegT(rM) );
20193 putIRegT( rD, binop(isSub ? Iop_Sub32 : Iop_Add32,
20194 mkexpr(argL), mkexpr(argR)),
20195 condT );
20196 setFlags_D1_D2( isSub ? ARMG_CC_OP_SUB : ARMG_CC_OP_ADD,
20197 argL, argR, cond_AND_notInIT_T );
20198 DIP("%s r%u, r%u, r%u\n", isSub ? "subs" : "adds", rD, rN, rM);
20199 goto decode_success;
20202 case BITS7(0,1,0,1,0,0,0): /* STR */
20203 case BITS7(0,1,0,1,1,0,0): { /* LDR */
20204 /* ------------- LDR Rd, [Rn, Rm] ------------- */
20205 /* ------------- STR Rd, [Rn, Rm] ------------- */
20206 /* LDR/STR Rd, [Rn + Rm] */
20207 UInt rD = INSN0(2,0);
20208 UInt rN = INSN0(5,3);
20209 UInt rM = INSN0(8,6);
20210 UInt isLD = INSN0(11,11);
20212 IRExpr* ea = binop(Iop_Add32, getIRegT(rN), getIRegT(rM));
20213 put_ITSTATE(old_itstate); // backout
20214 if (isLD) {
20215 IRTemp tD = newTemp(Ity_I32);
20216 loadGuardedLE( tD, ILGop_Ident32, ea, llGetIReg(rD), condT );
20217 putIRegT(rD, mkexpr(tD), IRTemp_INVALID);
20218 } else {
20219 storeGuardedLE(ea, getIRegT(rD), condT);
20221 put_ITSTATE(new_itstate); // restore
20223 DIP("%s r%u, [r%u, r%u]\n", isLD ? "ldr" : "str", rD, rN, rM);
20224 goto decode_success;
20227 case BITS7(0,1,0,1,0,0,1):
20228 case BITS7(0,1,0,1,1,0,1): {
20229 /* ------------- LDRH Rd, [Rn, Rm] ------------- */
20230 /* ------------- STRH Rd, [Rn, Rm] ------------- */
20231 /* LDRH/STRH Rd, [Rn + Rm] */
20232 UInt rD = INSN0(2,0);
20233 UInt rN = INSN0(5,3);
20234 UInt rM = INSN0(8,6);
20235 UInt isLD = INSN0(11,11);
20237 IRExpr* ea = binop(Iop_Add32, getIRegT(rN), getIRegT(rM));
20238 put_ITSTATE(old_itstate); // backout
20239 if (isLD) {
20240 IRTemp tD = newTemp(Ity_I32);
20241 loadGuardedLE(tD, ILGop_16Uto32, ea, llGetIReg(rD), condT);
20242 putIRegT(rD, mkexpr(tD), IRTemp_INVALID);
20243 } else {
20244 storeGuardedLE( ea, unop(Iop_32to16, getIRegT(rD)), condT );
20246 put_ITSTATE(new_itstate); // restore
20248 DIP("%sh r%u, [r%u, r%u]\n", isLD ? "ldr" : "str", rD, rN, rM);
20249 goto decode_success;
20252 case BITS7(0,1,0,1,1,1,1): {
20253 /* ------------- LDRSH Rd, [Rn, Rm] ------------- */
20254 /* LDRSH Rd, [Rn + Rm] */
20255 UInt rD = INSN0(2,0);
20256 UInt rN = INSN0(5,3);
20257 UInt rM = INSN0(8,6);
20259 IRExpr* ea = binop(Iop_Add32, getIRegT(rN), getIRegT(rM));
20260 put_ITSTATE(old_itstate); // backout
20261 IRTemp tD = newTemp(Ity_I32);
20262 loadGuardedLE(tD, ILGop_16Sto32, ea, llGetIReg(rD), condT);
20263 putIRegT(rD, mkexpr(tD), IRTemp_INVALID);
20264 put_ITSTATE(new_itstate); // restore
20266 DIP("ldrsh r%u, [r%u, r%u]\n", rD, rN, rM);
20267 goto decode_success;
20270 case BITS7(0,1,0,1,0,1,1): {
20271 /* ------------- LDRSB Rd, [Rn, Rm] ------------- */
20272 /* LDRSB Rd, [Rn + Rm] */
20273 UInt rD = INSN0(2,0);
20274 UInt rN = INSN0(5,3);
20275 UInt rM = INSN0(8,6);
20277 IRExpr* ea = binop(Iop_Add32, getIRegT(rN), getIRegT(rM));
20278 put_ITSTATE(old_itstate); // backout
20279 IRTemp tD = newTemp(Ity_I32);
20280 loadGuardedLE(tD, ILGop_8Sto32, ea, llGetIReg(rD), condT);
20281 putIRegT(rD, mkexpr(tD), IRTemp_INVALID);
20282 put_ITSTATE(new_itstate); // restore
20284 DIP("ldrsb r%u, [r%u, r%u]\n", rD, rN, rM);
20285 goto decode_success;
20288 case BITS7(0,1,0,1,0,1,0):
20289 case BITS7(0,1,0,1,1,1,0): {
20290 /* ------------- LDRB Rd, [Rn, Rm] ------------- */
20291 /* ------------- STRB Rd, [Rn, Rm] ------------- */
20292 /* LDRB/STRB Rd, [Rn + Rm] */
20293 UInt rD = INSN0(2,0);
20294 UInt rN = INSN0(5,3);
20295 UInt rM = INSN0(8,6);
20296 UInt isLD = INSN0(11,11);
20298 IRExpr* ea = binop(Iop_Add32, getIRegT(rN), getIRegT(rM));
20299 put_ITSTATE(old_itstate); // backout
20300 if (isLD) {
20301 IRTemp tD = newTemp(Ity_I32);
20302 loadGuardedLE(tD, ILGop_8Uto32, ea, llGetIReg(rD), condT);
20303 putIRegT(rD, mkexpr(tD), IRTemp_INVALID);
20304 } else {
20305 storeGuardedLE( ea, unop(Iop_32to8, getIRegT(rD)), condT );
20307 put_ITSTATE(new_itstate); // restore
20309 DIP("%sb r%u, [r%u, r%u]\n", isLD ? "ldr" : "str", rD, rN, rM);
20310 goto decode_success;
20313 default:
20314 break; /* examine the next shortest prefix */
20319 /* ================ 16-bit 15:11 cases ================ */
20321 switch (INSN0(15,11)) {
20323 case BITS5(0,0,1,1,0):
20324 case BITS5(0,0,1,1,1): {
20325 /* ---------------- ADDS Rn, #uimm8 ---------------- */
20326 /* ---------------- SUBS Rn, #uimm8 ---------------- */
20327 UInt isSub = INSN0(11,11);
20328 UInt rN = INSN0(10,8);
20329 UInt uimm8 = INSN0(7,0);
20330 IRTemp argL = newTemp(Ity_I32);
20331 IRTemp argR = newTemp(Ity_I32);
20332 assign( argL, getIRegT(rN) );
20333 assign( argR, mkU32(uimm8) );
20334 putIRegT( rN, binop(isSub ? Iop_Sub32 : Iop_Add32,
20335 mkexpr(argL), mkexpr(argR)), condT );
20336 setFlags_D1_D2( isSub ? ARMG_CC_OP_SUB : ARMG_CC_OP_ADD,
20337 argL, argR, cond_AND_notInIT_T );
20338 DIP("%s r%u, #%u\n", isSub ? "subs" : "adds", rN, uimm8);
20339 goto decode_success;
20342 case BITS5(1,0,1,0,0): {
20343 /* ---------------- ADD rD, PC, #imm8 * 4 ---------------- */
20344 /* a.k.a. ADR */
20345 /* rD = align4(PC) + imm8 * 4 */
20346 UInt rD = INSN0(10,8);
20347 UInt imm8 = INSN0(7,0);
20348 putIRegT(rD, binop(Iop_Add32,
20349 binop(Iop_And32, getIRegT(15), mkU32(~3U)),
20350 mkU32(imm8 * 4)),
20351 condT);
20352 DIP("add r%u, pc, #%u\n", rD, imm8 * 4);
20353 goto decode_success;
20356 case BITS5(1,0,1,0,1): {
20357 /* ---------------- ADD rD, SP, #imm8 * 4 ---------------- */
20358 UInt rD = INSN0(10,8);
20359 UInt imm8 = INSN0(7,0);
20360 putIRegT(rD, binop(Iop_Add32, getIRegT(13), mkU32(imm8 * 4)),
20361 condT);
20362 DIP("add r%u, r13, #%u\n", rD, imm8 * 4);
20363 goto decode_success;
20366 case BITS5(0,0,1,0,1): {
20367 /* ---------------- CMP Rn, #uimm8 ---------------- */
20368 UInt rN = INSN0(10,8);
20369 UInt uimm8 = INSN0(7,0);
20370 IRTemp argL = newTemp(Ity_I32);
20371 IRTemp argR = newTemp(Ity_I32);
20372 assign( argL, getIRegT(rN) );
20373 assign( argR, mkU32(uimm8) );
20374 /* Update flags regardless of whether in an IT block or not. */
20375 setFlags_D1_D2( ARMG_CC_OP_SUB, argL, argR, condT );
20376 DIP("cmp r%u, #%u\n", rN, uimm8);
20377 goto decode_success;
20380 case BITS5(0,0,1,0,0): {
20381 /* -------------- (T1) MOVS Rn, #uimm8 -------------- */
20382 UInt rD = INSN0(10,8);
20383 UInt uimm8 = INSN0(7,0);
20384 IRTemp oldV = newTemp(Ity_I32);
20385 IRTemp oldC = newTemp(Ity_I32);
20386 IRTemp res = newTemp(Ity_I32);
20387 assign( oldV, mk_armg_calculate_flag_v() );
20388 assign( oldC, mk_armg_calculate_flag_c() );
20389 assign( res, mkU32(uimm8) );
20390 putIRegT(rD, mkexpr(res), condT);
20391 setFlags_D1_D2_ND( ARMG_CC_OP_LOGIC, res, oldC, oldV,
20392 cond_AND_notInIT_T );
20393 DIP("movs r%u, #%u\n", rD, uimm8);
20394 goto decode_success;
20397 case BITS5(0,1,0,0,1): {
20398 /* ------------- LDR Rd, [PC, #imm8 * 4] ------------- */
20399 /* LDR Rd, [align4(PC) + imm8 * 4] */
20400 UInt rD = INSN0(10,8);
20401 UInt imm8 = INSN0(7,0);
20402 IRTemp ea = newTemp(Ity_I32);
20404 assign(ea, binop(Iop_Add32,
20405 binop(Iop_And32, getIRegT(15), mkU32(~3U)),
20406 mkU32(imm8 * 4)));
20407 put_ITSTATE(old_itstate); // backout
20408 IRTemp tD = newTemp(Ity_I32);
20409 loadGuardedLE( tD, ILGop_Ident32, mkexpr(ea), llGetIReg(rD), condT );
20410 putIRegT(rD, mkexpr(tD), IRTemp_INVALID);
20411 put_ITSTATE(new_itstate); // restore
20413 DIP("ldr r%u, [pc, #%u]\n", rD, imm8 * 4);
20414 goto decode_success;
20417 case BITS5(0,1,1,0,0): /* STR */
20418 case BITS5(0,1,1,0,1): { /* LDR */
20419 /* ------------- LDR Rd, [Rn, #imm5 * 4] ------------- */
20420 /* ------------- STR Rd, [Rn, #imm5 * 4] ------------- */
20421 /* LDR/STR Rd, [Rn + imm5 * 4] */
20422 UInt rD = INSN0(2,0);
20423 UInt rN = INSN0(5,3);
20424 UInt imm5 = INSN0(10,6);
20425 UInt isLD = INSN0(11,11);
20427 IRExpr* ea = binop(Iop_Add32, getIRegT(rN), mkU32(imm5 * 4));
20428 put_ITSTATE(old_itstate); // backout
20429 if (isLD) {
20430 IRTemp tD = newTemp(Ity_I32);
20431 loadGuardedLE( tD, ILGop_Ident32, ea, llGetIReg(rD), condT );
20432 putIRegT(rD, mkexpr(tD), IRTemp_INVALID);
20433 } else {
20434 storeGuardedLE( ea, getIRegT(rD), condT );
20436 put_ITSTATE(new_itstate); // restore
20438 DIP("%s r%u, [r%u, #%u]\n", isLD ? "ldr" : "str", rD, rN, imm5 * 4);
20439 goto decode_success;
20442 case BITS5(1,0,0,0,0): /* STRH */
20443 case BITS5(1,0,0,0,1): { /* LDRH */
20444 /* ------------- LDRH Rd, [Rn, #imm5 * 2] ------------- */
20445 /* ------------- STRH Rd, [Rn, #imm5 * 2] ------------- */
20446 /* LDRH/STRH Rd, [Rn + imm5 * 2] */
20447 UInt rD = INSN0(2,0);
20448 UInt rN = INSN0(5,3);
20449 UInt imm5 = INSN0(10,6);
20450 UInt isLD = INSN0(11,11);
20452 IRExpr* ea = binop(Iop_Add32, getIRegT(rN), mkU32(imm5 * 2));
20453 put_ITSTATE(old_itstate); // backout
20454 if (isLD) {
20455 IRTemp tD = newTemp(Ity_I32);
20456 loadGuardedLE( tD, ILGop_16Uto32, ea, llGetIReg(rD), condT );
20457 putIRegT(rD, mkexpr(tD), IRTemp_INVALID);
20458 } else {
20459 storeGuardedLE( ea, unop(Iop_32to16, getIRegT(rD)), condT );
20461 put_ITSTATE(new_itstate); // restore
20463 DIP("%sh r%u, [r%u, #%u]\n", isLD ? "ldr" : "str", rD, rN, imm5 * 2);
20464 goto decode_success;
20467 case BITS5(0,1,1,1,0): /* STRB */
20468 case BITS5(0,1,1,1,1): { /* LDRB */
20469 /* ------------- LDRB Rd, [Rn, #imm5] ------------- */
20470 /* ------------- STRB Rd, [Rn, #imm5] ------------- */
20471 /* LDRB/STRB Rd, [Rn + imm5] */
20472 UInt rD = INSN0(2,0);
20473 UInt rN = INSN0(5,3);
20474 UInt imm5 = INSN0(10,6);
20475 UInt isLD = INSN0(11,11);
20477 IRExpr* ea = binop(Iop_Add32, getIRegT(rN), mkU32(imm5));
20478 put_ITSTATE(old_itstate); // backout
20479 if (isLD) {
20480 IRTemp tD = newTemp(Ity_I32);
20481 loadGuardedLE( tD, ILGop_8Uto32, ea, llGetIReg(rD), condT );
20482 putIRegT(rD, mkexpr(tD), IRTemp_INVALID);
20483 } else {
20484 storeGuardedLE( ea, unop(Iop_32to8, getIRegT(rD)), condT );
20486 put_ITSTATE(new_itstate); // restore
20488 DIP("%sb r%u, [r%u, #%u]\n", isLD ? "ldr" : "str", rD, rN, imm5);
20489 goto decode_success;
20492 case BITS5(1,0,0,1,0): /* STR */
20493 case BITS5(1,0,0,1,1): { /* LDR */
20494 /* ------------- LDR Rd, [SP, #imm8 * 4] ------------- */
20495 /* ------------- STR Rd, [SP, #imm8 * 4] ------------- */
20496 /* LDR/STR Rd, [SP + imm8 * 4] */
20497 UInt rD = INSN0(10,8);
20498 UInt imm8 = INSN0(7,0);
20499 UInt isLD = INSN0(11,11);
20501 IRExpr* ea = binop(Iop_Add32, getIRegT(13), mkU32(imm8 * 4));
20502 put_ITSTATE(old_itstate); // backout
20503 if (isLD) {
20504 IRTemp tD = newTemp(Ity_I32);
20505 loadGuardedLE( tD, ILGop_Ident32, ea, llGetIReg(rD), condT );
20506 putIRegT(rD, mkexpr(tD), IRTemp_INVALID);
20507 } else {
20508 storeGuardedLE(ea, getIRegT(rD), condT);
20510 put_ITSTATE(new_itstate); // restore
20512 DIP("%s r%u, [sp, #%u]\n", isLD ? "ldr" : "str", rD, imm8 * 4);
20513 goto decode_success;
20516 case BITS5(1,1,0,0,1): {
20517 /* ------------- LDMIA Rn!, {reglist} ------------- */
20518 Int i, nRegs = 0;
20519 UInt rN = INSN0(10,8);
20520 UInt list = INSN0(7,0);
20521 /* Empty lists aren't allowed. */
20522 if (list != 0) {
20523 mk_skip_over_T16_if_cond_is_false(condT);
20524 condT = IRTemp_INVALID;
20525 put_ITSTATE(old_itstate);
20526 // now uncond
20528 IRTemp oldRn = newTemp(Ity_I32);
20529 IRTemp base = newTemp(Ity_I32);
20530 assign(oldRn, getIRegT(rN));
20531 assign(base, binop(Iop_And32, mkexpr(oldRn), mkU32(~3U)));
20532 for (i = 0; i < 8; i++) {
20533 if (0 == (list & (1 << i)))
20534 continue;
20535 nRegs++;
20536 putIRegT(
20537 i, loadLE(Ity_I32,
20538 binop(Iop_Add32, mkexpr(base),
20539 mkU32(nRegs * 4 - 4))),
20540 IRTemp_INVALID
20543 /* Only do the writeback for rN if it isn't in the list of
20544 registers to be transferred. */
20545 if (0 == (list & (1 << rN))) {
20546 putIRegT(rN,
20547 binop(Iop_Add32, mkexpr(oldRn),
20548 mkU32(nRegs * 4)),
20549 IRTemp_INVALID
20553 /* Reinstate the ITSTATE update. */
20554 put_ITSTATE(new_itstate);
20556 DIP("ldmia r%u!, {0x%04x}\n", rN, list);
20557 goto decode_success;
20559 break;
20562 case BITS5(1,1,0,0,0): {
20563 /* ------------- STMIA Rn!, {reglist} ------------- */
20564 Int i, nRegs = 0;
20565 UInt rN = INSN0(10,8);
20566 UInt list = INSN0(7,0);
20567 /* Empty lists aren't allowed. Also, if rN is in the list then
20568 it must be the lowest numbered register in the list. */
20569 Bool valid = list != 0;
20570 if (valid && 0 != (list & (1 << rN))) {
20571 for (i = 0; i < rN; i++) {
20572 if (0 != (list & (1 << i)))
20573 valid = False;
20576 if (valid) {
20577 mk_skip_over_T16_if_cond_is_false(condT);
20578 condT = IRTemp_INVALID;
20579 put_ITSTATE(old_itstate);
20580 // now uncond
20582 IRTemp oldRn = newTemp(Ity_I32);
20583 IRTemp base = newTemp(Ity_I32);
20584 assign(oldRn, getIRegT(rN));
20585 assign(base, binop(Iop_And32, mkexpr(oldRn), mkU32(~3U)));
20586 for (i = 0; i < 8; i++) {
20587 if (0 == (list & (1 << i)))
20588 continue;
20589 nRegs++;
20590 storeLE( binop(Iop_Add32, mkexpr(base), mkU32(nRegs * 4 - 4)),
20591 getIRegT(i) );
20593 /* Always do the writeback. */
20594 putIRegT(rN,
20595 binop(Iop_Add32, mkexpr(oldRn),
20596 mkU32(nRegs * 4)),
20597 IRTemp_INVALID);
20599 /* Reinstate the ITSTATE update. */
20600 put_ITSTATE(new_itstate);
20602 DIP("stmia r%u!, {0x%04x}\n", rN, list);
20603 goto decode_success;
20605 break;
20608 case BITS5(0,0,0,0,0): /* LSLS */
20609 case BITS5(0,0,0,0,1): /* LSRS */
20610 case BITS5(0,0,0,1,0): { /* ASRS */
20611 /* ---------------- LSLS Rd, Rm, #imm5 ---------------- */
20612 /* ---------------- LSRS Rd, Rm, #imm5 ---------------- */
20613 /* ---------------- ASRS Rd, Rm, #imm5 ---------------- */
20614 UInt rD = INSN0(2,0);
20615 UInt rM = INSN0(5,3);
20616 UInt imm5 = INSN0(10,6);
20617 IRTemp res = newTemp(Ity_I32);
20618 IRTemp resC = newTemp(Ity_I32);
20619 IRTemp rMt = newTemp(Ity_I32);
20620 IRTemp oldV = newTemp(Ity_I32);
20621 const HChar* wot = "???";
20622 assign(rMt, getIRegT(rM));
20623 assign(oldV, mk_armg_calculate_flag_v());
20624 /* Looks like INSN0(12,11) are the standard 'how' encoding.
20625 Could compactify if the ROR case later appears. */
20626 switch (INSN0(15,11)) {
20627 case BITS5(0,0,0,0,0):
20628 compute_result_and_C_after_LSL_by_imm5(
20629 dis_buf, &res, &resC, rMt, imm5, rM
20631 wot = "lsl";
20632 break;
20633 case BITS5(0,0,0,0,1):
20634 compute_result_and_C_after_LSR_by_imm5(
20635 dis_buf, &res, &resC, rMt, imm5, rM
20637 wot = "lsr";
20638 break;
20639 case BITS5(0,0,0,1,0):
20640 compute_result_and_C_after_ASR_by_imm5(
20641 dis_buf, &res, &resC, rMt, imm5, rM
20643 wot = "asr";
20644 break;
20645 default:
20646 /*NOTREACHED*/vassert(0);
20648 // not safe to read guest state after this point
20649 putIRegT(rD, mkexpr(res), condT);
20650 setFlags_D1_D2_ND( ARMG_CC_OP_LOGIC, res, resC, oldV,
20651 cond_AND_notInIT_T );
20652 /* ignore buf and roll our own output */
20653 DIP("%ss r%u, r%u, #%u\n", wot, rD, rM, imm5);
20654 goto decode_success;
20657 case BITS5(1,1,1,0,0): {
20658 /* ---------------- B #simm11 ---------------- */
20659 UInt uimm11 = INSN0(10,0); uimm11 <<= 21;
20660 Int simm11 = (Int)uimm11; simm11 >>= 20;
20661 UInt dst = simm11 + guest_R15_curr_instr_notENC + 4;
20662 /* Only allowed outside or last-in IT block; SIGILL if not so. */
20663 gen_SIGILL_T_if_in_but_NLI_ITBlock(old_itstate, new_itstate);
20664 // and skip this insn if not selected; being cleverer is too
20665 // difficult
20666 mk_skip_over_T16_if_cond_is_false(condT);
20667 condT = IRTemp_INVALID;
20668 // now uncond
20669 llPutIReg(15, mkU32( dst | 1 /*CPSR.T*/ ));
20670 dres.jk_StopHere = Ijk_Boring;
20671 dres.whatNext = Dis_StopHere;
20672 DIP("b 0x%x\n", dst);
20673 goto decode_success;
20676 default:
20677 break; /* examine the next shortest prefix */
20682 /* ================ 16-bit 15:12 cases ================ */
20684 switch (INSN0(15,12)) {
20686 case BITS4(1,1,0,1): {
20687 /* ---------------- Bcond #simm8 ---------------- */
20688 UInt cond = INSN0(11,8);
20689 UInt uimm8 = INSN0(7,0); uimm8 <<= 24;
20690 Int simm8 = (Int)uimm8; simm8 >>= 23;
20691 UInt dst = simm8 + guest_R15_curr_instr_notENC + 4;
20692 if (cond != ARMCondAL && cond != ARMCondNV) {
20693 /* Not allowed in an IT block; SIGILL if so. */
20694 gen_SIGILL_T_if_in_ITBlock(old_itstate, new_itstate);
20696 IRTemp kondT = newTemp(Ity_I32);
20697 assign( kondT, mk_armg_calculate_condition(cond) );
20698 stmt( IRStmt_Exit( unop(Iop_32to1, mkexpr(kondT)),
20699 Ijk_Boring,
20700 IRConst_U32(dst | 1/*CPSR.T*/),
20701 OFFB_R15T ));
20702 llPutIReg(15, mkU32( (guest_R15_curr_instr_notENC + 2)
20703 | 1 /*CPSR.T*/ ));
20704 dres.jk_StopHere = Ijk_Boring;
20705 dres.whatNext = Dis_StopHere;
20706 DIP("b%s 0x%x\n", nCC(cond), dst);
20707 goto decode_success;
20709 break;
20712 default:
20713 break; /* hmm, nothing matched */
20717 /* ================ 16-bit misc cases ================ */
20719 switch (INSN0(15,0)) {
20720 case 0xBF00:
20721 /* ------ NOP ------ */
20722 DIP("nop\n");
20723 goto decode_success;
20724 case 0xBF10: // YIELD
20725 case 0xBF20: // WFE
20726 /* ------ WFE, YIELD ------ */
20727 /* Both appear to get used as a spin-loop hints. Do the usual thing,
20728 which is to continue after yielding. */
20729 stmt( IRStmt_Exit( unop(Iop_32to1, mkexpr(condT)),
20730 Ijk_Yield,
20731 IRConst_U32((guest_R15_curr_instr_notENC + 2)
20732 | 1 /*CPSR.T*/),
20733 OFFB_R15T ));
20734 Bool isWFE = INSN0(15,0) == 0xBF20;
20735 DIP(isWFE ? "wfe\n" : "yield\n");
20736 goto decode_success;
20737 case 0xBF40:
20738 /* ------ SEV ------ */
20739 /* Treat this as a no-op. Any matching WFEs won't really
20740 cause the host CPU to snooze; they just cause V to try to
20741 run some other thread for a while. So there's no point in
20742 really doing anything for SEV. */
20743 DIP("sev\n");
20744 goto decode_success;
20745 default:
20746 break; /* fall through */
20749 /* ----------------------------------------------------------- */
20750 /* -- -- */
20751 /* -- Thumb 32-bit integer instructions -- */
20752 /* -- -- */
20753 /* ----------------------------------------------------------- */
20755 # define INSN1(_bMax,_bMin) SLICE_UInt(((UInt)insn1), (_bMax), (_bMin))
20757 /* second 16 bits of the instruction, if any */
20758 vassert(insn1 == 0);
20759 insn1 = getUShortLittleEndianly( guest_instr+2 );
20761 anOp = Iop_INVALID; /* paranoia */
20762 anOpNm = NULL; /* paranoia */
20764 /* Change result defaults to suit 32-bit insns. */
20765 vassert(dres.whatNext == Dis_Continue);
20766 vassert(dres.len == 2);
20767 vassert(dres.continueAt == 0);
20768 dres.len = 4;
20770 /* ---------------- BL/BLX simm26 ---------------- */
20771 if (BITS5(1,1,1,1,0) == INSN0(15,11) && BITS2(1,1) == INSN1(15,14)) {
20772 UInt isBL = INSN1(12,12);
20773 UInt bS = INSN0(10,10);
20774 UInt bJ1 = INSN1(13,13);
20775 UInt bJ2 = INSN1(11,11);
20776 UInt bI1 = 1 ^ (bJ1 ^ bS);
20777 UInt bI2 = 1 ^ (bJ2 ^ bS);
20778 UInt uimm25
20779 = (bS << (1 + 1 + 10 + 11 + 1))
20780 | (bI1 << (1 + 10 + 11 + 1))
20781 | (bI2 << (10 + 11 + 1))
20782 | (INSN0(9,0) << (11 + 1))
20783 | (INSN1(10,0) << 1);
20784 uimm25 <<= 7;
20785 Int simm25 = (Int)uimm25;
20786 simm25 >>= 7;
20788 vassert(0 == (guest_R15_curr_instr_notENC & 1));
20789 UInt dst = simm25 + guest_R15_curr_instr_notENC + 4;
20791 /* One further validity case to check: in the case of BLX
20792 (not-BL), that insn1[0] must be zero. */
20793 Bool valid = True;
20794 if (isBL == 0 && INSN1(0,0) == 1) valid = False;
20795 if (valid) {
20796 /* Only allowed outside or last-in IT block; SIGILL if not so. */
20797 gen_SIGILL_T_if_in_but_NLI_ITBlock(old_itstate, new_itstate);
20798 // and skip this insn if not selected; being cleverer is too
20799 // difficult
20800 mk_skip_over_T32_if_cond_is_false(condT);
20801 condT = IRTemp_INVALID;
20802 // now uncond
20804 /* We're returning to Thumb code, hence "| 1" */
20805 putIRegT( 14, mkU32( (guest_R15_curr_instr_notENC + 4) | 1 ),
20806 IRTemp_INVALID);
20807 if (isBL) {
20808 /* BL: unconditional T -> T call */
20809 /* we're calling Thumb code, hence "| 1" */
20810 llPutIReg(15, mkU32( dst | 1 ));
20811 DIP("bl 0x%x (stay in Thumb mode)\n", dst);
20812 } else {
20813 /* BLX: unconditional T -> A call */
20814 /* we're calling ARM code, hence "& 3" to align to a
20815 valid ARM insn address */
20816 llPutIReg(15, mkU32( dst & ~3 ));
20817 DIP("blx 0x%x (switch to ARM mode)\n", dst & ~3);
20819 dres.whatNext = Dis_StopHere;
20820 dres.jk_StopHere = Ijk_Call;
20821 goto decode_success;
20825 /* ---------------- {LD,ST}M{IA,DB} ---------------- */
20826 if (0x3a2 == INSN0(15,6) // {LD,ST}MIA
20827 || 0x3a4 == INSN0(15,6)) { // {LD,ST}MDB
20828 UInt bW = INSN0(5,5); /* writeback Rn ? */
20829 UInt bL = INSN0(4,4);
20830 UInt rN = INSN0(3,0);
20831 UInt bP = INSN1(15,15); /* reglist entry for r15 */
20832 UInt bM = INSN1(14,14); /* reglist entry for r14 */
20833 UInt rLmost = INSN1(12,0); /* reglist entry for r0 .. 12 */
20834 UInt rL13 = INSN1(13,13); /* must be zero */
20835 UInt regList = 0;
20836 Bool valid = True;
20838 UInt bINC = 1;
20839 UInt bBEFORE = 0;
20840 if (INSN0(15,6) == 0x3a4) {
20841 bINC = 0;
20842 bBEFORE = 1;
20845 /* detect statically invalid cases, and construct the final
20846 reglist */
20847 if (rL13 == 1)
20848 valid = False;
20850 if (bL == 1) {
20851 regList = (bP << 15) | (bM << 14) | rLmost;
20852 if (rN == 15) valid = False;
20853 if (popcount32(regList) < 2) valid = False;
20854 if (bP == 1 && bM == 1) valid = False;
20855 if (bW == 1 && (regList & (1<<rN))) valid = False;
20856 } else {
20857 regList = (bM << 14) | rLmost;
20858 if (bP == 1) valid = False;
20859 if (rN == 15) valid = False;
20860 if (popcount32(regList) < 2) valid = False;
20861 if (bW == 1 && (regList & (1<<rN))) valid = False;
20864 if (valid) {
20865 if (bL == 1 && bP == 1) {
20866 // We'll be writing the PC. Hence:
20867 /* Only allowed outside or last-in IT block; SIGILL if not so. */
20868 gen_SIGILL_T_if_in_but_NLI_ITBlock(old_itstate, new_itstate);
20871 /* Go uncond: */
20872 mk_skip_over_T32_if_cond_is_false(condT);
20873 condT = IRTemp_INVALID;
20874 // now uncond
20876 /* Generate the IR. This might generate a write to R15. */
20877 mk_ldm_stm(False/*!arm*/, rN, bINC, bBEFORE, bW, bL, regList);
20879 if (bL == 1 && (regList & (1<<15))) {
20880 // If we wrote to R15, we have an interworking return to
20881 // deal with.
20882 llPutIReg(15, llGetIReg(15));
20883 dres.jk_StopHere = Ijk_Ret;
20884 dres.whatNext = Dis_StopHere;
20887 DIP("%sm%c%c r%u%s, {0x%04x}\n",
20888 bL == 1 ? "ld" : "st", bINC ? 'i' : 'd', bBEFORE ? 'b' : 'a',
20889 rN, bW ? "!" : "", regList);
20891 goto decode_success;
20895 /* -------------- (T3) ADD{S}.W Rd, Rn, #constT -------------- */
20896 if (INSN0(15,11) == BITS5(1,1,1,1,0)
20897 && INSN0(9,5) == BITS5(0,1,0,0,0)
20898 && INSN1(15,15) == 0) {
20899 UInt bS = INSN0(4,4);
20900 UInt rN = INSN0(3,0);
20901 UInt rD = INSN1(11,8);
20902 Bool valid = !isBadRegT(rN) && !isBadRegT(rD);
20903 /* but allow "add.w reg, sp, #constT" for reg != PC */
20904 if (!valid && rD <= 14 && rN == 13)
20905 valid = True;
20906 if (valid) {
20907 IRTemp argL = newTemp(Ity_I32);
20908 IRTemp argR = newTemp(Ity_I32);
20909 IRTemp res = newTemp(Ity_I32);
20910 UInt imm32 = thumbExpandImm_from_I0_I1(NULL, insn0, insn1);
20911 assign(argL, getIRegT(rN));
20912 assign(argR, mkU32(imm32));
20913 assign(res, binop(Iop_Add32, mkexpr(argL), mkexpr(argR)));
20914 putIRegT(rD, mkexpr(res), condT);
20915 if (bS == 1)
20916 setFlags_D1_D2( ARMG_CC_OP_ADD, argL, argR, condT );
20917 DIP("add%s.w r%u, r%u, #%u\n",
20918 bS == 1 ? "s" : "", rD, rN, imm32);
20919 goto decode_success;
20923 /* ---------------- (T4) ADDW Rd, Rn, #uimm12 -------------- */
20924 if (INSN0(15,11) == BITS5(1,1,1,1,0)
20925 && INSN0(9,4) == BITS6(1,0,0,0,0,0)
20926 && INSN1(15,15) == 0) {
20927 UInt rN = INSN0(3,0);
20928 UInt rD = INSN1(11,8);
20929 Bool valid = !isBadRegT(rN) && !isBadRegT(rD);
20930 /* but allow "addw reg, sp, #uimm12" for reg != PC */
20931 if (!valid && rD <= 14 && rN == 13)
20932 valid = True;
20933 if (valid) {
20934 IRTemp argL = newTemp(Ity_I32);
20935 IRTemp argR = newTemp(Ity_I32);
20936 IRTemp res = newTemp(Ity_I32);
20937 UInt imm12 = (INSN0(10,10) << 11) | (INSN1(14,12) << 8) | INSN1(7,0);
20938 assign(argL, getIRegT(rN));
20939 assign(argR, mkU32(imm12));
20940 assign(res, binop(Iop_Add32, mkexpr(argL), mkexpr(argR)));
20941 putIRegT(rD, mkexpr(res), condT);
20942 DIP("addw r%u, r%u, #%u\n", rD, rN, imm12);
20943 goto decode_success;
20947 /* ---------------- (T2) CMP.W Rn, #constT ---------------- */
20948 /* ---------------- (T2) CMN.W Rn, #constT ---------------- */
20949 if (INSN0(15,11) == BITS5(1,1,1,1,0)
20950 && ( INSN0(9,4) == BITS6(0,1,1,0,1,1) // CMP
20951 || INSN0(9,4) == BITS6(0,1,0,0,0,1)) // CMN
20952 && INSN1(15,15) == 0
20953 && INSN1(11,8) == BITS4(1,1,1,1)) {
20954 UInt rN = INSN0(3,0);
20955 if (rN != 15) {
20956 IRTemp argL = newTemp(Ity_I32);
20957 IRTemp argR = newTemp(Ity_I32);
20958 Bool isCMN = INSN0(9,4) == BITS6(0,1,0,0,0,1);
20959 UInt imm32 = thumbExpandImm_from_I0_I1(NULL, insn0, insn1);
20960 assign(argL, getIRegT(rN));
20961 assign(argR, mkU32(imm32));
20962 setFlags_D1_D2( isCMN ? ARMG_CC_OP_ADD : ARMG_CC_OP_SUB,
20963 argL, argR, condT );
20964 DIP("%s.w r%u, #%u\n", isCMN ? "cmn" : "cmp", rN, imm32);
20965 goto decode_success;
20969 /* -------------- (T1) TST.W Rn, #constT -------------- */
20970 /* -------------- (T1) TEQ.W Rn, #constT -------------- */
20971 if (INSN0(15,11) == BITS5(1,1,1,1,0)
20972 && ( INSN0(9,4) == BITS6(0,0,0,0,0,1) // TST
20973 || INSN0(9,4) == BITS6(0,0,1,0,0,1)) // TEQ
20974 && INSN1(15,15) == 0
20975 && INSN1(11,8) == BITS4(1,1,1,1)) {
20976 UInt rN = INSN0(3,0);
20977 if (!isBadRegT(rN)) { // yes, really, it's inconsistent with CMP.W
20978 Bool isTST = INSN0(9,4) == BITS6(0,0,0,0,0,1);
20979 IRTemp argL = newTemp(Ity_I32);
20980 IRTemp argR = newTemp(Ity_I32);
20981 IRTemp res = newTemp(Ity_I32);
20982 IRTemp oldV = newTemp(Ity_I32);
20983 IRTemp oldC = newTemp(Ity_I32);
20984 Bool updC = False;
20985 UInt imm32 = thumbExpandImm_from_I0_I1(&updC, insn0, insn1);
20986 assign(argL, getIRegT(rN));
20987 assign(argR, mkU32(imm32));
20988 assign(res, binop(isTST ? Iop_And32 : Iop_Xor32,
20989 mkexpr(argL), mkexpr(argR)));
20990 assign( oldV, mk_armg_calculate_flag_v() );
20991 assign( oldC, updC
20992 ? mkU32((imm32 >> 31) & 1)
20993 : mk_armg_calculate_flag_c() );
20994 setFlags_D1_D2_ND( ARMG_CC_OP_LOGIC, res, oldC, oldV, condT );
20995 DIP("%s.w r%u, #%u\n", isTST ? "tst" : "teq", rN, imm32);
20996 goto decode_success;
21000 /* -------------- (T3) SUB{S}.W Rd, Rn, #constT -------------- */
21001 /* -------------- (T3) RSB{S}.W Rd, Rn, #constT -------------- */
21002 if (INSN0(15,11) == BITS5(1,1,1,1,0)
21003 && (INSN0(9,5) == BITS5(0,1,1,0,1) // SUB
21004 || INSN0(9,5) == BITS5(0,1,1,1,0)) // RSB
21005 && INSN1(15,15) == 0) {
21006 Bool isRSB = INSN0(9,5) == BITS5(0,1,1,1,0);
21007 UInt bS = INSN0(4,4);
21008 UInt rN = INSN0(3,0);
21009 UInt rD = INSN1(11,8);
21010 Bool valid = !isBadRegT(rN) && !isBadRegT(rD);
21011 /* but allow "sub{s}.w reg, sp, #constT
21012 this is (T2) of "SUB (SP minus immediate)" */
21013 if (!valid && !isRSB && rN == 13 && rD != 15)
21014 valid = True;
21015 if (valid) {
21016 IRTemp argL = newTemp(Ity_I32);
21017 IRTemp argR = newTemp(Ity_I32);
21018 IRTemp res = newTemp(Ity_I32);
21019 UInt imm32 = thumbExpandImm_from_I0_I1(NULL, insn0, insn1);
21020 assign(argL, getIRegT(rN));
21021 assign(argR, mkU32(imm32));
21022 assign(res, isRSB
21023 ? binop(Iop_Sub32, mkexpr(argR), mkexpr(argL))
21024 : binop(Iop_Sub32, mkexpr(argL), mkexpr(argR)));
21025 putIRegT(rD, mkexpr(res), condT);
21026 if (bS == 1) {
21027 if (isRSB)
21028 setFlags_D1_D2( ARMG_CC_OP_SUB, argR, argL, condT );
21029 else
21030 setFlags_D1_D2( ARMG_CC_OP_SUB, argL, argR, condT );
21032 DIP("%s%s.w r%u, r%u, #%u\n",
21033 isRSB ? "rsb" : "sub", bS == 1 ? "s" : "", rD, rN, imm32);
21034 goto decode_success;
21038 /* -------------- (T4) SUBW Rd, Rn, #uimm12 ------------------- */
21039 if (INSN0(15,11) == BITS5(1,1,1,1,0)
21040 && INSN0(9,4) == BITS6(1,0,1,0,1,0)
21041 && INSN1(15,15) == 0) {
21042 UInt rN = INSN0(3,0);
21043 UInt rD = INSN1(11,8);
21044 Bool valid = !isBadRegT(rN) && !isBadRegT(rD);
21045 /* but allow "subw sp, sp, #uimm12" */
21046 if (!valid && rD == 13 && rN == 13)
21047 valid = True;
21048 if (valid) {
21049 IRTemp argL = newTemp(Ity_I32);
21050 IRTemp argR = newTemp(Ity_I32);
21051 IRTemp res = newTemp(Ity_I32);
21052 UInt imm12 = (INSN0(10,10) << 11) | (INSN1(14,12) << 8) | INSN1(7,0);
21053 assign(argL, getIRegT(rN));
21054 assign(argR, mkU32(imm12));
21055 assign(res, binop(Iop_Sub32, mkexpr(argL), mkexpr(argR)));
21056 putIRegT(rD, mkexpr(res), condT);
21057 DIP("subw r%u, r%u, #%u\n", rD, rN, imm12);
21058 goto decode_success;
21062 /* -------------- (T1) ADC{S}.W Rd, Rn, #constT -------------- */
21063 /* -------------- (T1) SBC{S}.W Rd, Rn, #constT -------------- */
21064 if (INSN0(15,11) == BITS5(1,1,1,1,0)
21065 && ( INSN0(9,5) == BITS5(0,1,0,1,0) // ADC
21066 || INSN0(9,5) == BITS5(0,1,0,1,1)) // SBC
21067 && INSN1(15,15) == 0) {
21068 /* ADC: Rd = Rn + constT + oldC */
21069 /* SBC: Rd = Rn - constT - (oldC ^ 1) */
21070 UInt bS = INSN0(4,4);
21071 UInt rN = INSN0(3,0);
21072 UInt rD = INSN1(11,8);
21073 if (!isBadRegT(rN) && !isBadRegT(rD)) {
21074 IRTemp argL = newTemp(Ity_I32);
21075 IRTemp argR = newTemp(Ity_I32);
21076 IRTemp res = newTemp(Ity_I32);
21077 IRTemp oldC = newTemp(Ity_I32);
21078 UInt imm32 = thumbExpandImm_from_I0_I1(NULL, insn0, insn1);
21079 assign(argL, getIRegT(rN));
21080 assign(argR, mkU32(imm32));
21081 assign(oldC, mk_armg_calculate_flag_c() );
21082 const HChar* nm = "???";
21083 switch (INSN0(9,5)) {
21084 case BITS5(0,1,0,1,0): // ADC
21085 nm = "adc";
21086 assign(res,
21087 binop(Iop_Add32,
21088 binop(Iop_Add32, mkexpr(argL), mkexpr(argR)),
21089 mkexpr(oldC) ));
21090 putIRegT(rD, mkexpr(res), condT);
21091 if (bS)
21092 setFlags_D1_D2_ND( ARMG_CC_OP_ADC,
21093 argL, argR, oldC, condT );
21094 break;
21095 case BITS5(0,1,0,1,1): // SBC
21096 nm = "sbc";
21097 assign(res,
21098 binop(Iop_Sub32,
21099 binop(Iop_Sub32, mkexpr(argL), mkexpr(argR)),
21100 binop(Iop_Xor32, mkexpr(oldC), mkU32(1)) ));
21101 putIRegT(rD, mkexpr(res), condT);
21102 if (bS)
21103 setFlags_D1_D2_ND( ARMG_CC_OP_SBB,
21104 argL, argR, oldC, condT );
21105 break;
21106 default:
21107 vassert(0);
21109 DIP("%s%s.w r%u, r%u, #%u\n",
21110 nm, bS == 1 ? "s" : "", rD, rN, imm32);
21111 goto decode_success;
21115 /* -------------- (T1) ORR{S}.W Rd, Rn, #constT -------------- */
21116 /* -------------- (T1) AND{S}.W Rd, Rn, #constT -------------- */
21117 /* -------------- (T1) BIC{S}.W Rd, Rn, #constT -------------- */
21118 /* -------------- (T1) EOR{S}.W Rd, Rn, #constT -------------- */
21119 if (INSN0(15,11) == BITS5(1,1,1,1,0)
21120 && ( INSN0(9,5) == BITS5(0,0,0,1,0) // ORR
21121 || INSN0(9,5) == BITS5(0,0,0,0,0) // AND
21122 || INSN0(9,5) == BITS5(0,0,0,0,1) // BIC
21123 || INSN0(9,5) == BITS5(0,0,1,0,0) // EOR
21124 || INSN0(9,5) == BITS5(0,0,0,1,1)) // ORN
21125 && INSN1(15,15) == 0) {
21126 UInt bS = INSN0(4,4);
21127 UInt rN = INSN0(3,0);
21128 UInt rD = INSN1(11,8);
21129 if (!isBadRegT(rN) && !isBadRegT(rD)) {
21130 Bool notArgR = False;
21131 IROp op = Iop_INVALID;
21132 const HChar* nm = "???";
21133 switch (INSN0(9,5)) {
21134 case BITS5(0,0,0,1,0): op = Iop_Or32; nm = "orr"; break;
21135 case BITS5(0,0,0,0,0): op = Iop_And32; nm = "and"; break;
21136 case BITS5(0,0,0,0,1): op = Iop_And32; nm = "bic";
21137 notArgR = True; break;
21138 case BITS5(0,0,1,0,0): op = Iop_Xor32; nm = "eor"; break;
21139 case BITS5(0,0,0,1,1): op = Iop_Or32; nm = "orn";
21140 notArgR = True; break;
21141 default: vassert(0);
21143 IRTemp argL = newTemp(Ity_I32);
21144 IRTemp argR = newTemp(Ity_I32);
21145 IRTemp res = newTemp(Ity_I32);
21146 Bool updC = False;
21147 UInt imm32 = thumbExpandImm_from_I0_I1(&updC, insn0, insn1);
21148 assign(argL, getIRegT(rN));
21149 assign(argR, mkU32(notArgR ? ~imm32 : imm32));
21150 assign(res, binop(op, mkexpr(argL), mkexpr(argR)));
21151 putIRegT(rD, mkexpr(res), condT);
21152 if (bS) {
21153 IRTemp oldV = newTemp(Ity_I32);
21154 IRTemp oldC = newTemp(Ity_I32);
21155 assign( oldV, mk_armg_calculate_flag_v() );
21156 assign( oldC, updC
21157 ? mkU32((imm32 >> 31) & 1)
21158 : mk_armg_calculate_flag_c() );
21159 setFlags_D1_D2_ND( ARMG_CC_OP_LOGIC, res, oldC, oldV,
21160 condT );
21162 DIP("%s%s.w r%u, r%u, #%u\n",
21163 nm, bS == 1 ? "s" : "", rD, rN, imm32);
21164 goto decode_success;
21168 /* ---------- (T3) ADD{S}.W Rd, Rn, Rm, {shift} ---------- */
21169 /* ---------- (T3) SUB{S}.W Rd, Rn, Rm, {shift} ---------- */
21170 /* ---------- (T3) RSB{S}.W Rd, Rn, Rm, {shift} ---------- */
21171 if (INSN0(15,9) == BITS7(1,1,1,0,1,0,1)
21172 && ( INSN0(8,5) == BITS4(1,0,0,0) // add subopc
21173 || INSN0(8,5) == BITS4(1,1,0,1) // sub subopc
21174 || INSN0(8,5) == BITS4(1,1,1,0)) // rsb subopc
21175 && INSN1(15,15) == 0) {
21176 UInt rN = INSN0(3,0);
21177 UInt rD = INSN1(11,8);
21178 UInt rM = INSN1(3,0);
21179 UInt bS = INSN0(4,4);
21180 UInt imm5 = (INSN1(14,12) << 2) | INSN1(7,6);
21181 UInt how = INSN1(5,4);
21183 Bool valid = !isBadRegT(rD) && !isBadRegT(rN) && !isBadRegT(rM);
21184 /* but allow "add.w reg, sp, reg, lsl #N for N=0..31
21185 (T3) "ADD (SP plus register) */
21186 if (!valid && INSN0(8,5) == BITS4(1,0,0,0) // add
21187 && rD != 15 && rN == 13 && imm5 <= 31 && how == 0) {
21188 valid = True;
21190 /* also allow "sub.w reg, sp, reg lsl #N for N=0 .. 5
21191 (T1) "SUB (SP minus register) */
21192 if (!valid && INSN0(8,5) == BITS4(1,1,0,1) // sub
21193 && rD != 15 && rN == 13 && imm5 <= 5 && how == 0) {
21194 valid = True;
21196 if (valid) {
21197 Bool swap = False;
21198 IROp op = Iop_INVALID;
21199 const HChar* nm = "???";
21200 switch (INSN0(8,5)) {
21201 case BITS4(1,0,0,0): op = Iop_Add32; nm = "add"; break;
21202 case BITS4(1,1,0,1): op = Iop_Sub32; nm = "sub"; break;
21203 case BITS4(1,1,1,0): op = Iop_Sub32; nm = "rsb";
21204 swap = True; break;
21205 default: vassert(0);
21208 IRTemp argL = newTemp(Ity_I32);
21209 assign(argL, getIRegT(rN));
21211 IRTemp rMt = newTemp(Ity_I32);
21212 assign(rMt, getIRegT(rM));
21214 IRTemp argR = newTemp(Ity_I32);
21215 compute_result_and_C_after_shift_by_imm5(
21216 dis_buf, &argR, NULL, rMt, how, imm5, rM
21219 IRTemp res = newTemp(Ity_I32);
21220 assign(res, swap
21221 ? binop(op, mkexpr(argR), mkexpr(argL))
21222 : binop(op, mkexpr(argL), mkexpr(argR)));
21224 putIRegT(rD, mkexpr(res), condT);
21225 if (bS) {
21226 switch (op) {
21227 case Iop_Add32:
21228 setFlags_D1_D2( ARMG_CC_OP_ADD, argL, argR, condT );
21229 break;
21230 case Iop_Sub32:
21231 if (swap)
21232 setFlags_D1_D2( ARMG_CC_OP_SUB, argR, argL, condT );
21233 else
21234 setFlags_D1_D2( ARMG_CC_OP_SUB, argL, argR, condT );
21235 break;
21236 default:
21237 vassert(0);
21241 DIP("%s%s.w r%u, r%u, %s\n",
21242 nm, bS ? "s" : "", rD, rN, dis_buf);
21243 goto decode_success;
21247 /* ---------- (T3) ADC{S}.W Rd, Rn, Rm, {shift} ---------- */
21248 /* ---------- (T2) SBC{S}.W Rd, Rn, Rm, {shift} ---------- */
21249 if (INSN0(15,9) == BITS7(1,1,1,0,1,0,1)
21250 && ( INSN0(8,5) == BITS4(1,0,1,0) // adc subopc
21251 || INSN0(8,5) == BITS4(1,0,1,1)) // sbc subopc
21252 && INSN1(15,15) == 0) {
21253 /* ADC: Rd = Rn + shifter_operand + oldC */
21254 /* SBC: Rd = Rn - shifter_operand - (oldC ^ 1) */
21255 UInt rN = INSN0(3,0);
21256 UInt rD = INSN1(11,8);
21257 UInt rM = INSN1(3,0);
21258 if (!isBadRegT(rD) && !isBadRegT(rN) && !isBadRegT(rM)) {
21259 UInt bS = INSN0(4,4);
21260 UInt imm5 = (INSN1(14,12) << 2) | INSN1(7,6);
21261 UInt how = INSN1(5,4);
21263 IRTemp argL = newTemp(Ity_I32);
21264 assign(argL, getIRegT(rN));
21266 IRTemp rMt = newTemp(Ity_I32);
21267 assign(rMt, getIRegT(rM));
21269 IRTemp oldC = newTemp(Ity_I32);
21270 assign(oldC, mk_armg_calculate_flag_c());
21272 IRTemp argR = newTemp(Ity_I32);
21273 compute_result_and_C_after_shift_by_imm5(
21274 dis_buf, &argR, NULL, rMt, how, imm5, rM
21277 const HChar* nm = "???";
21278 IRTemp res = newTemp(Ity_I32);
21279 switch (INSN0(8,5)) {
21280 case BITS4(1,0,1,0): // ADC
21281 nm = "adc";
21282 assign(res,
21283 binop(Iop_Add32,
21284 binop(Iop_Add32, mkexpr(argL), mkexpr(argR)),
21285 mkexpr(oldC) ));
21286 putIRegT(rD, mkexpr(res), condT);
21287 if (bS)
21288 setFlags_D1_D2_ND( ARMG_CC_OP_ADC,
21289 argL, argR, oldC, condT );
21290 break;
21291 case BITS4(1,0,1,1): // SBC
21292 nm = "sbc";
21293 assign(res,
21294 binop(Iop_Sub32,
21295 binop(Iop_Sub32, mkexpr(argL), mkexpr(argR)),
21296 binop(Iop_Xor32, mkexpr(oldC), mkU32(1)) ));
21297 putIRegT(rD, mkexpr(res), condT);
21298 if (bS)
21299 setFlags_D1_D2_ND( ARMG_CC_OP_SBB,
21300 argL, argR, oldC, condT );
21301 break;
21302 default:
21303 vassert(0);
21306 DIP("%s%s.w r%u, r%u, %s\n",
21307 nm, bS ? "s" : "", rD, rN, dis_buf);
21308 goto decode_success;
21312 /* ---------- (T3) AND{S}.W Rd, Rn, Rm, {shift} ---------- */
21313 /* ---------- (T3) ORR{S}.W Rd, Rn, Rm, {shift} ---------- */
21314 /* ---------- (T3) EOR{S}.W Rd, Rn, Rm, {shift} ---------- */
21315 /* ---------- (T3) BIC{S}.W Rd, Rn, Rm, {shift} ---------- */
21316 /* ---------- (T1) ORN{S}.W Rd, Rn, Rm, {shift} ---------- */
21317 if (INSN0(15,9) == BITS7(1,1,1,0,1,0,1)
21318 && ( INSN0(8,5) == BITS4(0,0,0,0) // and subopc
21319 || INSN0(8,5) == BITS4(0,0,1,0) // orr subopc
21320 || INSN0(8,5) == BITS4(0,1,0,0) // eor subopc
21321 || INSN0(8,5) == BITS4(0,0,0,1) // bic subopc
21322 || INSN0(8,5) == BITS4(0,0,1,1)) // orn subopc
21323 && INSN1(15,15) == 0) {
21324 UInt rN = INSN0(3,0);
21325 UInt rD = INSN1(11,8);
21326 UInt rM = INSN1(3,0);
21327 if (!isBadRegT(rD) && !isBadRegT(rN) && !isBadRegT(rM)) {
21328 Bool notArgR = False;
21329 IROp op = Iop_INVALID;
21330 const HChar* nm = "???";
21331 switch (INSN0(8,5)) {
21332 case BITS4(0,0,0,0): op = Iop_And32; nm = "and"; break;
21333 case BITS4(0,0,1,0): op = Iop_Or32; nm = "orr"; break;
21334 case BITS4(0,1,0,0): op = Iop_Xor32; nm = "eor"; break;
21335 case BITS4(0,0,0,1): op = Iop_And32; nm = "bic";
21336 notArgR = True; break;
21337 case BITS4(0,0,1,1): op = Iop_Or32; nm = "orn";
21338 notArgR = True; break;
21339 default: vassert(0);
21341 UInt bS = INSN0(4,4);
21342 UInt imm5 = (INSN1(14,12) << 2) | INSN1(7,6);
21343 UInt how = INSN1(5,4);
21345 IRTemp rNt = newTemp(Ity_I32);
21346 assign(rNt, getIRegT(rN));
21348 IRTemp rMt = newTemp(Ity_I32);
21349 assign(rMt, getIRegT(rM));
21351 IRTemp argR = newTemp(Ity_I32);
21352 IRTemp oldC = bS ? newTemp(Ity_I32) : IRTemp_INVALID;
21354 compute_result_and_C_after_shift_by_imm5(
21355 dis_buf, &argR, bS ? &oldC : NULL, rMt, how, imm5, rM
21358 IRTemp res = newTemp(Ity_I32);
21359 if (notArgR) {
21360 vassert(op == Iop_And32 || op == Iop_Or32);
21361 assign(res, binop(op, mkexpr(rNt),
21362 unop(Iop_Not32, mkexpr(argR))));
21363 } else {
21364 assign(res, binop(op, mkexpr(rNt), mkexpr(argR)));
21367 putIRegT(rD, mkexpr(res), condT);
21368 if (bS) {
21369 IRTemp oldV = newTemp(Ity_I32);
21370 assign( oldV, mk_armg_calculate_flag_v() );
21371 setFlags_D1_D2_ND( ARMG_CC_OP_LOGIC, res, oldC, oldV,
21372 condT );
21375 DIP("%s%s.w r%u, r%u, %s\n",
21376 nm, bS ? "s" : "", rD, rN, dis_buf);
21377 goto decode_success;
21381 /* -------------- (T?) LSL{S}.W Rd, Rn, Rm -------------- */
21382 /* -------------- (T?) LSR{S}.W Rd, Rn, Rm -------------- */
21383 /* -------------- (T?) ASR{S}.W Rd, Rn, Rm -------------- */
21384 /* -------------- (T?) ROR{S}.W Rd, Rn, Rm -------------- */
21385 if (INSN0(15,7) == BITS9(1,1,1,1,1,0,1,0,0)
21386 && INSN1(15,12) == BITS4(1,1,1,1)
21387 && INSN1(7,4) == BITS4(0,0,0,0)) {
21388 UInt how = INSN0(6,5); // standard encoding
21389 UInt rN = INSN0(3,0);
21390 UInt rD = INSN1(11,8);
21391 UInt rM = INSN1(3,0);
21392 UInt bS = INSN0(4,4);
21393 Bool valid = !isBadRegT(rN) && !isBadRegT(rM) && !isBadRegT(rD);
21394 if (valid) {
21395 IRTemp rNt = newTemp(Ity_I32);
21396 IRTemp rMt = newTemp(Ity_I32);
21397 IRTemp res = newTemp(Ity_I32);
21398 IRTemp oldC = bS ? newTemp(Ity_I32) : IRTemp_INVALID;
21399 IRTemp oldV = bS ? newTemp(Ity_I32) : IRTemp_INVALID;
21400 const HChar* nms[4] = { "lsl", "lsr", "asr", "ror" };
21401 const HChar* nm = nms[how];
21402 assign(rNt, getIRegT(rN));
21403 assign(rMt, getIRegT(rM));
21404 compute_result_and_C_after_shift_by_reg(
21405 dis_buf, &res, bS ? &oldC : NULL,
21406 rNt, how, rMt, rN, rM
21408 if (bS)
21409 assign(oldV, mk_armg_calculate_flag_v());
21410 putIRegT(rD, mkexpr(res), condT);
21411 if (bS) {
21412 setFlags_D1_D2_ND( ARMG_CC_OP_LOGIC, res, oldC, oldV,
21413 condT );
21415 DIP("%s%s.w r%u, r%u, r%u\n",
21416 nm, bS ? "s" : "", rD, rN, rM);
21417 goto decode_success;
21421 /* ------------ (T?) MOV{S}.W Rd, Rn, {shift} ------------ */
21422 /* ------------ (T?) MVN{S}.W Rd, Rn, {shift} ------------ */
21423 if ((INSN0(15,0) & 0xFFCF) == 0xEA4F
21424 && INSN1(15,15) == 0) {
21425 UInt rD = INSN1(11,8);
21426 UInt rN = INSN1(3,0);
21427 UInt bS = INSN0(4,4);
21428 UInt isMVN = INSN0(5,5);
21429 Bool regsOK = (bS || isMVN)
21430 ? (!isBadRegT(rD) && !isBadRegT(rN))
21431 : (rD != 15 && rN != 15 && (rD != 13 || rN != 13));
21432 if (regsOK) {
21433 UInt imm5 = (INSN1(14,12) << 2) | INSN1(7,6);
21434 UInt how = INSN1(5,4);
21436 IRTemp rNt = newTemp(Ity_I32);
21437 assign(rNt, getIRegT(rN));
21439 IRTemp oldRn = newTemp(Ity_I32);
21440 IRTemp oldC = bS ? newTemp(Ity_I32) : IRTemp_INVALID;
21441 compute_result_and_C_after_shift_by_imm5(
21442 dis_buf, &oldRn, bS ? &oldC : NULL, rNt, how, imm5, rN
21445 IRTemp res = newTemp(Ity_I32);
21446 assign(res, isMVN ? unop(Iop_Not32, mkexpr(oldRn))
21447 : mkexpr(oldRn));
21449 putIRegT(rD, mkexpr(res), condT);
21450 if (bS) {
21451 IRTemp oldV = newTemp(Ity_I32);
21452 assign( oldV, mk_armg_calculate_flag_v() );
21453 setFlags_D1_D2_ND( ARMG_CC_OP_LOGIC, res, oldC, oldV, condT);
21455 DIP("%s%s.w r%u, %s\n",
21456 isMVN ? "mvn" : "mov", bS ? "s" : "", rD, dis_buf);
21457 goto decode_success;
21461 /* -------------- (T?) TST.W Rn, Rm, {shift} -------------- */
21462 /* -------------- (T?) TEQ.W Rn, Rm, {shift} -------------- */
21463 if (INSN0(15,9) == BITS7(1,1,1,0,1,0,1)
21464 && ( INSN0(8,4) == BITS5(0,0,0,0,1) // TST
21465 || INSN0(8,4) == BITS5(0,1,0,0,1)) // TEQ
21466 && INSN1(15,15) == 0
21467 && INSN1(11,8) == BITS4(1,1,1,1)) {
21468 UInt rN = INSN0(3,0);
21469 UInt rM = INSN1(3,0);
21470 if (!isBadRegT(rN) && !isBadRegT(rM)) {
21471 Bool isTST = INSN0(8,4) == BITS5(0,0,0,0,1);
21473 UInt how = INSN1(5,4);
21474 UInt imm5 = (INSN1(14,12) << 2) | INSN1(7,6);
21476 IRTemp argL = newTemp(Ity_I32);
21477 assign(argL, getIRegT(rN));
21479 IRTemp rMt = newTemp(Ity_I32);
21480 assign(rMt, getIRegT(rM));
21482 IRTemp argR = newTemp(Ity_I32);
21483 IRTemp oldC = newTemp(Ity_I32);
21484 compute_result_and_C_after_shift_by_imm5(
21485 dis_buf, &argR, &oldC, rMt, how, imm5, rM
21488 IRTemp oldV = newTemp(Ity_I32);
21489 assign( oldV, mk_armg_calculate_flag_v() );
21491 IRTemp res = newTemp(Ity_I32);
21492 assign(res, binop(isTST ? Iop_And32 : Iop_Xor32,
21493 mkexpr(argL), mkexpr(argR)));
21495 setFlags_D1_D2_ND( ARMG_CC_OP_LOGIC, res, oldC, oldV,
21496 condT );
21497 DIP("%s.w r%u, %s\n", isTST ? "tst" : "teq", rN, dis_buf);
21498 goto decode_success;
21502 /* -------------- (T3) CMP.W Rn, Rm, {shift} -------------- */
21503 /* -------------- (T2) CMN.W Rn, Rm, {shift} -------------- */
21504 if (INSN0(15,9) == BITS7(1,1,1,0,1,0,1)
21505 && ( INSN0(8,4) == BITS5(1,1,0,1,1) // CMP
21506 || INSN0(8,4) == BITS5(1,0,0,0,1)) // CMN
21507 && INSN1(15,15) == 0
21508 && INSN1(11,8) == BITS4(1,1,1,1)) {
21509 UInt rN = INSN0(3,0);
21510 UInt rM = INSN1(3,0);
21511 if (!isBadRegT(rN) && !isBadRegT(rM)) {
21512 Bool isCMN = INSN0(8,4) == BITS5(1,0,0,0,1);
21513 UInt how = INSN1(5,4);
21514 UInt imm5 = (INSN1(14,12) << 2) | INSN1(7,6);
21516 IRTemp argL = newTemp(Ity_I32);
21517 assign(argL, getIRegT(rN));
21519 IRTemp rMt = newTemp(Ity_I32);
21520 assign(rMt, getIRegT(rM));
21522 IRTemp argR = newTemp(Ity_I32);
21523 compute_result_and_C_after_shift_by_imm5(
21524 dis_buf, &argR, NULL, rMt, how, imm5, rM
21527 setFlags_D1_D2( isCMN ? ARMG_CC_OP_ADD : ARMG_CC_OP_SUB,
21528 argL, argR, condT );
21530 DIP("%s.w r%u, %s\n", isCMN ? "cmn" : "cmp", rN, dis_buf);
21531 goto decode_success;
21535 /* -------------- (T2) MOV{S}.W Rd, #constT -------------- */
21536 /* -------------- (T2) MVN{S}.W Rd, #constT -------------- */
21537 if (INSN0(15,11) == BITS5(1,1,1,1,0)
21538 && ( INSN0(9,5) == BITS5(0,0,0,1,0) // MOV
21539 || INSN0(9,5) == BITS5(0,0,0,1,1)) // MVN
21540 && INSN0(3,0) == BITS4(1,1,1,1)
21541 && INSN1(15,15) == 0) {
21542 UInt rD = INSN1(11,8);
21543 if (!isBadRegT(rD)) {
21544 Bool updC = False;
21545 UInt bS = INSN0(4,4);
21546 Bool isMVN = INSN0(5,5) == 1;
21547 UInt imm32 = thumbExpandImm_from_I0_I1(&updC, insn0, insn1);
21548 IRTemp res = newTemp(Ity_I32);
21549 assign(res, mkU32(isMVN ? ~imm32 : imm32));
21550 putIRegT(rD, mkexpr(res), condT);
21551 if (bS) {
21552 IRTemp oldV = newTemp(Ity_I32);
21553 IRTemp oldC = newTemp(Ity_I32);
21554 assign( oldV, mk_armg_calculate_flag_v() );
21555 assign( oldC, updC
21556 ? mkU32((imm32 >> 31) & 1)
21557 : mk_armg_calculate_flag_c() );
21558 setFlags_D1_D2_ND( ARMG_CC_OP_LOGIC, res, oldC, oldV,
21559 condT );
21561 DIP("%s%s.w r%u, #%u\n",
21562 isMVN ? "mvn" : "mov", bS ? "s" : "", rD, imm32);
21563 goto decode_success;
21567 /* -------------- (T3) MOVW Rd, #imm16 -------------- */
21568 if (INSN0(15,11) == BITS5(1,1,1,1,0)
21569 && INSN0(9,4) == BITS6(1,0,0,1,0,0)
21570 && INSN1(15,15) == 0) {
21571 UInt rD = INSN1(11,8);
21572 if (!isBadRegT(rD)) {
21573 UInt imm16 = (INSN0(3,0) << 12) | (INSN0(10,10) << 11)
21574 | (INSN1(14,12) << 8) | INSN1(7,0);
21575 putIRegT(rD, mkU32(imm16), condT);
21576 DIP("movw r%u, #%u\n", rD, imm16);
21577 goto decode_success;
21581 /* ---------------- MOVT Rd, #imm16 ---------------- */
21582 if (INSN0(15,11) == BITS5(1,1,1,1,0)
21583 && INSN0(9,4) == BITS6(1,0,1,1,0,0)
21584 && INSN1(15,15) == 0) {
21585 UInt rD = INSN1(11,8);
21586 if (!isBadRegT(rD)) {
21587 UInt imm16 = (INSN0(3,0) << 12) | (INSN0(10,10) << 11)
21588 | (INSN1(14,12) << 8) | INSN1(7,0);
21589 IRTemp res = newTemp(Ity_I32);
21590 assign(res,
21591 binop(Iop_Or32,
21592 binop(Iop_And32, getIRegT(rD), mkU32(0xFFFF)),
21593 mkU32(imm16 << 16)));
21594 putIRegT(rD, mkexpr(res), condT);
21595 DIP("movt r%u, #%u\n", rD, imm16);
21596 goto decode_success;
21600 /* ---------------- LD/ST reg+/-#imm8 ---------------- */
21601 /* Loads and stores of the form:
21602 op Rt, [Rn, #-imm8] or
21603 op Rt, [Rn], #+/-imm8 or
21604 op Rt, [Rn, #+/-imm8]!
21605 where op is one of
21606 ldrb ldrh ldr ldrsb ldrsh
21607 strb strh str
21609 if (INSN0(15,9) == BITS7(1,1,1,1,1,0,0) && INSN1(11,11) == 1) {
21610 Bool valid = True;
21611 Bool syned = False;
21612 Bool isST = False;
21613 IRType ty = Ity_I8;
21614 const HChar* nm = "???";
21616 switch (INSN0(8,4)) {
21617 case BITS5(0,0,0,0,0): // strb
21618 nm = "strb"; isST = True; break;
21619 case BITS5(0,0,0,0,1): // ldrb
21620 nm = "ldrb"; break;
21621 case BITS5(1,0,0,0,1): // ldrsb
21622 nm = "ldrsb"; syned = True; break;
21623 case BITS5(0,0,0,1,0): // strh
21624 nm = "strh"; ty = Ity_I16; isST = True; break;
21625 case BITS5(0,0,0,1,1): // ldrh
21626 nm = "ldrh"; ty = Ity_I16; break;
21627 case BITS5(1,0,0,1,1): // ldrsh
21628 nm = "ldrsh"; ty = Ity_I16; syned = True; break;
21629 case BITS5(0,0,1,0,0): // str
21630 nm = "str"; ty = Ity_I32; isST = True; break;
21631 case BITS5(0,0,1,0,1):
21632 nm = "ldr"; ty = Ity_I32; break; // ldr
21633 default:
21634 valid = False; break;
21637 UInt rN = INSN0(3,0);
21638 UInt rT = INSN1(15,12);
21639 UInt bP = INSN1(10,10);
21640 UInt bU = INSN1(9,9);
21641 UInt bW = INSN1(8,8);
21642 UInt imm8 = INSN1(7,0);
21643 Bool loadsPC = False;
21645 if (valid) {
21646 if (bP == 1 && bU == 1 && bW == 0)
21647 valid = False;
21648 if (bP == 0 && bW == 0)
21649 valid = False;
21650 if (rN == 15)
21651 valid = False;
21652 if (bW == 1 && rN == rT)
21653 valid = False;
21654 if (ty == Ity_I8 || ty == Ity_I16) {
21655 if (isBadRegT(rT))
21656 valid = False;
21657 } else {
21658 /* ty == Ity_I32 */
21659 if (isST && rT == 15)
21660 valid = False;
21661 if (!isST && rT == 15)
21662 loadsPC = True;
21666 if (valid) {
21667 // if it's a branch, it can't happen in the middle of an IT block
21668 // Also, if it is a branch, make it unconditional at this point.
21669 // Doing conditional branches in-line is too complex (for now)
21670 if (loadsPC) {
21671 gen_SIGILL_T_if_in_but_NLI_ITBlock(old_itstate, new_itstate);
21672 // go uncond
21673 mk_skip_over_T32_if_cond_is_false(condT);
21674 condT = IRTemp_INVALID;
21675 // now uncond
21678 IRTemp preAddr = newTemp(Ity_I32);
21679 assign(preAddr, getIRegT(rN));
21681 IRTemp postAddr = newTemp(Ity_I32);
21682 assign(postAddr, binop(bU == 1 ? Iop_Add32 : Iop_Sub32,
21683 mkexpr(preAddr), mkU32(imm8)));
21685 IRTemp transAddr = bP == 1 ? postAddr : preAddr;
21687 if (isST) {
21689 /* Store. If necessary, update the base register before
21690 the store itself, so that the common idiom of "str rX,
21691 [sp, #-4]!" (store rX at sp-4, then do new sp = sp-4,
21692 a.k.a "push rX") doesn't cause Memcheck to complain
21693 that the access is below the stack pointer. Also, not
21694 updating sp before the store confuses Valgrind's
21695 dynamic stack-extending logic. So do it before the
21696 store. Hence we need to snarf the store data before
21697 doing the basereg update. */
21699 /* get hold of the data to be stored */
21700 IRTemp oldRt = newTemp(Ity_I32);
21701 assign(oldRt, getIRegT(rT));
21703 /* Update Rn if necessary. */
21704 if (bW == 1) {
21705 vassert(rN != rT); // assured by validity check above
21706 putIRegT(rN, mkexpr(postAddr), condT);
21709 /* generate the transfer */
21710 IRExpr* data = NULL;
21711 switch (ty) {
21712 case Ity_I8:
21713 data = unop(Iop_32to8, mkexpr(oldRt));
21714 break;
21715 case Ity_I16:
21716 data = unop(Iop_32to16, mkexpr(oldRt));
21717 break;
21718 case Ity_I32:
21719 data = mkexpr(oldRt);
21720 break;
21721 default:
21722 vassert(0);
21724 storeGuardedLE(mkexpr(transAddr), data, condT);
21726 } else {
21728 /* Load. */
21729 IRTemp llOldRt = newTemp(Ity_I32);
21730 assign(llOldRt, llGetIReg(rT));
21732 /* generate the transfer */
21733 IRTemp newRt = newTemp(Ity_I32);
21734 IRLoadGOp widen = ILGop_INVALID;
21735 switch (ty) {
21736 case Ity_I8:
21737 widen = syned ? ILGop_8Sto32 : ILGop_8Uto32; break;
21738 case Ity_I16:
21739 widen = syned ? ILGop_16Sto32 : ILGop_16Uto32; break;
21740 case Ity_I32:
21741 widen = ILGop_Ident32; break;
21742 default:
21743 vassert(0);
21745 loadGuardedLE(newRt, widen,
21746 mkexpr(transAddr), mkexpr(llOldRt), condT);
21747 if (rT == 15) {
21748 vassert(loadsPC);
21749 /* We'll do the write to the PC just below */
21750 } else {
21751 vassert(!loadsPC);
21752 /* IRTemp_INVALID is OK here because in the case where
21753 condT is false at run time, we're just putting the
21754 old rT value back. */
21755 putIRegT(rT, mkexpr(newRt), IRTemp_INVALID);
21758 /* Update Rn if necessary. */
21759 if (bW == 1) {
21760 vassert(rN != rT); // assured by validity check above
21761 putIRegT(rN, mkexpr(postAddr), condT);
21764 if (loadsPC) {
21765 /* Presumably this is an interworking branch. */
21766 vassert(rN != 15); // assured by validity check above
21767 vassert(rT == 15);
21768 vassert(condT == IRTemp_INVALID); /* due to check above */
21769 llPutIReg(15, mkexpr(newRt));
21770 dres.jk_StopHere = Ijk_Boring; /* or _Ret ? */
21771 dres.whatNext = Dis_StopHere;
21775 if (bP == 1 && bW == 0) {
21776 DIP("%s.w r%u, [r%u, #%c%u]\n",
21777 nm, rT, rN, bU ? '+' : '-', imm8);
21779 else if (bP == 1 && bW == 1) {
21780 DIP("%s.w r%u, [r%u, #%c%u]!\n",
21781 nm, rT, rN, bU ? '+' : '-', imm8);
21783 else {
21784 vassert(bP == 0 && bW == 1);
21785 DIP("%s.w r%u, [r%u], #%c%u\n",
21786 nm, rT, rN, bU ? '+' : '-', imm8);
21789 goto decode_success;
21793 /* ------------- LD/ST reg+(reg<<imm2) ------------- */
21794 /* Loads and stores of the form:
21795 op Rt, [Rn, Rm, LSL #imm8]
21796 where op is one of
21797 ldrb ldrh ldr ldrsb ldrsh
21798 strb strh str
21800 if (INSN0(15,9) == BITS7(1,1,1,1,1,0,0)
21801 && INSN1(11,6) == BITS6(0,0,0,0,0,0)) {
21802 Bool valid = True;
21803 Bool syned = False;
21804 Bool isST = False;
21805 IRType ty = Ity_I8;
21806 const HChar* nm = "???";
21808 switch (INSN0(8,4)) {
21809 case BITS5(0,0,0,0,0): // strb
21810 nm = "strb"; isST = True; break;
21811 case BITS5(0,0,0,0,1): // ldrb
21812 nm = "ldrb"; break;
21813 case BITS5(1,0,0,0,1): // ldrsb
21814 nm = "ldrsb"; syned = True; break;
21815 case BITS5(0,0,0,1,0): // strh
21816 nm = "strh"; ty = Ity_I16; isST = True; break;
21817 case BITS5(0,0,0,1,1): // ldrh
21818 nm = "ldrh"; ty = Ity_I16; break;
21819 case BITS5(1,0,0,1,1): // ldrsh
21820 nm = "ldrsh"; ty = Ity_I16; syned = True; break;
21821 case BITS5(0,0,1,0,0): // str
21822 nm = "str"; ty = Ity_I32; isST = True; break;
21823 case BITS5(0,0,1,0,1):
21824 nm = "ldr"; ty = Ity_I32; break; // ldr
21825 default:
21826 valid = False; break;
21829 UInt rN = INSN0(3,0);
21830 UInt rM = INSN1(3,0);
21831 UInt rT = INSN1(15,12);
21832 UInt imm2 = INSN1(5,4);
21833 Bool loadsPC = False;
21835 if (ty == Ity_I8 || ty == Ity_I16) {
21836 /* all 8- and 16-bit load and store cases have the
21837 same exclusion set. */
21838 if (rN == 15 || isBadRegT(rT) || isBadRegT(rM))
21839 valid = False;
21840 } else {
21841 vassert(ty == Ity_I32);
21842 if (rN == 15 || isBadRegT(rM))
21843 valid = False;
21844 if (isST && rT == 15)
21845 valid = False;
21846 /* If it is a load and rT is 15, that's only allowable if we
21847 not in an IT block, or are the last in it. Need to insert
21848 a dynamic check for that. */
21849 if (!isST && rT == 15)
21850 loadsPC = True;
21853 if (valid) {
21854 // if it's a branch, it can't happen in the middle of an IT block
21855 // Also, if it is a branch, make it unconditional at this point.
21856 // Doing conditional branches in-line is too complex (for now)
21857 if (loadsPC) {
21858 gen_SIGILL_T_if_in_but_NLI_ITBlock(old_itstate, new_itstate);
21859 // go uncond
21860 mk_skip_over_T32_if_cond_is_false(condT);
21861 condT = IRTemp_INVALID;
21862 // now uncond
21865 IRTemp transAddr = newTemp(Ity_I32);
21866 assign(transAddr,
21867 binop( Iop_Add32,
21868 getIRegT(rN),
21869 binop(Iop_Shl32, getIRegT(rM), mkU8(imm2)) ));
21871 if (isST) {
21873 /* get hold of the data to be stored */
21874 IRTemp oldRt = newTemp(Ity_I32);
21875 assign(oldRt, getIRegT(rT));
21877 /* generate the transfer */
21878 IRExpr* data = NULL;
21879 switch (ty) {
21880 case Ity_I8:
21881 data = unop(Iop_32to8, mkexpr(oldRt));
21882 break;
21883 case Ity_I16:
21884 data = unop(Iop_32to16, mkexpr(oldRt));
21885 break;
21886 case Ity_I32:
21887 data = mkexpr(oldRt);
21888 break;
21889 default:
21890 vassert(0);
21892 storeGuardedLE(mkexpr(transAddr), data, condT);
21894 } else {
21896 /* Load. */
21897 IRTemp llOldRt = newTemp(Ity_I32);
21898 assign(llOldRt, llGetIReg(rT));
21900 /* generate the transfer */
21901 IRTemp newRt = newTemp(Ity_I32);
21902 IRLoadGOp widen = ILGop_INVALID;
21903 switch (ty) {
21904 case Ity_I8:
21905 widen = syned ? ILGop_8Sto32 : ILGop_8Uto32; break;
21906 case Ity_I16:
21907 widen = syned ? ILGop_16Sto32 : ILGop_16Uto32; break;
21908 case Ity_I32:
21909 widen = ILGop_Ident32; break;
21910 default:
21911 vassert(0);
21913 loadGuardedLE(newRt, widen,
21914 mkexpr(transAddr), mkexpr(llOldRt), condT);
21916 if (rT == 15) {
21917 vassert(loadsPC);
21918 /* We'll do the write to the PC just below */
21919 } else {
21920 vassert(!loadsPC);
21921 /* IRTemp_INVALID is OK here because in the case where
21922 condT is false at run time, we're just putting the
21923 old rT value back. */
21924 putIRegT(rT, mkexpr(newRt), IRTemp_INVALID);
21927 if (loadsPC) {
21928 /* Presumably this is an interworking branch. */
21929 vassert(rN != 15); // assured by validity check above
21930 vassert(rT == 15);
21931 vassert(condT == IRTemp_INVALID); /* due to check above */
21932 llPutIReg(15, mkexpr(newRt));
21933 dres.jk_StopHere = Ijk_Boring; /* or _Ret ? */
21934 dres.whatNext = Dis_StopHere;
21938 DIP("%s.w r%u, [r%u, r%u, LSL #%u]\n",
21939 nm, rT, rN, rM, imm2);
21941 goto decode_success;
21945 /* --------------- LD/ST reg+imm12 --------------- */
21946 /* Loads and stores of the form:
21947 op Rt, [Rn, #+-imm12]
21948 where op is one of
21949 ldrb ldrh ldr ldrsb ldrsh
21950 strb strh str
21952 if (INSN0(15,9) == BITS7(1,1,1,1,1,0,0)) {
21953 Bool valid = True;
21954 Bool syned = INSN0(8,8) == 1;
21955 Bool isST = False;
21956 IRType ty = Ity_I8;
21957 UInt bU = INSN0(7,7); // 1: +imm 0: -imm
21958 // -imm is only supported by literal versions
21959 const HChar* nm = "???";
21961 switch (INSN0(6,4)) {
21962 case BITS3(0,0,0): // strb
21963 nm = "strb"; isST = True; break;
21964 case BITS3(0,0,1): // ldrb
21965 nm = syned ? "ldrsb" : "ldrb"; break;
21966 case BITS3(0,1,0): // strh
21967 nm = "strh"; ty = Ity_I16; isST = True; break;
21968 case BITS3(0,1,1): // ldrh
21969 nm = syned ? "ldrsh" : "ldrh"; ty = Ity_I16; break;
21970 case BITS3(1,0,0): // str
21971 nm = "str"; ty = Ity_I32; isST = True; break;
21972 case BITS3(1,0,1):
21973 nm = "ldr"; ty = Ity_I32; break; // ldr
21974 default:
21975 valid = False; break;
21978 UInt rN = INSN0(3,0);
21979 UInt rT = INSN1(15,12);
21980 UInt imm12 = INSN1(11,0);
21981 Bool loadsPC = False;
21983 if (rN != 15 && bU == 0) {
21984 // only pc supports #-imm12
21985 valid = False;
21988 if (isST) {
21989 if (syned) valid = False;
21990 if (rN == 15 || rT == 15)
21991 valid = False;
21992 } else {
21993 /* For a 32-bit load, rT == 15 is only allowable if we are not
21994 in an IT block, or are the last in it. Need to insert
21995 a dynamic check for that. Also, in this particular
21996 case, rN == 15 is allowable. In this case however, the
21997 value obtained for rN is (apparently)
21998 "word-align(address of current insn + 4)". */
21999 if (rT == 15) {
22000 if (ty == Ity_I32)
22001 loadsPC = True;
22002 else // Can't do it for B/H loads
22003 valid = False;
22007 if (valid) {
22008 // if it's a branch, it can't happen in the middle of an IT block
22009 // Also, if it is a branch, make it unconditional at this point.
22010 // Doing conditional branches in-line is too complex (for now)
22011 if (loadsPC) {
22012 gen_SIGILL_T_if_in_but_NLI_ITBlock(old_itstate, new_itstate);
22013 // go uncond
22014 mk_skip_over_T32_if_cond_is_false(condT);
22015 condT = IRTemp_INVALID;
22016 // now uncond
22019 IRTemp rNt = newTemp(Ity_I32);
22020 if (rN == 15) {
22021 vassert(!isST);
22022 assign(rNt, binop(Iop_And32, getIRegT(15), mkU32(~3)));
22023 } else {
22024 assign(rNt, getIRegT(rN));
22027 IRTemp transAddr = newTemp(Ity_I32);
22028 assign(transAddr,
22029 binop(bU == 1 ? Iop_Add32 : Iop_Sub32,
22030 mkexpr(rNt), mkU32(imm12)));
22032 IRTemp oldRt = newTemp(Ity_I32);
22033 assign(oldRt, getIRegT(rT));
22035 IRTemp llOldRt = newTemp(Ity_I32);
22036 assign(llOldRt, llGetIReg(rT));
22038 if (isST) {
22039 IRExpr* data = NULL;
22040 switch (ty) {
22041 case Ity_I8:
22042 data = unop(Iop_32to8, mkexpr(oldRt));
22043 break;
22044 case Ity_I16:
22045 data = unop(Iop_32to16, mkexpr(oldRt));
22046 break;
22047 case Ity_I32:
22048 data = mkexpr(oldRt);
22049 break;
22050 default:
22051 vassert(0);
22053 storeGuardedLE(mkexpr(transAddr), data, condT);
22054 } else {
22055 IRTemp newRt = newTemp(Ity_I32);
22056 IRLoadGOp widen = ILGop_INVALID;
22057 switch (ty) {
22058 case Ity_I8:
22059 widen = syned ? ILGop_8Sto32 : ILGop_8Uto32; break;
22060 case Ity_I16:
22061 widen = syned ? ILGop_16Sto32 : ILGop_16Uto32; break;
22062 case Ity_I32:
22063 widen = ILGop_Ident32; break;
22064 default:
22065 vassert(0);
22067 loadGuardedLE(newRt, widen,
22068 mkexpr(transAddr), mkexpr(llOldRt), condT);
22069 if (rT == 15) {
22070 vassert(loadsPC);
22071 /* We'll do the write to the PC just below */
22072 } else {
22073 vassert(!loadsPC);
22074 /* IRTemp_INVALID is OK here because in the case where
22075 condT is false at run time, we're just putting the
22076 old rT value back. */
22077 putIRegT(rT, mkexpr(newRt), IRTemp_INVALID);
22080 if (loadsPC) {
22081 /* Presumably this is an interworking branch. */
22082 vassert(rT == 15);
22083 vassert(condT == IRTemp_INVALID); /* due to check above */
22084 llPutIReg(15, mkexpr(newRt));
22085 dres.jk_StopHere = Ijk_Boring;
22086 dres.whatNext = Dis_StopHere;
22090 DIP("%s.w r%u, [r%u, +#%u]\n", nm, rT, rN, imm12);
22092 goto decode_success;
22096 /* -------------- LDRD/STRD reg+/-#imm8 -------------- */
22097 /* Doubleword loads and stores of the form:
22098 ldrd/strd Rt, Rt2, [Rn, #+/-imm8] or
22099 ldrd/strd Rt, Rt2, [Rn], #+/-imm8 or
22100 ldrd/strd Rt, Rt2, [Rn, #+/-imm8]!
22102 if (INSN0(15,9) == BITS7(1,1,1,0,1,0,0) && INSN0(6,6) == 1) {
22103 UInt bP = INSN0(8,8);
22104 UInt bU = INSN0(7,7);
22105 UInt bW = INSN0(5,5);
22106 UInt bL = INSN0(4,4); // 1: load 0: store
22107 UInt rN = INSN0(3,0);
22108 UInt rT = INSN1(15,12);
22109 UInt rT2 = INSN1(11,8);
22110 UInt imm8 = INSN1(7,0);
22112 Bool valid = True;
22113 if (bP == 0 && bW == 0) valid = False;
22114 if (bW == 1 && (rN == rT || rN == rT2)) valid = False;
22115 if (isBadRegT(rT) || isBadRegT(rT2)) valid = False;
22116 if (bL == 1 && rT == rT2) valid = False;
22117 /* It's OK to use PC as the base register only in the
22118 following case: ldrd Rt, Rt2, [PC, #+/-imm8] */
22119 if (rN == 15 && (bL == 0/*store*/
22120 || bW == 1/*wb*/)) valid = False;
22122 if (valid) {
22123 IRTemp preAddr = newTemp(Ity_I32);
22124 assign(preAddr, 15 == rN
22125 ? binop(Iop_And32, getIRegT(15), mkU32(~3U))
22126 : getIRegT(rN));
22128 IRTemp postAddr = newTemp(Ity_I32);
22129 assign(postAddr, binop(bU == 1 ? Iop_Add32 : Iop_Sub32,
22130 mkexpr(preAddr), mkU32(imm8 << 2)));
22132 IRTemp transAddr = bP == 1 ? postAddr : preAddr;
22134 /* For almost all cases, we do the writeback after the transfers.
22135 However, that leaves the stack "uncovered" in cases like:
22136 strd rD, [sp, #-8]
22137 strd rD, [sp, #-16]
22138 In which case, do the writeback to SP now, instead of later.
22139 This is bad in that it makes the insn non-restartable if the
22140 accesses fault, but at least keeps Memcheck happy. */
22141 Bool writeback_already_done = False;
22142 if (bL == 0/*store*/ && bW == 1/*wb*/
22143 && rN == 13 && rN != rT && rN != rT2
22144 && bU == 0/*minus*/
22145 && ((imm8 << 2) == 8 || (imm8 << 2) == 16)) {
22146 putIRegT(rN, mkexpr(postAddr), condT);
22147 writeback_already_done = True;
22150 if (bL == 0) {
22151 IRTemp oldRt = newTemp(Ity_I32);
22152 IRTemp oldRt2 = newTemp(Ity_I32);
22153 assign(oldRt, getIRegT(rT));
22154 assign(oldRt2, getIRegT(rT2));
22155 storeGuardedLE( mkexpr(transAddr),
22156 mkexpr(oldRt), condT );
22157 storeGuardedLE( binop(Iop_Add32, mkexpr(transAddr), mkU32(4)),
22158 mkexpr(oldRt2), condT );
22159 } else {
22160 IRTemp oldRt = newTemp(Ity_I32);
22161 IRTemp oldRt2 = newTemp(Ity_I32);
22162 IRTemp newRt = newTemp(Ity_I32);
22163 IRTemp newRt2 = newTemp(Ity_I32);
22164 assign(oldRt, llGetIReg(rT));
22165 assign(oldRt2, llGetIReg(rT2));
22166 loadGuardedLE( newRt, ILGop_Ident32,
22167 mkexpr(transAddr),
22168 mkexpr(oldRt), condT );
22169 loadGuardedLE( newRt2, ILGop_Ident32,
22170 binop(Iop_Add32, mkexpr(transAddr), mkU32(4)),
22171 mkexpr(oldRt2), condT );
22172 /* Put unconditionally, since we already switched on the condT
22173 in the guarded loads. */
22174 putIRegT(rT, mkexpr(newRt), IRTemp_INVALID);
22175 putIRegT(rT2, mkexpr(newRt2), IRTemp_INVALID);
22178 if (bW == 1 && !writeback_already_done) {
22179 putIRegT(rN, mkexpr(postAddr), condT);
22182 const HChar* nm = bL ? "ldrd" : "strd";
22184 if (bP == 1 && bW == 0) {
22185 DIP("%s.w r%u, r%u, [r%u, #%c%u]\n",
22186 nm, rT, rT2, rN, bU ? '+' : '-', imm8 << 2);
22188 else if (bP == 1 && bW == 1) {
22189 DIP("%s.w r%u, r%u, [r%u, #%c%u]!\n",
22190 nm, rT, rT2, rN, bU ? '+' : '-', imm8 << 2);
22192 else {
22193 vassert(bP == 0 && bW == 1);
22194 DIP("%s.w r%u, r%u, [r%u], #%c%u\n",
22195 nm, rT, rT2, rN, bU ? '+' : '-', imm8 << 2);
22198 goto decode_success;
22202 /* -------------- (T3) Bcond.W label -------------- */
22203 /* This variant carries its own condition, so can't be part of an
22204 IT block ... */
22205 if (INSN0(15,11) == BITS5(1,1,1,1,0)
22206 && INSN1(15,14) == BITS2(1,0)
22207 && INSN1(12,12) == 0) {
22208 UInt cond = INSN0(9,6);
22209 if (cond != ARMCondAL && cond != ARMCondNV) {
22210 UInt uimm21
22211 = (INSN0(10,10) << (1 + 1 + 6 + 11 + 1))
22212 | (INSN1(11,11) << (1 + 6 + 11 + 1))
22213 | (INSN1(13,13) << (6 + 11 + 1))
22214 | (INSN0(5,0) << (11 + 1))
22215 | (INSN1(10,0) << 1);
22216 uimm21 <<= 11;
22217 Int simm21 = (Int)uimm21;
22218 simm21 >>= 11;
22220 vassert(0 == (guest_R15_curr_instr_notENC & 1));
22221 UInt dst = simm21 + guest_R15_curr_instr_notENC + 4;
22223 /* Not allowed in an IT block; SIGILL if so. */
22224 gen_SIGILL_T_if_in_ITBlock(old_itstate, new_itstate);
22226 IRTemp kondT = newTemp(Ity_I32);
22227 assign( kondT, mk_armg_calculate_condition(cond) );
22228 stmt( IRStmt_Exit( unop(Iop_32to1, mkexpr(kondT)),
22229 Ijk_Boring,
22230 IRConst_U32(dst | 1/*CPSR.T*/),
22231 OFFB_R15T ));
22232 llPutIReg(15, mkU32( (guest_R15_curr_instr_notENC + 4)
22233 | 1 /*CPSR.T*/ ));
22234 dres.jk_StopHere = Ijk_Boring;
22235 dres.whatNext = Dis_StopHere;
22236 DIP("b%s.w 0x%x\n", nCC(cond), dst);
22237 goto decode_success;
22241 /* ---------------- (T4) B.W label ---------------- */
22242 /* ... whereas this variant doesn't carry its own condition, so it
22243 has to be either unconditional or the conditional by virtue of
22244 being the last in an IT block. The upside is that there's 4
22245 more bits available for the jump offset, so it has a 16-times
22246 greater branch range than the T3 variant. */
22247 if (INSN0(15,11) == BITS5(1,1,1,1,0)
22248 && INSN1(15,14) == BITS2(1,0)
22249 && INSN1(12,12) == 1) {
22250 if (1) {
22251 UInt bS = INSN0(10,10);
22252 UInt bJ1 = INSN1(13,13);
22253 UInt bJ2 = INSN1(11,11);
22254 UInt bI1 = 1 ^ (bJ1 ^ bS);
22255 UInt bI2 = 1 ^ (bJ2 ^ bS);
22256 UInt uimm25
22257 = (bS << (1 + 1 + 10 + 11 + 1))
22258 | (bI1 << (1 + 10 + 11 + 1))
22259 | (bI2 << (10 + 11 + 1))
22260 | (INSN0(9,0) << (11 + 1))
22261 | (INSN1(10,0) << 1);
22262 uimm25 <<= 7;
22263 Int simm25 = (Int)uimm25;
22264 simm25 >>= 7;
22266 vassert(0 == (guest_R15_curr_instr_notENC & 1));
22267 UInt dst = simm25 + guest_R15_curr_instr_notENC + 4;
22269 /* If in an IT block, must be the last insn. */
22270 gen_SIGILL_T_if_in_but_NLI_ITBlock(old_itstate, new_itstate);
22272 // go uncond
22273 mk_skip_over_T32_if_cond_is_false(condT);
22274 condT = IRTemp_INVALID;
22275 // now uncond
22277 // branch to dst
22278 llPutIReg(15, mkU32( dst | 1 /*CPSR.T*/ ));
22279 dres.jk_StopHere = Ijk_Boring;
22280 dres.whatNext = Dis_StopHere;
22281 DIP("b.w 0x%x\n", dst);
22282 goto decode_success;
22286 /* ------------------ TBB, TBH ------------------ */
22287 if (INSN0(15,4) == 0xE8D && INSN1(15,5) == 0x780) {
22288 UInt rN = INSN0(3,0);
22289 UInt rM = INSN1(3,0);
22290 UInt bH = INSN1(4,4);
22291 if (bH/*ATC*/ || (rN != 13 && !isBadRegT(rM))) {
22292 /* Must be last or not-in IT block */
22293 gen_SIGILL_T_if_in_but_NLI_ITBlock(old_itstate, new_itstate);
22294 /* Go uncond */
22295 mk_skip_over_T32_if_cond_is_false(condT);
22296 condT = IRTemp_INVALID;
22298 IRExpr* ea
22299 = binop(Iop_Add32,
22300 getIRegT(rN),
22301 bH ? binop(Iop_Shl32, getIRegT(rM), mkU8(1))
22302 : getIRegT(rM));
22304 IRTemp delta = newTemp(Ity_I32);
22305 if (bH) {
22306 assign(delta, unop(Iop_16Uto32, loadLE(Ity_I16, ea)));
22307 } else {
22308 assign(delta, unop(Iop_8Uto32, loadLE(Ity_I8, ea)));
22311 llPutIReg(
22313 binop(Iop_Or32,
22314 binop(Iop_Add32,
22315 getIRegT(15),
22316 binop(Iop_Shl32, mkexpr(delta), mkU8(1))
22318 mkU32(1)
22320 dres.jk_StopHere = Ijk_Boring;
22321 dres.whatNext = Dis_StopHere;
22322 DIP("tb%c [r%u, r%u%s]\n",
22323 bH ? 'h' : 'b', rN, rM, bH ? ", LSL #1" : "");
22324 goto decode_success;
22328 /* ------------------ UBFX ------------------ */
22329 /* ------------------ SBFX ------------------ */
22330 /* There's also ARM versions of same, but it doesn't seem worth the
22331 hassle to common up the handling (it's only a couple of C
22332 statements). */
22333 if ((INSN0(15,4) == 0xF3C // UBFX
22334 || INSN0(15,4) == 0xF34) // SBFX
22335 && INSN1(15,15) == 0 && INSN1(5,5) == 0) {
22336 UInt rN = INSN0(3,0);
22337 UInt rD = INSN1(11,8);
22338 UInt lsb = (INSN1(14,12) << 2) | INSN1(7,6);
22339 UInt wm1 = INSN1(4,0);
22340 UInt msb = lsb + wm1;
22341 if (!isBadRegT(rD) && !isBadRegT(rN) && msb <= 31) {
22342 Bool isU = INSN0(15,4) == 0xF3C;
22343 IRTemp src = newTemp(Ity_I32);
22344 IRTemp tmp = newTemp(Ity_I32);
22345 IRTemp res = newTemp(Ity_I32);
22346 UInt mask = ((1 << wm1) - 1) + (1 << wm1);
22347 vassert(msb >= 0 && msb <= 31);
22348 vassert(mask != 0); // guaranteed by msb being in 0 .. 31 inclusive
22350 assign(src, getIRegT(rN));
22351 assign(tmp, binop(Iop_And32,
22352 binop(Iop_Shr32, mkexpr(src), mkU8(lsb)),
22353 mkU32(mask)));
22354 assign(res, binop(isU ? Iop_Shr32 : Iop_Sar32,
22355 binop(Iop_Shl32, mkexpr(tmp), mkU8(31-wm1)),
22356 mkU8(31-wm1)));
22358 putIRegT(rD, mkexpr(res), condT);
22360 DIP("%s r%u, r%u, #%u, #%u\n",
22361 isU ? "ubfx" : "sbfx", rD, rN, lsb, wm1 + 1);
22362 goto decode_success;
22366 /* ------------------ UXTB ------------------ */
22367 /* ------------------ UXTH ------------------ */
22368 /* ------------------ SXTB ------------------ */
22369 /* ------------------ SXTH ------------------ */
22370 /* ----------------- UXTB16 ----------------- */
22371 /* ----------------- SXTB16 ----------------- */
22372 /* FIXME: this is an exact duplicate of the ARM version. They
22373 should be commoned up. */
22374 if ((INSN0(15,0) == 0xFA5F // UXTB
22375 || INSN0(15,0) == 0xFA1F // UXTH
22376 || INSN0(15,0) == 0xFA4F // SXTB
22377 || INSN0(15,0) == 0xFA0F // SXTH
22378 || INSN0(15,0) == 0xFA3F // UXTB16
22379 || INSN0(15,0) == 0xFA2F) // SXTB16
22380 && INSN1(15,12) == BITS4(1,1,1,1)
22381 && INSN1(7,6) == BITS2(1,0)) {
22382 UInt rD = INSN1(11,8);
22383 UInt rM = INSN1(3,0);
22384 UInt rot = INSN1(5,4);
22385 if (!isBadRegT(rD) && !isBadRegT(rM)) {
22386 const HChar* nm = "???";
22387 IRTemp srcT = newTemp(Ity_I32);
22388 IRTemp rotT = newTemp(Ity_I32);
22389 IRTemp dstT = newTemp(Ity_I32);
22390 assign(srcT, getIRegT(rM));
22391 assign(rotT, genROR32(srcT, 8 * rot));
22392 switch (INSN0(15,0)) {
22393 case 0xFA5F: // UXTB
22394 nm = "uxtb";
22395 assign(dstT, unop(Iop_8Uto32,
22396 unop(Iop_32to8, mkexpr(rotT))));
22397 break;
22398 case 0xFA1F: // UXTH
22399 nm = "uxth";
22400 assign(dstT, unop(Iop_16Uto32,
22401 unop(Iop_32to16, mkexpr(rotT))));
22402 break;
22403 case 0xFA4F: // SXTB
22404 nm = "sxtb";
22405 assign(dstT, unop(Iop_8Sto32,
22406 unop(Iop_32to8, mkexpr(rotT))));
22407 break;
22408 case 0xFA0F: // SXTH
22409 nm = "sxth";
22410 assign(dstT, unop(Iop_16Sto32,
22411 unop(Iop_32to16, mkexpr(rotT))));
22412 break;
22413 case 0xFA3F: // UXTB16
22414 nm = "uxtb16";
22415 assign(dstT, binop(Iop_And32, mkexpr(rotT),
22416 mkU32(0x00FF00FF)));
22417 break;
22418 case 0xFA2F: { // SXTB16
22419 nm = "sxtb16";
22420 IRTemp lo32 = newTemp(Ity_I32);
22421 IRTemp hi32 = newTemp(Ity_I32);
22422 assign(lo32, binop(Iop_And32, mkexpr(rotT), mkU32(0xFF)));
22423 assign(hi32, binop(Iop_Shr32, mkexpr(rotT), mkU8(16)));
22424 assign(
22425 dstT,
22426 binop(Iop_Or32,
22427 binop(Iop_And32,
22428 unop(Iop_8Sto32,
22429 unop(Iop_32to8, mkexpr(lo32))),
22430 mkU32(0xFFFF)),
22431 binop(Iop_Shl32,
22432 unop(Iop_8Sto32,
22433 unop(Iop_32to8, mkexpr(hi32))),
22434 mkU8(16))
22436 break;
22438 default:
22439 vassert(0);
22441 putIRegT(rD, mkexpr(dstT), condT);
22442 DIP("%s r%u, r%u, ror #%u\n", nm, rD, rM, 8 * rot);
22443 goto decode_success;
22447 /* -------------- MUL.W Rd, Rn, Rm -------------- */
22448 if (INSN0(15,4) == 0xFB0
22449 && (INSN1(15,0) & 0xF0F0) == 0xF000) {
22450 UInt rN = INSN0(3,0);
22451 UInt rD = INSN1(11,8);
22452 UInt rM = INSN1(3,0);
22453 if (!isBadRegT(rD) && !isBadRegT(rN) && !isBadRegT(rM)) {
22454 IRTemp res = newTemp(Ity_I32);
22455 assign(res, binop(Iop_Mul32, getIRegT(rN), getIRegT(rM)));
22456 putIRegT(rD, mkexpr(res), condT);
22457 DIP("mul.w r%u, r%u, r%u\n", rD, rN, rM);
22458 goto decode_success;
22462 /* -------------- SDIV.W Rd, Rn, Rm -------------- */
22463 if (INSN0(15,4) == 0xFB9
22464 && (INSN1(15,0) & 0xF0F0) == 0xF0F0) {
22465 UInt rN = INSN0(3,0);
22466 UInt rD = INSN1(11,8);
22467 UInt rM = INSN1(3,0);
22468 if (!isBadRegT(rD) && !isBadRegT(rN) && !isBadRegT(rM)) {
22469 IRTemp res = newTemp(Ity_I32);
22470 IRTemp argL = newTemp(Ity_I32);
22471 IRTemp argR = newTemp(Ity_I32);
22472 assign(argL, getIRegT(rN));
22473 assign(argR, getIRegT(rM));
22474 assign(res, binop(Iop_DivS32, mkexpr(argL), mkexpr(argR)));
22475 putIRegT(rD, mkexpr(res), condT);
22476 DIP("sdiv.w r%u, r%u, r%u\n", rD, rN, rM);
22477 goto decode_success;
22481 /* -------------- UDIV.W Rd, Rn, Rm -------------- */
22482 if (INSN0(15,4) == 0xFBB
22483 && (INSN1(15,0) & 0xF0F0) == 0xF0F0) {
22484 UInt rN = INSN0(3,0);
22485 UInt rD = INSN1(11,8);
22486 UInt rM = INSN1(3,0);
22487 if (!isBadRegT(rD) && !isBadRegT(rN) && !isBadRegT(rM)) {
22488 IRTemp res = newTemp(Ity_I32);
22489 IRTemp argL = newTemp(Ity_I32);
22490 IRTemp argR = newTemp(Ity_I32);
22491 assign(argL, getIRegT(rN));
22492 assign(argR, getIRegT(rM));
22493 assign(res, binop(Iop_DivU32, mkexpr(argL), mkexpr(argR)));
22494 putIRegT(rD, mkexpr(res), condT);
22495 DIP("udiv.w r%u, r%u, r%u\n", rD, rN, rM);
22496 goto decode_success;
22500 /* ------------------ {U,S}MULL ------------------ */
22501 if ((INSN0(15,4) == 0xFB8 || INSN0(15,4) == 0xFBA)
22502 && INSN1(7,4) == BITS4(0,0,0,0)) {
22503 UInt isU = INSN0(5,5);
22504 UInt rN = INSN0(3,0);
22505 UInt rDlo = INSN1(15,12);
22506 UInt rDhi = INSN1(11,8);
22507 UInt rM = INSN1(3,0);
22508 if (!isBadRegT(rDhi) && !isBadRegT(rDlo)
22509 && !isBadRegT(rN) && !isBadRegT(rM) && rDlo != rDhi) {
22510 IRTemp res = newTemp(Ity_I64);
22511 assign(res, binop(isU ? Iop_MullU32 : Iop_MullS32,
22512 getIRegT(rN), getIRegT(rM)));
22513 putIRegT( rDhi, unop(Iop_64HIto32, mkexpr(res)), condT );
22514 putIRegT( rDlo, unop(Iop_64to32, mkexpr(res)), condT );
22515 DIP("%cmull r%u, r%u, r%u, r%u\n",
22516 isU ? 'u' : 's', rDlo, rDhi, rN, rM);
22517 goto decode_success;
22521 /* ------------------ ML{A,S} ------------------ */
22522 if (INSN0(15,4) == 0xFB0
22523 && ( INSN1(7,4) == BITS4(0,0,0,0) // MLA
22524 || INSN1(7,4) == BITS4(0,0,0,1))) { // MLS
22525 UInt rN = INSN0(3,0);
22526 UInt rA = INSN1(15,12);
22527 UInt rD = INSN1(11,8);
22528 UInt rM = INSN1(3,0);
22529 if (!isBadRegT(rD) && !isBadRegT(rN)
22530 && !isBadRegT(rM) && !isBadRegT(rA)) {
22531 Bool isMLA = INSN1(7,4) == BITS4(0,0,0,0);
22532 IRTemp res = newTemp(Ity_I32);
22533 assign(res,
22534 binop(isMLA ? Iop_Add32 : Iop_Sub32,
22535 getIRegT(rA),
22536 binop(Iop_Mul32, getIRegT(rN), getIRegT(rM))));
22537 putIRegT(rD, mkexpr(res), condT);
22538 DIP("%s r%u, r%u, r%u, r%u\n",
22539 isMLA ? "mla" : "mls", rD, rN, rM, rA);
22540 goto decode_success;
22544 /* ------------------ (T3) ADR ------------------ */
22545 if ((INSN0(15,0) == 0xF20F || INSN0(15,0) == 0xF60F)
22546 && INSN1(15,15) == 0) {
22547 /* rD = align4(PC) + imm32 */
22548 UInt rD = INSN1(11,8);
22549 if (!isBadRegT(rD)) {
22550 UInt imm32 = (INSN0(10,10) << 11)
22551 | (INSN1(14,12) << 8) | INSN1(7,0);
22552 putIRegT(rD, binop(Iop_Add32,
22553 binop(Iop_And32, getIRegT(15), mkU32(~3U)),
22554 mkU32(imm32)),
22555 condT);
22556 DIP("add r%u, pc, #%u\n", rD, imm32);
22557 goto decode_success;
22561 /* ----------------- (T1) UMLAL ----------------- */
22562 /* ----------------- (T1) SMLAL ----------------- */
22563 if ((INSN0(15,4) == 0xFBE // UMLAL
22564 || INSN0(15,4) == 0xFBC) // SMLAL
22565 && INSN1(7,4) == BITS4(0,0,0,0)) {
22566 UInt rN = INSN0(3,0);
22567 UInt rDlo = INSN1(15,12);
22568 UInt rDhi = INSN1(11,8);
22569 UInt rM = INSN1(3,0);
22570 if (!isBadRegT(rDlo) && !isBadRegT(rDhi) && !isBadRegT(rN)
22571 && !isBadRegT(rM) && rDhi != rDlo) {
22572 Bool isS = INSN0(15,4) == 0xFBC;
22573 IRTemp argL = newTemp(Ity_I32);
22574 IRTemp argR = newTemp(Ity_I32);
22575 IRTemp old = newTemp(Ity_I64);
22576 IRTemp res = newTemp(Ity_I64);
22577 IRTemp resHi = newTemp(Ity_I32);
22578 IRTemp resLo = newTemp(Ity_I32);
22579 IROp mulOp = isS ? Iop_MullS32 : Iop_MullU32;
22580 assign( argL, getIRegT(rM));
22581 assign( argR, getIRegT(rN));
22582 assign( old, binop(Iop_32HLto64, getIRegT(rDhi), getIRegT(rDlo)) );
22583 assign( res, binop(Iop_Add64,
22584 mkexpr(old),
22585 binop(mulOp, mkexpr(argL), mkexpr(argR))) );
22586 assign( resHi, unop(Iop_64HIto32, mkexpr(res)) );
22587 assign( resLo, unop(Iop_64to32, mkexpr(res)) );
22588 putIRegT( rDhi, mkexpr(resHi), condT );
22589 putIRegT( rDlo, mkexpr(resLo), condT );
22590 DIP("%cmlal r%u, r%u, r%u, r%u\n",
22591 isS ? 's' : 'u', rDlo, rDhi, rN, rM);
22592 goto decode_success;
22596 /* ------------------ (T1) UMAAL ------------------ */
22597 if (INSN0(15,4) == 0xFBE && INSN1(7,4) == BITS4(0,1,1,0)) {
22598 UInt rN = INSN0(3,0);
22599 UInt rDlo = INSN1(15,12);
22600 UInt rDhi = INSN1(11,8);
22601 UInt rM = INSN1(3,0);
22602 if (!isBadRegT(rDlo) && !isBadRegT(rDhi) && !isBadRegT(rN)
22603 && !isBadRegT(rM) && rDhi != rDlo) {
22604 IRTemp argN = newTemp(Ity_I32);
22605 IRTemp argM = newTemp(Ity_I32);
22606 IRTemp argDhi = newTemp(Ity_I32);
22607 IRTemp argDlo = newTemp(Ity_I32);
22608 IRTemp res = newTemp(Ity_I64);
22609 IRTemp resHi = newTemp(Ity_I32);
22610 IRTemp resLo = newTemp(Ity_I32);
22611 assign( argN, getIRegT(rN) );
22612 assign( argM, getIRegT(rM) );
22613 assign( argDhi, getIRegT(rDhi) );
22614 assign( argDlo, getIRegT(rDlo) );
22615 assign( res,
22616 binop(Iop_Add64,
22617 binop(Iop_Add64,
22618 binop(Iop_MullU32, mkexpr(argN), mkexpr(argM)),
22619 unop(Iop_32Uto64, mkexpr(argDhi))),
22620 unop(Iop_32Uto64, mkexpr(argDlo))) );
22621 assign( resHi, unop(Iop_64HIto32, mkexpr(res)) );
22622 assign( resLo, unop(Iop_64to32, mkexpr(res)) );
22623 putIRegT( rDhi, mkexpr(resHi), condT );
22624 putIRegT( rDlo, mkexpr(resLo), condT );
22625 DIP("umaal r%u, r%u, r%u, r%u\n", rDlo, rDhi, rN, rM);
22626 goto decode_success;
22630 /* ------------------- (T1) SMMUL{R} ------------------ */
22631 if (INSN0(15,7) == BITS9(1,1,1,1,1,0,1,1,0)
22632 && INSN0(6,4) == BITS3(1,0,1)
22633 && INSN1(15,12) == BITS4(1,1,1,1)
22634 && INSN1(7,5) == BITS3(0,0,0)) {
22635 UInt bitR = INSN1(4,4);
22636 UInt rD = INSN1(11,8);
22637 UInt rM = INSN1(3,0);
22638 UInt rN = INSN0(3,0);
22639 if (!isBadRegT(rD) && !isBadRegT(rN) && !isBadRegT(rM)) {
22640 IRExpr* res
22641 = unop(Iop_64HIto32,
22642 binop(Iop_Add64,
22643 binop(Iop_MullS32, getIRegT(rN), getIRegT(rM)),
22644 mkU64(bitR ? 0x80000000ULL : 0ULL)));
22645 putIRegT(rD, res, condT);
22646 DIP("smmul%s r%u, r%u, r%u\n",
22647 bitR ? "r" : "", rD, rN, rM);
22648 goto decode_success;
22652 /* ------------------- (T1) SMMLA{R} ------------------ */
22653 if (INSN0(15,7) == BITS9(1,1,1,1,1,0,1,1,0)
22654 && INSN0(6,4) == BITS3(1,0,1)
22655 && INSN1(7,5) == BITS3(0,0,0)) {
22656 UInt bitR = INSN1(4,4);
22657 UInt rA = INSN1(15,12);
22658 UInt rD = INSN1(11,8);
22659 UInt rM = INSN1(3,0);
22660 UInt rN = INSN0(3,0);
22661 if (!isBadRegT(rD) && !isBadRegT(rN) && !isBadRegT(rM) && (rA != 13)) {
22662 IRExpr* res
22663 = unop(Iop_64HIto32,
22664 binop(Iop_Add64,
22665 binop(Iop_Add64,
22666 binop(Iop_32HLto64, getIRegT(rA), mkU32(0)),
22667 binop(Iop_MullS32, getIRegT(rN), getIRegT(rM))),
22668 mkU64(bitR ? 0x80000000ULL : 0ULL)));
22669 putIRegT(rD, res, condT);
22670 DIP("smmla%s r%u, r%u, r%u, r%u\n",
22671 bitR ? "r" : "", rD, rN, rM, rA);
22672 goto decode_success;
22676 /* ------------------ (T2) ADR ------------------ */
22677 if ((INSN0(15,0) == 0xF2AF || INSN0(15,0) == 0xF6AF)
22678 && INSN1(15,15) == 0) {
22679 /* rD = align4(PC) - imm32 */
22680 UInt rD = INSN1(11,8);
22681 if (!isBadRegT(rD)) {
22682 UInt imm32 = (INSN0(10,10) << 11)
22683 | (INSN1(14,12) << 8) | INSN1(7,0);
22684 putIRegT(rD, binop(Iop_Sub32,
22685 binop(Iop_And32, getIRegT(15), mkU32(~3U)),
22686 mkU32(imm32)),
22687 condT);
22688 DIP("sub r%u, pc, #%u\n", rD, imm32);
22689 goto decode_success;
22693 /* ------------------- (T1) BFI ------------------- */
22694 /* ------------------- (T1) BFC ------------------- */
22695 if (INSN0(15,4) == 0xF36 && INSN1(15,15) == 0 && INSN1(5,5) == 0) {
22696 UInt rD = INSN1(11,8);
22697 UInt rN = INSN0(3,0);
22698 UInt msb = INSN1(4,0);
22699 UInt lsb = (INSN1(14,12) << 2) | INSN1(7,6);
22700 if (isBadRegT(rD) || rN == 13 || msb < lsb) {
22701 /* undecodable; fall through */
22702 } else {
22703 IRTemp src = newTemp(Ity_I32);
22704 IRTemp olddst = newTemp(Ity_I32);
22705 IRTemp newdst = newTemp(Ity_I32);
22706 UInt mask = ((UInt)1) << (msb - lsb);
22707 mask = (mask - 1) + mask;
22708 vassert(mask != 0); // guaranteed by "msb < lsb" check above
22709 mask <<= lsb;
22711 assign(src, rN == 15 ? mkU32(0) : getIRegT(rN));
22712 assign(olddst, getIRegT(rD));
22713 assign(newdst,
22714 binop(Iop_Or32,
22715 binop(Iop_And32,
22716 binop(Iop_Shl32, mkexpr(src), mkU8(lsb)),
22717 mkU32(mask)),
22718 binop(Iop_And32,
22719 mkexpr(olddst),
22720 mkU32(~mask)))
22723 putIRegT(rD, mkexpr(newdst), condT);
22725 if (rN == 15) {
22726 DIP("bfc r%u, #%u, #%u\n",
22727 rD, lsb, msb-lsb+1);
22728 } else {
22729 DIP("bfi r%u, r%u, #%u, #%u\n",
22730 rD, rN, lsb, msb-lsb+1);
22732 goto decode_success;
22736 /* ------------------- (T1) SXTAH ------------------- */
22737 /* ------------------- (T1) UXTAH ------------------- */
22738 if ((INSN0(15,4) == 0xFA1 // UXTAH
22739 || INSN0(15,4) == 0xFA0) // SXTAH
22740 && INSN1(15,12) == BITS4(1,1,1,1)
22741 && INSN1(7,6) == BITS2(1,0)) {
22742 Bool isU = INSN0(15,4) == 0xFA1;
22743 UInt rN = INSN0(3,0);
22744 UInt rD = INSN1(11,8);
22745 UInt rM = INSN1(3,0);
22746 UInt rot = INSN1(5,4);
22747 if (!isBadRegT(rD) && !isBadRegT(rN) && !isBadRegT(rM)) {
22748 IRTemp srcL = newTemp(Ity_I32);
22749 IRTemp srcR = newTemp(Ity_I32);
22750 IRTemp res = newTemp(Ity_I32);
22751 assign(srcR, getIRegT(rM));
22752 assign(srcL, getIRegT(rN));
22753 assign(res, binop(Iop_Add32,
22754 mkexpr(srcL),
22755 unop(isU ? Iop_16Uto32 : Iop_16Sto32,
22756 unop(Iop_32to16,
22757 genROR32(srcR, 8 * rot)))));
22758 putIRegT(rD, mkexpr(res), condT);
22759 DIP("%cxtah r%u, r%u, r%u, ror #%u\n",
22760 isU ? 'u' : 's', rD, rN, rM, rot);
22761 goto decode_success;
22765 /* ------------------- (T1) SXTAB ------------------- */
22766 /* ------------------- (T1) UXTAB ------------------- */
22767 if ((INSN0(15,4) == 0xFA5 // UXTAB
22768 || INSN0(15,4) == 0xFA4) // SXTAB
22769 && INSN1(15,12) == BITS4(1,1,1,1)
22770 && INSN1(7,6) == BITS2(1,0)) {
22771 Bool isU = INSN0(15,4) == 0xFA5;
22772 UInt rN = INSN0(3,0);
22773 UInt rD = INSN1(11,8);
22774 UInt rM = INSN1(3,0);
22775 UInt rot = INSN1(5,4);
22776 if (!isBadRegT(rD) && !isBadRegT(rN) && !isBadRegT(rM)) {
22777 IRTemp srcL = newTemp(Ity_I32);
22778 IRTemp srcR = newTemp(Ity_I32);
22779 IRTemp res = newTemp(Ity_I32);
22780 assign(srcR, getIRegT(rM));
22781 assign(srcL, getIRegT(rN));
22782 assign(res, binop(Iop_Add32,
22783 mkexpr(srcL),
22784 unop(isU ? Iop_8Uto32 : Iop_8Sto32,
22785 unop(Iop_32to8,
22786 genROR32(srcR, 8 * rot)))));
22787 putIRegT(rD, mkexpr(res), condT);
22788 DIP("%cxtab r%u, r%u, r%u, ror #%u\n",
22789 isU ? 'u' : 's', rD, rN, rM, rot);
22790 goto decode_success;
22794 /* ------------------- (T1) CLZ ------------------- */
22795 if (INSN0(15,4) == 0xFAB
22796 && INSN1(15,12) == BITS4(1,1,1,1)
22797 && INSN1(7,4) == BITS4(1,0,0,0)) {
22798 UInt rM1 = INSN0(3,0);
22799 UInt rD = INSN1(11,8);
22800 UInt rM2 = INSN1(3,0);
22801 if (!isBadRegT(rD) && !isBadRegT(rM1) && rM1 == rM2) {
22802 IRTemp arg = newTemp(Ity_I32);
22803 IRTemp res = newTemp(Ity_I32);
22804 assign(arg, getIRegT(rM1));
22805 assign(res, IRExpr_ITE(
22806 binop(Iop_CmpEQ32, mkexpr(arg), mkU32(0)),
22807 mkU32(32),
22808 unop(Iop_Clz32, mkexpr(arg))
22810 putIRegT(rD, mkexpr(res), condT);
22811 DIP("clz r%u, r%u\n", rD, rM1);
22812 goto decode_success;
22816 /* ------------------- (T1) RBIT ------------------- */
22817 if (INSN0(15,4) == 0xFA9
22818 && INSN1(15,12) == BITS4(1,1,1,1)
22819 && INSN1(7,4) == BITS4(1,0,1,0)) {
22820 UInt rM1 = INSN0(3,0);
22821 UInt rD = INSN1(11,8);
22822 UInt rM2 = INSN1(3,0);
22823 if (!isBadRegT(rD) && !isBadRegT(rM1) && rM1 == rM2) {
22824 IRTemp arg = newTemp(Ity_I32);
22825 assign(arg, getIRegT(rM1));
22826 IRTemp res = gen_BITREV(arg);
22827 putIRegT(rD, mkexpr(res), condT);
22828 DIP("rbit r%u, r%u\n", rD, rM1);
22829 goto decode_success;
22833 /* ------------------- (T2) REV ------------------- */
22834 /* ------------------- (T2) REV16 ------------------- */
22835 if (INSN0(15,4) == 0xFA9
22836 && INSN1(15,12) == BITS4(1,1,1,1)
22837 && ( INSN1(7,4) == BITS4(1,0,0,0) // REV
22838 || INSN1(7,4) == BITS4(1,0,0,1))) { // REV16
22839 UInt rM1 = INSN0(3,0);
22840 UInt rD = INSN1(11,8);
22841 UInt rM2 = INSN1(3,0);
22842 Bool isREV = INSN1(7,4) == BITS4(1,0,0,0);
22843 if (!isBadRegT(rD) && !isBadRegT(rM1) && rM1 == rM2) {
22844 IRTemp arg = newTemp(Ity_I32);
22845 assign(arg, getIRegT(rM1));
22846 IRTemp res = isREV ? gen_REV(arg) : gen_REV16(arg);
22847 putIRegT(rD, mkexpr(res), condT);
22848 DIP("rev%s r%u, r%u\n", isREV ? "" : "16", rD, rM1);
22849 goto decode_success;
22853 /* ------------------- (T2) REVSH ------------------ */
22854 if (INSN0(15,4) == 0xFA9
22855 && INSN1(15,12) == BITS4(1,1,1,1)
22856 && INSN1(7,4) == BITS4(1,0,1,1)) {
22857 UInt rM1 = INSN0(3,0);
22858 UInt rM2 = INSN1(3,0);
22859 UInt rD = INSN1(11,8);
22860 if (!isBadRegT(rD) && !isBadRegT(rM1) && rM1 == rM2) {
22861 IRTemp irt_rM = newTemp(Ity_I32);
22862 IRTemp irt_hi = newTemp(Ity_I32);
22863 IRTemp irt_low = newTemp(Ity_I32);
22864 IRTemp irt_res = newTemp(Ity_I32);
22865 assign(irt_rM, getIRegT(rM1));
22866 assign(irt_hi,
22867 binop(Iop_Sar32,
22868 binop(Iop_Shl32, mkexpr(irt_rM), mkU8(24)),
22869 mkU8(16)
22872 assign(irt_low,
22873 binop(Iop_And32,
22874 binop(Iop_Shr32, mkexpr(irt_rM), mkU8(8)),
22875 mkU32(0xFF)
22878 assign(irt_res,
22879 binop(Iop_Or32, mkexpr(irt_hi), mkexpr(irt_low))
22881 putIRegT(rD, mkexpr(irt_res), condT);
22882 DIP("revsh r%u, r%u\n", rD, rM1);
22883 goto decode_success;
22887 /* -------------- (T1) MSR apsr, reg -------------- */
22888 if (INSN0(15,4) == 0xF38
22889 && INSN1(15,12) == BITS4(1,0,0,0) && INSN1(9,0) == 0x000) {
22890 UInt rN = INSN0(3,0);
22891 UInt write_ge = INSN1(10,10);
22892 UInt write_nzcvq = INSN1(11,11);
22893 if (!isBadRegT(rN) && (write_nzcvq || write_ge)) {
22894 IRTemp rNt = newTemp(Ity_I32);
22895 assign(rNt, getIRegT(rN));
22896 desynthesise_APSR( write_nzcvq, write_ge, rNt, condT );
22897 DIP("msr cpsr_%s%s, r%u\n",
22898 write_nzcvq ? "f" : "", write_ge ? "g" : "", rN);
22899 goto decode_success;
22903 /* -------------- (T1) MRS reg, apsr -------------- */
22904 if (INSN0(15,0) == 0xF3EF
22905 && INSN1(15,12) == BITS4(1,0,0,0) && INSN1(7,0) == 0x00) {
22906 UInt rD = INSN1(11,8);
22907 if (!isBadRegT(rD)) {
22908 IRTemp apsr = synthesise_APSR();
22909 putIRegT( rD, mkexpr(apsr), condT );
22910 DIP("mrs r%u, cpsr\n", rD);
22911 goto decode_success;
22915 /* ----------------- (T1) LDREX ----------------- */
22916 if (INSN0(15,4) == 0xE85 && INSN1(11,8) == BITS4(1,1,1,1)) {
22917 UInt rN = INSN0(3,0);
22918 UInt rT = INSN1(15,12);
22919 UInt imm8 = INSN1(7,0);
22920 if (!isBadRegT(rT) && rN != 15) {
22921 IRTemp res;
22922 // go uncond
22923 mk_skip_over_T32_if_cond_is_false( condT );
22924 // now uncond
22925 res = newTemp(Ity_I32);
22926 stmt( IRStmt_LLSC(Iend_LE,
22927 res,
22928 binop(Iop_Add32, getIRegT(rN), mkU32(imm8 * 4)),
22929 NULL/*this is a load*/ ));
22930 putIRegT(rT, mkexpr(res), IRTemp_INVALID);
22931 DIP("ldrex r%u, [r%u, #+%u]\n", rT, rN, imm8 * 4);
22932 goto decode_success;
22936 /* --------------- (T1) LDREX{B,H} --------------- */
22937 if (INSN0(15,4) == 0xE8D
22938 && (INSN1(11,0) == 0xF4F || INSN1(11,0) == 0xF5F)) {
22939 UInt rN = INSN0(3,0);
22940 UInt rT = INSN1(15,12);
22941 Bool isH = INSN1(11,0) == 0xF5F;
22942 if (!isBadRegT(rT) && rN != 15) {
22943 IRTemp res;
22944 // go uncond
22945 mk_skip_over_T32_if_cond_is_false( condT );
22946 // now uncond
22947 res = newTemp(isH ? Ity_I16 : Ity_I8);
22948 stmt( IRStmt_LLSC(Iend_LE, res, getIRegT(rN),
22949 NULL/*this is a load*/ ));
22950 putIRegT(rT, unop(isH ? Iop_16Uto32 : Iop_8Uto32, mkexpr(res)),
22951 IRTemp_INVALID);
22952 DIP("ldrex%c r%u, [r%u]\n", isH ? 'h' : 'b', rT, rN);
22953 goto decode_success;
22957 /* --------------- (T1) LDREXD --------------- */
22958 if (INSN0(15,4) == 0xE8D && INSN1(7,0) == 0x7F) {
22959 UInt rN = INSN0(3,0);
22960 UInt rT = INSN1(15,12);
22961 UInt rT2 = INSN1(11,8);
22962 if (!isBadRegT(rT) && !isBadRegT(rT2) && rT != rT2 && rN != 15) {
22963 IRTemp res;
22964 // go uncond
22965 mk_skip_over_T32_if_cond_is_false( condT );
22966 // now uncond
22967 res = newTemp(Ity_I64);
22968 // FIXME: assumes little-endian guest
22969 stmt( IRStmt_LLSC(Iend_LE, res, getIRegT(rN),
22970 NULL/*this is a load*/ ));
22971 // FIXME: assumes little-endian guest
22972 putIRegT(rT, unop(Iop_64to32, mkexpr(res)), IRTemp_INVALID);
22973 putIRegT(rT2, unop(Iop_64HIto32, mkexpr(res)), IRTemp_INVALID);
22974 DIP("ldrexd r%u, r%u, [r%u]\n", rT, rT2, rN);
22975 goto decode_success;
22979 /* ----------------- (T1) STREX ----------------- */
22980 if (INSN0(15,4) == 0xE84) {
22981 UInt rN = INSN0(3,0);
22982 UInt rT = INSN1(15,12);
22983 UInt rD = INSN1(11,8);
22984 UInt imm8 = INSN1(7,0);
22985 if (!isBadRegT(rD) && !isBadRegT(rT) && rN != 15
22986 && rD != rN && rD != rT) {
22987 IRTemp resSC1, resSC32;
22988 // go uncond
22989 mk_skip_over_T32_if_cond_is_false( condT );
22990 // now uncond
22991 /* Ok, now we're unconditional. Do the store. */
22992 resSC1 = newTemp(Ity_I1);
22993 stmt( IRStmt_LLSC(Iend_LE,
22994 resSC1,
22995 binop(Iop_Add32, getIRegT(rN), mkU32(imm8 * 4)),
22996 getIRegT(rT)) );
22997 /* Set rD to 1 on failure, 0 on success. Currently we have
22998 resSC1 == 0 on failure, 1 on success. */
22999 resSC32 = newTemp(Ity_I32);
23000 assign(resSC32,
23001 unop(Iop_1Uto32, unop(Iop_Not1, mkexpr(resSC1))));
23002 putIRegT(rD, mkexpr(resSC32), IRTemp_INVALID);
23003 DIP("strex r%u, r%u, [r%u, #+%u]\n", rD, rT, rN, imm8 * 4);
23004 goto decode_success;
23008 /* --------------- (T1) STREX{B,H} --------------- */
23009 if (INSN0(15,4) == 0xE8C
23010 && (INSN1(11,4) == 0xF4 || INSN1(11,4) == 0xF5)) {
23011 UInt rN = INSN0(3,0);
23012 UInt rT = INSN1(15,12);
23013 UInt rD = INSN1(3,0);
23014 Bool isH = INSN1(11,4) == 0xF5;
23015 if (!isBadRegT(rD) && !isBadRegT(rT) && rN != 15
23016 && rD != rN && rD != rT) {
23017 IRTemp resSC1, resSC32;
23018 // go uncond
23019 mk_skip_over_T32_if_cond_is_false( condT );
23020 // now uncond
23021 /* Ok, now we're unconditional. Do the store. */
23022 resSC1 = newTemp(Ity_I1);
23023 stmt( IRStmt_LLSC(Iend_LE, resSC1, getIRegT(rN),
23024 unop(isH ? Iop_32to16 : Iop_32to8,
23025 getIRegT(rT))) );
23026 /* Set rD to 1 on failure, 0 on success. Currently we have
23027 resSC1 == 0 on failure, 1 on success. */
23028 resSC32 = newTemp(Ity_I32);
23029 assign(resSC32,
23030 unop(Iop_1Uto32, unop(Iop_Not1, mkexpr(resSC1))));
23031 putIRegT(rD, mkexpr(resSC32), IRTemp_INVALID);
23032 DIP("strex%c r%u, r%u, [r%u]\n", isH ? 'h' : 'b', rD, rT, rN);
23033 goto decode_success;
23037 /* ---------------- (T1) STREXD ---------------- */
23038 if (INSN0(15,4) == 0xE8C && INSN1(7,4) == BITS4(0,1,1,1)) {
23039 UInt rN = INSN0(3,0);
23040 UInt rT = INSN1(15,12);
23041 UInt rT2 = INSN1(11,8);
23042 UInt rD = INSN1(3,0);
23043 if (!isBadRegT(rD) && !isBadRegT(rT) && !isBadRegT(rT2)
23044 && rN != 15 && rD != rN && rD != rT && rD != rT2) {
23045 IRTemp resSC1, resSC32, data;
23046 // go uncond
23047 mk_skip_over_T32_if_cond_is_false( condT );
23048 // now uncond
23049 /* Ok, now we're unconditional. Do the store. */
23050 resSC1 = newTemp(Ity_I1);
23051 data = newTemp(Ity_I64);
23052 // FIXME: assumes little-endian guest
23053 assign(data, binop(Iop_32HLto64, getIRegT(rT2), getIRegT(rT)));
23054 // FIXME: assumes little-endian guest
23055 stmt( IRStmt_LLSC(Iend_LE, resSC1, getIRegT(rN), mkexpr(data)));
23056 /* Set rD to 1 on failure, 0 on success. Currently we have
23057 resSC1 == 0 on failure, 1 on success. */
23058 resSC32 = newTemp(Ity_I32);
23059 assign(resSC32,
23060 unop(Iop_1Uto32, unop(Iop_Not1, mkexpr(resSC1))));
23061 putIRegT(rD, mkexpr(resSC32), IRTemp_INVALID);
23062 DIP("strexd r%u, r%u, r%u, [r%u]\n", rD, rT, rT2, rN);
23063 goto decode_success;
23067 /* -------------- v7 barrier insns -------------- */
23068 if (INSN0(15,0) == 0xF3BF && (INSN1(15,0) & 0xFF00) == 0x8F00) {
23069 /* FIXME: should this be unconditional? */
23070 /* XXX this isn't really right, is it? The generated IR does
23071 them unconditionally. I guess it doesn't matter since it
23072 doesn't do any harm to do them even when the guarding
23073 condition is false -- it's just a performance loss. */
23074 switch (INSN1(7,0)) {
23075 case 0x4F: /* DSB sy */
23076 case 0x4E: /* DSB st */
23077 case 0x4B: /* DSB ish */
23078 case 0x4A: /* DSB ishst */
23079 case 0x47: /* DSB nsh */
23080 case 0x46: /* DSB nshst */
23081 case 0x43: /* DSB osh */
23082 case 0x42: /* DSB oshst */
23083 stmt( IRStmt_MBE(Imbe_Fence) );
23084 DIP("DSB\n");
23085 goto decode_success;
23086 case 0x5F: /* DMB sy */
23087 case 0x5E: /* DMB st */
23088 case 0x5B: /* DMB ish */
23089 case 0x5A: /* DMB ishst */
23090 case 0x57: /* DMB nsh */
23091 case 0x56: /* DMB nshst */
23092 case 0x53: /* DMB osh */
23093 case 0x52: /* DMB oshst */
23094 stmt( IRStmt_MBE(Imbe_Fence) );
23095 DIP("DMB\n");
23096 goto decode_success;
23097 case 0x6F: /* ISB */
23098 stmt( IRStmt_MBE(Imbe_Fence) );
23099 DIP("ISB\n");
23100 goto decode_success;
23101 default:
23102 break;
23106 /* ---------------------- PLD{,W} ---------------------- */
23107 if ((INSN0(15,4) & 0xFFD) == 0xF89 && INSN1(15,12) == 0xF) {
23108 /* FIXME: should this be unconditional? */
23109 /* PLD/PLDW immediate, encoding T1 */
23110 UInt rN = INSN0(3,0);
23111 UInt bW = INSN0(5,5);
23112 UInt imm12 = INSN1(11,0);
23113 DIP("pld%s [r%u, #%u]\n", bW ? "w" : "", rN, imm12);
23114 goto decode_success;
23117 if ((INSN0(15,4) & 0xFFD) == 0xF81 && INSN1(15,8) == 0xFC) {
23118 /* FIXME: should this be unconditional? */
23119 /* PLD/PLDW immediate, encoding T2 */
23120 UInt rN = INSN0(3,0);
23121 UInt bW = INSN0(5,5);
23122 UInt imm8 = INSN1(7,0);
23123 DIP("pld%s [r%u, #-%u]\n", bW ? "w" : "", rN, imm8);
23124 goto decode_success;
23127 if ((INSN0(15,4) & 0xFFD) == 0xF81 && INSN1(15,6) == 0x3C0) {
23128 /* FIXME: should this be unconditional? */
23129 /* PLD/PLDW register, encoding T1 */
23130 UInt rN = INSN0(3,0);
23131 UInt rM = INSN1(3,0);
23132 UInt bW = INSN0(5,5);
23133 UInt imm2 = INSN1(5,4);
23134 if (!isBadRegT(rM)) {
23135 DIP("pld%s [r%u, r%u, lsl %u]\n", bW ? "w" : "", rN, rM, imm2);
23136 goto decode_success;
23138 /* fall through */
23141 /* -------------- read CP15 TPIDRURO register ------------- */
23142 /* mrc p15, 0, r0, c13, c0, 3 up to
23143 mrc p15, 0, r14, c13, c0, 3
23145 /* I don't know whether this is really v7-only. But anyway, we
23146 have to support it since arm-linux uses TPIDRURO as a thread
23147 state register. */
23148 if ((INSN0(15,0) == 0xEE1D) && (INSN1(11,0) == 0x0F70)) {
23149 UInt rD = INSN1(15,12);
23150 if (!isBadRegT(rD)) {
23151 putIRegT(rD, IRExpr_Get(OFFB_TPIDRURO, Ity_I32), condT);
23152 DIP("mrc p15,0, r%u, c13, c0, 3\n", rD);
23153 goto decode_success;
23155 /* fall through */
23158 /* ------------ read/write CP15 TPIDRURW register ----------- */
23159 /* mcr p15, 0, r0, c13, c0, 2 (r->cr xfer) up to
23160 mcr p15, 0, r14, c13, c0, 2
23162 mrc p15, 0, r0, c13, c0, 2 (rc->r xfer) up to
23163 mrc p15, 0, r14, c13, c0, 2
23165 if ((INSN0(15,0) == 0xEE0D) && (INSN1(11,0) == 0x0F50)) {
23166 UInt rS = INSN1(15,12);
23167 if (!isBadRegT(rS)) {
23168 putMiscReg32(OFFB_TPIDRURW, getIRegT(rS), condT);
23169 DIP("mcr p15,0, r%u, c13, c0, 2\n", rS);
23170 goto decode_success;
23172 /* fall through */
23174 if ((INSN0(15,0) == 0xEE1D) && (INSN1(11,0) == 0x0F50)) {
23175 UInt rD = INSN1(15,12);
23176 if (!isBadRegT(rD)) {
23177 putIRegT(rD, IRExpr_Get(OFFB_TPIDRURW, Ity_I32), condT);
23178 DIP("mrc p15,0, r%u, c13, c0, 2\n", rD);
23179 goto decode_success;
23181 /* fall through */
23184 /* -------------- read CP15 PMUSRENR register ------------- */
23185 /* mrc p15, 0, r0, c9, c14, 0 up to
23186 mrc p15, 0, r14, c9, c14, 0
23187 See comment on the ARM equivalent of this (above) for details.
23189 if ((INSN0(15,0) == 0xEE19) && (INSN1(11,0) == 0x0F1E)) {
23190 UInt rD = INSN1(15,12);
23191 if (!isBadRegT(rD)) {
23192 putIRegT(rD, mkU32(0), condT);
23193 DIP("mrc p15,0, r%u, c9, c14, 0\n", rD);
23194 goto decode_success;
23196 /* fall through */
23199 /* ------------------- CLREX ------------------ */
23200 if (INSN0(15,0) == 0xF3BF && INSN1(15,0) == 0x8F2F) {
23201 /* AFAICS, this simply cancels a (all?) reservations made by a
23202 (any?) preceding LDREX(es). Arrange to hand it through to
23203 the back end. */
23204 mk_skip_over_T32_if_cond_is_false( condT );
23205 stmt( IRStmt_MBE(Imbe_CancelReservation) );
23206 DIP("clrex\n");
23207 goto decode_success;
23210 /* ------------------- NOP ------------------ */
23211 if (INSN0(15,0) == 0xF3AF && INSN1(15,0) == 0x8000) {
23212 DIP("nop\n");
23213 goto decode_success;
23216 /* -------------- (T1) LDRT reg+#imm8 -------------- */
23217 /* Load Register Unprivileged:
23218 ldrt Rt, [Rn, #imm8]
23220 if (INSN0(15,6) == BITS10(1,1,1,1,1,0,0,0,0,1) && INSN0(5,4) == BITS2(0,1)
23221 && INSN1(11,8) == BITS4(1,1,1,0)) {
23222 UInt rT = INSN1(15,12);
23223 UInt rN = INSN0(3,0);
23224 UInt imm8 = INSN1(7,0);
23225 Bool valid = True;
23226 if (rN == 15 || isBadRegT(rT)) valid = False;
23227 if (valid) {
23228 put_ITSTATE(old_itstate);
23229 IRExpr* ea = binop(Iop_Add32, getIRegT(rN), mkU32(imm8));
23230 IRTemp newRt = newTemp(Ity_I32);
23231 loadGuardedLE( newRt, ILGop_Ident32, ea, llGetIReg(rT), condT );
23232 putIRegT(rT, mkexpr(newRt), IRTemp_INVALID);
23233 put_ITSTATE(new_itstate);
23234 DIP("ldrt r%u, [r%u, #%u]\n", rT, rN, imm8);
23235 goto decode_success;
23239 /* -------------- (T1) STRT reg+#imm8 -------------- */
23240 /* Store Register Unprivileged:
23241 strt Rt, [Rn, #imm8]
23243 if (INSN0(15,6) == BITS10(1,1,1,1,1,0,0,0,0,1) && INSN0(5,4) == BITS2(0,0)
23244 && INSN1(11,8) == BITS4(1,1,1,0)) {
23245 UInt rT = INSN1(15,12);
23246 UInt rN = INSN0(3,0);
23247 UInt imm8 = INSN1(7,0);
23248 Bool valid = True;
23249 if (rN == 15 || isBadRegT(rT)) valid = False;
23250 if (valid) {
23251 put_ITSTATE(old_itstate);
23252 IRExpr* address = binop(Iop_Add32, getIRegT(rN), mkU32(imm8));
23253 storeGuardedLE( address, llGetIReg(rT), condT );
23254 put_ITSTATE(new_itstate);
23255 DIP("strt r%u, [r%u, #%u]\n", rT, rN, imm8);
23256 goto decode_success;
23260 /* -------------- (T1) STRBT reg+#imm8 -------------- */
23261 /* Store Register Byte Unprivileged:
23262 strbt Rt, [Rn, #imm8]
23264 if (INSN0(15,6) == BITS10(1,1,1,1,1,0,0,0,0,0) && INSN0(5,4) == BITS2(0,0)
23265 && INSN1(11,8) == BITS4(1,1,1,0)) {
23266 UInt rT = INSN1(15,12);
23267 UInt rN = INSN0(3,0);
23268 UInt imm8 = INSN1(7,0);
23269 Bool valid = True;
23270 if (rN == 15 || isBadRegT(rT)) valid = False;
23271 if (valid) {
23272 put_ITSTATE(old_itstate);
23273 IRExpr* address = binop(Iop_Add32, getIRegT(rN), mkU32(imm8));
23274 IRExpr* data = unop(Iop_32to8, llGetIReg(rT));
23275 storeGuardedLE( address, data, condT );
23276 put_ITSTATE(new_itstate);
23277 DIP("strbt r%u, [r%u, #%u]\n", rT, rN, imm8);
23278 goto decode_success;
23282 /* -------------- (T1) LDRHT reg+#imm8 -------------- */
23283 /* Load Register Halfword Unprivileged:
23284 ldrht Rt, [Rn, #imm8]
23286 if (INSN0(15,6) == BITS10(1,1,1,1,1,0,0,0,0,0) && INSN0(5,4) == BITS2(1,1)
23287 && INSN1(11,8) == BITS4(1,1,1,0)) {
23288 UInt rN = INSN0(3,0);
23289 Bool valid = True;
23290 if (rN == 15) {
23291 /* In this case our instruction is LDRH (literal), in fact:
23292 LDRH (literal) was realized earlier, so we don't want to
23293 make it twice. */
23294 valid = False;
23296 UInt rT = INSN1(15,12);
23297 UInt imm8 = INSN1(7,0);
23298 if (isBadRegT(rT)) valid = False;
23299 if (valid) {
23300 put_ITSTATE(old_itstate);
23301 IRExpr* ea = binop(Iop_Add32, getIRegT(rN), mkU32(imm8));
23302 IRTemp newRt = newTemp(Ity_I32);
23303 loadGuardedLE( newRt, ILGop_16Uto32, ea, llGetIReg(rT), condT );
23304 putIRegT(rT, mkexpr(newRt), IRTemp_INVALID);
23305 put_ITSTATE(new_itstate);
23306 DIP("ldrht r%u, [r%u, #%u]\n", rT, rN, imm8);
23307 goto decode_success;
23311 /* -------------- (T1) LDRSHT reg+#imm8 -------------- */
23312 /* Load Register Signed Halfword Unprivileged:
23313 ldrsht Rt, [Rn, #imm8]
23315 if (INSN0(15,6) == BITS10(1,1,1,1,1,0,0,1,0,0) && INSN0(5,4) == BITS2(1,1)
23316 && INSN1(11,8) == BITS4(1,1,1,0)) {
23317 UInt rN = INSN0(3,0);
23318 Bool valid = True;
23319 if (rN == 15) {
23320 /* In this case our instruction is LDRSH (literal), in fact:
23321 LDRSH (literal) was realized earlier, so we don't want to
23322 make it twice. */
23323 valid = False;
23325 UInt rT = INSN1(15,12);
23326 UInt imm8 = INSN1(7,0);
23327 if (isBadRegT(rT)) valid = False;
23328 if (valid) {
23329 put_ITSTATE(old_itstate);
23330 IRExpr* ea = binop(Iop_Add32, getIRegT(rN), mkU32(imm8));
23331 IRTemp newRt = newTemp(Ity_I32);
23332 loadGuardedLE( newRt, ILGop_16Sto32, ea, llGetIReg(rT), condT );
23333 putIRegT(rT, mkexpr(newRt), IRTemp_INVALID);
23334 put_ITSTATE(new_itstate);
23335 DIP("ldrsht r%u, [r%u, #%u]\n", rT, rN, imm8);
23336 goto decode_success;
23340 /* -------------- (T1) STRHT reg+#imm8 -------------- */
23341 /* Store Register Halfword Unprivileged:
23342 strht Rt, [Rn, #imm8]
23344 if (INSN0(15,6) == BITS10(1,1,1,1,1,0,0,0,0,0) && INSN0(5,4) == BITS2(1,0)
23345 && INSN1(11,8) == BITS4(1,1,1,0)) {
23346 UInt rT = INSN1(15,12);
23347 UInt rN = INSN0(3,0);
23348 UInt imm8 = INSN1(7,0);
23349 Bool valid = True;
23350 if (rN == 15 || isBadRegT(rT)) valid = False;
23351 if (valid) {
23352 put_ITSTATE(old_itstate);
23353 IRExpr* address = binop(Iop_Add32, getIRegT(rN), mkU32(imm8));
23354 IRExpr* data = unop(Iop_32to16, llGetIReg(rT));
23355 storeGuardedLE( address, data, condT );
23356 put_ITSTATE(new_itstate);
23357 DIP("strht r%u, [r%u, #%u]\n", rT, rN, imm8);
23358 goto decode_success;
23362 /* -------------- (T1) LDRBT reg+#imm8 -------------- */
23363 /* Load Register Byte Unprivileged:
23364 ldrbt Rt, [Rn, #imm8]
23366 if (INSN0(15,6) == BITS10(1,1,1,1,1,0,0,0,0,0) && INSN0(5,4) == BITS2(0,1)
23367 && INSN1(11,8) == BITS4(1,1,1,0)) {
23368 UInt rN = INSN0(3,0);
23369 UInt rT = INSN1(15,12);
23370 UInt imm8 = INSN1(7,0);
23371 Bool valid = True;
23372 if (rN == 15 /* insn is LDRB (literal) */) valid = False;
23373 if (isBadRegT(rT)) valid = False;
23374 if (valid) {
23375 put_ITSTATE(old_itstate);
23376 IRExpr* ea = binop(Iop_Add32, getIRegT(rN), mkU32(imm8));
23377 IRTemp newRt = newTemp(Ity_I32);
23378 loadGuardedLE( newRt, ILGop_8Uto32, ea, llGetIReg(rT), condT );
23379 putIRegT(rT, mkexpr(newRt), IRTemp_INVALID);
23380 put_ITSTATE(new_itstate);
23381 DIP("ldrbt r%u, [r%u, #%u]\n", rT, rN, imm8);
23382 goto decode_success;
23386 /* -------------- (T1) LDRSBT reg+#imm8 -------------- */
23387 /* Load Register Signed Byte Unprivileged:
23388 ldrsbt Rt, [Rn, #imm8]
23390 if (INSN0(15,6) == BITS10(1,1,1,1,1,0,0,1,0,0) && INSN0(5,4) == BITS2(0,1)
23391 && INSN1(11,8) == BITS4(1,1,1,0)) {
23392 UInt rN = INSN0(3,0);
23393 Bool valid = True;
23394 UInt rT = INSN1(15,12);
23395 UInt imm8 = INSN1(7,0);
23396 if (rN == 15 /* insn is LDRSB (literal) */) valid = False;
23397 if (isBadRegT(rT)) valid = False;
23398 if (valid) {
23399 put_ITSTATE(old_itstate);
23400 IRExpr* ea = binop(Iop_Add32, getIRegT(rN), mkU32(imm8));
23401 IRTemp newRt = newTemp(Ity_I32);
23402 loadGuardedLE( newRt, ILGop_8Sto32, ea, llGetIReg(rT), condT );
23403 putIRegT(rT, mkexpr(newRt), IRTemp_INVALID);
23404 put_ITSTATE(new_itstate);
23405 DIP("ldrsbt r%u, [r%u, #%u]\n", rT, rN, imm8);
23406 goto decode_success;
23410 /* -------------- (T1) PLI reg+#imm12 -------------- */
23411 /* Preload Instruction:
23412 pli [Rn, #imm12]
23414 if (INSN0(15,6) == BITS10(1,1,1,1,1,0,0,1,1,0) && INSN0(5,4) == BITS2(0,1)
23415 && INSN1(15,12) == BITS4(1,1,1,1)) {
23416 UInt rN = INSN0(3,0);
23417 UInt imm12 = INSN1(11,0);
23418 if (rN != 15) {
23419 DIP("pli [r%u, #%u]\n", rN, imm12);
23420 goto decode_success;
23424 /* -------------- (T2) PLI reg-#imm8 -------------- */
23425 /* Preload Instruction:
23426 pli [Rn, #-imm8]
23428 if (INSN0(15,6) == BITS10(1,1,1,1,1,0,0,1,0,0) && INSN0(5,4) == BITS2(0,1)
23429 && INSN1(15,8) == BITS8(1,1,1,1,1,1,0,0)) {
23430 UInt rN = INSN0(3,0);
23431 UInt imm8 = INSN1(7,0);
23432 if (rN != 15) {
23433 DIP("pli [r%u, #-%u]\n", rN, imm8);
23434 goto decode_success;
23438 /* -------------- (T3) PLI PC+/-#imm12 -------------- */
23439 /* Preload Instruction:
23440 pli [PC, #+/-imm12]
23442 if (INSN0(15,8) == BITS8(1,1,1,1,1,0,0,1)
23443 && INSN0(6,0) == BITS7(0,0,1,1,1,1,1)
23444 && INSN1(15,12) == BITS4(1,1,1,1)) {
23445 UInt imm12 = INSN1(11,0);
23446 UInt bU = INSN0(7,7);
23447 DIP("pli [pc, #%c%u]\n", bU == 1 ? '+' : '-', imm12);
23448 goto decode_success;
23451 /* ----------------------------------------------------------- */
23452 /* -- VFP (CP 10, CP 11) instructions (in Thumb mode) -- */
23453 /* ----------------------------------------------------------- */
23455 if (INSN0(15,12) == BITS4(1,1,1,0)) {
23456 UInt insn28 = (INSN0(11,0) << 16) | INSN1(15,0);
23457 Bool ok_vfp = decode_CP10_CP11_instruction (
23458 &dres, insn28, condT, ARMCondAL/*bogus*/,
23459 True/*isT*/
23461 if (ok_vfp)
23462 goto decode_success;
23465 /* ----------------------------------------------------------- */
23466 /* -- NEON instructions (only v7 and below, in Thumb mode) -- */
23467 /* ----------------------------------------------------------- */
23469 if (archinfo->hwcaps & VEX_HWCAPS_ARM_NEON) {
23470 UInt insn32 = (INSN0(15,0) << 16) | INSN1(15,0);
23471 Bool ok_neon = decode_NEON_instruction_ARMv7_and_below(
23472 &dres, insn32, condT, True/*isT*/
23474 if (ok_neon)
23475 goto decode_success;
23478 /* ----------------------------------------------------------- */
23479 /* -- v6 media instructions (in Thumb mode) -- */
23480 /* ----------------------------------------------------------- */
23482 { UInt insn32 = (INSN0(15,0) << 16) | INSN1(15,0);
23483 Bool ok_v6m = decode_V6MEDIA_instruction(
23484 &dres, insn32, condT, ARMCondAL/*bogus*/,
23485 True/*isT*/
23487 if (ok_v6m)
23488 goto decode_success;
23491 /* ----------------------------------------------------------- */
23492 /* -- v8 instructions (in Thumb mode) -- */
23493 /* ----------------------------------------------------------- */
23495 /* If we get here, it means that all attempts to decode the
23496 instruction as ARMv7 or earlier have failed. So, if we're doing
23497 ARMv8 or later, here is the point to try for it. */
23499 if (VEX_ARM_ARCHLEVEL(archinfo->hwcaps) >= 8) {
23500 UInt insn32 = (INSN0(15,0) << 16) | INSN1(15,0);
23501 Bool ok_v8
23502 = decode_V8_instruction( &dres, insn32, condT, True/*isT*/,
23503 old_itstate, new_itstate );
23504 if (ok_v8)
23505 goto decode_success;
23508 /* ----------------------------------------------------------- */
23509 /* -- Undecodable -- */
23510 /* ----------------------------------------------------------- */
23512 goto decode_failure;
23513 /*NOTREACHED*/
23515 decode_failure:
23516 /* All decode failures end up here. */
23517 if (sigill_diag)
23518 vex_printf("disInstr(thumb): unhandled instruction: "
23519 "0x%04x 0x%04x\n", (UInt)insn0, (UInt)insn1);
23521 /* Back up ITSTATE to the initial value for this instruction.
23522 If we don't do that, any subsequent restart of the instruction
23523 will restart with the wrong value. */
23524 if (old_itstate != IRTemp_INVALID)
23525 put_ITSTATE(old_itstate);
23527 /* Tell the dispatcher that this insn cannot be decoded, and so has
23528 not been executed, and (is currently) the next to be executed.
23529 R15 should be up-to-date since it made so at the start of each
23530 insn, but nevertheless be paranoid and update it again right
23531 now. */
23532 vassert(0 == (guest_R15_curr_instr_notENC & 1));
23533 llPutIReg( 15, mkU32(guest_R15_curr_instr_notENC | 1) );
23534 dres.len = 0;
23535 dres.whatNext = Dis_StopHere;
23536 dres.jk_StopHere = Ijk_NoDecode;
23537 dres.continueAt = 0;
23538 return dres;
23540 decode_success:
23541 /* All decode successes end up here. */
23542 vassert(dres.len == 4 || dres.len == 2 || dres.len == 20);
23543 switch (dres.whatNext) {
23544 case Dis_Continue:
23545 llPutIReg(15, mkU32(dres.len + (guest_R15_curr_instr_notENC | 1)));
23546 break;
23547 case Dis_ResteerU:
23548 case Dis_ResteerC:
23549 llPutIReg(15, mkU32(dres.continueAt));
23550 break;
23551 case Dis_StopHere:
23552 break;
23553 default:
23554 vassert(0);
23557 DIP("\n");
23559 return dres;
23561 # undef INSN0
23562 # undef INSN1
23565 #undef DIP
23566 #undef DIS
23569 /* Helper table for figuring out how many insns an IT insn
23570 conditionalises.
23572 An ITxyz instruction of the format "1011 1111 firstcond mask"
23573 conditionalises some number of instructions, as indicated by the
23574 following table. A value of zero indicates the instruction is
23575 invalid in some way.
23577 mask = 0 means this isn't an IT instruction
23578 fc = 15 (NV) means unpredictable
23580 The line fc = 14 (AL) is different from the others; there are
23581 additional constraints in this case.
23583 mask(0 .. 15)
23584 +--------------------------------
23585 fc(0 | 0 4 3 4 2 4 3 4 1 4 3 4 2 4 3 4
23586 .. | 0 4 3 4 2 4 3 4 1 4 3 4 2 4 3 4
23587 | 0 4 3 4 2 4 3 4 1 4 3 4 2 4 3 4
23588 | 0 4 3 4 2 4 3 4 1 4 3 4 2 4 3 4
23589 | 0 4 3 4 2 4 3 4 1 4 3 4 2 4 3 4
23590 | 0 4 3 4 2 4 3 4 1 4 3 4 2 4 3 4
23591 | 0 4 3 4 2 4 3 4 1 4 3 4 2 4 3 4
23592 | 0 4 3 4 2 4 3 4 1 4 3 4 2 4 3 4
23593 | 0 4 3 4 2 4 3 4 1 4 3 4 2 4 3 4
23594 | 0 4 3 4 2 4 3 4 1 4 3 4 2 4 3 4
23595 | 0 4 3 4 2 4 3 4 1 4 3 4 2 4 3 4
23596 | 0 4 3 4 2 4 3 4 1 4 3 4 2 4 3 4
23597 | 0 4 3 4 2 4 3 4 1 4 3 4 2 4 3 4
23598 | 0 4 3 4 2 4 3 4 1 4 3 4 2 4 3 4
23599 | 0 4 3 0 2 0 0 0 1 0 0 0 0 0 0 0
23600 15) | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
23602 To be conservative with the analysis, let's rule out the mask = 0
23603 case, since that isn't an IT insn at all. But for all the other
23604 cases where the table contains zero, that means unpredictable, so
23605 let's say 4 to be conservative. Hence we have a safe value for any
23606 IT (mask,fc) pair that the CPU would actually identify as an IT
23607 instruction. The final table is
23609 mask(0 .. 15)
23610 +--------------------------------
23611 fc(0 | 0 4 3 4 2 4 3 4 1 4 3 4 2 4 3 4
23612 .. | 0 4 3 4 2 4 3 4 1 4 3 4 2 4 3 4
23613 | 0 4 3 4 2 4 3 4 1 4 3 4 2 4 3 4
23614 | 0 4 3 4 2 4 3 4 1 4 3 4 2 4 3 4
23615 | 0 4 3 4 2 4 3 4 1 4 3 4 2 4 3 4
23616 | 0 4 3 4 2 4 3 4 1 4 3 4 2 4 3 4
23617 | 0 4 3 4 2 4 3 4 1 4 3 4 2 4 3 4
23618 | 0 4 3 4 2 4 3 4 1 4 3 4 2 4 3 4
23619 | 0 4 3 4 2 4 3 4 1 4 3 4 2 4 3 4
23620 | 0 4 3 4 2 4 3 4 1 4 3 4 2 4 3 4
23621 | 0 4 3 4 2 4 3 4 1 4 3 4 2 4 3 4
23622 | 0 4 3 4 2 4 3 4 1 4 3 4 2 4 3 4
23623 | 0 4 3 4 2 4 3 4 1 4 3 4 2 4 3 4
23624 | 0 4 3 4 2 4 3 4 1 4 3 4 2 4 3 4
23625 | 0 4 3 4 2 4 4 4 1 4 4 4 4 4 4 4
23626 15) | 0 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4
23628 static const UChar it_length_table[256]
23629 = { 0, 4, 3, 4, 2, 4, 3, 4, 1, 4, 3, 4, 2, 4, 3, 4,
23630 0, 4, 3, 4, 2, 4, 3, 4, 1, 4, 3, 4, 2, 4, 3, 4,
23631 0, 4, 3, 4, 2, 4, 3, 4, 1, 4, 3, 4, 2, 4, 3, 4,
23632 0, 4, 3, 4, 2, 4, 3, 4, 1, 4, 3, 4, 2, 4, 3, 4,
23633 0, 4, 3, 4, 2, 4, 3, 4, 1, 4, 3, 4, 2, 4, 3, 4,
23634 0, 4, 3, 4, 2, 4, 3, 4, 1, 4, 3, 4, 2, 4, 3, 4,
23635 0, 4, 3, 4, 2, 4, 3, 4, 1, 4, 3, 4, 2, 4, 3, 4,
23636 0, 4, 3, 4, 2, 4, 3, 4, 1, 4, 3, 4, 2, 4, 3, 4,
23637 0, 4, 3, 4, 2, 4, 3, 4, 1, 4, 3, 4, 2, 4, 3, 4,
23638 0, 4, 3, 4, 2, 4, 3, 4, 1, 4, 3, 4, 2, 4, 3, 4,
23639 0, 4, 3, 4, 2, 4, 3, 4, 1, 4, 3, 4, 2, 4, 3, 4,
23640 0, 4, 3, 4, 2, 4, 3, 4, 1, 4, 3, 4, 2, 4, 3, 4,
23641 0, 4, 3, 4, 2, 4, 3, 4, 1, 4, 3, 4, 2, 4, 3, 4,
23642 0, 4, 3, 4, 2, 4, 3, 4, 1, 4, 3, 4, 2, 4, 3, 4,
23643 0, 4, 3, 4, 2, 4, 4, 4, 1, 4, 4, 4, 4, 4, 4, 4,
23644 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4
23648 /*------------------------------------------------------------*/
23649 /*--- Top-level fn ---*/
23650 /*------------------------------------------------------------*/
23652 /* Disassemble a single instruction into IR. The instruction
23653 is located in host memory at &guest_code[delta]. */
23655 DisResult disInstr_ARM ( IRSB* irsb_IN,
23656 Bool (*resteerOkFn) ( void*, Addr ),
23657 Bool resteerCisOk,
23658 void* callback_opaque,
23659 const UChar* guest_code_IN,
23660 Long delta_ENCODED,
23661 Addr guest_IP_ENCODED,
23662 VexArch guest_arch,
23663 const VexArchInfo* archinfo,
23664 const VexAbiInfo* abiinfo,
23665 VexEndness host_endness_IN,
23666 Bool sigill_diag_IN )
23668 DisResult dres;
23669 Bool isThumb = (Bool)(guest_IP_ENCODED & 1);
23671 /* Set globals (see top of this file) */
23672 vassert(guest_arch == VexArchARM);
23674 irsb = irsb_IN;
23675 host_endness = host_endness_IN;
23676 __curr_is_Thumb = isThumb;
23678 if (isThumb) {
23679 guest_R15_curr_instr_notENC = (Addr32)guest_IP_ENCODED - 1;
23680 } else {
23681 guest_R15_curr_instr_notENC = (Addr32)guest_IP_ENCODED;
23684 if (isThumb) {
23685 dres = disInstr_THUMB_WRK ( resteerOkFn,
23686 resteerCisOk, callback_opaque,
23687 &guest_code_IN[delta_ENCODED - 1],
23688 archinfo, abiinfo, sigill_diag_IN );
23689 } else {
23690 dres = disInstr_ARM_WRK ( resteerOkFn,
23691 resteerCisOk, callback_opaque,
23692 &guest_code_IN[delta_ENCODED],
23693 archinfo, abiinfo, sigill_diag_IN );
23696 return dres;
23699 /* Test program for the conversion of IRCmpF64Result values to VFP
23700 nzcv values. See handling of FCMPD et al above. */
23702 UInt foo ( UInt x )
23704 UInt ix = ((x >> 5) & 3) | (x & 1);
23705 UInt termL = (((((ix ^ 1) << 30) - 1) >> 29) + 1);
23706 UInt termR = (ix & (ix >> 1) & 1);
23707 return termL - termR;
23710 void try ( char* s, UInt ir, UInt req )
23712 UInt act = foo(ir);
23713 printf("%s 0x%02x -> req %d%d%d%d act %d%d%d%d (0x%x)\n",
23714 s, ir, (req >> 3) & 1, (req >> 2) & 1,
23715 (req >> 1) & 1, (req >> 0) & 1,
23716 (act >> 3) & 1, (act >> 2) & 1,
23717 (act >> 1) & 1, (act >> 0) & 1, act);
23721 int main ( void )
23723 printf("\n");
23724 try("UN", 0x45, 0b0011);
23725 try("LT", 0x01, 0b1000);
23726 try("GT", 0x00, 0b0010);
23727 try("EQ", 0x40, 0b0110);
23728 printf("\n");
23729 return 0;
23733 /* Spare code for doing reference implementations of various 64-bit
23734 SIMD interleaves/deinterleaves/concatenation ops. */
23736 // Split a 64 bit value into 4 16 bit ones, in 32-bit IRTemps with
23737 // the top halves guaranteed to be zero.
23738 static void break64to16s ( IRTemp* out3, IRTemp* out2, IRTemp* out1,
23739 IRTemp* out0, IRTemp v64 )
23741 if (out3) *out3 = newTemp(Ity_I32);
23742 if (out2) *out2 = newTemp(Ity_I32);
23743 if (out1) *out1 = newTemp(Ity_I32);
23744 if (out0) *out0 = newTemp(Ity_I32);
23745 IRTemp hi32 = newTemp(Ity_I32);
23746 IRTemp lo32 = newTemp(Ity_I32);
23747 assign(hi32, unop(Iop_64HIto32, mkexpr(v64)) );
23748 assign(lo32, unop(Iop_64to32, mkexpr(v64)) );
23749 if (out3) assign(*out3, binop(Iop_Shr32, mkexpr(hi32), mkU8(16)));
23750 if (out2) assign(*out2, binop(Iop_And32, mkexpr(hi32), mkU32(0xFFFF)));
23751 if (out1) assign(*out1, binop(Iop_Shr32, mkexpr(lo32), mkU8(16)));
23752 if (out0) assign(*out0, binop(Iop_And32, mkexpr(lo32), mkU32(0xFFFF)));
23755 // Make a 64 bit value from 4 16 bit ones, each of which is in a 32 bit
23756 // IRTemp.
23757 static IRTemp mk64from16s ( IRTemp in3, IRTemp in2, IRTemp in1, IRTemp in0 )
23759 IRTemp hi32 = newTemp(Ity_I32);
23760 IRTemp lo32 = newTemp(Ity_I32);
23761 assign(hi32,
23762 binop(Iop_Or32,
23763 binop(Iop_Shl32, mkexpr(in3), mkU8(16)),
23764 binop(Iop_And32, mkexpr(in2), mkU32(0xFFFF))));
23765 assign(lo32,
23766 binop(Iop_Or32,
23767 binop(Iop_Shl32, mkexpr(in1), mkU8(16)),
23768 binop(Iop_And32, mkexpr(in0), mkU32(0xFFFF))));
23769 IRTemp res = newTemp(Ity_I64);
23770 assign(res, binop(Iop_32HLto64, mkexpr(hi32), mkexpr(lo32)));
23771 return res;
23774 static IRExpr* mk_InterleaveLO16x4 ( IRTemp a3210, IRTemp b3210 )
23776 // returns a1 b1 a0 b0
23777 IRTemp a1, a0, b1, b0;
23778 break64to16s(NULL, NULL, &a1, &a0, a3210);
23779 break64to16s(NULL, NULL, &b1, &b0, b3210);
23780 return mkexpr(mk64from16s(a1, b1, a0, b0));
23783 static IRExpr* mk_InterleaveHI16x4 ( IRTemp a3210, IRTemp b3210 )
23785 // returns a3 b3 a2 b2
23786 IRTemp a3, a2, b3, b2;
23787 break64to16s(&a3, &a2, NULL, NULL, a3210);
23788 break64to16s(&b3, &b2, NULL, NULL, b3210);
23789 return mkexpr(mk64from16s(a3, b3, a2, b2));
23792 static IRExpr* mk_CatEvenLanes16x4 ( IRTemp a3210, IRTemp b3210 )
23794 // returns a2 a0 b2 b0
23795 IRTemp a2, a0, b2, b0;
23796 break64to16s(NULL, &a2, NULL, &a0, a3210);
23797 break64to16s(NULL, &b2, NULL, &b0, b3210);
23798 return mkexpr(mk64from16s(a2, a0, b2, b0));
23801 static IRExpr* mk_CatOddLanes16x4 ( IRTemp a3210, IRTemp b3210 )
23803 // returns a3 a1 b3 b1
23804 IRTemp a3, a1, b3, b1;
23805 break64to16s(&a3, NULL, &a1, NULL, a3210);
23806 break64to16s(&b3, NULL, &b1, NULL, b3210);
23807 return mkexpr(mk64from16s(a3, a1, b3, b1));
23810 static IRExpr* mk_InterleaveOddLanes16x4 ( IRTemp a3210, IRTemp b3210 )
23812 // returns a3 b3 a1 b1
23813 IRTemp a3, b3, a1, b1;
23814 break64to16s(&a3, NULL, &a1, NULL, a3210);
23815 break64to16s(&b3, NULL, &b1, NULL, b3210);
23816 return mkexpr(mk64from16s(a3, b3, a1, b1));
23819 static IRExpr* mk_InterleaveEvenLanes16x4 ( IRTemp a3210, IRTemp b3210 )
23821 // returns a2 b2 a0 b0
23822 IRTemp a2, b2, a0, b0;
23823 break64to16s(NULL, &a2, NULL, &a0, a3210);
23824 break64to16s(NULL, &b2, NULL, &b0, b3210);
23825 return mkexpr(mk64from16s(a2, b2, a0, b0));
23828 static void break64to8s ( IRTemp* out7, IRTemp* out6, IRTemp* out5,
23829 IRTemp* out4, IRTemp* out3, IRTemp* out2,
23830 IRTemp* out1,IRTemp* out0, IRTemp v64 )
23832 if (out7) *out7 = newTemp(Ity_I32);
23833 if (out6) *out6 = newTemp(Ity_I32);
23834 if (out5) *out5 = newTemp(Ity_I32);
23835 if (out4) *out4 = newTemp(Ity_I32);
23836 if (out3) *out3 = newTemp(Ity_I32);
23837 if (out2) *out2 = newTemp(Ity_I32);
23838 if (out1) *out1 = newTemp(Ity_I32);
23839 if (out0) *out0 = newTemp(Ity_I32);
23840 IRTemp hi32 = newTemp(Ity_I32);
23841 IRTemp lo32 = newTemp(Ity_I32);
23842 assign(hi32, unop(Iop_64HIto32, mkexpr(v64)) );
23843 assign(lo32, unop(Iop_64to32, mkexpr(v64)) );
23844 if (out7)
23845 assign(*out7, binop(Iop_And32,
23846 binop(Iop_Shr32, mkexpr(hi32), mkU8(24)),
23847 mkU32(0xFF)));
23848 if (out6)
23849 assign(*out6, binop(Iop_And32,
23850 binop(Iop_Shr32, mkexpr(hi32), mkU8(16)),
23851 mkU32(0xFF)));
23852 if (out5)
23853 assign(*out5, binop(Iop_And32,
23854 binop(Iop_Shr32, mkexpr(hi32), mkU8(8)),
23855 mkU32(0xFF)));
23856 if (out4)
23857 assign(*out4, binop(Iop_And32, mkexpr(hi32), mkU32(0xFF)));
23858 if (out3)
23859 assign(*out3, binop(Iop_And32,
23860 binop(Iop_Shr32, mkexpr(lo32), mkU8(24)),
23861 mkU32(0xFF)));
23862 if (out2)
23863 assign(*out2, binop(Iop_And32,
23864 binop(Iop_Shr32, mkexpr(lo32), mkU8(16)),
23865 mkU32(0xFF)));
23866 if (out1)
23867 assign(*out1, binop(Iop_And32,
23868 binop(Iop_Shr32, mkexpr(lo32), mkU8(8)),
23869 mkU32(0xFF)));
23870 if (out0)
23871 assign(*out0, binop(Iop_And32, mkexpr(lo32), mkU32(0xFF)));
23874 static IRTemp mk64from8s ( IRTemp in7, IRTemp in6, IRTemp in5, IRTemp in4,
23875 IRTemp in3, IRTemp in2, IRTemp in1, IRTemp in0 )
23877 IRTemp hi32 = newTemp(Ity_I32);
23878 IRTemp lo32 = newTemp(Ity_I32);
23879 assign(hi32,
23880 binop(Iop_Or32,
23881 binop(Iop_Or32,
23882 binop(Iop_Shl32,
23883 binop(Iop_And32, mkexpr(in7), mkU32(0xFF)),
23884 mkU8(24)),
23885 binop(Iop_Shl32,
23886 binop(Iop_And32, mkexpr(in6), mkU32(0xFF)),
23887 mkU8(16))),
23888 binop(Iop_Or32,
23889 binop(Iop_Shl32,
23890 binop(Iop_And32, mkexpr(in5), mkU32(0xFF)), mkU8(8)),
23891 binop(Iop_And32,
23892 mkexpr(in4), mkU32(0xFF)))));
23893 assign(lo32,
23894 binop(Iop_Or32,
23895 binop(Iop_Or32,
23896 binop(Iop_Shl32,
23897 binop(Iop_And32, mkexpr(in3), mkU32(0xFF)),
23898 mkU8(24)),
23899 binop(Iop_Shl32,
23900 binop(Iop_And32, mkexpr(in2), mkU32(0xFF)),
23901 mkU8(16))),
23902 binop(Iop_Or32,
23903 binop(Iop_Shl32,
23904 binop(Iop_And32, mkexpr(in1), mkU32(0xFF)), mkU8(8)),
23905 binop(Iop_And32,
23906 mkexpr(in0), mkU32(0xFF)))));
23907 IRTemp res = newTemp(Ity_I64);
23908 assign(res, binop(Iop_32HLto64, mkexpr(hi32), mkexpr(lo32)));
23909 return res;
23912 static IRExpr* mk_InterleaveLO8x8 ( IRTemp a76543210, IRTemp b76543210 )
23914 // returns a3 b3 a2 b2 a1 b1 a0 b0
23915 IRTemp a3, b3, a2, b2, a1, a0, b1, b0;
23916 break64to8s(NULL, NULL, NULL, NULL, &a3, &a2, &a1, &a0, a76543210);
23917 break64to8s(NULL, NULL, NULL, NULL, &b3, &b2, &b1, &b0, b76543210);
23918 return mkexpr(mk64from8s(a3, b3, a2, b2, a1, b1, a0, b0));
23921 static IRExpr* mk_InterleaveHI8x8 ( IRTemp a76543210, IRTemp b76543210 )
23923 // returns a7 b7 a6 b6 a5 b5 a4 b4
23924 IRTemp a7, b7, a6, b6, a5, b5, a4, b4;
23925 break64to8s(&a7, &a6, &a5, &a4, NULL, NULL, NULL, NULL, a76543210);
23926 break64to8s(&b7, &b6, &b5, &b4, NULL, NULL, NULL, NULL, b76543210);
23927 return mkexpr(mk64from8s(a7, b7, a6, b6, a5, b5, a4, b4));
23930 static IRExpr* mk_CatEvenLanes8x8 ( IRTemp a76543210, IRTemp b76543210 )
23932 // returns a6 a4 a2 a0 b6 b4 b2 b0
23933 IRTemp a6, a4, a2, a0, b6, b4, b2, b0;
23934 break64to8s(NULL, &a6, NULL, &a4, NULL, &a2, NULL, &a0, a76543210);
23935 break64to8s(NULL, &b6, NULL, &b4, NULL, &b2, NULL, &b0, b76543210);
23936 return mkexpr(mk64from8s(a6, a4, a2, a0, b6, b4, b2, b0));
23939 static IRExpr* mk_CatOddLanes8x8 ( IRTemp a76543210, IRTemp b76543210 )
23941 // returns a7 a5 a3 a1 b7 b5 b3 b1
23942 IRTemp a7, a5, a3, a1, b7, b5, b3, b1;
23943 break64to8s(&a7, NULL, &a5, NULL, &a3, NULL, &a1, NULL, a76543210);
23944 break64to8s(&b7, NULL, &b5, NULL, &b3, NULL, &b1, NULL, b76543210);
23945 return mkexpr(mk64from8s(a7, a5, a3, a1, b7, b5, b3, b1));
23948 static IRExpr* mk_InterleaveEvenLanes8x8 ( IRTemp a76543210, IRTemp b76543210 )
23950 // returns a6 b6 a4 b4 a2 b2 a0 b0
23951 IRTemp a6, b6, a4, b4, a2, b2, a0, b0;
23952 break64to8s(NULL, &a6, NULL, &a4, NULL, &a2, NULL, &a0, a76543210);
23953 break64to8s(NULL, &b6, NULL, &b4, NULL, &b2, NULL, &b0, b76543210);
23954 return mkexpr(mk64from8s(a6, b6, a4, b4, a2, b2, a0, b0));
23957 static IRExpr* mk_InterleaveOddLanes8x8 ( IRTemp a76543210, IRTemp b76543210 )
23959 // returns a7 b7 a5 b5 a3 b3 a1 b1
23960 IRTemp a7, b7, a5, b5, a3, b3, a1, b1;
23961 break64to8s(&a7, NULL, &a5, NULL, &a3, NULL, &a1, NULL, a76543210);
23962 break64to8s(&b7, NULL, &b5, NULL, &b3, NULL, &b1, NULL, b76543210);
23963 return mkexpr(mk64from8s(a7, b7, a5, b5, a3, b3, a1, b1));
23966 static IRExpr* mk_InterleaveLO32x2 ( IRTemp a10, IRTemp b10 )
23968 // returns a0 b0
23969 return binop(Iop_32HLto64, unop(Iop_64to32, mkexpr(a10)),
23970 unop(Iop_64to32, mkexpr(b10)));
23973 static IRExpr* mk_InterleaveHI32x2 ( IRTemp a10, IRTemp b10 )
23975 // returns a1 b1
23976 return binop(Iop_32HLto64, unop(Iop_64HIto32, mkexpr(a10)),
23977 unop(Iop_64HIto32, mkexpr(b10)));
23981 /*--------------------------------------------------------------------*/
23982 /*--- end guest_arm_toIR.c ---*/
23983 /*--------------------------------------------------------------------*/