blob: 1bc824af407e0e42b2d301af721a7ec98fed9433 [file] [log] [blame]
sewardjbbcf1882014-01-12 12:49:10 +00001/* -*- mode: C; c-basic-offset: 3; -*- */
2
3/*--------------------------------------------------------------------*/
4/*--- begin guest_arm64_toIR.c ---*/
5/*--------------------------------------------------------------------*/
6
7/*
8 This file is part of Valgrind, a dynamic binary instrumentation
9 framework.
10
11 Copyright (C) 2013-2013 OpenWorks
12 info@open-works.net
13
14 This program is free software; you can redistribute it and/or
15 modify it under the terms of the GNU General Public License as
16 published by the Free Software Foundation; either version 2 of the
17 License, or (at your option) any later version.
18
19 This program is distributed in the hope that it will be useful, but
20 WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 General Public License for more details.
23
24 You should have received a copy of the GNU General Public License
25 along with this program; if not, write to the Free Software
26 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
27 02110-1301, USA.
28
29 The GNU General Public License is contained in the file COPYING.
30*/
31
32//ZZ /* XXXX thumb to check:
33//ZZ that all cases where putIRegT writes r15, we generate a jump.
34//ZZ
35//ZZ All uses of newTemp assign to an IRTemp and not a UInt
36//ZZ
37//ZZ For all thumb loads and stores, including VFP ones, new-ITSTATE is
38//ZZ backed out before the memory op, and restored afterwards. This
39//ZZ needs to happen even after we go uncond. (and for sure it doesn't
40//ZZ happen for VFP loads/stores right now).
41//ZZ
42//ZZ VFP on thumb: check that we exclude all r13/r15 cases that we
43//ZZ should.
44//ZZ
45//ZZ XXXX thumb to do: improve the ITSTATE-zeroing optimisation by
46//ZZ taking into account the number of insns guarded by an IT.
47//ZZ
48//ZZ remove the nasty hack, in the spechelper, of looking for Or32(...,
49//ZZ 0xE0) in as the first arg to armg_calculate_condition, and instead
50//ZZ use Slice44 as specified in comments in the spechelper.
51//ZZ
52//ZZ add specialisations for armg_calculate_flag_c and _v, as they
53//ZZ are moderately often needed in Thumb code.
54//ZZ
55//ZZ Correctness: ITSTATE handling in Thumb SVCs is wrong.
56//ZZ
57//ZZ Correctness (obscure): in m_transtab, when invalidating code
58//ZZ address ranges, invalidate up to 18 bytes after the end of the
59//ZZ range. This is because the ITSTATE optimisation at the top of
60//ZZ _THUMB_WRK below analyses up to 18 bytes before the start of any
61//ZZ given instruction, and so might depend on the invalidated area.
62//ZZ */
63//ZZ
64//ZZ /* Limitations, etc
65//ZZ
66//ZZ - pretty dodgy exception semantics for {LD,ST}Mxx and {LD,ST}RD.
67//ZZ These instructions are non-restartable in the case where the
68//ZZ transfer(s) fault.
69//ZZ
70//ZZ - SWP: the restart jump back is Ijk_Boring; it should be
71//ZZ Ijk_NoRedir but that's expensive. See comments on casLE() in
72//ZZ guest_x86_toIR.c.
73//ZZ */
74
75/* "Special" instructions.
76
77 This instruction decoder can decode four special instructions
78 which mean nothing natively (are no-ops as far as regs/mem are
79 concerned) but have meaning for supporting Valgrind. A special
80 instruction is flagged by a 16-byte preamble:
81
82 93CC0D8C 93CC358C 93CCCD8C 93CCF58C
83 (ror x12, x12, #3; ror x12, x12, #13
84 ror x12, x12, #51; ror x12, x12, #61)
85
86 Following that, one of the following 3 are allowed
87 (standard interpretation in parentheses):
88
89 AA0A014A (orr x10,x10,x10) X3 = client_request ( X4 )
90 AA0B016B (orr x11,x11,x11) X3 = guest_NRADDR
91 AA0C018C (orr x12,x12,x12) branch-and-link-to-noredir X8
92 AA090129 (orr x9,x9,x9) IR injection
93
94 Any other bytes following the 16-byte preamble are illegal and
95 constitute a failure in instruction decoding. This all assumes
96 that the preamble will never occur except in specific code
97 fragments designed for Valgrind to catch.
98*/
99
100/* Translates ARM64 code to IR. */
101
102#include "libvex_basictypes.h"
103#include "libvex_ir.h"
104#include "libvex.h"
105#include "libvex_guest_arm64.h"
106
107#include "main_util.h"
108#include "main_globals.h"
109#include "guest_generic_bb_to_IR.h"
110#include "guest_arm64_defs.h"
111
112
113/*------------------------------------------------------------*/
114/*--- Globals ---*/
115/*------------------------------------------------------------*/
116
117/* These are set at the start of the translation of a instruction, so
118 that we don't have to pass them around endlessly. CONST means does
119 not change during translation of the instruction.
120*/
121
122/* CONST: is the host bigendian? We need to know this in order to do
123 sub-register accesses to the SIMD/FP registers correctly. */
124static Bool host_is_bigendian;
125
126/* CONST: The guest address for the instruction currently being
127 translated. */
128static Addr64 guest_PC_curr_instr;
129
130/* MOD: The IRSB* into which we're generating code. */
131static IRSB* irsb;
132
133
134/*------------------------------------------------------------*/
135/*--- Debugging output ---*/
136/*------------------------------------------------------------*/
137
138#define DIP(format, args...) \
139 if (vex_traceflags & VEX_TRACE_FE) \
140 vex_printf(format, ## args)
141
142#define DIS(buf, format, args...) \
143 if (vex_traceflags & VEX_TRACE_FE) \
144 vex_sprintf(buf, format, ## args)
145
146
147/*------------------------------------------------------------*/
148/*--- Helper bits and pieces for deconstructing the ---*/
149/*--- arm insn stream. ---*/
150/*------------------------------------------------------------*/
151
152/* Do a little-endian load of a 32-bit word, regardless of the
153 endianness of the underlying host. */
154static inline UInt getUIntLittleEndianly ( UChar* p )
155{
156 UInt w = 0;
157 w = (w << 8) | p[3];
158 w = (w << 8) | p[2];
159 w = (w << 8) | p[1];
160 w = (w << 8) | p[0];
161 return w;
162}
163
164/* Sign extend a N-bit value up to 64 bits, by copying
165 bit N-1 into all higher positions. */
166static ULong sx_to_64 ( ULong x, UInt n )
167{
168 vassert(n > 1 && n < 64);
169 Long r = (Long)x;
170 r = (r << (64-n)) >> (64-n);
171 return (ULong)r;
172}
173
174//ZZ /* Do a little-endian load of a 16-bit word, regardless of the
175//ZZ endianness of the underlying host. */
176//ZZ static inline UShort getUShortLittleEndianly ( UChar* p )
177//ZZ {
178//ZZ UShort w = 0;
179//ZZ w = (w << 8) | p[1];
180//ZZ w = (w << 8) | p[0];
181//ZZ return w;
182//ZZ }
183//ZZ
184//ZZ static UInt ROR32 ( UInt x, UInt sh ) {
185//ZZ vassert(sh >= 0 && sh < 32);
186//ZZ if (sh == 0)
187//ZZ return x;
188//ZZ else
189//ZZ return (x << (32-sh)) | (x >> sh);
190//ZZ }
191//ZZ
192//ZZ static Int popcount32 ( UInt x )
193//ZZ {
194//ZZ Int res = 0, i;
195//ZZ for (i = 0; i < 32; i++) {
196//ZZ res += (x & 1);
197//ZZ x >>= 1;
198//ZZ }
199//ZZ return res;
200//ZZ }
201//ZZ
202//ZZ static UInt setbit32 ( UInt x, Int ix, UInt b )
203//ZZ {
204//ZZ UInt mask = 1 << ix;
205//ZZ x &= ~mask;
206//ZZ x |= ((b << ix) & mask);
207//ZZ return x;
208//ZZ }
209
210#define BITS2(_b1,_b0) \
211 (((_b1) << 1) | (_b0))
212
213#define BITS3(_b2,_b1,_b0) \
214 (((_b2) << 2) | ((_b1) << 1) | (_b0))
215
216#define BITS4(_b3,_b2,_b1,_b0) \
217 (((_b3) << 3) | ((_b2) << 2) | ((_b1) << 1) | (_b0))
218
219#define BITS8(_b7,_b6,_b5,_b4,_b3,_b2,_b1,_b0) \
220 ((BITS4((_b7),(_b6),(_b5),(_b4)) << 4) \
221 | BITS4((_b3),(_b2),(_b1),(_b0)))
222
223#define BITS5(_b4,_b3,_b2,_b1,_b0) \
224 (BITS8(0,0,0,(_b4),(_b3),(_b2),(_b1),(_b0)))
225#define BITS6(_b5,_b4,_b3,_b2,_b1,_b0) \
226 (BITS8(0,0,(_b5),(_b4),(_b3),(_b2),(_b1),(_b0)))
227#define BITS7(_b6,_b5,_b4,_b3,_b2,_b1,_b0) \
228 (BITS8(0,(_b6),(_b5),(_b4),(_b3),(_b2),(_b1),(_b0)))
229
230#define BITS9(_b8,_b7,_b6,_b5,_b4,_b3,_b2,_b1,_b0) \
231 (((_b8) << 8) \
232 | BITS8((_b7),(_b6),(_b5),(_b4),(_b3),(_b2),(_b1),(_b0)))
233
234#define BITS10(_b9,_b8,_b7,_b6,_b5,_b4,_b3,_b2,_b1,_b0) \
235 (((_b9) << 9) | ((_b8) << 8) \
236 | BITS8((_b7),(_b6),(_b5),(_b4),(_b3),(_b2),(_b1),(_b0)))
237
238#define BITS11(_b10,_b9,_b8,_b7,_b6,_b5,_b4,_b3,_b2,_b1,_b0) \
239 (((_b10) << 10) \
240 | BITS10(_b9,_b8,_b7,_b6,_b5,_b4,_b3,_b2,_b1,_b0))
241
sewardjdc9259c2014-02-27 11:10:19 +0000242#define BITS12(_b11, _b10,_b9,_b8,_b7,_b6,_b5,_b4,_b3,_b2,_b1,_b0) \
243 (((_b11) << 11) \
244 | BITS11(_b10,_b9,_b8,_b7,_b6,_b5,_b4,_b3,_b2,_b1,_b0))
245
sewardjdf1628c2014-06-10 22:52:05 +0000246#define X00 BITS2(0,0)
247#define X01 BITS2(0,1)
248#define X10 BITS2(1,0)
249#define X11 BITS2(1,1)
250
sewardjbbcf1882014-01-12 12:49:10 +0000251// produces _uint[_bMax:_bMin]
252#define SLICE_UInt(_uint,_bMax,_bMin) \
253 (( ((UInt)(_uint)) >> (_bMin)) \
254 & (UInt)((1ULL << ((_bMax) - (_bMin) + 1)) - 1ULL))
255
256
257/*------------------------------------------------------------*/
258/*--- Helper bits and pieces for creating IR fragments. ---*/
259/*------------------------------------------------------------*/
260
261static IRExpr* mkV128 ( UShort w )
262{
263 return IRExpr_Const(IRConst_V128(w));
264}
265
266static IRExpr* mkU64 ( ULong i )
267{
268 return IRExpr_Const(IRConst_U64(i));
269}
270
271static IRExpr* mkU32 ( UInt i )
272{
273 return IRExpr_Const(IRConst_U32(i));
274}
275
sewardj25523c42014-06-15 19:36:29 +0000276static IRExpr* mkU16 ( UInt i )
277{
278 vassert(i < 65536);
279 return IRExpr_Const(IRConst_U16(i));
280}
281
sewardjbbcf1882014-01-12 12:49:10 +0000282static IRExpr* mkU8 ( UInt i )
283{
284 vassert(i < 256);
285 return IRExpr_Const(IRConst_U8( (UChar)i ));
286}
287
288static IRExpr* mkexpr ( IRTemp tmp )
289{
290 return IRExpr_RdTmp(tmp);
291}
292
293static IRExpr* unop ( IROp op, IRExpr* a )
294{
295 return IRExpr_Unop(op, a);
296}
297
298static IRExpr* binop ( IROp op, IRExpr* a1, IRExpr* a2 )
299{
300 return IRExpr_Binop(op, a1, a2);
301}
302
303static IRExpr* triop ( IROp op, IRExpr* a1, IRExpr* a2, IRExpr* a3 )
304{
305 return IRExpr_Triop(op, a1, a2, a3);
306}
307
308static IRExpr* loadLE ( IRType ty, IRExpr* addr )
309{
310 return IRExpr_Load(Iend_LE, ty, addr);
311}
312
313/* Add a statement to the list held by "irbb". */
314static void stmt ( IRStmt* st )
315{
316 addStmtToIRSB( irsb, st );
317}
318
319static void assign ( IRTemp dst, IRExpr* e )
320{
321 stmt( IRStmt_WrTmp(dst, e) );
322}
323
324static void storeLE ( IRExpr* addr, IRExpr* data )
325{
326 stmt( IRStmt_Store(Iend_LE, addr, data) );
327}
328
329//ZZ static void storeGuardedLE ( IRExpr* addr, IRExpr* data, IRTemp guardT )
330//ZZ {
331//ZZ if (guardT == IRTemp_INVALID) {
332//ZZ /* unconditional */
333//ZZ storeLE(addr, data);
334//ZZ } else {
335//ZZ stmt( IRStmt_StoreG(Iend_LE, addr, data,
336//ZZ binop(Iop_CmpNE32, mkexpr(guardT), mkU32(0))) );
337//ZZ }
338//ZZ }
339//ZZ
340//ZZ static void loadGuardedLE ( IRTemp dst, IRLoadGOp cvt,
341//ZZ IRExpr* addr, IRExpr* alt,
342//ZZ IRTemp guardT /* :: Ity_I32, 0 or 1 */ )
343//ZZ {
344//ZZ if (guardT == IRTemp_INVALID) {
345//ZZ /* unconditional */
346//ZZ IRExpr* loaded = NULL;
347//ZZ switch (cvt) {
348//ZZ case ILGop_Ident32:
349//ZZ loaded = loadLE(Ity_I32, addr); break;
350//ZZ case ILGop_8Uto32:
351//ZZ loaded = unop(Iop_8Uto32, loadLE(Ity_I8, addr)); break;
352//ZZ case ILGop_8Sto32:
353//ZZ loaded = unop(Iop_8Sto32, loadLE(Ity_I8, addr)); break;
354//ZZ case ILGop_16Uto32:
355//ZZ loaded = unop(Iop_16Uto32, loadLE(Ity_I16, addr)); break;
356//ZZ case ILGop_16Sto32:
357//ZZ loaded = unop(Iop_16Sto32, loadLE(Ity_I16, addr)); break;
358//ZZ default:
359//ZZ vassert(0);
360//ZZ }
361//ZZ vassert(loaded != NULL);
362//ZZ assign(dst, loaded);
363//ZZ } else {
364//ZZ /* Generate a guarded load into 'dst', but apply 'cvt' to the
365//ZZ loaded data before putting the data in 'dst'. If the load
366//ZZ does not take place, 'alt' is placed directly in 'dst'. */
367//ZZ stmt( IRStmt_LoadG(Iend_LE, cvt, dst, addr, alt,
368//ZZ binop(Iop_CmpNE32, mkexpr(guardT), mkU32(0))) );
369//ZZ }
370//ZZ }
371
372/* Generate a new temporary of the given type. */
373static IRTemp newTemp ( IRType ty )
374{
375 vassert(isPlausibleIRType(ty));
376 return newIRTemp( irsb->tyenv, ty );
377}
378
379//ZZ /* Produces a value in 0 .. 3, which is encoded as per the type
380//ZZ IRRoundingMode. */
381//ZZ static IRExpr* /* :: Ity_I32 */ get_FAKE_roundingmode ( void )
382//ZZ {
383//ZZ return mkU32(Irrm_NEAREST);
384//ZZ }
385//ZZ
386//ZZ /* Generate an expression for SRC rotated right by ROT. */
387//ZZ static IRExpr* genROR32( IRTemp src, Int rot )
388//ZZ {
389//ZZ vassert(rot >= 0 && rot < 32);
390//ZZ if (rot == 0)
391//ZZ return mkexpr(src);
392//ZZ return
393//ZZ binop(Iop_Or32,
394//ZZ binop(Iop_Shl32, mkexpr(src), mkU8(32 - rot)),
395//ZZ binop(Iop_Shr32, mkexpr(src), mkU8(rot)));
396//ZZ }
397//ZZ
398//ZZ static IRExpr* mkU128 ( ULong i )
399//ZZ {
400//ZZ return binop(Iop_64HLtoV128, mkU64(i), mkU64(i));
401//ZZ }
402//ZZ
403//ZZ /* Generate a 4-aligned version of the given expression if
404//ZZ the given condition is true. Else return it unchanged. */
405//ZZ static IRExpr* align4if ( IRExpr* e, Bool b )
406//ZZ {
407//ZZ if (b)
408//ZZ return binop(Iop_And32, e, mkU32(~3));
409//ZZ else
410//ZZ return e;
411//ZZ }
412
413/* Other IR construction helpers. */
414static IROp mkAND ( IRType ty ) {
415 switch (ty) {
416 case Ity_I32: return Iop_And32;
417 case Ity_I64: return Iop_And64;
418 default: vpanic("mkAND");
419 }
420}
421
422static IROp mkOR ( IRType ty ) {
423 switch (ty) {
424 case Ity_I32: return Iop_Or32;
425 case Ity_I64: return Iop_Or64;
426 default: vpanic("mkOR");
427 }
428}
429
430static IROp mkXOR ( IRType ty ) {
431 switch (ty) {
432 case Ity_I32: return Iop_Xor32;
433 case Ity_I64: return Iop_Xor64;
434 default: vpanic("mkXOR");
435 }
436}
437
438static IROp mkSHL ( IRType ty ) {
439 switch (ty) {
440 case Ity_I32: return Iop_Shl32;
441 case Ity_I64: return Iop_Shl64;
442 default: vpanic("mkSHL");
443 }
444}
445
446static IROp mkSHR ( IRType ty ) {
447 switch (ty) {
448 case Ity_I32: return Iop_Shr32;
449 case Ity_I64: return Iop_Shr64;
450 default: vpanic("mkSHR");
451 }
452}
453
454static IROp mkSAR ( IRType ty ) {
455 switch (ty) {
456 case Ity_I32: return Iop_Sar32;
457 case Ity_I64: return Iop_Sar64;
458 default: vpanic("mkSAR");
459 }
460}
461
462static IROp mkNOT ( IRType ty ) {
463 switch (ty) {
464 case Ity_I32: return Iop_Not32;
465 case Ity_I64: return Iop_Not64;
466 default: vpanic("mkNOT");
467 }
468}
469
470static IROp mkADD ( IRType ty ) {
471 switch (ty) {
472 case Ity_I32: return Iop_Add32;
473 case Ity_I64: return Iop_Add64;
474 default: vpanic("mkADD");
475 }
476}
477
478static IROp mkSUB ( IRType ty ) {
479 switch (ty) {
480 case Ity_I32: return Iop_Sub32;
481 case Ity_I64: return Iop_Sub64;
482 default: vpanic("mkSUB");
483 }
484}
485
486static IROp mkADDF ( IRType ty ) {
487 switch (ty) {
488 case Ity_F32: return Iop_AddF32;
489 case Ity_F64: return Iop_AddF64;
490 default: vpanic("mkADDF");
491 }
492}
493
494static IROp mkSUBF ( IRType ty ) {
495 switch (ty) {
496 case Ity_F32: return Iop_SubF32;
497 case Ity_F64: return Iop_SubF64;
498 default: vpanic("mkSUBF");
499 }
500}
501
502static IROp mkMULF ( IRType ty ) {
503 switch (ty) {
504 case Ity_F32: return Iop_MulF32;
505 case Ity_F64: return Iop_MulF64;
506 default: vpanic("mkMULF");
507 }
508}
509
510static IROp mkDIVF ( IRType ty ) {
511 switch (ty) {
512 case Ity_F32: return Iop_DivF32;
513 case Ity_F64: return Iop_DivF64;
514 default: vpanic("mkMULF");
515 }
516}
517
518static IROp mkNEGF ( IRType ty ) {
519 switch (ty) {
520 case Ity_F32: return Iop_NegF32;
521 case Ity_F64: return Iop_NegF64;
522 default: vpanic("mkNEGF");
523 }
524}
525
526static IROp mkABSF ( IRType ty ) {
527 switch (ty) {
528 case Ity_F32: return Iop_AbsF32;
529 case Ity_F64: return Iop_AbsF64;
530 default: vpanic("mkNEGF");
531 }
532}
533
534static IROp mkSQRTF ( IRType ty ) {
535 switch (ty) {
536 case Ity_F32: return Iop_SqrtF32;
537 case Ity_F64: return Iop_SqrtF64;
538 default: vpanic("mkNEGF");
539 }
540}
541
542static IRExpr* mkU ( IRType ty, ULong imm ) {
543 switch (ty) {
544 case Ity_I32: return mkU32((UInt)(imm & 0xFFFFFFFFULL));
545 case Ity_I64: return mkU64(imm);
546 default: vpanic("mkU");
547 }
548}
549
550/* Generate IR to create 'arg rotated right by imm', for sane values
551 of 'ty' and 'imm'. */
552static IRTemp mathROR ( IRType ty, IRTemp arg, UInt imm )
553{
554 UInt w = 0;
555 if (ty == Ity_I64) {
556 w = 64;
557 } else {
558 vassert(ty == Ity_I32);
559 w = 32;
560 }
561 vassert(w != 0);
562 vassert(imm < w);
563 if (imm == 0) {
564 return arg;
565 }
566 IRTemp res = newTemp(ty);
567 assign(res, binop(mkOR(ty),
568 binop(mkSHL(ty), mkexpr(arg), mkU8(w - imm)),
569 binop(mkSHR(ty), mkexpr(arg), mkU8(imm)) ));
570 return res;
571}
572
573/* Generate IR to set the returned temp to either all-zeroes or
574 all ones, as a copy of arg<imm>. */
575static IRTemp mathREPLICATE ( IRType ty, IRTemp arg, UInt imm )
576{
577 UInt w = 0;
578 if (ty == Ity_I64) {
579 w = 64;
580 } else {
581 vassert(ty == Ity_I32);
582 w = 32;
583 }
584 vassert(w != 0);
585 vassert(imm < w);
586 IRTemp res = newTemp(ty);
587 assign(res, binop(mkSAR(ty),
588 binop(mkSHL(ty), mkexpr(arg), mkU8(w - 1 - imm)),
589 mkU8(w - 1)));
590 return res;
591}
592
sewardj7d009132014-02-20 17:43:38 +0000593/* U-widen 8/16/32/64 bit int expr to 64. */
594static IRExpr* widenUto64 ( IRType srcTy, IRExpr* e )
595{
596 switch (srcTy) {
597 case Ity_I64: return e;
598 case Ity_I32: return unop(Iop_32Uto64, e);
599 case Ity_I16: return unop(Iop_16Uto64, e);
600 case Ity_I8: return unop(Iop_8Uto64, e);
601 default: vpanic("widenUto64(arm64)");
602 }
603}
604
605/* Narrow 64 bit int expr to 8/16/32/64. Clearly only some
606 of these combinations make sense. */
607static IRExpr* narrowFrom64 ( IRType dstTy, IRExpr* e )
608{
609 switch (dstTy) {
610 case Ity_I64: return e;
611 case Ity_I32: return unop(Iop_64to32, e);
612 case Ity_I16: return unop(Iop_64to16, e);
613 case Ity_I8: return unop(Iop_64to8, e);
614 default: vpanic("narrowFrom64(arm64)");
615 }
616}
617
sewardjbbcf1882014-01-12 12:49:10 +0000618
619/*------------------------------------------------------------*/
620/*--- Helpers for accessing guest registers. ---*/
621/*------------------------------------------------------------*/
622
623#define OFFB_X0 offsetof(VexGuestARM64State,guest_X0)
624#define OFFB_X1 offsetof(VexGuestARM64State,guest_X1)
625#define OFFB_X2 offsetof(VexGuestARM64State,guest_X2)
626#define OFFB_X3 offsetof(VexGuestARM64State,guest_X3)
627#define OFFB_X4 offsetof(VexGuestARM64State,guest_X4)
628#define OFFB_X5 offsetof(VexGuestARM64State,guest_X5)
629#define OFFB_X6 offsetof(VexGuestARM64State,guest_X6)
630#define OFFB_X7 offsetof(VexGuestARM64State,guest_X7)
631#define OFFB_X8 offsetof(VexGuestARM64State,guest_X8)
632#define OFFB_X9 offsetof(VexGuestARM64State,guest_X9)
633#define OFFB_X10 offsetof(VexGuestARM64State,guest_X10)
634#define OFFB_X11 offsetof(VexGuestARM64State,guest_X11)
635#define OFFB_X12 offsetof(VexGuestARM64State,guest_X12)
636#define OFFB_X13 offsetof(VexGuestARM64State,guest_X13)
637#define OFFB_X14 offsetof(VexGuestARM64State,guest_X14)
638#define OFFB_X15 offsetof(VexGuestARM64State,guest_X15)
639#define OFFB_X16 offsetof(VexGuestARM64State,guest_X16)
640#define OFFB_X17 offsetof(VexGuestARM64State,guest_X17)
641#define OFFB_X18 offsetof(VexGuestARM64State,guest_X18)
642#define OFFB_X19 offsetof(VexGuestARM64State,guest_X19)
643#define OFFB_X20 offsetof(VexGuestARM64State,guest_X20)
644#define OFFB_X21 offsetof(VexGuestARM64State,guest_X21)
645#define OFFB_X22 offsetof(VexGuestARM64State,guest_X22)
646#define OFFB_X23 offsetof(VexGuestARM64State,guest_X23)
647#define OFFB_X24 offsetof(VexGuestARM64State,guest_X24)
648#define OFFB_X25 offsetof(VexGuestARM64State,guest_X25)
649#define OFFB_X26 offsetof(VexGuestARM64State,guest_X26)
650#define OFFB_X27 offsetof(VexGuestARM64State,guest_X27)
651#define OFFB_X28 offsetof(VexGuestARM64State,guest_X28)
652#define OFFB_X29 offsetof(VexGuestARM64State,guest_X29)
653#define OFFB_X30 offsetof(VexGuestARM64State,guest_X30)
654
sewardj60687882014-01-15 10:25:21 +0000655#define OFFB_XSP offsetof(VexGuestARM64State,guest_XSP)
sewardjbbcf1882014-01-12 12:49:10 +0000656#define OFFB_PC offsetof(VexGuestARM64State,guest_PC)
657
658#define OFFB_CC_OP offsetof(VexGuestARM64State,guest_CC_OP)
659#define OFFB_CC_DEP1 offsetof(VexGuestARM64State,guest_CC_DEP1)
660#define OFFB_CC_DEP2 offsetof(VexGuestARM64State,guest_CC_DEP2)
661#define OFFB_CC_NDEP offsetof(VexGuestARM64State,guest_CC_NDEP)
662
663#define OFFB_TPIDR_EL0 offsetof(VexGuestARM64State,guest_TPIDR_EL0)
664#define OFFB_NRADDR offsetof(VexGuestARM64State,guest_NRADDR)
665
666#define OFFB_Q0 offsetof(VexGuestARM64State,guest_Q0)
667#define OFFB_Q1 offsetof(VexGuestARM64State,guest_Q1)
668#define OFFB_Q2 offsetof(VexGuestARM64State,guest_Q2)
669#define OFFB_Q3 offsetof(VexGuestARM64State,guest_Q3)
670#define OFFB_Q4 offsetof(VexGuestARM64State,guest_Q4)
671#define OFFB_Q5 offsetof(VexGuestARM64State,guest_Q5)
672#define OFFB_Q6 offsetof(VexGuestARM64State,guest_Q6)
673#define OFFB_Q7 offsetof(VexGuestARM64State,guest_Q7)
674#define OFFB_Q8 offsetof(VexGuestARM64State,guest_Q8)
675#define OFFB_Q9 offsetof(VexGuestARM64State,guest_Q9)
676#define OFFB_Q10 offsetof(VexGuestARM64State,guest_Q10)
677#define OFFB_Q11 offsetof(VexGuestARM64State,guest_Q11)
678#define OFFB_Q12 offsetof(VexGuestARM64State,guest_Q12)
679#define OFFB_Q13 offsetof(VexGuestARM64State,guest_Q13)
680#define OFFB_Q14 offsetof(VexGuestARM64State,guest_Q14)
681#define OFFB_Q15 offsetof(VexGuestARM64State,guest_Q15)
682#define OFFB_Q16 offsetof(VexGuestARM64State,guest_Q16)
683#define OFFB_Q17 offsetof(VexGuestARM64State,guest_Q17)
684#define OFFB_Q18 offsetof(VexGuestARM64State,guest_Q18)
685#define OFFB_Q19 offsetof(VexGuestARM64State,guest_Q19)
686#define OFFB_Q20 offsetof(VexGuestARM64State,guest_Q20)
687#define OFFB_Q21 offsetof(VexGuestARM64State,guest_Q21)
688#define OFFB_Q22 offsetof(VexGuestARM64State,guest_Q22)
689#define OFFB_Q23 offsetof(VexGuestARM64State,guest_Q23)
690#define OFFB_Q24 offsetof(VexGuestARM64State,guest_Q24)
691#define OFFB_Q25 offsetof(VexGuestARM64State,guest_Q25)
692#define OFFB_Q26 offsetof(VexGuestARM64State,guest_Q26)
693#define OFFB_Q27 offsetof(VexGuestARM64State,guest_Q27)
694#define OFFB_Q28 offsetof(VexGuestARM64State,guest_Q28)
695#define OFFB_Q29 offsetof(VexGuestARM64State,guest_Q29)
696#define OFFB_Q30 offsetof(VexGuestARM64State,guest_Q30)
697#define OFFB_Q31 offsetof(VexGuestARM64State,guest_Q31)
698
699#define OFFB_FPCR offsetof(VexGuestARM64State,guest_FPCR)
700#define OFFB_FPSR offsetof(VexGuestARM64State,guest_FPSR)
701//ZZ #define OFFB_TPIDRURO offsetof(VexGuestARMState,guest_TPIDRURO)
702//ZZ #define OFFB_ITSTATE offsetof(VexGuestARMState,guest_ITSTATE)
703//ZZ #define OFFB_QFLAG32 offsetof(VexGuestARMState,guest_QFLAG32)
704//ZZ #define OFFB_GEFLAG0 offsetof(VexGuestARMState,guest_GEFLAG0)
705//ZZ #define OFFB_GEFLAG1 offsetof(VexGuestARMState,guest_GEFLAG1)
706//ZZ #define OFFB_GEFLAG2 offsetof(VexGuestARMState,guest_GEFLAG2)
707//ZZ #define OFFB_GEFLAG3 offsetof(VexGuestARMState,guest_GEFLAG3)
708
sewardj05f5e012014-05-04 10:52:11 +0000709#define OFFB_CMSTART offsetof(VexGuestARM64State,guest_CMSTART)
710#define OFFB_CMLEN offsetof(VexGuestARM64State,guest_CMLEN)
sewardjbbcf1882014-01-12 12:49:10 +0000711
712
713/* ---------------- Integer registers ---------------- */
714
715static Int offsetIReg64 ( UInt iregNo )
716{
717 /* Do we care about endianness here? We do if sub-parts of integer
718 registers are accessed. */
719 switch (iregNo) {
720 case 0: return OFFB_X0;
721 case 1: return OFFB_X1;
722 case 2: return OFFB_X2;
723 case 3: return OFFB_X3;
724 case 4: return OFFB_X4;
725 case 5: return OFFB_X5;
726 case 6: return OFFB_X6;
727 case 7: return OFFB_X7;
728 case 8: return OFFB_X8;
729 case 9: return OFFB_X9;
730 case 10: return OFFB_X10;
731 case 11: return OFFB_X11;
732 case 12: return OFFB_X12;
733 case 13: return OFFB_X13;
734 case 14: return OFFB_X14;
735 case 15: return OFFB_X15;
736 case 16: return OFFB_X16;
737 case 17: return OFFB_X17;
738 case 18: return OFFB_X18;
739 case 19: return OFFB_X19;
740 case 20: return OFFB_X20;
741 case 21: return OFFB_X21;
742 case 22: return OFFB_X22;
743 case 23: return OFFB_X23;
744 case 24: return OFFB_X24;
745 case 25: return OFFB_X25;
746 case 26: return OFFB_X26;
747 case 27: return OFFB_X27;
748 case 28: return OFFB_X28;
749 case 29: return OFFB_X29;
750 case 30: return OFFB_X30;
751 /* but not 31 */
752 default: vassert(0);
753 }
754}
755
756static Int offsetIReg64orSP ( UInt iregNo )
757{
sewardj60687882014-01-15 10:25:21 +0000758 return iregNo == 31 ? OFFB_XSP : offsetIReg64(iregNo);
sewardjbbcf1882014-01-12 12:49:10 +0000759}
760
761static const HChar* nameIReg64orZR ( UInt iregNo )
762{
763 vassert(iregNo < 32);
764 static const HChar* names[32]
765 = { "x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7",
766 "x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15",
767 "x16", "x17", "x18", "x19", "x20", "x21", "x22", "x23",
768 "x24", "x25", "x26", "x27", "x28", "x29", "x30", "xzr" };
769 return names[iregNo];
770}
771
772static const HChar* nameIReg64orSP ( UInt iregNo )
773{
774 if (iregNo == 31) {
775 return "sp";
776 }
777 vassert(iregNo < 31);
778 return nameIReg64orZR(iregNo);
779}
780
781static IRExpr* getIReg64orSP ( UInt iregNo )
782{
783 vassert(iregNo < 32);
784 return IRExpr_Get( offsetIReg64orSP(iregNo), Ity_I64 );
785}
786
787static IRExpr* getIReg64orZR ( UInt iregNo )
788{
789 if (iregNo == 31) {
790 return mkU64(0);
791 }
792 vassert(iregNo < 31);
793 return IRExpr_Get( offsetIReg64orSP(iregNo), Ity_I64 );
794}
795
796static void putIReg64orSP ( UInt iregNo, IRExpr* e )
797{
798 vassert(typeOfIRExpr(irsb->tyenv, e) == Ity_I64);
799 stmt( IRStmt_Put(offsetIReg64orSP(iregNo), e) );
800}
801
802static void putIReg64orZR ( UInt iregNo, IRExpr* e )
803{
804 vassert(typeOfIRExpr(irsb->tyenv, e) == Ity_I64);
805 if (iregNo == 31) {
806 return;
807 }
808 vassert(iregNo < 31);
809 stmt( IRStmt_Put(offsetIReg64orSP(iregNo), e) );
810}
811
812static const HChar* nameIReg32orZR ( UInt iregNo )
813{
814 vassert(iregNo < 32);
815 static const HChar* names[32]
816 = { "w0", "w1", "w2", "w3", "w4", "w5", "w6", "w7",
817 "w8", "w9", "w10", "w11", "w12", "w13", "w14", "w15",
818 "w16", "w17", "w18", "w19", "w20", "w21", "w22", "w23",
819 "w24", "w25", "w26", "w27", "w28", "w29", "w30", "wzr" };
820 return names[iregNo];
821}
822
823static const HChar* nameIReg32orSP ( UInt iregNo )
824{
825 if (iregNo == 31) {
826 return "wsp";
827 }
828 vassert(iregNo < 31);
829 return nameIReg32orZR(iregNo);
830}
831
832static IRExpr* getIReg32orSP ( UInt iregNo )
833{
834 vassert(iregNo < 32);
835 return unop(Iop_64to32,
836 IRExpr_Get( offsetIReg64orSP(iregNo), Ity_I64 ));
837}
838
839static IRExpr* getIReg32orZR ( UInt iregNo )
840{
841 if (iregNo == 31) {
842 return mkU32(0);
843 }
844 vassert(iregNo < 31);
845 return unop(Iop_64to32,
846 IRExpr_Get( offsetIReg64orSP(iregNo), Ity_I64 ));
847}
848
849static void putIReg32orSP ( UInt iregNo, IRExpr* e )
850{
851 vassert(typeOfIRExpr(irsb->tyenv, e) == Ity_I32);
852 stmt( IRStmt_Put(offsetIReg64orSP(iregNo), unop(Iop_32Uto64, e)) );
853}
854
855static void putIReg32orZR ( UInt iregNo, IRExpr* e )
856{
857 vassert(typeOfIRExpr(irsb->tyenv, e) == Ity_I32);
858 if (iregNo == 31) {
859 return;
860 }
861 vassert(iregNo < 31);
862 stmt( IRStmt_Put(offsetIReg64orSP(iregNo), unop(Iop_32Uto64, e)) );
863}
864
865static const HChar* nameIRegOrSP ( Bool is64, UInt iregNo )
866{
867 vassert(is64 == True || is64 == False);
868 return is64 ? nameIReg64orSP(iregNo) : nameIReg32orSP(iregNo);
869}
870
871static const HChar* nameIRegOrZR ( Bool is64, UInt iregNo )
872{
873 vassert(is64 == True || is64 == False);
874 return is64 ? nameIReg64orZR(iregNo) : nameIReg32orZR(iregNo);
875}
876
877static IRExpr* getIRegOrZR ( Bool is64, UInt iregNo )
878{
879 vassert(is64 == True || is64 == False);
880 return is64 ? getIReg64orZR(iregNo) : getIReg32orZR(iregNo);
881}
882
883static void putIRegOrZR ( Bool is64, UInt iregNo, IRExpr* e )
884{
885 vassert(is64 == True || is64 == False);
886 if (is64) putIReg64orZR(iregNo, e); else putIReg32orZR(iregNo, e);
887}
888
889static void putPC ( IRExpr* e )
890{
891 vassert(typeOfIRExpr(irsb->tyenv, e) == Ity_I64);
892 stmt( IRStmt_Put(OFFB_PC, e) );
893}
894
895
896/* ---------------- Vector (Q) registers ---------------- */
897
898static Int offsetQReg128 ( UInt qregNo )
899{
900 /* We don't care about endianness at this point. It only becomes
901 relevant when dealing with sections of these registers.*/
902 switch (qregNo) {
903 case 0: return OFFB_Q0;
904 case 1: return OFFB_Q1;
905 case 2: return OFFB_Q2;
906 case 3: return OFFB_Q3;
907 case 4: return OFFB_Q4;
908 case 5: return OFFB_Q5;
909 case 6: return OFFB_Q6;
910 case 7: return OFFB_Q7;
911 case 8: return OFFB_Q8;
912 case 9: return OFFB_Q9;
913 case 10: return OFFB_Q10;
914 case 11: return OFFB_Q11;
915 case 12: return OFFB_Q12;
916 case 13: return OFFB_Q13;
917 case 14: return OFFB_Q14;
918 case 15: return OFFB_Q15;
919 case 16: return OFFB_Q16;
920 case 17: return OFFB_Q17;
921 case 18: return OFFB_Q18;
922 case 19: return OFFB_Q19;
923 case 20: return OFFB_Q20;
924 case 21: return OFFB_Q21;
925 case 22: return OFFB_Q22;
926 case 23: return OFFB_Q23;
927 case 24: return OFFB_Q24;
928 case 25: return OFFB_Q25;
929 case 26: return OFFB_Q26;
930 case 27: return OFFB_Q27;
931 case 28: return OFFB_Q28;
932 case 29: return OFFB_Q29;
933 case 30: return OFFB_Q30;
934 case 31: return OFFB_Q31;
935 default: vassert(0);
936 }
937}
938
sewardjbbcf1882014-01-12 12:49:10 +0000939/* Write to a complete Qreg. */
940static void putQReg128 ( UInt qregNo, IRExpr* e )
941{
942 vassert(qregNo < 32);
943 vassert(typeOfIRExpr(irsb->tyenv, e) == Ity_V128);
944 stmt( IRStmt_Put(offsetQReg128(qregNo), e) );
945}
946
947/* Read a complete Qreg. */
948static IRExpr* getQReg128 ( UInt qregNo )
949{
950 vassert(qregNo < 32);
951 return IRExpr_Get(offsetQReg128(qregNo), Ity_V128);
952}
953
954/* Produce the IR type for some sub-part of a vector. For 32- and 64-
955 bit sub-parts we can choose either integer or float types, and
956 choose float on the basis that that is the common use case and so
957 will give least interference with Put-to-Get forwarding later
958 on. */
959static IRType preferredVectorSubTypeFromSize ( UInt szB )
960{
961 switch (szB) {
962 case 1: return Ity_I8;
963 case 2: return Ity_I16;
964 case 4: return Ity_I32; //Ity_F32;
965 case 8: return Ity_F64;
966 case 16: return Ity_V128;
967 default: vassert(0);
968 }
969}
970
sewardj606c4ba2014-01-26 19:11:14 +0000971/* Find the offset of the laneNo'th lane of type laneTy in the given
972 Qreg. Since the host is little-endian, the least significant lane
973 has the lowest offset. */
974static Int offsetQRegLane ( UInt qregNo, IRType laneTy, UInt laneNo )
sewardjbbcf1882014-01-12 12:49:10 +0000975{
976 vassert(!host_is_bigendian);
977 Int base = offsetQReg128(qregNo);
sewardj606c4ba2014-01-26 19:11:14 +0000978 /* Since the host is little-endian, the least significant lane
979 will be at the lowest address. */
980 /* Restrict this to known types, so as to avoid silently accepting
981 stupid types. */
982 UInt laneSzB = 0;
983 switch (laneTy) {
sewardj5860ec72014-03-01 11:19:45 +0000984 case Ity_I8: laneSzB = 1; break;
985 case Ity_I16: laneSzB = 2; break;
sewardj606c4ba2014-01-26 19:11:14 +0000986 case Ity_F32: case Ity_I32: laneSzB = 4; break;
987 case Ity_F64: case Ity_I64: laneSzB = 8; break;
988 case Ity_V128: laneSzB = 16; break;
989 default: break;
sewardjbbcf1882014-01-12 12:49:10 +0000990 }
sewardj606c4ba2014-01-26 19:11:14 +0000991 vassert(laneSzB > 0);
992 UInt minOff = laneNo * laneSzB;
993 UInt maxOff = minOff + laneSzB - 1;
994 vassert(maxOff < 16);
995 return base + minOff;
sewardjbbcf1882014-01-12 12:49:10 +0000996}
997
sewardj606c4ba2014-01-26 19:11:14 +0000998/* Put to the least significant lane of a Qreg. */
999static void putQRegLO ( UInt qregNo, IRExpr* e )
sewardjbbcf1882014-01-12 12:49:10 +00001000{
1001 IRType ty = typeOfIRExpr(irsb->tyenv, e);
sewardj606c4ba2014-01-26 19:11:14 +00001002 Int off = offsetQRegLane(qregNo, ty, 0);
sewardjbbcf1882014-01-12 12:49:10 +00001003 switch (ty) {
sewardj606c4ba2014-01-26 19:11:14 +00001004 case Ity_I8: case Ity_I16: case Ity_I32: case Ity_I64:
1005 case Ity_F32: case Ity_F64: case Ity_V128:
1006 break;
1007 default:
1008 vassert(0); // Other cases are probably invalid
sewardjbbcf1882014-01-12 12:49:10 +00001009 }
1010 stmt(IRStmt_Put(off, e));
1011}
1012
sewardj606c4ba2014-01-26 19:11:14 +00001013/* Get from the least significant lane of a Qreg. */
1014static IRExpr* getQRegLO ( UInt qregNo, IRType ty )
sewardjbbcf1882014-01-12 12:49:10 +00001015{
sewardj606c4ba2014-01-26 19:11:14 +00001016 Int off = offsetQRegLane(qregNo, ty, 0);
sewardjbbcf1882014-01-12 12:49:10 +00001017 switch (ty) {
sewardjb3553472014-05-15 16:49:21 +00001018 case Ity_I8:
1019 case Ity_I16:
sewardj606c4ba2014-01-26 19:11:14 +00001020 case Ity_I32: case Ity_I64:
1021 case Ity_F32: case Ity_F64: case Ity_V128:
1022 break;
1023 default:
1024 vassert(0); // Other cases are ATC
sewardjbbcf1882014-01-12 12:49:10 +00001025 }
1026 return IRExpr_Get(off, ty);
1027}
1028
sewardj606c4ba2014-01-26 19:11:14 +00001029static const HChar* nameQRegLO ( UInt qregNo, IRType laneTy )
sewardjbbcf1882014-01-12 12:49:10 +00001030{
1031 static const HChar* namesQ[32]
1032 = { "q0", "q1", "q2", "q3", "q4", "q5", "q6", "q7",
1033 "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15",
1034 "q16", "q17", "q18", "q19", "q20", "q21", "q22", "q23",
1035 "q24", "q25", "q26", "q27", "q28", "q29", "q30", "q31" };
1036 static const HChar* namesD[32]
1037 = { "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7",
1038 "d8", "d9", "d10", "d11", "d12", "d13", "d14", "d15",
1039 "d16", "d17", "d18", "d19", "d20", "d21", "d22", "d23",
1040 "d24", "d25", "d26", "d27", "d28", "d29", "d30", "d31" };
1041 static const HChar* namesS[32]
1042 = { "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
1043 "s8", "s9", "s10", "s11", "s12", "s13", "s14", "s15",
1044 "s16", "s17", "s18", "s19", "s20", "s21", "s22", "s23",
1045 "s24", "s25", "s26", "s27", "s28", "s29", "s30", "s31" };
1046 static const HChar* namesH[32]
1047 = { "h0", "h1", "h2", "h3", "h4", "h5", "h6", "h7",
1048 "h8", "h9", "h10", "h11", "h12", "h13", "h14", "h15",
1049 "h16", "h17", "h18", "h19", "h20", "h21", "h22", "h23",
1050 "h24", "h25", "h26", "h27", "h28", "h29", "h30", "h31" };
1051 static const HChar* namesB[32]
1052 = { "b0", "b1", "b2", "b3", "b4", "b5", "b6", "b7",
1053 "b8", "b9", "b10", "b11", "b12", "b13", "b14", "b15",
1054 "b16", "b17", "b18", "b19", "b20", "b21", "b22", "b23",
1055 "b24", "b25", "b26", "b27", "b28", "b29", "b30", "b31" };
1056 vassert(qregNo < 32);
sewardj606c4ba2014-01-26 19:11:14 +00001057 switch (sizeofIRType(laneTy)) {
sewardjbbcf1882014-01-12 12:49:10 +00001058 case 1: return namesB[qregNo];
1059 case 2: return namesH[qregNo];
1060 case 4: return namesS[qregNo];
1061 case 8: return namesD[qregNo];
1062 case 16: return namesQ[qregNo];
1063 default: vassert(0);
1064 }
1065 /*NOTREACHED*/
1066}
1067
sewardj606c4ba2014-01-26 19:11:14 +00001068static const HChar* nameQReg128 ( UInt qregNo )
1069{
1070 return nameQRegLO(qregNo, Ity_V128);
1071}
1072
sewardjbbcf1882014-01-12 12:49:10 +00001073/* Find the offset of the most significant half (8 bytes) of the given
1074 Qreg. This requires knowing the endianness of the host. */
sewardj606c4ba2014-01-26 19:11:14 +00001075static Int offsetQRegHI64 ( UInt qregNo )
sewardjbbcf1882014-01-12 12:49:10 +00001076{
sewardj606c4ba2014-01-26 19:11:14 +00001077 return offsetQRegLane(qregNo, Ity_I64, 1);
sewardjbbcf1882014-01-12 12:49:10 +00001078}
1079
sewardj606c4ba2014-01-26 19:11:14 +00001080static IRExpr* getQRegHI64 ( UInt qregNo )
sewardjbbcf1882014-01-12 12:49:10 +00001081{
sewardj606c4ba2014-01-26 19:11:14 +00001082 return IRExpr_Get(offsetQRegHI64(qregNo), Ity_I64);
sewardjbbcf1882014-01-12 12:49:10 +00001083}
1084
sewardj606c4ba2014-01-26 19:11:14 +00001085static void putQRegHI64 ( UInt qregNo, IRExpr* e )
sewardjbbcf1882014-01-12 12:49:10 +00001086{
1087 IRType ty = typeOfIRExpr(irsb->tyenv, e);
sewardj606c4ba2014-01-26 19:11:14 +00001088 Int off = offsetQRegHI64(qregNo);
sewardjbbcf1882014-01-12 12:49:10 +00001089 switch (ty) {
sewardj606c4ba2014-01-26 19:11:14 +00001090 case Ity_I64: case Ity_F64:
1091 break;
1092 default:
1093 vassert(0); // Other cases are plain wrong
sewardjbbcf1882014-01-12 12:49:10 +00001094 }
1095 stmt(IRStmt_Put(off, e));
1096}
1097
sewardj606c4ba2014-01-26 19:11:14 +00001098/* Put to a specified lane of a Qreg. */
1099static void putQRegLane ( UInt qregNo, UInt laneNo, IRExpr* e )
1100{
1101 IRType laneTy = typeOfIRExpr(irsb->tyenv, e);
1102 Int off = offsetQRegLane(qregNo, laneTy, laneNo);
1103 switch (laneTy) {
1104 case Ity_F64: case Ity_I64:
sewardj32d86752014-03-02 12:47:18 +00001105 case Ity_I32: case Ity_F32:
sewardj5860ec72014-03-01 11:19:45 +00001106 case Ity_I16:
1107 case Ity_I8:
sewardj606c4ba2014-01-26 19:11:14 +00001108 break;
1109 default:
1110 vassert(0); // Other cases are ATC
1111 }
1112 stmt(IRStmt_Put(off, e));
1113}
1114
sewardj32d86752014-03-02 12:47:18 +00001115/* Get from a specified lane of a Qreg. */
sewardj606c4ba2014-01-26 19:11:14 +00001116static IRExpr* getQRegLane ( UInt qregNo, UInt laneNo, IRType laneTy )
1117{
1118 Int off = offsetQRegLane(qregNo, laneTy, laneNo);
1119 switch (laneTy) {
sewardj32d86752014-03-02 12:47:18 +00001120 case Ity_I64: case Ity_I32: case Ity_I16: case Ity_I8:
sewardj85fbb022014-06-12 13:16:01 +00001121 case Ity_F64: case Ity_F32:
sewardj606c4ba2014-01-26 19:11:14 +00001122 break;
1123 default:
1124 vassert(0); // Other cases are ATC
1125 }
1126 return IRExpr_Get(off, laneTy);
1127}
1128
1129
sewardjbbcf1882014-01-12 12:49:10 +00001130//ZZ /* ---------------- Misc registers ---------------- */
1131//ZZ
1132//ZZ static void putMiscReg32 ( UInt gsoffset,
1133//ZZ IRExpr* e, /* :: Ity_I32 */
1134//ZZ IRTemp guardT /* :: Ity_I32, 0 or 1 */)
1135//ZZ {
1136//ZZ switch (gsoffset) {
1137//ZZ case OFFB_FPSCR: break;
1138//ZZ case OFFB_QFLAG32: break;
1139//ZZ case OFFB_GEFLAG0: break;
1140//ZZ case OFFB_GEFLAG1: break;
1141//ZZ case OFFB_GEFLAG2: break;
1142//ZZ case OFFB_GEFLAG3: break;
1143//ZZ default: vassert(0); /* awaiting more cases */
1144//ZZ }
1145//ZZ vassert(typeOfIRExpr(irsb->tyenv, e) == Ity_I32);
1146//ZZ
1147//ZZ if (guardT == IRTemp_INVALID) {
1148//ZZ /* unconditional write */
1149//ZZ stmt(IRStmt_Put(gsoffset, e));
1150//ZZ } else {
1151//ZZ stmt(IRStmt_Put(
1152//ZZ gsoffset,
1153//ZZ IRExpr_ITE( binop(Iop_CmpNE32, mkexpr(guardT), mkU32(0)),
1154//ZZ e, IRExpr_Get(gsoffset, Ity_I32) )
1155//ZZ ));
1156//ZZ }
1157//ZZ }
1158//ZZ
1159//ZZ static IRTemp get_ITSTATE ( void )
1160//ZZ {
1161//ZZ ASSERT_IS_THUMB;
1162//ZZ IRTemp t = newTemp(Ity_I32);
1163//ZZ assign(t, IRExpr_Get( OFFB_ITSTATE, Ity_I32));
1164//ZZ return t;
1165//ZZ }
1166//ZZ
1167//ZZ static void put_ITSTATE ( IRTemp t )
1168//ZZ {
1169//ZZ ASSERT_IS_THUMB;
1170//ZZ stmt( IRStmt_Put( OFFB_ITSTATE, mkexpr(t)) );
1171//ZZ }
1172//ZZ
1173//ZZ static IRTemp get_QFLAG32 ( void )
1174//ZZ {
1175//ZZ IRTemp t = newTemp(Ity_I32);
1176//ZZ assign(t, IRExpr_Get( OFFB_QFLAG32, Ity_I32));
1177//ZZ return t;
1178//ZZ }
1179//ZZ
1180//ZZ static void put_QFLAG32 ( IRTemp t, IRTemp condT )
1181//ZZ {
1182//ZZ putMiscReg32( OFFB_QFLAG32, mkexpr(t), condT );
1183//ZZ }
1184//ZZ
1185//ZZ /* Stickily set the 'Q' flag (APSR bit 27) of the APSR (Application Program
1186//ZZ Status Register) to indicate that overflow or saturation occurred.
1187//ZZ Nb: t must be zero to denote no saturation, and any nonzero
1188//ZZ value to indicate saturation. */
1189//ZZ static void or_into_QFLAG32 ( IRExpr* e, IRTemp condT )
1190//ZZ {
1191//ZZ IRTemp old = get_QFLAG32();
1192//ZZ IRTemp nyu = newTemp(Ity_I32);
1193//ZZ assign(nyu, binop(Iop_Or32, mkexpr(old), e) );
1194//ZZ put_QFLAG32(nyu, condT);
1195//ZZ }
1196
1197
1198/* ---------------- FPCR stuff ---------------- */
1199
1200/* Generate IR to get hold of the rounding mode bits in FPCR, and
1201 convert them to IR format. Bind the final result to the
1202 returned temp. */
1203static IRTemp /* :: Ity_I32 */ mk_get_IR_rounding_mode ( void )
1204{
1205 /* The ARMvfp encoding for rounding mode bits is:
1206 00 to nearest
1207 01 to +infinity
1208 10 to -infinity
1209 11 to zero
1210 We need to convert that to the IR encoding:
1211 00 to nearest (the default)
1212 10 to +infinity
1213 01 to -infinity
1214 11 to zero
1215 Which can be done by swapping bits 0 and 1.
1216 The rmode bits are at 23:22 in FPSCR.
1217 */
1218 IRTemp armEncd = newTemp(Ity_I32);
1219 IRTemp swapped = newTemp(Ity_I32);
1220 /* Fish FPCR[23:22] out, and slide to bottom. Doesn't matter that
1221 we don't zero out bits 24 and above, since the assignment to
1222 'swapped' will mask them out anyway. */
1223 assign(armEncd,
1224 binop(Iop_Shr32, IRExpr_Get(OFFB_FPCR, Ity_I32), mkU8(22)));
1225 /* Now swap them. */
1226 assign(swapped,
1227 binop(Iop_Or32,
1228 binop(Iop_And32,
1229 binop(Iop_Shl32, mkexpr(armEncd), mkU8(1)),
1230 mkU32(2)),
1231 binop(Iop_And32,
1232 binop(Iop_Shr32, mkexpr(armEncd), mkU8(1)),
1233 mkU32(1))
1234 ));
1235 return swapped;
1236}
1237
1238
1239/*------------------------------------------------------------*/
1240/*--- Helpers for flag handling and conditional insns ---*/
1241/*------------------------------------------------------------*/
1242
1243static const HChar* nameARM64Condcode ( ARM64Condcode cond )
1244{
1245 switch (cond) {
1246 case ARM64CondEQ: return "eq";
1247 case ARM64CondNE: return "ne";
1248 case ARM64CondCS: return "cs"; // or 'hs'
1249 case ARM64CondCC: return "cc"; // or 'lo'
1250 case ARM64CondMI: return "mi";
1251 case ARM64CondPL: return "pl";
1252 case ARM64CondVS: return "vs";
1253 case ARM64CondVC: return "vc";
1254 case ARM64CondHI: return "hi";
1255 case ARM64CondLS: return "ls";
1256 case ARM64CondGE: return "ge";
1257 case ARM64CondLT: return "lt";
1258 case ARM64CondGT: return "gt";
1259 case ARM64CondLE: return "le";
1260 case ARM64CondAL: return "al";
1261 case ARM64CondNV: return "nv";
1262 default: vpanic("name_ARM64Condcode");
1263 }
1264}
1265
1266/* and a handy shorthand for it */
1267static const HChar* nameCC ( ARM64Condcode cond ) {
1268 return nameARM64Condcode(cond);
1269}
1270
1271
1272/* Build IR to calculate some particular condition from stored
1273 CC_OP/CC_DEP1/CC_DEP2/CC_NDEP. Returns an expression of type
1274 Ity_I64, suitable for narrowing. Although the return type is
1275 Ity_I64, the returned value is either 0 or 1. 'cond' must be
1276 :: Ity_I64 and must denote the condition to compute in
1277 bits 7:4, and be zero everywhere else.
1278*/
1279static IRExpr* mk_arm64g_calculate_condition_dyn ( IRExpr* cond )
1280{
1281 vassert(typeOfIRExpr(irsb->tyenv, cond) == Ity_I64);
1282 /* And 'cond' had better produce a value in which only bits 7:4 are
1283 nonzero. However, obviously we can't assert for that. */
1284
1285 /* So what we're constructing for the first argument is
1286 "(cond << 4) | stored-operation".
1287 However, as per comments above, 'cond' must be supplied
1288 pre-shifted to this function.
1289
1290 This pairing scheme requires that the ARM64_CC_OP_ values all fit
1291 in 4 bits. Hence we are passing a (COND, OP) pair in the lowest
1292 8 bits of the first argument. */
1293 IRExpr** args
1294 = mkIRExprVec_4(
1295 binop(Iop_Or64, IRExpr_Get(OFFB_CC_OP, Ity_I64), cond),
1296 IRExpr_Get(OFFB_CC_DEP1, Ity_I64),
1297 IRExpr_Get(OFFB_CC_DEP2, Ity_I64),
1298 IRExpr_Get(OFFB_CC_NDEP, Ity_I64)
1299 );
1300 IRExpr* call
1301 = mkIRExprCCall(
1302 Ity_I64,
1303 0/*regparm*/,
1304 "arm64g_calculate_condition", &arm64g_calculate_condition,
1305 args
1306 );
1307
1308 /* Exclude the requested condition, OP and NDEP from definedness
1309 checking. We're only interested in DEP1 and DEP2. */
1310 call->Iex.CCall.cee->mcx_mask = (1<<0) | (1<<3);
1311 return call;
1312}
1313
1314
1315/* Build IR to calculate some particular condition from stored
1316 CC_OP/CC_DEP1/CC_DEP2/CC_NDEP. Returns an expression of type
1317 Ity_I64, suitable for narrowing. Although the return type is
1318 Ity_I64, the returned value is either 0 or 1.
1319*/
1320static IRExpr* mk_arm64g_calculate_condition ( ARM64Condcode cond )
1321{
1322 /* First arg is "(cond << 4) | condition". This requires that the
1323 ARM64_CC_OP_ values all fit in 4 bits. Hence we are passing a
1324 (COND, OP) pair in the lowest 8 bits of the first argument. */
1325 vassert(cond >= 0 && cond <= 15);
1326 return mk_arm64g_calculate_condition_dyn( mkU64(cond << 4) );
1327}
1328
1329
sewardjdee30502014-06-04 13:09:44 +00001330/* Build IR to calculate just the carry flag from stored
1331 CC_OP/CC_DEP1/CC_DEP2/CC_NDEP. Returns an expression ::
1332 Ity_I64. */
1333static IRExpr* mk_arm64g_calculate_flag_c ( void )
1334{
1335 IRExpr** args
1336 = mkIRExprVec_4( IRExpr_Get(OFFB_CC_OP, Ity_I64),
1337 IRExpr_Get(OFFB_CC_DEP1, Ity_I64),
1338 IRExpr_Get(OFFB_CC_DEP2, Ity_I64),
1339 IRExpr_Get(OFFB_CC_NDEP, Ity_I64) );
1340 IRExpr* call
1341 = mkIRExprCCall(
1342 Ity_I64,
1343 0/*regparm*/,
1344 "arm64g_calculate_flag_c", &arm64g_calculate_flag_c,
1345 args
1346 );
1347 /* Exclude OP and NDEP from definedness checking. We're only
1348 interested in DEP1 and DEP2. */
1349 call->Iex.CCall.cee->mcx_mask = (1<<0) | (1<<3);
1350 return call;
1351}
1352
1353
sewardjbbcf1882014-01-12 12:49:10 +00001354//ZZ /* Build IR to calculate just the overflow flag from stored
1355//ZZ CC_OP/CC_DEP1/CC_DEP2/CC_NDEP. Returns an expression ::
1356//ZZ Ity_I32. */
1357//ZZ static IRExpr* mk_armg_calculate_flag_v ( void )
1358//ZZ {
1359//ZZ IRExpr** args
1360//ZZ = mkIRExprVec_4( IRExpr_Get(OFFB_CC_OP, Ity_I32),
1361//ZZ IRExpr_Get(OFFB_CC_DEP1, Ity_I32),
1362//ZZ IRExpr_Get(OFFB_CC_DEP2, Ity_I32),
1363//ZZ IRExpr_Get(OFFB_CC_NDEP, Ity_I32) );
1364//ZZ IRExpr* call
1365//ZZ = mkIRExprCCall(
1366//ZZ Ity_I32,
1367//ZZ 0/*regparm*/,
1368//ZZ "armg_calculate_flag_v", &armg_calculate_flag_v,
1369//ZZ args
1370//ZZ );
1371//ZZ /* Exclude OP and NDEP from definedness checking. We're only
1372//ZZ interested in DEP1 and DEP2. */
1373//ZZ call->Iex.CCall.cee->mcx_mask = (1<<0) | (1<<3);
1374//ZZ return call;
1375//ZZ }
1376
1377
1378/* Build IR to calculate N Z C V in bits 31:28 of the
1379 returned word. */
1380static IRExpr* mk_arm64g_calculate_flags_nzcv ( void )
1381{
1382 IRExpr** args
1383 = mkIRExprVec_4( IRExpr_Get(OFFB_CC_OP, Ity_I64),
1384 IRExpr_Get(OFFB_CC_DEP1, Ity_I64),
1385 IRExpr_Get(OFFB_CC_DEP2, Ity_I64),
1386 IRExpr_Get(OFFB_CC_NDEP, Ity_I64) );
1387 IRExpr* call
1388 = mkIRExprCCall(
1389 Ity_I64,
1390 0/*regparm*/,
1391 "arm64g_calculate_flags_nzcv", &arm64g_calculate_flags_nzcv,
1392 args
1393 );
1394 /* Exclude OP and NDEP from definedness checking. We're only
1395 interested in DEP1 and DEP2. */
1396 call->Iex.CCall.cee->mcx_mask = (1<<0) | (1<<3);
1397 return call;
1398}
1399
1400
1401/* Build IR to set the flags thunk, in the most general case. */
1402static
1403void setFlags_D1_D2_ND ( UInt cc_op,
1404 IRTemp t_dep1, IRTemp t_dep2, IRTemp t_ndep )
1405{
1406 vassert(typeOfIRTemp(irsb->tyenv, t_dep1 == Ity_I64));
1407 vassert(typeOfIRTemp(irsb->tyenv, t_dep2 == Ity_I64));
1408 vassert(typeOfIRTemp(irsb->tyenv, t_ndep == Ity_I64));
1409 vassert(cc_op >= ARM64G_CC_OP_COPY && cc_op < ARM64G_CC_OP_NUMBER);
1410 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(cc_op) ));
1411 stmt( IRStmt_Put( OFFB_CC_DEP1, mkexpr(t_dep1) ));
1412 stmt( IRStmt_Put( OFFB_CC_DEP2, mkexpr(t_dep2) ));
1413 stmt( IRStmt_Put( OFFB_CC_NDEP, mkexpr(t_ndep) ));
1414}
1415
1416/* Build IR to set the flags thunk after ADD or SUB. */
1417static
1418void setFlags_ADD_SUB ( Bool is64, Bool isSUB, IRTemp argL, IRTemp argR )
1419{
1420 IRTemp argL64 = IRTemp_INVALID;
1421 IRTemp argR64 = IRTemp_INVALID;
1422 IRTemp z64 = newTemp(Ity_I64);
1423 if (is64) {
1424 argL64 = argL;
1425 argR64 = argR;
1426 } else {
1427 argL64 = newTemp(Ity_I64);
1428 argR64 = newTemp(Ity_I64);
1429 assign(argL64, unop(Iop_32Uto64, mkexpr(argL)));
1430 assign(argR64, unop(Iop_32Uto64, mkexpr(argR)));
1431 }
1432 assign(z64, mkU64(0));
1433 UInt cc_op = ARM64G_CC_OP_NUMBER;
1434 /**/ if ( isSUB && is64) { cc_op = ARM64G_CC_OP_SUB64; }
1435 else if ( isSUB && !is64) { cc_op = ARM64G_CC_OP_SUB32; }
1436 else if (!isSUB && is64) { cc_op = ARM64G_CC_OP_ADD64; }
1437 else if (!isSUB && !is64) { cc_op = ARM64G_CC_OP_ADD32; }
1438 else { vassert(0); }
1439 setFlags_D1_D2_ND(cc_op, argL64, argR64, z64);
1440}
1441
sewardjdee30502014-06-04 13:09:44 +00001442/* Build IR to set the flags thunk after ADC or SBC. */
1443static
1444void setFlags_ADC_SBC ( Bool is64, Bool isSBC,
1445 IRTemp argL, IRTemp argR, IRTemp oldC )
1446{
1447 IRTemp argL64 = IRTemp_INVALID;
1448 IRTemp argR64 = IRTemp_INVALID;
1449 IRTemp oldC64 = IRTemp_INVALID;
1450 if (is64) {
1451 argL64 = argL;
1452 argR64 = argR;
1453 oldC64 = oldC;
1454 } else {
1455 argL64 = newTemp(Ity_I64);
1456 argR64 = newTemp(Ity_I64);
1457 oldC64 = newTemp(Ity_I64);
1458 assign(argL64, unop(Iop_32Uto64, mkexpr(argL)));
1459 assign(argR64, unop(Iop_32Uto64, mkexpr(argR)));
1460 assign(oldC64, unop(Iop_32Uto64, mkexpr(oldC)));
1461 }
1462 UInt cc_op = ARM64G_CC_OP_NUMBER;
1463 /**/ if ( isSBC && is64) { cc_op = ARM64G_CC_OP_SBC64; }
1464 else if ( isSBC && !is64) { cc_op = ARM64G_CC_OP_SBC32; }
1465 else if (!isSBC && is64) { cc_op = ARM64G_CC_OP_ADC64; }
1466 else if (!isSBC && !is64) { cc_op = ARM64G_CC_OP_ADC32; }
1467 else { vassert(0); }
1468 setFlags_D1_D2_ND(cc_op, argL64, argR64, oldC64);
1469}
1470
sewardjbbcf1882014-01-12 12:49:10 +00001471/* Build IR to set the flags thunk after ADD or SUB, if the given
1472 condition evaluates to True at run time. If not, the flags are set
1473 to the specified NZCV value. */
1474static
1475void setFlags_ADD_SUB_conditionally (
1476 Bool is64, Bool isSUB,
1477 IRTemp cond, IRTemp argL, IRTemp argR, UInt nzcv
1478 )
1479{
1480 /* Generate IR as follows:
1481 CC_OP = ITE(cond, OP_{ADD,SUB}{32,64}, OP_COPY)
1482 CC_DEP1 = ITE(cond, argL64, nzcv << 28)
1483 CC_DEP2 = ITE(cond, argR64, 0)
1484 CC_NDEP = 0
1485 */
1486
1487 IRTemp z64 = newTemp(Ity_I64);
1488 assign(z64, mkU64(0));
1489
1490 /* Establish the operation and operands for the True case. */
1491 IRTemp t_dep1 = IRTemp_INVALID;
1492 IRTemp t_dep2 = IRTemp_INVALID;
1493 UInt t_op = ARM64G_CC_OP_NUMBER;
1494 /**/ if ( isSUB && is64) { t_op = ARM64G_CC_OP_SUB64; }
1495 else if ( isSUB && !is64) { t_op = ARM64G_CC_OP_SUB32; }
1496 else if (!isSUB && is64) { t_op = ARM64G_CC_OP_ADD64; }
1497 else if (!isSUB && !is64) { t_op = ARM64G_CC_OP_ADD32; }
1498 else { vassert(0); }
1499 /* */
1500 if (is64) {
1501 t_dep1 = argL;
1502 t_dep2 = argR;
1503 } else {
1504 t_dep1 = newTemp(Ity_I64);
1505 t_dep2 = newTemp(Ity_I64);
1506 assign(t_dep1, unop(Iop_32Uto64, mkexpr(argL)));
1507 assign(t_dep2, unop(Iop_32Uto64, mkexpr(argR)));
1508 }
1509
1510 /* Establish the operation and operands for the False case. */
1511 IRTemp f_dep1 = newTemp(Ity_I64);
1512 IRTemp f_dep2 = z64;
1513 UInt f_op = ARM64G_CC_OP_COPY;
1514 assign(f_dep1, mkU64(nzcv << 28));
1515
1516 /* Final thunk values */
1517 IRTemp dep1 = newTemp(Ity_I64);
1518 IRTemp dep2 = newTemp(Ity_I64);
1519 IRTemp op = newTemp(Ity_I64);
1520
1521 assign(op, IRExpr_ITE(mkexpr(cond), mkU64(t_op), mkU64(f_op)));
1522 assign(dep1, IRExpr_ITE(mkexpr(cond), mkexpr(t_dep1), mkexpr(f_dep1)));
1523 assign(dep2, IRExpr_ITE(mkexpr(cond), mkexpr(t_dep2), mkexpr(f_dep2)));
1524
1525 /* finally .. */
1526 stmt( IRStmt_Put( OFFB_CC_OP, mkexpr(op) ));
1527 stmt( IRStmt_Put( OFFB_CC_DEP1, mkexpr(dep1) ));
1528 stmt( IRStmt_Put( OFFB_CC_DEP2, mkexpr(dep2) ));
1529 stmt( IRStmt_Put( OFFB_CC_NDEP, mkexpr(z64) ));
1530}
1531
1532/* Build IR to set the flags thunk after AND/OR/XOR or variants thereof. */
1533static
1534void setFlags_LOGIC ( Bool is64, IRTemp res )
1535{
1536 IRTemp res64 = IRTemp_INVALID;
1537 IRTemp z64 = newTemp(Ity_I64);
1538 UInt cc_op = ARM64G_CC_OP_NUMBER;
1539 if (is64) {
1540 res64 = res;
1541 cc_op = ARM64G_CC_OP_LOGIC64;
1542 } else {
1543 res64 = newTemp(Ity_I64);
1544 assign(res64, unop(Iop_32Uto64, mkexpr(res)));
1545 cc_op = ARM64G_CC_OP_LOGIC32;
1546 }
1547 assign(z64, mkU64(0));
1548 setFlags_D1_D2_ND(cc_op, res64, z64, z64);
1549}
1550
1551/* Build IR to set the flags thunk to a given NZCV value. NZCV is
1552 located in bits 31:28 of the supplied value. */
1553static
1554void setFlags_COPY ( IRTemp nzcv_28x0 )
1555{
1556 IRTemp z64 = newTemp(Ity_I64);
1557 assign(z64, mkU64(0));
1558 setFlags_D1_D2_ND(ARM64G_CC_OP_COPY, nzcv_28x0, z64, z64);
1559}
1560
1561
1562//ZZ /* Minor variant of the above that sets NDEP to zero (if it
1563//ZZ sets it at all) */
1564//ZZ static void setFlags_D1_D2 ( UInt cc_op, IRTemp t_dep1,
1565//ZZ IRTemp t_dep2,
1566//ZZ IRTemp guardT /* :: Ity_I32, 0 or 1 */ )
1567//ZZ {
1568//ZZ IRTemp z32 = newTemp(Ity_I32);
1569//ZZ assign( z32, mkU32(0) );
1570//ZZ setFlags_D1_D2_ND( cc_op, t_dep1, t_dep2, z32, guardT );
1571//ZZ }
1572//ZZ
1573//ZZ
1574//ZZ /* Minor variant of the above that sets DEP2 to zero (if it
1575//ZZ sets it at all) */
1576//ZZ static void setFlags_D1_ND ( UInt cc_op, IRTemp t_dep1,
1577//ZZ IRTemp t_ndep,
1578//ZZ IRTemp guardT /* :: Ity_I32, 0 or 1 */ )
1579//ZZ {
1580//ZZ IRTemp z32 = newTemp(Ity_I32);
1581//ZZ assign( z32, mkU32(0) );
1582//ZZ setFlags_D1_D2_ND( cc_op, t_dep1, z32, t_ndep, guardT );
1583//ZZ }
1584//ZZ
1585//ZZ
1586//ZZ /* Minor variant of the above that sets DEP2 and NDEP to zero (if it
1587//ZZ sets them at all) */
1588//ZZ static void setFlags_D1 ( UInt cc_op, IRTemp t_dep1,
1589//ZZ IRTemp guardT /* :: Ity_I32, 0 or 1 */ )
1590//ZZ {
1591//ZZ IRTemp z32 = newTemp(Ity_I32);
1592//ZZ assign( z32, mkU32(0) );
1593//ZZ setFlags_D1_D2_ND( cc_op, t_dep1, z32, z32, guardT );
1594//ZZ }
1595
1596
1597/*------------------------------------------------------------*/
1598/*--- Misc math helpers ---*/
1599/*------------------------------------------------------------*/
1600
sewardj32d86752014-03-02 12:47:18 +00001601/* Generate IR for ((x & mask) >>u sh) | ((x << sh) & mask) */
1602static IRTemp math_SWAPHELPER ( IRTemp x, ULong mask, Int sh )
sewardjbbcf1882014-01-12 12:49:10 +00001603{
sewardj32d86752014-03-02 12:47:18 +00001604 IRTemp maskT = newTemp(Ity_I64);
1605 IRTemp res = newTemp(Ity_I64);
1606 vassert(sh >= 1 && sh <= 63);
1607 assign(maskT, mkU64(mask));
sewardjdc9259c2014-02-27 11:10:19 +00001608 assign( res,
sewardjbbcf1882014-01-12 12:49:10 +00001609 binop(Iop_Or64,
1610 binop(Iop_Shr64,
sewardj32d86752014-03-02 12:47:18 +00001611 binop(Iop_And64,mkexpr(x),mkexpr(maskT)),
1612 mkU8(sh)),
sewardjbbcf1882014-01-12 12:49:10 +00001613 binop(Iop_And64,
sewardj32d86752014-03-02 12:47:18 +00001614 binop(Iop_Shl64,mkexpr(x),mkU8(sh)),
1615 mkexpr(maskT))
sewardjbbcf1882014-01-12 12:49:10 +00001616 )
1617 );
sewardjdc9259c2014-02-27 11:10:19 +00001618 return res;
1619}
1620
sewardj32d86752014-03-02 12:47:18 +00001621/* Generates byte swaps within 32-bit lanes. */
1622static IRTemp math_UINTSWAP64 ( IRTemp src )
1623{
1624 IRTemp res;
1625 res = math_SWAPHELPER(src, 0xFF00FF00FF00FF00ULL, 8);
1626 res = math_SWAPHELPER(res, 0xFFFF0000FFFF0000ULL, 16);
1627 return res;
1628}
1629
1630/* Generates byte swaps within 16-bit lanes. */
1631static IRTemp math_USHORTSWAP64 ( IRTemp src )
1632{
1633 IRTemp res;
1634 res = math_SWAPHELPER(src, 0xFF00FF00FF00FF00ULL, 8);
1635 return res;
1636}
1637
1638/* Generates a 64-bit byte swap. */
1639static IRTemp math_BYTESWAP64 ( IRTemp src )
1640{
1641 IRTemp res;
1642 res = math_SWAPHELPER(src, 0xFF00FF00FF00FF00ULL, 8);
1643 res = math_SWAPHELPER(res, 0xFFFF0000FFFF0000ULL, 16);
1644 res = math_SWAPHELPER(res, 0xFFFFFFFF00000000ULL, 32);
1645 return res;
1646}
sewardjdc9259c2014-02-27 11:10:19 +00001647
1648/* Generates a 64-bit bit swap. */
1649static IRTemp math_BITSWAP64 ( IRTemp src )
1650{
sewardj32d86752014-03-02 12:47:18 +00001651 IRTemp res;
1652 res = math_SWAPHELPER(src, 0xAAAAAAAAAAAAAAAAULL, 1);
1653 res = math_SWAPHELPER(res, 0xCCCCCCCCCCCCCCCCULL, 2);
1654 res = math_SWAPHELPER(res, 0xF0F0F0F0F0F0F0F0ULL, 4);
1655 return math_BYTESWAP64(res);
sewardjbbcf1882014-01-12 12:49:10 +00001656}
1657
sewardj606c4ba2014-01-26 19:11:14 +00001658/* Duplicates the bits at the bottom of the given word to fill the
1659 whole word. src :: Ity_I64 is assumed to have zeroes everywhere
1660 except for the bottom bits. */
1661static IRTemp math_DUP_TO_64 ( IRTemp src, IRType srcTy )
1662{
1663 if (srcTy == Ity_I8) {
1664 IRTemp t16 = newTemp(Ity_I64);
1665 assign(t16, binop(Iop_Or64, mkexpr(src),
1666 binop(Iop_Shl64, mkexpr(src), mkU8(8))));
1667 IRTemp t32 = newTemp(Ity_I64);
1668 assign(t32, binop(Iop_Or64, mkexpr(t16),
1669 binop(Iop_Shl64, mkexpr(t16), mkU8(16))));
1670 IRTemp t64 = newTemp(Ity_I64);
1671 assign(t64, binop(Iop_Or64, mkexpr(t32),
1672 binop(Iop_Shl64, mkexpr(t32), mkU8(32))));
1673 return t64;
1674 }
1675 if (srcTy == Ity_I16) {
1676 IRTemp t32 = newTemp(Ity_I64);
1677 assign(t32, binop(Iop_Or64, mkexpr(src),
1678 binop(Iop_Shl64, mkexpr(src), mkU8(16))));
1679 IRTemp t64 = newTemp(Ity_I64);
1680 assign(t64, binop(Iop_Or64, mkexpr(t32),
1681 binop(Iop_Shl64, mkexpr(t32), mkU8(32))));
1682 return t64;
1683 }
1684 if (srcTy == Ity_I32) {
1685 IRTemp t64 = newTemp(Ity_I64);
1686 assign(t64, binop(Iop_Or64, mkexpr(src),
1687 binop(Iop_Shl64, mkexpr(src), mkU8(32))));
1688 return t64;
1689 }
1690 if (srcTy == Ity_I64) {
1691 return src;
1692 }
1693 vassert(0);
1694}
1695
1696
sewardj18bf5172014-06-14 18:05:30 +00001697/* Duplicates the src element exactly so as to fill a V128 value. */
sewardj85fbb022014-06-12 13:16:01 +00001698static IRTemp math_DUP_TO_V128 ( IRTemp src, IRType srcTy )
1699{
1700 IRTemp res = newTemp(Ity_V128);
1701 if (srcTy == Ity_F64) {
1702 IRTemp i64 = newTemp(Ity_I64);
1703 assign(i64, unop(Iop_ReinterpF64asI64, mkexpr(src)));
1704 assign(res, binop(Iop_64HLtoV128, mkexpr(i64), mkexpr(i64)));
1705 return res;
1706 }
1707 if (srcTy == Ity_F32) {
1708 IRTemp i64a = newTemp(Ity_I64);
1709 assign(i64a, unop(Iop_32Uto64, unop(Iop_ReinterpF32asI32, mkexpr(src))));
1710 IRTemp i64b = newTemp(Ity_I64);
1711 assign(i64b, binop(Iop_Or64, binop(Iop_Shl64, mkexpr(i64a), mkU8(32)),
1712 mkexpr(i64a)));
1713 assign(res, binop(Iop_64HLtoV128, mkexpr(i64b), mkexpr(i64b)));
1714 return res;
1715 }
sewardj18bf5172014-06-14 18:05:30 +00001716 if (srcTy == Ity_I64) {
1717 assign(res, binop(Iop_64HLtoV128, mkexpr(src), mkexpr(src)));
1718 return res;
1719 }
1720 if (srcTy == Ity_I32 || srcTy == Ity_I16 || srcTy == Ity_I8) {
1721 IRTemp t1 = newTemp(Ity_I64);
1722 assign(t1, widenUto64(srcTy, mkexpr(src)));
1723 IRTemp t2 = math_DUP_TO_64(t1, srcTy);
1724 assign(res, binop(Iop_64HLtoV128, mkexpr(t2), mkexpr(t2)));
1725 return res;
1726 }
sewardj85fbb022014-06-12 13:16:01 +00001727 vassert(0);
1728}
1729
1730
sewardjbbcf1882014-01-12 12:49:10 +00001731/*------------------------------------------------------------*/
1732/*--- FP comparison helpers ---*/
1733/*------------------------------------------------------------*/
1734
1735/* irRes :: Ity_I32 holds a floating point comparison result encoded
1736 as an IRCmpF64Result. Generate code to convert it to an
1737 ARM64-encoded (N,Z,C,V) group in the lowest 4 bits of an I64 value.
1738 Assign a new temp to hold that value, and return the temp. */
1739static
1740IRTemp mk_convert_IRCmpF64Result_to_NZCV ( IRTemp irRes32 )
1741{
1742 IRTemp ix = newTemp(Ity_I64);
1743 IRTemp termL = newTemp(Ity_I64);
1744 IRTemp termR = newTemp(Ity_I64);
1745 IRTemp nzcv = newTemp(Ity_I64);
1746 IRTemp irRes = newTemp(Ity_I64);
1747
1748 /* This is where the fun starts. We have to convert 'irRes' from
1749 an IR-convention return result (IRCmpF64Result) to an
1750 ARM-encoded (N,Z,C,V) group. The final result is in the bottom
1751 4 bits of 'nzcv'. */
1752 /* Map compare result from IR to ARM(nzcv) */
1753 /*
1754 FP cmp result | IR | ARM(nzcv)
1755 --------------------------------
1756 UN 0x45 0011
1757 LT 0x01 1000
1758 GT 0x00 0010
1759 EQ 0x40 0110
1760 */
1761 /* Now since you're probably wondering WTF ..
1762
1763 ix fishes the useful bits out of the IR value, bits 6 and 0, and
1764 places them side by side, giving a number which is 0, 1, 2 or 3.
1765
1766 termL is a sequence cooked up by GNU superopt. It converts ix
1767 into an almost correct value NZCV value (incredibly), except
1768 for the case of UN, where it produces 0100 instead of the
1769 required 0011.
1770
1771 termR is therefore a correction term, also computed from ix. It
1772 is 1 in the UN case and 0 for LT, GT and UN. Hence, to get
1773 the final correct value, we subtract termR from termL.
1774
1775 Don't take my word for it. There's a test program at the bottom
1776 of guest_arm_toIR.c, to try this out with.
1777 */
1778 assign(irRes, unop(Iop_32Uto64, mkexpr(irRes32)));
1779
1780 assign(
1781 ix,
1782 binop(Iop_Or64,
1783 binop(Iop_And64,
1784 binop(Iop_Shr64, mkexpr(irRes), mkU8(5)),
1785 mkU64(3)),
1786 binop(Iop_And64, mkexpr(irRes), mkU64(1))));
1787
1788 assign(
1789 termL,
1790 binop(Iop_Add64,
1791 binop(Iop_Shr64,
1792 binop(Iop_Sub64,
1793 binop(Iop_Shl64,
1794 binop(Iop_Xor64, mkexpr(ix), mkU64(1)),
1795 mkU8(62)),
1796 mkU64(1)),
1797 mkU8(61)),
1798 mkU64(1)));
1799
1800 assign(
1801 termR,
1802 binop(Iop_And64,
1803 binop(Iop_And64,
1804 mkexpr(ix),
1805 binop(Iop_Shr64, mkexpr(ix), mkU8(1))),
1806 mkU64(1)));
1807
1808 assign(nzcv, binop(Iop_Sub64, mkexpr(termL), mkexpr(termR)));
1809 return nzcv;
1810}
1811
1812
1813/*------------------------------------------------------------*/
1814/*--- Data processing (immediate) ---*/
1815/*------------------------------------------------------------*/
1816
1817/* Helper functions for supporting "DecodeBitMasks" */
1818
1819static ULong dbm_ROR ( Int width, ULong x, Int rot )
1820{
1821 vassert(width > 0 && width <= 64);
1822 vassert(rot >= 0 && rot < width);
1823 if (rot == 0) return x;
1824 ULong res = x >> rot;
1825 res |= (x << (width - rot));
1826 if (width < 64)
1827 res &= ((1ULL << width) - 1);
1828 return res;
1829}
1830
1831static ULong dbm_RepTo64( Int esize, ULong x )
1832{
1833 switch (esize) {
1834 case 64:
1835 return x;
1836 case 32:
1837 x &= 0xFFFFFFFF; x |= (x << 32);
1838 return x;
1839 case 16:
1840 x &= 0xFFFF; x |= (x << 16); x |= (x << 32);
1841 return x;
1842 case 8:
1843 x &= 0xFF; x |= (x << 8); x |= (x << 16); x |= (x << 32);
1844 return x;
1845 case 4:
1846 x &= 0xF; x |= (x << 4); x |= (x << 8);
1847 x |= (x << 16); x |= (x << 32);
1848 return x;
1849 case 2:
1850 x &= 0x3; x |= (x << 2); x |= (x << 4); x |= (x << 8);
1851 x |= (x << 16); x |= (x << 32);
1852 return x;
1853 default:
1854 break;
1855 }
1856 vpanic("dbm_RepTo64");
1857 /*NOTREACHED*/
1858 return 0;
1859}
1860
1861static Int dbm_highestSetBit ( ULong x )
1862{
1863 Int i;
1864 for (i = 63; i >= 0; i--) {
1865 if (x & (1ULL << i))
1866 return i;
1867 }
1868 vassert(x == 0);
1869 return -1;
1870}
1871
1872static
1873Bool dbm_DecodeBitMasks ( /*OUT*/ULong* wmask, /*OUT*/ULong* tmask,
1874 ULong immN, ULong imms, ULong immr, Bool immediate,
1875 UInt M /*32 or 64*/)
1876{
1877 vassert(immN < (1ULL << 1));
1878 vassert(imms < (1ULL << 6));
1879 vassert(immr < (1ULL << 6));
1880 vassert(immediate == False || immediate == True);
1881 vassert(M == 32 || M == 64);
1882
1883 Int len = dbm_highestSetBit( ((immN << 6) & 64) | ((~imms) & 63) );
1884 if (len < 1) { /* printf("fail1\n"); */ return False; }
1885 vassert(len <= 6);
1886 vassert(M >= (1 << len));
1887
1888 vassert(len >= 1 && len <= 6);
1889 ULong levels = // (zeroes(6 - len) << (6-len)) | ones(len);
1890 (1 << len) - 1;
1891 vassert(levels >= 1 && levels <= 63);
1892
1893 if (immediate && ((imms & levels) == levels)) {
1894 /* printf("fail2 imms %llu levels %llu len %d\n", imms, levels, len); */
1895 return False;
1896 }
1897
1898 ULong S = imms & levels;
1899 ULong R = immr & levels;
1900 Int diff = S - R;
1901 diff &= 63;
1902 Int esize = 1 << len;
1903 vassert(2 <= esize && esize <= 64);
1904
1905 /* Be careful of these (1ULL << (S+1)) - 1 expressions, and the
1906 same below with d. S can be 63 in which case we have an out of
1907 range and hence undefined shift. */
1908 vassert(S >= 0 && S <= 63);
1909 vassert(esize >= (S+1));
1910 ULong elem_s = // Zeroes(esize-(S+1)):Ones(S+1)
1911 //(1ULL << (S+1)) - 1;
1912 ((1ULL << S) - 1) + (1ULL << S);
1913
1914 Int d = // diff<len-1:0>
1915 diff & ((1 << len)-1);
1916 vassert(esize >= (d+1));
1917 vassert(d >= 0 && d <= 63);
1918
1919 ULong elem_d = // Zeroes(esize-(d+1)):Ones(d+1)
1920 //(1ULL << (d+1)) - 1;
1921 ((1ULL << d) - 1) + (1ULL << d);
1922
1923 if (esize != 64) vassert(elem_s < (1ULL << esize));
1924 if (esize != 64) vassert(elem_d < (1ULL << esize));
1925
1926 if (wmask) *wmask = dbm_RepTo64(esize, dbm_ROR(esize, elem_s, R));
1927 if (tmask) *tmask = dbm_RepTo64(esize, elem_d);
1928
1929 return True;
1930}
1931
1932
1933static
1934Bool dis_ARM64_data_processing_immediate(/*MB_OUT*/DisResult* dres,
1935 UInt insn)
1936{
1937# define INSN(_bMax,_bMin) SLICE_UInt(insn, (_bMax), (_bMin))
1938
1939 /* insn[28:23]
1940 10000x PC-rel addressing
1941 10001x Add/subtract (immediate)
1942 100100 Logical (immediate)
1943 100101 Move Wide (immediate)
1944 100110 Bitfield
1945 100111 Extract
1946 */
1947
1948 /* ------------------ ADD/SUB{,S} imm12 ------------------ */
1949 if (INSN(28,24) == BITS5(1,0,0,0,1)) {
1950 Bool is64 = INSN(31,31) == 1;
1951 Bool isSub = INSN(30,30) == 1;
1952 Bool setCC = INSN(29,29) == 1;
1953 UInt sh = INSN(23,22);
1954 UInt uimm12 = INSN(21,10);
1955 UInt nn = INSN(9,5);
1956 UInt dd = INSN(4,0);
1957 const HChar* nm = isSub ? "sub" : "add";
1958 if (sh >= 2) {
1959 /* Invalid; fall through */
1960 } else {
1961 vassert(sh <= 1);
1962 uimm12 <<= (12 * sh);
1963 if (is64) {
1964 IRTemp argL = newTemp(Ity_I64);
1965 IRTemp argR = newTemp(Ity_I64);
1966 IRTemp res = newTemp(Ity_I64);
1967 assign(argL, getIReg64orSP(nn));
1968 assign(argR, mkU64(uimm12));
1969 assign(res, binop(isSub ? Iop_Sub64 : Iop_Add64,
1970 mkexpr(argL), mkexpr(argR)));
1971 if (setCC) {
1972 putIReg64orZR(dd, mkexpr(res));
1973 setFlags_ADD_SUB(True/*is64*/, isSub, argL, argR);
1974 DIP("%ss %s, %s, 0x%x\n",
1975 nm, nameIReg64orZR(dd), nameIReg64orSP(nn), uimm12);
1976 } else {
1977 putIReg64orSP(dd, mkexpr(res));
1978 DIP("%s %s, %s, 0x%x\n",
1979 nm, nameIReg64orSP(dd), nameIReg64orSP(nn), uimm12);
1980 }
1981 } else {
1982 IRTemp argL = newTemp(Ity_I32);
1983 IRTemp argR = newTemp(Ity_I32);
1984 IRTemp res = newTemp(Ity_I32);
1985 assign(argL, getIReg32orSP(nn));
1986 assign(argR, mkU32(uimm12));
1987 assign(res, binop(isSub ? Iop_Sub32 : Iop_Add32,
1988 mkexpr(argL), mkexpr(argR)));
1989 if (setCC) {
1990 putIReg32orZR(dd, mkexpr(res));
1991 setFlags_ADD_SUB(False/*!is64*/, isSub, argL, argR);
1992 DIP("%ss %s, %s, 0x%x\n",
1993 nm, nameIReg32orZR(dd), nameIReg32orSP(nn), uimm12);
1994 } else {
1995 putIReg32orSP(dd, mkexpr(res));
1996 DIP("%s %s, %s, 0x%x\n",
1997 nm, nameIReg32orSP(dd), nameIReg32orSP(nn), uimm12);
1998 }
1999 }
2000 return True;
2001 }
2002 }
2003
2004 /* -------------------- ADR/ADRP -------------------- */
2005 if (INSN(28,24) == BITS5(1,0,0,0,0)) {
2006 UInt bP = INSN(31,31);
2007 UInt immLo = INSN(30,29);
2008 UInt immHi = INSN(23,5);
2009 UInt rD = INSN(4,0);
2010 ULong uimm = (immHi << 2) | immLo;
2011 ULong simm = sx_to_64(uimm, 21);
2012 ULong val;
2013 if (bP) {
2014 val = (guest_PC_curr_instr & 0xFFFFFFFFFFFFF000ULL) + (simm << 12);
2015 } else {
2016 val = guest_PC_curr_instr + simm;
2017 }
2018 putIReg64orZR(rD, mkU64(val));
2019 DIP("adr%s %s, 0x%llx\n", bP ? "p" : "", nameIReg64orZR(rD), val);
2020 return True;
2021 }
2022
2023 /* -------------------- LOGIC(imm) -------------------- */
2024 if (INSN(28,23) == BITS6(1,0,0,1,0,0)) {
2025 /* 31 30 28 22 21 15 9 4
2026 sf op 100100 N immr imms Rn Rd
2027 op=00: AND Rd|SP, Rn, #imm
2028 op=01: ORR Rd|SP, Rn, #imm
2029 op=10: EOR Rd|SP, Rn, #imm
2030 op=11: ANDS Rd|ZR, Rn, #imm
2031 */
2032 Bool is64 = INSN(31,31) == 1;
2033 UInt op = INSN(30,29);
2034 UInt N = INSN(22,22);
2035 UInt immR = INSN(21,16);
2036 UInt immS = INSN(15,10);
2037 UInt nn = INSN(9,5);
2038 UInt dd = INSN(4,0);
2039 ULong imm = 0;
2040 Bool ok;
2041 if (N == 1 && !is64)
2042 goto after_logic_imm; /* not allowed; fall through */
2043 ok = dbm_DecodeBitMasks(&imm, NULL,
2044 N, immS, immR, True, is64 ? 64 : 32);
2045 if (!ok)
2046 goto after_logic_imm;
2047
2048 const HChar* names[4] = { "and", "orr", "eor", "ands" };
2049 const IROp ops64[4] = { Iop_And64, Iop_Or64, Iop_Xor64, Iop_And64 };
2050 const IROp ops32[4] = { Iop_And32, Iop_Or32, Iop_Xor32, Iop_And32 };
2051
2052 vassert(op < 4);
2053 if (is64) {
2054 IRExpr* argL = getIReg64orZR(nn);
2055 IRExpr* argR = mkU64(imm);
2056 IRTemp res = newTemp(Ity_I64);
2057 assign(res, binop(ops64[op], argL, argR));
2058 if (op < 3) {
2059 putIReg64orSP(dd, mkexpr(res));
2060 DIP("%s %s, %s, 0x%llx\n", names[op],
2061 nameIReg64orSP(dd), nameIReg64orZR(nn), imm);
2062 } else {
2063 putIReg64orZR(dd, mkexpr(res));
2064 setFlags_LOGIC(True/*is64*/, res);
2065 DIP("%s %s, %s, 0x%llx\n", names[op],
2066 nameIReg64orZR(dd), nameIReg64orZR(nn), imm);
2067 }
2068 } else {
2069 IRExpr* argL = getIReg32orZR(nn);
2070 IRExpr* argR = mkU32((UInt)imm);
2071 IRTemp res = newTemp(Ity_I32);
2072 assign(res, binop(ops32[op], argL, argR));
2073 if (op < 3) {
2074 putIReg32orSP(dd, mkexpr(res));
2075 DIP("%s %s, %s, 0x%x\n", names[op],
2076 nameIReg32orSP(dd), nameIReg32orZR(nn), (UInt)imm);
2077 } else {
2078 putIReg32orZR(dd, mkexpr(res));
2079 setFlags_LOGIC(False/*!is64*/, res);
2080 DIP("%s %s, %s, 0x%x\n", names[op],
2081 nameIReg32orZR(dd), nameIReg32orZR(nn), (UInt)imm);
2082 }
2083 }
2084 return True;
2085 }
2086 after_logic_imm:
2087
2088 /* -------------------- MOV{Z,N,K} -------------------- */
2089 if (INSN(28,23) == BITS6(1,0,0,1,0,1)) {
2090 /* 31 30 28 22 20 4
2091 | | | | | |
2092 sf 10 100 101 hw imm16 Rd MOV(Z) Rd, (imm16 << (16*hw))
2093 sf 00 100 101 hw imm16 Rd MOV(N) Rd, ~(imm16 << (16*hw))
2094 sf 11 100 101 hw imm16 Rd MOV(K) Rd, (imm16 << (16*hw))
2095 */
2096 Bool is64 = INSN(31,31) == 1;
2097 UInt subopc = INSN(30,29);
2098 UInt hw = INSN(22,21);
2099 UInt imm16 = INSN(20,5);
2100 UInt dd = INSN(4,0);
2101 if (subopc == BITS2(0,1) || (!is64 && hw >= 2)) {
2102 /* invalid; fall through */
2103 } else {
2104 ULong imm64 = ((ULong)imm16) << (16 * hw);
2105 if (!is64)
2106 vassert(imm64 < 0x100000000ULL);
2107 switch (subopc) {
2108 case BITS2(1,0): // MOVZ
2109 putIRegOrZR(is64, dd, is64 ? mkU64(imm64) : mkU32((UInt)imm64));
2110 DIP("movz %s, 0x%llx\n", nameIRegOrZR(is64, dd), imm64);
2111 break;
2112 case BITS2(0,0): // MOVN
2113 imm64 = ~imm64;
2114 if (!is64)
2115 imm64 &= 0xFFFFFFFFULL;
2116 putIRegOrZR(is64, dd, is64 ? mkU64(imm64) : mkU32((UInt)imm64));
2117 DIP("movn %s, 0x%llx\n", nameIRegOrZR(is64, dd), imm64);
2118 break;
2119 case BITS2(1,1): // MOVK
2120 /* This is more complex. We are inserting a slice into
2121 the destination register, so we need to have the old
2122 value of it. */
2123 if (is64) {
2124 IRTemp old = newTemp(Ity_I64);
2125 assign(old, getIReg64orZR(dd));
2126 ULong mask = 0xFFFFULL << (16 * hw);
2127 IRExpr* res
2128 = binop(Iop_Or64,
2129 binop(Iop_And64, mkexpr(old), mkU64(~mask)),
2130 mkU64(imm64));
2131 putIReg64orZR(dd, res);
2132 DIP("movk %s, 0x%x, lsl %u\n",
2133 nameIReg64orZR(dd), imm16, 16*hw);
2134 } else {
2135 IRTemp old = newTemp(Ity_I32);
2136 assign(old, getIReg32orZR(dd));
2137 vassert(hw <= 1);
2138 UInt mask = 0xFFFF << (16 * hw);
2139 IRExpr* res
2140 = binop(Iop_Or32,
2141 binop(Iop_And32, mkexpr(old), mkU32(~mask)),
2142 mkU32((UInt)imm64));
2143 putIReg32orZR(dd, res);
2144 DIP("movk %s, 0x%x, lsl %u\n",
2145 nameIReg32orZR(dd), imm16, 16*hw);
2146 }
2147 break;
2148 default:
2149 vassert(0);
2150 }
2151 return True;
2152 }
2153 }
2154
2155 /* -------------------- {U,S,}BFM -------------------- */
2156 /* 30 28 22 21 15 9 4
2157
2158 sf 10 100110 N immr imms nn dd
2159 UBFM Wd, Wn, #immr, #imms when sf=0, N=0, immr[5]=0, imms[5]=0
2160 UBFM Xd, Xn, #immr, #imms when sf=1, N=1
2161
2162 sf 00 100110 N immr imms nn dd
2163 SBFM Wd, Wn, #immr, #imms when sf=0, N=0, immr[5]=0, imms[5]=0
2164 SBFM Xd, Xn, #immr, #imms when sf=1, N=1
2165
2166 sf 01 100110 N immr imms nn dd
2167 BFM Wd, Wn, #immr, #imms when sf=0, N=0, immr[5]=0, imms[5]=0
2168 BFM Xd, Xn, #immr, #imms when sf=1, N=1
2169 */
2170 if (INSN(28,23) == BITS6(1,0,0,1,1,0)) {
2171 UInt sf = INSN(31,31);
2172 UInt opc = INSN(30,29);
2173 UInt N = INSN(22,22);
2174 UInt immR = INSN(21,16);
2175 UInt immS = INSN(15,10);
2176 UInt nn = INSN(9,5);
2177 UInt dd = INSN(4,0);
2178 Bool inZero = False;
2179 Bool extend = False;
2180 const HChar* nm = "???";
2181 /* skip invalid combinations */
2182 switch (opc) {
2183 case BITS2(0,0):
2184 inZero = True; extend = True; nm = "sbfm"; break;
2185 case BITS2(0,1):
2186 inZero = False; extend = False; nm = "bfm"; break;
2187 case BITS2(1,0):
2188 inZero = True; extend = False; nm = "ubfm"; break;
2189 case BITS2(1,1):
2190 goto after_bfm; /* invalid */
2191 default:
2192 vassert(0);
2193 }
2194 if (sf == 1 && N != 1) goto after_bfm;
2195 if (sf == 0 && (N != 0 || ((immR >> 5) & 1) != 0
2196 || ((immS >> 5) & 1) != 0)) goto after_bfm;
2197 ULong wmask = 0, tmask = 0;
2198 Bool ok = dbm_DecodeBitMasks(&wmask, &tmask,
2199 N, immS, immR, False, sf == 1 ? 64 : 32);
2200 if (!ok) goto after_bfm; /* hmmm */
2201
2202 Bool is64 = sf == 1;
2203 IRType ty = is64 ? Ity_I64 : Ity_I32;
2204
2205 IRTemp dst = newTemp(ty);
2206 IRTemp src = newTemp(ty);
2207 IRTemp bot = newTemp(ty);
2208 IRTemp top = newTemp(ty);
2209 IRTemp res = newTemp(ty);
2210 assign(dst, inZero ? mkU(ty,0) : getIRegOrZR(is64, dd));
2211 assign(src, getIRegOrZR(is64, nn));
2212 /* perform bitfield move on low bits */
2213 assign(bot, binop(mkOR(ty),
2214 binop(mkAND(ty), mkexpr(dst), mkU(ty, ~wmask)),
2215 binop(mkAND(ty), mkexpr(mathROR(ty, src, immR)),
2216 mkU(ty, wmask))));
2217 /* determine extension bits (sign, zero or dest register) */
2218 assign(top, mkexpr(extend ? mathREPLICATE(ty, src, immS) : dst));
2219 /* combine extension bits and result bits */
2220 assign(res, binop(mkOR(ty),
2221 binop(mkAND(ty), mkexpr(top), mkU(ty, ~tmask)),
2222 binop(mkAND(ty), mkexpr(bot), mkU(ty, tmask))));
2223 putIRegOrZR(is64, dd, mkexpr(res));
2224 DIP("%s %s, %s, immR=%u, immS=%u\n",
2225 nm, nameIRegOrZR(is64, dd), nameIRegOrZR(is64, nn), immR, immS);
2226 return True;
2227 }
2228 after_bfm:
2229
2230 /* ---------------------- EXTR ---------------------- */
2231 /* 30 28 22 20 15 9 4
2232 1 00 100111 10 m imm6 n d EXTR Xd, Xn, Xm, #imm6
2233 0 00 100111 00 m imm6 n d EXTR Wd, Wn, Wm, #imm6 when #imm6 < 32
2234 */
2235 if (INSN(30,23) == BITS8(0,0,1,0,0,1,1,1) && INSN(21,21) == 0) {
2236 Bool is64 = INSN(31,31) == 1;
2237 UInt mm = INSN(20,16);
2238 UInt imm6 = INSN(15,10);
2239 UInt nn = INSN(9,5);
2240 UInt dd = INSN(4,0);
2241 Bool valid = True;
2242 if (INSN(31,31) != INSN(22,22))
2243 valid = False;
2244 if (!is64 && imm6 >= 32)
2245 valid = False;
2246 if (!valid) goto after_extr;
2247 IRType ty = is64 ? Ity_I64 : Ity_I32;
2248 IRTemp srcHi = newTemp(ty);
2249 IRTemp srcLo = newTemp(ty);
2250 IRTemp res = newTemp(ty);
2251 assign(srcHi, getIRegOrZR(is64, nn));
2252 assign(srcLo, getIRegOrZR(is64, mm));
2253 if (imm6 == 0) {
2254 assign(res, mkexpr(srcLo));
2255 } else {
2256 UInt szBits = 8 * sizeofIRType(ty);
2257 vassert(imm6 > 0 && imm6 < szBits);
2258 assign(res, binop(mkOR(ty),
2259 binop(mkSHL(ty), mkexpr(srcHi), mkU8(szBits-imm6)),
2260 binop(mkSHR(ty), mkexpr(srcLo), mkU8(imm6))));
2261 }
2262 putIRegOrZR(is64, dd, mkexpr(res));
2263 DIP("extr %s, %s, %s, #%u\n",
2264 nameIRegOrZR(is64,dd),
2265 nameIRegOrZR(is64,nn), nameIRegOrZR(is64,mm), imm6);
2266 return True;
2267 }
2268 after_extr:
2269
2270 vex_printf("ARM64 front end: data_processing_immediate\n");
2271 return False;
2272# undef INSN
2273}
2274
2275
2276/*------------------------------------------------------------*/
2277/*--- Data processing (register) instructions ---*/
2278/*------------------------------------------------------------*/
2279
2280static const HChar* nameSH ( UInt sh ) {
2281 switch (sh) {
2282 case 0: return "lsl";
2283 case 1: return "lsr";
2284 case 2: return "asr";
2285 case 3: return "ror";
2286 default: vassert(0);
2287 }
2288}
2289
2290/* Generate IR to get a register value, possibly shifted by an
2291 immediate. Returns either a 32- or 64-bit temporary holding the
2292 result. After the shift, the value can optionally be NOT-ed
2293 too.
2294
2295 sh_how coding: 00=SHL, 01=SHR, 10=SAR, 11=ROR. sh_amt may only be
2296 in the range 0 to (is64 ? 64 : 32)-1. For some instructions, ROR
2297 isn't allowed, but it's the job of the caller to check that.
2298*/
2299static IRTemp getShiftedIRegOrZR ( Bool is64,
2300 UInt sh_how, UInt sh_amt, UInt regNo,
2301 Bool invert )
2302{
2303 vassert(sh_how < 4);
2304 vassert(sh_amt < (is64 ? 64 : 32));
2305 IRType ty = is64 ? Ity_I64 : Ity_I32;
2306 IRTemp t0 = newTemp(ty);
2307 assign(t0, getIRegOrZR(is64, regNo));
2308 IRTemp t1 = newTemp(ty);
2309 switch (sh_how) {
2310 case BITS2(0,0):
2311 assign(t1, binop(mkSHL(ty), mkexpr(t0), mkU8(sh_amt)));
2312 break;
2313 case BITS2(0,1):
2314 assign(t1, binop(mkSHR(ty), mkexpr(t0), mkU8(sh_amt)));
2315 break;
2316 case BITS2(1,0):
2317 assign(t1, binop(mkSAR(ty), mkexpr(t0), mkU8(sh_amt)));
2318 break;
2319 case BITS2(1,1):
2320 assign(t1, mkexpr(mathROR(ty, t0, sh_amt)));
2321 break;
2322 default:
2323 vassert(0);
2324 }
2325 if (invert) {
2326 IRTemp t2 = newTemp(ty);
2327 assign(t2, unop(mkNOT(ty), mkexpr(t1)));
2328 return t2;
2329 } else {
2330 return t1;
2331 }
2332}
2333
2334
2335static
2336Bool dis_ARM64_data_processing_register(/*MB_OUT*/DisResult* dres,
2337 UInt insn)
2338{
2339# define INSN(_bMax,_bMin) SLICE_UInt(insn, (_bMax), (_bMin))
2340
2341 /* ------------------- ADD/SUB(reg) ------------------- */
2342 /* x==0 => 32 bit op x==1 => 64 bit op
2343 sh: 00=LSL, 01=LSR, 10=ASR, 11=ROR(NOT ALLOWED)
2344
2345 31 30 29 28 23 21 20 15 9 4
2346 | | | | | | | | | |
2347 x 0 0 01011 sh 0 Rm imm6 Rn Rd ADD Rd,Rn, sh(Rm,imm6)
2348 x 0 1 01011 sh 0 Rm imm6 Rn Rd ADDS Rd,Rn, sh(Rm,imm6)
2349 x 1 0 01011 sh 0 Rm imm6 Rn Rd SUB Rd,Rn, sh(Rm,imm6)
2350 x 1 1 01011 sh 0 Rm imm6 Rn Rd SUBS Rd,Rn, sh(Rm,imm6)
2351 */
2352 if (INSN(28,24) == BITS5(0,1,0,1,1) && INSN(21,21) == 0) {
2353 UInt bX = INSN(31,31);
2354 UInt bOP = INSN(30,30); /* 0: ADD, 1: SUB */
2355 UInt bS = INSN(29, 29); /* set flags? */
2356 UInt sh = INSN(23,22);
2357 UInt rM = INSN(20,16);
2358 UInt imm6 = INSN(15,10);
2359 UInt rN = INSN(9,5);
2360 UInt rD = INSN(4,0);
2361 Bool isSUB = bOP == 1;
2362 Bool is64 = bX == 1;
2363 IRType ty = is64 ? Ity_I64 : Ity_I32;
2364 if ((!is64 && imm6 > 31) || sh == BITS2(1,1)) {
2365 /* invalid; fall through */
2366 } else {
2367 IRTemp argL = newTemp(ty);
2368 assign(argL, getIRegOrZR(is64, rN));
2369 IRTemp argR = getShiftedIRegOrZR(is64, sh, imm6, rM, False);
2370 IROp op = isSUB ? mkSUB(ty) : mkADD(ty);
2371 IRTemp res = newTemp(ty);
2372 assign(res, binop(op, mkexpr(argL), mkexpr(argR)));
2373 if (rD != 31) putIRegOrZR(is64, rD, mkexpr(res));
2374 if (bS) {
2375 setFlags_ADD_SUB(is64, isSUB, argL, argR);
2376 }
2377 DIP("%s%s %s, %s, %s, %s #%u\n",
2378 bOP ? "sub" : "add", bS ? "s" : "",
2379 nameIRegOrZR(is64, rD), nameIRegOrZR(is64, rN),
2380 nameIRegOrZR(is64, rM), nameSH(sh), imm6);
2381 return True;
2382 }
2383 }
2384
sewardjdee30502014-06-04 13:09:44 +00002385 /* ------------------- ADC/SBC(reg) ------------------- */
2386 /* x==0 => 32 bit op x==1 => 64 bit op
2387
2388 31 30 29 28 23 21 20 15 9 4
2389 | | | | | | | | | |
2390 x 0 0 11010 00 0 Rm 000000 Rn Rd ADC Rd,Rn,Rm
2391 x 0 1 11010 00 0 Rm 000000 Rn Rd ADCS Rd,Rn,Rm
2392 x 1 0 11010 00 0 Rm 000000 Rn Rd SBC Rd,Rn,Rm
2393 x 1 1 11010 00 0 Rm 000000 Rn Rd SBCS Rd,Rn,Rm
2394 */
2395
2396 if (INSN(28,21) == BITS8(1,1,0,1,0,0,0,0) && INSN(15,10) == 0 ) {
2397 UInt bX = INSN(31,31);
2398 UInt bOP = INSN(30,30); /* 0: ADC, 1: SBC */
2399 UInt bS = INSN(29,29); /* set flags */
2400 UInt rM = INSN(20,16);
2401 UInt rN = INSN(9,5);
2402 UInt rD = INSN(4,0);
2403
2404 Bool isSUB = bOP == 1;
2405 Bool is64 = bX == 1;
2406 IRType ty = is64 ? Ity_I64 : Ity_I32;
2407
2408 IRTemp oldC = newTemp(ty);
2409 assign(oldC,
2410 is64 ? mk_arm64g_calculate_flag_c()
2411 : unop(Iop_64to32, mk_arm64g_calculate_flag_c()) );
2412
2413 IRTemp argL = newTemp(ty);
2414 assign(argL, getIRegOrZR(is64, rN));
2415 IRTemp argR = newTemp(ty);
2416 assign(argR, getIRegOrZR(is64, rM));
2417
2418 IROp op = isSUB ? mkSUB(ty) : mkADD(ty);
2419 IRTemp res = newTemp(ty);
2420 if (isSUB) {
2421 IRExpr* one = is64 ? mkU64(1) : mkU32(1);
2422 IROp xorOp = is64 ? Iop_Xor64 : Iop_Xor32;
2423 assign(res,
2424 binop(op,
2425 binop(op, mkexpr(argL), mkexpr(argR)),
2426 binop(xorOp, mkexpr(oldC), one)));
2427 } else {
2428 assign(res,
2429 binop(op,
2430 binop(op, mkexpr(argL), mkexpr(argR)),
2431 mkexpr(oldC)));
2432 }
2433
2434 if (rD != 31) putIRegOrZR(is64, rD, mkexpr(res));
2435
2436 if (bS) {
2437 setFlags_ADC_SBC(is64, isSUB, argL, argR, oldC);
2438 }
2439
2440 DIP("%s%s %s, %s, %s\n",
2441 bOP ? "sbc" : "adc", bS ? "s" : "",
2442 nameIRegOrZR(is64, rD), nameIRegOrZR(is64, rN),
2443 nameIRegOrZR(is64, rM));
2444 return True;
2445 }
2446
sewardjbbcf1882014-01-12 12:49:10 +00002447 /* -------------------- LOGIC(reg) -------------------- */
2448 /* x==0 => 32 bit op x==1 => 64 bit op
2449 N==0 => inv? is no-op (no inversion)
2450 N==1 => inv? is NOT
2451 sh: 00=LSL, 01=LSR, 10=ASR, 11=ROR
2452
2453 31 30 28 23 21 20 15 9 4
2454 | | | | | | | | |
2455 x 00 01010 sh N Rm imm6 Rn Rd AND Rd,Rn, inv?(sh(Rm,imm6))
2456 x 01 01010 sh N Rm imm6 Rn Rd ORR Rd,Rn, inv?(sh(Rm,imm6))
2457 x 10 01010 sh N Rm imm6 Rn Rd EOR Rd,Rn, inv?(sh(Rm,imm6))
2458 x 11 01010 sh N Rm imm6 Rn Rd ANDS Rd,Rn, inv?(sh(Rm,imm6))
2459 With N=1, the names are: BIC ORN EON BICS
2460 */
2461 if (INSN(28,24) == BITS5(0,1,0,1,0)) {
2462 UInt bX = INSN(31,31);
2463 UInt sh = INSN(23,22);
2464 UInt bN = INSN(21,21);
2465 UInt rM = INSN(20,16);
2466 UInt imm6 = INSN(15,10);
2467 UInt rN = INSN(9,5);
2468 UInt rD = INSN(4,0);
2469 Bool is64 = bX == 1;
2470 IRType ty = is64 ? Ity_I64 : Ity_I32;
2471 if (!is64 && imm6 > 31) {
2472 /* invalid; fall though */
2473 } else {
2474 IRTemp argL = newTemp(ty);
2475 assign(argL, getIRegOrZR(is64, rN));
2476 IRTemp argR = getShiftedIRegOrZR(is64, sh, imm6, rM, bN == 1);
2477 IROp op = Iop_INVALID;
2478 switch (INSN(30,29)) {
2479 case BITS2(0,0): case BITS2(1,1): op = mkAND(ty); break;
2480 case BITS2(0,1): op = mkOR(ty); break;
2481 case BITS2(1,0): op = mkXOR(ty); break;
2482 default: vassert(0);
2483 }
2484 IRTemp res = newTemp(ty);
2485 assign(res, binop(op, mkexpr(argL), mkexpr(argR)));
2486 if (INSN(30,29) == BITS2(1,1)) {
2487 setFlags_LOGIC(is64, res);
2488 }
2489 putIRegOrZR(is64, rD, mkexpr(res));
2490
2491 static const HChar* names_op[8]
2492 = { "and", "orr", "eor", "ands", "bic", "orn", "eon", "bics" };
2493 vassert(((bN << 2) | INSN(30,29)) < 8);
2494 const HChar* nm_op = names_op[(bN << 2) | INSN(30,29)];
2495 /* Special-case the printing of "MOV" */
2496 if (rN == 31/*zr*/ && sh == 0/*LSL*/ && imm6 == 0 && bN == 0) {
2497 DIP("mov %s, %s\n", nameIRegOrZR(is64, rD),
2498 nameIRegOrZR(is64, rM));
2499 } else {
2500 DIP("%s %s, %s, %s, %s #%u\n", nm_op,
2501 nameIRegOrZR(is64, rD), nameIRegOrZR(is64, rN),
2502 nameIRegOrZR(is64, rM), nameSH(sh), imm6);
2503 }
2504 return True;
2505 }
2506 }
2507
2508 /* -------------------- {U,S}MULH -------------------- */
2509 /* 31 23 22 20 15 9 4
2510 10011011 1 10 Rm 011111 Rn Rd UMULH Xd,Xn,Xm
2511 10011011 0 10 Rm 011111 Rn Rd SMULH Xd,Xn,Xm
2512 */
2513 if (INSN(31,24) == BITS8(1,0,0,1,1,0,1,1)
sewardj7fce7cc2014-05-07 09:41:40 +00002514 && INSN(22,21) == BITS2(1,0) && INSN(15,10) == BITS6(0,1,1,1,1,1)) {
sewardjbbcf1882014-01-12 12:49:10 +00002515 Bool isU = INSN(23,23) == 1;
2516 UInt mm = INSN(20,16);
2517 UInt nn = INSN(9,5);
2518 UInt dd = INSN(4,0);
2519 putIReg64orZR(dd, unop(Iop_128HIto64,
2520 binop(isU ? Iop_MullU64 : Iop_MullS64,
2521 getIReg64orZR(nn), getIReg64orZR(mm))));
2522 DIP("%cmulh %s, %s, %s\n",
2523 isU ? 'u' : 's',
2524 nameIReg64orZR(dd), nameIReg64orZR(nn), nameIReg64orZR(mm));
2525 return True;
2526 }
2527
2528 /* -------------------- M{ADD,SUB} -------------------- */
2529 /* 31 30 20 15 14 9 4
2530 sf 00 11011 000 m 0 a n r MADD Rd,Rn,Rm,Ra d = a+m*n
2531 sf 00 11011 000 m 1 a n r MADD Rd,Rn,Rm,Ra d = a-m*n
2532 */
2533 if (INSN(30,21) == BITS10(0,0,1,1,0,1,1,0,0,0)) {
2534 Bool is64 = INSN(31,31) == 1;
2535 UInt mm = INSN(20,16);
2536 Bool isAdd = INSN(15,15) == 0;
2537 UInt aa = INSN(14,10);
2538 UInt nn = INSN(9,5);
2539 UInt dd = INSN(4,0);
2540 if (is64) {
2541 putIReg64orZR(
2542 dd,
2543 binop(isAdd ? Iop_Add64 : Iop_Sub64,
2544 getIReg64orZR(aa),
2545 binop(Iop_Mul64, getIReg64orZR(mm), getIReg64orZR(nn))));
2546 } else {
2547 putIReg32orZR(
2548 dd,
2549 binop(isAdd ? Iop_Add32 : Iop_Sub32,
2550 getIReg32orZR(aa),
2551 binop(Iop_Mul32, getIReg32orZR(mm), getIReg32orZR(nn))));
2552 }
2553 DIP("%s %s, %s, %s, %s\n",
2554 isAdd ? "madd" : "msub",
2555 nameIRegOrZR(is64, dd), nameIRegOrZR(is64, nn),
2556 nameIRegOrZR(is64, mm), nameIRegOrZR(is64, aa));
2557 return True;
2558 }
2559
2560 /* ---------------- CS{EL,INC,INV,NEG} ---------------- */
2561 /* 31 30 28 20 15 11 9 4
2562 sf 00 1101 0100 mm cond 00 nn dd CSEL Rd,Rn,Rm
2563 sf 00 1101 0100 mm cond 01 nn dd CSINC Rd,Rn,Rm
2564 sf 10 1101 0100 mm cond 00 nn dd CSINV Rd,Rn,Rm
2565 sf 10 1101 0100 mm cond 01 nn dd CSNEG Rd,Rn,Rm
2566 In all cases, the operation is: Rd = if cond then Rn else OP(Rm)
2567 */
2568 if (INSN(29,21) == BITS9(0, 1,1,0,1, 0,1,0,0) && INSN(11,11) == 0) {
2569 Bool is64 = INSN(31,31) == 1;
2570 UInt b30 = INSN(30,30);
2571 UInt mm = INSN(20,16);
2572 UInt cond = INSN(15,12);
2573 UInt b10 = INSN(10,10);
2574 UInt nn = INSN(9,5);
2575 UInt dd = INSN(4,0);
2576 UInt op = (b30 << 1) | b10; /* 00=id 01=inc 10=inv 11=neg */
2577 IRType ty = is64 ? Ity_I64 : Ity_I32;
2578 IRExpr* argL = getIRegOrZR(is64, nn);
2579 IRExpr* argR = getIRegOrZR(is64, mm);
2580 switch (op) {
2581 case BITS2(0,0):
2582 break;
2583 case BITS2(0,1):
2584 argR = binop(mkADD(ty), argR, mkU(ty,1));
2585 break;
2586 case BITS2(1,0):
2587 argR = unop(mkNOT(ty), argR);
2588 break;
2589 case BITS2(1,1):
2590 argR = binop(mkSUB(ty), mkU(ty,0), argR);
2591 break;
2592 default:
2593 vassert(0);
2594 }
2595 putIRegOrZR(
2596 is64, dd,
2597 IRExpr_ITE(unop(Iop_64to1, mk_arm64g_calculate_condition(cond)),
2598 argL, argR)
2599 );
2600 const HChar* op_nm[4] = { "csel", "csinc", "csinv", "csneg" };
2601 DIP("%s %s, %s, %s, %s\n", op_nm[op],
2602 nameIRegOrZR(is64, dd), nameIRegOrZR(is64, nn),
2603 nameIRegOrZR(is64, mm), nameCC(cond));
2604 return True;
2605 }
2606
2607 /* -------------- ADD/SUB(extended reg) -------------- */
2608 /* 28 20 15 12 9 4
2609 000 01011 00 1 m opt imm3 n d ADD Wd|SP, Wn|SP, Wm ext&lsld
2610 100 01011 00 1 m opt imm3 n d ADD Xd|SP, Xn|SP, Rm ext&lsld
2611
2612 001 01011 00 1 m opt imm3 n d ADDS Wd, Wn|SP, Wm ext&lsld
2613 101 01011 00 1 m opt imm3 n d ADDS Xd, Xn|SP, Rm ext&lsld
2614
2615 010 01011 00 1 m opt imm3 n d SUB Wd|SP, Wn|SP, Wm ext&lsld
2616 110 01011 00 1 m opt imm3 n d SUB Xd|SP, Xn|SP, Rm ext&lsld
2617
2618 011 01011 00 1 m opt imm3 n d SUBS Wd, Wn|SP, Wm ext&lsld
2619 111 01011 00 1 m opt imm3 n d SUBS Xd, Xn|SP, Rm ext&lsld
2620
2621 The 'm' operand is extended per opt, thusly:
2622
2623 000 Xm & 0xFF UXTB
2624 001 Xm & 0xFFFF UXTH
2625 010 Xm & (2^32)-1 UXTW
2626 011 Xm UXTX
2627
2628 100 Xm sx from bit 7 SXTB
2629 101 Xm sx from bit 15 SXTH
2630 110 Xm sx from bit 31 SXTW
2631 111 Xm SXTX
2632
2633 In the 64 bit case (bit31 == 1), UXTX and SXTX are the identity
2634 operation on Xm. In the 32 bit case, UXTW, UXTX, SXTW and SXTX
2635 are the identity operation on Wm.
2636
2637 After extension, the value is shifted left by imm3 bits, which
2638 may only be in the range 0 .. 4 inclusive.
2639 */
2640 if (INSN(28,21) == BITS8(0,1,0,1,1,0,0,1) && INSN(12,10) <= 4) {
2641 Bool is64 = INSN(31,31) == 1;
2642 Bool isSub = INSN(30,30) == 1;
2643 Bool setCC = INSN(29,29) == 1;
2644 UInt mm = INSN(20,16);
2645 UInt opt = INSN(15,13);
2646 UInt imm3 = INSN(12,10);
2647 UInt nn = INSN(9,5);
2648 UInt dd = INSN(4,0);
2649 const HChar* nameExt[8] = { "uxtb", "uxth", "uxtw", "uxtx",
2650 "sxtb", "sxth", "sxtw", "sxtx" };
2651 /* Do almost the same thing in the 32- and 64-bit cases. */
2652 IRTemp xN = newTemp(Ity_I64);
2653 IRTemp xM = newTemp(Ity_I64);
2654 assign(xN, getIReg64orSP(nn));
2655 assign(xM, getIReg64orZR(mm));
2656 IRExpr* xMw = mkexpr(xM); /* "xM widened" */
2657 Int shSX = 0;
2658 /* widen Xm .. */
2659 switch (opt) {
2660 case BITS3(0,0,0): // UXTB
2661 xMw = binop(Iop_And64, xMw, mkU64(0xFF)); break;
2662 case BITS3(0,0,1): // UXTH
2663 xMw = binop(Iop_And64, xMw, mkU64(0xFFFF)); break;
2664 case BITS3(0,1,0): // UXTW -- noop for the 32bit case
2665 if (is64) {
2666 xMw = unop(Iop_32Uto64, unop(Iop_64to32, xMw));
2667 }
2668 break;
2669 case BITS3(0,1,1): // UXTX -- always a noop
2670 break;
2671 case BITS3(1,0,0): // SXTB
2672 shSX = 56; goto sxTo64;
2673 case BITS3(1,0,1): // SXTH
2674 shSX = 48; goto sxTo64;
2675 case BITS3(1,1,0): // SXTW -- noop for the 32bit case
2676 if (is64) {
2677 shSX = 32; goto sxTo64;
2678 }
2679 break;
2680 case BITS3(1,1,1): // SXTX -- always a noop
2681 break;
2682 sxTo64:
2683 vassert(shSX >= 32);
2684 xMw = binop(Iop_Sar64, binop(Iop_Shl64, xMw, mkU8(shSX)),
2685 mkU8(shSX));
2686 break;
2687 default:
2688 vassert(0);
2689 }
2690 /* and now shift */
2691 IRTemp argL = xN;
2692 IRTemp argR = newTemp(Ity_I64);
2693 assign(argR, binop(Iop_Shl64, xMw, mkU8(imm3)));
2694 IRTemp res = newTemp(Ity_I64);
2695 assign(res, binop(isSub ? Iop_Sub64 : Iop_Add64,
2696 mkexpr(argL), mkexpr(argR)));
2697 if (is64) {
2698 if (setCC) {
2699 putIReg64orZR(dd, mkexpr(res));
2700 setFlags_ADD_SUB(True/*is64*/, isSub, argL, argR);
2701 } else {
2702 putIReg64orSP(dd, mkexpr(res));
2703 }
2704 } else {
2705 if (setCC) {
2706 IRTemp argL32 = newTemp(Ity_I32);
2707 IRTemp argR32 = newTemp(Ity_I32);
2708 putIReg32orZR(dd, unop(Iop_64to32, mkexpr(res)));
2709 assign(argL32, unop(Iop_64to32, mkexpr(argL)));
2710 assign(argR32, unop(Iop_64to32, mkexpr(argR)));
2711 setFlags_ADD_SUB(False/*!is64*/, isSub, argL32, argR32);
2712 } else {
2713 putIReg32orSP(dd, unop(Iop_64to32, mkexpr(res)));
2714 }
2715 }
2716 DIP("%s%s %s, %s, %s %s lsl %u\n",
2717 isSub ? "sub" : "add", setCC ? "s" : "",
2718 setCC ? nameIRegOrZR(is64, dd) : nameIRegOrSP(is64, dd),
2719 nameIRegOrSP(is64, nn), nameIRegOrSP(is64, mm),
2720 nameExt[opt], imm3);
2721 return True;
2722 }
2723
2724 /* ---------------- CCMP/CCMN(imm) ---------------- */
2725 /* Bizarrely, these appear in the "data processing register"
2726 category, even though they are operations against an
2727 immediate. */
2728 /* 31 29 20 15 11 9 3
2729 sf 1 111010010 imm5 cond 10 Rn 0 nzcv CCMP Rn, #imm5, #nzcv, cond
2730 sf 0 111010010 imm5 cond 10 Rn 0 nzcv CCMN Rn, #imm5, #nzcv, cond
2731
2732 Operation is:
2733 (CCMP) flags = if cond then flags-after-sub(Rn,imm5) else nzcv
2734 (CCMN) flags = if cond then flags-after-add(Rn,imm5) else nzcv
2735 */
2736 if (INSN(29,21) == BITS9(1,1,1,0,1,0,0,1,0)
2737 && INSN(11,10) == BITS2(1,0) && INSN(4,4) == 0) {
2738 Bool is64 = INSN(31,31) == 1;
2739 Bool isSUB = INSN(30,30) == 1;
2740 UInt imm5 = INSN(20,16);
2741 UInt cond = INSN(15,12);
2742 UInt nn = INSN(9,5);
2743 UInt nzcv = INSN(3,0);
2744
2745 IRTemp condT = newTemp(Ity_I1);
2746 assign(condT, unop(Iop_64to1, mk_arm64g_calculate_condition(cond)));
2747
2748 IRType ty = is64 ? Ity_I64 : Ity_I32;
2749 IRTemp argL = newTemp(ty);
2750 IRTemp argR = newTemp(ty);
2751
2752 if (is64) {
2753 assign(argL, getIReg64orZR(nn));
2754 assign(argR, mkU64(imm5));
2755 } else {
2756 assign(argL, getIReg32orZR(nn));
2757 assign(argR, mkU32(imm5));
2758 }
2759 setFlags_ADD_SUB_conditionally(is64, isSUB, condT, argL, argR, nzcv);
2760
2761 DIP("ccm%c %s, #%u, #%u, %s\n",
2762 isSUB ? 'p' : 'n', nameIRegOrZR(is64, nn),
2763 imm5, nzcv, nameCC(cond));
2764 return True;
2765 }
2766
2767 /* ---------------- CCMP/CCMN(reg) ---------------- */
2768 /* 31 29 20 15 11 9 3
2769 sf 1 111010010 Rm cond 00 Rn 0 nzcv CCMP Rn, Rm, #nzcv, cond
2770 sf 0 111010010 Rm cond 00 Rn 0 nzcv CCMN Rn, Rm, #nzcv, cond
2771 Operation is:
2772 (CCMP) flags = if cond then flags-after-sub(Rn,Rm) else nzcv
2773 (CCMN) flags = if cond then flags-after-add(Rn,Rm) else nzcv
2774 */
2775 if (INSN(29,21) == BITS9(1,1,1,0,1,0,0,1,0)
2776 && INSN(11,10) == BITS2(0,0) && INSN(4,4) == 0) {
2777 Bool is64 = INSN(31,31) == 1;
2778 Bool isSUB = INSN(30,30) == 1;
2779 UInt mm = INSN(20,16);
2780 UInt cond = INSN(15,12);
2781 UInt nn = INSN(9,5);
2782 UInt nzcv = INSN(3,0);
2783
2784 IRTemp condT = newTemp(Ity_I1);
2785 assign(condT, unop(Iop_64to1, mk_arm64g_calculate_condition(cond)));
2786
2787 IRType ty = is64 ? Ity_I64 : Ity_I32;
2788 IRTemp argL = newTemp(ty);
2789 IRTemp argR = newTemp(ty);
2790
2791 if (is64) {
2792 assign(argL, getIReg64orZR(nn));
2793 assign(argR, getIReg64orZR(mm));
2794 } else {
2795 assign(argL, getIReg32orZR(nn));
2796 assign(argR, getIReg32orZR(mm));
2797 }
2798 setFlags_ADD_SUB_conditionally(is64, isSUB, condT, argL, argR, nzcv);
2799
2800 DIP("ccm%c %s, %s, #%u, %s\n",
2801 isSUB ? 'p' : 'n', nameIRegOrZR(is64, nn),
2802 nameIRegOrZR(is64, mm), nzcv, nameCC(cond));
2803 return True;
2804 }
2805
2806
2807 /* -------------- REV/REV16/REV32/RBIT -------------- */
2808 /* 31 30 28 20 15 11 9 4
2809
sewardj32d86752014-03-02 12:47:18 +00002810 1 10 11010110 00000 0000 11 n d (1) REV Xd, Xn
2811 0 10 11010110 00000 0000 10 n d (2) REV Wd, Wn
sewardjbbcf1882014-01-12 12:49:10 +00002812
sewardj32d86752014-03-02 12:47:18 +00002813 1 10 11010110 00000 0000 00 n d (3) RBIT Xd, Xn
2814 0 10 11010110 00000 0000 00 n d (4) RBIT Wd, Wn
sewardjbbcf1882014-01-12 12:49:10 +00002815
sewardjdc9259c2014-02-27 11:10:19 +00002816 1 10 11010110 00000 0000 01 n d (5) REV16 Xd, Xn
2817 0 10 11010110 00000 0000 01 n d (6) REV16 Wd, Wn
sewardjbbcf1882014-01-12 12:49:10 +00002818
sewardjdc9259c2014-02-27 11:10:19 +00002819 1 10 11010110 00000 0000 10 n d (7) REV32 Xd, Xn
sewardjbbcf1882014-01-12 12:49:10 +00002820 */
sewardjbbcf1882014-01-12 12:49:10 +00002821 if (INSN(30,21) == BITS10(1,0,1,1,0,1,0,1,1,0)
sewardjdc9259c2014-02-27 11:10:19 +00002822 && INSN(20,12) == BITS9(0,0,0,0,0,0,0,0,0)) {
2823 UInt b31 = INSN(31,31);
2824 UInt opc = INSN(11,10);
2825
2826 UInt ix = 0;
2827 /**/ if (b31 == 1 && opc == BITS2(1,1)) ix = 1;
2828 else if (b31 == 0 && opc == BITS2(1,0)) ix = 2;
2829 else if (b31 == 1 && opc == BITS2(0,0)) ix = 3;
2830 else if (b31 == 0 && opc == BITS2(0,0)) ix = 4;
2831 else if (b31 == 1 && opc == BITS2(0,1)) ix = 5;
2832 else if (b31 == 0 && opc == BITS2(0,1)) ix = 6;
2833 else if (b31 == 1 && opc == BITS2(1,0)) ix = 7;
sewardj32d86752014-03-02 12:47:18 +00002834 if (ix >= 1 && ix <= 7) {
2835 Bool is64 = ix == 1 || ix == 3 || ix == 5 || ix == 7;
sewardjdc9259c2014-02-27 11:10:19 +00002836 UInt nn = INSN(9,5);
2837 UInt dd = INSN(4,0);
2838 IRTemp src = newTemp(Ity_I64);
2839 IRTemp dst = IRTemp_INVALID;
sewardj32d86752014-03-02 12:47:18 +00002840 IRTemp (*math)(IRTemp) = NULL;
2841 switch (ix) {
2842 case 1: case 2: math = math_BYTESWAP64; break;
2843 case 3: case 4: math = math_BITSWAP64; break;
2844 case 5: case 6: math = math_USHORTSWAP64; break;
2845 case 7: math = math_UINTSWAP64; break;
2846 default: vassert(0);
2847 }
2848 const HChar* names[7]
2849 = { "rev", "rev", "rbit", "rbit", "rev16", "rev16", "rev32" };
2850 const HChar* nm = names[ix-1];
2851 vassert(math);
2852 if (ix == 6) {
2853 /* This has to be special cased, since the logic below doesn't
2854 handle it correctly. */
sewardjdc9259c2014-02-27 11:10:19 +00002855 assign(src, getIReg64orZR(nn));
sewardj32d86752014-03-02 12:47:18 +00002856 dst = math(src);
2857 putIReg64orZR(dd,
2858 unop(Iop_32Uto64, unop(Iop_64to32, mkexpr(dst))));
2859 } else if (is64) {
2860 assign(src, getIReg64orZR(nn));
2861 dst = math(src);
sewardjdc9259c2014-02-27 11:10:19 +00002862 putIReg64orZR(dd, mkexpr(dst));
2863 } else {
2864 assign(src, binop(Iop_Shl64, getIReg64orZR(nn), mkU8(32)));
sewardj32d86752014-03-02 12:47:18 +00002865 dst = math(src);
sewardjdc9259c2014-02-27 11:10:19 +00002866 putIReg32orZR(dd, unop(Iop_64to32, mkexpr(dst)));
2867 }
sewardj32d86752014-03-02 12:47:18 +00002868 DIP("%s %s, %s\n", nm,
sewardjdc9259c2014-02-27 11:10:19 +00002869 nameIRegOrZR(is64,dd), nameIRegOrZR(is64,nn));
2870 return True;
sewardjbbcf1882014-01-12 12:49:10 +00002871 }
sewardjdc9259c2014-02-27 11:10:19 +00002872 /* else fall through */
sewardjbbcf1882014-01-12 12:49:10 +00002873 }
2874
2875 /* -------------------- CLZ/CLS -------------------- */
2876 /* 30 28 24 20 15 9 4
2877 sf 10 1101 0110 00000 00010 0 n d CLZ Rd, Rn
2878 sf 10 1101 0110 00000 00010 1 n d CLS Rd, Rn
2879 */
2880 if (INSN(30,21) == BITS10(1,0,1,1,0,1,0,1,1,0)
2881 && INSN(20,11) == BITS10(0,0,0,0,0,0,0,0,1,0)) {
2882 Bool is64 = INSN(31,31) == 1;
2883 Bool isCLS = INSN(10,10) == 1;
2884 UInt nn = INSN(9,5);
2885 UInt dd = INSN(4,0);
2886 IRTemp src = newTemp(Ity_I64);
2887 IRTemp dst = newTemp(Ity_I64);
2888 if (!isCLS) { // CLS not yet supported
2889 if (is64) {
2890 assign(src, getIReg64orZR(nn));
2891 assign(dst, IRExpr_ITE(binop(Iop_CmpEQ64, mkexpr(src), mkU64(0)),
2892 mkU64(64),
2893 unop(Iop_Clz64, mkexpr(src))));
2894 putIReg64orZR(dd, mkexpr(dst));
2895 } else {
2896 assign(src, binop(Iop_Shl64,
2897 unop(Iop_32Uto64, getIReg32orZR(nn)), mkU8(32)));
2898 assign(dst, IRExpr_ITE(binop(Iop_CmpEQ64, mkexpr(src), mkU64(0)),
2899 mkU64(32),
2900 unop(Iop_Clz64, mkexpr(src))));
2901 putIReg32orZR(dd, unop(Iop_64to32, mkexpr(dst)));
2902 }
2903 DIP("cl%c %s, %s\n",
2904 isCLS ? 's' : 'z', nameIRegOrZR(is64, dd), nameIRegOrZR(is64, nn));
2905 return True;
2906 }
2907 }
2908
2909 /* -------------------- LSLV/LSRV/ASRV -------------------- */
2910 /* 30 28 20 15 11 9 4
2911 sf 00 1101 0110 m 0010 00 n d LSLV Rd,Rn,Rm
2912 sf 00 1101 0110 m 0010 01 n d LSRV Rd,Rn,Rm
2913 sf 00 1101 0110 m 0010 10 n d ASRV Rd,Rn,Rm
2914 */
2915 if (INSN(30,21) == BITS10(0,0,1,1,0,1,0,1,1,0)
2916 && INSN(15,12) == BITS4(0,0,1,0) && INSN(11,10) < BITS2(1,1)) {
2917 Bool is64 = INSN(31,31) == 1;
2918 UInt mm = INSN(20,16);
2919 UInt op = INSN(11,10);
2920 UInt nn = INSN(9,5);
2921 UInt dd = INSN(4,0);
2922 IRType ty = is64 ? Ity_I64 : Ity_I32;
2923 IRTemp srcL = newTemp(ty);
2924 IRTemp srcR = newTemp(Ity_I8);
2925 IRTemp res = newTemp(ty);
2926 IROp iop = Iop_INVALID;
2927 assign(srcL, getIRegOrZR(is64, nn));
2928 assign(srcR,
2929 unop(Iop_64to8,
2930 binop(Iop_And64,
2931 getIReg64orZR(mm), mkU64(is64 ? 63 : 31))));
2932 switch (op) {
2933 case BITS2(0,0): iop = mkSHL(ty); break;
2934 case BITS2(0,1): iop = mkSHR(ty); break;
2935 case BITS2(1,0): iop = mkSAR(ty); break;
2936 default: vassert(0);
2937 }
2938 assign(res, binop(iop, mkexpr(srcL), mkexpr(srcR)));
2939 putIRegOrZR(is64, dd, mkexpr(res));
2940 vassert(op < 3);
2941 const HChar* names[3] = { "lslv", "lsrv", "asrv" };
2942 DIP("%s %s, %s, %s\n",
2943 names[op], nameIRegOrZR(is64,dd),
2944 nameIRegOrZR(is64,nn), nameIRegOrZR(is64,mm));
2945 return True;
2946 }
2947
2948 /* -------------------- SDIV/UDIV -------------------- */
2949 /* 30 28 20 15 10 9 4
2950 sf 00 1101 0110 m 00001 1 n d SDIV Rd,Rn,Rm
2951 sf 00 1101 0110 m 00001 0 n d UDIV Rd,Rn,Rm
2952 */
2953 if (INSN(30,21) == BITS10(0,0,1,1,0,1,0,1,1,0)
2954 && INSN(15,11) == BITS5(0,0,0,0,1)) {
2955 Bool is64 = INSN(31,31) == 1;
2956 UInt mm = INSN(20,16);
2957 Bool isS = INSN(10,10) == 1;
2958 UInt nn = INSN(9,5);
2959 UInt dd = INSN(4,0);
2960 if (isS) {
2961 putIRegOrZR(is64, dd, binop(is64 ? Iop_DivS64 : Iop_DivS32,
2962 getIRegOrZR(is64, nn),
2963 getIRegOrZR(is64, mm)));
2964 } else {
2965 putIRegOrZR(is64, dd, binop(is64 ? Iop_DivU64 : Iop_DivU32,
2966 getIRegOrZR(is64, nn),
2967 getIRegOrZR(is64, mm)));
2968 }
2969 DIP("%cdiv %s, %s, %s\n", isS ? 's' : 'u',
2970 nameIRegOrZR(is64, dd),
2971 nameIRegOrZR(is64, nn), nameIRegOrZR(is64, mm));
2972 return True;
2973 }
2974
2975 /* ------------------ {S,U}M{ADD,SUB}L ------------------ */
2976 /* 31 23 20 15 14 9 4
2977 1001 1011 101 m 0 a n d UMADDL Xd,Wn,Wm,Xa
2978 1001 1011 001 m 0 a n d SMADDL Xd,Wn,Wm,Xa
2979 1001 1011 101 m 1 a n d UMSUBL Xd,Wn,Wm,Xa
2980 1001 1011 001 m 1 a n d SMSUBL Xd,Wn,Wm,Xa
2981 with operation
2982 Xd = Xa +/- (Wn *u/s Wm)
2983 */
2984 if (INSN(31,24) == BITS8(1,0,0,1,1,0,1,1) && INSN(22,21) == BITS2(0,1)) {
2985 Bool isU = INSN(23,23) == 1;
2986 UInt mm = INSN(20,16);
2987 Bool isAdd = INSN(15,15) == 0;
2988 UInt aa = INSN(14,10);
2989 UInt nn = INSN(9,5);
2990 UInt dd = INSN(4,0);
2991 IRTemp wN = newTemp(Ity_I32);
2992 IRTemp wM = newTemp(Ity_I32);
2993 IRTemp xA = newTemp(Ity_I64);
2994 IRTemp muld = newTemp(Ity_I64);
2995 IRTemp res = newTemp(Ity_I64);
2996 assign(wN, getIReg32orZR(nn));
2997 assign(wM, getIReg32orZR(mm));
2998 assign(xA, getIReg64orZR(aa));
2999 assign(muld, binop(isU ? Iop_MullU32 : Iop_MullS32,
3000 mkexpr(wN), mkexpr(wM)));
3001 assign(res, binop(isAdd ? Iop_Add64 : Iop_Sub64,
3002 mkexpr(xA), mkexpr(muld)));
3003 putIReg64orZR(dd, mkexpr(res));
3004 DIP("%cm%sl %s, %s, %s, %s\n", isU ? 'u' : 's', isAdd ? "add" : "sub",
3005 nameIReg64orZR(dd), nameIReg32orZR(nn),
3006 nameIReg32orZR(mm), nameIReg64orZR(aa));
3007 return True;
3008 }
3009 vex_printf("ARM64 front end: data_processing_register\n");
3010 return False;
3011# undef INSN
3012}
3013
3014
3015/*------------------------------------------------------------*/
3016/*--- Load and Store instructions ---*/
3017/*------------------------------------------------------------*/
3018
3019/* Generate the EA for a "reg + reg" style amode. This is done from
3020 parts of the insn, but for sanity checking sake it takes the whole
3021 insn. This appears to depend on insn[15:12], with opt=insn[15:13]
3022 and S=insn[12]:
3023
3024 The possible forms, along with their opt:S values, are:
3025 011:0 Xn|SP + Xm
3026 111:0 Xn|SP + Xm
3027 011:1 Xn|SP + Xm * transfer_szB
3028 111:1 Xn|SP + Xm * transfer_szB
3029 010:0 Xn|SP + 32Uto64(Wm)
3030 010:1 Xn|SP + 32Uto64(Wm) * transfer_szB
3031 110:0 Xn|SP + 32Sto64(Wm)
3032 110:1 Xn|SP + 32Sto64(Wm) * transfer_szB
3033
3034 Rm is insn[20:16]. Rn is insn[9:5]. Rt is insn[4:0]. Log2 of
3035 the transfer size is insn[23,31,30]. For integer loads/stores,
3036 insn[23] is zero, hence szLg2 can be at most 3 in such cases.
3037
3038 If the decoding fails, it returns IRTemp_INVALID.
3039
3040 isInt is True iff this is decoding is for transfers to/from integer
3041 registers. If False it is for transfers to/from vector registers.
3042*/
3043static IRTemp gen_indexed_EA ( /*OUT*/HChar* buf, UInt insn, Bool isInt )
3044{
3045 UInt optS = SLICE_UInt(insn, 15, 12);
3046 UInt mm = SLICE_UInt(insn, 20, 16);
3047 UInt nn = SLICE_UInt(insn, 9, 5);
3048 UInt szLg2 = (isInt ? 0 : (SLICE_UInt(insn, 23, 23) << 2))
3049 | SLICE_UInt(insn, 31, 30); // Log2 of the size
3050
3051 buf[0] = 0;
3052
3053 /* Sanity checks, that this really is a load/store insn. */
3054 if (SLICE_UInt(insn, 11, 10) != BITS2(1,0))
3055 goto fail;
3056
3057 if (isInt
3058 && SLICE_UInt(insn, 29, 21) != BITS9(1,1,1,0,0,0,0,1,1)/*LDR*/
3059 && SLICE_UInt(insn, 29, 21) != BITS9(1,1,1,0,0,0,0,0,1)/*STR*/
3060 && SLICE_UInt(insn, 29, 21) != BITS9(1,1,1,0,0,0,1,0,1)/*LDRSbhw Xt*/
3061 && SLICE_UInt(insn, 29, 21) != BITS9(1,1,1,0,0,0,1,1,1))/*LDRSbhw Wt*/
3062 goto fail;
3063
3064 if (!isInt
3065 && SLICE_UInt(insn, 29, 24) != BITS6(1,1,1,1,0,0)) /*LDR/STR*/
3066 goto fail;
3067
3068 /* Throw out non-verified but possibly valid cases. */
3069 switch (szLg2) {
3070 case BITS3(0,0,0): break; // 8 bit, valid for both int and vec
3071 case BITS3(0,0,1): break; // 16 bit, valid for both int and vec
3072 case BITS3(0,1,0): break; // 32 bit, valid for both int and vec
3073 case BITS3(0,1,1): break; // 64 bit, valid for both int and vec
3074 case BITS3(1,0,0): // can only ever be valid for the vector case
3075 if (isInt) goto fail; else goto fail;
3076 case BITS3(1,0,1): // these sizes are never valid
3077 case BITS3(1,1,0):
3078 case BITS3(1,1,1): goto fail;
3079
3080 default: vassert(0);
3081 }
3082
3083 IRExpr* rhs = NULL;
3084 switch (optS) {
3085 case BITS4(1,1,1,0): goto fail; //ATC
3086 case BITS4(0,1,1,0):
3087 rhs = getIReg64orZR(mm);
3088 vex_sprintf(buf, "[%s, %s]",
3089 nameIReg64orZR(nn), nameIReg64orZR(mm));
3090 break;
3091 case BITS4(1,1,1,1): goto fail; //ATC
3092 case BITS4(0,1,1,1):
3093 rhs = binop(Iop_Shl64, getIReg64orZR(mm), mkU8(szLg2));
3094 vex_sprintf(buf, "[%s, %s lsl %u]",
3095 nameIReg64orZR(nn), nameIReg64orZR(mm), szLg2);
3096 break;
3097 case BITS4(0,1,0,0):
3098 rhs = unop(Iop_32Uto64, getIReg32orZR(mm));
3099 vex_sprintf(buf, "[%s, %s uxtx]",
3100 nameIReg64orZR(nn), nameIReg32orZR(mm));
3101 break;
3102 case BITS4(0,1,0,1):
3103 rhs = binop(Iop_Shl64,
3104 unop(Iop_32Uto64, getIReg32orZR(mm)), mkU8(szLg2));
3105 vex_sprintf(buf, "[%s, %s uxtx, lsl %u]",
3106 nameIReg64orZR(nn), nameIReg32orZR(mm), szLg2);
3107 break;
3108 case BITS4(1,1,0,0):
3109 rhs = unop(Iop_32Sto64, getIReg32orZR(mm));
3110 vex_sprintf(buf, "[%s, %s sxtx]",
3111 nameIReg64orZR(nn), nameIReg32orZR(mm));
3112 break;
3113 case BITS4(1,1,0,1):
3114 rhs = binop(Iop_Shl64,
3115 unop(Iop_32Sto64, getIReg32orZR(mm)), mkU8(szLg2));
3116 vex_sprintf(buf, "[%s, %s sxtx, lsl %u]",
3117 nameIReg64orZR(nn), nameIReg32orZR(mm), szLg2);
3118 break;
3119 default:
3120 /* The rest appear to be genuinely invalid */
3121 goto fail;
3122 }
3123
3124 vassert(rhs);
3125 IRTemp res = newTemp(Ity_I64);
3126 assign(res, binop(Iop_Add64, getIReg64orSP(nn), rhs));
3127 return res;
3128
3129 fail:
3130 vex_printf("gen_indexed_EA: unhandled case optS == 0x%x\n", optS);
3131 return IRTemp_INVALID;
3132}
3133
3134
3135/* Generate an 8/16/32/64 bit integer store to ADDR for the lowest
3136 bits of DATAE :: Ity_I64. */
3137static void gen_narrowing_store ( UInt szB, IRTemp addr, IRExpr* dataE )
3138{
3139 IRExpr* addrE = mkexpr(addr);
3140 switch (szB) {
3141 case 8:
3142 storeLE(addrE, dataE);
3143 break;
3144 case 4:
3145 storeLE(addrE, unop(Iop_64to32, dataE));
3146 break;
3147 case 2:
3148 storeLE(addrE, unop(Iop_64to16, dataE));
3149 break;
3150 case 1:
3151 storeLE(addrE, unop(Iop_64to8, dataE));
3152 break;
3153 default:
3154 vassert(0);
3155 }
3156}
3157
3158
3159/* Generate an 8/16/32/64 bit unsigned widening load from ADDR,
3160 placing the result in an Ity_I64 temporary. */
3161static IRTemp gen_zwidening_load ( UInt szB, IRTemp addr )
3162{
3163 IRTemp res = newTemp(Ity_I64);
3164 IRExpr* addrE = mkexpr(addr);
3165 switch (szB) {
3166 case 8:
3167 assign(res, loadLE(Ity_I64,addrE));
3168 break;
3169 case 4:
3170 assign(res, unop(Iop_32Uto64, loadLE(Ity_I32,addrE)));
3171 break;
3172 case 2:
3173 assign(res, unop(Iop_16Uto64, loadLE(Ity_I16,addrE)));
3174 break;
3175 case 1:
3176 assign(res, unop(Iop_8Uto64, loadLE(Ity_I8,addrE)));
3177 break;
3178 default:
3179 vassert(0);
3180 }
3181 return res;
3182}
3183
3184
sewardj18bf5172014-06-14 18:05:30 +00003185/* Generate a "standard 7" name, from bitQ and size. But also
3186 allow ".1d" since that's occasionally useful. */
3187static
3188const HChar* nameArr_Q_SZ ( UInt bitQ, UInt size )
3189{
3190 vassert(bitQ <= 1 && size <= 3);
3191 const HChar* nms[8]
sewardj25523c42014-06-15 19:36:29 +00003192 = { "8b", "4h", "2s", "1d", "16b", "8h", "4s", "2d" };
sewardj18bf5172014-06-14 18:05:30 +00003193 UInt ix = (bitQ << 2) | size;
3194 vassert(ix < 8);
3195 return nms[ix];
3196}
3197
3198
sewardjbbcf1882014-01-12 12:49:10 +00003199static
3200Bool dis_ARM64_load_store(/*MB_OUT*/DisResult* dres, UInt insn)
3201{
3202# define INSN(_bMax,_bMin) SLICE_UInt(insn, (_bMax), (_bMin))
3203
3204 /* ------------ LDR,STR (immediate, uimm12) ----------- */
3205 /* uimm12 is scaled by the transfer size
3206
3207 31 29 26 21 9 4
3208 | | | | | |
3209 11 111 00100 imm12 nn tt STR Xt, [Xn|SP, #imm12 * 8]
3210 11 111 00101 imm12 nn tt LDR Xt, [Xn|SP, #imm12 * 8]
3211
3212 10 111 00100 imm12 nn tt STR Wt, [Xn|SP, #imm12 * 4]
3213 10 111 00101 imm12 nn tt LDR Wt, [Xn|SP, #imm12 * 4]
3214
3215 01 111 00100 imm12 nn tt STRH Wt, [Xn|SP, #imm12 * 2]
3216 01 111 00101 imm12 nn tt LDRH Wt, [Xn|SP, #imm12 * 2]
3217
3218 00 111 00100 imm12 nn tt STRB Wt, [Xn|SP, #imm12 * 1]
3219 00 111 00101 imm12 nn tt LDRB Wt, [Xn|SP, #imm12 * 1]
3220 */
3221 if (INSN(29,23) == BITS7(1,1,1,0,0,1,0)) {
3222 UInt szLg2 = INSN(31,30);
3223 UInt szB = 1 << szLg2;
3224 Bool isLD = INSN(22,22) == 1;
3225 UInt offs = INSN(21,10) * szB;
3226 UInt nn = INSN(9,5);
3227 UInt tt = INSN(4,0);
3228 IRTemp ta = newTemp(Ity_I64);
3229 assign(ta, binop(Iop_Add64, getIReg64orSP(nn), mkU64(offs)));
3230 if (nn == 31) { /* FIXME generate stack alignment check */ }
3231 vassert(szLg2 < 4);
3232 if (isLD) {
3233 putIReg64orZR(tt, mkexpr(gen_zwidening_load(szB, ta)));
3234 } else {
3235 gen_narrowing_store(szB, ta, getIReg64orZR(tt));
3236 }
3237 const HChar* ld_name[4] = { "ldrb", "ldrh", "ldr", "ldr" };
3238 const HChar* st_name[4] = { "strb", "strh", "str", "str" };
3239 DIP("%s %s, [%s, #%u]\n",
3240 (isLD ? ld_name : st_name)[szLg2], nameIRegOrZR(szB == 8, tt),
3241 nameIReg64orSP(nn), offs);
3242 return True;
3243 }
3244
3245 /* ------------ LDUR,STUR (immediate, simm9) ----------- */
3246 /*
3247 31 29 26 20 11 9 4
3248 | | | | | | |
3249 (at-Rn-then-Rn=EA) | | |
3250 sz 111 00000 0 imm9 01 Rn Rt STR Rt, [Xn|SP], #simm9
3251 sz 111 00001 0 imm9 01 Rn Rt LDR Rt, [Xn|SP], #simm9
3252
3253 (at-EA-then-Rn=EA)
3254 sz 111 00000 0 imm9 11 Rn Rt STR Rt, [Xn|SP, #simm9]!
3255 sz 111 00001 0 imm9 11 Rn Rt LDR Rt, [Xn|SP, #simm9]!
3256
3257 (at-EA)
3258 sz 111 00000 0 imm9 00 Rn Rt STR Rt, [Xn|SP, #simm9]
3259 sz 111 00001 0 imm9 00 Rn Rt LDR Rt, [Xn|SP, #simm9]
3260
3261 simm9 is unscaled.
3262
3263 The case 'wback && Rn == Rt && Rt != 31' is disallowed. In the
3264 load case this is because would create two competing values for
3265 Rt. In the store case the reason is unclear, but the spec
3266 disallows it anyway.
3267
3268 Stores are narrowing, loads are unsigned widening. sz encodes
3269 the transfer size in the normal way: 00=1, 01=2, 10=4, 11=8.
3270 */
3271 if ((INSN(29,21) & BITS9(1,1,1, 1,1,1,1,0, 1))
3272 == BITS9(1,1,1, 0,0,0,0,0, 0)) {
3273 UInt szLg2 = INSN(31,30);
3274 UInt szB = 1 << szLg2;
3275 Bool isLoad = INSN(22,22) == 1;
3276 UInt imm9 = INSN(20,12);
3277 UInt nn = INSN(9,5);
3278 UInt tt = INSN(4,0);
3279 Bool wBack = INSN(10,10) == 1;
3280 UInt how = INSN(11,10);
3281 if (how == BITS2(1,0) || (wBack && nn == tt && tt != 31)) {
3282 /* undecodable; fall through */
3283 } else {
3284 if (nn == 31) { /* FIXME generate stack alignment check */ }
3285
3286 // Compute the transfer address TA and the writeback address WA.
3287 IRTemp tRN = newTemp(Ity_I64);
3288 assign(tRN, getIReg64orSP(nn));
3289 IRTemp tEA = newTemp(Ity_I64);
3290 Long simm9 = (Long)sx_to_64(imm9, 9);
3291 assign(tEA, binop(Iop_Add64, mkexpr(tRN), mkU64(simm9)));
3292
3293 IRTemp tTA = newTemp(Ity_I64);
3294 IRTemp tWA = newTemp(Ity_I64);
3295 switch (how) {
3296 case BITS2(0,1):
3297 assign(tTA, mkexpr(tRN)); assign(tWA, mkexpr(tEA)); break;
3298 case BITS2(1,1):
3299 assign(tTA, mkexpr(tEA)); assign(tWA, mkexpr(tEA)); break;
3300 case BITS2(0,0):
3301 assign(tTA, mkexpr(tEA)); /* tWA is unused */ break;
3302 default:
3303 vassert(0); /* NOTREACHED */
3304 }
3305
sewardje0bff8b2014-03-09 09:40:23 +00003306 /* Normally rN would be updated after the transfer. However, in
3307 the special case typifed by
3308 str x30, [sp,#-16]!
3309 it is necessary to update SP before the transfer, (1)
3310 because Memcheck will otherwise complain about a write
3311 below the stack pointer, and (2) because the segfault
3312 stack extension mechanism will otherwise extend the stack
3313 only down to SP before the instruction, which might not be
3314 far enough, if the -16 bit takes the actual access
3315 address to the next page.
3316 */
3317 Bool earlyWBack
3318 = wBack && simm9 < 0 && szB == 8
3319 && how == BITS2(1,1) && nn == 31 && !isLoad && tt != nn;
3320
3321 if (wBack && earlyWBack)
3322 putIReg64orSP(nn, mkexpr(tEA));
3323
sewardjbbcf1882014-01-12 12:49:10 +00003324 if (isLoad) {
3325 putIReg64orZR(tt, mkexpr(gen_zwidening_load(szB, tTA)));
3326 } else {
3327 gen_narrowing_store(szB, tTA, getIReg64orZR(tt));
3328 }
3329
sewardje0bff8b2014-03-09 09:40:23 +00003330 if (wBack && !earlyWBack)
sewardjbbcf1882014-01-12 12:49:10 +00003331 putIReg64orSP(nn, mkexpr(tEA));
3332
3333 const HChar* ld_name[4] = { "ldurb", "ldurh", "ldur", "ldur" };
3334 const HChar* st_name[4] = { "sturb", "sturh", "stur", "stur" };
3335 const HChar* fmt_str = NULL;
3336 switch (how) {
3337 case BITS2(0,1):
3338 fmt_str = "%s %s, [%s], #%lld (at-Rn-then-Rn=EA)\n";
3339 break;
3340 case BITS2(1,1):
3341 fmt_str = "%s %s, [%s, #%lld]! (at-EA-then-Rn=EA)\n";
3342 break;
3343 case BITS2(0,0):
3344 fmt_str = "%s %s, [%s, #%lld] (at-Rn)\n";
3345 break;
3346 default:
3347 vassert(0);
3348 }
3349 DIP(fmt_str, (isLoad ? ld_name : st_name)[szLg2],
3350 nameIRegOrZR(szB == 8, tt),
3351 nameIReg64orSP(nn), simm9);
3352 return True;
3353 }
3354 }
3355
3356 /* -------- LDP,STP (immediate, simm7) (INT REGS) -------- */
3357 /* L==1 => mm==LD
3358 L==0 => mm==ST
3359 x==0 => 32 bit transfers, and zero extended loads
3360 x==1 => 64 bit transfers
3361 simm7 is scaled by the (single-register) transfer size
3362
3363 (at-Rn-then-Rn=EA)
3364 x0 101 0001 L imm7 Rt2 Rn Rt1 mmP Rt1,Rt2, [Xn|SP], #imm
3365
3366 (at-EA-then-Rn=EA)
3367 x0 101 0011 L imm7 Rt2 Rn Rt1 mmP Rt1,Rt2, [Xn|SP, #imm]!
3368
3369 (at-EA)
3370 x0 101 0010 L imm7 Rt2 Rn Rt1 mmP Rt1,Rt2, [Xn|SP, #imm]
3371 */
3372
3373 UInt insn_30_23 = INSN(30,23);
3374 if (insn_30_23 == BITS8(0,1,0,1,0,0,0,1)
3375 || insn_30_23 == BITS8(0,1,0,1,0,0,1,1)
3376 || insn_30_23 == BITS8(0,1,0,1,0,0,1,0)) {
3377 UInt bL = INSN(22,22);
3378 UInt bX = INSN(31,31);
3379 UInt bWBack = INSN(23,23);
3380 UInt rT1 = INSN(4,0);
3381 UInt rN = INSN(9,5);
3382 UInt rT2 = INSN(14,10);
3383 Long simm7 = (Long)sx_to_64(INSN(21,15), 7);
3384 if ((bWBack && (rT1 == rN || rT2 == rN) && rN != 31)
3385 || (bL && rT1 == rT2)) {
3386 /* undecodable; fall through */
3387 } else {
3388 if (rN == 31) { /* FIXME generate stack alignment check */ }
3389
3390 // Compute the transfer address TA and the writeback address WA.
3391 IRTemp tRN = newTemp(Ity_I64);
3392 assign(tRN, getIReg64orSP(rN));
3393 IRTemp tEA = newTemp(Ity_I64);
3394 simm7 = (bX ? 8 : 4) * simm7;
3395 assign(tEA, binop(Iop_Add64, mkexpr(tRN), mkU64(simm7)));
3396
3397 IRTemp tTA = newTemp(Ity_I64);
3398 IRTemp tWA = newTemp(Ity_I64);
3399 switch (INSN(24,23)) {
3400 case BITS2(0,1):
3401 assign(tTA, mkexpr(tRN)); assign(tWA, mkexpr(tEA)); break;
3402 case BITS2(1,1):
3403 assign(tTA, mkexpr(tEA)); assign(tWA, mkexpr(tEA)); break;
3404 case BITS2(1,0):
3405 assign(tTA, mkexpr(tEA)); /* tWA is unused */ break;
3406 default:
3407 vassert(0); /* NOTREACHED */
3408 }
3409
3410 /* Normally rN would be updated after the transfer. However, in
3411 the special case typifed by
3412 stp x29, x30, [sp,#-112]!
3413 it is necessary to update SP before the transfer, (1)
3414 because Memcheck will otherwise complain about a write
3415 below the stack pointer, and (2) because the segfault
3416 stack extension mechanism will otherwise extend the stack
3417 only down to SP before the instruction, which might not be
3418 far enough, if the -112 bit takes the actual access
3419 address to the next page.
3420 */
3421 Bool earlyWBack
3422 = bWBack && simm7 < 0
3423 && INSN(24,23) == BITS2(1,1) && rN == 31 && bL == 0;
3424
3425 if (bWBack && earlyWBack)
3426 putIReg64orSP(rN, mkexpr(tEA));
3427
3428 /**/ if (bL == 1 && bX == 1) {
3429 // 64 bit load
3430 putIReg64orZR(rT1, loadLE(Ity_I64,
3431 binop(Iop_Add64,mkexpr(tTA),mkU64(0))));
3432 putIReg64orZR(rT2, loadLE(Ity_I64,
3433 binop(Iop_Add64,mkexpr(tTA),mkU64(8))));
3434 } else if (bL == 1 && bX == 0) {
sewardjbbcf1882014-01-12 12:49:10 +00003435 // 32 bit load
3436 putIReg32orZR(rT1, loadLE(Ity_I32,
3437 binop(Iop_Add64,mkexpr(tTA),mkU64(0))));
3438 putIReg32orZR(rT2, loadLE(Ity_I32,
3439 binop(Iop_Add64,mkexpr(tTA),mkU64(4))));
3440 } else if (bL == 0 && bX == 1) {
3441 // 64 bit store
3442 storeLE(binop(Iop_Add64,mkexpr(tTA),mkU64(0)),
3443 getIReg64orZR(rT1));
3444 storeLE(binop(Iop_Add64,mkexpr(tTA),mkU64(8)),
3445 getIReg64orZR(rT2));
3446 } else {
3447 vassert(bL == 0 && bX == 0);
sewardjbbcf1882014-01-12 12:49:10 +00003448 // 32 bit store
3449 storeLE(binop(Iop_Add64,mkexpr(tTA),mkU64(0)),
3450 getIReg32orZR(rT1));
3451 storeLE(binop(Iop_Add64,mkexpr(tTA),mkU64(4)),
3452 getIReg32orZR(rT2));
3453 }
3454
3455 if (bWBack && !earlyWBack)
3456 putIReg64orSP(rN, mkexpr(tEA));
3457
3458 const HChar* fmt_str = NULL;
3459 switch (INSN(24,23)) {
3460 case BITS2(0,1):
3461 fmt_str = "%sp %s, %s, [%s], #%lld (at-Rn-then-Rn=EA)\n";
3462 break;
3463 case BITS2(1,1):
3464 fmt_str = "%sp %s, %s, [%s, #%lld]! (at-EA-then-Rn=EA)\n";
3465 break;
3466 case BITS2(1,0):
3467 fmt_str = "%sp %s, %s, [%s, #%lld] (at-Rn)\n";
3468 break;
3469 default:
3470 vassert(0);
3471 }
3472 DIP(fmt_str, bL == 0 ? "st" : "ld",
3473 nameIRegOrZR(bX == 1, rT1),
3474 nameIRegOrZR(bX == 1, rT2),
3475 nameIReg64orSP(rN), simm7);
3476 return True;
3477 }
3478 }
3479
3480 /* ---------------- LDR (literal, int reg) ---------------- */
3481 /* 31 29 23 4
3482 00 011 000 imm19 Rt LDR Wt, [PC + sxTo64(imm19 << 2)]
3483 01 011 000 imm19 Rt LDR Xt, [PC + sxTo64(imm19 << 2)]
3484 10 011 000 imm19 Rt LDRSW Xt, [PC + sxTo64(imm19 << 2)]
3485 11 011 000 imm19 Rt prefetch [PC + sxTo64(imm19 << 2)]
3486 Just handles the first two cases for now.
3487 */
3488 if (INSN(29,24) == BITS6(0,1,1,0,0,0) && INSN(31,31) == 0) {
3489 UInt imm19 = INSN(23,5);
3490 UInt rT = INSN(4,0);
3491 UInt bX = INSN(30,30);
3492 ULong ea = guest_PC_curr_instr + sx_to_64(imm19 << 2, 21);
3493 if (bX) {
3494 putIReg64orZR(rT, loadLE(Ity_I64, mkU64(ea)));
3495 } else {
3496 putIReg32orZR(rT, loadLE(Ity_I32, mkU64(ea)));
3497 }
3498 DIP("ldr %s, 0x%llx (literal)\n", nameIRegOrZR(bX == 1, rT), ea);
3499 return True;
3500 }
3501
3502 /* -------------- {LD,ST}R (integer register) --------------- */
3503 /* 31 29 20 15 12 11 9 4
3504 | | | | | | | |
3505 11 111000011 Rm option S 10 Rn Rt LDR Xt, [Xn|SP, R<m>{ext/sh}]
3506 10 111000011 Rm option S 10 Rn Rt LDR Wt, [Xn|SP, R<m>{ext/sh}]
3507 01 111000011 Rm option S 10 Rn Rt LDRH Wt, [Xn|SP, R<m>{ext/sh}]
3508 00 111000011 Rm option S 10 Rn Rt LDRB Wt, [Xn|SP, R<m>{ext/sh}]
3509
3510 11 111000001 Rm option S 10 Rn Rt STR Xt, [Xn|SP, R<m>{ext/sh}]
3511 10 111000001 Rm option S 10 Rn Rt STR Wt, [Xn|SP, R<m>{ext/sh}]
3512 01 111000001 Rm option S 10 Rn Rt STRH Wt, [Xn|SP, R<m>{ext/sh}]
3513 00 111000001 Rm option S 10 Rn Rt STRB Wt, [Xn|SP, R<m>{ext/sh}]
3514 */
3515 if (INSN(29,23) == BITS7(1,1,1,0,0,0,0)
3516 && INSN(21,21) == 1 && INSN(11,10) == BITS2(1,0)) {
3517 HChar dis_buf[64];
3518 UInt szLg2 = INSN(31,30);
3519 Bool isLD = INSN(22,22) == 1;
3520 UInt tt = INSN(4,0);
3521 IRTemp ea = gen_indexed_EA(dis_buf, insn, True/*to/from int regs*/);
3522 if (ea != IRTemp_INVALID) {
3523 switch (szLg2) {
3524 case 3: /* 64 bit */
3525 if (isLD) {
3526 putIReg64orZR(tt, loadLE(Ity_I64, mkexpr(ea)));
3527 DIP("ldr %s, %s\n", nameIReg64orZR(tt), dis_buf);
3528 } else {
3529 storeLE(mkexpr(ea), getIReg64orZR(tt));
3530 DIP("str %s, %s\n", nameIReg64orZR(tt), dis_buf);
3531 }
3532 break;
3533 case 2: /* 32 bit */
3534 if (isLD) {
3535 putIReg32orZR(tt, loadLE(Ity_I32, mkexpr(ea)));
3536 DIP("ldr %s, %s\n", nameIReg32orZR(tt), dis_buf);
3537 } else {
3538 storeLE(mkexpr(ea), getIReg32orZR(tt));
3539 DIP("str %s, %s\n", nameIReg32orZR(tt), dis_buf);
3540 }
3541 break;
3542 case 1: /* 16 bit */
3543 if (isLD) {
3544 putIReg64orZR(tt, unop(Iop_16Uto64,
3545 loadLE(Ity_I16, mkexpr(ea))));
3546 DIP("ldruh %s, %s\n", nameIReg32orZR(tt), dis_buf);
3547 } else {
3548 storeLE(mkexpr(ea), unop(Iop_64to16, getIReg64orZR(tt)));
3549 DIP("strh %s, %s\n", nameIReg32orZR(tt), dis_buf);
3550 }
3551 break;
3552 case 0: /* 8 bit */
3553 if (isLD) {
3554 putIReg64orZR(tt, unop(Iop_8Uto64,
3555 loadLE(Ity_I8, mkexpr(ea))));
3556 DIP("ldrub %s, %s\n", nameIReg32orZR(tt), dis_buf);
3557 } else {
3558 storeLE(mkexpr(ea), unop(Iop_64to8, getIReg64orZR(tt)));
3559 DIP("strb %s, %s\n", nameIReg32orZR(tt), dis_buf);
3560 }
3561 break;
3562 default:
3563 vassert(0);
3564 }
3565 return True;
3566 }
3567 }
3568
3569 /* -------------- LDRS{B,H,W} (uimm12) -------------- */
3570 /* 31 29 26 23 21 9 4
3571 10 111 001 10 imm12 n t LDRSW Xt, [Xn|SP, #pimm12 * 4]
3572 01 111 001 1x imm12 n t LDRSH Rt, [Xn|SP, #pimm12 * 2]
3573 00 111 001 1x imm12 n t LDRSB Rt, [Xn|SP, #pimm12 * 1]
3574 where
3575 Rt is Wt when x==1, Xt when x==0
3576 */
3577 if (INSN(29,23) == BITS7(1,1,1,0,0,1,1)) {
3578 /* Further checks on bits 31:30 and 22 */
3579 Bool valid = False;
3580 switch ((INSN(31,30) << 1) | INSN(22,22)) {
3581 case BITS3(1,0,0):
3582 case BITS3(0,1,0): case BITS3(0,1,1):
3583 case BITS3(0,0,0): case BITS3(0,0,1):
3584 valid = True;
3585 break;
3586 }
3587 if (valid) {
3588 UInt szLg2 = INSN(31,30);
3589 UInt bitX = INSN(22,22);
3590 UInt imm12 = INSN(21,10);
3591 UInt nn = INSN(9,5);
3592 UInt tt = INSN(4,0);
3593 UInt szB = 1 << szLg2;
3594 IRExpr* ea = binop(Iop_Add64,
3595 getIReg64orSP(nn), mkU64(imm12 * szB));
3596 switch (szB) {
3597 case 4:
3598 vassert(bitX == 0);
3599 putIReg64orZR(tt, unop(Iop_32Sto64, loadLE(Ity_I32, ea)));
3600 DIP("ldrsw %s, [%s, #%u]\n", nameIReg64orZR(tt),
3601 nameIReg64orSP(nn), imm12 * szB);
3602 break;
3603 case 2:
3604 if (bitX == 1) {
3605 putIReg32orZR(tt, unop(Iop_16Sto32, loadLE(Ity_I16, ea)));
3606 } else {
3607 putIReg64orZR(tt, unop(Iop_16Sto64, loadLE(Ity_I16, ea)));
3608 }
3609 DIP("ldrsh %s, [%s, #%u]\n",
3610 nameIRegOrZR(bitX == 0, tt),
3611 nameIReg64orSP(nn), imm12 * szB);
3612 break;
3613 case 1:
3614 if (bitX == 1) {
3615 putIReg32orZR(tt, unop(Iop_8Sto32, loadLE(Ity_I8, ea)));
3616 } else {
3617 putIReg64orZR(tt, unop(Iop_8Sto64, loadLE(Ity_I8, ea)));
3618 }
3619 DIP("ldrsb %s, [%s, #%u]\n",
3620 nameIRegOrZR(bitX == 0, tt),
3621 nameIReg64orSP(nn), imm12 * szB);
3622 break;
3623 default:
3624 vassert(0);
3625 }
3626 return True;
3627 }
3628 /* else fall through */
3629 }
3630
3631 /* -------------- LDRS{B,H,W} (simm9, upd) -------------- */
3632 /* (at-Rn-then-Rn=EA)
3633 31 29 23 21 20 11 9 4
3634 00 111 000 1x 0 imm9 01 n t LDRSB Rt, [Xn|SP], #simm9
3635 01 111 000 1x 0 imm9 01 n t LDRSH Rt, [Xn|SP], #simm9
3636 10 111 000 10 0 imm9 01 n t LDRSW Xt, [Xn|SP], #simm9
3637
3638 (at-EA-then-Rn=EA)
3639 00 111 000 1x 0 imm9 11 n t LDRSB Rt, [Xn|SP, #simm9]!
3640 01 111 000 1x 0 imm9 11 n t LDRSH Rt, [Xn|SP, #simm9]!
3641 10 111 000 10 0 imm9 11 n t LDRSW Xt, [Xn|SP, #simm9]!
3642 where
3643 Rt is Wt when x==1, Xt when x==0
3644 transfer-at-Rn when [11]==0, at EA when [11]==1
3645 */
3646 if (INSN(29,23) == BITS7(1,1,1,0,0,0,1)
3647 && INSN(21,21) == 0 && INSN(10,10) == 1) {
3648 /* Further checks on bits 31:30 and 22 */
3649 Bool valid = False;
3650 switch ((INSN(31,30) << 1) | INSN(22,22)) {
3651 case BITS3(1,0,0): // LDRSW Xt
3652 case BITS3(0,1,0): case BITS3(0,1,1): // LDRSH Xt, Wt
3653 case BITS3(0,0,0): case BITS3(0,0,1): // LDRSB Xt, Wt
3654 valid = True;
3655 break;
3656 }
3657 if (valid) {
3658 UInt szLg2 = INSN(31,30);
3659 UInt imm9 = INSN(20,12);
3660 Bool atRN = INSN(11,11) == 0;
3661 UInt nn = INSN(9,5);
3662 UInt tt = INSN(4,0);
3663 IRTemp tRN = newTemp(Ity_I64);
3664 IRTemp tEA = newTemp(Ity_I64);
3665 IRTemp tTA = IRTemp_INVALID;
3666 ULong simm9 = sx_to_64(imm9, 9);
3667 Bool is64 = INSN(22,22) == 0;
3668 assign(tRN, getIReg64orSP(nn));
3669 assign(tEA, binop(Iop_Add64, mkexpr(tRN), mkU64(simm9)));
3670 tTA = atRN ? tRN : tEA;
3671 HChar ch = '?';
3672 /* There are 5 cases:
3673 byte load, SX to 64
3674 byte load, SX to 32, ZX to 64
3675 halfword load, SX to 64
3676 halfword load, SX to 32, ZX to 64
3677 word load, SX to 64
3678 The ifs below handle them in the listed order.
3679 */
3680 if (szLg2 == 0) {
3681 ch = 'b';
3682 if (is64) {
3683 putIReg64orZR(tt, unop(Iop_8Sto64,
3684 loadLE(Ity_I8, mkexpr(tTA))));
3685 } else {
3686 putIReg32orZR(tt, unop(Iop_8Sto32,
3687 loadLE(Ity_I8, mkexpr(tTA))));
3688 }
3689 }
3690 else if (szLg2 == 1) {
3691 ch = 'h';
3692 if (is64) {
3693 putIReg64orZR(tt, unop(Iop_16Sto64,
3694 loadLE(Ity_I16, mkexpr(tTA))));
3695 } else {
3696 putIReg32orZR(tt, unop(Iop_16Sto32,
3697 loadLE(Ity_I16, mkexpr(tTA))));
3698 }
3699 }
3700 else if (szLg2 == 2 && is64) {
3701 ch = 'w';
3702 putIReg64orZR(tt, unop(Iop_32Sto64,
3703 loadLE(Ity_I32, mkexpr(tTA))));
3704 }
3705 else {
3706 vassert(0);
3707 }
3708 putIReg64orSP(nn, mkexpr(tEA));
3709 DIP(atRN ? "ldrs%c %s, [%s], #%lld\n" : "ldrs%c %s, [%s, #%lld]!",
3710 ch, nameIRegOrZR(is64, tt), nameIReg64orSP(nn), simm9);
3711 return True;
3712 }
3713 /* else fall through */
3714 }
3715
3716 /* -------------- LDRS{B,H,W} (simm9, noUpd) -------------- */
3717 /* 31 29 23 21 20 11 9 4
3718 00 111 000 1x 0 imm9 00 n t LDURSB Rt, [Xn|SP, #simm9]
3719 01 111 000 1x 0 imm9 00 n t LDURSH Rt, [Xn|SP, #simm9]
3720 10 111 000 10 0 imm9 00 n t LDURSW Xt, [Xn|SP, #simm9]
3721 where
3722 Rt is Wt when x==1, Xt when x==0
3723 */
3724 if (INSN(29,23) == BITS7(1,1,1,0,0,0,1)
3725 && INSN(21,21) == 0 && INSN(11,10) == BITS2(0,0)) {
3726 /* Further checks on bits 31:30 and 22 */
3727 Bool valid = False;
3728 switch ((INSN(31,30) << 1) | INSN(22,22)) {
3729 case BITS3(1,0,0): // LDURSW Xt
3730 case BITS3(0,1,0): case BITS3(0,1,1): // LDURSH Xt, Wt
3731 case BITS3(0,0,0): case BITS3(0,0,1): // LDURSB Xt, Wt
3732 valid = True;
3733 break;
3734 }
3735 if (valid) {
3736 UInt szLg2 = INSN(31,30);
3737 UInt imm9 = INSN(20,12);
3738 UInt nn = INSN(9,5);
3739 UInt tt = INSN(4,0);
3740 IRTemp tRN = newTemp(Ity_I64);
3741 IRTemp tEA = newTemp(Ity_I64);
3742 ULong simm9 = sx_to_64(imm9, 9);
3743 Bool is64 = INSN(22,22) == 0;
3744 assign(tRN, getIReg64orSP(nn));
3745 assign(tEA, binop(Iop_Add64, mkexpr(tRN), mkU64(simm9)));
3746 HChar ch = '?';
3747 /* There are 5 cases:
3748 byte load, SX to 64
3749 byte load, SX to 32, ZX to 64
3750 halfword load, SX to 64
3751 halfword load, SX to 32, ZX to 64
3752 word load, SX to 64
3753 The ifs below handle them in the listed order.
3754 */
3755 if (szLg2 == 0) {
3756 ch = 'b';
3757 if (is64) {
3758 putIReg64orZR(tt, unop(Iop_8Sto64,
3759 loadLE(Ity_I8, mkexpr(tEA))));
3760 } else {
3761 putIReg32orZR(tt, unop(Iop_8Sto32,
3762 loadLE(Ity_I8, mkexpr(tEA))));
3763 }
3764 }
3765 else if (szLg2 == 1) {
3766 ch = 'h';
3767 if (is64) {
3768 putIReg64orZR(tt, unop(Iop_16Sto64,
3769 loadLE(Ity_I16, mkexpr(tEA))));
3770 } else {
3771 putIReg32orZR(tt, unop(Iop_16Sto32,
3772 loadLE(Ity_I16, mkexpr(tEA))));
3773 }
3774 }
3775 else if (szLg2 == 2 && is64) {
3776 ch = 'w';
3777 putIReg64orZR(tt, unop(Iop_32Sto64,
3778 loadLE(Ity_I32, mkexpr(tEA))));
3779 }
3780 else {
3781 vassert(0);
3782 }
3783 DIP("ldurs%c %s, [%s, #%lld]",
3784 ch, nameIRegOrZR(is64, tt), nameIReg64orSP(nn), simm9);
3785 return True;
3786 }
3787 /* else fall through */
3788 }
3789
3790 /* -------- LDP,STP (immediate, simm7) (FP&VEC) -------- */
3791 /* L==1 => mm==LD
3792 L==0 => mm==ST
3793 sz==00 => 32 bit (S) transfers
3794 sz==01 => 64 bit (D) transfers
3795 sz==10 => 128 bit (Q) transfers
3796 sz==11 isn't allowed
3797 simm7 is scaled by the (single-register) transfer size
3798
3799 31 29 22 21 14 9 4
3800 sz 101 1001 L imm7 t2 n t1 mmP SDQt1, SDQt2, [Xn|SP], #imm
3801 (at-Rn-then-Rn=EA)
3802
3803 sz 101 1011 L imm7 t2 n t1 mmP SDQt1, SDQt2, [Xn|SP, #imm]!
3804 (at-EA-then-Rn=EA)
3805
3806 sz 101 1010 L imm7 t2 n t1 mmP SDQt1, SDQt2, [Xn|SP, #imm]
3807 (at-EA)
3808 */
3809
3810 UInt insn_29_23 = INSN(29,23);
3811 if (insn_29_23 == BITS7(1,0,1,1,0,0,1)
3812 || insn_29_23 == BITS7(1,0,1,1,0,1,1)
3813 || insn_29_23 == BITS7(1,0,1,1,0,1,0)) {
3814 UInt szSlg2 = INSN(31,30); // log2 of the xfer size in 32-bit units
3815 Bool isLD = INSN(22,22) == 1;
3816 Bool wBack = INSN(23,23) == 1;
3817 Long simm7 = (Long)sx_to_64(INSN(21,15), 7);
3818 UInt tt2 = INSN(14,10);
3819 UInt nn = INSN(9,5);
3820 UInt tt1 = INSN(4,0);
3821 if (szSlg2 == BITS2(1,1) || (isLD && tt1 == tt2)) {
3822 /* undecodable; fall through */
3823 } else {
3824 if (nn == 31) { /* FIXME generate stack alignment check */ }
3825
3826 // Compute the transfer address TA and the writeback address WA.
3827 UInt szB = 4 << szSlg2; /* szB is the per-register size */
3828 IRTemp tRN = newTemp(Ity_I64);
3829 assign(tRN, getIReg64orSP(nn));
3830 IRTemp tEA = newTemp(Ity_I64);
3831 simm7 = szB * simm7;
3832 assign(tEA, binop(Iop_Add64, mkexpr(tRN), mkU64(simm7)));
3833
3834 IRTemp tTA = newTemp(Ity_I64);
3835 IRTemp tWA = newTemp(Ity_I64);
3836 switch (INSN(24,23)) {
3837 case BITS2(0,1):
3838 assign(tTA, mkexpr(tRN)); assign(tWA, mkexpr(tEA)); break;
3839 case BITS2(1,1):
3840 assign(tTA, mkexpr(tEA)); assign(tWA, mkexpr(tEA)); break;
3841 case BITS2(1,0):
3842 assign(tTA, mkexpr(tEA)); /* tWA is unused */ break;
3843 default:
3844 vassert(0); /* NOTREACHED */
3845 }
3846
3847 IRType ty = Ity_INVALID;
3848 switch (szB) {
3849 case 4: ty = Ity_F32; break;
3850 case 8: ty = Ity_F64; break;
3851 case 16: ty = Ity_V128; break;
3852 default: vassert(0);
3853 }
3854
sewardje0bff8b2014-03-09 09:40:23 +00003855 /* Normally rN would be updated after the transfer. However, in
sewardj19551432014-05-07 09:20:11 +00003856 the special cases typifed by
sewardje0bff8b2014-03-09 09:40:23 +00003857 stp q0, q1, [sp,#-512]!
sewardj19551432014-05-07 09:20:11 +00003858 stp d0, d1, [sp,#-512]!
3859 stp s0, s1, [sp,#-512]!
sewardje0bff8b2014-03-09 09:40:23 +00003860 it is necessary to update SP before the transfer, (1)
3861 because Memcheck will otherwise complain about a write
3862 below the stack pointer, and (2) because the segfault
3863 stack extension mechanism will otherwise extend the stack
3864 only down to SP before the instruction, which might not be
3865 far enough, if the -512 bit takes the actual access
3866 address to the next page.
3867 */
3868 Bool earlyWBack
sewardj19551432014-05-07 09:20:11 +00003869 = wBack && simm7 < 0
sewardje0bff8b2014-03-09 09:40:23 +00003870 && INSN(24,23) == BITS2(1,1) && nn == 31 && !isLD;
3871
3872 if (wBack && earlyWBack)
3873 putIReg64orSP(nn, mkexpr(tEA));
3874
sewardjbbcf1882014-01-12 12:49:10 +00003875 if (isLD) {
sewardj5ba41302014-03-03 08:42:16 +00003876 if (szB < 16) {
3877 putQReg128(tt1, mkV128(0x0000));
3878 }
sewardj606c4ba2014-01-26 19:11:14 +00003879 putQRegLO(tt1,
3880 loadLE(ty, binop(Iop_Add64, mkexpr(tTA), mkU64(0))));
sewardj5ba41302014-03-03 08:42:16 +00003881 if (szB < 16) {
3882 putQReg128(tt2, mkV128(0x0000));
3883 }
sewardj606c4ba2014-01-26 19:11:14 +00003884 putQRegLO(tt2,
3885 loadLE(ty, binop(Iop_Add64, mkexpr(tTA), mkU64(szB))));
sewardjbbcf1882014-01-12 12:49:10 +00003886 } else {
3887 storeLE(binop(Iop_Add64, mkexpr(tTA), mkU64(0)),
sewardj606c4ba2014-01-26 19:11:14 +00003888 getQRegLO(tt1, ty));
sewardjbbcf1882014-01-12 12:49:10 +00003889 storeLE(binop(Iop_Add64, mkexpr(tTA), mkU64(szB)),
sewardj606c4ba2014-01-26 19:11:14 +00003890 getQRegLO(tt2, ty));
sewardjbbcf1882014-01-12 12:49:10 +00003891 }
3892
sewardje0bff8b2014-03-09 09:40:23 +00003893 if (wBack && !earlyWBack)
sewardjbbcf1882014-01-12 12:49:10 +00003894 putIReg64orSP(nn, mkexpr(tEA));
3895
3896 const HChar* fmt_str = NULL;
3897 switch (INSN(24,23)) {
3898 case BITS2(0,1):
3899 fmt_str = "%sp %s, %s, [%s], #%lld (at-Rn-then-Rn=EA)\n";
3900 break;
3901 case BITS2(1,1):
3902 fmt_str = "%sp %s, %s, [%s, #%lld]! (at-EA-then-Rn=EA)\n";
3903 break;
3904 case BITS2(1,0):
3905 fmt_str = "%sp %s, %s, [%s, #%lld] (at-Rn)\n";
3906 break;
3907 default:
3908 vassert(0);
3909 }
3910 DIP(fmt_str, isLD ? "ld" : "st",
sewardj606c4ba2014-01-26 19:11:14 +00003911 nameQRegLO(tt1, ty), nameQRegLO(tt2, ty),
sewardjbbcf1882014-01-12 12:49:10 +00003912 nameIReg64orSP(nn), simm7);
3913 return True;
3914 }
3915 }
3916
3917 /* -------------- {LD,ST}R (vector register) --------------- */
3918 /* 31 29 23 20 15 12 11 9 4
3919 | | | | | | | | |
3920 00 111100 011 Rm option S 10 Rn Rt LDR Bt, [Xn|SP, R<m>{ext/sh}]
3921 01 111100 011 Rm option S 10 Rn Rt LDR Ht, [Xn|SP, R<m>{ext/sh}]
3922 10 111100 011 Rm option S 10 Rn Rt LDR St, [Xn|SP, R<m>{ext/sh}]
3923 11 111100 011 Rm option S 10 Rn Rt LDR Dt, [Xn|SP, R<m>{ext/sh}]
3924 00 111100 111 Rm option S 10 Rn Rt LDR Qt, [Xn|SP, R<m>{ext/sh}]
3925
3926 00 111100 001 Rm option S 10 Rn Rt STR Bt, [Xn|SP, R<m>{ext/sh}]
3927 01 111100 001 Rm option S 10 Rn Rt STR Ht, [Xn|SP, R<m>{ext/sh}]
3928 10 111100 001 Rm option S 10 Rn Rt STR St, [Xn|SP, R<m>{ext/sh}]
3929 11 111100 001 Rm option S 10 Rn Rt STR Dt, [Xn|SP, R<m>{ext/sh}]
3930 00 111100 101 Rm option S 10 Rn Rt STR Qt, [Xn|SP, R<m>{ext/sh}]
3931 */
3932 if (INSN(29,24) == BITS6(1,1,1,1,0,0)
3933 && INSN(21,21) == 1 && INSN(11,10) == BITS2(1,0)) {
3934 HChar dis_buf[64];
3935 UInt szLg2 = (INSN(23,23) << 2) | INSN(31,30);
3936 Bool isLD = INSN(22,22) == 1;
3937 UInt tt = INSN(4,0);
3938 if (szLg2 >= 4) goto after_LDR_STR_vector_register;
3939 IRTemp ea = gen_indexed_EA(dis_buf, insn, False/*to/from vec regs*/);
3940 if (ea == IRTemp_INVALID) goto after_LDR_STR_vector_register;
3941 switch (szLg2) {
3942 case 0: /* 8 bit */
3943 if (isLD) {
3944 putQReg128(tt, mkV128(0x0000));
sewardj606c4ba2014-01-26 19:11:14 +00003945 putQRegLO(tt, loadLE(Ity_I8, mkexpr(ea)));
3946 DIP("ldr %s, %s\n", nameQRegLO(tt, Ity_I8), dis_buf);
sewardjbbcf1882014-01-12 12:49:10 +00003947 } else {
3948 vassert(0); //ATC
sewardj606c4ba2014-01-26 19:11:14 +00003949 storeLE(mkexpr(ea), getQRegLO(tt, Ity_I8));
3950 DIP("str %s, %s\n", nameQRegLO(tt, Ity_I8), dis_buf);
sewardjbbcf1882014-01-12 12:49:10 +00003951 }
3952 break;
3953 case 1:
3954 if (isLD) {
3955 putQReg128(tt, mkV128(0x0000));
sewardj606c4ba2014-01-26 19:11:14 +00003956 putQRegLO(tt, loadLE(Ity_I16, mkexpr(ea)));
3957 DIP("ldr %s, %s\n", nameQRegLO(tt, Ity_I16), dis_buf);
sewardjbbcf1882014-01-12 12:49:10 +00003958 } else {
3959 vassert(0); //ATC
sewardj606c4ba2014-01-26 19:11:14 +00003960 storeLE(mkexpr(ea), getQRegLO(tt, Ity_I16));
3961 DIP("str %s, %s\n", nameQRegLO(tt, Ity_I16), dis_buf);
sewardjbbcf1882014-01-12 12:49:10 +00003962 }
3963 break;
3964 case 2: /* 32 bit */
3965 if (isLD) {
3966 putQReg128(tt, mkV128(0x0000));
sewardj606c4ba2014-01-26 19:11:14 +00003967 putQRegLO(tt, loadLE(Ity_I32, mkexpr(ea)));
3968 DIP("ldr %s, %s\n", nameQRegLO(tt, Ity_I32), dis_buf);
sewardjbbcf1882014-01-12 12:49:10 +00003969 } else {
sewardj606c4ba2014-01-26 19:11:14 +00003970 storeLE(mkexpr(ea), getQRegLO(tt, Ity_I32));
3971 DIP("str %s, %s\n", nameQRegLO(tt, Ity_I32), dis_buf);
sewardjbbcf1882014-01-12 12:49:10 +00003972 }
3973 break;
3974 case 3: /* 64 bit */
3975 if (isLD) {
3976 putQReg128(tt, mkV128(0x0000));
sewardj606c4ba2014-01-26 19:11:14 +00003977 putQRegLO(tt, loadLE(Ity_I64, mkexpr(ea)));
3978 DIP("ldr %s, %s\n", nameQRegLO(tt, Ity_I64), dis_buf);
sewardjbbcf1882014-01-12 12:49:10 +00003979 } else {
sewardj606c4ba2014-01-26 19:11:14 +00003980 storeLE(mkexpr(ea), getQRegLO(tt, Ity_I64));
3981 DIP("str %s, %s\n", nameQRegLO(tt, Ity_I64), dis_buf);
sewardjbbcf1882014-01-12 12:49:10 +00003982 }
3983 break;
3984 case 4: return False; //ATC
3985 default: vassert(0);
3986 }
3987 return True;
3988 }
3989 after_LDR_STR_vector_register:
3990
3991 /* ---------- LDRS{B,H,W} (integer register, SX) ---------- */
3992 /* 31 29 22 20 15 12 11 9 4
3993 | | | | | | | | |
3994 10 1110001 01 Rm opt S 10 Rn Rt LDRSW Xt, [Xn|SP, R<m>{ext/sh}]
3995
3996 01 1110001 01 Rm opt S 10 Rn Rt LDRSH Xt, [Xn|SP, R<m>{ext/sh}]
3997 01 1110001 11 Rm opt S 10 Rn Rt LDRSH Wt, [Xn|SP, R<m>{ext/sh}]
3998
3999 00 1110001 01 Rm opt S 10 Rn Rt LDRSB Xt, [Xn|SP, R<m>{ext/sh}]
4000 00 1110001 11 Rm opt S 10 Rn Rt LDRSB Wt, [Xn|SP, R<m>{ext/sh}]
4001 */
4002 if (INSN(29,23) == BITS7(1,1,1,0,0,0,1)
4003 && INSN(21,21) == 1 && INSN(11,10) == BITS2(1,0)) {
4004 HChar dis_buf[64];
4005 UInt szLg2 = INSN(31,30);
4006 Bool sxTo64 = INSN(22,22) == 0; // else sx to 32 and zx to 64
4007 UInt tt = INSN(4,0);
4008 if (szLg2 == 3) goto after_LDRS_integer_register;
4009 IRTemp ea = gen_indexed_EA(dis_buf, insn, True/*to/from int regs*/);
4010 if (ea == IRTemp_INVALID) goto after_LDRS_integer_register;
4011 /* Enumerate the 5 variants explicitly. */
4012 if (szLg2 == 2/*32 bit*/ && sxTo64) {
4013 putIReg64orZR(tt, unop(Iop_32Sto64, loadLE(Ity_I32, mkexpr(ea))));
4014 DIP("ldrsw %s, %s\n", nameIReg64orZR(tt), dis_buf);
4015 return True;
4016 }
4017 else
4018 if (szLg2 == 1/*16 bit*/) {
4019 if (sxTo64) {
4020 putIReg64orZR(tt, unop(Iop_16Sto64, loadLE(Ity_I16, mkexpr(ea))));
4021 DIP("ldrsh %s, %s\n", nameIReg64orZR(tt), dis_buf);
4022 } else {
4023 putIReg32orZR(tt, unop(Iop_16Sto32, loadLE(Ity_I16, mkexpr(ea))));
4024 DIP("ldrsh %s, %s\n", nameIReg32orZR(tt), dis_buf);
4025 }
4026 return True;
4027 }
4028 else
4029 if (szLg2 == 0/*8 bit*/) {
4030 if (sxTo64) {
4031 putIReg64orZR(tt, unop(Iop_8Sto64, loadLE(Ity_I8, mkexpr(ea))));
4032 DIP("ldrsb %s, %s\n", nameIReg64orZR(tt), dis_buf);
4033 } else {
4034 putIReg32orZR(tt, unop(Iop_8Sto32, loadLE(Ity_I8, mkexpr(ea))));
4035 DIP("ldrsb %s, %s\n", nameIReg32orZR(tt), dis_buf);
4036 }
4037 return True;
4038 }
4039 /* else it's an invalid combination */
4040 }
4041 after_LDRS_integer_register:
4042
4043 /* -------- LDR/STR (immediate, SIMD&FP, unsigned offset) -------- */
4044 /* This is the Unsigned offset variant only. The Post-Index and
4045 Pre-Index variants are below.
4046
4047 31 29 23 21 9 4
4048 00 111 101 01 imm12 n t LDR Bt, [Xn|SP + imm12 * 1]
4049 01 111 101 01 imm12 n t LDR Ht, [Xn|SP + imm12 * 2]
4050 10 111 101 01 imm12 n t LDR St, [Xn|SP + imm12 * 4]
4051 11 111 101 01 imm12 n t LDR Dt, [Xn|SP + imm12 * 8]
4052 00 111 101 11 imm12 n t LDR Qt, [Xn|SP + imm12 * 16]
4053
4054 00 111 101 00 imm12 n t STR Bt, [Xn|SP + imm12 * 1]
4055 01 111 101 00 imm12 n t STR Ht, [Xn|SP + imm12 * 2]
4056 10 111 101 00 imm12 n t STR St, [Xn|SP + imm12 * 4]
4057 11 111 101 00 imm12 n t STR Dt, [Xn|SP + imm12 * 8]
4058 00 111 101 10 imm12 n t STR Qt, [Xn|SP + imm12 * 16]
4059 */
4060 if (INSN(29,24) == BITS6(1,1,1,1,0,1)
4061 && ((INSN(23,23) << 2) | INSN(31,30)) <= 4) {
4062 UInt szLg2 = (INSN(23,23) << 2) | INSN(31,30);
4063 Bool isLD = INSN(22,22) == 1;
4064 UInt pimm12 = INSN(21,10) << szLg2;
4065 UInt nn = INSN(9,5);
4066 UInt tt = INSN(4,0);
4067 IRTemp tEA = newTemp(Ity_I64);
4068 IRType ty = preferredVectorSubTypeFromSize(1 << szLg2);
4069 assign(tEA, binop(Iop_Add64, getIReg64orSP(nn), mkU64(pimm12)));
4070 if (isLD) {
4071 if (szLg2 < 4) {
4072 putQReg128(tt, mkV128(0x0000));
4073 }
sewardj606c4ba2014-01-26 19:11:14 +00004074 putQRegLO(tt, loadLE(ty, mkexpr(tEA)));
sewardjbbcf1882014-01-12 12:49:10 +00004075 } else {
sewardj606c4ba2014-01-26 19:11:14 +00004076 storeLE(mkexpr(tEA), getQRegLO(tt, ty));
sewardjbbcf1882014-01-12 12:49:10 +00004077 }
4078 DIP("%s %s, [%s, #%u]\n",
4079 isLD ? "ldr" : "str",
sewardj606c4ba2014-01-26 19:11:14 +00004080 nameQRegLO(tt, ty), nameIReg64orSP(nn), pimm12);
sewardjbbcf1882014-01-12 12:49:10 +00004081 return True;
4082 }
4083
4084 /* -------- LDR/STR (immediate, SIMD&FP, pre/post index) -------- */
4085 /* These are the Post-Index and Pre-Index variants.
4086
4087 31 29 23 20 11 9 4
4088 (at-Rn-then-Rn=EA)
4089 00 111 100 01 0 imm9 01 n t LDR Bt, [Xn|SP], #simm
4090 01 111 100 01 0 imm9 01 n t LDR Ht, [Xn|SP], #simm
4091 10 111 100 01 0 imm9 01 n t LDR St, [Xn|SP], #simm
4092 11 111 100 01 0 imm9 01 n t LDR Dt, [Xn|SP], #simm
4093 00 111 100 11 0 imm9 01 n t LDR Qt, [Xn|SP], #simm
4094
4095 (at-EA-then-Rn=EA)
4096 00 111 100 01 0 imm9 11 n t LDR Bt, [Xn|SP, #simm]!
4097 01 111 100 01 0 imm9 11 n t LDR Ht, [Xn|SP, #simm]!
4098 10 111 100 01 0 imm9 11 n t LDR St, [Xn|SP, #simm]!
4099 11 111 100 01 0 imm9 11 n t LDR Dt, [Xn|SP, #simm]!
4100 00 111 100 11 0 imm9 11 n t LDR Qt, [Xn|SP, #simm]!
4101
4102 Stores are the same except with bit 22 set to 0.
4103 */
4104 if (INSN(29,24) == BITS6(1,1,1,1,0,0)
4105 && ((INSN(23,23) << 2) | INSN(31,30)) <= 4
4106 && INSN(21,21) == 0 && INSN(10,10) == 1) {
4107 UInt szLg2 = (INSN(23,23) << 2) | INSN(31,30);
4108 Bool isLD = INSN(22,22) == 1;
4109 UInt imm9 = INSN(20,12);
4110 Bool atRN = INSN(11,11) == 0;
4111 UInt nn = INSN(9,5);
4112 UInt tt = INSN(4,0);
4113 IRTemp tRN = newTemp(Ity_I64);
4114 IRTemp tEA = newTemp(Ity_I64);
4115 IRTemp tTA = IRTemp_INVALID;
4116 IRType ty = preferredVectorSubTypeFromSize(1 << szLg2);
4117 ULong simm9 = sx_to_64(imm9, 9);
4118 assign(tRN, getIReg64orSP(nn));
4119 assign(tEA, binop(Iop_Add64, mkexpr(tRN), mkU64(simm9)));
4120 tTA = atRN ? tRN : tEA;
4121 if (isLD) {
4122 if (szLg2 < 4) {
4123 putQReg128(tt, mkV128(0x0000));
4124 }
sewardj606c4ba2014-01-26 19:11:14 +00004125 putQRegLO(tt, loadLE(ty, mkexpr(tTA)));
sewardjbbcf1882014-01-12 12:49:10 +00004126 } else {
sewardj606c4ba2014-01-26 19:11:14 +00004127 storeLE(mkexpr(tTA), getQRegLO(tt, ty));
sewardjbbcf1882014-01-12 12:49:10 +00004128 }
4129 putIReg64orSP(nn, mkexpr(tEA));
4130 DIP(atRN ? "%s %s, [%s], #%lld\n" : "%s %s, [%s, #%lld]!\n",
4131 isLD ? "ldr" : "str",
sewardj606c4ba2014-01-26 19:11:14 +00004132 nameQRegLO(tt, ty), nameIReg64orSP(nn), simm9);
sewardjbbcf1882014-01-12 12:49:10 +00004133 return True;
4134 }
4135
4136 /* -------- LDUR/STUR (unscaled offset, SIMD&FP) -------- */
4137 /* 31 29 23 20 11 9 4
4138 00 111 100 01 0 imm9 00 n t LDR Bt, [Xn|SP, #simm]
4139 01 111 100 01 0 imm9 00 n t LDR Ht, [Xn|SP, #simm]
4140 10 111 100 01 0 imm9 00 n t LDR St, [Xn|SP, #simm]
4141 11 111 100 01 0 imm9 00 n t LDR Dt, [Xn|SP, #simm]
4142 00 111 100 11 0 imm9 00 n t LDR Qt, [Xn|SP, #simm]
4143
4144 00 111 100 00 0 imm9 00 n t STR Bt, [Xn|SP, #simm]
4145 01 111 100 00 0 imm9 00 n t STR Ht, [Xn|SP, #simm]
4146 10 111 100 00 0 imm9 00 n t STR St, [Xn|SP, #simm]
4147 11 111 100 00 0 imm9 00 n t STR Dt, [Xn|SP, #simm]
4148 00 111 100 10 0 imm9 00 n t STR Qt, [Xn|SP, #simm]
4149 */
4150 if (INSN(29,24) == BITS6(1,1,1,1,0,0)
4151 && ((INSN(23,23) << 2) | INSN(31,30)) <= 4
4152 && INSN(21,21) == 0 && INSN(11,10) == BITS2(0,0)) {
4153 UInt szLg2 = (INSN(23,23) << 2) | INSN(31,30);
4154 Bool isLD = INSN(22,22) == 1;
4155 UInt imm9 = INSN(20,12);
4156 UInt nn = INSN(9,5);
4157 UInt tt = INSN(4,0);
4158 ULong simm9 = sx_to_64(imm9, 9);
4159 IRTemp tEA = newTemp(Ity_I64);
4160 IRType ty = preferredVectorSubTypeFromSize(1 << szLg2);
4161 assign(tEA, binop(Iop_Add64, getIReg64orSP(nn), mkU64(simm9)));
4162 if (isLD) {
sewardj606c4ba2014-01-26 19:11:14 +00004163 if (szLg2 < 4) {
4164 putQReg128(tt, mkV128(0x0000));
4165 }
4166 putQRegLO(tt, loadLE(ty, mkexpr(tEA)));
sewardjbbcf1882014-01-12 12:49:10 +00004167 } else {
sewardj606c4ba2014-01-26 19:11:14 +00004168 storeLE(mkexpr(tEA), getQRegLO(tt, ty));
sewardjbbcf1882014-01-12 12:49:10 +00004169 }
4170 DIP("%s %s, [%s, #%lld]\n",
4171 isLD ? "ldur" : "stur",
sewardj606c4ba2014-01-26 19:11:14 +00004172 nameQRegLO(tt, ty), nameIReg64orSP(nn), (Long)simm9);
sewardjbbcf1882014-01-12 12:49:10 +00004173 return True;
4174 }
4175
4176 /* ---------------- LDR (literal, SIMD&FP) ---------------- */
4177 /* 31 29 23 4
4178 00 011 100 imm19 t LDR St, [PC + sxTo64(imm19 << 2)]
4179 01 011 100 imm19 t LDR Dt, [PC + sxTo64(imm19 << 2)]
4180 10 011 100 imm19 t LDR Qt, [PC + sxTo64(imm19 << 2)]
4181 */
4182 if (INSN(29,24) == BITS6(0,1,1,1,0,0) && INSN(31,30) < BITS2(1,1)) {
4183 UInt szB = 4 << INSN(31,30);
4184 UInt imm19 = INSN(23,5);
4185 UInt tt = INSN(4,0);
4186 ULong ea = guest_PC_curr_instr + sx_to_64(imm19 << 2, 21);
4187 IRType ty = preferredVectorSubTypeFromSize(szB);
sewardj606c4ba2014-01-26 19:11:14 +00004188 putQReg128(tt, mkV128(0x0000));
4189 putQRegLO(tt, loadLE(ty, mkU64(ea)));
4190 DIP("ldr %s, 0x%llx (literal)\n", nameQRegLO(tt, ty), ea);
sewardjbbcf1882014-01-12 12:49:10 +00004191 return True;
4192 }
4193
sewardj606c4ba2014-01-26 19:11:14 +00004194 /* ---------- LD1/ST1 (single structure, no offset) ---------- */
sewardjbbcf1882014-01-12 12:49:10 +00004195 /* 31 23
sewardj606c4ba2014-01-26 19:11:14 +00004196 0100 1100 0100 0000 0111 11 N T LD1 {vT.2d}, [Xn|SP]
4197 0100 1100 0000 0000 0111 11 N T ST1 {vT.2d}, [Xn|SP]
4198 0100 1100 0100 0000 0111 10 N T LD1 {vT.4s}, [Xn|SP]
4199 0100 1100 0000 0000 0111 10 N T ST1 {vT.4s}, [Xn|SP]
4200 0100 1100 0100 0000 0111 01 N T LD1 {vT.8h}, [Xn|SP]
4201 0100 1100 0000 0000 0111 01 N T ST1 {vT.8h}, [Xn|SP]
sewardjbbcf1882014-01-12 12:49:10 +00004202 0100 1100 0100 0000 0111 00 N T LD1 {vT.16b}, [Xn|SP]
4203 0100 1100 0000 0000 0111 00 N T ST1 {vT.16b}, [Xn|SP]
sewardj606c4ba2014-01-26 19:11:14 +00004204 FIXME does this assume that the host is little endian?
sewardjbbcf1882014-01-12 12:49:10 +00004205 */
sewardj606c4ba2014-01-26 19:11:14 +00004206 if ( (insn & 0xFFFFF000) == 0x4C407000 // LD1 cases
4207 || (insn & 0xFFFFF000) == 0x4C007000 // ST1 cases
sewardjbbcf1882014-01-12 12:49:10 +00004208 ) {
4209 Bool isLD = INSN(22,22) == 1;
4210 UInt rN = INSN(9,5);
4211 UInt vT = INSN(4,0);
4212 IRTemp tEA = newTemp(Ity_I64);
sewardj606c4ba2014-01-26 19:11:14 +00004213 const HChar* names[4] = { "2d", "4s", "8h", "16b" };
4214 const HChar* name = names[INSN(11,10)];
sewardjbbcf1882014-01-12 12:49:10 +00004215 assign(tEA, getIReg64orSP(rN));
4216 if (rN == 31) { /* FIXME generate stack alignment check */ }
4217 if (isLD) {
4218 putQReg128(vT, loadLE(Ity_V128, mkexpr(tEA)));
4219 } else {
4220 storeLE(mkexpr(tEA), getQReg128(vT));
4221 }
4222 DIP("%s {v%u.%s}, [%s]\n", isLD ? "ld1" : "st1",
sewardj606c4ba2014-01-26 19:11:14 +00004223 vT, name, nameIReg64orSP(rN));
sewardjbbcf1882014-01-12 12:49:10 +00004224 return True;
4225 }
4226
sewardj606c4ba2014-01-26 19:11:14 +00004227 /* 31 23
4228 0000 1100 0100 0000 0111 11 N T LD1 {vT.1d}, [Xn|SP]
4229 0000 1100 0000 0000 0111 11 N T ST1 {vT.1d}, [Xn|SP]
4230 0000 1100 0100 0000 0111 10 N T LD1 {vT.2s}, [Xn|SP]
4231 0000 1100 0000 0000 0111 10 N T ST1 {vT.2s}, [Xn|SP]
4232 0000 1100 0100 0000 0111 01 N T LD1 {vT.4h}, [Xn|SP]
4233 0000 1100 0000 0000 0111 01 N T ST1 {vT.4h}, [Xn|SP]
4234 0000 1100 0100 0000 0111 00 N T LD1 {vT.8b}, [Xn|SP]
4235 0000 1100 0000 0000 0111 00 N T ST1 {vT.8b}, [Xn|SP]
4236 FIXME does this assume that the host is little endian?
4237 */
4238 if ( (insn & 0xFFFFF000) == 0x0C407000 // LD1 cases
4239 || (insn & 0xFFFFF000) == 0x0C007000 // ST1 cases
4240 ) {
4241 Bool isLD = INSN(22,22) == 1;
4242 UInt rN = INSN(9,5);
4243 UInt vT = INSN(4,0);
4244 IRTemp tEA = newTemp(Ity_I64);
4245 const HChar* names[4] = { "1d", "2s", "4h", "8b" };
4246 const HChar* name = names[INSN(11,10)];
4247 assign(tEA, getIReg64orSP(rN));
4248 if (rN == 31) { /* FIXME generate stack alignment check */ }
4249 if (isLD) {
4250 putQRegLane(vT, 0, loadLE(Ity_I64, mkexpr(tEA)));
4251 putQRegLane(vT, 1, mkU64(0));
4252 } else {
4253 storeLE(mkexpr(tEA), getQRegLane(vT, 0, Ity_I64));
4254 }
4255 DIP("%s {v%u.%s}, [%s]\n", isLD ? "ld1" : "st1",
4256 vT, name, nameIReg64orSP(rN));
4257 return True;
4258 }
4259
4260 /* ---------- LD1/ST1 (single structure, post index) ---------- */
4261 /* 31 23
sewardj7d009132014-02-20 17:43:38 +00004262 0100 1100 1001 1111 0111 11 N T ST1 {vT.2d}, [xN|SP], #16
4263 0100 1100 1101 1111 0111 11 N T LD1 {vT.2d}, [xN|SP], #16
4264 0100 1100 1001 1111 0111 10 N T ST1 {vT.4s}, [xN|SP], #16
4265 0100 1100 1101 1111 0111 10 N T LD1 {vT.4s}, [xN|SP], #16
4266 0100 1100 1001 1111 0111 01 N T ST1 {vT.8h}, [xN|SP], #16
4267 0100 1100 1101 1111 0111 01 N T LD1 {vT.8h}, [xN|SP], #16
4268 0100 1100 1001 1111 0111 00 N T ST1 {vT.16b}, [xN|SP], #16
sewardjf5b08912014-02-06 12:57:58 +00004269 0100 1100 1101 1111 0111 00 N T LD1 {vT.16b}, [xN|SP], #16
sewardj606c4ba2014-01-26 19:11:14 +00004270 Note that #16 is implied and cannot be any other value.
4271 FIXME does this assume that the host is little endian?
4272 */
sewardj7d009132014-02-20 17:43:38 +00004273 if ( (insn & 0xFFFFF000) == 0x4CDF7000 // LD1 cases
4274 || (insn & 0xFFFFF000) == 0x4C9F7000 // ST1 cases
sewardj606c4ba2014-01-26 19:11:14 +00004275 ) {
4276 Bool isLD = INSN(22,22) == 1;
4277 UInt rN = INSN(9,5);
4278 UInt vT = INSN(4,0);
4279 IRTemp tEA = newTemp(Ity_I64);
4280 const HChar* names[4] = { "2d", "4s", "8h", "16b" };
4281 const HChar* name = names[INSN(11,10)];
4282 assign(tEA, getIReg64orSP(rN));
4283 if (rN == 31) { /* FIXME generate stack alignment check */ }
4284 if (isLD) {
4285 putQReg128(vT, loadLE(Ity_V128, mkexpr(tEA)));
4286 } else {
4287 storeLE(mkexpr(tEA), getQReg128(vT));
4288 }
4289 putIReg64orSP(rN, binop(Iop_Add64, mkexpr(tEA), mkU64(16)));
4290 DIP("%s {v%u.%s}, [%s], #16\n", isLD ? "ld1" : "st1",
4291 vT, name, nameIReg64orSP(rN));
4292 return True;
4293 }
4294
sewardj950ca7a2014-04-03 23:03:32 +00004295 /* 31 23
4296 0000 1100 1001 1111 0111 11 N T ST1 {vT.1d}, [xN|SP], #8
4297 0000 1100 1101 1111 0111 11 N T LD1 {vT.1d}, [xN|SP], #8
sewardj606c4ba2014-01-26 19:11:14 +00004298 0000 1100 1001 1111 0111 10 N T ST1 {vT.2s}, [xN|SP], #8
sewardj950ca7a2014-04-03 23:03:32 +00004299 0000 1100 1101 1111 0111 10 N T LD1 {vT.2s}, [xN|SP], #8
sewardjf5b08912014-02-06 12:57:58 +00004300 0000 1100 1001 1111 0111 01 N T ST1 {vT.4h}, [xN|SP], #8
sewardj950ca7a2014-04-03 23:03:32 +00004301 0000 1100 1101 1111 0111 01 N T LD1 {vT.4h}, [xN|SP], #8
4302 0000 1100 1001 1111 0111 00 N T ST1 {vT.8b}, [xN|SP], #8
4303 0000 1100 1101 1111 0111 00 N T LD1 {vT.8b}, [xN|SP], #8
sewardj606c4ba2014-01-26 19:11:14 +00004304 Note that #8 is implied and cannot be any other value.
4305 FIXME does this assume that the host is little endian?
4306 */
sewardj950ca7a2014-04-03 23:03:32 +00004307 if ( (insn & 0xFFFFF000) == 0x0CDF7000 // LD1 cases
4308 || (insn & 0xFFFFF000) == 0x0C9F7000 // ST1 cases
sewardj606c4ba2014-01-26 19:11:14 +00004309 ) {
sewardj950ca7a2014-04-03 23:03:32 +00004310 Bool isLD = INSN(22,22) == 1;
sewardj606c4ba2014-01-26 19:11:14 +00004311 UInt rN = INSN(9,5);
4312 UInt vT = INSN(4,0);
4313 IRTemp tEA = newTemp(Ity_I64);
4314 const HChar* names[4] = { "1d", "2s", "4h", "8b" };
4315 const HChar* name = names[INSN(11,10)];
4316 assign(tEA, getIReg64orSP(rN));
4317 if (rN == 31) { /* FIXME generate stack alignment check */ }
sewardj950ca7a2014-04-03 23:03:32 +00004318 if (isLD) {
4319 putQRegLane(vT, 0, loadLE(Ity_I64, mkexpr(tEA)));
4320 putQRegLane(vT, 1, mkU64(0));
4321 } else {
4322 storeLE(mkexpr(tEA), getQRegLane(vT, 0, Ity_I64));
4323 }
sewardj606c4ba2014-01-26 19:11:14 +00004324 putIReg64orSP(rN, binop(Iop_Add64, mkexpr(tEA), mkU64(8)));
sewardj950ca7a2014-04-03 23:03:32 +00004325 DIP("%s {v%u.%s}, [%s], #8\n", isLD ? "ld1" : "st1",
4326 vT, name, nameIReg64orSP(rN));
4327 return True;
4328 }
4329
sewardj18bf5172014-06-14 18:05:30 +00004330 /* ---------- LD1R (single structure, replicate) ---------- */
4331 /* 31 29 22 20 15 11 9 4
4332 0q 001 1010 10 00000 110 0 sz n t LD1R Vt.T, [Xn|SP]
4333 0q 001 1011 10 m 110 0 sz n t LD1R Vt.T, [Xn|SP], #sz (m=11111)
4334 , Xm (m!=11111)
4335 */
4336 if (INSN(31,31) == 0 && INSN(29,24) == BITS6(0,0,1,1,0,1)
4337 && INSN(22,21) == BITS2(1,0) && INSN(15,12) == BITS4(1,1,0,0)) {
4338 Bool isQ = INSN(30,30) == 1;
4339 Bool isPX = INSN(23,23) == 1;
4340 UInt mm = INSN(20,16);
4341 UInt sz = INSN(11,10);
4342 UInt nn = INSN(9,5);
4343 UInt tt = INSN(4,0);
4344 IRType ty = integerIRTypeOfSize(1 << sz);
4345 IRTemp tEA = newTemp(Ity_I64);
4346 assign(tEA, getIReg64orSP(nn));
4347 if (nn == 31) { /* FIXME generate stack alignment check */ }
4348 IRTemp loaded = newTemp(ty);
4349 assign(loaded, loadLE(ty, mkexpr(tEA)));
4350 IRTemp dupd = math_DUP_TO_V128(loaded, ty);
4351 putQReg128(tt, isQ ? mkexpr(dupd)
4352 : unop(Iop_ZeroHI64ofV128, mkexpr(dupd)));
4353 const HChar* arr = nameArr_Q_SZ(isQ ? 1 : 0, sz);
4354 /* Deal with the writeback, if any. */
4355 if (!isPX && mm == BITS5(0,0,0,0,0)) {
4356 /* No writeback. */
4357 DIP("ld1r v%u.%s, [%s]\n", tt, arr, nameIReg64orSP(nn));
4358 return True;
4359 }
4360 if (isPX) {
4361 putIReg64orSP(nn, binop(Iop_Add64, mkexpr(tEA),
4362 mm == BITS5(1,1,1,1,1) ? mkU64(1 << sz)
4363 : getIReg64orZR(mm)));
4364 if (mm == BITS5(1,1,1,1,1)) {
4365 DIP("ld1r v%u.%s, [%s], %s\n", tt, arr,
4366 nameIReg64orSP(nn), nameIReg64orZR(mm));
4367 } else {
4368 DIP("ld1r v%u.%s, [%s], #%u\n", tt, arr,
4369 nameIReg64orSP(nn), 1 << sz);
4370 }
4371 return True;
4372 }
4373 return False;
4374 }
4375
sewardj168c8bd2014-06-25 13:05:23 +00004376 /* -------- LD2/ST2 (multi 2-elem structs, 2 regs, post index) -------- */
sewardj950ca7a2014-04-03 23:03:32 +00004377 /* Only a very few cases. */
4378 /* 31 23 11 9 4
4379 0100 1100 1101 1111 1000 11 n t LD2 {Vt.2d, V(t+1)%32.2d}, [Xn|SP], #32
4380 0100 1100 1001 1111 1000 11 n t ST2 {Vt.2d, V(t+1)%32.2d}, [Xn|SP], #32
4381 0100 1100 1101 1111 1000 10 n t LD2 {Vt.4s, V(t+1)%32.4s}, [Xn|SP], #32
4382 0100 1100 1001 1111 1000 10 n t ST2 {Vt.4s, V(t+1)%32.4s}, [Xn|SP], #32
4383 */
4384 if ( (insn & 0xFFFFFC00) == 0x4CDF8C00 // LD2 .2d
4385 || (insn & 0xFFFFFC00) == 0x4C9F8C00 // ST2 .2d
4386 || (insn & 0xFFFFFC00) == 0x4CDF8800 // LD2 .4s
4387 || (insn & 0xFFFFFC00) == 0x4C9F8800 // ST2 .4s
4388 ) {
4389 Bool isLD = INSN(22,22) == 1;
4390 UInt rN = INSN(9,5);
4391 UInt vT = INSN(4,0);
4392 IRTemp tEA = newTemp(Ity_I64);
4393 UInt sz = INSN(11,10);
4394 const HChar* name = "??";
4395 assign(tEA, getIReg64orSP(rN));
4396 if (rN == 31) { /* FIXME generate stack alignment check */ }
4397 IRExpr* tEA_0 = binop(Iop_Add64, mkexpr(tEA), mkU64(0));
4398 IRExpr* tEA_8 = binop(Iop_Add64, mkexpr(tEA), mkU64(8));
4399 IRExpr* tEA_16 = binop(Iop_Add64, mkexpr(tEA), mkU64(16));
4400 IRExpr* tEA_24 = binop(Iop_Add64, mkexpr(tEA), mkU64(24));
4401 if (sz == BITS2(1,1)) {
4402 name = "2d";
4403 if (isLD) {
4404 putQRegLane((vT+0) % 32, 0, loadLE(Ity_I64, tEA_0));
4405 putQRegLane((vT+0) % 32, 1, loadLE(Ity_I64, tEA_16));
4406 putQRegLane((vT+1) % 32, 0, loadLE(Ity_I64, tEA_8));
4407 putQRegLane((vT+1) % 32, 1, loadLE(Ity_I64, tEA_24));
4408 } else {
4409 storeLE(tEA_0, getQRegLane((vT+0) % 32, 0, Ity_I64));
4410 storeLE(tEA_16, getQRegLane((vT+0) % 32, 1, Ity_I64));
4411 storeLE(tEA_8, getQRegLane((vT+1) % 32, 0, Ity_I64));
4412 storeLE(tEA_24, getQRegLane((vT+1) % 32, 1, Ity_I64));
4413 }
4414 }
4415 else if (sz == BITS2(1,0)) {
4416 /* Uh, this is ugly. TODO: better. */
4417 name = "4s";
4418 IRExpr* tEA_4 = binop(Iop_Add64, mkexpr(tEA), mkU64(4));
4419 IRExpr* tEA_12 = binop(Iop_Add64, mkexpr(tEA), mkU64(12));
4420 IRExpr* tEA_20 = binop(Iop_Add64, mkexpr(tEA), mkU64(20));
4421 IRExpr* tEA_28 = binop(Iop_Add64, mkexpr(tEA), mkU64(28));
4422 if (isLD) {
4423 putQRegLane((vT+0) % 32, 0, loadLE(Ity_I32, tEA_0));
4424 putQRegLane((vT+0) % 32, 1, loadLE(Ity_I32, tEA_8));
4425 putQRegLane((vT+0) % 32, 2, loadLE(Ity_I32, tEA_16));
4426 putQRegLane((vT+0) % 32, 3, loadLE(Ity_I32, tEA_24));
4427 putQRegLane((vT+1) % 32, 0, loadLE(Ity_I32, tEA_4));
4428 putQRegLane((vT+1) % 32, 1, loadLE(Ity_I32, tEA_12));
4429 putQRegLane((vT+1) % 32, 2, loadLE(Ity_I32, tEA_20));
4430 putQRegLane((vT+1) % 32, 3, loadLE(Ity_I32, tEA_28));
4431 } else {
4432 storeLE(tEA_0, getQRegLane((vT+0) % 32, 0, Ity_I32));
4433 storeLE(tEA_8, getQRegLane((vT+0) % 32, 1, Ity_I32));
4434 storeLE(tEA_16, getQRegLane((vT+0) % 32, 2, Ity_I32));
4435 storeLE(tEA_24, getQRegLane((vT+0) % 32, 3, Ity_I32));
4436 storeLE(tEA_4, getQRegLane((vT+1) % 32, 0, Ity_I32));
4437 storeLE(tEA_12, getQRegLane((vT+1) % 32, 1, Ity_I32));
4438 storeLE(tEA_20, getQRegLane((vT+1) % 32, 2, Ity_I32));
4439 storeLE(tEA_28, getQRegLane((vT+1) % 32, 3, Ity_I32));
4440 }
4441 }
4442 else {
4443 vassert(0); // Can't happen.
4444 }
4445 putIReg64orSP(rN, binop(Iop_Add64, mkexpr(tEA), mkU64(32)));
4446 DIP("%s {v%u.%s, v%u.%s}, [%s], #32\n", isLD ? "ld2" : "st2",
4447 (vT+0) % 32, name, (vT+1) % 32, name, nameIReg64orSP(rN));
4448 return True;
4449 }
4450
sewardj39f754d2014-06-24 10:26:52 +00004451 /* -------- LD1/ST1 (multi 1-elem structs, 2 regs, no offset) -------- */
sewardj950ca7a2014-04-03 23:03:32 +00004452 /* Only a very few cases. */
4453 /* 31 23
4454 0100 1100 0100 0000 1010 00 n t LD1 {Vt.16b, V(t+1)%32.16b}, [Xn|SP]
4455 0100 1100 0000 0000 1010 00 n t ST1 {Vt.16b, V(t+1)%32.16b}, [Xn|SP]
4456 */
4457 if ( (insn & 0xFFFFFC00) == 0x4C40A000 // LD1
4458 || (insn & 0xFFFFFC00) == 0x4C00A000 // ST1
4459 ) {
4460 Bool isLD = INSN(22,22) == 1;
4461 UInt rN = INSN(9,5);
4462 UInt vT = INSN(4,0);
4463 IRTemp tEA = newTemp(Ity_I64);
4464 const HChar* name = "16b";
4465 assign(tEA, getIReg64orSP(rN));
4466 if (rN == 31) { /* FIXME generate stack alignment check */ }
4467 IRExpr* tEA_0 = binop(Iop_Add64, mkexpr(tEA), mkU64(0));
4468 IRExpr* tEA_16 = binop(Iop_Add64, mkexpr(tEA), mkU64(16));
4469 if (isLD) {
4470 putQReg128((vT+0) % 32, loadLE(Ity_V128, tEA_0));
4471 putQReg128((vT+1) % 32, loadLE(Ity_V128, tEA_16));
4472 } else {
4473 storeLE(tEA_0, getQReg128((vT+0) % 32));
4474 storeLE(tEA_16, getQReg128((vT+1) % 32));
4475 }
4476 DIP("%s {v%u.%s, v%u.%s}, [%s], #32\n", isLD ? "ld1" : "st1",
4477 (vT+0) % 32, name, (vT+1) % 32, name, nameIReg64orSP(rN));
sewardj606c4ba2014-01-26 19:11:14 +00004478 return True;
4479 }
4480
sewardj39f754d2014-06-24 10:26:52 +00004481 /* -------- LD1/ST1 (multi 1-elem structs, 3 regs, no offset) -------- */
4482 /* Only a very few cases. */
4483 /* 31 23
4484 0100 1100 0100 0000 0110 00 n t LD1 {Vt.16b .. V(t+2)%32.16b}, [Xn|SP]
4485 0100 1100 0000 0000 0110 00 n t ST1 {Vt.16b .. V(t+2)%32.16b}, [Xn|SP]
4486 */
4487 if ( (insn & 0xFFFFFC00) == 0x4C406000 // LD1
4488 || (insn & 0xFFFFFC00) == 0x4C006000 // ST1
4489 ) {
4490 Bool isLD = INSN(22,22) == 1;
4491 UInt rN = INSN(9,5);
4492 UInt vT = INSN(4,0);
4493 IRTemp tEA = newTemp(Ity_I64);
4494 const HChar* name = "16b";
4495 assign(tEA, getIReg64orSP(rN));
4496 if (rN == 31) { /* FIXME generate stack alignment check */ }
4497 IRExpr* tEA_0 = binop(Iop_Add64, mkexpr(tEA), mkU64(0));
4498 IRExpr* tEA_16 = binop(Iop_Add64, mkexpr(tEA), mkU64(16));
4499 IRExpr* tEA_32 = binop(Iop_Add64, mkexpr(tEA), mkU64(32));
4500 if (isLD) {
4501 putQReg128((vT+0) % 32, loadLE(Ity_V128, tEA_0));
4502 putQReg128((vT+1) % 32, loadLE(Ity_V128, tEA_16));
4503 putQReg128((vT+2) % 32, loadLE(Ity_V128, tEA_32));
4504 } else {
4505 storeLE(tEA_0, getQReg128((vT+0) % 32));
4506 storeLE(tEA_16, getQReg128((vT+1) % 32));
4507 storeLE(tEA_32, getQReg128((vT+2) % 32));
4508 }
4509 DIP("%s {v%u.%s, v%u.%s, v%u.%s}, [%s], #32\n",
4510 isLD ? "ld1" : "st1",
4511 (vT+0) % 32, name, (vT+1) % 32, name, (vT+2) % 32, name,
4512 nameIReg64orSP(rN));
4513 return True;
4514 }
4515
sewardj168c8bd2014-06-25 13:05:23 +00004516 /* -------- LD3/ST3 (multi 3-elem structs, 3 regs, post index) -------- */
4517 /* Only a very few cases. */
4518 /* 31 23 11 9 4
4519 0100 1100 1101 1111 0100 11 n t LD3 {Vt.2d .. V(t+2)%32.2d}, [Xn|SP], #48
4520 0100 1100 1001 1111 0100 11 n t ST3 {Vt.2d .. V(t+2)%32.2d}, [Xn|SP], #48
4521 */
4522 if ( (insn & 0xFFFFFC00) == 0x4CDF4C00 // LD3 .2d
4523 || (insn & 0xFFFFFC00) == 0x4C9F4C00 // ST3 .2d
4524 ) {
4525 Bool isLD = INSN(22,22) == 1;
4526 UInt rN = INSN(9,5);
4527 UInt vT = INSN(4,0);
4528 IRTemp tEA = newTemp(Ity_I64);
4529 UInt sz = INSN(11,10);
4530 const HChar* name = "??";
4531 assign(tEA, getIReg64orSP(rN));
4532 if (rN == 31) { /* FIXME generate stack alignment check */ }
4533 IRExpr* tEA_0 = binop(Iop_Add64, mkexpr(tEA), mkU64(0));
4534 IRExpr* tEA_8 = binop(Iop_Add64, mkexpr(tEA), mkU64(8));
4535 IRExpr* tEA_16 = binop(Iop_Add64, mkexpr(tEA), mkU64(16));
4536 IRExpr* tEA_24 = binop(Iop_Add64, mkexpr(tEA), mkU64(24));
4537 IRExpr* tEA_32 = binop(Iop_Add64, mkexpr(tEA), mkU64(32));
4538 IRExpr* tEA_40 = binop(Iop_Add64, mkexpr(tEA), mkU64(40));
4539 if (sz == BITS2(1,1)) {
4540 name = "2d";
4541 if (isLD) {
4542 putQRegLane((vT+0) % 32, 0, loadLE(Ity_I64, tEA_0));
4543 putQRegLane((vT+0) % 32, 1, loadLE(Ity_I64, tEA_24));
4544 putQRegLane((vT+1) % 32, 0, loadLE(Ity_I64, tEA_8));
4545 putQRegLane((vT+1) % 32, 1, loadLE(Ity_I64, tEA_32));
4546 putQRegLane((vT+2) % 32, 0, loadLE(Ity_I64, tEA_16));
4547 putQRegLane((vT+2) % 32, 1, loadLE(Ity_I64, tEA_40));
4548 } else {
4549 storeLE(tEA_0, getQRegLane((vT+0) % 32, 0, Ity_I64));
4550 storeLE(tEA_24, getQRegLane((vT+0) % 32, 1, Ity_I64));
4551 storeLE(tEA_8, getQRegLane((vT+1) % 32, 0, Ity_I64));
4552 storeLE(tEA_32, getQRegLane((vT+1) % 32, 1, Ity_I64));
4553 storeLE(tEA_16, getQRegLane((vT+2) % 32, 0, Ity_I64));
4554 storeLE(tEA_40, getQRegLane((vT+2) % 32, 1, Ity_I64));
4555 }
4556 }
4557 else {
4558 vassert(0); // Can't happen.
4559 }
4560 putIReg64orSP(rN, binop(Iop_Add64, mkexpr(tEA), mkU64(48)));
4561 DIP("%s {v%u.%s, v%u.%s, v%u.%s}, [%s], #32\n",
4562 isLD ? "ld3" : "st3",
4563 (vT+0) % 32, name, (vT+1) % 32, name, (vT+2) % 32, name,
4564 nameIReg64orSP(rN));
4565 return True;
4566 }
4567
sewardj7d009132014-02-20 17:43:38 +00004568 /* ------------------ LD{,A}X{R,RH,RB} ------------------ */
4569 /* ------------------ ST{,L}X{R,RH,RB} ------------------ */
4570 /* 31 29 23 20 14 9 4
4571 sz 001000 010 11111 0 11111 n t LDX{R,RH,RB} Rt, [Xn|SP]
4572 sz 001000 010 11111 1 11111 n t LDAX{R,RH,RB} Rt, [Xn|SP]
4573 sz 001000 000 s 0 11111 n t STX{R,RH,RB} Ws, Rt, [Xn|SP]
4574 sz 001000 000 s 1 11111 n t STLX{R,RH,RB} Ws, Rt, [Xn|SP]
sewardjbbcf1882014-01-12 12:49:10 +00004575 */
sewardj7d009132014-02-20 17:43:38 +00004576 if (INSN(29,23) == BITS7(0,0,1,0,0,0,0)
4577 && (INSN(23,21) & BITS3(1,0,1)) == BITS3(0,0,0)
4578 && INSN(14,10) == BITS5(1,1,1,1,1)) {
sewardjdc9259c2014-02-27 11:10:19 +00004579 UInt szBlg2 = INSN(31,30);
4580 Bool isLD = INSN(22,22) == 1;
4581 Bool isAcqOrRel = INSN(15,15) == 1;
4582 UInt ss = INSN(20,16);
4583 UInt nn = INSN(9,5);
4584 UInt tt = INSN(4,0);
sewardjbbcf1882014-01-12 12:49:10 +00004585
sewardjdc9259c2014-02-27 11:10:19 +00004586 vassert(szBlg2 < 4);
4587 UInt szB = 1 << szBlg2; /* 1, 2, 4 or 8 */
4588 IRType ty = integerIRTypeOfSize(szB);
4589 const HChar* suffix[4] = { "rb", "rh", "r", "r" };
sewardj7d009132014-02-20 17:43:38 +00004590
sewardjdc9259c2014-02-27 11:10:19 +00004591 IRTemp ea = newTemp(Ity_I64);
4592 assign(ea, getIReg64orSP(nn));
4593 /* FIXME generate check that ea is szB-aligned */
sewardj7d009132014-02-20 17:43:38 +00004594
sewardjdc9259c2014-02-27 11:10:19 +00004595 if (isLD && ss == BITS5(1,1,1,1,1)) {
4596 IRTemp res = newTemp(ty);
4597 stmt(IRStmt_LLSC(Iend_LE, res, mkexpr(ea), NULL/*LL*/));
4598 putIReg64orZR(tt, widenUto64(ty, mkexpr(res)));
4599 if (isAcqOrRel) {
4600 stmt(IRStmt_MBE(Imbe_Fence));
4601 }
4602 DIP("ld%sx%s %s, [%s]\n", isAcqOrRel ? "a" : "", suffix[szBlg2],
4603 nameIRegOrZR(szB == 8, tt), nameIReg64orSP(nn));
4604 return True;
4605 }
4606 if (!isLD) {
4607 if (isAcqOrRel) {
4608 stmt(IRStmt_MBE(Imbe_Fence));
4609 }
4610 IRTemp res = newTemp(Ity_I1);
4611 IRExpr* data = narrowFrom64(ty, getIReg64orZR(tt));
4612 stmt(IRStmt_LLSC(Iend_LE, res, mkexpr(ea), data));
4613 /* IR semantics: res is 1 if store succeeds, 0 if it fails.
4614 Need to set rS to 1 on failure, 0 on success. */
4615 putIReg64orZR(ss, binop(Iop_Xor64, unop(Iop_1Uto64, mkexpr(res)),
4616 mkU64(1)));
4617 DIP("st%sx%s %s, %s, [%s]\n", isAcqOrRel ? "a" : "", suffix[szBlg2],
4618 nameIRegOrZR(False, ss),
4619 nameIRegOrZR(szB == 8, tt), nameIReg64orSP(nn));
4620 return True;
4621 }
4622 /* else fall through */
4623 }
4624
4625 /* ------------------ LDA{R,RH,RB} ------------------ */
4626 /* ------------------ STL{R,RH,RB} ------------------ */
4627 /* 31 29 23 20 14 9 4
4628 sz 001000 110 11111 1 11111 n t LDAR<sz> Rt, [Xn|SP]
4629 sz 001000 100 11111 1 11111 n t STLR<sz> Rt, [Xn|SP]
4630 */
4631 if (INSN(29,23) == BITS7(0,0,1,0,0,0,1)
4632 && INSN(21,10) == BITS12(0,1,1,1,1,1,1,1,1,1,1,1)) {
4633 UInt szBlg2 = INSN(31,30);
4634 Bool isLD = INSN(22,22) == 1;
4635 UInt nn = INSN(9,5);
4636 UInt tt = INSN(4,0);
4637
4638 vassert(szBlg2 < 4);
4639 UInt szB = 1 << szBlg2; /* 1, 2, 4 or 8 */
4640 IRType ty = integerIRTypeOfSize(szB);
4641 const HChar* suffix[4] = { "rb", "rh", "r", "r" };
4642
4643 IRTemp ea = newTemp(Ity_I64);
4644 assign(ea, getIReg64orSP(nn));
4645 /* FIXME generate check that ea is szB-aligned */
4646
4647 if (isLD) {
4648 IRTemp res = newTemp(ty);
4649 assign(res, loadLE(ty, mkexpr(ea)));
4650 putIReg64orZR(tt, widenUto64(ty, mkexpr(res)));
4651 stmt(IRStmt_MBE(Imbe_Fence));
4652 DIP("lda%s %s, [%s]\n", suffix[szBlg2],
4653 nameIRegOrZR(szB == 8, tt), nameIReg64orSP(nn));
4654 } else {
4655 stmt(IRStmt_MBE(Imbe_Fence));
4656 IRExpr* data = narrowFrom64(ty, getIReg64orZR(tt));
4657 storeLE(mkexpr(ea), data);
4658 DIP("stl%s %s, [%s]\n", suffix[szBlg2],
4659 nameIRegOrZR(szB == 8, tt), nameIReg64orSP(nn));
4660 }
4661 return True;
sewardjbbcf1882014-01-12 12:49:10 +00004662 }
4663
4664 vex_printf("ARM64 front end: load_store\n");
4665 return False;
4666# undef INSN
4667}
4668
4669
4670/*------------------------------------------------------------*/
4671/*--- Control flow and misc instructions ---*/
4672/*------------------------------------------------------------*/
4673
4674static
sewardj65902992014-05-03 21:20:56 +00004675Bool dis_ARM64_branch_etc(/*MB_OUT*/DisResult* dres, UInt insn,
4676 VexArchInfo* archinfo)
sewardjbbcf1882014-01-12 12:49:10 +00004677{
4678# define INSN(_bMax,_bMin) SLICE_UInt(insn, (_bMax), (_bMin))
4679
4680 /* ---------------------- B cond ----------------------- */
4681 /* 31 24 4 3
4682 0101010 0 imm19 0 cond */
4683 if (INSN(31,24) == BITS8(0,1,0,1,0,1,0,0) && INSN(4,4) == 0) {
4684 UInt cond = INSN(3,0);
4685 ULong uimm64 = INSN(23,5) << 2;
4686 Long simm64 = (Long)sx_to_64(uimm64, 21);
4687 vassert(dres->whatNext == Dis_Continue);
4688 vassert(dres->len == 4);
4689 vassert(dres->continueAt == 0);
4690 vassert(dres->jk_StopHere == Ijk_INVALID);
4691 stmt( IRStmt_Exit(unop(Iop_64to1, mk_arm64g_calculate_condition(cond)),
4692 Ijk_Boring,
4693 IRConst_U64(guest_PC_curr_instr + simm64),
4694 OFFB_PC) );
4695 putPC(mkU64(guest_PC_curr_instr + 4));
4696 dres->whatNext = Dis_StopHere;
4697 dres->jk_StopHere = Ijk_Boring;
4698 DIP("b.%s 0x%llx\n", nameCC(cond), guest_PC_curr_instr + simm64);
4699 return True;
4700 }
4701
4702 /* -------------------- B{L} uncond -------------------- */
4703 if (INSN(30,26) == BITS5(0,0,1,0,1)) {
4704 /* 000101 imm26 B (PC + sxTo64(imm26 << 2))
4705 100101 imm26 B (PC + sxTo64(imm26 << 2))
4706 */
4707 UInt bLink = INSN(31,31);
4708 ULong uimm64 = INSN(25,0) << 2;
4709 Long simm64 = (Long)sx_to_64(uimm64, 28);
4710 if (bLink) {
4711 putIReg64orSP(30, mkU64(guest_PC_curr_instr + 4));
4712 }
4713 putPC(mkU64(guest_PC_curr_instr + simm64));
4714 dres->whatNext = Dis_StopHere;
4715 dres->jk_StopHere = Ijk_Call;
4716 DIP("b%s 0x%llx\n", bLink == 1 ? "l" : "",
4717 guest_PC_curr_instr + simm64);
4718 return True;
4719 }
4720
4721 /* --------------------- B{L} reg --------------------- */
4722 /* 31 24 22 20 15 9 4
4723 1101011 00 10 11111 000000 nn 00000 RET Rn
4724 1101011 00 01 11111 000000 nn 00000 CALL Rn
4725 1101011 00 00 11111 000000 nn 00000 JMP Rn
4726 */
4727 if (INSN(31,23) == BITS9(1,1,0,1,0,1,1,0,0)
4728 && INSN(20,16) == BITS5(1,1,1,1,1)
4729 && INSN(15,10) == BITS6(0,0,0,0,0,0)
4730 && INSN(4,0) == BITS5(0,0,0,0,0)) {
4731 UInt branch_type = INSN(22,21);
4732 UInt nn = INSN(9,5);
4733 if (branch_type == BITS2(1,0) /* RET */) {
4734 putPC(getIReg64orZR(nn));
4735 dres->whatNext = Dis_StopHere;
4736 dres->jk_StopHere = Ijk_Ret;
4737 DIP("ret %s\n", nameIReg64orZR(nn));
4738 return True;
4739 }
4740 if (branch_type == BITS2(0,1) /* CALL */) {
sewardj702054e2014-05-07 11:09:28 +00004741 IRTemp dst = newTemp(Ity_I64);
4742 assign(dst, getIReg64orZR(nn));
sewardjbbcf1882014-01-12 12:49:10 +00004743 putIReg64orSP(30, mkU64(guest_PC_curr_instr + 4));
sewardj702054e2014-05-07 11:09:28 +00004744 putPC(mkexpr(dst));
sewardjbbcf1882014-01-12 12:49:10 +00004745 dres->whatNext = Dis_StopHere;
4746 dres->jk_StopHere = Ijk_Call;
4747 DIP("blr %s\n", nameIReg64orZR(nn));
4748 return True;
4749 }
4750 if (branch_type == BITS2(0,0) /* JMP */) {
4751 putPC(getIReg64orZR(nn));
4752 dres->whatNext = Dis_StopHere;
4753 dres->jk_StopHere = Ijk_Boring;
4754 DIP("jmp %s\n", nameIReg64orZR(nn));
4755 return True;
4756 }
4757 }
4758
4759 /* -------------------- CB{N}Z -------------------- */
4760 /* sf 011 010 1 imm19 Rt CBNZ Xt|Wt, (PC + sxTo64(imm19 << 2))
4761 sf 011 010 0 imm19 Rt CBZ Xt|Wt, (PC + sxTo64(imm19 << 2))
4762 */
4763 if (INSN(30,25) == BITS6(0,1,1,0,1,0)) {
4764 Bool is64 = INSN(31,31) == 1;
4765 Bool bIfZ = INSN(24,24) == 0;
4766 ULong uimm64 = INSN(23,5) << 2;
4767 UInt rT = INSN(4,0);
4768 Long simm64 = (Long)sx_to_64(uimm64, 21);
4769 IRExpr* cond = NULL;
4770 if (is64) {
4771 cond = binop(bIfZ ? Iop_CmpEQ64 : Iop_CmpNE64,
4772 getIReg64orZR(rT), mkU64(0));
4773 } else {
4774 cond = binop(bIfZ ? Iop_CmpEQ32 : Iop_CmpNE32,
4775 getIReg32orZR(rT), mkU32(0));
4776 }
4777 stmt( IRStmt_Exit(cond,
4778 Ijk_Boring,
4779 IRConst_U64(guest_PC_curr_instr + simm64),
4780 OFFB_PC) );
4781 putPC(mkU64(guest_PC_curr_instr + 4));
4782 dres->whatNext = Dis_StopHere;
4783 dres->jk_StopHere = Ijk_Boring;
4784 DIP("cb%sz %s, 0x%llx\n",
4785 bIfZ ? "" : "n", nameIRegOrZR(is64, rT),
4786 guest_PC_curr_instr + simm64);
4787 return True;
4788 }
4789
4790 /* -------------------- TB{N}Z -------------------- */
4791 /* 31 30 24 23 18 5 4
4792 b5 011 011 1 b40 imm14 t TBNZ Xt, #(b5:b40), (PC + sxTo64(imm14 << 2))
4793 b5 011 011 0 b40 imm14 t TBZ Xt, #(b5:b40), (PC + sxTo64(imm14 << 2))
4794 */
4795 if (INSN(30,25) == BITS6(0,1,1,0,1,1)) {
4796 UInt b5 = INSN(31,31);
4797 Bool bIfZ = INSN(24,24) == 0;
4798 UInt b40 = INSN(23,19);
4799 UInt imm14 = INSN(18,5);
4800 UInt tt = INSN(4,0);
4801 UInt bitNo = (b5 << 5) | b40;
4802 ULong uimm64 = imm14 << 2;
4803 Long simm64 = sx_to_64(uimm64, 16);
4804 IRExpr* cond
4805 = binop(bIfZ ? Iop_CmpEQ64 : Iop_CmpNE64,
4806 binop(Iop_And64,
4807 binop(Iop_Shr64, getIReg64orZR(tt), mkU8(bitNo)),
4808 mkU64(1)),
4809 mkU64(0));
4810 stmt( IRStmt_Exit(cond,
4811 Ijk_Boring,
4812 IRConst_U64(guest_PC_curr_instr + simm64),
4813 OFFB_PC) );
4814 putPC(mkU64(guest_PC_curr_instr + 4));
4815 dres->whatNext = Dis_StopHere;
4816 dres->jk_StopHere = Ijk_Boring;
4817 DIP("tb%sz %s, #%u, 0x%llx\n",
4818 bIfZ ? "" : "n", nameIReg64orZR(tt), bitNo,
4819 guest_PC_curr_instr + simm64);
4820 return True;
4821 }
4822
4823 /* -------------------- SVC -------------------- */
4824 /* 11010100 000 imm16 000 01
4825 Don't bother with anything except the imm16==0 case.
4826 */
4827 if (INSN(31,0) == 0xD4000001) {
4828 putPC(mkU64(guest_PC_curr_instr + 4));
4829 dres->whatNext = Dis_StopHere;
4830 dres->jk_StopHere = Ijk_Sys_syscall;
4831 DIP("svc #0\n");
4832 return True;
4833 }
4834
4835 /* ------------------ M{SR,RS} ------------------ */
4836 /* Only handles the case where the system register is TPIDR_EL0.
4837 0xD51BD0 010 Rt MSR tpidr_el0, rT
4838 0xD53BD0 010 Rt MRS rT, tpidr_el0
4839 */
4840 if ( (INSN(31,0) & 0xFFFFFFE0) == 0xD51BD040 /*MSR*/
4841 || (INSN(31,0) & 0xFFFFFFE0) == 0xD53BD040 /*MRS*/) {
4842 Bool toSys = INSN(21,21) == 0;
4843 UInt tt = INSN(4,0);
4844 if (toSys) {
4845 stmt( IRStmt_Put( OFFB_TPIDR_EL0, getIReg64orZR(tt)) );
4846 DIP("msr tpidr_el0, %s\n", nameIReg64orZR(tt));
4847 } else {
4848 putIReg64orZR(tt, IRExpr_Get( OFFB_TPIDR_EL0, Ity_I64 ));
4849 DIP("mrs %s, tpidr_el0\n", nameIReg64orZR(tt));
4850 }
4851 return True;
4852 }
4853 /* Cases for FPCR
4854 0xD51B44 000 Rt MSR fpcr, rT
4855 0xD53B44 000 Rt MSR rT, fpcr
4856 */
4857 if ( (INSN(31,0) & 0xFFFFFFE0) == 0xD51B4400 /*MSR*/
4858 || (INSN(31,0) & 0xFFFFFFE0) == 0xD53B4400 /*MRS*/) {
4859 Bool toSys = INSN(21,21) == 0;
4860 UInt tt = INSN(4,0);
4861 if (toSys) {
4862 stmt( IRStmt_Put( OFFB_FPCR, getIReg32orZR(tt)) );
4863 DIP("msr fpcr, %s\n", nameIReg64orZR(tt));
4864 } else {
4865 putIReg32orZR(tt, IRExpr_Get(OFFB_FPCR, Ity_I32));
4866 DIP("mrs %s, fpcr\n", nameIReg64orZR(tt));
4867 }
4868 return True;
4869 }
4870 /* Cases for FPSR
sewardj7d009132014-02-20 17:43:38 +00004871 0xD51B44 001 Rt MSR fpsr, rT
4872 0xD53B44 001 Rt MSR rT, fpsr
sewardjbbcf1882014-01-12 12:49:10 +00004873 */
4874 if ( (INSN(31,0) & 0xFFFFFFE0) == 0xD51B4420 /*MSR*/
4875 || (INSN(31,0) & 0xFFFFFFE0) == 0xD53B4420 /*MRS*/) {
4876 Bool toSys = INSN(21,21) == 0;
4877 UInt tt = INSN(4,0);
4878 if (toSys) {
4879 stmt( IRStmt_Put( OFFB_FPSR, getIReg32orZR(tt)) );
4880 DIP("msr fpsr, %s\n", nameIReg64orZR(tt));
4881 } else {
4882 putIReg32orZR(tt, IRExpr_Get(OFFB_FPSR, Ity_I32));
4883 DIP("mrs %s, fpsr\n", nameIReg64orZR(tt));
4884 }
4885 return True;
4886 }
4887 /* Cases for NZCV
4888 D51B42 000 Rt MSR nzcv, rT
4889 D53B42 000 Rt MRS rT, nzcv
4890 */
4891 if ( (INSN(31,0) & 0xFFFFFFE0) == 0xD51B4200 /*MSR*/
4892 || (INSN(31,0) & 0xFFFFFFE0) == 0xD53B4200 /*MRS*/) {
4893 Bool toSys = INSN(21,21) == 0;
4894 UInt tt = INSN(4,0);
4895 if (toSys) {
4896 IRTemp t = newTemp(Ity_I64);
4897 assign(t, binop(Iop_And64, getIReg64orZR(tt), mkU64(0xF0000000ULL)));
4898 setFlags_COPY(t);
4899 DIP("msr %s, nzcv\n", nameIReg32orZR(tt));
4900 } else {
4901 IRTemp res = newTemp(Ity_I64);
4902 assign(res, mk_arm64g_calculate_flags_nzcv());
4903 putIReg32orZR(tt, unop(Iop_64to32, mkexpr(res)));
4904 DIP("mrs %s, nzcv\n", nameIReg64orZR(tt));
4905 }
4906 return True;
4907 }
sewardjd512d102014-02-21 14:49:44 +00004908 /* Cases for DCZID_EL0
4909 Don't support arbitrary reads and writes to this register. Just
4910 return the value 16, which indicates that the DC ZVA instruction
4911 is not permitted, so we don't have to emulate it.
4912 D5 3B 00 111 Rt MRS rT, dczid_el0
4913 */
4914 if ((INSN(31,0) & 0xFFFFFFE0) == 0xD53B00E0) {
4915 UInt tt = INSN(4,0);
4916 putIReg64orZR(tt, mkU64(1<<4));
4917 DIP("mrs %s, dczid_el0 (FAKED)\n", nameIReg64orZR(tt));
4918 return True;
4919 }
sewardj65902992014-05-03 21:20:56 +00004920 /* Cases for CTR_EL0
4921 We just handle reads, and make up a value from the D and I line
4922 sizes in the VexArchInfo we are given, and patch in the following
4923 fields that the Foundation model gives ("natively"):
4924 CWG = 0b0100, ERG = 0b0100, L1Ip = 0b11
4925 D5 3B 00 001 Rt MRS rT, dczid_el0
4926 */
4927 if ((INSN(31,0) & 0xFFFFFFE0) == 0xD53B0020) {
4928 UInt tt = INSN(4,0);
4929 /* Need to generate a value from dMinLine_lg2_szB and
4930 dMinLine_lg2_szB. The value in the register is in 32-bit
4931 units, so need to subtract 2 from the values in the
4932 VexArchInfo. We can assume that the values here are valid --
4933 disInstr_ARM64 checks them -- so there's no need to deal with
4934 out-of-range cases. */
4935 vassert(archinfo->arm64_dMinLine_lg2_szB >= 2
4936 && archinfo->arm64_dMinLine_lg2_szB <= 17
4937 && archinfo->arm64_iMinLine_lg2_szB >= 2
4938 && archinfo->arm64_iMinLine_lg2_szB <= 17);
4939 UInt val
4940 = 0x8440c000 | ((0xF & (archinfo->arm64_dMinLine_lg2_szB - 2)) << 16)
4941 | ((0xF & (archinfo->arm64_iMinLine_lg2_szB - 2)) << 0);
4942 putIReg64orZR(tt, mkU64(val));
4943 DIP("mrs %s, ctr_el0\n", nameIReg64orZR(tt));
4944 return True;
4945 }
sewardjbbcf1882014-01-12 12:49:10 +00004946
sewardj65902992014-05-03 21:20:56 +00004947 /* ------------------ IC_IVAU ------------------ */
4948 /* D5 0B 75 001 Rt ic ivau, rT
4949 */
4950 if ((INSN(31,0) & 0xFFFFFFE0) == 0xD50B7520) {
4951 /* We will always be provided with a valid iMinLine value. */
4952 vassert(archinfo->arm64_iMinLine_lg2_szB >= 2
4953 && archinfo->arm64_iMinLine_lg2_szB <= 17);
4954 /* Round the requested address, in rT, down to the start of the
4955 containing block. */
4956 UInt tt = INSN(4,0);
4957 ULong lineszB = 1ULL << archinfo->arm64_iMinLine_lg2_szB;
4958 IRTemp addr = newTemp(Ity_I64);
4959 assign( addr, binop( Iop_And64,
4960 getIReg64orZR(tt),
4961 mkU64(~(lineszB - 1))) );
4962 /* Set the invalidation range, request exit-and-invalidate, with
4963 continuation at the next instruction. */
sewardj05f5e012014-05-04 10:52:11 +00004964 stmt(IRStmt_Put(OFFB_CMSTART, mkexpr(addr)));
4965 stmt(IRStmt_Put(OFFB_CMLEN, mkU64(lineszB)));
sewardj65902992014-05-03 21:20:56 +00004966 /* be paranoid ... */
4967 stmt( IRStmt_MBE(Imbe_Fence) );
4968 putPC(mkU64( guest_PC_curr_instr + 4 ));
4969 dres->whatNext = Dis_StopHere;
sewardj05f5e012014-05-04 10:52:11 +00004970 dres->jk_StopHere = Ijk_InvalICache;
sewardj65902992014-05-03 21:20:56 +00004971 DIP("ic ivau, %s\n", nameIReg64orZR(tt));
4972 return True;
4973 }
4974
4975 /* ------------------ DC_CVAU ------------------ */
4976 /* D5 0B 7B 001 Rt dc cvau, rT
4977 */
4978 if ((INSN(31,0) & 0xFFFFFFE0) == 0xD50B7B20) {
4979 /* Exactly the same scheme as for IC IVAU, except we observe the
sewardj05f5e012014-05-04 10:52:11 +00004980 dMinLine size, and request an Ijk_FlushDCache instead of
4981 Ijk_InvalICache. */
sewardj65902992014-05-03 21:20:56 +00004982 /* We will always be provided with a valid dMinLine value. */
4983 vassert(archinfo->arm64_dMinLine_lg2_szB >= 2
4984 && archinfo->arm64_dMinLine_lg2_szB <= 17);
4985 /* Round the requested address, in rT, down to the start of the
4986 containing block. */
4987 UInt tt = INSN(4,0);
4988 ULong lineszB = 1ULL << archinfo->arm64_dMinLine_lg2_szB;
4989 IRTemp addr = newTemp(Ity_I64);
4990 assign( addr, binop( Iop_And64,
4991 getIReg64orZR(tt),
4992 mkU64(~(lineszB - 1))) );
4993 /* Set the flush range, request exit-and-flush, with
4994 continuation at the next instruction. */
sewardj05f5e012014-05-04 10:52:11 +00004995 stmt(IRStmt_Put(OFFB_CMSTART, mkexpr(addr)));
4996 stmt(IRStmt_Put(OFFB_CMLEN, mkU64(lineszB)));
sewardj65902992014-05-03 21:20:56 +00004997 /* be paranoid ... */
4998 stmt( IRStmt_MBE(Imbe_Fence) );
4999 putPC(mkU64( guest_PC_curr_instr + 4 ));
5000 dres->whatNext = Dis_StopHere;
5001 dres->jk_StopHere = Ijk_FlushDCache;
5002 DIP("dc cvau, %s\n", nameIReg64orZR(tt));
5003 return True;
5004 }
5005
5006 /* ------------------ ISB, DMB, DSB ------------------ */
sewardjbbcf1882014-01-12 12:49:10 +00005007 if (INSN(31,0) == 0xD5033FDF) {
sewardjd512d102014-02-21 14:49:44 +00005008 stmt(IRStmt_MBE(Imbe_Fence));
sewardjbbcf1882014-01-12 12:49:10 +00005009 DIP("isb\n");
5010 return True;
5011 }
5012 if (INSN(31,0) == 0xD5033BBF) {
sewardjd512d102014-02-21 14:49:44 +00005013 stmt(IRStmt_MBE(Imbe_Fence));
sewardjbbcf1882014-01-12 12:49:10 +00005014 DIP("dmb ish\n");
5015 return True;
5016 }
sewardjab102bd2014-06-04 11:44:45 +00005017 if (INSN(31,0) == 0xD5033ABF) {
5018 stmt(IRStmt_MBE(Imbe_Fence));
5019 DIP("dmb ishst\n");
5020 return True;
5021 }
sewardj65902992014-05-03 21:20:56 +00005022 if (INSN(31,0) == 0xD5033B9F) {
5023 stmt(IRStmt_MBE(Imbe_Fence));
5024 DIP("dsb ish\n");
5025 return True;
5026 }
sewardjbbcf1882014-01-12 12:49:10 +00005027
sewardjdc9259c2014-02-27 11:10:19 +00005028 /* -------------------- NOP -------------------- */
5029 if (INSN(31,0) == 0xD503201F) {
5030 DIP("nop\n");
5031 return True;
5032 }
5033
sewardjbbcf1882014-01-12 12:49:10 +00005034 //fail:
5035 vex_printf("ARM64 front end: branch_etc\n");
5036 return False;
5037# undef INSN
5038}
5039
5040
5041/*------------------------------------------------------------*/
5042/*--- SIMD and FP instructions ---*/
5043/*------------------------------------------------------------*/
5044
sewardjd96daf62014-06-15 08:17:35 +00005045/* Some constructors for interleave/deinterleave expressions. */
sewardje520bb32014-02-17 11:00:53 +00005046
sewardjd96daf62014-06-15 08:17:35 +00005047static IRExpr* mk_CatEvenLanes64x2 ( IRTemp a10, IRTemp b10 ) {
5048 // returns a0 b0
5049 return binop(Iop_InterleaveLO64x2, mkexpr(a10), mkexpr(b10));
5050}
sewardje520bb32014-02-17 11:00:53 +00005051
sewardjd96daf62014-06-15 08:17:35 +00005052static IRExpr* mk_CatOddLanes64x2 ( IRTemp a10, IRTemp b10 ) {
5053 // returns a1 b1
5054 return binop(Iop_InterleaveHI64x2, mkexpr(a10), mkexpr(b10));
5055}
sewardje520bb32014-02-17 11:00:53 +00005056
sewardjd96daf62014-06-15 08:17:35 +00005057static IRExpr* mk_CatEvenLanes32x4 ( IRTemp a3210, IRTemp b3210 ) {
5058 // returns a2 a0 b2 b0
5059 return binop(Iop_CatEvenLanes32x4, mkexpr(a3210), mkexpr(b3210));
5060}
5061
5062static IRExpr* mk_CatOddLanes32x4 ( IRTemp a3210, IRTemp b3210 ) {
5063 // returns a3 a1 b3 b1
5064 return binop(Iop_CatOddLanes32x4, mkexpr(a3210), mkexpr(b3210));
5065}
5066
5067static IRExpr* mk_InterleaveLO32x4 ( IRTemp a3210, IRTemp b3210 ) {
5068 // returns a1 b1 a0 b0
5069 return binop(Iop_InterleaveLO32x4, mkexpr(a3210), mkexpr(b3210));
5070}
5071
5072static IRExpr* mk_InterleaveHI32x4 ( IRTemp a3210, IRTemp b3210 ) {
5073 // returns a3 b3 a2 b2
5074 return binop(Iop_InterleaveHI32x4, mkexpr(a3210), mkexpr(b3210));
5075}
5076
5077static IRExpr* mk_CatEvenLanes16x8 ( IRTemp a76543210, IRTemp b76543210 ) {
5078 // returns a6 a4 a2 a0 b6 b4 b2 b0
5079 return binop(Iop_CatEvenLanes16x8, mkexpr(a76543210), mkexpr(b76543210));
5080}
5081
5082static IRExpr* mk_CatOddLanes16x8 ( IRTemp a76543210, IRTemp b76543210 ) {
5083 // returns a7 a5 a3 a1 b7 b5 b3 b1
5084 return binop(Iop_CatOddLanes16x8, mkexpr(a76543210), mkexpr(b76543210));
5085}
5086
5087static IRExpr* mk_InterleaveLO16x8 ( IRTemp a76543210, IRTemp b76543210 ) {
5088 // returns a3 b3 a2 b2 a1 b1 a0 b0
5089 return binop(Iop_InterleaveLO16x8, mkexpr(a76543210), mkexpr(b76543210));
5090}
5091
5092static IRExpr* mk_InterleaveHI16x8 ( IRTemp a76543210, IRTemp b76543210 ) {
5093 // returns a7 b7 a6 b6 a5 b5 a4 b4
5094 return binop(Iop_InterleaveHI16x8, mkexpr(a76543210), mkexpr(b76543210));
5095}
5096
5097static IRExpr* mk_CatEvenLanes8x16 ( IRTemp aFEDCBA9876543210,
5098 IRTemp bFEDCBA9876543210 ) {
5099 // returns aE aC aA a8 a6 a4 a2 a0 bE bC bA b8 b6 b4 b2 b0
5100 return binop(Iop_CatEvenLanes8x16, mkexpr(aFEDCBA9876543210),
5101 mkexpr(bFEDCBA9876543210));
5102}
5103
5104static IRExpr* mk_CatOddLanes8x16 ( IRTemp aFEDCBA9876543210,
5105 IRTemp bFEDCBA9876543210 ) {
5106 // returns aF aD aB a9 a7 a5 a3 a1 bF bD bB b9 b7 b5 b3 b1
5107 return binop(Iop_CatOddLanes8x16, mkexpr(aFEDCBA9876543210),
5108 mkexpr(bFEDCBA9876543210));
5109}
5110
5111static IRExpr* mk_InterleaveLO8x16 ( IRTemp aFEDCBA9876543210,
5112 IRTemp bFEDCBA9876543210 ) {
5113 // returns a7 b7 a6 b6 a5 b5 a4 b4 a3 b3 a2 b2 a1 b1 a0 b0
5114 return binop(Iop_InterleaveLO8x16, mkexpr(aFEDCBA9876543210),
5115 mkexpr(bFEDCBA9876543210));
5116}
5117
5118static IRExpr* mk_InterleaveHI8x16 ( IRTemp aFEDCBA9876543210,
5119 IRTemp bFEDCBA9876543210 ) {
5120 // returns aF bF aE bE aD bD aC bC aB bB aA bA a9 b9 a8 b8
5121 return binop(Iop_InterleaveHI8x16, mkexpr(aFEDCBA9876543210),
5122 mkexpr(bFEDCBA9876543210));
5123}
sewardjecde6972014-02-05 11:01:19 +00005124
sewardjbbcf1882014-01-12 12:49:10 +00005125/* Generate N copies of |bit| in the bottom of a ULong. */
5126static ULong Replicate ( ULong bit, Int N )
5127{
sewardj606c4ba2014-01-26 19:11:14 +00005128 vassert(bit <= 1 && N >= 1 && N < 64);
5129 if (bit == 0) {
5130 return 0;
5131 } else {
5132 /* Careful. This won't work for N == 64. */
5133 return (1ULL << N) - 1;
5134 }
sewardjbbcf1882014-01-12 12:49:10 +00005135}
5136
sewardjfab09142014-02-10 10:28:13 +00005137static ULong Replicate32x2 ( ULong bits32 )
5138{
5139 vassert(0 == (bits32 & ~0xFFFFFFFFULL));
5140 return (bits32 << 32) | bits32;
5141}
5142
5143static ULong Replicate16x4 ( ULong bits16 )
5144{
5145 vassert(0 == (bits16 & ~0xFFFFULL));
5146 return Replicate32x2((bits16 << 16) | bits16);
5147}
5148
5149static ULong Replicate8x8 ( ULong bits8 )
5150{
5151 vassert(0 == (bits8 & ~0xFFULL));
5152 return Replicate16x4((bits8 << 8) | bits8);
5153}
5154
5155/* Expand the VFPExpandImm-style encoding in the bottom 8 bits of
5156 |imm8| to either a 32-bit value if N is 32 or a 64 bit value if N
5157 is 64. In the former case, the upper 32 bits of the returned value
5158 are guaranteed to be zero. */
sewardjbbcf1882014-01-12 12:49:10 +00005159static ULong VFPExpandImm ( ULong imm8, Int N )
5160{
sewardj606c4ba2014-01-26 19:11:14 +00005161 vassert(imm8 <= 0xFF);
5162 vassert(N == 32 || N == 64);
5163 Int E = ((N == 32) ? 8 : 11) - 2; // The spec incorrectly omits the -2.
5164 Int F = N - E - 1;
5165 ULong imm8_6 = (imm8 >> 6) & 1;
5166 /* sign: 1 bit */
5167 /* exp: E bits */
5168 /* frac: F bits */
5169 ULong sign = (imm8 >> 7) & 1;
5170 ULong exp = ((imm8_6 ^ 1) << (E-1)) | Replicate(imm8_6, E-1);
5171 ULong frac = ((imm8 & 63) << (F-6)) | Replicate(0, F-6);
5172 vassert(sign < (1ULL << 1));
5173 vassert(exp < (1ULL << E));
5174 vassert(frac < (1ULL << F));
5175 vassert(1 + E + F == N);
5176 ULong res = (sign << (E+F)) | (exp << F) | frac;
5177 return res;
sewardjbbcf1882014-01-12 12:49:10 +00005178}
5179
sewardjfab09142014-02-10 10:28:13 +00005180/* Expand an AdvSIMDExpandImm-style encoding into a 64-bit value.
5181 This might fail, as indicated by the returned Bool. Page 2530 of
5182 the manual. */
5183static Bool AdvSIMDExpandImm ( /*OUT*/ULong* res,
5184 UInt op, UInt cmode, UInt imm8 )
5185{
5186 vassert(op <= 1);
5187 vassert(cmode <= 15);
5188 vassert(imm8 <= 255);
5189
5190 *res = 0; /* will overwrite iff returning True */
5191
5192 ULong imm64 = 0;
5193 Bool testimm8 = False;
5194
5195 switch (cmode >> 1) {
5196 case 0:
5197 testimm8 = False; imm64 = Replicate32x2(imm8); break;
5198 case 1:
5199 testimm8 = True; imm64 = Replicate32x2(imm8 << 8); break;
5200 case 2:
5201 testimm8 = True; imm64 = Replicate32x2(imm8 << 16); break;
5202 case 3:
5203 testimm8 = True; imm64 = Replicate32x2(imm8 << 24); break;
5204 case 4:
5205 testimm8 = False; imm64 = Replicate16x4(imm8); break;
5206 case 5:
5207 testimm8 = True; imm64 = Replicate16x4(imm8 << 8); break;
5208 case 6:
5209 testimm8 = True;
5210 if ((cmode & 1) == 0)
5211 imm64 = Replicate32x2((imm8 << 8) | 0xFF);
5212 else
5213 imm64 = Replicate32x2((imm8 << 16) | 0xFFFF);
5214 break;
5215 case 7:
5216 testimm8 = False;
5217 if ((cmode & 1) == 0 && op == 0)
5218 imm64 = Replicate8x8(imm8);
5219 if ((cmode & 1) == 0 && op == 1) {
5220 imm64 = 0; imm64 |= (imm8 & 0x80) ? 0xFF : 0x00;
5221 imm64 <<= 8; imm64 |= (imm8 & 0x40) ? 0xFF : 0x00;
5222 imm64 <<= 8; imm64 |= (imm8 & 0x20) ? 0xFF : 0x00;
5223 imm64 <<= 8; imm64 |= (imm8 & 0x10) ? 0xFF : 0x00;
5224 imm64 <<= 8; imm64 |= (imm8 & 0x08) ? 0xFF : 0x00;
5225 imm64 <<= 8; imm64 |= (imm8 & 0x04) ? 0xFF : 0x00;
5226 imm64 <<= 8; imm64 |= (imm8 & 0x02) ? 0xFF : 0x00;
5227 imm64 <<= 8; imm64 |= (imm8 & 0x01) ? 0xFF : 0x00;
5228 }
5229 if ((cmode & 1) == 1 && op == 0) {
5230 ULong imm8_7 = (imm8 >> 7) & 1;
5231 ULong imm8_6 = (imm8 >> 6) & 1;
5232 ULong imm8_50 = imm8 & 63;
5233 ULong imm32 = (imm8_7 << (1 + 5 + 6 + 19))
5234 | ((imm8_6 ^ 1) << (5 + 6 + 19))
5235 | (Replicate(imm8_6, 5) << (6 + 19))
5236 | (imm8_50 << 19);
5237 imm64 = Replicate32x2(imm32);
5238 }
5239 if ((cmode & 1) == 1 && op == 1) {
5240 // imm64 = imm8<7>:NOT(imm8<6>)
5241 // :Replicate(imm8<6>,8):imm8<5:0>:Zeros(48);
5242 ULong imm8_7 = (imm8 >> 7) & 1;
5243 ULong imm8_6 = (imm8 >> 6) & 1;
5244 ULong imm8_50 = imm8 & 63;
5245 imm64 = (imm8_7 << 63) | ((imm8_6 ^ 1) << 62)
5246 | (Replicate(imm8_6, 8) << 54)
5247 | (imm8_50 << 48);
5248 }
5249 break;
5250 default:
5251 vassert(0);
5252 }
5253
5254 if (testimm8 && imm8 == 0)
5255 return False;
5256
5257 *res = imm64;
5258 return True;
5259}
5260
sewardj606c4ba2014-01-26 19:11:14 +00005261/* Help a bit for decoding laneage for vector operations that can be
5262 of the form 4x32, 2x64 or 2x32-and-zero-upper-half, as encoded by Q
5263 and SZ bits, typically for vector floating point. */
5264static Bool getLaneInfo_Q_SZ ( /*OUT*/IRType* tyI, /*OUT*/IRType* tyF,
5265 /*OUT*/UInt* nLanes, /*OUT*/Bool* zeroUpper,
5266 /*OUT*/const HChar** arrSpec,
5267 Bool bitQ, Bool bitSZ )
5268{
5269 vassert(bitQ == True || bitQ == False);
5270 vassert(bitSZ == True || bitSZ == False);
5271 if (bitQ && bitSZ) { // 2x64
5272 if (tyI) *tyI = Ity_I64;
5273 if (tyF) *tyF = Ity_F64;
5274 if (nLanes) *nLanes = 2;
5275 if (zeroUpper) *zeroUpper = False;
5276 if (arrSpec) *arrSpec = "2d";
5277 return True;
5278 }
5279 if (bitQ && !bitSZ) { // 4x32
5280 if (tyI) *tyI = Ity_I32;
5281 if (tyF) *tyF = Ity_F32;
5282 if (nLanes) *nLanes = 4;
5283 if (zeroUpper) *zeroUpper = False;
5284 if (arrSpec) *arrSpec = "4s";
5285 return True;
5286 }
5287 if (!bitQ && !bitSZ) { // 2x32
5288 if (tyI) *tyI = Ity_I32;
5289 if (tyF) *tyF = Ity_F32;
5290 if (nLanes) *nLanes = 2;
5291 if (zeroUpper) *zeroUpper = True;
5292 if (arrSpec) *arrSpec = "2s";
5293 return True;
5294 }
5295 // Else impliedly 1x64, which isn't allowed.
5296 return False;
5297}
5298
sewardje520bb32014-02-17 11:00:53 +00005299/* Helper for decoding laneage for shift-style vector operations
5300 that involve an immediate shift amount. */
5301static Bool getLaneInfo_IMMH_IMMB ( /*OUT*/UInt* shift, /*OUT*/UInt* szBlg2,
5302 UInt immh, UInt immb )
5303{
5304 vassert(immh < (1<<4));
5305 vassert(immb < (1<<3));
5306 UInt immhb = (immh << 3) | immb;
5307 if (immh & 8) {
5308 if (shift) *shift = 128 - immhb;
5309 if (szBlg2) *szBlg2 = 3;
5310 return True;
5311 }
5312 if (immh & 4) {
5313 if (shift) *shift = 64 - immhb;
5314 if (szBlg2) *szBlg2 = 2;
5315 return True;
5316 }
5317 if (immh & 2) {
5318 if (shift) *shift = 32 - immhb;
5319 if (szBlg2) *szBlg2 = 1;
5320 return True;
5321 }
5322 if (immh & 1) {
5323 if (shift) *shift = 16 - immhb;
5324 if (szBlg2) *szBlg2 = 0;
5325 return True;
5326 }
5327 return False;
5328}
5329
sewardjecde6972014-02-05 11:01:19 +00005330/* Generate IR to fold all lanes of the V128 value in 'src' as
5331 characterised by the operator 'op', and return the result in the
5332 bottom bits of a V128, with all other bits set to zero. */
5333static IRTemp math_MINMAXV ( IRTemp src, IROp op )
5334{
5335 /* The basic idea is to use repeated applications of Iop_CatEven*
5336 and Iop_CatOdd* operators to 'src' so as to clone each lane into
5337 a complete vector. Then fold all those vectors with 'op' and
5338 zero out all but the least significant lane. */
5339 switch (op) {
5340 case Iop_Min8Sx16: case Iop_Min8Ux16:
sewardjb9aff1e2014-06-15 21:55:33 +00005341 case Iop_Max8Sx16: case Iop_Max8Ux16: case Iop_Add8x16: {
sewardjfab09142014-02-10 10:28:13 +00005342 /* NB: temp naming here is misleading -- the naming is for 8
5343 lanes of 16 bit, whereas what is being operated on is 16
5344 lanes of 8 bits. */
5345 IRTemp x76543210 = src;
5346 IRTemp x76547654 = newTemp(Ity_V128);
5347 IRTemp x32103210 = newTemp(Ity_V128);
5348 assign(x76547654, mk_CatOddLanes64x2 (x76543210, x76543210));
5349 assign(x32103210, mk_CatEvenLanes64x2(x76543210, x76543210));
5350 IRTemp x76767676 = newTemp(Ity_V128);
5351 IRTemp x54545454 = newTemp(Ity_V128);
5352 IRTemp x32323232 = newTemp(Ity_V128);
5353 IRTemp x10101010 = newTemp(Ity_V128);
5354 assign(x76767676, mk_CatOddLanes32x4 (x76547654, x76547654));
5355 assign(x54545454, mk_CatEvenLanes32x4(x76547654, x76547654));
5356 assign(x32323232, mk_CatOddLanes32x4 (x32103210, x32103210));
5357 assign(x10101010, mk_CatEvenLanes32x4(x32103210, x32103210));
5358 IRTemp x77777777 = newTemp(Ity_V128);
5359 IRTemp x66666666 = newTemp(Ity_V128);
5360 IRTemp x55555555 = newTemp(Ity_V128);
5361 IRTemp x44444444 = newTemp(Ity_V128);
5362 IRTemp x33333333 = newTemp(Ity_V128);
5363 IRTemp x22222222 = newTemp(Ity_V128);
5364 IRTemp x11111111 = newTemp(Ity_V128);
5365 IRTemp x00000000 = newTemp(Ity_V128);
5366 assign(x77777777, mk_CatOddLanes16x8 (x76767676, x76767676));
5367 assign(x66666666, mk_CatEvenLanes16x8(x76767676, x76767676));
5368 assign(x55555555, mk_CatOddLanes16x8 (x54545454, x54545454));
5369 assign(x44444444, mk_CatEvenLanes16x8(x54545454, x54545454));
5370 assign(x33333333, mk_CatOddLanes16x8 (x32323232, x32323232));
5371 assign(x22222222, mk_CatEvenLanes16x8(x32323232, x32323232));
5372 assign(x11111111, mk_CatOddLanes16x8 (x10101010, x10101010));
5373 assign(x00000000, mk_CatEvenLanes16x8(x10101010, x10101010));
5374 /* Naming not misleading after here. */
5375 IRTemp xAllF = newTemp(Ity_V128);
5376 IRTemp xAllE = newTemp(Ity_V128);
5377 IRTemp xAllD = newTemp(Ity_V128);
5378 IRTemp xAllC = newTemp(Ity_V128);
5379 IRTemp xAllB = newTemp(Ity_V128);
5380 IRTemp xAllA = newTemp(Ity_V128);
5381 IRTemp xAll9 = newTemp(Ity_V128);
5382 IRTemp xAll8 = newTemp(Ity_V128);
5383 IRTemp xAll7 = newTemp(Ity_V128);
5384 IRTemp xAll6 = newTemp(Ity_V128);
5385 IRTemp xAll5 = newTemp(Ity_V128);
5386 IRTemp xAll4 = newTemp(Ity_V128);
5387 IRTemp xAll3 = newTemp(Ity_V128);
5388 IRTemp xAll2 = newTemp(Ity_V128);
5389 IRTemp xAll1 = newTemp(Ity_V128);
5390 IRTemp xAll0 = newTemp(Ity_V128);
5391 assign(xAllF, mk_CatOddLanes8x16 (x77777777, x77777777));
5392 assign(xAllE, mk_CatEvenLanes8x16(x77777777, x77777777));
5393 assign(xAllD, mk_CatOddLanes8x16 (x66666666, x66666666));
5394 assign(xAllC, mk_CatEvenLanes8x16(x66666666, x66666666));
5395 assign(xAllB, mk_CatOddLanes8x16 (x55555555, x55555555));
5396 assign(xAllA, mk_CatEvenLanes8x16(x55555555, x55555555));
5397 assign(xAll9, mk_CatOddLanes8x16 (x44444444, x44444444));
5398 assign(xAll8, mk_CatEvenLanes8x16(x44444444, x44444444));
5399 assign(xAll7, mk_CatOddLanes8x16 (x33333333, x33333333));
5400 assign(xAll6, mk_CatEvenLanes8x16(x33333333, x33333333));
5401 assign(xAll5, mk_CatOddLanes8x16 (x22222222, x22222222));
5402 assign(xAll4, mk_CatEvenLanes8x16(x22222222, x22222222));
5403 assign(xAll3, mk_CatOddLanes8x16 (x11111111, x11111111));
5404 assign(xAll2, mk_CatEvenLanes8x16(x11111111, x11111111));
5405 assign(xAll1, mk_CatOddLanes8x16 (x00000000, x00000000));
5406 assign(xAll0, mk_CatEvenLanes8x16(x00000000, x00000000));
5407 IRTemp maxFE = newTemp(Ity_V128);
5408 IRTemp maxDC = newTemp(Ity_V128);
5409 IRTemp maxBA = newTemp(Ity_V128);
5410 IRTemp max98 = newTemp(Ity_V128);
5411 IRTemp max76 = newTemp(Ity_V128);
5412 IRTemp max54 = newTemp(Ity_V128);
5413 IRTemp max32 = newTemp(Ity_V128);
5414 IRTemp max10 = newTemp(Ity_V128);
5415 assign(maxFE, binop(op, mkexpr(xAllF), mkexpr(xAllE)));
5416 assign(maxDC, binop(op, mkexpr(xAllD), mkexpr(xAllC)));
5417 assign(maxBA, binop(op, mkexpr(xAllB), mkexpr(xAllA)));
5418 assign(max98, binop(op, mkexpr(xAll9), mkexpr(xAll8)));
5419 assign(max76, binop(op, mkexpr(xAll7), mkexpr(xAll6)));
5420 assign(max54, binop(op, mkexpr(xAll5), mkexpr(xAll4)));
5421 assign(max32, binop(op, mkexpr(xAll3), mkexpr(xAll2)));
5422 assign(max10, binop(op, mkexpr(xAll1), mkexpr(xAll0)));
5423 IRTemp maxFEDC = newTemp(Ity_V128);
5424 IRTemp maxBA98 = newTemp(Ity_V128);
5425 IRTemp max7654 = newTemp(Ity_V128);
5426 IRTemp max3210 = newTemp(Ity_V128);
5427 assign(maxFEDC, binop(op, mkexpr(maxFE), mkexpr(maxDC)));
5428 assign(maxBA98, binop(op, mkexpr(maxBA), mkexpr(max98)));
5429 assign(max7654, binop(op, mkexpr(max76), mkexpr(max54)));
5430 assign(max3210, binop(op, mkexpr(max32), mkexpr(max10)));
5431 IRTemp maxFEDCBA98 = newTemp(Ity_V128);
5432 IRTemp max76543210 = newTemp(Ity_V128);
5433 assign(maxFEDCBA98, binop(op, mkexpr(maxFEDC), mkexpr(maxBA98)));
5434 assign(max76543210, binop(op, mkexpr(max7654), mkexpr(max3210)));
5435 IRTemp maxAllLanes = newTemp(Ity_V128);
5436 assign(maxAllLanes, binop(op, mkexpr(maxFEDCBA98),
5437 mkexpr(max76543210)));
5438 IRTemp res = newTemp(Ity_V128);
5439 assign(res, unop(Iop_ZeroHI120ofV128, mkexpr(maxAllLanes)));
5440 return res;
sewardjecde6972014-02-05 11:01:19 +00005441 }
5442 case Iop_Min16Sx8: case Iop_Min16Ux8:
sewardjb9aff1e2014-06-15 21:55:33 +00005443 case Iop_Max16Sx8: case Iop_Max16Ux8: case Iop_Add16x8: {
sewardjecde6972014-02-05 11:01:19 +00005444 IRTemp x76543210 = src;
5445 IRTemp x76547654 = newTemp(Ity_V128);
5446 IRTemp x32103210 = newTemp(Ity_V128);
5447 assign(x76547654, mk_CatOddLanes64x2 (x76543210, x76543210));
5448 assign(x32103210, mk_CatEvenLanes64x2(x76543210, x76543210));
5449 IRTemp x76767676 = newTemp(Ity_V128);
5450 IRTemp x54545454 = newTemp(Ity_V128);
5451 IRTemp x32323232 = newTemp(Ity_V128);
5452 IRTemp x10101010 = newTemp(Ity_V128);
5453 assign(x76767676, mk_CatOddLanes32x4 (x76547654, x76547654));
5454 assign(x54545454, mk_CatEvenLanes32x4(x76547654, x76547654));
5455 assign(x32323232, mk_CatOddLanes32x4 (x32103210, x32103210));
5456 assign(x10101010, mk_CatEvenLanes32x4(x32103210, x32103210));
5457 IRTemp x77777777 = newTemp(Ity_V128);
5458 IRTemp x66666666 = newTemp(Ity_V128);
5459 IRTemp x55555555 = newTemp(Ity_V128);
5460 IRTemp x44444444 = newTemp(Ity_V128);
5461 IRTemp x33333333 = newTemp(Ity_V128);
5462 IRTemp x22222222 = newTemp(Ity_V128);
5463 IRTemp x11111111 = newTemp(Ity_V128);
5464 IRTemp x00000000 = newTemp(Ity_V128);
5465 assign(x77777777, mk_CatOddLanes16x8 (x76767676, x76767676));
5466 assign(x66666666, mk_CatEvenLanes16x8(x76767676, x76767676));
5467 assign(x55555555, mk_CatOddLanes16x8 (x54545454, x54545454));
5468 assign(x44444444, mk_CatEvenLanes16x8(x54545454, x54545454));
5469 assign(x33333333, mk_CatOddLanes16x8 (x32323232, x32323232));
5470 assign(x22222222, mk_CatEvenLanes16x8(x32323232, x32323232));
5471 assign(x11111111, mk_CatOddLanes16x8 (x10101010, x10101010));
5472 assign(x00000000, mk_CatEvenLanes16x8(x10101010, x10101010));
5473 IRTemp max76 = newTemp(Ity_V128);
5474 IRTemp max54 = newTemp(Ity_V128);
5475 IRTemp max32 = newTemp(Ity_V128);
5476 IRTemp max10 = newTemp(Ity_V128);
5477 assign(max76, binop(op, mkexpr(x77777777), mkexpr(x66666666)));
5478 assign(max54, binop(op, mkexpr(x55555555), mkexpr(x44444444)));
5479 assign(max32, binop(op, mkexpr(x33333333), mkexpr(x22222222)));
5480 assign(max10, binop(op, mkexpr(x11111111), mkexpr(x00000000)));
5481 IRTemp max7654 = newTemp(Ity_V128);
5482 IRTemp max3210 = newTemp(Ity_V128);
5483 assign(max7654, binop(op, mkexpr(max76), mkexpr(max54)));
5484 assign(max3210, binop(op, mkexpr(max32), mkexpr(max10)));
5485 IRTemp max76543210 = newTemp(Ity_V128);
5486 assign(max76543210, binop(op, mkexpr(max7654), mkexpr(max3210)));
5487 IRTemp res = newTemp(Ity_V128);
5488 assign(res, unop(Iop_ZeroHI112ofV128, mkexpr(max76543210)));
5489 return res;
5490 }
5491 case Iop_Min32Sx4: case Iop_Min32Ux4:
sewardjb9aff1e2014-06-15 21:55:33 +00005492 case Iop_Max32Sx4: case Iop_Max32Ux4: case Iop_Add32x4: {
sewardjecde6972014-02-05 11:01:19 +00005493 IRTemp x3210 = src;
5494 IRTemp x3232 = newTemp(Ity_V128);
5495 IRTemp x1010 = newTemp(Ity_V128);
5496 assign(x3232, mk_CatOddLanes64x2 (x3210, x3210));
5497 assign(x1010, mk_CatEvenLanes64x2(x3210, x3210));
5498 IRTemp x3333 = newTemp(Ity_V128);
5499 IRTemp x2222 = newTemp(Ity_V128);
5500 IRTemp x1111 = newTemp(Ity_V128);
5501 IRTemp x0000 = newTemp(Ity_V128);
5502 assign(x3333, mk_CatOddLanes32x4 (x3232, x3232));
5503 assign(x2222, mk_CatEvenLanes32x4(x3232, x3232));
5504 assign(x1111, mk_CatOddLanes32x4 (x1010, x1010));
5505 assign(x0000, mk_CatEvenLanes32x4(x1010, x1010));
5506 IRTemp max32 = newTemp(Ity_V128);
5507 IRTemp max10 = newTemp(Ity_V128);
5508 assign(max32, binop(op, mkexpr(x3333), mkexpr(x2222)));
5509 assign(max10, binop(op, mkexpr(x1111), mkexpr(x0000)));
5510 IRTemp max3210 = newTemp(Ity_V128);
5511 assign(max3210, binop(op, mkexpr(max32), mkexpr(max10)));
5512 IRTemp res = newTemp(Ity_V128);
5513 assign(res, unop(Iop_ZeroHI96ofV128, mkexpr(max3210)));
5514 return res;
5515 }
5516 default:
5517 vassert(0);
5518 }
5519}
5520
5521
sewardj92d0ae32014-04-03 13:48:54 +00005522/* Generate IR for TBL and TBX. This deals with the 128 bit case
5523 only. */
5524static IRTemp math_TBL_TBX ( IRTemp tab[4], UInt len, IRTemp src,
5525 IRTemp oor_values )
5526{
5527 vassert(len >= 0 && len <= 3);
5528
5529 /* Generate some useful constants as concisely as possible. */
5530 IRTemp half15 = newTemp(Ity_I64);
5531 assign(half15, mkU64(0x0F0F0F0F0F0F0F0FULL));
5532 IRTemp half16 = newTemp(Ity_I64);
5533 assign(half16, mkU64(0x1010101010101010ULL));
5534
5535 /* A zero vector */
5536 IRTemp allZero = newTemp(Ity_V128);
5537 assign(allZero, mkV128(0x0000));
5538 /* A vector containing 15 in each 8-bit lane */
5539 IRTemp all15 = newTemp(Ity_V128);
5540 assign(all15, binop(Iop_64HLtoV128, mkexpr(half15), mkexpr(half15)));
5541 /* A vector containing 16 in each 8-bit lane */
5542 IRTemp all16 = newTemp(Ity_V128);
5543 assign(all16, binop(Iop_64HLtoV128, mkexpr(half16), mkexpr(half16)));
5544 /* A vector containing 32 in each 8-bit lane */
5545 IRTemp all32 = newTemp(Ity_V128);
5546 assign(all32, binop(Iop_Add8x16, mkexpr(all16), mkexpr(all16)));
5547 /* A vector containing 48 in each 8-bit lane */
5548 IRTemp all48 = newTemp(Ity_V128);
5549 assign(all48, binop(Iop_Add8x16, mkexpr(all16), mkexpr(all32)));
5550 /* A vector containing 64 in each 8-bit lane */
5551 IRTemp all64 = newTemp(Ity_V128);
5552 assign(all64, binop(Iop_Add8x16, mkexpr(all32), mkexpr(all32)));
5553
5554 /* Group the 16/32/48/64 vectors so as to be indexable. */
5555 IRTemp allXX[4] = { all16, all32, all48, all64 };
5556
5557 /* Compute the result for each table vector, with zeroes in places
5558 where the index values are out of range, and OR them into the
5559 running vector. */
5560 IRTemp running_result = newTemp(Ity_V128);
5561 assign(running_result, mkV128(0));
5562
5563 UInt tabent;
5564 for (tabent = 0; tabent <= len; tabent++) {
5565 vassert(tabent >= 0 && tabent < 4);
5566 IRTemp bias = newTemp(Ity_V128);
5567 assign(bias,
5568 mkexpr(tabent == 0 ? allZero : allXX[tabent-1]));
5569 IRTemp biased_indices = newTemp(Ity_V128);
5570 assign(biased_indices,
5571 binop(Iop_Sub8x16, mkexpr(src), mkexpr(bias)));
5572 IRTemp valid_mask = newTemp(Ity_V128);
5573 assign(valid_mask,
5574 binop(Iop_CmpGT8Ux16, mkexpr(all16), mkexpr(biased_indices)));
5575 IRTemp safe_biased_indices = newTemp(Ity_V128);
5576 assign(safe_biased_indices,
5577 binop(Iop_AndV128, mkexpr(biased_indices), mkexpr(all15)));
5578 IRTemp results_or_junk = newTemp(Ity_V128);
5579 assign(results_or_junk,
5580 binop(Iop_Perm8x16, mkexpr(tab[tabent]),
5581 mkexpr(safe_biased_indices)));
5582 IRTemp results_or_zero = newTemp(Ity_V128);
5583 assign(results_or_zero,
5584 binop(Iop_AndV128, mkexpr(results_or_junk), mkexpr(valid_mask)));
5585 /* And OR that into the running result. */
5586 IRTemp tmp = newTemp(Ity_V128);
5587 assign(tmp, binop(Iop_OrV128, mkexpr(results_or_zero),
5588 mkexpr(running_result)));
5589 running_result = tmp;
5590 }
5591
5592 /* So now running_result holds the overall result where the indices
5593 are in range, and zero in out-of-range lanes. Now we need to
5594 compute an overall validity mask and use this to copy in the
5595 lanes in the oor_values for out of range indices. This is
5596 unnecessary for TBL but will get folded out by iropt, so we lean
5597 on that and generate the same code for TBL and TBX here. */
5598 IRTemp overall_valid_mask = newTemp(Ity_V128);
5599 assign(overall_valid_mask,
5600 binop(Iop_CmpGT8Ux16, mkexpr(allXX[len]), mkexpr(src)));
5601 IRTemp result = newTemp(Ity_V128);
5602 assign(result,
5603 binop(Iop_OrV128,
5604 mkexpr(running_result),
5605 binop(Iop_AndV128,
5606 mkexpr(oor_values),
5607 unop(Iop_NotV128, mkexpr(overall_valid_mask)))));
5608 return result;
5609}
5610
5611
sewardj31b5a952014-06-26 07:41:14 +00005612/* Let |argL| and |argR| be V128 values, and let |opI64x2toV128| be
5613 an op which takes two I64s and produces a V128. That is, a widening
5614 operator. Generate IR which applies |opI64x2toV128| to either the
5615 lower (if |is2| is False) or upper (if |is2| is True) halves of
5616 |argL| and |argR|, and return the value in a new IRTemp.
5617*/
5618static
5619IRTemp math_BINARY_WIDENING_V128 ( Bool is2, IROp opI64x2toV128,
5620 IRExpr* argL, IRExpr* argR )
5621{
5622 IRTemp res = newTemp(Ity_V128);
5623 IROp slice = is2 ? Iop_V128HIto64 : Iop_V128to64;
5624 assign(res, binop(opI64x2toV128, unop(slice, argL),
5625 unop(slice, argR)));
5626 return res;
5627}
5628
5629
sewardj25523c42014-06-15 19:36:29 +00005630/* Let |new64| be a V128 in which only the lower 64 bits are interesting,
5631 and the upper can contain any value -- it is ignored. If |is2| is False,
5632 generate IR to put |new64| in the lower half of vector reg |dd| and zero
5633 the upper half. If |is2| is True, generate IR to put |new64| in the upper
5634 half of vector reg |dd| and leave the lower half unchanged. This
5635 simulates the behaviour of the "foo/foo2" instructions in which the
5636 destination is half the width of sources, for example addhn/addhn2.
5637*/
5638static
5639void putLO64andZUorPutHI64 ( Bool is2, UInt dd, IRTemp new64 )
5640{
5641 if (is2) {
5642 /* Get the old contents of Vdd, zero the upper half, and replace
5643 it with 'x'. */
5644 IRTemp t_zero_oldLO = newTemp(Ity_V128);
5645 assign(t_zero_oldLO, unop(Iop_ZeroHI64ofV128, getQReg128(dd)));
5646 IRTemp t_newHI_zero = newTemp(Ity_V128);
5647 assign(t_newHI_zero, binop(Iop_InterleaveLO64x2, mkexpr(new64),
5648 mkV128(0x0000)));
5649 IRTemp res = newTemp(Ity_V128);
5650 assign(res, binop(Iop_OrV128, mkexpr(t_zero_oldLO),
5651 mkexpr(t_newHI_zero)));
5652 putQReg128(dd, mkexpr(res));
5653 } else {
5654 /* This is simple. */
5655 putQReg128(dd, unop(Iop_ZeroHI64ofV128, mkexpr(new64)));
5656 }
5657}
5658
5659
sewardj715d1622014-06-26 12:39:05 +00005660/* |fullWidth| is a full V128 width result. Depending on bitQ,
5661 zero out the upper half. */
5662static IRExpr* math_MAYBE_ZERO_HI64 ( UInt bitQ, IRTemp fullWidth )
5663{
5664 if (bitQ == 1) return mkexpr(fullWidth);
5665 if (bitQ == 0) return unop(Iop_ZeroHI64ofV128, mkexpr(fullWidth));
5666 vassert(0);
5667}
5668
5669
sewardjdf1628c2014-06-10 22:52:05 +00005670static
5671Bool dis_AdvSIMD_EXT(/*MB_OUT*/DisResult* dres, UInt insn)
sewardjbbcf1882014-01-12 12:49:10 +00005672{
sewardjab33a7a2014-06-19 22:20:47 +00005673 /* 31 29 23 21 20 15 14 10 9 4
5674 0 q 101110 op2 0 m 0 imm4 0 n d
5675 Decode fields: op2
5676 */
sewardjbbcf1882014-01-12 12:49:10 +00005677# define INSN(_bMax,_bMin) SLICE_UInt(insn, (_bMax), (_bMin))
sewardjab33a7a2014-06-19 22:20:47 +00005678 if (INSN(31,31) != 0
5679 || INSN(29,24) != BITS6(1,0,1,1,1,0)
5680 || INSN(21,21) != 0 || INSN(15,15) != 0 || INSN(10,10) != 0) {
5681 return False;
5682 }
5683 UInt bitQ = INSN(30,30);
5684 UInt op2 = INSN(23,22);
5685 UInt mm = INSN(20,16);
5686 UInt imm4 = INSN(14,11);
5687 UInt nn = INSN(9,5);
5688 UInt dd = INSN(4,0);
5689
5690 if (op2 == BITS2(0,0)) {
5691 /* -------- 00: EXT 16b_16b_16b, 8b_8b_8b -------- */
5692 IRTemp sHi = newTemp(Ity_V128);
5693 IRTemp sLo = newTemp(Ity_V128);
5694 IRTemp res = newTemp(Ity_V128);
5695 assign(sHi, getQReg128(mm));
5696 assign(sLo, getQReg128(nn));
5697 if (bitQ == 1) {
5698 if (imm4 == 0) {
5699 assign(res, mkexpr(sLo));
5700 } else {
5701 vassert(imm4 <= 15);
5702 assign(res,
5703 binop(Iop_OrV128,
5704 binop(Iop_ShlV128, mkexpr(sHi), mkU8(8 * (16-imm4))),
5705 binop(Iop_ShrV128, mkexpr(sLo), mkU8(8 * imm4))));
5706 }
5707 putQReg128(dd, mkexpr(res));
5708 DIP("ext v%u.16b, v%u.16b, v%u.16b, #%u\n", dd, nn, mm, imm4);
5709 } else {
5710 if (imm4 >= 8) return False;
5711 if (imm4 == 0) {
5712 assign(res, mkexpr(sLo));
5713 } else {
5714 assign(res,
5715 binop(Iop_ShrV128,
5716 binop(Iop_InterleaveLO64x2, mkexpr(sHi), mkexpr(sLo)),
5717 mkU8(8 * imm4)));
5718 }
5719 putQReg128(dd, unop(Iop_ZeroHI64ofV128, mkexpr(res)));
5720 DIP("ext v%u.8b, v%u.8b, v%u.8b, #%u\n", dd, nn, mm, imm4);
5721 }
5722 return True;
5723 }
5724
sewardjdf1628c2014-06-10 22:52:05 +00005725 return False;
5726# undef INSN
5727}
sewardjbbcf1882014-01-12 12:49:10 +00005728
sewardjbbcf1882014-01-12 12:49:10 +00005729
sewardjdf1628c2014-06-10 22:52:05 +00005730static
5731Bool dis_AdvSIMD_TBL_TBX(/*MB_OUT*/DisResult* dres, UInt insn)
5732{
5733 /* 31 29 23 21 20 15 14 12 11 9 4
5734 0 q 001110 op2 0 m 0 len op 00 n d
5735 Decode fields: op2,len,op
sewardjbbcf1882014-01-12 12:49:10 +00005736 */
sewardjdf1628c2014-06-10 22:52:05 +00005737# define INSN(_bMax,_bMin) SLICE_UInt(insn, (_bMax), (_bMin))
5738 if (INSN(31,31) != 0
5739 || INSN(29,24) != BITS6(0,0,1,1,1,0)
5740 || INSN(21,21) != 0
5741 || INSN(15,15) != 0
5742 || INSN(11,10) != BITS2(0,0)) {
5743 return False;
5744 }
5745 UInt bitQ = INSN(30,30);
5746 UInt op2 = INSN(23,22);
5747 UInt mm = INSN(20,16);
5748 UInt len = INSN(14,13);
5749 UInt bitOP = INSN(12,12);
5750 UInt nn = INSN(9,5);
5751 UInt dd = INSN(4,0);
5752
5753 if (op2 == X00) {
5754 /* -------- 00,xx,0 TBL, xx register table -------- */
5755 /* -------- 00,xx,1 TBX, xx register table -------- */
5756 /* 31 28 20 15 14 12 9 4
5757 0q0 01110 000 m 0 len 000 n d TBL Vd.Ta, {Vn .. V(n+len)%32}, Vm.Ta
5758 0q0 01110 000 m 0 len 100 n d TBX Vd.Ta, {Vn .. V(n+len)%32}, Vm.Ta
5759 where Ta = 16b(q=1) or 8b(q=0)
5760 */
5761 Bool isQ = bitQ == 1;
5762 Bool isTBX = bitOP == 1;
5763 /* The out-of-range values to use. */
5764 IRTemp oor_values = newTemp(Ity_V128);
5765 assign(oor_values, isTBX ? getQReg128(dd) : mkV128(0));
5766 /* src value */
5767 IRTemp src = newTemp(Ity_V128);
5768 assign(src, getQReg128(mm));
5769 /* The table values */
5770 IRTemp tab[4];
5771 UInt i;
5772 for (i = 0; i <= len; i++) {
5773 vassert(i < 4);
5774 tab[i] = newTemp(Ity_V128);
5775 assign(tab[i], getQReg128((nn + i) % 32));
5776 }
5777 IRTemp res = math_TBL_TBX(tab, len, src, oor_values);
5778 putQReg128(dd, isQ ? mkexpr(res)
5779 : unop(Iop_ZeroHI64ofV128, mkexpr(res)) );
5780 const HChar* Ta = isQ ? "16b" : "8b";
5781 const HChar* nm = isTBX ? "tbx" : "tbl";
5782 DIP("%s %s.%s, {v%d.16b .. v%d.16b}, %s.%s\n",
5783 nm, nameQReg128(dd), Ta, nn, (nn + len) % 32, nameQReg128(mm), Ta);
5784 return True;
5785 }
5786
5787# define INSN(_bMax,_bMin) SLICE_UInt(insn, (_bMax), (_bMin))
5788 return False;
5789# undef INSN
5790}
5791
5792
5793static
5794Bool dis_AdvSIMD_ZIP_UZP_TRN(/*MB_OUT*/DisResult* dres, UInt insn)
5795{
5796# define INSN(_bMax,_bMin) SLICE_UInt(insn, (_bMax), (_bMin))
5797 return False;
5798# undef INSN
5799}
5800
5801
5802static
5803Bool dis_AdvSIMD_across_lanes(/*MB_OUT*/DisResult* dres, UInt insn)
5804{
5805 /* 31 28 23 21 16 11 9 4
5806 0 q u 01110 size 11000 opcode 10 n d
5807 Decode fields: u,size,opcode
5808 */
5809# define INSN(_bMax,_bMin) SLICE_UInt(insn, (_bMax), (_bMin))
5810 if (INSN(31,31) != 0
5811 || INSN(28,24) != BITS5(0,1,1,1,0)
5812 || INSN(21,17) != BITS5(1,1,0,0,0) || INSN(11,10) != BITS2(1,0)) {
5813 return False;
5814 }
5815 UInt bitQ = INSN(30,30);
5816 UInt bitU = INSN(29,29);
5817 UInt size = INSN(23,22);
5818 UInt opcode = INSN(16,12);
5819 UInt nn = INSN(9,5);
5820 UInt dd = INSN(4,0);
5821
sewardjb9aff1e2014-06-15 21:55:33 +00005822 UInt ix = 0;
5823 /**/ if (opcode == BITS5(0,1,0,1,0)) { ix = bitU == 0 ? 1 : 2; }
5824 else if (opcode == BITS5(1,1,0,1,0)) { ix = bitU == 0 ? 3 : 4; }
5825 else if (opcode == BITS5(1,1,0,1,1) && bitU == 0) { ix = 5; }
5826 /**/
5827 if (ix != 0) {
5828 /* -------- 0,xx,01010: SMAXV -------- (1) */
5829 /* -------- 1,xx,01010: UMAXV -------- (2) */
5830 /* -------- 0,xx,11010: SMINV -------- (3) */
5831 /* -------- 1,xx,11010: UMINV -------- (4) */
5832 /* -------- 0,xx,11011: ADDV -------- (5) */
5833 vassert(ix >= 1 && ix <= 5);
sewardjdf1628c2014-06-10 22:52:05 +00005834 if (size == X11) return False; // 1d,2d cases not allowed
5835 if (size == X10 && bitQ == 0) return False; // 2s case not allowed
sewardjdf1628c2014-06-10 22:52:05 +00005836 const IROp opMAXS[3]
5837 = { Iop_Max8Sx16, Iop_Max16Sx8, Iop_Max32Sx4 };
5838 const IROp opMAXU[3]
5839 = { Iop_Max8Ux16, Iop_Max16Ux8, Iop_Max32Ux4 };
sewardjb9aff1e2014-06-15 21:55:33 +00005840 const IROp opMINS[3]
5841 = { Iop_Min8Sx16, Iop_Min16Sx8, Iop_Min32Sx4 };
5842 const IROp opMINU[3]
5843 = { Iop_Min8Ux16, Iop_Min16Ux8, Iop_Min32Ux4 };
5844 const IROp opADD[3]
5845 = { Iop_Add8x16, Iop_Add16x8, Iop_Add32x4 };
sewardjdf1628c2014-06-10 22:52:05 +00005846 vassert(size < 3);
sewardjb9aff1e2014-06-15 21:55:33 +00005847 IROp op = Iop_INVALID;
5848 const HChar* nm = NULL;
5849 switch (ix) {
5850 case 1: op = opMAXS[size]; nm = "smaxv"; break;
5851 case 2: op = opMAXU[size]; nm = "umaxv"; break;
5852 case 3: op = opMINS[size]; nm = "sminv"; break;
5853 case 4: op = opMINU[size]; nm = "uminv"; break;
5854 case 5: op = opADD[size]; nm = "addv"; break;
5855 default: vassert(0);
5856 }
5857 vassert(op != Iop_INVALID && nm != NULL);
sewardjdf1628c2014-06-10 22:52:05 +00005858 IRTemp tN1 = newTemp(Ity_V128);
5859 assign(tN1, getQReg128(nn));
5860 /* If Q == 0, we're just folding lanes in the lower half of
5861 the value. In which case, copy the lower half of the
5862 source into the upper half, so we can then treat it the
sewardjb9aff1e2014-06-15 21:55:33 +00005863 same as the full width case. Except for the addition case,
5864 in which we have to zero out the upper half. */
sewardjdf1628c2014-06-10 22:52:05 +00005865 IRTemp tN2 = newTemp(Ity_V128);
sewardjb9aff1e2014-06-15 21:55:33 +00005866 assign(tN2, bitQ == 0
5867 ? (ix == 5 ? unop(Iop_ZeroHI64ofV128, mkexpr(tN1))
5868 : mk_CatEvenLanes64x2(tN1,tN1))
5869 : mkexpr(tN1));
sewardjdf1628c2014-06-10 22:52:05 +00005870 IRTemp res = math_MINMAXV(tN2, op);
5871 if (res == IRTemp_INVALID)
5872 return False; /* means math_MINMAXV
5873 doesn't handle this case yet */
5874 putQReg128(dd, mkexpr(res));
sewardjdf1628c2014-06-10 22:52:05 +00005875 const IRType tys[3] = { Ity_I8, Ity_I16, Ity_I32 };
5876 IRType laneTy = tys[size];
5877 const HChar* arr = nameArr_Q_SZ(bitQ, size);
5878 DIP("%s %s, %s.%s\n", nm,
5879 nameQRegLO(dd, laneTy), nameQReg128(nn), arr);
5880 return True;
5881 }
5882
5883# define INSN(_bMax,_bMin) SLICE_UInt(insn, (_bMax), (_bMin))
5884 return False;
5885# undef INSN
5886}
5887
5888
5889static
5890Bool dis_AdvSIMD_copy(/*MB_OUT*/DisResult* dres, UInt insn)
5891{
5892 /* 31 28 20 15 14 10 9 4
5893 0 q op 01110000 imm5 0 imm4 1 n d
5894 Decode fields: q,op,imm4
5895 */
5896# define INSN(_bMax,_bMin) SLICE_UInt(insn, (_bMax), (_bMin))
5897 if (INSN(31,31) != 0
5898 || INSN(28,21) != BITS8(0,1,1,1,0,0,0,0)
5899 || INSN(15,15) != 0 || INSN(10,10) != 1) {
5900 return False;
5901 }
5902 UInt bitQ = INSN(30,30);
5903 UInt bitOP = INSN(29,29);
5904 UInt imm5 = INSN(20,16);
5905 UInt imm4 = INSN(14,11);
5906 UInt nn = INSN(9,5);
5907 UInt dd = INSN(4,0);
5908
5909 /* -------- x,0,0000: DUP (element, vector) -------- */
5910 /* 31 28 20 15 9 4
5911 0q0 01110000 imm5 000001 n d DUP Vd.T, Vn.Ts[index]
5912 */
5913 if (bitOP == 0 && imm4 == BITS4(0,0,0,0)) {
5914 Bool isQ = bitQ == 1;
5915 IRTemp w0 = newTemp(Ity_I64);
5916 const HChar* arT = "??";
5917 const HChar* arTs = "??";
5918 IRType laneTy = Ity_INVALID;
5919 UInt laneNo = 16; /* invalid */
5920 if (imm5 & 1) {
5921 arT = isQ ? "16b" : "8b";
5922 arTs = "b";
5923 laneNo = (imm5 >> 1) & 15;
5924 laneTy = Ity_I8;
5925 assign(w0, unop(Iop_8Uto64, getQRegLane(nn, laneNo, laneTy)));
5926 }
5927 else if (imm5 & 2) {
5928 arT = isQ ? "8h" : "4h";
5929 arTs = "h";
5930 laneNo = (imm5 >> 2) & 7;
5931 laneTy = Ity_I16;
5932 assign(w0, unop(Iop_16Uto64, getQRegLane(nn, laneNo, laneTy)));
5933 }
5934 else if (imm5 & 4) {
5935 arT = isQ ? "4s" : "2s";
5936 arTs = "s";
5937 laneNo = (imm5 >> 3) & 3;
5938 laneTy = Ity_I32;
5939 assign(w0, unop(Iop_32Uto64, getQRegLane(nn, laneNo, laneTy)));
5940 }
5941 else if ((imm5 & 8) && isQ) {
5942 arT = "2d";
5943 arTs = "d";
5944 laneNo = (imm5 >> 4) & 1;
5945 laneTy = Ity_I64;
5946 assign(w0, getQRegLane(nn, laneNo, laneTy));
5947 }
5948 else {
5949 /* invalid; leave laneTy unchanged. */
5950 }
5951 /* */
5952 if (laneTy != Ity_INVALID) {
5953 vassert(laneNo < 16);
5954 IRTemp w1 = math_DUP_TO_64(w0, laneTy);
5955 putQReg128(dd, binop(Iop_64HLtoV128,
5956 isQ ? mkexpr(w1) : mkU64(0), mkexpr(w1)));
5957 DIP("dup %s.%s, %s.%s[%u]\n",
5958 nameQReg128(dd), arT, nameQReg128(nn), arTs, laneNo);
5959 return True;
5960 }
sewardj787a67f2014-06-23 09:09:41 +00005961 /* invalid */
5962 return False;
sewardjdf1628c2014-06-10 22:52:05 +00005963 }
5964
5965 /* -------- x,0,0001: DUP (general, vector) -------- */
5966 /* 31 28 20 15 9 4
5967 0q0 01110000 imm5 0 0001 1 n d DUP Vd.T, Rn
5968 Q=0 writes 64, Q=1 writes 128
5969 imm5: xxxx1 8B(q=0) or 16b(q=1), R=W
5970 xxx10 4H(q=0) or 8H(q=1), R=W
5971 xx100 2S(q=0) or 4S(q=1), R=W
5972 x1000 Invalid(q=0) or 2D(q=1), R=X
5973 x0000 Invalid(q=0) or Invalid(q=1)
5974 Require op=0, imm4=0001
5975 */
5976 if (bitOP == 0 && imm4 == BITS4(0,0,0,1)) {
5977 Bool isQ = bitQ == 1;
5978 IRTemp w0 = newTemp(Ity_I64);
5979 const HChar* arT = "??";
5980 IRType laneTy = Ity_INVALID;
5981 if (imm5 & 1) {
5982 arT = isQ ? "16b" : "8b";
5983 laneTy = Ity_I8;
5984 assign(w0, unop(Iop_8Uto64, unop(Iop_64to8, getIReg64orZR(nn))));
5985 }
5986 else if (imm5 & 2) {
5987 arT = isQ ? "8h" : "4h";
5988 laneTy = Ity_I16;
5989 assign(w0, unop(Iop_16Uto64, unop(Iop_64to16, getIReg64orZR(nn))));
5990 }
5991 else if (imm5 & 4) {
5992 arT = isQ ? "4s" : "2s";
5993 laneTy = Ity_I32;
5994 assign(w0, unop(Iop_32Uto64, unop(Iop_64to32, getIReg64orZR(nn))));
5995 }
5996 else if ((imm5 & 8) && isQ) {
5997 arT = "2d";
5998 laneTy = Ity_I64;
5999 assign(w0, getIReg64orZR(nn));
6000 }
6001 else {
6002 /* invalid; leave laneTy unchanged. */
6003 }
6004 /* */
6005 if (laneTy != Ity_INVALID) {
6006 IRTemp w1 = math_DUP_TO_64(w0, laneTy);
6007 putQReg128(dd, binop(Iop_64HLtoV128,
6008 isQ ? mkexpr(w1) : mkU64(0), mkexpr(w1)));
6009 DIP("dup %s.%s, %s\n",
6010 nameQReg128(dd), arT, nameIRegOrZR(laneTy == Ity_I64, nn));
6011 return True;
6012 }
sewardj787a67f2014-06-23 09:09:41 +00006013 /* invalid */
6014 return False;
sewardjdf1628c2014-06-10 22:52:05 +00006015 }
6016
6017 /* -------- 1,0,0011: INS (general) -------- */
6018 /* 31 28 20 15 9 4
6019 010 01110000 imm5 000111 n d INS Vd.Ts[ix], Rn
6020 where Ts,ix = case imm5 of xxxx1 -> B, xxxx
6021 xxx10 -> H, xxx
6022 xx100 -> S, xx
6023 x1000 -> D, x
6024 */
6025 if (bitQ == 1 && bitOP == 0 && imm4 == BITS4(0,0,1,1)) {
6026 HChar ts = '?';
6027 UInt laneNo = 16;
6028 IRExpr* src = NULL;
6029 if (imm5 & 1) {
6030 src = unop(Iop_64to8, getIReg64orZR(nn));
6031 laneNo = (imm5 >> 1) & 15;
6032 ts = 'b';
6033 }
6034 else if (imm5 & 2) {
6035 src = unop(Iop_64to16, getIReg64orZR(nn));
6036 laneNo = (imm5 >> 2) & 7;
6037 ts = 'h';
6038 }
6039 else if (imm5 & 4) {
6040 src = unop(Iop_64to32, getIReg64orZR(nn));
6041 laneNo = (imm5 >> 3) & 3;
6042 ts = 's';
6043 }
6044 else if (imm5 & 8) {
6045 src = getIReg64orZR(nn);
6046 laneNo = (imm5 >> 4) & 1;
6047 ts = 'd';
6048 }
6049 /* */
6050 if (src) {
6051 vassert(laneNo < 16);
6052 putQRegLane(dd, laneNo, src);
6053 DIP("ins %s.%c[%u], %s\n",
6054 nameQReg128(dd), ts, laneNo, nameIReg64orZR(nn));
6055 return True;
6056 }
sewardj787a67f2014-06-23 09:09:41 +00006057 /* invalid */
6058 return False;
sewardjdf1628c2014-06-10 22:52:05 +00006059 }
6060
6061 /* -------- x,0,0101: SMOV -------- */
6062 /* -------- x,0,0111: UMOV -------- */
6063 /* 31 28 20 15 9 4
6064 0q0 01110 000 imm5 001111 n d UMOV Xd/Wd, Vn.Ts[index]
6065 0q0 01110 000 imm5 001011 n d SMOV Xd/Wd, Vn.Ts[index]
6066 dest is Xd when q==1, Wd when q==0
6067 UMOV:
6068 Ts,index,ops = case q:imm5 of
6069 0:xxxx1 -> B, xxxx, 8Uto64
6070 1:xxxx1 -> invalid
6071 0:xxx10 -> H, xxx, 16Uto64
6072 1:xxx10 -> invalid
6073 0:xx100 -> S, xx, 32Uto64
6074 1:xx100 -> invalid
6075 1:x1000 -> D, x, copy64
6076 other -> invalid
6077 SMOV:
6078 Ts,index,ops = case q:imm5 of
6079 0:xxxx1 -> B, xxxx, (32Uto64 . 8Sto32)
6080 1:xxxx1 -> B, xxxx, 8Sto64
6081 0:xxx10 -> H, xxx, (32Uto64 . 16Sto32)
6082 1:xxx10 -> H, xxx, 16Sto64
6083 0:xx100 -> invalid
6084 1:xx100 -> S, xx, 32Sto64
6085 1:x1000 -> invalid
6086 other -> invalid
6087 */
6088 if (bitOP == 0 && (imm4 == BITS4(0,1,0,1) || imm4 == BITS4(0,1,1,1))) {
6089 Bool isU = (imm4 & 2) == 2;
6090 const HChar* arTs = "??";
6091 UInt laneNo = 16; /* invalid */
6092 // Setting 'res' to non-NULL determines valid/invalid
6093 IRExpr* res = NULL;
6094 if (!bitQ && (imm5 & 1)) { // 0:xxxx1
6095 laneNo = (imm5 >> 1) & 15;
6096 IRExpr* lane = getQRegLane(nn, laneNo, Ity_I8);
6097 res = isU ? unop(Iop_8Uto64, lane)
6098 : unop(Iop_32Uto64, unop(Iop_8Sto32, lane));
6099 arTs = "b";
6100 }
6101 else if (bitQ && (imm5 & 1)) { // 1:xxxx1
6102 laneNo = (imm5 >> 1) & 15;
6103 IRExpr* lane = getQRegLane(nn, laneNo, Ity_I8);
6104 res = isU ? NULL
6105 : unop(Iop_8Sto64, lane);
6106 arTs = "b";
6107 }
6108 else if (!bitQ && (imm5 & 2)) { // 0:xxx10
6109 laneNo = (imm5 >> 2) & 7;
6110 IRExpr* lane = getQRegLane(nn, laneNo, Ity_I16);
6111 res = isU ? unop(Iop_16Uto64, lane)
6112 : unop(Iop_32Uto64, unop(Iop_16Sto32, lane));
6113 arTs = "h";
6114 }
6115 else if (bitQ && (imm5 & 2)) { // 1:xxx10
6116 laneNo = (imm5 >> 2) & 7;
6117 IRExpr* lane = getQRegLane(nn, laneNo, Ity_I16);
6118 res = isU ? NULL
6119 : unop(Iop_16Sto64, lane);
6120 arTs = "h";
6121 }
6122 else if (!bitQ && (imm5 & 4)) { // 0:xx100
6123 laneNo = (imm5 >> 3) & 3;
6124 IRExpr* lane = getQRegLane(nn, laneNo, Ity_I32);
6125 res = isU ? unop(Iop_32Uto64, lane)
6126 : NULL;
6127 arTs = "s";
6128 }
6129 else if (bitQ && (imm5 & 4)) { // 1:xxx10
6130 laneNo = (imm5 >> 3) & 3;
6131 IRExpr* lane = getQRegLane(nn, laneNo, Ity_I32);
6132 res = isU ? NULL
6133 : unop(Iop_32Sto64, lane);
6134 arTs = "s";
6135 }
6136 else if (bitQ && (imm5 & 8)) { // 1:x1000
6137 laneNo = (imm5 >> 4) & 1;
6138 IRExpr* lane = getQRegLane(nn, laneNo, Ity_I64);
6139 res = isU ? lane
6140 : NULL;
6141 arTs = "d";
6142 }
6143 /* */
6144 if (res) {
6145 vassert(laneNo < 16);
6146 putIReg64orZR(dd, res);
6147 DIP("%cmov %s, %s.%s[%u]\n", isU ? 'u' : 's',
6148 nameIRegOrZR(bitQ == 1, dd),
6149 nameQReg128(nn), arTs, laneNo);
6150 return True;
6151 }
sewardj787a67f2014-06-23 09:09:41 +00006152 /* invalid */
6153 return False;
6154 }
6155
6156 /* -------- 1,1,xxxx: INS (element) -------- */
6157 /* 31 28 20 14 9 4
6158 011 01110000 imm5 0 imm4 n d INS Vd.Ts[ix1], Vn.Ts[ix2]
6159 where Ts,ix1,ix2
6160 = case imm5 of xxxx1 -> B, xxxx, imm4[3:0]
6161 xxx10 -> H, xxx, imm4[3:1]
6162 xx100 -> S, xx, imm4[3:2]
6163 x1000 -> D, x, imm4[3:3]
6164 */
6165 if (bitQ == 1 && bitOP == 1) {
6166 HChar ts = '?';
6167 IRType ity = Ity_INVALID;
6168 UInt ix1 = 16;
6169 UInt ix2 = 16;
6170 if (imm5 & 1) {
6171 ts = 'b';
6172 ity = Ity_I8;
6173 ix1 = (imm5 >> 1) & 15;
6174 ix2 = (imm4 >> 0) & 15;
6175 }
6176 else if (imm5 & 2) {
6177 ts = 'h';
6178 ity = Ity_I16;
6179 ix1 = (imm5 >> 2) & 7;
6180 ix2 = (imm4 >> 1) & 7;
6181 }
6182 else if (imm5 & 4) {
6183 ts = 's';
6184 ity = Ity_I32;
6185 ix1 = (imm5 >> 3) & 3;
6186 ix2 = (imm4 >> 2) & 3;
6187 }
6188 else if (imm5 & 8) {
6189 ts = 'd';
6190 ity = Ity_I64;
6191 ix1 = (imm5 >> 4) & 1;
6192 ix2 = (imm4 >> 3) & 1;
6193 }
6194 /* */
6195 if (ity != Ity_INVALID) {
6196 vassert(ix1 < 16);
6197 vassert(ix2 < 16);
6198 putQRegLane(dd, ix1, getQRegLane(nn, ix2, ity));
6199 DIP("ins %s.%c[%u], %s.%c[%u]\n",
6200 nameQReg128(dd), ts, ix1, nameQReg128(nn), ts, ix2);
6201 return True;
6202 }
6203 /* invalid */
6204 return False;
sewardjdf1628c2014-06-10 22:52:05 +00006205 }
6206
6207 return False;
6208# undef INSN
6209}
6210
6211
6212static
6213Bool dis_AdvSIMD_modified_immediate(/*MB_OUT*/DisResult* dres, UInt insn)
6214{
6215 /* 31 28 18 15 11 9 4
6216 0q op 01111 00000 abc cmode 01 defgh d
sewardj2b6fd5e2014-06-19 14:21:37 +00006217 Decode fields: q,op,cmode
6218 Bit 11 is really "o2", but it is always zero.
sewardjdf1628c2014-06-10 22:52:05 +00006219 */
6220# define INSN(_bMax,_bMin) SLICE_UInt(insn, (_bMax), (_bMin))
6221 if (INSN(31,31) != 0
6222 || INSN(28,19) != BITS10(0,1,1,1,1,0,0,0,0,0)
6223 || INSN(11,10) != BITS2(0,1)) {
6224 return False;
6225 }
6226 UInt bitQ = INSN(30,30);
6227 UInt bitOP = INSN(29,29);
6228 UInt cmode = INSN(15,12);
6229 UInt abcdefgh = (INSN(18,16) << 5) | INSN(9,5);
6230 UInt dd = INSN(4,0);
6231
sewardjdf1628c2014-06-10 22:52:05 +00006232 ULong imm64lo = 0;
6233 UInt op_cmode = (bitOP << 4) | cmode;
6234 Bool ok = False;
sewardj2b6fd5e2014-06-19 14:21:37 +00006235 Bool isORR = False;
6236 Bool isBIC = False;
sewardj787a67f2014-06-23 09:09:41 +00006237 Bool isMOV = False;
6238 Bool isMVN = False;
6239 Bool isFMOV = False;
sewardjdf1628c2014-06-10 22:52:05 +00006240 switch (op_cmode) {
sewardj2b6fd5e2014-06-19 14:21:37 +00006241 /* -------- x,0,0000 MOVI 32-bit shifted imm -------- */
sewardj2b6fd5e2014-06-19 14:21:37 +00006242 /* -------- x,0,0010 MOVI 32-bit shifted imm -------- */
sewardj787a67f2014-06-23 09:09:41 +00006243 /* -------- x,0,0100 MOVI 32-bit shifted imm -------- */
6244 /* -------- x,0,0110 MOVI 32-bit shifted imm -------- */
6245 case BITS5(0,0,0,0,0): case BITS5(0,0,0,1,0):
6246 case BITS5(0,0,1,0,0): case BITS5(0,0,1,1,0): // 0:0xx0
6247 ok = True; isMOV = True; break;
sewardj2b6fd5e2014-06-19 14:21:37 +00006248
6249 /* -------- x,0,0001 ORR (vector, immediate) 32-bit -------- */
6250 /* -------- x,0,0011 ORR (vector, immediate) 32-bit -------- */
6251 /* -------- x,0,0101 ORR (vector, immediate) 32-bit -------- */
6252 /* -------- x,0,0111 ORR (vector, immediate) 32-bit -------- */
6253 case BITS5(0,0,0,0,1): case BITS5(0,0,0,1,1):
6254 case BITS5(0,0,1,0,1): case BITS5(0,0,1,1,1): // 0:0xx1
6255 ok = True; isORR = True; break;
6256
sewardj787a67f2014-06-23 09:09:41 +00006257 /* -------- x,0,1000 MOVI 16-bit shifted imm -------- */
6258 /* -------- x,0,1010 MOVI 16-bit shifted imm -------- */
6259 case BITS5(0,1,0,0,0): case BITS5(0,1,0,1,0): // 0:10x0
6260 ok = True; isMOV = True; break;
6261
6262 /* -------- x,0,1001 ORR (vector, immediate) 16-bit -------- */
6263 /* -------- x,0,1011 ORR (vector, immediate) 16-bit -------- */
6264 case BITS5(0,1,0,0,1): case BITS5(0,1,0,1,1): // 0:10x1
6265 ok = True; isORR = True; break;
6266
6267 /* -------- x,0,1100 MOVI 32-bit shifting ones -------- */
6268 /* -------- x,0,1101 MOVI 32-bit shifting ones -------- */
6269 case BITS5(0,1,1,0,0): case BITS5(0,1,1,0,1): // 0:110x
6270 ok = True; isMOV = True; break;
6271
6272 /* -------- x,0,1110 MOVI 8-bit -------- */
6273 case BITS5(0,1,1,1,0):
6274 ok = True; isMOV = True; break;
6275
6276 /* FMOV (vector, immediate, single precision) */
6277
6278 /* -------- x,1,0000 MVNI 32-bit shifted imm -------- */
6279 /* -------- x,1,0010 MVNI 32-bit shifted imm -------- */
6280 /* -------- x,1,0100 MVNI 32-bit shifted imm -------- */
6281 /* -------- x,1,0110 MVNI 32-bit shifted imm -------- */
6282 case BITS5(1,0,0,0,0): case BITS5(1,0,0,1,0):
6283 case BITS5(1,0,1,0,0): case BITS5(1,0,1,1,0): // 1:0xx0
6284 ok = True; isMVN = True; break;
6285
sewardj2b6fd5e2014-06-19 14:21:37 +00006286 /* -------- x,1,0001 BIC (vector, immediate) 32-bit -------- */
6287 /* -------- x,1,0011 BIC (vector, immediate) 32-bit -------- */
6288 /* -------- x,1,0101 BIC (vector, immediate) 32-bit -------- */
6289 /* -------- x,1,0111 BIC (vector, immediate) 32-bit -------- */
6290 case BITS5(1,0,0,0,1): case BITS5(1,0,0,1,1):
6291 case BITS5(1,0,1,0,1): case BITS5(1,0,1,1,1): // 1:0xx1
6292 ok = True; isBIC = True; break;
6293
sewardj787a67f2014-06-23 09:09:41 +00006294 /* -------- x,1,1000 MVNI 16-bit shifted imm -------- */
6295 /* -------- x,1,1010 MVNI 16-bit shifted imm -------- */
6296 case BITS5(1,1,0,0,0): case BITS5(1,1,0,1,0): // 1:10x0
6297 ok = True; isMVN = True; break;
6298
6299 /* -------- x,1,1001 BIC (vector, immediate) 16-bit -------- */
6300 /* -------- x,1,1011 BIC (vector, immediate) 16-bit -------- */
6301 case BITS5(1,1,0,0,1): case BITS5(1,1,0,1,1): // 1:10x1
6302 ok = True; isBIC = True; break;
6303
6304 /* -------- x,1,1100 MVNI 32-bit shifting ones -------- */
6305 /* -------- x,1,1101 MVNI 32-bit shifting ones -------- */
6306 case BITS5(1,1,1,0,0): case BITS5(1,1,1,0,1): // 1:110x
6307 ok = True; isMVN = True; break;
6308
6309 /* -------- 0,1,1110 MOVI 64-bit scalar -------- */
6310 /* -------- 1,1,1110 MOVI 64-bit vector -------- */
6311 case BITS5(1,1,1,1,0):
6312 ok = True; isMOV = True; break;
6313
6314 /* -------- 1,1,1111 FMOV (vector, immediate) -------- */
6315 case BITS5(1,1,1,1,1): // 1:1111
6316 ok = bitQ == 1; isFMOV = True; break;
6317
sewardjdf1628c2014-06-10 22:52:05 +00006318 default:
6319 break;
6320 }
6321 if (ok) {
sewardj787a67f2014-06-23 09:09:41 +00006322 vassert(1 == (isMOV ? 1 : 0) + (isMVN ? 1 : 0)
6323 + (isORR ? 1 : 0) + (isBIC ? 1 : 0) + (isFMOV ? 1 : 0));
sewardjdf1628c2014-06-10 22:52:05 +00006324 ok = AdvSIMDExpandImm(&imm64lo, bitOP, cmode, abcdefgh);
6325 }
6326 if (ok) {
sewardj2b6fd5e2014-06-19 14:21:37 +00006327 if (isORR || isBIC) {
6328 ULong inv
6329 = isORR ? 0ULL : ~0ULL;
6330 IRExpr* immV128
6331 = binop(Iop_64HLtoV128, mkU64(inv ^ imm64lo), mkU64(inv ^ imm64lo));
6332 IRExpr* res
6333 = binop(isORR ? Iop_OrV128 : Iop_AndV128, getQReg128(dd), immV128);
6334 putQReg128(dd, bitQ == 0 ? unop(Iop_ZeroHI64ofV128, res) : res);
6335 const HChar* nm = isORR ? "orr" : "bic";
6336 if (bitQ == 0) {
6337 putQReg128(dd, unop(Iop_ZeroHI64ofV128, res));
6338 DIP("%s %s.1d, %016llx\n", nm, nameQReg128(dd), imm64lo);
6339 } else {
6340 putQReg128(dd, res);
6341 DIP("%s %s.2d, #0x%016llx'%016llx\n", nm,
6342 nameQReg128(dd), imm64lo, imm64lo);
6343 }
sewardj787a67f2014-06-23 09:09:41 +00006344 }
6345 else if (isMOV || isMVN || isFMOV) {
6346 if (isMVN) imm64lo = ~imm64lo;
6347 ULong imm64hi = bitQ == 0 ? 0 : imm64lo;
sewardj2b6fd5e2014-06-19 14:21:37 +00006348 IRExpr* immV128 = binop(Iop_64HLtoV128, mkU64(imm64hi), mkU64(imm64lo));
6349 putQReg128(dd, immV128);
6350 DIP("mov %s, #0x%016llx'%016llx\n", nameQReg128(dd), imm64hi, imm64lo);
6351 }
sewardjdf1628c2014-06-10 22:52:05 +00006352 return True;
6353 }
6354 /* else fall through */
6355
6356 return False;
6357# undef INSN
6358}
6359
6360
6361static
6362Bool dis_AdvSIMD_scalar_copy(/*MB_OUT*/DisResult* dres, UInt insn)
6363{
sewardjab33a7a2014-06-19 22:20:47 +00006364 /* 31 28 20 15 14 10 9 4
6365 01 op 11110000 imm5 0 imm4 1 n d
6366 Decode fields: op,imm4
6367 */
sewardjdf1628c2014-06-10 22:52:05 +00006368# define INSN(_bMax,_bMin) SLICE_UInt(insn, (_bMax), (_bMin))
sewardjab33a7a2014-06-19 22:20:47 +00006369 if (INSN(31,30) != BITS2(0,1)
6370 || INSN(28,21) != BITS8(1,1,1,1,0,0,0,0)
6371 || INSN(15,15) != 0 || INSN(10,10) != 1) {
6372 return False;
6373 }
6374 UInt bitOP = INSN(29,29);
6375 UInt imm5 = INSN(20,16);
6376 UInt imm4 = INSN(14,11);
6377 UInt nn = INSN(9,5);
6378 UInt dd = INSN(4,0);
6379
6380 if (bitOP == 0 && imm4 == BITS4(0,0,0,0)) {
6381 /* -------- 0,0000 DUP (element, scalar) -------- */
6382 IRTemp w0 = newTemp(Ity_I64);
6383 const HChar* arTs = "??";
6384 IRType laneTy = Ity_INVALID;
6385 UInt laneNo = 16; /* invalid */
6386 if (imm5 & 1) {
6387 arTs = "b";
6388 laneNo = (imm5 >> 1) & 15;
6389 laneTy = Ity_I8;
6390 assign(w0, unop(Iop_8Uto64, getQRegLane(nn, laneNo, laneTy)));
6391 }
6392 else if (imm5 & 2) {
6393 arTs = "h";
6394 laneNo = (imm5 >> 2) & 7;
6395 laneTy = Ity_I16;
6396 assign(w0, unop(Iop_16Uto64, getQRegLane(nn, laneNo, laneTy)));
6397 }
6398 else if (imm5 & 4) {
6399 arTs = "s";
6400 laneNo = (imm5 >> 3) & 3;
6401 laneTy = Ity_I32;
6402 assign(w0, unop(Iop_32Uto64, getQRegLane(nn, laneNo, laneTy)));
6403 }
6404 else if (imm5 & 8) {
6405 arTs = "d";
6406 laneNo = (imm5 >> 4) & 1;
6407 laneTy = Ity_I64;
6408 assign(w0, getQRegLane(nn, laneNo, laneTy));
6409 }
6410 else {
6411 /* invalid; leave laneTy unchanged. */
6412 }
6413 /* */
6414 if (laneTy != Ity_INVALID) {
6415 vassert(laneNo < 16);
6416 putQReg128(dd, binop(Iop_64HLtoV128, mkU64(0), mkexpr(w0)));
6417 DIP("dup %s, %s.%s[%u]\n",
6418 nameQRegLO(dd, laneTy), nameQReg128(nn), arTs, laneNo);
6419 return True;
6420 }
6421 /* else fall through */
6422 }
6423
sewardjdf1628c2014-06-10 22:52:05 +00006424 return False;
6425# undef INSN
6426}
6427
sewardjfc83d2c2014-06-12 10:15:46 +00006428
sewardjdf1628c2014-06-10 22:52:05 +00006429static
6430Bool dis_AdvSIMD_scalar_pairwise(/*MB_OUT*/DisResult* dres, UInt insn)
6431{
sewardjb9aff1e2014-06-15 21:55:33 +00006432 /* 31 28 23 21 16 11 9 4
6433 01 u 11110 sz 11000 opcode 10 n d
6434 Decode fields: u,sz,opcode
6435 */
sewardjdf1628c2014-06-10 22:52:05 +00006436# define INSN(_bMax,_bMin) SLICE_UInt(insn, (_bMax), (_bMin))
sewardjb9aff1e2014-06-15 21:55:33 +00006437 if (INSN(31,30) != BITS2(0,1)
6438 || INSN(28,24) != BITS5(1,1,1,1,0)
6439 || INSN(21,17) != BITS5(1,1,0,0,0)
6440 || INSN(11,10) != BITS2(1,0)) {
6441 return False;
6442 }
6443 UInt bitU = INSN(29,29);
6444 UInt sz = INSN(23,22);
6445 UInt opcode = INSN(16,12);
6446 UInt nn = INSN(9,5);
6447 UInt dd = INSN(4,0);
6448
6449 if (bitU == 0 && sz == X11 && opcode == BITS5(1,1,0,1,1)) {
6450 /* -------- 0,11,11011 ADDP d_2d -------- */
6451 IRTemp xy = newTemp(Ity_V128);
6452 IRTemp xx = newTemp(Ity_V128);
6453 assign(xy, getQReg128(nn));
6454 assign(xx, binop(Iop_InterleaveHI64x2, mkexpr(xy), mkexpr(xy)));
6455 putQReg128(dd, unop(Iop_ZeroHI64ofV128,
6456 binop(Iop_Add64x2, mkexpr(xy), mkexpr(xx))));
6457 DIP("addp d%u, %s.2d\n", dd, nameQReg128(nn));
6458 return True;
6459 }
6460
sewardjdf1628c2014-06-10 22:52:05 +00006461 return False;
6462# undef INSN
6463}
6464
sewardjfc83d2c2014-06-12 10:15:46 +00006465
sewardjdf1628c2014-06-10 22:52:05 +00006466static
6467Bool dis_AdvSIMD_scalar_shift_by_imm(/*MB_OUT*/DisResult* dres, UInt insn)
6468{
6469 /* 31 28 22 18 15 10 9 4
6470 01 u 111110 immh immb opcode 1 n d
6471 Decode fields: u,immh,opcode
6472 */
6473# define INSN(_bMax,_bMin) SLICE_UInt(insn, (_bMax), (_bMin))
6474 if (INSN(31,30) != BITS2(0,1)
6475 || INSN(28,23) != BITS6(1,1,1,1,1,0) || INSN(10,10) != 1) {
6476 return False;
6477 }
6478 UInt bitU = INSN(29,29);
6479 UInt immh = INSN(22,19);
6480 UInt immb = INSN(18,16);
6481 UInt opcode = INSN(15,11);
6482 UInt nn = INSN(9,5);
6483 UInt dd = INSN(4,0);
6484 UInt immhb = (immh << 3) | immb;
6485
sewardjfc83d2c2014-06-12 10:15:46 +00006486 if (bitU == 1 && (immh & 8) == 8 && opcode == BITS5(0,0,0,0,0)) {
6487 /* -------- 1,1xxx,00000 SHR d_d_#imm -------- */
6488 UInt sh = 128 - immhb;
6489 vassert(sh >= 1 && sh <= 64);
6490 /* Don't generate an out of range IR shift */
6491 putQReg128(dd, sh == 64
6492 ? mkV128(0x0000)
6493 : unop(Iop_ZeroHI64ofV128,
6494 binop(Iop_ShrN64x2, getQReg128(nn), mkU8(sh))));
6495 DIP("shr d%u, d%u, #%u\n", dd, nn, sh);
6496 return True;
6497 }
6498
sewardjdf1628c2014-06-10 22:52:05 +00006499 if (bitU == 0 && (immh & 8) == 8 && opcode == BITS5(0,1,0,1,0)) {
6500 /* -------- 0,1xxx,01010 SHL d_d_#imm -------- */
6501 UInt sh = immhb - 64;
6502 vassert(sh >= 0 && sh < 64);
6503 putQReg128(dd, unop(Iop_ZeroHI64ofV128,
6504 binop(Iop_ShlN64x2, getQReg128(nn), mkU8(sh))));
6505 DIP("shl d%u, d%u, #%u\n", dd, nn, sh);
6506 return True;
6507 }
6508
6509# define INSN(_bMax,_bMin) SLICE_UInt(insn, (_bMax), (_bMin))
6510 return False;
6511# undef INSN
6512}
6513
sewardjfc83d2c2014-06-12 10:15:46 +00006514
sewardjdf1628c2014-06-10 22:52:05 +00006515static
6516Bool dis_AdvSIMD_scalar_three_different(/*MB_OUT*/DisResult* dres, UInt insn)
6517{
6518# define INSN(_bMax,_bMin) SLICE_UInt(insn, (_bMax), (_bMin))
6519 return False;
6520# undef INSN
6521}
6522
6523
6524static
6525Bool dis_AdvSIMD_scalar_three_same(/*MB_OUT*/DisResult* dres, UInt insn)
6526{
6527 /* 31 29 28 23 21 20 15 10 9 4
6528 01 U 11110 size 1 m opcode 1 n d
6529 */
6530# define INSN(_bMax,_bMin) SLICE_UInt(insn, (_bMax), (_bMin))
6531 if (INSN(31,30) != BITS2(0,1)
6532 || INSN(28,24) != BITS5(1,1,1,1,0)
6533 || INSN(21,21) != 1
6534 || INSN(10,10) != 1) {
6535 return False;
6536 }
6537 UInt bitU = INSN(29,29);
6538 UInt size = INSN(23,22);
6539 UInt mm = INSN(20,16);
6540 UInt opcode = INSN(15,11);
6541 UInt nn = INSN(9,5);
6542 UInt dd = INSN(4,0);
6543 vassert(size < 4);
6544
sewardj2b6fd5e2014-06-19 14:21:37 +00006545 if (size == X11 && opcode == BITS5(0,0,1,1,0)) {
6546 /* -------- 0,11,00110 CMGT d_d_d -------- */ // >s
6547 /* -------- 1,11,00110 CMHI d_d_d -------- */ // >u
6548 Bool isGT = bitU == 0;
6549 IRExpr* argL = getQReg128(nn);
6550 IRExpr* argR = getQReg128(mm);
6551 IRTemp res = newTemp(Ity_V128);
6552 assign(res,
6553 isGT ? binop(Iop_CmpGT64Sx2, argL, argR)
6554 : binop(Iop_CmpGT64Ux2, argL, argR));
6555 putQReg128(dd, unop(Iop_ZeroHI64ofV128, mkexpr(res)));
6556 DIP("%s %s, %s, %s\n",isGT ? "cmgt" : "cmhi",
6557 nameQRegLO(dd, Ity_I64),
6558 nameQRegLO(nn, Ity_I64), nameQRegLO(mm, Ity_I64));
6559 return True;
6560 }
6561
6562 if (size == X11 && opcode == BITS5(0,0,1,1,1)) {
6563 /* -------- 0,11,00111 CMGE d_d_d -------- */ // >=s
6564 /* -------- 1,11,00111 CMHS d_d_d -------- */ // >=u
6565 Bool isGE = bitU == 0;
6566 IRExpr* argL = getQReg128(nn);
6567 IRExpr* argR = getQReg128(mm);
6568 IRTemp res = newTemp(Ity_V128);
6569 assign(res,
6570 isGE ? unop(Iop_NotV128, binop(Iop_CmpGT64Sx2, argR, argL))
6571 : unop(Iop_NotV128, binop(Iop_CmpGT64Ux2, argR, argL)));
6572 putQReg128(dd, unop(Iop_ZeroHI64ofV128, mkexpr(res)));
6573 DIP("%s %s, %s, %s\n", isGE ? "cmge" : "cmhs",
6574 nameQRegLO(dd, Ity_I64),
6575 nameQRegLO(nn, Ity_I64), nameQRegLO(mm, Ity_I64));
6576 return True;
6577 }
6578
sewardjdf1628c2014-06-10 22:52:05 +00006579 if (size == X11 && opcode == BITS5(1,0,0,0,0)) {
6580 /* -------- 0,11,10000 ADD d_d_d -------- */
6581 /* -------- 1,11,10000 SUB d_d_d -------- */
6582 Bool isSUB = bitU == 1;
6583 IRTemp res = newTemp(Ity_I64);
6584 assign(res, binop(isSUB ? Iop_Sub64 : Iop_Add64,
6585 getQRegLane(nn, 0, Ity_I64),
6586 getQRegLane(mm, 0, Ity_I64)));
6587 putQRegLane(dd, 0, mkexpr(res));
6588 putQRegLane(dd, 1, mkU64(0));
6589 DIP("%s %s, %s, %s\n", isSUB ? "sub" : "add",
6590 nameQRegLO(dd, Ity_I64),
6591 nameQRegLO(nn, Ity_I64), nameQRegLO(mm, Ity_I64));
6592 return True;
6593 }
6594
sewardj2b6fd5e2014-06-19 14:21:37 +00006595 if (size == X11 && opcode == BITS5(1,0,0,0,1)) {
6596 /* -------- 0,11,10001 CMTST d_d_d -------- */ // &, != 0
6597 /* -------- 1,11,10001 CMEQ d_d_d -------- */ // ==
6598 Bool isEQ = bitU == 1;
6599 IRExpr* argL = getQReg128(nn);
6600 IRExpr* argR = getQReg128(mm);
6601 IRTemp res = newTemp(Ity_V128);
6602 assign(res,
6603 isEQ ? binop(Iop_CmpEQ64x2, argL, argR)
6604 : unop(Iop_NotV128, binop(Iop_CmpEQ64x2,
6605 binop(Iop_AndV128, argL, argR),
6606 mkV128(0x0000))));
6607 putQReg128(dd, unop(Iop_ZeroHI64ofV128, mkexpr(res)));
6608 DIP("%s %s, %s, %s\n", isEQ ? "cmeq" : "cmtst",
6609 nameQRegLO(dd, Ity_I64),
6610 nameQRegLO(nn, Ity_I64), nameQRegLO(mm, Ity_I64));
6611 return True;
6612 }
6613
sewardjdf1628c2014-06-10 22:52:05 +00006614 if (bitU == 1 && size >= X10 && opcode == BITS5(1,1,0,1,0)) {
6615 /* -------- 1,1x,11010 FABD d_d_d, s_s_s -------- */
6616 IRType ity = size == X11 ? Ity_F64 : Ity_F32;
6617 IRTemp res = newTemp(ity);
6618 assign(res, unop(mkABSF(ity),
6619 triop(mkSUBF(ity),
6620 mkexpr(mk_get_IR_rounding_mode()),
6621 getQRegLO(nn,ity), getQRegLO(mm,ity))));
6622 putQReg128(dd, mkV128(0x0000));
6623 putQRegLO(dd, mkexpr(res));
6624 DIP("fabd %s, %s, %s\n",
6625 nameQRegLO(dd, ity), nameQRegLO(nn, ity), nameQRegLO(mm, ity));
6626 return True;
6627 }
6628
6629
6630
6631 return False;
6632# undef INSN
6633}
6634
6635
6636static
6637Bool dis_AdvSIMD_scalar_two_reg_misc(/*MB_OUT*/DisResult* dres, UInt insn)
6638{
6639 /* 31 29 28 23 21 16 11 9 4
6640 01 U 11110 size 10000 opcode 10 n d
6641 */
6642# define INSN(_bMax,_bMin) SLICE_UInt(insn, (_bMax), (_bMin))
6643 if (INSN(31,30) != BITS2(0,1)
6644 || INSN(28,24) != BITS5(1,1,1,1,0)
6645 || INSN(21,17) != BITS5(1,0,0,0,0)
6646 || INSN(11,10) != BITS2(1,0)) {
6647 return False;
6648 }
6649 UInt bitU = INSN(29,29);
6650 UInt size = INSN(23,22);
6651 UInt opcode = INSN(16,12);
6652 UInt nn = INSN(9,5);
6653 UInt dd = INSN(4,0);
6654 vassert(size < 4);
6655
sewardj2b6fd5e2014-06-19 14:21:37 +00006656 if (size == X11 && opcode == BITS5(0,1,0,0,0)) {
6657 /* -------- 0,11,01000: CMGT d_d_#0 -------- */ // >s 0
6658 /* -------- 1,11,01000: CMGE d_d_#0 -------- */ // >=s 0
6659 Bool isGT = bitU == 0;
6660 IRExpr* argL = getQReg128(nn);
6661 IRExpr* argR = mkV128(0x0000);
6662 IRTemp res = newTemp(Ity_V128);
6663 assign(res, isGT ? binop(Iop_CmpGT64Sx2, argL, argR)
6664 : unop(Iop_NotV128, binop(Iop_CmpGT64Sx2, argR, argL)));
6665 putQReg128(dd, unop(Iop_ZeroHI64ofV128, mkexpr(res)));
6666 DIP("cm%s d%u, d%u, #0\n", isGT ? "gt" : "ge", dd, nn);
6667 return True;
6668 }
6669
6670 if (size == X11 && opcode == BITS5(0,1,0,0,1)) {
6671 /* -------- 0,11,01001: CMEQ d_d_#0 -------- */ // == 0
6672 /* -------- 1,11,01001: CMLE d_d_#0 -------- */ // <=s 0
6673 Bool isEQ = bitU == 0;
6674 IRExpr* argL = getQReg128(nn);
6675 IRExpr* argR = mkV128(0x0000);
6676 IRTemp res = newTemp(Ity_V128);
6677 assign(res, isEQ ? binop(Iop_CmpEQ64x2, argL, argR)
6678 : unop(Iop_NotV128,
6679 binop(Iop_CmpGT64Sx2, argL, argR)));
6680 putQReg128(dd, unop(Iop_ZeroHI64ofV128, mkexpr(res)));
6681 DIP("cm%s d%u, d%u, #0\n", isEQ ? "eq" : "le", dd, nn);
6682 return True;
6683 }
6684
6685 if (bitU == 0 && size == X11 && opcode == BITS5(0,1,0,1,0)) {
6686 /* -------- 0,11,01010: CMLT d_d_#0 -------- */ // <s 0
sewardjdf1628c2014-06-10 22:52:05 +00006687 putQReg128(dd, unop(Iop_ZeroHI64ofV128,
sewardj2b6fd5e2014-06-19 14:21:37 +00006688 binop(Iop_CmpGT64Sx2, mkV128(0x0000),
6689 getQReg128(nn))));
6690 DIP("cm%s d%u, d%u, #0\n", "lt", dd, nn);
sewardjdf1628c2014-06-10 22:52:05 +00006691 return True;
6692 }
6693
sewardj25523c42014-06-15 19:36:29 +00006694 if (bitU == 0 && size == X11 && opcode == BITS5(0,1,0,1,1)) {
6695 /* -------- 0,11,01011 ABS d_d -------- */
6696 putQReg128(dd, unop(Iop_ZeroHI64ofV128,
6697 unop(Iop_Abs64x2, getQReg128(nn))));
6698 DIP("abs d%u, d%u\n", dd, nn);
6699 return True;
6700 }
6701
6702 if (bitU == 1 && size == X11 && opcode == BITS5(0,1,0,1,1)) {
6703 /* -------- 1,11,01011 NEG d_d -------- */
6704 putQReg128(dd, unop(Iop_ZeroHI64ofV128,
6705 binop(Iop_Sub64x2, mkV128(0x0000), getQReg128(nn))));
6706 DIP("neg d%u, d%u\n", dd, nn);
6707 return True;
6708 }
6709
sewardjdf1628c2014-06-10 22:52:05 +00006710# define INSN(_bMax,_bMin) SLICE_UInt(insn, (_bMax), (_bMin))
6711 return False;
6712# undef INSN
6713}
6714
sewardjfc83d2c2014-06-12 10:15:46 +00006715
sewardjdf1628c2014-06-10 22:52:05 +00006716static
6717Bool dis_AdvSIMD_scalar_x_indexed_element(/*MB_OUT*/DisResult* dres, UInt insn)
6718{
6719# define INSN(_bMax,_bMin) SLICE_UInt(insn, (_bMax), (_bMin))
6720 return False;
6721# undef INSN
6722}
6723
sewardjfc83d2c2014-06-12 10:15:46 +00006724
sewardjdf1628c2014-06-10 22:52:05 +00006725static
6726Bool dis_AdvSIMD_shift_by_immediate(/*MB_OUT*/DisResult* dres, UInt insn)
6727{
6728 /* 31 28 22 18 15 10 9 4
6729 0 q u 011110 immh immb opcode 1 n d
6730 Decode fields: u,opcode
6731 */
6732# define INSN(_bMax,_bMin) SLICE_UInt(insn, (_bMax), (_bMin))
6733 if (INSN(31,31) != 0
6734 || INSN(28,23) != BITS6(0,1,1,1,1,0) || INSN(10,10) != 1) {
6735 return False;
6736 }
6737 UInt bitQ = INSN(30,30);
6738 UInt bitU = INSN(29,29);
6739 UInt immh = INSN(22,19);
6740 UInt immb = INSN(18,16);
6741 UInt opcode = INSN(15,11);
6742 UInt nn = INSN(9,5);
6743 UInt dd = INSN(4,0);
6744
6745 if (opcode == BITS5(0,0,0,0,0)) {
6746 /* -------- 0,00000 SSHR std7_std7_#imm -------- */
6747 /* -------- 1,00000 USHR std7_std7_#imm -------- */
6748 /* laneTy, shift = case immh:immb of
6749 0001:xxx -> B, SHR:8-xxx
6750 001x:xxx -> H, SHR:16-xxxx
6751 01xx:xxx -> S, SHR:32-xxxxx
6752 1xxx:xxx -> D, SHR:64-xxxxxx
6753 other -> invalid
6754 */
6755 const IROp opsSHRN[4]
6756 = { Iop_ShrN8x16, Iop_ShrN16x8, Iop_ShrN32x4, Iop_ShrN64x2 };
6757 const IROp opsSARN[4]
6758 = { Iop_SarN8x16, Iop_SarN16x8, Iop_SarN32x4, Iop_SarN64x2 };
6759 UInt size = 0;
6760 UInt shift = 0;
6761 Bool isQ = bitQ == 1;
6762 Bool isU = bitU == 1;
6763 Bool ok = getLaneInfo_IMMH_IMMB(&shift, &size, immh, immb);
6764 vassert(size >= 0 && size <= 3);
6765 if (ok && size < 4 && shift > 0 && shift < (8 << size)
6766 && !(size == 3/*64bit*/ && !isQ)) {
6767 IROp op = isU ? opsSHRN[size] : opsSARN[size];
6768 IRExpr* src = getQReg128(nn);
6769 IRExpr* res = binop(op, src, mkU8(shift));
6770 putQReg128(dd, isQ ? res : unop(Iop_ZeroHI64ofV128, res));
6771 HChar laneCh = "bhsd"[size];
6772 UInt nLanes = (isQ ? 128 : 64) / (8 << size);
6773 const HChar* nm = isU ? "ushr" : "sshr";
6774 DIP("%s %s.%u%c, %s.%u%c, #%u\n", nm,
6775 nameQReg128(dd), nLanes, laneCh,
6776 nameQReg128(nn), nLanes, laneCh, shift);
6777 return True;
6778 }
6779 return False;
6780 }
6781
6782 if (bitU == 0 && opcode == BITS5(0,1,0,1,0)) {
6783 /* -------- 0,01010 SHL std7_std7_#imm -------- */
6784 /* laneTy, shift = case immh:immb of
6785 0001:xxx -> B, xxx
6786 001x:xxx -> H, xxxx
6787 01xx:xxx -> S, xxxxx
6788 1xxx:xxx -> D, xxxxxx
6789 other -> invalid
6790 */
6791 const IROp opsSHLN[4]
6792 = { Iop_ShlN8x16, Iop_ShlN16x8, Iop_ShlN32x4, Iop_ShlN64x2 };
6793 UInt size = 0;
6794 UInt shift = 0;
6795 Bool isQ = bitQ == 1;
6796 Bool ok = getLaneInfo_IMMH_IMMB(&shift, &size, immh, immb);
6797 vassert(size >= 0 && size <= 3);
6798 /* The shift encoding has opposite sign for the leftwards case.
6799 Adjust shift to compensate. */
6800 shift = (8 << size) - shift;
6801 if (ok && size < 4 && shift > 0 && shift < (8 << size)
6802 && !(size == 3/*64bit*/ && !isQ)) {
6803 IROp op = opsSHLN[size];
6804 IRExpr* src = getQReg128(nn);
6805 IRExpr* res = binop(op, src, mkU8(shift));
6806 putQReg128(dd, isQ ? res : unop(Iop_ZeroHI64ofV128, res));
6807 HChar laneCh = "bhsd"[size];
6808 UInt nLanes = (isQ ? 128 : 64) / (8 << size);
6809 const HChar* nm = "shl";
6810 DIP("%s %s.%u%c, %s.%u%c, #%u\n", nm,
6811 nameQReg128(dd), nLanes, laneCh,
6812 nameQReg128(nn), nLanes, laneCh, shift);
6813 return True;
6814 }
6815 return False;
6816 }
6817
6818 if (opcode == BITS5(1,0,1,0,0)) {
6819 /* -------- 0,10100 SSHLL{,2} #imm -------- */
6820 /* -------- 1,10100 USHLL{,2} #imm -------- */
6821 /* 31 28 22 18 15 9 4
6822 0q0 011110 immh immb 101001 n d SSHLL Vd.Ta, Vn.Tb, #sh
6823 0q1 011110 immh immb 101001 n d USHLL Vd.Ta, Vn.Tb, #sh
6824 where Ta,Tb,sh
6825 = case immh of 1xxx -> invalid
6826 01xx -> 2d, 2s(q0)/4s(q1), immh:immb - 32 (0..31)
6827 001x -> 4s, 4h(q0)/8h(q1), immh:immb - 16 (0..15)
6828 0001 -> 8h, 8b(q0)/16b(q1), immh:immb - 8 (0..7)
6829 0000 -> AdvSIMD modified immediate (???)
6830 */
6831 Bool isQ = bitQ == 1;
6832 Bool isU = bitU == 1;
6833 UInt immhb = (immh << 3) | immb;
6834 IRTemp src = newTemp(Ity_V128);
6835 IRTemp zero = newTemp(Ity_V128);
6836 IRExpr* res = NULL;
6837 UInt sh = 0;
6838 const HChar* ta = "??";
6839 const HChar* tb = "??";
6840 assign(src, getQReg128(nn));
6841 assign(zero, mkV128(0x0000));
6842 if (immh & 8) {
6843 /* invalid; don't assign to res */
6844 }
6845 else if (immh & 4) {
6846 sh = immhb - 32;
6847 vassert(sh < 32); /* so 32-sh is 1..32 */
6848 ta = "2d";
6849 tb = isQ ? "4s" : "2s";
6850 IRExpr* tmp = isQ ? mk_InterleaveHI32x4(src, zero)
6851 : mk_InterleaveLO32x4(src, zero);
6852 res = binop(isU ? Iop_ShrN64x2 : Iop_SarN64x2, tmp, mkU8(32-sh));
6853 }
6854 else if (immh & 2) {
6855 sh = immhb - 16;
6856 vassert(sh < 16); /* so 16-sh is 1..16 */
6857 ta = "4s";
6858 tb = isQ ? "8h" : "4h";
6859 IRExpr* tmp = isQ ? mk_InterleaveHI16x8(src, zero)
6860 : mk_InterleaveLO16x8(src, zero);
6861 res = binop(isU ? Iop_ShrN32x4 : Iop_SarN32x4, tmp, mkU8(16-sh));
6862 }
6863 else if (immh & 1) {
6864 sh = immhb - 8;
6865 vassert(sh < 8); /* so 8-sh is 1..8 */
6866 ta = "8h";
6867 tb = isQ ? "16b" : "8b";
6868 IRExpr* tmp = isQ ? mk_InterleaveHI8x16(src, zero)
6869 : mk_InterleaveLO8x16(src, zero);
6870 res = binop(isU ? Iop_ShrN16x8 : Iop_SarN16x8, tmp, mkU8(8-sh));
6871 } else {
6872 vassert(immh == 0);
6873 /* invalid; don't assign to res */
6874 }
6875 /* */
6876 if (res) {
6877 putQReg128(dd, res);
6878 DIP("%cshll%s %s.%s, %s.%s, #%d\n",
6879 isU ? 'u' : 's', isQ ? "2" : "",
6880 nameQReg128(dd), ta, nameQReg128(nn), tb, sh);
6881 return True;
6882 }
6883 return False;
6884 }
6885
6886# define INSN(_bMax,_bMin) SLICE_UInt(insn, (_bMax), (_bMin))
6887 return False;
6888# undef INSN
6889}
6890
sewardjfc83d2c2014-06-12 10:15:46 +00006891
sewardjdf1628c2014-06-10 22:52:05 +00006892static
6893Bool dis_AdvSIMD_three_different(/*MB_OUT*/DisResult* dres, UInt insn)
6894{
sewardj25523c42014-06-15 19:36:29 +00006895 /* 31 30 29 28 23 21 20 15 11 9 4
6896 0 Q U 01110 size 1 m opcode 00 n d
6897 Decode fields: u,opcode
6898 */
sewardjdf1628c2014-06-10 22:52:05 +00006899# define INSN(_bMax,_bMin) SLICE_UInt(insn, (_bMax), (_bMin))
sewardj25523c42014-06-15 19:36:29 +00006900 if (INSN(31,31) != 0
6901 || INSN(28,24) != BITS5(0,1,1,1,0)
6902 || INSN(21,21) != 1
6903 || INSN(11,10) != BITS2(0,0)) {
6904 return False;
6905 }
6906 UInt bitQ = INSN(30,30);
6907 UInt bitU = INSN(29,29);
6908 UInt size = INSN(23,22);
6909 UInt mm = INSN(20,16);
6910 UInt opcode = INSN(15,12);
6911 UInt nn = INSN(9,5);
6912 UInt dd = INSN(4,0);
6913 vassert(size < 4);
6914 Bool is2 = bitQ == 1;
6915
6916 if (opcode == BITS4(0,1,0,0) || opcode == BITS4(0,1,1,0)) {
6917 /* -------- 0,0100 ADDHN{2} -------- */
6918 /* -------- 1,0100 RADDHN{2} -------- */
6919 /* -------- 0,0110 SUBHN{2} -------- */
6920 /* -------- 1,0110 RSUBHN{2} -------- */
6921 /* Narrows, and size refers to the narrowed lanes. */
6922 if (size == X11) return False;
6923 vassert(size <= 2);
6924 const IROp opADD[3] = { Iop_Add16x8, Iop_Add32x4, Iop_Add64x2 };
6925 const IROp opSUB[3] = { Iop_Sub16x8, Iop_Sub32x4, Iop_Sub64x2 };
6926 const IROp opSHR[3] = { Iop_ShrN16x8, Iop_ShrN32x4, Iop_ShrN64x2 };
6927 const UInt shift[3] = { 8, 16, 32 };
6928 const IROp opCAT[3] = { Iop_CatEvenLanes8x16, Iop_CatEvenLanes16x8,
6929 Iop_CatEvenLanes32x4 };
6930 Bool isADD = opcode == BITS4(0,1,0,0);
6931 Bool isR = bitU == 1;
6932 /* Combined elements in wide lanes */
6933 IRTemp wide = newTemp(Ity_V128);
6934 IRExpr* wideE = binop(isADD ? opADD[size] : opSUB[size],
6935 getQReg128(nn), getQReg128(mm));
6936 if (isR) {
6937 IRType ty = Ity_INVALID;
6938 IRTemp rcS = IRTemp_INVALID;
6939 switch (size) {
6940 case X00: ty = Ity_I16;
6941 rcS = newTemp(ty); assign(rcS, mkU16(0x80)); break;
6942 case X01: ty = Ity_I32;
6943 rcS = newTemp(ty); assign(rcS, mkU32(0x8000)); break;
6944 case X10: ty = Ity_I64;
6945 rcS = newTemp(ty); assign(rcS, mkU64(0x80000000)); break;
6946 default: vassert(0);
6947 }
6948 IRTemp rcV = math_DUP_TO_V128(rcS, ty);
6949 wideE = binop(opADD[size], wideE, mkexpr(rcV));
6950 }
6951 assign(wide, wideE);
6952 /* Top halves of elements, still in wide lanes */
6953 IRTemp shrd = newTemp(Ity_V128);
6954 assign(shrd, binop(opSHR[size], mkexpr(wide), mkU8(shift[size])));
6955 /* Elements now compacted into lower 64 bits */
6956 IRTemp new64 = newTemp(Ity_V128);
6957 assign(new64, binop(opCAT[size], mkexpr(shrd), mkexpr(shrd)));
6958 putLO64andZUorPutHI64(is2, dd, new64);
6959 const HChar* arrNarrow = nameArr_Q_SZ(bitQ, size);
6960 const HChar* arrWide = nameArr_Q_SZ(1, size+1);
6961 const HChar* nm = isADD ? (isR ? "raddhn" : "addhn")
6962 : (isR ? "rsubhn" : "subhn");
6963 DIP("%s%s %s.%s, %s.%s, %s.%s\n", nm, is2 ? "2" : "",
6964 nameQReg128(dd), arrNarrow,
6965 nameQReg128(nn), arrWide, nameQReg128(mm), arrWide);
6966 return True;
6967 }
6968
sewardj31b5a952014-06-26 07:41:14 +00006969 if (bitU == 0 && opcode == BITS4(1,1,1,0)) {
6970 /* -------- 0,1110 PMULL{2} -------- */
6971 /* Narrows, and size refers to the narrowed lanes. */
6972 if (size != X00) return False;
6973 IRTemp res
6974 = math_BINARY_WIDENING_V128(is2, Iop_PolynomialMull8x8,
6975 getQReg128(nn), getQReg128(mm));
6976 putQReg128(dd, mkexpr(res));
6977 const HChar* arrNarrow = nameArr_Q_SZ(bitQ, size);
6978 const HChar* arrWide = nameArr_Q_SZ(1, size+1);
6979 DIP("%s%s %s.%s, %s.%s, %s.%s\n", "pmull", is2 ? "2" : "",
6980 nameQReg128(dd), arrNarrow,
6981 nameQReg128(nn), arrWide, nameQReg128(mm), arrWide);
6982 return True;
6983 }
6984
sewardjdf1628c2014-06-10 22:52:05 +00006985 return False;
6986# undef INSN
6987}
6988
6989
6990static
6991Bool dis_AdvSIMD_three_same(/*MB_OUT*/DisResult* dres, UInt insn)
6992{
6993 /* 31 30 29 28 23 21 20 15 10 9 4
6994 0 Q U 01110 size 1 m opcode 1 n d
6995 Decode fields: u,size,opcode
6996 */
6997# define INSN(_bMax,_bMin) SLICE_UInt(insn, (_bMax), (_bMin))
6998 if (INSN(31,31) != 0
6999 || INSN(28,24) != BITS5(0,1,1,1,0)
7000 || INSN(21,21) != 1
7001 || INSN(10,10) != 1) {
7002 return False;
7003 }
7004 UInt bitQ = INSN(30,30);
7005 UInt bitU = INSN(29,29);
7006 UInt size = INSN(23,22);
7007 UInt mm = INSN(20,16);
7008 UInt opcode = INSN(15,11);
7009 UInt nn = INSN(9,5);
7010 UInt dd = INSN(4,0);
7011 vassert(size < 4);
7012
7013 if (bitU == 0 && opcode == BITS5(0,0,0,1,1)) {
7014 /* -------- 0,00,00011 AND 16b_16b_16b, 8b_8b_8b -------- */
7015 /* -------- 0,01,00011 BIC 16b_16b_16b, 8b_8b_8b -------- */
7016 /* -------- 0,10,00011 ORR 16b_16b_16b, 8b_8b_8b -------- */
7017 /* -------- 0,10,00011 ORN 16b_16b_16b, 8b_8b_8b -------- */
7018 Bool isQ = bitQ == 1;
7019 Bool isORR = (size & 2) == 2;
7020 Bool invert = (size & 1) == 1;
7021 IRTemp res = newTemp(Ity_V128);
7022 assign(res, binop(isORR ? Iop_OrV128 : Iop_AndV128,
7023 getQReg128(nn),
7024 invert ? unop(Iop_NotV128, getQReg128(mm))
7025 : getQReg128(mm)));
7026 putQReg128(dd, isQ ? mkexpr(res)
7027 : unop(Iop_ZeroHI64ofV128, mkexpr(res)));
7028 const HChar* names[4] = { "and", "bic", "orr", "orn" };
7029 const HChar* ar = isQ ? "16b" : "8b";
7030 DIP("%s %s.%s, %s.%s, %s.%s\n", names[INSN(23,22)],
7031 nameQReg128(dd), ar, nameQReg128(nn), ar, nameQReg128(mm), ar);
7032 return True;
7033 }
7034
7035 if (bitU == 1 && opcode == BITS5(0,0,0,1,1)) {
7036 /* -------- 1,00,00011 EOR 16b_16b_16b, 8b_8b_8b -------- */
7037 /* -------- 1,01,00011 BSL 16b_16b_16b, 8b_8b_8b -------- */
7038 /* -------- 1,10,00011 BIT 16b_16b_16b, 8b_8b_8b -------- */
7039 /* -------- 1,10,00011 BIF 16b_16b_16b, 8b_8b_8b -------- */
7040 Bool isQ = bitQ == 1;
7041 IRTemp argD = newTemp(Ity_V128);
7042 IRTemp argN = newTemp(Ity_V128);
7043 IRTemp argM = newTemp(Ity_V128);
7044 assign(argD, getQReg128(dd));
7045 assign(argN, getQReg128(nn));
7046 assign(argM, getQReg128(mm));
7047 const IROp opXOR = Iop_XorV128;
7048 const IROp opAND = Iop_AndV128;
7049 const IROp opNOT = Iop_NotV128;
7050 IRExpr* res = NULL;
7051 switch (size) {
7052 case BITS2(0,0): /* EOR */
7053 res = binop(opXOR, mkexpr(argM), mkexpr(argN));
7054 break;
7055 case BITS2(0,1): /* BSL */
7056 res = binop(opXOR, mkexpr(argM),
7057 binop(opAND,
7058 binop(opXOR, mkexpr(argM), mkexpr(argN)),
7059 mkexpr(argD)));
7060 break;
7061 case BITS2(1,0): /* BIT */
7062 res = binop(opXOR, mkexpr(argD),
7063 binop(opAND,
7064 binop(opXOR, mkexpr(argD), mkexpr(argN)),
7065 mkexpr(argM)));
7066 break;
7067 case BITS2(1,1): /* BIF */
7068 res = binop(opXOR, mkexpr(argD),
7069 binop(opAND,
7070 binop(opXOR, mkexpr(argD), mkexpr(argN)),
7071 unop(opNOT, mkexpr(argM))));
7072 break;
7073 default:
7074 vassert(0);
7075 }
7076 vassert(res);
7077 putQReg128(dd, isQ ? res : unop(Iop_ZeroHI64ofV128, res));
7078 const HChar* nms[4] = { "eor", "bsl", "bit", "bif" };
7079 const HChar* arr = isQ ? "16b" : "8b";
7080 DIP("%s %s.%s, %s.%s, %s.%s\n", nms[size],
7081 nameQReg128(dd), arr, nameQReg128(nn), arr, nameQReg128(mm), arr);
7082 return True;
7083 }
7084
7085 if (opcode == BITS5(0,0,1,1,0)) {
7086 /* -------- 0,xx,00110 CMGT std7_std7_std7 -------- */ // >s
7087 /* -------- 1,xx,00110 CMHI std7_std7_std7 -------- */ // >u
7088 if (bitQ == 0 && size == X11) return False; // implied 1d case
7089 Bool isGT = bitU == 0;
7090 const IROp opsGTS[4]
7091 = { Iop_CmpGT8Sx16, Iop_CmpGT16Sx8, Iop_CmpGT32Sx4, Iop_CmpGT64Sx2 };
7092 const IROp opsGTU[4]
7093 = { Iop_CmpGT8Ux16, Iop_CmpGT16Ux8, Iop_CmpGT32Ux4, Iop_CmpGT64Ux2 };
7094 IRExpr* argL = getQReg128(nn);
7095 IRExpr* argR = getQReg128(mm);
7096 IRTemp res = newTemp(Ity_V128);
7097 assign(res,
7098 isGT ? binop(opsGTS[size], argL, argR)
7099 : binop(opsGTU[size], argL, argR));
7100 putQReg128(dd, bitQ == 0 ? unop(Iop_ZeroHI64ofV128, mkexpr(res))
7101 : mkexpr(res));
7102 const HChar* nm = isGT ? "cmgt" : "cmhi";
7103 const HChar* arr = nameArr_Q_SZ(bitQ, size);
7104 DIP("%s %s.%s, %s.%s, %s.%s\n", nm,
7105 nameQReg128(dd), arr, nameQReg128(nn), arr, nameQReg128(mm), arr);
7106 return True;
7107 }
7108
7109 if (opcode == BITS5(0,0,1,1,1)) {
7110 /* -------- 0,xx,00111 CMGE std7_std7_std7 -------- */ // >=s
7111 /* -------- 1,xx,00111 CMHS std7_std7_std7 -------- */ // >=u
7112 if (bitQ == 0 && size == X11) return False; // implied 1d case
7113 Bool isGE = bitU == 0;
7114 const IROp opsGTS[4]
7115 = { Iop_CmpGT8Sx16, Iop_CmpGT16Sx8, Iop_CmpGT32Sx4, Iop_CmpGT64Sx2 };
7116 const IROp opsGTU[4]
7117 = { Iop_CmpGT8Ux16, Iop_CmpGT16Ux8, Iop_CmpGT32Ux4, Iop_CmpGT64Ux2 };
7118 IRExpr* argL = getQReg128(nn);
7119 IRExpr* argR = getQReg128(mm);
7120 IRTemp res = newTemp(Ity_V128);
7121 assign(res,
7122 isGE ? unop(Iop_NotV128, binop(opsGTS[size], argR, argL))
7123 : unop(Iop_NotV128, binop(opsGTU[size], argR, argL)));
7124 putQReg128(dd, bitQ == 0 ? unop(Iop_ZeroHI64ofV128, mkexpr(res))
7125 : mkexpr(res));
7126 const HChar* nm = isGE ? "cmge" : "cmhs";
7127 const HChar* arr = nameArr_Q_SZ(bitQ, size);
7128 DIP("%s %s.%s, %s.%s, %s.%s\n", nm,
7129 nameQReg128(dd), arr, nameQReg128(nn), arr, nameQReg128(mm), arr);
7130 return True;
7131 }
7132
7133 if (opcode == BITS5(0,1,1,0,0) || opcode == BITS5(0,1,1,0,1)) {
7134 /* -------- 0,xx,01100 SMAX std7_std7_std7 -------- */
7135 /* -------- 1,xx,01100 UMAX std7_std7_std7 -------- */
7136 /* -------- 0,xx,01101 SMIN std7_std7_std7 -------- */
7137 /* -------- 1,xx,01101 UMIN std7_std7_std7 -------- */
7138 if (bitQ == 0 && size == X11) return False; // implied 1d case
7139 Bool isU = bitU == 1;
7140 Bool isMAX = (opcode & 1) == 0;
7141 const IROp opMINS[4]
7142 = { Iop_Min8Sx16, Iop_Min16Sx8, Iop_Min32Sx4, Iop_Min64Sx2 };
7143 const IROp opMINU[4]
7144 = { Iop_Min8Ux16, Iop_Min16Ux8, Iop_Min32Ux4, Iop_Min64Ux2 };
7145 const IROp opMAXS[4]
7146 = { Iop_Max8Sx16, Iop_Max16Sx8, Iop_Max32Sx4, Iop_Max64Sx2 };
7147 const IROp opMAXU[4]
7148 = { Iop_Max8Ux16, Iop_Max16Ux8, Iop_Max32Ux4, Iop_Max64Ux2 };
7149 IROp op = isMAX ? (isU ? opMAXU[size] : opMAXS[size])
7150 : (isU ? opMINU[size] : opMINS[size]);
7151 IRTemp t = newTemp(Ity_V128);
7152 assign(t, binop(op, getQReg128(nn), getQReg128(mm)));
7153 putQReg128(dd, bitQ == 0 ? unop(Iop_ZeroHI64ofV128, mkexpr(t))
7154 : mkexpr(t));
7155 const HChar* nm = isMAX ? (isU ? "umax" : "smax")
7156 : (isU ? "umin" : "smin");
7157 const HChar* arr = nameArr_Q_SZ(bitQ, size);
7158 DIP("%s %s.%s, %s.%s, %s.%s\n", nm,
7159 nameQReg128(dd), arr, nameQReg128(nn), arr, nameQReg128(mm), arr);
7160 return True;
7161 }
7162
7163 if (opcode == BITS5(1,0,0,0,0)) {
7164 /* -------- 0,xx,10000 ADD std7_std7_std7 -------- */
7165 /* -------- 1,xx,10000 SUB std7_std7_std7 -------- */
7166 if (bitQ == 0 && size == X11) return False; // implied 1d case
7167 Bool isSUB = bitU == 1;
7168 const IROp opsADD[4]
7169 = { Iop_Add8x16, Iop_Add16x8, Iop_Add32x4, Iop_Add64x2 };
7170 const IROp opsSUB[4]
7171 = { Iop_Sub8x16, Iop_Sub16x8, Iop_Sub32x4, Iop_Sub64x2 };
7172 IROp op = isSUB ? opsSUB[size] : opsADD[size];
7173 IRTemp t = newTemp(Ity_V128);
7174 assign(t, binop(op, getQReg128(nn), getQReg128(mm)));
7175 putQReg128(dd, bitQ == 0 ? unop(Iop_ZeroHI64ofV128, mkexpr(t))
7176 : mkexpr(t));
7177 const HChar* nm = isSUB ? "sub" : "add";
7178 const HChar* arr = nameArr_Q_SZ(bitQ, size);
7179 DIP("%s %s.%s, %s.%s, %s.%s\n", nm,
7180 nameQReg128(dd), arr, nameQReg128(nn), arr, nameQReg128(mm), arr);
7181 return True;
7182 }
7183
7184 if (opcode == BITS5(1,0,0,0,1)) {
7185 /* -------- 0,xx,10001 CMTST std7_std7_std7 -------- */ // &, != 0
7186 /* -------- 1,xx,10001 CMEQ std7_std7_std7 -------- */ // ==
7187 if (bitQ == 0 && size == X11) return False; // implied 1d case
7188 Bool isEQ = bitU == 1;
7189 const IROp opsEQ[4]
7190 = { Iop_CmpEQ8x16, Iop_CmpEQ16x8, Iop_CmpEQ32x4, Iop_CmpEQ64x2 };
7191 IRExpr* argL = getQReg128(nn);
7192 IRExpr* argR = getQReg128(mm);
7193 IRTemp res = newTemp(Ity_V128);
7194 assign(res,
7195 isEQ ? binop(opsEQ[size], argL, argR)
7196 : unop(Iop_NotV128, binop(opsEQ[size],
7197 binop(Iop_AndV128, argL, argR),
7198 mkV128(0x0000))));
7199 putQReg128(dd, bitQ == 0 ? unop(Iop_ZeroHI64ofV128, mkexpr(res))
7200 : mkexpr(res));
7201 const HChar* nm = isEQ ? "cmeq" : "cmtst";
7202 const HChar* arr = nameArr_Q_SZ(bitQ, size);
7203 DIP("%s %s.%s, %s.%s, %s.%s\n", nm,
7204 nameQReg128(dd), arr, nameQReg128(nn), arr, nameQReg128(mm), arr);
7205 return True;
7206 }
7207
7208 if (opcode == BITS5(1,0,0,1,0)) {
7209 /* -------- 0,xx,10010 MLA std7_std7_std7 -------- */
7210 /* -------- 1,xx,10010 MLS std7_std7_std7 -------- */
7211 if (bitQ == 0 && size == X11) return False; // implied 1d case
7212 Bool isMLS = bitU == 1;
7213 const IROp opsADD[4]
7214 = { Iop_Add8x16, Iop_Add16x8, Iop_Add32x4, Iop_INVALID };
7215 const IROp opsSUB[4]
7216 = { Iop_Sub8x16, Iop_Sub16x8, Iop_Sub32x4, Iop_INVALID };
7217 const IROp opsMUL[4]
7218 = { Iop_Mul8x16, Iop_Mul16x8, Iop_Mul32x4, Iop_INVALID };
7219 IROp opMUL = opsMUL[size];
7220 IROp opADDSUB = isMLS ? opsSUB[size] : opsADD[size];
7221 IRTemp res = newTemp(Ity_V128);
7222 if (opMUL != Iop_INVALID && opADDSUB != Iop_INVALID) {
7223 assign(res, binop(opADDSUB,
7224 getQReg128(dd),
7225 binop(opMUL, getQReg128(nn), getQReg128(mm))));
7226 putQReg128(dd, bitQ == 0 ? unop(Iop_ZeroHI64ofV128, mkexpr(res))
7227 : mkexpr(res));
7228 const HChar* arr = nameArr_Q_SZ(bitQ, size);
7229 DIP("%s %s.%s, %s.%s, %s.%s\n", isMLS ? "mls" : "mla",
7230 nameQReg128(dd), arr, nameQReg128(nn), arr, nameQReg128(mm), arr);
7231 return True;
7232 }
7233 return False;
7234 }
7235
sewardjb9aff1e2014-06-15 21:55:33 +00007236 if (bitU == 0 && opcode == BITS5(1,0,1,1,1)) {
7237 if (bitQ == 0 && size == X11) return False; // implied 1d case
7238 /* -------- 0,xx,10111 ADDP std7_std7_std7 -------- */
7239 const IROp opsADD[4]
7240 = { Iop_Add8x16, Iop_Add16x8, Iop_Add32x4, Iop_Add64x2 };
7241 const IROp opsCEV[4]
7242 = { Iop_CatEvenLanes8x16, Iop_CatEvenLanes16x8, Iop_CatEvenLanes32x4,
7243 Iop_InterleaveLO64x2 };
7244 const IROp opsCOD[4]
7245 = { Iop_CatOddLanes8x16, Iop_CatOddLanes16x8, Iop_CatOddLanes32x4,
7246 Iop_InterleaveHI64x2 };
7247 IRTemp vN = newTemp(Ity_V128);
7248 IRTemp vM = newTemp(Ity_V128);
7249 assign(vN, getQReg128(nn));
7250 assign(vM, getQReg128(mm));
7251 IRTemp res128 = newTemp(Ity_V128);
7252 assign(res128, binop(opsADD[size],
7253 binop(opsCEV[size], mkexpr(vM), mkexpr(vN)),
7254 binop(opsCOD[size], mkexpr(vM), mkexpr(vN))));
7255 /* In the half-width case, use CatEL32x4 to extract the half-width
7256 result from the full-width result. */
7257 IRExpr* res
7258 = bitQ == 0 ? unop(Iop_ZeroHI64ofV128,
7259 binop(Iop_CatEvenLanes32x4, mkexpr(res128),
7260 mkexpr(res128)))
7261 : mkexpr(res128);
7262 putQReg128(dd, res);
7263 const HChar* arr = nameArr_Q_SZ(bitQ, size);
7264 DIP("addp %s.%s, %s.%s, %s.%s\n",
7265 nameQReg128(dd), arr, nameQReg128(nn), arr, nameQReg128(mm), arr);
7266 return True;
7267 }
7268
sewardjdf1628c2014-06-10 22:52:05 +00007269 if (opcode == BITS5(1,0,0,1,1)) {
7270 /* -------- 0,xx,10011 MUL std7_std7_std7 -------- */
7271 /* -------- 1,xx,10011 PMUL 16b_16b_16b, 8b_8b_8b -------- */
7272 if (bitQ == 0 && size == X11) return False; // implied 1d case
7273 Bool isPMUL = bitU == 1;
7274 const IROp opsMUL[4]
7275 = { Iop_Mul8x16, Iop_Mul16x8, Iop_Mul32x4, Iop_INVALID };
7276 const IROp opsPMUL[4]
7277 = { Iop_PolynomialMul8x16, Iop_INVALID, Iop_INVALID, Iop_INVALID };
7278 IROp opMUL = isPMUL ? opsPMUL[size] : opsMUL[size];
7279 IRTemp res = newTemp(Ity_V128);
7280 if (opMUL != Iop_INVALID) {
7281 assign(res, binop(opMUL, getQReg128(nn), getQReg128(mm)));
7282 putQReg128(dd, bitQ == 0 ? unop(Iop_ZeroHI64ofV128, mkexpr(res))
7283 : mkexpr(res));
7284 const HChar* arr = nameArr_Q_SZ(bitQ, size);
7285 DIP("%s %s.%s, %s.%s, %s.%s\n", isPMUL ? "pmul" : "mul",
7286 nameQReg128(dd), arr, nameQReg128(nn), arr, nameQReg128(mm), arr);
7287 return True;
7288 }
7289 return False;
7290 }
7291
7292 if (bitU == 0 && opcode == BITS5(1,1,0,0,1)) {
7293 /* -------- 0,0x,11001 FMLA 2d_2d_2d, 4s_4s_4s, 2s_2s_2s -------- */
7294 /* -------- 0,1x,11001 FMLS 2d_2d_2d, 4s_4s_4s, 2s_2s_2s -------- */
7295 Bool isD = (size & 1) == 1;
7296 Bool isSUB = (size & 2) == 2;
7297 if (bitQ == 0 && isD) return False; // implied 1d case
7298 IROp opADD = isD ? Iop_Add64Fx2 : Iop_Add32Fx4;
7299 IROp opSUB = isD ? Iop_Sub64Fx2 : Iop_Sub32Fx4;
7300 IROp opMUL = isD ? Iop_Mul64Fx2 : Iop_Mul32Fx4;
7301 IRTemp rm = mk_get_IR_rounding_mode();
7302 IRTemp t1 = newTemp(Ity_V128);
7303 IRTemp t2 = newTemp(Ity_V128);
7304 // FIXME: double rounding; use FMA primops instead
7305 assign(t1, triop(opMUL,
7306 mkexpr(rm), getQReg128(nn), getQReg128(mm)));
7307 assign(t2, triop(isSUB ? opSUB : opADD,
7308 mkexpr(rm), getQReg128(dd), mkexpr(t1)));
7309 putQReg128(dd, bitQ == 0 ? unop(Iop_ZeroHI64ofV128, mkexpr(t2))
7310 : mkexpr(t2));
7311 const HChar* arr = bitQ == 0 ? "2s" : (isD ? "2d" : "4s");
7312 DIP("%s %s.%s, %s.%s, %s.%s\n", isSUB ? "fmls" : "fmla",
7313 nameQReg128(dd), arr, nameQReg128(nn), arr, nameQReg128(mm), arr);
7314 return True;
7315 }
7316
7317 if (bitU == 0 && opcode == BITS5(1,1,0,1,0)) {
7318 /* -------- 0,0x,11010 FADD 2d_2d_2d, 4s_4s_4s, 2s_2s_2s -------- */
7319 /* -------- 0,1x,11010 FSUB 2d_2d_2d, 4s_4s_4s, 2s_2s_2s -------- */
7320 Bool isD = (size & 1) == 1;
7321 Bool isSUB = (size & 2) == 2;
7322 if (bitQ == 0 && isD) return False; // implied 1d case
7323 const IROp ops[4]
7324 = { Iop_Add32Fx4, Iop_Add64Fx2, Iop_Sub32Fx4, Iop_Sub64Fx2 };
7325 IROp op = ops[size];
7326 IRTemp rm = mk_get_IR_rounding_mode();
7327 IRTemp t1 = newTemp(Ity_V128);
7328 IRTemp t2 = newTemp(Ity_V128);
7329 assign(t1, triop(op, mkexpr(rm), getQReg128(nn), getQReg128(mm)));
7330 assign(t2, bitQ == 0 ? unop(Iop_ZeroHI64ofV128, mkexpr(t1))
7331 : mkexpr(t1));
7332 putQReg128(dd, mkexpr(t2));
7333 const HChar* arr = bitQ == 0 ? "2s" : (isD ? "2d" : "4s");
7334 DIP("%s %s.%s, %s.%s, %s.%s\n", isSUB ? "fsub" : "fadd",
7335 nameQReg128(dd), arr, nameQReg128(nn), arr, nameQReg128(mm), arr);
7336 return True;
7337 }
7338
7339 if (bitU == 1 && size >= X10 && opcode == BITS5(1,1,0,1,0)) {
7340 /* -------- 1,1x,11010 FABD 2d_2d_2d, 4s_4s_4s, 2s_2s_2s -------- */
7341 Bool isD = (size & 1) == 1;
7342 if (bitQ == 0 && isD) return False; // implied 1d case
7343 IROp opSUB = isD ? Iop_Sub64Fx2 : Iop_Sub32Fx4;
7344 IROp opABS = isD ? Iop_Abs64Fx2 : Iop_Abs32Fx4;
7345 IRTemp rm = mk_get_IR_rounding_mode();
7346 IRTemp t1 = newTemp(Ity_V128);
7347 IRTemp t2 = newTemp(Ity_V128);
7348 // FIXME: use Abd primop instead?
7349 assign(t1, triop(opSUB,
7350 mkexpr(rm), getQReg128(nn), getQReg128(mm)));
7351 assign(t2, unop(opABS, mkexpr(t1)));
7352 putQReg128(dd, bitQ == 0 ? unop(Iop_ZeroHI64ofV128, mkexpr(t2))
7353 : mkexpr(t2));
7354 const HChar* arr = bitQ == 0 ? "2s" : (isD ? "2d" : "4s");
7355 DIP("fabd %s.%s, %s.%s, %s.%s\n",
7356 nameQReg128(dd), arr, nameQReg128(nn), arr, nameQReg128(mm), arr);
7357 return True;
7358 }
7359
7360 if (bitU == 1 && size <= X01 && opcode == BITS5(1,1,0,1,1)) {
7361 /* -------- 1,0x,11011 FMUL 2d_2d_2d, 4s_4s_4s, 2s_2s_2s -------- */
7362 Bool isD = (size & 1) == 1;
7363 if (bitQ == 0 && isD) return False; // implied 1d case
7364 IRTemp rm = mk_get_IR_rounding_mode();
7365 IRTemp t1 = newTemp(Ity_V128);
7366 assign(t1, triop(isD ? Iop_Mul64Fx2 : Iop_Mul32Fx4,
7367 mkexpr(rm), getQReg128(nn), getQReg128(mm)));
7368 putQReg128(dd, bitQ == 0 ? unop(Iop_ZeroHI64ofV128, mkexpr(t1))
7369 : mkexpr(t1));
7370 const HChar* arr = bitQ == 0 ? "2s" : (isD ? "2d" : "4s");
7371 DIP("fmul %s.%s, %s.%s, %s.%s\n",
7372 nameQReg128(dd), arr, nameQReg128(nn), arr, nameQReg128(mm), arr);
7373 return True;
7374 }
7375
7376 if (size <= X01 && opcode == BITS5(1,1,1,0,0)) {
7377 /* -------- 0,0x,11100 FCMEQ 2d_2d_2d, 4s_4s_4s, 2s_2s_2s -------- */
7378 /* -------- 1,0x,11100 FCMGE 2d_2d_2d, 4s_4s_4s, 2s_2s_2s -------- */
7379 Bool isD = (size & 1) == 1;
7380 if (bitQ == 0 && isD) return False; // implied 1d case
7381 Bool isGE = bitU == 1;
7382 IROp opCMP = isGE ? (isD ? Iop_CmpLE64Fx2 : Iop_CmpLE32Fx4)
7383 : (isD ? Iop_CmpEQ64Fx2 : Iop_CmpEQ32Fx4);
7384 IRTemp t1 = newTemp(Ity_V128);
7385 assign(t1, isGE ? binop(opCMP, getQReg128(mm), getQReg128(nn)) // swapd
7386 : binop(opCMP, getQReg128(nn), getQReg128(mm)));
7387 putQReg128(dd, bitQ == 0 ? unop(Iop_ZeroHI64ofV128, mkexpr(t1))
7388 : mkexpr(t1));
7389 const HChar* arr = bitQ == 0 ? "2s" : (isD ? "2d" : "4s");
7390 DIP("%s %s.%s, %s.%s, %s.%s\n", isGE ? "fcmge" : "fcmeq",
7391 nameQReg128(dd), arr, nameQReg128(nn), arr, nameQReg128(mm), arr);
7392 return True;
7393 }
7394
7395 if (bitU == 1 && size >= X10 && opcode == BITS5(1,1,1,0,0)) {
7396 /* -------- 1,1x,11100 FCMGT 2d_2d_2d, 4s_4s_4s, 2s_2s_2s -------- */
7397 Bool isD = (size & 1) == 1;
7398 if (bitQ == 0 && isD) return False; // implied 1d case
7399 IROp opCMP = isD ? Iop_CmpLT64Fx2 : Iop_CmpLT32Fx4;
7400 IRTemp t1 = newTemp(Ity_V128);
7401 assign(t1, binop(opCMP, getQReg128(mm), getQReg128(nn))); // swapd
7402 putQReg128(dd, bitQ == 0 ? unop(Iop_ZeroHI64ofV128, mkexpr(t1))
7403 : mkexpr(t1));
7404 const HChar* arr = bitQ == 0 ? "2s" : (isD ? "2d" : "4s");
7405 DIP("%s %s.%s, %s.%s, %s.%s\n", "fcmgt",
7406 nameQReg128(dd), arr, nameQReg128(nn), arr, nameQReg128(mm), arr);
7407 return True;
7408 }
7409
7410 if (bitU == 1 && opcode == BITS5(1,1,1,0,1)) {
7411 /* -------- 1,0x,11101 FACGE 2d_2d_2d, 4s_4s_4s, 2s_2s_2s -------- */
7412 /* -------- 1,1x,11101 FACGT 2d_2d_2d, 4s_4s_4s, 2s_2s_2s -------- */
7413 Bool isD = (size & 1) == 1;
7414 Bool isGT = (size & 2) == 2;
7415 if (bitQ == 0 && isD) return False; // implied 1d case
7416 IROp opCMP = isGT ? (isD ? Iop_CmpLT64Fx2 : Iop_CmpLT32Fx4)
7417 : (isD ? Iop_CmpLE64Fx2 : Iop_CmpLE32Fx4);
7418 IROp opABS = isD ? Iop_Abs64Fx2 : Iop_Abs32Fx4;
7419 IRTemp t1 = newTemp(Ity_V128);
7420 assign(t1, binop(opCMP, unop(opABS, getQReg128(mm)),
7421 unop(opABS, getQReg128(nn)))); // swapd
7422 putQReg128(dd, bitQ == 0 ? unop(Iop_ZeroHI64ofV128, mkexpr(t1))
7423 : mkexpr(t1));
7424 const HChar* arr = bitQ == 0 ? "2s" : (isD ? "2d" : "4s");
7425 DIP("%s %s.%s, %s.%s, %s.%s\n", isGT ? "facgt" : "facge",
7426 nameQReg128(dd), arr, nameQReg128(nn), arr, nameQReg128(mm), arr);
7427 return True;
7428 }
7429
7430 if (bitU == 1 && size <= X01 && opcode == BITS5(1,1,1,1,1)) {
7431 /* -------- 1,0x,11111 FDIV 2d_2d_2d, 4s_4s_4s, 2s_2s_2s -------- */
7432 Bool isD = (size & 1) == 1;
7433 if (bitQ == 0 && isD) return False; // implied 1d case
7434 vassert(size <= 1);
7435 const IROp ops[2] = { Iop_Div32Fx4, Iop_Div64Fx2 };
7436 IROp op = ops[size];
7437 IRTemp rm = mk_get_IR_rounding_mode();
7438 IRTemp t1 = newTemp(Ity_V128);
7439 IRTemp t2 = newTemp(Ity_V128);
7440 assign(t1, triop(op, mkexpr(rm), getQReg128(nn), getQReg128(mm)));
7441 assign(t2, bitQ == 0 ? unop(Iop_ZeroHI64ofV128, mkexpr(t1))
7442 : mkexpr(t1));
7443 putQReg128(dd, mkexpr(t2));
7444 const HChar* arr = bitQ == 0 ? "2s" : (isD ? "2d" : "4s");
7445 DIP("%s %s.%s, %s.%s, %s.%s\n", "fdiv",
7446 nameQReg128(dd), arr, nameQReg128(nn), arr, nameQReg128(mm), arr);
7447 return True;
7448 }
7449
7450 return False;
7451# undef INSN
7452}
7453
7454
7455static
7456Bool dis_AdvSIMD_two_reg_misc(/*MB_OUT*/DisResult* dres, UInt insn)
7457{
7458 /* 31 30 29 28 23 21 16 11 9 4
7459 0 Q U 01110 size 10000 opcode 10 n d
7460 Decode fields: U,size,opcode
7461 */
7462# define INSN(_bMax,_bMin) SLICE_UInt(insn, (_bMax), (_bMin))
7463 if (INSN(31,31) != 0
7464 || INSN(28,24) != BITS5(0,1,1,1,0)
7465 || INSN(21,17) != BITS5(1,0,0,0,0)
7466 || INSN(11,10) != BITS2(1,0)) {
7467 return False;
7468 }
7469 UInt bitQ = INSN(30,30);
7470 UInt bitU = INSN(29,29);
7471 UInt size = INSN(23,22);
7472 UInt opcode = INSN(16,12);
7473 UInt nn = INSN(9,5);
7474 UInt dd = INSN(4,0);
7475 vassert(size < 4);
7476
sewardj715d1622014-06-26 12:39:05 +00007477 if (bitU == 0 && size == X00 && opcode == BITS5(0,0,0,0,1)) {
7478 /* -------- 0,00,00001: REV16 16b_16b, 8b_8b -------- */
7479 IRTemp res = newTemp(Ity_V128);
7480 assign(res, unop(Iop_Reverse8sIn16_x8, getQReg128(nn)));
7481 putQReg128(dd, math_MAYBE_ZERO_HI64(bitQ, res));
7482 const HChar* arr = nameArr_Q_SZ(bitQ, 0);
7483 DIP("%s %s.%s, %s.%s\n", "rev16",
7484 nameQReg128(dd), arr, nameQReg128(nn), arr);
7485 return True;
7486 }
7487
sewardj2b6fd5e2014-06-19 14:21:37 +00007488 if (opcode == BITS5(0,0,1,0,0)) {
7489 /* -------- 0,xx,00100: CLS std6_std6 -------- */
7490 /* -------- 1,xx,00100: CLZ std6_std6 -------- */
7491 if (size == X11) return False; // no 1d or 2d cases
sewardja8c7b0f2014-06-26 08:18:08 +00007492 const IROp opsCLS[3] = { Iop_Cls8x16, Iop_Cls16x8, Iop_Cls32x4 };
7493 const IROp opsCLZ[3] = { Iop_Clz8x16, Iop_Clz16x8, Iop_Clz32x4 };
sewardj2b6fd5e2014-06-19 14:21:37 +00007494 Bool isCLZ = bitU == 1;
7495 IRTemp res = newTemp(Ity_V128);
7496 vassert(size <= 2);
7497 assign(res, unop(isCLZ ? opsCLZ[size] : opsCLS[size], getQReg128(nn)));
7498 putQReg128(dd, bitQ == 0 ? unop(Iop_ZeroHI64ofV128, mkexpr(res))
7499 : mkexpr(res));
7500 const HChar* arr = nameArr_Q_SZ(bitQ, size);
7501 DIP("%s %s.%s, %s.%s\n", isCLZ ? "clz" : "cls",
7502 nameQReg128(dd), arr, nameQReg128(nn), arr);
7503 return True;
7504 }
7505
sewardj787a67f2014-06-23 09:09:41 +00007506 if (size == X00 && opcode == BITS5(0,0,1,0,1)) {
sewardj2b6fd5e2014-06-19 14:21:37 +00007507 /* -------- 0,00,00101: CNT 16b_16b, 8b_8b -------- */
sewardj787a67f2014-06-23 09:09:41 +00007508 /* -------- 1,00,00101: NOT 16b_16b, 8b_8b -------- */
sewardj2b6fd5e2014-06-19 14:21:37 +00007509 IRTemp res = newTemp(Ity_V128);
sewardj787a67f2014-06-23 09:09:41 +00007510 assign(res, unop(bitU == 0 ? Iop_Cnt8x16 : Iop_NotV128, getQReg128(nn)));
sewardj2b6fd5e2014-06-19 14:21:37 +00007511 putQReg128(dd, bitQ == 0 ? unop(Iop_ZeroHI64ofV128, mkexpr(res))
7512 : mkexpr(res));
sewardj715d1622014-06-26 12:39:05 +00007513 const HChar* arr = nameArr_Q_SZ(bitQ, 0);
sewardj787a67f2014-06-23 09:09:41 +00007514 DIP("%s %s.%s, %s.%s\n", bitU == 0 ? "cnt" : "not",
sewardj2b6fd5e2014-06-19 14:21:37 +00007515 nameQReg128(dd), arr, nameQReg128(nn), arr);
7516 return True;
7517 }
7518
sewardj715d1622014-06-26 12:39:05 +00007519 if (bitU == 1 && size == X01 && opcode == BITS5(0,0,1,0,1)) {
7520 /* -------- 1,01,00101 RBIT 16b_16b, 8b_8b -------- */
7521 IRTemp res = newTemp(Ity_V128);
7522 assign(res, unop(Iop_Reverse1sIn8_x16, getQReg128(nn)));
7523 putQReg128(dd, bitQ == 0 ? unop(Iop_ZeroHI64ofV128, mkexpr(res))
7524 : mkexpr(res));
7525 const HChar* arr = nameArr_Q_SZ(bitQ, 0);
7526 DIP("%s %s.%s, %s.%s\n", "rbit",
7527 nameQReg128(dd), arr, nameQReg128(nn), arr);
7528 return True;
7529 }
7530
sewardjdf1628c2014-06-10 22:52:05 +00007531 if (opcode == BITS5(0,1,0,0,0)) {
7532 /* -------- 0,xx,01000: CMGT std7_std7_#0 -------- */ // >s 0
7533 /* -------- 1,xx,01000: CMGE std7_std7_#0 -------- */ // >=s 0
7534 if (bitQ == 0 && size == X11) return False; // implied 1d case
7535 const IROp opsGTS[4]
7536 = { Iop_CmpGT8Sx16, Iop_CmpGT16Sx8, Iop_CmpGT32Sx4, Iop_CmpGT64Sx2 };
7537 Bool isGT = bitU == 0;
7538 IRExpr* argL = getQReg128(nn);
7539 IRExpr* argR = mkV128(0x0000);
7540 IRTemp res = newTemp(Ity_V128);
7541 assign(res, isGT ? binop(opsGTS[size], argL, argR)
7542 : unop(Iop_NotV128, binop(opsGTS[size], argR, argL)));
7543 putQReg128(dd, bitQ == 0 ? unop(Iop_ZeroHI64ofV128, mkexpr(res))
7544 : mkexpr(res));
7545 const HChar* arr = nameArr_Q_SZ(bitQ, size);
7546 DIP("cm%s %s.%s, %s.%s, #0\n", isGT ? "gt" : "ge",
7547 nameQReg128(dd), arr, nameQReg128(nn), arr);
7548 return True;
7549 }
7550
7551 if (opcode == BITS5(0,1,0,0,1)) {
7552 /* -------- 0,xx,01001: CMEQ std7_std7_#0 -------- */ // == 0
7553 /* -------- 1,xx,01001: CMLE std7_std7_#0 -------- */ // <=s 0
7554 if (bitQ == 0 && size == X11) return False; // implied 1d case
7555 const IROp opsEQ[4]
7556 = { Iop_CmpEQ8x16, Iop_CmpEQ16x8, Iop_CmpEQ32x4, Iop_CmpEQ64x2 };
7557 const IROp opsGTS[4]
7558 = { Iop_CmpGT8Sx16, Iop_CmpGT16Sx8, Iop_CmpGT32Sx4, Iop_CmpGT64Sx2 };
7559 Bool isEQ = bitU == 0;
7560 IRExpr* argL = getQReg128(nn);
7561 IRExpr* argR = mkV128(0x0000);
7562 IRTemp res = newTemp(Ity_V128);
7563 assign(res, isEQ ? binop(opsEQ[size], argL, argR)
7564 : unop(Iop_NotV128,
7565 binop(opsGTS[size], argL, argR)));
7566 putQReg128(dd, bitQ == 0 ? unop(Iop_ZeroHI64ofV128, mkexpr(res))
7567 : mkexpr(res));
7568 const HChar* arr = nameArr_Q_SZ(bitQ, size);
7569 DIP("cm%s %s.%s, %s.%s, #0\n", isEQ ? "eq" : "le",
7570 nameQReg128(dd), arr, nameQReg128(nn), arr);
7571 return True;
7572 }
7573
7574 if (bitU == 0 && opcode == BITS5(0,1,0,1,0)) {
7575 /* -------- 0,xx,01010: CMLT std7_std7_#0 -------- */ // <s 0
7576 if (bitQ == 0 && size == X11) return False; // implied 1d case
7577 const IROp opsGTS[4]
7578 = { Iop_CmpGT8Sx16, Iop_CmpGT16Sx8, Iop_CmpGT32Sx4, Iop_CmpGT64Sx2 };
7579 IRExpr* argL = getQReg128(nn);
7580 IRExpr* argR = mkV128(0x0000);
7581 IRTemp res = newTemp(Ity_V128);
7582 assign(res, binop(opsGTS[size], argR, argL));
7583 putQReg128(dd, bitQ == 0 ? unop(Iop_ZeroHI64ofV128, mkexpr(res))
7584 : mkexpr(res));
7585 const HChar* arr = nameArr_Q_SZ(bitQ, size);
7586 DIP("cm%s %s.%s, %s.%s, #0\n", "lt",
7587 nameQReg128(dd), arr, nameQReg128(nn), arr);
7588 return True;
7589 }
7590
sewardj25523c42014-06-15 19:36:29 +00007591 if (bitU == 0 && opcode == BITS5(0,1,0,1,1)) {
7592 /* -------- 0,xx,01011: ABS std7_std7 -------- */
7593 if (bitQ == 0 && size == X11) return False; // implied 1d case
7594 const IROp opABS[4]
7595 = { Iop_Abs8x16, Iop_Abs16x8, Iop_Abs32x4, Iop_Abs64x2 };
7596 IRTemp res = newTemp(Ity_V128);
7597 assign(res, unop(opABS[size], getQReg128(nn)));
7598 putQReg128(dd, bitQ == 0 ? unop(Iop_ZeroHI64ofV128, mkexpr(res))
7599 : mkexpr(res));
7600 const HChar* arr = nameArr_Q_SZ(bitQ, size);
7601 DIP("abs %s.%s, %s.%s\n", nameQReg128(dd), arr, nameQReg128(nn), arr);
7602 return True;
7603 }
7604
sewardjdf1628c2014-06-10 22:52:05 +00007605 if (bitU == 1 && opcode == BITS5(0,1,0,1,1)) {
7606 /* -------- 1,xx,01011: NEG std7_std7 -------- */
7607 if (bitQ == 0 && size == X11) return False; // implied 1d case
7608 const IROp opSUB[4]
7609 = { Iop_Sub8x16, Iop_Sub16x8, Iop_Sub32x4, Iop_Sub64x2 };
7610 IRTemp res = newTemp(Ity_V128);
7611 assign(res, binop(opSUB[size], mkV128(0x0000), getQReg128(nn)));
7612 putQReg128(dd, bitQ == 0 ? unop(Iop_ZeroHI64ofV128, mkexpr(res))
7613 : mkexpr(res));
7614 const HChar* arr = nameArr_Q_SZ(bitQ, size);
7615 DIP("neg %s.%s, %s.%s\n", nameQReg128(dd), arr, nameQReg128(nn), arr);
7616 return True;
7617 }
7618
7619 if (size >= X10 && opcode == BITS5(0,1,1,1,1)) {
7620 /* -------- 0,1x,01111: FABS 2d_2d, 4s_4s, 2s_2s -------- */
7621 /* -------- 1,1x,01111: FNEG 2d_2d, 4s_4s, 2s_2s -------- */
7622 if (bitQ == 0 && size == X11) return False; // implied 1d case
7623 Bool isFNEG = bitU == 1;
7624 IROp op = isFNEG ? (size == X10 ? Iop_Neg32Fx4 : Iop_Neg64Fx2)
7625 : (size == X10 ? Iop_Abs32Fx4 : Iop_Abs64Fx2);
7626 IRTemp res = newTemp(Ity_V128);
7627 assign(res, unop(op, getQReg128(nn)));
7628 putQReg128(dd, bitQ == 0 ? unop(Iop_ZeroHI64ofV128, mkexpr(res))
7629 : mkexpr(res));
7630 const HChar* arr = bitQ == 0 ? "2s" : (size == X11 ? "2d" : "4s");
7631 DIP("%s %s.%s, %s.%s\n", isFNEG ? "fneg" : "fabs",
7632 nameQReg128(dd), arr, nameQReg128(nn), arr);
7633 return True;
7634 }
7635
7636 if (bitU == 0 && opcode == BITS5(1,0,0,1,0)) {
7637 /* -------- 0,xx,10010: XTN{,2} -------- */
7638 /* 31 28 23 21 15 9 4 XTN{,2} Vd.Tb, Vn.Ta
7639 0q0 01110 size 100001 001010 n d
7640 */
7641 Bool isQ = bitQ == 1;
7642 IROp op = Iop_INVALID;
7643 const HChar* tb = NULL;
7644 const HChar* ta = NULL;
7645 switch ((size << 1) | (isQ ? 1 : 0)) {
7646 case 0: tb = "8b"; ta = "8h"; op = Iop_NarrowUn16to8x8; break;
7647 case 1: tb = "16b"; ta = "8h"; op = Iop_NarrowUn16to8x8; break;
7648 case 2: tb = "4h"; ta = "4s"; op = Iop_NarrowUn32to16x4; break;
7649 case 3: tb = "8h"; ta = "4s"; op = Iop_NarrowUn32to16x4; break;
7650 case 4: tb = "2s"; ta = "2d"; op = Iop_NarrowUn64to32x2; break;
7651 case 5: tb = "4s"; ta = "2d"; op = Iop_NarrowUn64to32x2; break;
7652 case 6: break;
7653 case 7: break;
7654 default: vassert(0);
7655 }
7656 if (op != Iop_INVALID) {
7657 if (!isQ) {
7658 putQRegLane(dd, 1, mkU64(0));
7659 }
7660 putQRegLane(dd, isQ ? 1 : 0, unop(op, getQReg128(nn)));
7661 DIP("xtn%s %s.%s, %s.%s\n", isQ ? "2" : "",
7662 nameQReg128(dd), tb, nameQReg128(nn), ta);
7663 return True;
7664 }
7665 return False;
7666 }
7667
7668 if (bitU == 0 && size == X01 && opcode == BITS5(1,0,1,1,0)) {
7669 /* -------- 0,01,10110: FCVTN 2s/4s_2d -------- */
7670 IRTemp rm = mk_get_IR_rounding_mode();
7671 IRExpr* srcLo = getQRegLane(nn, 0, Ity_F64);
7672 IRExpr* srcHi = getQRegLane(nn, 1, Ity_F64);
7673 putQRegLane(dd, 2 * bitQ + 0, binop(Iop_F64toF32, mkexpr(rm), srcLo));
7674 putQRegLane(dd, 2 * bitQ + 1, binop(Iop_F64toF32, mkexpr(rm), srcHi));
7675 if (bitQ == 0) {
7676 putQRegLane(dd, 1, mkU64(0));
7677 }
7678 DIP("fcvtn%s %s.%s, %s.2d\n", bitQ ? "2" : "",
7679 nameQReg128(dd), bitQ ? "4s" : "2s", nameQReg128(nn));
7680 return True;
7681 }
7682
sewardj5747c4a2014-06-11 20:57:23 +00007683 if (size <= X01 && opcode == BITS5(1,1,1,0,1)) {
7684 /* -------- 0,0x,11101: SCVTF -------- */
7685 /* -------- 1,0x,11101: UCVTF -------- */
7686 /* 31 28 22 21 15 9 4
7687 0q0 01110 0 sz 1 00001 110110 n d SCVTF Vd, Vn
7688 0q1 01110 0 sz 1 00001 110110 n d UCVTF Vd, Vn
7689 with laneage:
7690 case sz:Q of 00 -> 2S, zero upper, 01 -> 4S, 10 -> illegal, 11 -> 2D
7691 */
7692 Bool isQ = bitQ == 1;
7693 Bool isU = bitU == 1;
7694 Bool isF64 = (size & 1) == 1;
7695 if (isQ || !isF64) {
7696 IRType tyF = Ity_INVALID, tyI = Ity_INVALID;
7697 UInt nLanes = 0;
7698 Bool zeroHI = False;
7699 const HChar* arrSpec = NULL;
7700 Bool ok = getLaneInfo_Q_SZ(&tyI, &tyF, &nLanes, &zeroHI, &arrSpec,
7701 isQ, isF64 );
7702 IROp iop = isU ? (isF64 ? Iop_I64UtoF64 : Iop_I32UtoF32)
7703 : (isF64 ? Iop_I64StoF64 : Iop_I32StoF32);
7704 IRTemp rm = mk_get_IR_rounding_mode();
7705 UInt i;
7706 vassert(ok); /* the 'if' above should ensure this */
7707 for (i = 0; i < nLanes; i++) {
7708 putQRegLane(dd, i,
7709 binop(iop, mkexpr(rm), getQRegLane(nn, i, tyI)));
7710 }
7711 if (zeroHI) {
7712 putQRegLane(dd, 1, mkU64(0));
7713 }
7714 DIP("%ccvtf %s.%s, %s.%s\n", isU ? 'u' : 's',
7715 nameQReg128(dd), arrSpec, nameQReg128(nn), arrSpec);
7716 return True;
7717 }
7718 /* else fall through */
7719 }
7720
sewardjdf1628c2014-06-10 22:52:05 +00007721 return False;
7722# undef INSN
7723}
7724
sewardjfc83d2c2014-06-12 10:15:46 +00007725
sewardjdf1628c2014-06-10 22:52:05 +00007726static
7727Bool dis_AdvSIMD_vector_x_indexed_elem(/*MB_OUT*/DisResult* dres, UInt insn)
7728{
sewardj85fbb022014-06-12 13:16:01 +00007729 /* 31 28 23 21 20 19 15 11 9 4
7730 0 Q U 01111 size L M m opcode H 0 n d
7731 Decode fields are: u,size,opcode
sewardj787a67f2014-06-23 09:09:41 +00007732 M is really part of the mm register number. Individual
7733 cases need to inspect L and H though.
sewardj85fbb022014-06-12 13:16:01 +00007734 */
sewardjdf1628c2014-06-10 22:52:05 +00007735# define INSN(_bMax,_bMin) SLICE_UInt(insn, (_bMax), (_bMin))
sewardj85fbb022014-06-12 13:16:01 +00007736 if (INSN(31,31) != 0
7737 && INSN(28,24) != BITS5(0,1,1,1,1) && INSN(10,10) !=0) {
7738 return False;
7739 }
7740 UInt bitQ = INSN(30,30);
7741 UInt bitU = INSN(29,29);
7742 UInt size = INSN(23,22);
7743 UInt bitL = INSN(21,21);
7744 UInt bitM = INSN(20,20);
7745 UInt mmLO4 = INSN(19,16);
7746 UInt opcode = INSN(15,12);
7747 UInt bitH = INSN(11,11);
7748 UInt nn = INSN(9,5);
7749 UInt dd = INSN(4,0);
sewardj85fbb022014-06-12 13:16:01 +00007750 vassert(size < 4);
sewardj787a67f2014-06-23 09:09:41 +00007751 vassert(bitH < 2 && bitM < 2 && bitL < 2);
sewardj85fbb022014-06-12 13:16:01 +00007752
7753 if (bitU == 0 && size >= X10 && opcode == BITS4(1,0,0,1)) {
7754 /* -------- 0,1x,1001 FMUL 2d_2d_d[], 4s_4s_s[], 2s_2s_s[] -------- */
7755 if (bitQ == 0 && size == X11) return False; // implied 1d case
7756 Bool isD = (size & 1) == 1;
7757 UInt index;
7758 if (!isD) index = (bitH << 1) | bitL;
7759 else if (isD && bitL == 0) index = bitH;
7760 else return False; // sz:L == x11 => unallocated encoding
7761 vassert(index < (isD ? 2 : 4));
7762 IRType ity = isD ? Ity_F64 : Ity_F32;
7763 IRTemp elem = newTemp(ity);
sewardj787a67f2014-06-23 09:09:41 +00007764 UInt mm = (bitM << 4) | mmLO4;
sewardj85fbb022014-06-12 13:16:01 +00007765 assign(elem, getQRegLane(mm, index, ity));
7766 IRTemp dupd = math_DUP_TO_V128(elem, ity);
7767 IRTemp res = newTemp(Ity_V128);
7768 assign(res, triop(isD ? Iop_Mul64Fx2 : Iop_Mul32Fx4,
7769 mkexpr(mk_get_IR_rounding_mode()),
7770 getQReg128(nn), mkexpr(dupd)));
7771 putQReg128(dd, bitQ == 0 ? unop(Iop_ZeroHI64ofV128, mkexpr(res))
7772 : mkexpr(res));
7773 const HChar* arr = bitQ == 0 ? "2s" : (isD ? "2d" : "4s");
7774 DIP("fmul %s.%s, %s.%s, %s.%c[%u]\n", nameQReg128(dd), arr,
7775 nameQReg128(nn), arr, nameQReg128(mm), isD ? 'd' : 's', index);
7776 return True;
7777 }
7778
sewardj787a67f2014-06-23 09:09:41 +00007779 if ((bitU == 1 && (opcode == BITS4(0,0,0,0) || opcode == BITS4(0,1,0,0)))
7780 || (bitU == 0 && opcode == BITS4(1,0,0,0))) {
7781 /* -------- 1,xx,0000 MLA s/h variants only -------- */
7782 /* -------- 1,xx,0100 MLS s/h variants only -------- */
7783 /* -------- 0,xx,1000 MUL s/h variants only -------- */
7784 Bool isMLA = opcode == BITS4(0,0,0,0);
7785 Bool isMLS = opcode == BITS4(0,1,0,0);
7786 UInt mm = 32; // invalid
7787 UInt ix = 16; // invalid
7788 switch (size) {
7789 case X00:
7790 return False; // b case is not allowed
7791 case X01:
7792 mm = mmLO4; ix = (bitH << 2) | (bitL << 1) | (bitM << 0); break;
7793 case X10:
7794 mm = (bitM << 4) | mmLO4; ix = (bitH << 1) | (bitL << 0); break;
7795 case X11:
7796 return False; // d case is not allowed
7797 default:
7798 vassert(0);
7799 }
7800 vassert(mm < 32 && ix < 16);
7801 IROp opMUL = size == X01 ? Iop_Mul16x8 : Iop_Mul32x4;
7802 IROp opADD = size == X01 ? Iop_Add16x8 : Iop_Add32x4;
7803 IROp opSUB = size == X01 ? Iop_Sub16x8 : Iop_Sub32x4;
7804 IRType ity = size == X01 ? Ity_I16 : Ity_I32;
7805 HChar ch = size == X01 ? 'h' : 's';
7806 IRTemp elemM = newTemp(ity);
7807 assign(elemM, getQRegLane(mm, ix, ity));
7808 IRTemp vecM = math_DUP_TO_V128(elemM, ity);
7809 IRTemp vecD = newTemp(Ity_V128);
7810 IRTemp vecN = newTemp(Ity_V128);
7811 IRTemp res = newTemp(Ity_V128);
7812 assign(vecD, getQReg128(dd));
7813 assign(vecN, getQReg128(nn));
7814 IRExpr* prod = binop(opMUL, mkexpr(vecN), mkexpr(vecM));
7815 if (isMLA || isMLS) {
7816 assign(res, binop(isMLA ? opADD : opSUB, mkexpr(vecD), prod));
7817 } else {
7818 assign(res, prod);
7819 }
7820 putQReg128(dd, bitQ == 0 ? unop(Iop_ZeroHI64ofV128, mkexpr(res))
7821 : mkexpr(res));
7822 const HChar* arr = nameArr_Q_SZ(bitQ, size);
7823 DIP("%s %s.%s, %s.%s, %s.%c[%u]\n", isMLA ? "mla"
7824 : (isMLS ? "mls" : "mul"),
7825 nameQReg128(dd), arr,
7826 nameQReg128(nn), arr, nameQReg128(dd), ch, ix);
7827 return True;
7828 }
7829
sewardjdf1628c2014-06-10 22:52:05 +00007830 return False;
7831# undef INSN
7832}
7833
sewardjfc83d2c2014-06-12 10:15:46 +00007834
sewardjdf1628c2014-06-10 22:52:05 +00007835static
7836Bool dis_AdvSIMD_crypto_aes(/*MB_OUT*/DisResult* dres, UInt insn)
7837{
7838# define INSN(_bMax,_bMin) SLICE_UInt(insn, (_bMax), (_bMin))
7839 return False;
7840# undef INSN
7841}
7842
sewardjfc83d2c2014-06-12 10:15:46 +00007843
sewardjdf1628c2014-06-10 22:52:05 +00007844static
7845Bool dis_AdvSIMD_crypto_three_reg_sha(/*MB_OUT*/DisResult* dres, UInt insn)
7846{
7847# define INSN(_bMax,_bMin) SLICE_UInt(insn, (_bMax), (_bMin))
7848 return False;
7849# undef INSN
7850}
7851
sewardjfc83d2c2014-06-12 10:15:46 +00007852
sewardjdf1628c2014-06-10 22:52:05 +00007853static
7854Bool dis_AdvSIMD_crypto_two_reg_sha(/*MB_OUT*/DisResult* dres, UInt insn)
7855{
7856# define INSN(_bMax,_bMin) SLICE_UInt(insn, (_bMax), (_bMin))
7857 return False;
7858# undef INSN
7859}
7860
sewardj5747c4a2014-06-11 20:57:23 +00007861
sewardjdf1628c2014-06-10 22:52:05 +00007862static
7863Bool dis_AdvSIMD_fp_compare(/*MB_OUT*/DisResult* dres, UInt insn)
7864{
sewardj5747c4a2014-06-11 20:57:23 +00007865 /* 31 28 23 21 20 15 13 9 4
7866 000 11110 ty 1 m op 1000 n opcode2
7867 The first 3 bits are really "M 0 S", but M and S are always zero.
7868 Decode fields are: ty,op,opcode2
7869 */
sewardjdf1628c2014-06-10 22:52:05 +00007870# define INSN(_bMax,_bMin) SLICE_UInt(insn, (_bMax), (_bMin))
sewardj5747c4a2014-06-11 20:57:23 +00007871 if (INSN(31,24) != BITS8(0,0,0,1,1,1,1,0)
7872 || INSN(21,21) != 1 || INSN(13,10) != BITS4(1,0,0,0)) {
7873 return False;
7874 }
7875 UInt ty = INSN(23,22);
7876 UInt mm = INSN(20,16);
7877 UInt op = INSN(15,14);
7878 UInt nn = INSN(9,5);
7879 UInt opcode2 = INSN(4,0);
7880 vassert(ty < 4);
7881
7882 if (ty <= X01 && op == X00
7883 && (opcode2 & BITS5(0,0,1,1,1)) == BITS5(0,0,0,0,0)) {
7884 /* -------- 0x,00,00000 FCMP d_d, s_s -------- */
7885 /* -------- 0x,00,01000 FCMP d_#0, s_#0 -------- */
7886 /* -------- 0x,00,10000 FCMPE d_d, s_s -------- */
7887 /* -------- 0x,00,11000 FCMPE d_#0, s_#0 -------- */
7888 /* 31 23 20 15 9 4
7889 000 11110 01 1 m 00 1000 n 10 000 FCMPE Dn, Dm
7890 000 11110 01 1 00000 00 1000 n 11 000 FCMPE Dn, #0.0
7891 000 11110 01 1 m 00 1000 n 00 000 FCMP Dn, Dm
7892 000 11110 01 1 00000 00 1000 n 01 000 FCMP Dn, #0.0
7893
7894 000 11110 00 1 m 00 1000 n 10 000 FCMPE Sn, Sm
7895 000 11110 00 1 00000 00 1000 n 11 000 FCMPE Sn, #0.0
7896 000 11110 00 1 m 00 1000 n 00 000 FCMP Sn, Sm
7897 000 11110 00 1 00000 00 1000 n 01 000 FCMP Sn, #0.0
7898
7899 FCMPE generates Invalid Operation exn if either arg is any kind
7900 of NaN. FCMP generates Invalid Operation exn if either arg is a
7901 signalling NaN. We ignore this detail here and produce the same
7902 IR for both.
7903 */
7904 Bool isD = (ty & 1) == 1;
7905 Bool isCMPE = (opcode2 & 16) == 16;
7906 Bool cmpZero = (opcode2 & 8) == 8;
7907 IRType ity = isD ? Ity_F64 : Ity_F32;
7908 Bool valid = True;
7909 if (cmpZero && mm != 0) valid = False;
7910 if (valid) {
7911 IRTemp argL = newTemp(ity);
7912 IRTemp argR = newTemp(ity);
7913 IRTemp irRes = newTemp(Ity_I32);
7914 assign(argL, getQRegLO(nn, ity));
7915 assign(argR,
7916 cmpZero
7917 ? (IRExpr_Const(isD ? IRConst_F64i(0) : IRConst_F32i(0)))
7918 : getQRegLO(mm, ity));
7919 assign(irRes, binop(isD ? Iop_CmpF64 : Iop_CmpF32,
7920 mkexpr(argL), mkexpr(argR)));
7921 IRTemp nzcv = mk_convert_IRCmpF64Result_to_NZCV(irRes);
7922 IRTemp nzcv_28x0 = newTemp(Ity_I64);
7923 assign(nzcv_28x0, binop(Iop_Shl64, mkexpr(nzcv), mkU8(28)));
7924 setFlags_COPY(nzcv_28x0);
7925 DIP("fcmp%s %s, %s\n", isCMPE ? "e" : "", nameQRegLO(nn, ity),
7926 cmpZero ? "#0.0" : nameQRegLO(mm, ity));
7927 return True;
7928 }
7929 return False;
7930 }
7931
sewardjdf1628c2014-06-10 22:52:05 +00007932 return False;
7933# undef INSN
7934}
7935
sewardj5747c4a2014-06-11 20:57:23 +00007936
sewardjdf1628c2014-06-10 22:52:05 +00007937static
7938Bool dis_AdvSIMD_fp_conditional_compare(/*MB_OUT*/DisResult* dres, UInt insn)
7939{
7940# define INSN(_bMax,_bMin) SLICE_UInt(insn, (_bMax), (_bMin))
7941 return False;
7942# undef INSN
7943}
7944
sewardjfc83d2c2014-06-12 10:15:46 +00007945
sewardjdf1628c2014-06-10 22:52:05 +00007946static
7947Bool dis_AdvSIMD_fp_conditional_select(/*MB_OUT*/DisResult* dres, UInt insn)
7948{
7949# define INSN(_bMax,_bMin) SLICE_UInt(insn, (_bMax), (_bMin))
7950 return False;
7951# undef INSN
7952}
7953
sewardj5747c4a2014-06-11 20:57:23 +00007954
sewardjdf1628c2014-06-10 22:52:05 +00007955static
7956Bool dis_AdvSIMD_fp_data_proc_1_source(/*MB_OUT*/DisResult* dres, UInt insn)
7957{
7958 /* 31 28 23 21 20 14 9 4
7959 000 11110 ty 1 opcode 10000 n d
7960 The first 3 bits are really "M 0 S", but M and S are always zero.
sewardj5747c4a2014-06-11 20:57:23 +00007961 Decode fields: ty,opcode
sewardjdf1628c2014-06-10 22:52:05 +00007962 */
7963# define INSN(_bMax,_bMin) SLICE_UInt(insn, (_bMax), (_bMin))
7964 if (INSN(31,24) != BITS8(0,0,0,1,1,1,1,0)
7965 || INSN(21,21) != 1 || INSN(14,10) != BITS5(1,0,0,0,0)) {
7966 return False;
7967 }
7968 UInt ty = INSN(23,22);
7969 UInt opcode = INSN(20,15);
7970 UInt nn = INSN(9,5);
7971 UInt dd = INSN(4,0);
7972
7973 if (ty <= X01 && opcode <= BITS6(0,0,0,0,1,1)) {
7974 /* -------- 0x,000000: FMOV d_d, s_s -------- */
7975 /* -------- 0x,000001: FABS d_d, s_s -------- */
7976 /* -------- 0x,000010: FNEG d_d, s_s -------- */
7977 /* -------- 0x,000011: FSQRT d_d, s_s -------- */
7978 IRType ity = ty == X01 ? Ity_F64 : Ity_F32;
7979 IRTemp src = newTemp(ity);
7980 IRTemp res = newTemp(ity);
7981 const HChar* nm = "??";
7982 assign(src, getQRegLO(nn, ity));
7983 switch (opcode) {
7984 case BITS6(0,0,0,0,0,0):
7985 nm = "fmov"; assign(res, mkexpr(src)); break;
7986 case BITS6(0,0,0,0,0,1):
7987 nm = "fabs"; assign(res, unop(mkABSF(ity), mkexpr(src))); break;
7988 case BITS6(0,0,0,0,1,0):
7989 nm = "fabs"; assign(res, unop(mkNEGF(ity), mkexpr(src))); break;
7990 case BITS6(0,0,0,0,1,1):
7991 nm = "fsqrt";
7992 assign(res, binop(mkSQRTF(ity),
7993 mkexpr(mk_get_IR_rounding_mode()),
7994 mkexpr(src))); break;
7995 default:
7996 vassert(0);
7997 }
7998 putQReg128(dd, mkV128(0x0000));
7999 putQRegLO(dd, mkexpr(res));
8000 DIP("%s %s, %s\n", nm, nameQRegLO(dd, ity), nameQRegLO(nn, ity));
8001 return True;
8002 }
8003
sewardj5747c4a2014-06-11 20:57:23 +00008004 if ( (ty == X11 && (opcode == BITS6(0,0,0,1,0,0)
8005 || opcode == BITS6(0,0,0,1,0,1)))
8006 || (ty == X00 && (opcode == BITS6(0,0,0,1,1,1)
8007 || opcode == BITS6(0,0,0,1,0,1)))
8008 || (ty == X01 && (opcode == BITS6(0,0,0,1,1,1)
8009 || opcode == BITS6(0,0,0,1,0,0)))) {
8010 /* -------- 11,000100: FCVT s_h -------- */
8011 /* -------- 11,000101: FCVT d_h -------- */
8012 /* -------- 00,000111: FCVT h_s -------- */
8013 /* -------- 00,000101: FCVT d_s -------- */
8014 /* -------- 01,000111: FCVT h_d -------- */
8015 /* -------- 01,000100: FCVT s_d -------- */
8016 /* 31 23 21 16 14 9 4
8017 000 11110 11 10001 00 10000 n d FCVT Sd, Hn (unimp)
8018 --------- 11 ----- 01 --------- FCVT Dd, Hn (unimp)
8019 --------- 00 ----- 11 --------- FCVT Hd, Sn (unimp)
8020 --------- 00 ----- 01 --------- FCVT Dd, Sn
8021 --------- 01 ----- 11 --------- FCVT Hd, Dn (unimp)
8022 --------- 01 ----- 00 --------- FCVT Sd, Dn
8023 Rounding, when dst is smaller than src, is per the FPCR.
8024 */
8025 UInt b2322 = ty;
8026 UInt b1615 = opcode & BITS2(1,1);
8027 if (b2322 == BITS2(0,0) && b1615 == BITS2(0,1)) {
8028 /* Convert S to D */
8029 IRTemp res = newTemp(Ity_F64);
8030 assign(res, unop(Iop_F32toF64, getQRegLO(nn, Ity_F32)));
8031 putQReg128(dd, mkV128(0x0000));
8032 putQRegLO(dd, mkexpr(res));
8033 DIP("fcvt %s, %s\n",
8034 nameQRegLO(dd, Ity_F64), nameQRegLO(nn, Ity_F32));
8035 return True;
8036 }
8037 if (b2322 == BITS2(0,1) && b1615 == BITS2(0,0)) {
8038 /* Convert D to S */
8039 IRTemp res = newTemp(Ity_F32);
8040 assign(res, binop(Iop_F64toF32, mkexpr(mk_get_IR_rounding_mode()),
8041 getQRegLO(nn, Ity_F64)));
8042 putQReg128(dd, mkV128(0x0000));
8043 putQRegLO(dd, mkexpr(res));
8044 DIP("fcvt %s, %s\n",
8045 nameQRegLO(dd, Ity_F32), nameQRegLO(nn, Ity_F64));
8046 return True;
8047 }
8048 /* else unhandled */
8049 return False;
8050 }
8051
8052 if (ty <= X01
8053 && opcode >= BITS6(0,0,1,0,0,0) && opcode <= BITS6(0,0,1,1,1,1)
8054 && opcode != BITS6(0,0,1,1,0,1)) {
8055 /* -------- 0x,001000 FRINTN d_d, s_s -------- */
8056 /* -------- 0x,001001 FRINTP d_d, s_s -------- */
8057 /* -------- 0x,001010 FRINTM d_d, s_s -------- */
8058 /* -------- 0x,001011 FRINTZ d_d, s_s -------- */
8059 /* -------- 0x,001100 FRINTA d_d, s_s -------- */
8060 /* -------- 0x,001110 FRINTX d_d, s_s -------- */
8061 /* -------- 0x,001111 FRINTI d_d, s_s -------- */
8062 /* 31 23 21 17 14 9 4
8063 000 11110 0x 1001 111 10000 n d FRINTI Fd, Fm (round per FPCR)
8064 rm
8065 x==0 => S-registers, x==1 => D-registers
8066 rm (17:15) encodings:
8067 111 per FPCR (FRINTI)
8068 001 +inf (FRINTP)
8069 010 -inf (FRINTM)
8070 011 zero (FRINTZ)
8071 000 tieeven
8072 100 tieaway (FRINTA) -- !! FIXME KLUDGED !!
8073 110 per FPCR + "exact = TRUE"
8074 101 unallocated
8075 */
8076 Bool isD = (ty & 1) == 1;
8077 UInt rm = opcode & BITS6(0,0,0,1,1,1);
8078 IRType ity = isD ? Ity_F64 : Ity_F32;
8079 IRExpr* irrmE = NULL;
8080 UChar ch = '?';
8081 switch (rm) {
8082 case BITS3(0,1,1): ch = 'z'; irrmE = mkU32(Irrm_ZERO); break;
8083 case BITS3(0,1,0): ch = 'm'; irrmE = mkU32(Irrm_NegINF); break;
8084 case BITS3(0,0,1): ch = 'p'; irrmE = mkU32(Irrm_PosINF); break;
8085 // The following is a kludge. Should be: Irrm_NEAREST_TIE_AWAY_0
8086 case BITS3(1,0,0): ch = 'a'; irrmE = mkU32(Irrm_NEAREST); break;
8087 default: break;
8088 }
8089 if (irrmE) {
8090 IRTemp src = newTemp(ity);
8091 IRTemp dst = newTemp(ity);
8092 assign(src, getQRegLO(nn, ity));
8093 assign(dst, binop(isD ? Iop_RoundF64toInt : Iop_RoundF32toInt,
8094 irrmE, mkexpr(src)));
8095 putQReg128(dd, mkV128(0x0000));
8096 putQRegLO(dd, mkexpr(dst));
8097 DIP("frint%c %s, %s\n",
8098 ch, nameQRegLO(dd, ity), nameQRegLO(nn, ity));
8099 return True;
8100 }
8101 return False;
8102 }
8103
sewardjdf1628c2014-06-10 22:52:05 +00008104 return False;
8105# undef INSN
8106}
8107
8108
8109static
8110Bool dis_AdvSIMD_fp_data_proc_2_source(/*MB_OUT*/DisResult* dres, UInt insn)
8111{
8112 /* 31 28 23 21 20 15 11 9 4
8113 000 11110 ty 1 m opcode 10 n d
8114 The first 3 bits are really "M 0 S", but M and S are always zero.
8115 */
8116# define INSN(_bMax,_bMin) SLICE_UInt(insn, (_bMax), (_bMin))
8117 if (INSN(31,24) != BITS8(0,0,0,1,1,1,1,0)
8118 || INSN(21,21) != 1 || INSN(11,10) != BITS2(1,0)) {
8119 return False;
8120 }
8121 UInt ty = INSN(23,22);
8122 UInt mm = INSN(20,16);
8123 UInt opcode = INSN(15,12);
8124 UInt nn = INSN(9,5);
8125 UInt dd = INSN(4,0);
8126
8127 if (ty <= X01 && opcode <= BITS4(0,0,1,1)) {
8128 /* ------- 0x,0000: FMUL d_d, s_s ------- */
8129 /* ------- 0x,0001: FDIV d_d, s_s ------- */
8130 /* ------- 0x,0010: FADD d_d, s_s ------- */
8131 /* ------- 0x,0011: FSUB d_d, s_s ------- */
8132 IRType ity = ty == X00 ? Ity_F32 : Ity_F64;
8133 IROp iop = Iop_INVALID;
8134 const HChar* nm = "???";
8135 switch (opcode) {
8136 case BITS4(0,0,0,0): nm = "fmul"; iop = mkMULF(ity); break;
8137 case BITS4(0,0,0,1): nm = "fdiv"; iop = mkDIVF(ity); break;
8138 case BITS4(0,0,1,0): nm = "fadd"; iop = mkADDF(ity); break;
8139 case BITS4(0,0,1,1): nm = "fsub"; iop = mkSUBF(ity); break;
8140 default: vassert(0);
8141 }
8142 IRExpr* resE = triop(iop, mkexpr(mk_get_IR_rounding_mode()),
8143 getQRegLO(nn, ity), getQRegLO(mm, ity));
8144 IRTemp res = newTemp(ity);
8145 assign(res, resE);
8146 putQReg128(dd, mkV128(0));
8147 putQRegLO(dd, mkexpr(res));
8148 DIP("%s %s, %s, %s\n",
8149 nm, nameQRegLO(dd, ity), nameQRegLO(nn, ity), nameQRegLO(mm, ity));
8150 return True;
8151 }
8152
8153 if (ty <= X01 && opcode == BITS4(1,0,0,0)) {
8154 /* ------- 0x,1000: FNMUL d_d, s_s ------- */
8155 IRType ity = ty == X00 ? Ity_F32 : Ity_F64;
8156 IROp iop = mkMULF(ity);
8157 IROp iopn = mkNEGF(ity);
8158 const HChar* nm = "fnmul";
8159 IRExpr* resE = unop(iopn,
8160 triop(iop, mkexpr(mk_get_IR_rounding_mode()),
8161 getQRegLO(nn, ity), getQRegLO(mm, ity)));
8162 IRTemp res = newTemp(ity);
8163 assign(res, resE);
8164 putQReg128(dd, mkV128(0));
8165 putQRegLO(dd, mkexpr(res));
8166 DIP("%s %s, %s, %s\n",
8167 nm, nameQRegLO(dd, ity), nameQRegLO(nn, ity), nameQRegLO(mm, ity));
8168 return True;
8169 }
8170
8171# define INSN(_bMax,_bMin) SLICE_UInt(insn, (_bMax), (_bMin))
8172 return False;
8173# undef INSN
8174}
8175
8176
8177static
8178Bool dis_AdvSIMD_fp_data_proc_3_source(/*MB_OUT*/DisResult* dres, UInt insn)
8179{
sewardj5747c4a2014-06-11 20:57:23 +00008180 /* 31 28 23 21 20 15 14 9 4
8181 000 11111 ty o1 m o0 a n d
8182 The first 3 bits are really "M 0 S", but M and S are always zero.
8183 Decode fields: ty,o1,o0
8184 */
sewardjdf1628c2014-06-10 22:52:05 +00008185# define INSN(_bMax,_bMin) SLICE_UInt(insn, (_bMax), (_bMin))
sewardj5747c4a2014-06-11 20:57:23 +00008186 if (INSN(31,24) != BITS8(0,0,0,1,1,1,1,1)) {
8187 return False;
8188 }
8189 UInt ty = INSN(23,22);
8190 UInt bitO1 = INSN(21,21);
8191 UInt mm = INSN(20,16);
8192 UInt bitO0 = INSN(15,15);
8193 UInt aa = INSN(14,10);
8194 UInt nn = INSN(9,5);
8195 UInt dd = INSN(4,0);
8196 vassert(ty < 4);
8197
8198 if (ty <= X01) {
8199 /* -------- 0x,0,0 FMADD d_d_d_d, s_s_s_s -------- */
8200 /* -------- 0x,0,1 FMSUB d_d_d_d, s_s_s_s -------- */
8201 /* -------- 0x,1,0 FNMADD d_d_d_d, s_s_s_s -------- */
8202 /* -------- 0x,1,1 FNMSUB d_d_d_d, s_s_s_s -------- */
8203 /* -------------------- F{N}M{ADD,SUB} -------------------- */
8204 /* 31 22 20 15 14 9 4 ix
8205 000 11111 0 sz 0 m 0 a n d 0 FMADD Fd,Fn,Fm,Fa
8206 000 11111 0 sz 0 m 1 a n d 1 FMSUB Fd,Fn,Fm,Fa
8207 000 11111 0 sz 1 m 0 a n d 2 FNMADD Fd,Fn,Fm,Fa
8208 000 11111 0 sz 1 m 1 a n d 3 FNMSUB Fd,Fn,Fm,Fa
8209 where Fx=Dx when sz=1, Fx=Sx when sz=0
8210
8211 -----SPEC------ ----IMPL----
8212 fmadd a + n * m a + n * m
8213 fmsub a + (-n) * m a - n * m
8214 fnmadd (-a) + (-n) * m -(a + n * m)
8215 fnmsub (-a) + n * m -(a - n * m)
8216 */
8217 Bool isD = (ty & 1) == 1;
8218 UInt ix = (bitO1 << 1) | bitO0;
8219 IRType ity = isD ? Ity_F64 : Ity_F32;
8220 IROp opADD = mkADDF(ity);
8221 IROp opSUB = mkSUBF(ity);
8222 IROp opMUL = mkMULF(ity);
8223 IROp opNEG = mkNEGF(ity);
8224 IRTemp res = newTemp(ity);
8225 IRExpr* eA = getQRegLO(aa, ity);
8226 IRExpr* eN = getQRegLO(nn, ity);
8227 IRExpr* eM = getQRegLO(mm, ity);
8228 IRExpr* rm = mkexpr(mk_get_IR_rounding_mode());
8229 IRExpr* eNxM = triop(opMUL, rm, eN, eM);
8230 switch (ix) {
8231 case 0: assign(res, triop(opADD, rm, eA, eNxM)); break;
8232 case 1: assign(res, triop(opSUB, rm, eA, eNxM)); break;
8233 case 2: assign(res, unop(opNEG, triop(opADD, rm, eA, eNxM))); break;
8234 case 3: assign(res, unop(opNEG, triop(opSUB, rm, eA, eNxM))); break;
8235 default: vassert(0);
8236 }
8237 putQReg128(dd, mkV128(0x0000));
8238 putQRegLO(dd, mkexpr(res));
8239 const HChar* names[4] = { "fmadd", "fmsub", "fnmadd", "fnmsub" };
8240 DIP("%s %s, %s, %s, %s\n",
8241 names[ix], nameQRegLO(dd, ity), nameQRegLO(nn, ity),
8242 nameQRegLO(mm, ity), nameQRegLO(aa, ity));
8243 return True;
8244 }
8245
sewardjdf1628c2014-06-10 22:52:05 +00008246 return False;
8247# undef INSN
8248}
8249
8250
8251static
8252Bool dis_AdvSIMD_fp_immediate(/*MB_OUT*/DisResult* dres, UInt insn)
8253{
8254 /* 31 28 23 21 20 12 9 4
8255 000 11110 ty 1 imm8 100 imm5 d
8256 The first 3 bits are really "M 0 S", but M and S are always zero.
8257 */
8258# define INSN(_bMax,_bMin) SLICE_UInt(insn, (_bMax), (_bMin))
8259 if (INSN(31,24) != BITS8(0,0,0,1,1,1,1,0)
8260 || INSN(21,21) != 1 || INSN(12,10) != BITS3(1,0,0)) {
8261 return False;
8262 }
8263 UInt ty = INSN(23,22);
8264 UInt imm8 = INSN(20,13);
8265 UInt imm5 = INSN(9,5);
8266 UInt dd = INSN(4,0);
8267
8268 /* ------- 00,00000: FMOV s_imm ------- */
8269 /* ------- 01,00000: FMOV d_imm ------- */
8270 if (ty <= X01 && imm5 == BITS5(0,0,0,0,0)) {
8271 Bool isD = (ty & 1) == 1;
8272 ULong imm = VFPExpandImm(imm8, isD ? 64 : 32);
8273 if (!isD) {
8274 vassert(0 == (imm & 0xFFFFFFFF00000000ULL));
8275 }
8276 putQReg128(dd, mkV128(0));
8277 putQRegLO(dd, isD ? mkU64(imm) : mkU32(imm & 0xFFFFFFFFULL));
8278 DIP("fmov %s, #0x%llx\n",
8279 nameQRegLO(dd, isD ? Ity_F64 : Ity_F32), imm);
8280 return True;
8281 }
8282
8283 return False;
8284# undef INSN
8285}
8286
8287
8288static
8289Bool dis_AdvSIMD_fp_to_fixedp_conv(/*MB_OUT*/DisResult* dres, UInt insn)
8290{
8291# define INSN(_bMax,_bMin) SLICE_UInt(insn, (_bMax), (_bMin))
8292 return False;
8293# undef INSN
8294}
8295
8296
8297static
sewardj5747c4a2014-06-11 20:57:23 +00008298Bool dis_AdvSIMD_fp_to_from_int_conv(/*MB_OUT*/DisResult* dres, UInt insn)
sewardjdf1628c2014-06-10 22:52:05 +00008299{
8300 /* 31 30 29 28 23 21 20 18 15 9 4
sewardj5747c4a2014-06-11 20:57:23 +00008301 sf 0 0 11110 type 1 rmode opcode 000000 n d
8302 The first 3 bits are really "sf 0 S", but S is always zero.
sewardjdf1628c2014-06-10 22:52:05 +00008303 */
8304# define INSN(_bMax,_bMin) SLICE_UInt(insn, (_bMax), (_bMin))
sewardj5747c4a2014-06-11 20:57:23 +00008305 if (INSN(30,29) != BITS2(0,0)
sewardjdf1628c2014-06-10 22:52:05 +00008306 || INSN(28,24) != BITS5(1,1,1,1,0)
8307 || INSN(21,21) != 1
8308 || INSN(15,10) != BITS6(0,0,0,0,0,0)) {
8309 return False;
8310 }
8311 UInt bitSF = INSN(31,31);
sewardjdf1628c2014-06-10 22:52:05 +00008312 UInt ty = INSN(23,22); // type
8313 UInt rm = INSN(20,19); // rmode
8314 UInt op = INSN(18,16); // opcode
8315 UInt nn = INSN(9,5);
8316 UInt dd = INSN(4,0);
8317
sewardj5747c4a2014-06-11 20:57:23 +00008318 // op = 000, 001
8319 /* -------- FCVT{N,P,M,Z}{S,U} (scalar, integer) -------- */
8320 /* 30 23 20 18 15 9 4
8321 sf 00 11110 0x 1 00 000 000000 n d FCVTNS Rd, Fn (round to
8322 sf 00 11110 0x 1 00 001 000000 n d FCVTNU Rd, Fn nearest)
8323 ---------------- 01 -------------- FCVTP-------- (round to +inf)
8324 ---------------- 10 -------------- FCVTM-------- (round to -inf)
8325 ---------------- 11 -------------- FCVTZ-------- (round to zero)
8326
8327 Rd is Xd when sf==1, Wd when sf==0
8328 Fn is Dn when x==1, Sn when x==0
8329 20:19 carry the rounding mode, using the same encoding as FPCR
8330 */
8331 if (ty <= X01 && (op == BITS3(0,0,0) || op == BITS3(0,0,1))) {
8332 Bool isI64 = bitSF == 1;
8333 Bool isF64 = (ty & 1) == 1;
8334 Bool isU = (op & 1) == 1;
8335 /* Decide on the IR rounding mode to use. */
8336 IRRoundingMode irrm = 8; /*impossible*/
8337 HChar ch = '?';
8338 switch (rm) {
8339 case BITS2(0,0): ch = 'n'; irrm = Irrm_NEAREST; break;
8340 case BITS2(0,1): ch = 'p'; irrm = Irrm_PosINF; break;
8341 case BITS2(1,0): ch = 'm'; irrm = Irrm_NegINF; break;
8342 case BITS2(1,1): ch = 'z'; irrm = Irrm_ZERO; break;
8343 default: vassert(0);
8344 }
8345 vassert(irrm != 8);
8346 /* Decide on the conversion primop, based on the source size,
8347 dest size and signedness (8 possibilities). Case coding:
8348 F32 ->s I32 0
8349 F32 ->u I32 1
8350 F32 ->s I64 2
8351 F32 ->u I64 3
8352 F64 ->s I32 4
8353 F64 ->u I32 5
8354 F64 ->s I64 6
8355 F64 ->u I64 7
8356 */
8357 UInt ix = (isF64 ? 4 : 0) | (isI64 ? 2 : 0) | (isU ? 1 : 0);
8358 vassert(ix < 8);
8359 const IROp iops[8]
8360 = { Iop_F32toI32S, Iop_F32toI32U, Iop_F32toI64S, Iop_F32toI64U,
8361 Iop_F64toI32S, Iop_F64toI32U, Iop_F64toI64S, Iop_F64toI64U };
8362 IROp iop = iops[ix];
8363 // A bit of ATCery: bounce all cases we haven't seen an example of.
8364 if (/* F32toI32S */
8365 (iop == Iop_F32toI32S && irrm == Irrm_ZERO) /* FCVTZS Wd,Sn */
8366 || (iop == Iop_F32toI32S && irrm == Irrm_NegINF) /* FCVTMS Wd,Sn */
8367 || (iop == Iop_F32toI32S && irrm == Irrm_PosINF) /* FCVTPS Wd,Sn */
8368 /* F32toI32U */
8369 || (iop == Iop_F32toI32U && irrm == Irrm_ZERO) /* FCVTZU Wd,Sn */
8370 || (iop == Iop_F32toI32U && irrm == Irrm_NegINF) /* FCVTMU Wd,Sn */
8371 /* F32toI64S */
8372 || (iop == Iop_F32toI64S && irrm == Irrm_ZERO) /* FCVTZS Xd,Sn */
8373 /* F32toI64U */
8374 || (iop == Iop_F32toI64U && irrm == Irrm_ZERO) /* FCVTZU Xd,Sn */
8375 /* F64toI32S */
8376 || (iop == Iop_F64toI32S && irrm == Irrm_ZERO) /* FCVTZS Wd,Dn */
8377 || (iop == Iop_F64toI32S && irrm == Irrm_NegINF) /* FCVTMS Wd,Dn */
8378 || (iop == Iop_F64toI32S && irrm == Irrm_PosINF) /* FCVTPS Wd,Dn */
8379 /* F64toI32U */
8380 || (iop == Iop_F64toI32U && irrm == Irrm_ZERO) /* FCVTZU Wd,Dn */
8381 || (iop == Iop_F64toI32U && irrm == Irrm_NegINF) /* FCVTMU Wd,Dn */
8382 || (iop == Iop_F64toI32U && irrm == Irrm_PosINF) /* FCVTPU Wd,Dn */
8383 /* F64toI64S */
8384 || (iop == Iop_F64toI64S && irrm == Irrm_ZERO) /* FCVTZS Xd,Dn */
8385 || (iop == Iop_F64toI64S && irrm == Irrm_NegINF) /* FCVTMS Xd,Dn */
8386 || (iop == Iop_F64toI64S && irrm == Irrm_PosINF) /* FCVTPS Xd,Dn */
8387 /* F64toI64U */
8388 || (iop == Iop_F64toI64U && irrm == Irrm_ZERO) /* FCVTZU Xd,Dn */
8389 || (iop == Iop_F64toI64U && irrm == Irrm_PosINF) /* FCVTPU Xd,Dn */
8390 ) {
8391 /* validated */
8392 } else {
8393 return False;
8394 }
8395 IRType srcTy = isF64 ? Ity_F64 : Ity_F32;
8396 IRType dstTy = isI64 ? Ity_I64 : Ity_I32;
8397 IRTemp src = newTemp(srcTy);
8398 IRTemp dst = newTemp(dstTy);
8399 assign(src, getQRegLO(nn, srcTy));
8400 assign(dst, binop(iop, mkU32(irrm), mkexpr(src)));
8401 putIRegOrZR(isI64, dd, mkexpr(dst));
8402 DIP("fcvt%c%c %s, %s\n", ch, isU ? 'u' : 's',
8403 nameIRegOrZR(isI64, dd), nameQRegLO(nn, srcTy));
8404 return True;
8405 }
8406
8407 // op = 010, 011
sewardjdf1628c2014-06-10 22:52:05 +00008408 /* -------------- {S,U}CVTF (scalar, integer) -------------- */
8409 /* (ix) sf S 28 ty rm op 15 9 4
8410 0 0 0 0 11110 00 1 00 010 000000 n d SCVTF Sd, Wn
8411 1 0 0 0 11110 01 1 00 010 000000 n d SCVTF Dd, Wn
8412 2 1 0 0 11110 00 1 00 010 000000 n d SCVTF Sd, Xn
8413 3 1 0 0 11110 01 1 00 010 000000 n d SCVTF Dd, Xn
8414
8415 4 0 0 0 11110 00 1 00 011 000000 n d UCVTF Sd, Wn
8416 5 0 0 0 11110 01 1 00 011 000000 n d UCVTF Dd, Wn
8417 6 1 0 0 11110 00 1 00 011 000000 n d UCVTF Sd, Xn
8418 7 1 0 0 11110 01 1 00 011 000000 n d UCVTF Dd, Xn
8419
8420 These are signed/unsigned conversion from integer registers to
8421 FP registers, all 4 32/64-bit combinations, rounded per FPCR.
8422 */
sewardj5747c4a2014-06-11 20:57:23 +00008423 if (ty <= X01 && rm == X00 && (op == BITS3(0,1,0) || op == BITS3(0,1,1))) {
sewardjdf1628c2014-06-10 22:52:05 +00008424 Bool isI64 = bitSF == 1;
8425 Bool isF64 = (ty & 1) == 1;
8426 Bool isU = (op & 1) == 1;
8427 UInt ix = (isU ? 4 : 0) | (isI64 ? 2 : 0) | (isF64 ? 1 : 0);
8428 const IROp ops[8]
8429 = { Iop_I32StoF32, Iop_I32StoF64, Iop_I64StoF32, Iop_I64StoF64,
8430 Iop_I32UtoF32, Iop_I32UtoF64, Iop_I64UtoF32, Iop_I64UtoF64 };
8431 IRExpr* src = getIRegOrZR(isI64, nn);
8432 IRExpr* res = (isF64 && !isI64)
8433 ? unop(ops[ix], src)
8434 : binop(ops[ix], mkexpr(mk_get_IR_rounding_mode()), src);
8435 putQReg128(dd, mkV128(0));
8436 putQRegLO(dd, res);
8437 DIP("%ccvtf %s, %s\n",
8438 isU ? 'u' : 's', nameQRegLO(dd, isF64 ? Ity_F64 : Ity_F32),
8439 nameIRegOrZR(isI64, nn));
8440 return True;
8441 }
8442
sewardj5747c4a2014-06-11 20:57:23 +00008443 // op = 110, 111
sewardjdf1628c2014-06-10 22:52:05 +00008444 /* -------- FMOV (general) -------- */
8445 /* case sf S ty rm op 15 9 4
8446 (1) 0 0 0 11110 00 1 00 111 000000 n d FMOV Sd, Wn
8447 (2) 1 0 0 11110 01 1 00 111 000000 n d FMOV Dd, Xn
8448 (3) 1 0 0 11110 10 1 01 111 000000 n d FMOV Vd.D[1], Xn
8449
8450 (4) 0 0 0 11110 00 1 00 110 000000 n d FMOV Wd, Sn
8451 (5) 1 0 0 11110 01 1 00 110 000000 n d FMOV Xd, Dn
8452 (6) 1 0 0 11110 10 1 01 110 000000 n d FMOV Xd, Vn.D[1]
8453 */
sewardj5747c4a2014-06-11 20:57:23 +00008454 if (1) {
sewardjbbcf1882014-01-12 12:49:10 +00008455 UInt ix = 0; // case
sewardjdf1628c2014-06-10 22:52:05 +00008456 if (bitSF == 0) {
sewardjbbcf1882014-01-12 12:49:10 +00008457 if (ty == BITS2(0,0) && rm == BITS2(0,0) && op == BITS3(1,1,1))
8458 ix = 1;
8459 else
8460 if (ty == BITS2(0,0) && rm == BITS2(0,0) && op == BITS3(1,1,0))
8461 ix = 4;
8462 } else {
sewardjdf1628c2014-06-10 22:52:05 +00008463 vassert(bitSF == 1);
sewardjbbcf1882014-01-12 12:49:10 +00008464 if (ty == BITS2(0,1) && rm == BITS2(0,0) && op == BITS3(1,1,1))
8465 ix = 2;
8466 else
8467 if (ty == BITS2(0,1) && rm == BITS2(0,0) && op == BITS3(1,1,0))
8468 ix = 5;
8469 else
8470 if (ty == BITS2(1,0) && rm == BITS2(0,1) && op == BITS3(1,1,1))
8471 ix = 3;
8472 else
8473 if (ty == BITS2(1,0) && rm == BITS2(0,1) && op == BITS3(1,1,0))
8474 ix = 6;
8475 }
8476 if (ix > 0) {
8477 switch (ix) {
8478 case 1:
8479 putQReg128(dd, mkV128(0));
sewardj606c4ba2014-01-26 19:11:14 +00008480 putQRegLO(dd, getIReg32orZR(nn));
sewardjbbcf1882014-01-12 12:49:10 +00008481 DIP("fmov s%u, w%u\n", dd, nn);
8482 break;
8483 case 2:
8484 putQReg128(dd, mkV128(0));
sewardj606c4ba2014-01-26 19:11:14 +00008485 putQRegLO(dd, getIReg64orZR(nn));
sewardjbbcf1882014-01-12 12:49:10 +00008486 DIP("fmov d%u, x%u\n", dd, nn);
8487 break;
8488 case 3:
sewardj606c4ba2014-01-26 19:11:14 +00008489 putQRegHI64(dd, getIReg64orZR(nn));
sewardjbbcf1882014-01-12 12:49:10 +00008490 DIP("fmov v%u.d[1], x%u\n", dd, nn);
8491 break;
8492 case 4:
sewardj606c4ba2014-01-26 19:11:14 +00008493 putIReg32orZR(dd, getQRegLO(nn, Ity_I32));
sewardjbbcf1882014-01-12 12:49:10 +00008494 DIP("fmov w%u, s%u\n", dd, nn);
8495 break;
8496 case 5:
sewardj606c4ba2014-01-26 19:11:14 +00008497 putIReg64orZR(dd, getQRegLO(nn, Ity_I64));
sewardjbbcf1882014-01-12 12:49:10 +00008498 DIP("fmov x%u, d%u\n", dd, nn);
8499 break;
8500 case 6:
sewardj606c4ba2014-01-26 19:11:14 +00008501 putIReg64orZR(dd, getQRegHI64(nn));
sewardjbbcf1882014-01-12 12:49:10 +00008502 DIP("fmov x%u, v%u.d[1]\n", dd, nn);
8503 break;
8504 default:
8505 vassert(0);
8506 }
8507 return True;
8508 }
8509 /* undecodable; fall through */
8510 }
8511
sewardjdf1628c2014-06-10 22:52:05 +00008512 return False;
8513# undef INSN
8514}
8515
8516
8517static
8518Bool dis_ARM64_simd_and_fp(/*MB_OUT*/DisResult* dres, UInt insn)
8519{
8520 Bool ok;
8521 ok = dis_AdvSIMD_EXT(dres, insn);
8522 if (UNLIKELY(ok)) return True;
8523 ok = dis_AdvSIMD_TBL_TBX(dres, insn);
8524 if (UNLIKELY(ok)) return True;
8525 ok = dis_AdvSIMD_ZIP_UZP_TRN(dres, insn);
8526 if (UNLIKELY(ok)) return True;
8527 ok = dis_AdvSIMD_across_lanes(dres, insn);
8528 if (UNLIKELY(ok)) return True;
8529 ok = dis_AdvSIMD_copy(dres, insn);
8530 if (UNLIKELY(ok)) return True;
8531 ok = dis_AdvSIMD_modified_immediate(dres, insn);
8532 if (UNLIKELY(ok)) return True;
8533 ok = dis_AdvSIMD_scalar_copy(dres, insn);
8534 if (UNLIKELY(ok)) return True;
8535 ok = dis_AdvSIMD_scalar_pairwise(dres, insn);
8536 if (UNLIKELY(ok)) return True;
8537 ok = dis_AdvSIMD_scalar_shift_by_imm(dres, insn);
8538 if (UNLIKELY(ok)) return True;
8539 ok = dis_AdvSIMD_scalar_three_different(dres, insn);
8540 if (UNLIKELY(ok)) return True;
8541 ok = dis_AdvSIMD_scalar_three_same(dres, insn);
8542 if (UNLIKELY(ok)) return True;
8543 ok = dis_AdvSIMD_scalar_two_reg_misc(dres, insn);
8544 if (UNLIKELY(ok)) return True;
8545 ok = dis_AdvSIMD_scalar_x_indexed_element(dres, insn);
8546 if (UNLIKELY(ok)) return True;
8547 ok = dis_AdvSIMD_shift_by_immediate(dres, insn);
8548 if (UNLIKELY(ok)) return True;
8549 ok = dis_AdvSIMD_three_different(dres, insn);
8550 if (UNLIKELY(ok)) return True;
8551 ok = dis_AdvSIMD_three_same(dres, insn);
8552 if (UNLIKELY(ok)) return True;
8553 ok = dis_AdvSIMD_two_reg_misc(dres, insn);
8554 if (UNLIKELY(ok)) return True;
8555 ok = dis_AdvSIMD_vector_x_indexed_elem(dres, insn);
8556 if (UNLIKELY(ok)) return True;
8557 ok = dis_AdvSIMD_crypto_aes(dres, insn);
8558 if (UNLIKELY(ok)) return True;
8559 ok = dis_AdvSIMD_crypto_three_reg_sha(dres, insn);
8560 if (UNLIKELY(ok)) return True;
8561 ok = dis_AdvSIMD_crypto_two_reg_sha(dres, insn);
8562 if (UNLIKELY(ok)) return True;
8563 ok = dis_AdvSIMD_fp_compare(dres, insn);
8564 if (UNLIKELY(ok)) return True;
8565 ok = dis_AdvSIMD_fp_conditional_compare(dres, insn);
8566 if (UNLIKELY(ok)) return True;
8567 ok = dis_AdvSIMD_fp_conditional_select(dres, insn);
8568 if (UNLIKELY(ok)) return True;
8569 ok = dis_AdvSIMD_fp_data_proc_1_source(dres, insn);
8570 if (UNLIKELY(ok)) return True;
8571 ok = dis_AdvSIMD_fp_data_proc_2_source(dres, insn);
8572 if (UNLIKELY(ok)) return True;
8573 ok = dis_AdvSIMD_fp_data_proc_3_source(dres, insn);
8574 if (UNLIKELY(ok)) return True;
8575 ok = dis_AdvSIMD_fp_immediate(dres, insn);
8576 if (UNLIKELY(ok)) return True;
8577 ok = dis_AdvSIMD_fp_to_fixedp_conv(dres, insn);
8578 if (UNLIKELY(ok)) return True;
sewardj5747c4a2014-06-11 20:57:23 +00008579 ok = dis_AdvSIMD_fp_to_from_int_conv(dres, insn);
sewardjdf1628c2014-06-10 22:52:05 +00008580 if (UNLIKELY(ok)) return True;
8581 return False;
8582}
8583
sewardjbbcf1882014-01-12 12:49:10 +00008584
8585/*------------------------------------------------------------*/
8586/*--- Disassemble a single ARM64 instruction ---*/
8587/*------------------------------------------------------------*/
8588
8589/* Disassemble a single ARM64 instruction into IR. The instruction
8590 has is located at |guest_instr| and has guest IP of
8591 |guest_PC_curr_instr|, which will have been set before the call
8592 here. Returns True iff the instruction was decoded, in which case
8593 *dres will be set accordingly, or False, in which case *dres should
8594 be ignored by the caller. */
8595
8596static
8597Bool disInstr_ARM64_WRK (
8598 /*MB_OUT*/DisResult* dres,
8599 Bool (*resteerOkFn) ( /*opaque*/void*, Addr64 ),
8600 Bool resteerCisOk,
8601 void* callback_opaque,
8602 UChar* guest_instr,
8603 VexArchInfo* archinfo,
8604 VexAbiInfo* abiinfo
8605 )
8606{
8607 // A macro to fish bits out of 'insn'.
8608# define INSN(_bMax,_bMin) SLICE_UInt(insn, (_bMax), (_bMin))
8609
8610//ZZ DisResult dres;
8611//ZZ UInt insn;
8612//ZZ //Bool allow_VFP = False;
8613//ZZ //UInt hwcaps = archinfo->hwcaps;
8614//ZZ IRTemp condT; /* :: Ity_I32 */
8615//ZZ UInt summary;
8616//ZZ HChar dis_buf[128]; // big enough to hold LDMIA etc text
8617//ZZ
8618//ZZ /* What insn variants are we supporting today? */
8619//ZZ //allow_VFP = (0 != (hwcaps & VEX_HWCAPS_ARM_VFP));
8620//ZZ // etc etc
8621
8622 /* Set result defaults. */
8623 dres->whatNext = Dis_Continue;
8624 dres->len = 4;
8625 dres->continueAt = 0;
8626 dres->jk_StopHere = Ijk_INVALID;
8627
8628 /* At least this is simple on ARM64: insns are all 4 bytes long, and
8629 4-aligned. So just fish the whole thing out of memory right now
8630 and have done. */
8631 UInt insn = getUIntLittleEndianly( guest_instr );
8632
8633 if (0) vex_printf("insn: 0x%x\n", insn);
8634
8635 DIP("\t(arm64) 0x%llx: ", (ULong)guest_PC_curr_instr);
8636
8637 vassert(0 == (guest_PC_curr_instr & 3ULL));
8638
8639 /* ----------------------------------------------------------- */
8640
8641 /* Spot "Special" instructions (see comment at top of file). */
8642 {
8643 UChar* code = (UChar*)guest_instr;
8644 /* Spot the 16-byte preamble:
8645 93CC0D8C ror x12, x12, #3
8646 93CC358C ror x12, x12, #13
8647 93CCCD8C ror x12, x12, #51
8648 93CCF58C ror x12, x12, #61
8649 */
8650 UInt word1 = 0x93CC0D8C;
8651 UInt word2 = 0x93CC358C;
8652 UInt word3 = 0x93CCCD8C;
8653 UInt word4 = 0x93CCF58C;
8654 if (getUIntLittleEndianly(code+ 0) == word1 &&
8655 getUIntLittleEndianly(code+ 4) == word2 &&
8656 getUIntLittleEndianly(code+ 8) == word3 &&
8657 getUIntLittleEndianly(code+12) == word4) {
8658 /* Got a "Special" instruction preamble. Which one is it? */
8659 if (getUIntLittleEndianly(code+16) == 0xAA0A014A
8660 /* orr x10,x10,x10 */) {
8661 /* X3 = client_request ( X4 ) */
8662 DIP("x3 = client_request ( x4 )\n");
8663 putPC(mkU64( guest_PC_curr_instr + 20 ));
8664 dres->jk_StopHere = Ijk_ClientReq;
8665 dres->whatNext = Dis_StopHere;
8666 return True;
8667 }
8668 else
8669 if (getUIntLittleEndianly(code+16) == 0xAA0B016B
8670 /* orr x11,x11,x11 */) {
8671 /* X3 = guest_NRADDR */
8672 DIP("x3 = guest_NRADDR\n");
8673 dres->len = 20;
8674 putIReg64orZR(3, IRExpr_Get( OFFB_NRADDR, Ity_I64 ));
8675 return True;
8676 }
8677 else
8678 if (getUIntLittleEndianly(code+16) == 0xAA0C018C
8679 /* orr x12,x12,x12 */) {
8680 /* branch-and-link-to-noredir X8 */
8681 DIP("branch-and-link-to-noredir x8\n");
8682 putIReg64orZR(30, mkU64(guest_PC_curr_instr + 20));
8683 putPC(getIReg64orZR(8));
8684 dres->jk_StopHere = Ijk_NoRedir;
8685 dres->whatNext = Dis_StopHere;
8686 return True;
8687 }
8688 else
8689 if (getUIntLittleEndianly(code+16) == 0xAA090129
8690 /* orr x9,x9,x9 */) {
8691 /* IR injection */
8692 DIP("IR injection\n");
8693 vex_inject_ir(irsb, Iend_LE);
8694 // Invalidate the current insn. The reason is that the IRop we're
8695 // injecting here can change. In which case the translation has to
8696 // be redone. For ease of handling, we simply invalidate all the
8697 // time.
sewardj05f5e012014-05-04 10:52:11 +00008698 stmt(IRStmt_Put(OFFB_CMSTART, mkU64(guest_PC_curr_instr)));
8699 stmt(IRStmt_Put(OFFB_CMLEN, mkU64(20)));
sewardjbbcf1882014-01-12 12:49:10 +00008700 putPC(mkU64( guest_PC_curr_instr + 20 ));
8701 dres->whatNext = Dis_StopHere;
sewardj05f5e012014-05-04 10:52:11 +00008702 dres->jk_StopHere = Ijk_InvalICache;
sewardjbbcf1882014-01-12 12:49:10 +00008703 return True;
8704 }
8705 /* We don't know what it is. */
8706 return False;
8707 /*NOTREACHED*/
8708 }
8709 }
8710
8711 /* ----------------------------------------------------------- */
8712
8713 /* Main ARM64 instruction decoder starts here. */
8714
8715 Bool ok = False;
8716
8717 /* insn[28:25] determines the top-level grouping, so let's start
8718 off with that.
8719
8720 For all of these dis_ARM64_ functions, we pass *dres with the
8721 normal default results "insn OK, 4 bytes long, keep decoding" so
8722 they don't need to change it. However, decodes of control-flow
8723 insns may cause *dres to change.
8724 */
8725 switch (INSN(28,25)) {
8726 case BITS4(1,0,0,0): case BITS4(1,0,0,1):
8727 // Data processing - immediate
8728 ok = dis_ARM64_data_processing_immediate(dres, insn);
8729 break;
8730 case BITS4(1,0,1,0): case BITS4(1,0,1,1):
8731 // Branch, exception generation and system instructions
sewardj65902992014-05-03 21:20:56 +00008732 ok = dis_ARM64_branch_etc(dres, insn, archinfo);
sewardjbbcf1882014-01-12 12:49:10 +00008733 break;
8734 case BITS4(0,1,0,0): case BITS4(0,1,1,0):
8735 case BITS4(1,1,0,0): case BITS4(1,1,1,0):
8736 // Loads and stores
8737 ok = dis_ARM64_load_store(dres, insn);
8738 break;
8739 case BITS4(0,1,0,1): case BITS4(1,1,0,1):
8740 // Data processing - register
8741 ok = dis_ARM64_data_processing_register(dres, insn);
8742 break;
8743 case BITS4(0,1,1,1): case BITS4(1,1,1,1):
8744 // Data processing - SIMD and floating point
8745 ok = dis_ARM64_simd_and_fp(dres, insn);
8746 break;
8747 case BITS4(0,0,0,0): case BITS4(0,0,0,1):
8748 case BITS4(0,0,1,0): case BITS4(0,0,1,1):
8749 // UNALLOCATED
8750 break;
8751 default:
8752 vassert(0); /* Can't happen */
8753 }
8754
8755 /* If the next-level down decoders failed, make sure |dres| didn't
8756 get changed. */
8757 if (!ok) {
8758 vassert(dres->whatNext == Dis_Continue);
8759 vassert(dres->len == 4);
8760 vassert(dres->continueAt == 0);
8761 vassert(dres->jk_StopHere == Ijk_INVALID);
8762 }
8763
8764 return ok;
8765
8766# undef INSN
8767}
8768
8769
8770/*------------------------------------------------------------*/
8771/*--- Top-level fn ---*/
8772/*------------------------------------------------------------*/
8773
8774/* Disassemble a single instruction into IR. The instruction
8775 is located in host memory at &guest_code[delta]. */
8776
8777DisResult disInstr_ARM64 ( IRSB* irsb_IN,
8778 Bool (*resteerOkFn) ( void*, Addr64 ),
8779 Bool resteerCisOk,
8780 void* callback_opaque,
8781 UChar* guest_code_IN,
8782 Long delta_IN,
8783 Addr64 guest_IP,
8784 VexArch guest_arch,
8785 VexArchInfo* archinfo,
8786 VexAbiInfo* abiinfo,
8787 Bool host_bigendian_IN,
8788 Bool sigill_diag_IN )
8789{
8790 DisResult dres;
8791 vex_bzero(&dres, sizeof(dres));
8792
8793 /* Set globals (see top of this file) */
8794 vassert(guest_arch == VexArchARM64);
8795
8796 irsb = irsb_IN;
8797 host_is_bigendian = host_bigendian_IN;
8798 guest_PC_curr_instr = (Addr64)guest_IP;
8799
sewardj65902992014-05-03 21:20:56 +00008800 /* Sanity checks */
8801 /* (x::UInt - 2) <= 15 === x >= 2 && x <= 17 (I hope) */
8802 vassert((archinfo->arm64_dMinLine_lg2_szB - 2) <= 15);
8803 vassert((archinfo->arm64_iMinLine_lg2_szB - 2) <= 15);
8804
sewardjbbcf1882014-01-12 12:49:10 +00008805 /* Try to decode */
8806 Bool ok = disInstr_ARM64_WRK( &dres,
8807 resteerOkFn, resteerCisOk, callback_opaque,
8808 (UChar*)&guest_code_IN[delta_IN],
8809 archinfo, abiinfo );
8810 if (ok) {
8811 /* All decode successes end up here. */
sewardjdc9259c2014-02-27 11:10:19 +00008812 vassert(dres.len == 4 || dres.len == 20);
sewardjbbcf1882014-01-12 12:49:10 +00008813 switch (dres.whatNext) {
8814 case Dis_Continue:
8815 putPC( mkU64(dres.len + guest_PC_curr_instr) );
8816 break;
8817 case Dis_ResteerU:
8818 case Dis_ResteerC:
8819 putPC(mkU64(dres.continueAt));
8820 break;
8821 case Dis_StopHere:
8822 break;
8823 default:
8824 vassert(0);
8825 }
8826 DIP("\n");
8827 } else {
8828 /* All decode failures end up here. */
8829 if (sigill_diag_IN) {
8830 Int i, j;
8831 UChar buf[64];
8832 UInt insn
8833 = getUIntLittleEndianly( (UChar*)&guest_code_IN[delta_IN] );
8834 vex_bzero(buf, sizeof(buf));
8835 for (i = j = 0; i < 32; i++) {
8836 if (i > 0) {
8837 if ((i & 7) == 0) buf[j++] = ' ';
8838 else if ((i & 3) == 0) buf[j++] = '\'';
8839 }
8840 buf[j++] = (insn & (1<<(31-i))) ? '1' : '0';
8841 }
8842 vex_printf("disInstr(arm64): unhandled instruction 0x%08x\n", insn);
8843 vex_printf("disInstr(arm64): %s\n", buf);
8844 }
8845
8846 /* Tell the dispatcher that this insn cannot be decoded, and so
8847 has not been executed, and (is currently) the next to be
8848 executed. PC should be up-to-date since it is made so at the
8849 start of each insn, but nevertheless be paranoid and update
8850 it again right now. */
8851 putPC( mkU64(guest_PC_curr_instr) );
8852 dres.whatNext = Dis_StopHere;
8853 dres.len = 0;
8854 dres.continueAt = 0;
8855 dres.jk_StopHere = Ijk_NoDecode;
8856 }
8857 return dres;
8858}
8859
sewardjecde6972014-02-05 11:01:19 +00008860
sewardjbbcf1882014-01-12 12:49:10 +00008861/*--------------------------------------------------------------------*/
8862/*--- end guest_arm64_toIR.c ---*/
8863/*--------------------------------------------------------------------*/