blob: 25a6bf3ca27e0f32e986585956acf2f3350122c8 [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
sewardjbbcf1882014-01-12 12:49:10 +0000246// produces _uint[_bMax:_bMin]
247#define SLICE_UInt(_uint,_bMax,_bMin) \
248 (( ((UInt)(_uint)) >> (_bMin)) \
249 & (UInt)((1ULL << ((_bMax) - (_bMin) + 1)) - 1ULL))
250
251
252/*------------------------------------------------------------*/
253/*--- Helper bits and pieces for creating IR fragments. ---*/
254/*------------------------------------------------------------*/
255
256static IRExpr* mkV128 ( UShort w )
257{
258 return IRExpr_Const(IRConst_V128(w));
259}
260
261static IRExpr* mkU64 ( ULong i )
262{
263 return IRExpr_Const(IRConst_U64(i));
264}
265
266static IRExpr* mkU32 ( UInt i )
267{
268 return IRExpr_Const(IRConst_U32(i));
269}
270
271static IRExpr* mkU8 ( UInt i )
272{
273 vassert(i < 256);
274 return IRExpr_Const(IRConst_U8( (UChar)i ));
275}
276
277static IRExpr* mkexpr ( IRTemp tmp )
278{
279 return IRExpr_RdTmp(tmp);
280}
281
282static IRExpr* unop ( IROp op, IRExpr* a )
283{
284 return IRExpr_Unop(op, a);
285}
286
287static IRExpr* binop ( IROp op, IRExpr* a1, IRExpr* a2 )
288{
289 return IRExpr_Binop(op, a1, a2);
290}
291
292static IRExpr* triop ( IROp op, IRExpr* a1, IRExpr* a2, IRExpr* a3 )
293{
294 return IRExpr_Triop(op, a1, a2, a3);
295}
296
297static IRExpr* loadLE ( IRType ty, IRExpr* addr )
298{
299 return IRExpr_Load(Iend_LE, ty, addr);
300}
301
302/* Add a statement to the list held by "irbb". */
303static void stmt ( IRStmt* st )
304{
305 addStmtToIRSB( irsb, st );
306}
307
308static void assign ( IRTemp dst, IRExpr* e )
309{
310 stmt( IRStmt_WrTmp(dst, e) );
311}
312
313static void storeLE ( IRExpr* addr, IRExpr* data )
314{
315 stmt( IRStmt_Store(Iend_LE, addr, data) );
316}
317
318//ZZ static void storeGuardedLE ( IRExpr* addr, IRExpr* data, IRTemp guardT )
319//ZZ {
320//ZZ if (guardT == IRTemp_INVALID) {
321//ZZ /* unconditional */
322//ZZ storeLE(addr, data);
323//ZZ } else {
324//ZZ stmt( IRStmt_StoreG(Iend_LE, addr, data,
325//ZZ binop(Iop_CmpNE32, mkexpr(guardT), mkU32(0))) );
326//ZZ }
327//ZZ }
328//ZZ
329//ZZ static void loadGuardedLE ( IRTemp dst, IRLoadGOp cvt,
330//ZZ IRExpr* addr, IRExpr* alt,
331//ZZ IRTemp guardT /* :: Ity_I32, 0 or 1 */ )
332//ZZ {
333//ZZ if (guardT == IRTemp_INVALID) {
334//ZZ /* unconditional */
335//ZZ IRExpr* loaded = NULL;
336//ZZ switch (cvt) {
337//ZZ case ILGop_Ident32:
338//ZZ loaded = loadLE(Ity_I32, addr); break;
339//ZZ case ILGop_8Uto32:
340//ZZ loaded = unop(Iop_8Uto32, loadLE(Ity_I8, addr)); break;
341//ZZ case ILGop_8Sto32:
342//ZZ loaded = unop(Iop_8Sto32, loadLE(Ity_I8, addr)); break;
343//ZZ case ILGop_16Uto32:
344//ZZ loaded = unop(Iop_16Uto32, loadLE(Ity_I16, addr)); break;
345//ZZ case ILGop_16Sto32:
346//ZZ loaded = unop(Iop_16Sto32, loadLE(Ity_I16, addr)); break;
347//ZZ default:
348//ZZ vassert(0);
349//ZZ }
350//ZZ vassert(loaded != NULL);
351//ZZ assign(dst, loaded);
352//ZZ } else {
353//ZZ /* Generate a guarded load into 'dst', but apply 'cvt' to the
354//ZZ loaded data before putting the data in 'dst'. If the load
355//ZZ does not take place, 'alt' is placed directly in 'dst'. */
356//ZZ stmt( IRStmt_LoadG(Iend_LE, cvt, dst, addr, alt,
357//ZZ binop(Iop_CmpNE32, mkexpr(guardT), mkU32(0))) );
358//ZZ }
359//ZZ }
360
361/* Generate a new temporary of the given type. */
362static IRTemp newTemp ( IRType ty )
363{
364 vassert(isPlausibleIRType(ty));
365 return newIRTemp( irsb->tyenv, ty );
366}
367
368//ZZ /* Produces a value in 0 .. 3, which is encoded as per the type
369//ZZ IRRoundingMode. */
370//ZZ static IRExpr* /* :: Ity_I32 */ get_FAKE_roundingmode ( void )
371//ZZ {
372//ZZ return mkU32(Irrm_NEAREST);
373//ZZ }
374//ZZ
375//ZZ /* Generate an expression for SRC rotated right by ROT. */
376//ZZ static IRExpr* genROR32( IRTemp src, Int rot )
377//ZZ {
378//ZZ vassert(rot >= 0 && rot < 32);
379//ZZ if (rot == 0)
380//ZZ return mkexpr(src);
381//ZZ return
382//ZZ binop(Iop_Or32,
383//ZZ binop(Iop_Shl32, mkexpr(src), mkU8(32 - rot)),
384//ZZ binop(Iop_Shr32, mkexpr(src), mkU8(rot)));
385//ZZ }
386//ZZ
387//ZZ static IRExpr* mkU128 ( ULong i )
388//ZZ {
389//ZZ return binop(Iop_64HLtoV128, mkU64(i), mkU64(i));
390//ZZ }
391//ZZ
392//ZZ /* Generate a 4-aligned version of the given expression if
393//ZZ the given condition is true. Else return it unchanged. */
394//ZZ static IRExpr* align4if ( IRExpr* e, Bool b )
395//ZZ {
396//ZZ if (b)
397//ZZ return binop(Iop_And32, e, mkU32(~3));
398//ZZ else
399//ZZ return e;
400//ZZ }
401
402/* Other IR construction helpers. */
403static IROp mkAND ( IRType ty ) {
404 switch (ty) {
405 case Ity_I32: return Iop_And32;
406 case Ity_I64: return Iop_And64;
407 default: vpanic("mkAND");
408 }
409}
410
411static IROp mkOR ( IRType ty ) {
412 switch (ty) {
413 case Ity_I32: return Iop_Or32;
414 case Ity_I64: return Iop_Or64;
415 default: vpanic("mkOR");
416 }
417}
418
419static IROp mkXOR ( IRType ty ) {
420 switch (ty) {
421 case Ity_I32: return Iop_Xor32;
422 case Ity_I64: return Iop_Xor64;
423 default: vpanic("mkXOR");
424 }
425}
426
427static IROp mkSHL ( IRType ty ) {
428 switch (ty) {
429 case Ity_I32: return Iop_Shl32;
430 case Ity_I64: return Iop_Shl64;
431 default: vpanic("mkSHL");
432 }
433}
434
435static IROp mkSHR ( IRType ty ) {
436 switch (ty) {
437 case Ity_I32: return Iop_Shr32;
438 case Ity_I64: return Iop_Shr64;
439 default: vpanic("mkSHR");
440 }
441}
442
443static IROp mkSAR ( IRType ty ) {
444 switch (ty) {
445 case Ity_I32: return Iop_Sar32;
446 case Ity_I64: return Iop_Sar64;
447 default: vpanic("mkSAR");
448 }
449}
450
451static IROp mkNOT ( IRType ty ) {
452 switch (ty) {
453 case Ity_I32: return Iop_Not32;
454 case Ity_I64: return Iop_Not64;
455 default: vpanic("mkNOT");
456 }
457}
458
459static IROp mkADD ( IRType ty ) {
460 switch (ty) {
461 case Ity_I32: return Iop_Add32;
462 case Ity_I64: return Iop_Add64;
463 default: vpanic("mkADD");
464 }
465}
466
467static IROp mkSUB ( IRType ty ) {
468 switch (ty) {
469 case Ity_I32: return Iop_Sub32;
470 case Ity_I64: return Iop_Sub64;
471 default: vpanic("mkSUB");
472 }
473}
474
475static IROp mkADDF ( IRType ty ) {
476 switch (ty) {
477 case Ity_F32: return Iop_AddF32;
478 case Ity_F64: return Iop_AddF64;
479 default: vpanic("mkADDF");
480 }
481}
482
483static IROp mkSUBF ( IRType ty ) {
484 switch (ty) {
485 case Ity_F32: return Iop_SubF32;
486 case Ity_F64: return Iop_SubF64;
487 default: vpanic("mkSUBF");
488 }
489}
490
491static IROp mkMULF ( IRType ty ) {
492 switch (ty) {
493 case Ity_F32: return Iop_MulF32;
494 case Ity_F64: return Iop_MulF64;
495 default: vpanic("mkMULF");
496 }
497}
498
499static IROp mkDIVF ( IRType ty ) {
500 switch (ty) {
501 case Ity_F32: return Iop_DivF32;
502 case Ity_F64: return Iop_DivF64;
503 default: vpanic("mkMULF");
504 }
505}
506
507static IROp mkNEGF ( IRType ty ) {
508 switch (ty) {
509 case Ity_F32: return Iop_NegF32;
510 case Ity_F64: return Iop_NegF64;
511 default: vpanic("mkNEGF");
512 }
513}
514
515static IROp mkABSF ( IRType ty ) {
516 switch (ty) {
517 case Ity_F32: return Iop_AbsF32;
518 case Ity_F64: return Iop_AbsF64;
519 default: vpanic("mkNEGF");
520 }
521}
522
523static IROp mkSQRTF ( IRType ty ) {
524 switch (ty) {
525 case Ity_F32: return Iop_SqrtF32;
526 case Ity_F64: return Iop_SqrtF64;
527 default: vpanic("mkNEGF");
528 }
529}
530
531static IRExpr* mkU ( IRType ty, ULong imm ) {
532 switch (ty) {
533 case Ity_I32: return mkU32((UInt)(imm & 0xFFFFFFFFULL));
534 case Ity_I64: return mkU64(imm);
535 default: vpanic("mkU");
536 }
537}
538
539/* Generate IR to create 'arg rotated right by imm', for sane values
540 of 'ty' and 'imm'. */
541static IRTemp mathROR ( IRType ty, IRTemp arg, UInt imm )
542{
543 UInt w = 0;
544 if (ty == Ity_I64) {
545 w = 64;
546 } else {
547 vassert(ty == Ity_I32);
548 w = 32;
549 }
550 vassert(w != 0);
551 vassert(imm < w);
552 if (imm == 0) {
553 return arg;
554 }
555 IRTemp res = newTemp(ty);
556 assign(res, binop(mkOR(ty),
557 binop(mkSHL(ty), mkexpr(arg), mkU8(w - imm)),
558 binop(mkSHR(ty), mkexpr(arg), mkU8(imm)) ));
559 return res;
560}
561
562/* Generate IR to set the returned temp to either all-zeroes or
563 all ones, as a copy of arg<imm>. */
564static IRTemp mathREPLICATE ( IRType ty, IRTemp arg, UInt imm )
565{
566 UInt w = 0;
567 if (ty == Ity_I64) {
568 w = 64;
569 } else {
570 vassert(ty == Ity_I32);
571 w = 32;
572 }
573 vassert(w != 0);
574 vassert(imm < w);
575 IRTemp res = newTemp(ty);
576 assign(res, binop(mkSAR(ty),
577 binop(mkSHL(ty), mkexpr(arg), mkU8(w - 1 - imm)),
578 mkU8(w - 1)));
579 return res;
580}
581
sewardj7d009132014-02-20 17:43:38 +0000582/* U-widen 8/16/32/64 bit int expr to 64. */
583static IRExpr* widenUto64 ( IRType srcTy, IRExpr* e )
584{
585 switch (srcTy) {
586 case Ity_I64: return e;
587 case Ity_I32: return unop(Iop_32Uto64, e);
588 case Ity_I16: return unop(Iop_16Uto64, e);
589 case Ity_I8: return unop(Iop_8Uto64, e);
590 default: vpanic("widenUto64(arm64)");
591 }
592}
593
594/* Narrow 64 bit int expr to 8/16/32/64. Clearly only some
595 of these combinations make sense. */
596static IRExpr* narrowFrom64 ( IRType dstTy, IRExpr* e )
597{
598 switch (dstTy) {
599 case Ity_I64: return e;
600 case Ity_I32: return unop(Iop_64to32, e);
601 case Ity_I16: return unop(Iop_64to16, e);
602 case Ity_I8: return unop(Iop_64to8, e);
603 default: vpanic("narrowFrom64(arm64)");
604 }
605}
606
sewardjbbcf1882014-01-12 12:49:10 +0000607
608/*------------------------------------------------------------*/
609/*--- Helpers for accessing guest registers. ---*/
610/*------------------------------------------------------------*/
611
612#define OFFB_X0 offsetof(VexGuestARM64State,guest_X0)
613#define OFFB_X1 offsetof(VexGuestARM64State,guest_X1)
614#define OFFB_X2 offsetof(VexGuestARM64State,guest_X2)
615#define OFFB_X3 offsetof(VexGuestARM64State,guest_X3)
616#define OFFB_X4 offsetof(VexGuestARM64State,guest_X4)
617#define OFFB_X5 offsetof(VexGuestARM64State,guest_X5)
618#define OFFB_X6 offsetof(VexGuestARM64State,guest_X6)
619#define OFFB_X7 offsetof(VexGuestARM64State,guest_X7)
620#define OFFB_X8 offsetof(VexGuestARM64State,guest_X8)
621#define OFFB_X9 offsetof(VexGuestARM64State,guest_X9)
622#define OFFB_X10 offsetof(VexGuestARM64State,guest_X10)
623#define OFFB_X11 offsetof(VexGuestARM64State,guest_X11)
624#define OFFB_X12 offsetof(VexGuestARM64State,guest_X12)
625#define OFFB_X13 offsetof(VexGuestARM64State,guest_X13)
626#define OFFB_X14 offsetof(VexGuestARM64State,guest_X14)
627#define OFFB_X15 offsetof(VexGuestARM64State,guest_X15)
628#define OFFB_X16 offsetof(VexGuestARM64State,guest_X16)
629#define OFFB_X17 offsetof(VexGuestARM64State,guest_X17)
630#define OFFB_X18 offsetof(VexGuestARM64State,guest_X18)
631#define OFFB_X19 offsetof(VexGuestARM64State,guest_X19)
632#define OFFB_X20 offsetof(VexGuestARM64State,guest_X20)
633#define OFFB_X21 offsetof(VexGuestARM64State,guest_X21)
634#define OFFB_X22 offsetof(VexGuestARM64State,guest_X22)
635#define OFFB_X23 offsetof(VexGuestARM64State,guest_X23)
636#define OFFB_X24 offsetof(VexGuestARM64State,guest_X24)
637#define OFFB_X25 offsetof(VexGuestARM64State,guest_X25)
638#define OFFB_X26 offsetof(VexGuestARM64State,guest_X26)
639#define OFFB_X27 offsetof(VexGuestARM64State,guest_X27)
640#define OFFB_X28 offsetof(VexGuestARM64State,guest_X28)
641#define OFFB_X29 offsetof(VexGuestARM64State,guest_X29)
642#define OFFB_X30 offsetof(VexGuestARM64State,guest_X30)
643
sewardj60687882014-01-15 10:25:21 +0000644#define OFFB_XSP offsetof(VexGuestARM64State,guest_XSP)
sewardjbbcf1882014-01-12 12:49:10 +0000645#define OFFB_PC offsetof(VexGuestARM64State,guest_PC)
646
647#define OFFB_CC_OP offsetof(VexGuestARM64State,guest_CC_OP)
648#define OFFB_CC_DEP1 offsetof(VexGuestARM64State,guest_CC_DEP1)
649#define OFFB_CC_DEP2 offsetof(VexGuestARM64State,guest_CC_DEP2)
650#define OFFB_CC_NDEP offsetof(VexGuestARM64State,guest_CC_NDEP)
651
652#define OFFB_TPIDR_EL0 offsetof(VexGuestARM64State,guest_TPIDR_EL0)
653#define OFFB_NRADDR offsetof(VexGuestARM64State,guest_NRADDR)
654
655#define OFFB_Q0 offsetof(VexGuestARM64State,guest_Q0)
656#define OFFB_Q1 offsetof(VexGuestARM64State,guest_Q1)
657#define OFFB_Q2 offsetof(VexGuestARM64State,guest_Q2)
658#define OFFB_Q3 offsetof(VexGuestARM64State,guest_Q3)
659#define OFFB_Q4 offsetof(VexGuestARM64State,guest_Q4)
660#define OFFB_Q5 offsetof(VexGuestARM64State,guest_Q5)
661#define OFFB_Q6 offsetof(VexGuestARM64State,guest_Q6)
662#define OFFB_Q7 offsetof(VexGuestARM64State,guest_Q7)
663#define OFFB_Q8 offsetof(VexGuestARM64State,guest_Q8)
664#define OFFB_Q9 offsetof(VexGuestARM64State,guest_Q9)
665#define OFFB_Q10 offsetof(VexGuestARM64State,guest_Q10)
666#define OFFB_Q11 offsetof(VexGuestARM64State,guest_Q11)
667#define OFFB_Q12 offsetof(VexGuestARM64State,guest_Q12)
668#define OFFB_Q13 offsetof(VexGuestARM64State,guest_Q13)
669#define OFFB_Q14 offsetof(VexGuestARM64State,guest_Q14)
670#define OFFB_Q15 offsetof(VexGuestARM64State,guest_Q15)
671#define OFFB_Q16 offsetof(VexGuestARM64State,guest_Q16)
672#define OFFB_Q17 offsetof(VexGuestARM64State,guest_Q17)
673#define OFFB_Q18 offsetof(VexGuestARM64State,guest_Q18)
674#define OFFB_Q19 offsetof(VexGuestARM64State,guest_Q19)
675#define OFFB_Q20 offsetof(VexGuestARM64State,guest_Q20)
676#define OFFB_Q21 offsetof(VexGuestARM64State,guest_Q21)
677#define OFFB_Q22 offsetof(VexGuestARM64State,guest_Q22)
678#define OFFB_Q23 offsetof(VexGuestARM64State,guest_Q23)
679#define OFFB_Q24 offsetof(VexGuestARM64State,guest_Q24)
680#define OFFB_Q25 offsetof(VexGuestARM64State,guest_Q25)
681#define OFFB_Q26 offsetof(VexGuestARM64State,guest_Q26)
682#define OFFB_Q27 offsetof(VexGuestARM64State,guest_Q27)
683#define OFFB_Q28 offsetof(VexGuestARM64State,guest_Q28)
684#define OFFB_Q29 offsetof(VexGuestARM64State,guest_Q29)
685#define OFFB_Q30 offsetof(VexGuestARM64State,guest_Q30)
686#define OFFB_Q31 offsetof(VexGuestARM64State,guest_Q31)
687
688#define OFFB_FPCR offsetof(VexGuestARM64State,guest_FPCR)
689#define OFFB_FPSR offsetof(VexGuestARM64State,guest_FPSR)
690//ZZ #define OFFB_TPIDRURO offsetof(VexGuestARMState,guest_TPIDRURO)
691//ZZ #define OFFB_ITSTATE offsetof(VexGuestARMState,guest_ITSTATE)
692//ZZ #define OFFB_QFLAG32 offsetof(VexGuestARMState,guest_QFLAG32)
693//ZZ #define OFFB_GEFLAG0 offsetof(VexGuestARMState,guest_GEFLAG0)
694//ZZ #define OFFB_GEFLAG1 offsetof(VexGuestARMState,guest_GEFLAG1)
695//ZZ #define OFFB_GEFLAG2 offsetof(VexGuestARMState,guest_GEFLAG2)
696//ZZ #define OFFB_GEFLAG3 offsetof(VexGuestARMState,guest_GEFLAG3)
697
698#define OFFB_TISTART offsetof(VexGuestARM64State,guest_TISTART)
699#define OFFB_TILEN offsetof(VexGuestARM64State,guest_TILEN)
700
701
702/* ---------------- Integer registers ---------------- */
703
704static Int offsetIReg64 ( UInt iregNo )
705{
706 /* Do we care about endianness here? We do if sub-parts of integer
707 registers are accessed. */
708 switch (iregNo) {
709 case 0: return OFFB_X0;
710 case 1: return OFFB_X1;
711 case 2: return OFFB_X2;
712 case 3: return OFFB_X3;
713 case 4: return OFFB_X4;
714 case 5: return OFFB_X5;
715 case 6: return OFFB_X6;
716 case 7: return OFFB_X7;
717 case 8: return OFFB_X8;
718 case 9: return OFFB_X9;
719 case 10: return OFFB_X10;
720 case 11: return OFFB_X11;
721 case 12: return OFFB_X12;
722 case 13: return OFFB_X13;
723 case 14: return OFFB_X14;
724 case 15: return OFFB_X15;
725 case 16: return OFFB_X16;
726 case 17: return OFFB_X17;
727 case 18: return OFFB_X18;
728 case 19: return OFFB_X19;
729 case 20: return OFFB_X20;
730 case 21: return OFFB_X21;
731 case 22: return OFFB_X22;
732 case 23: return OFFB_X23;
733 case 24: return OFFB_X24;
734 case 25: return OFFB_X25;
735 case 26: return OFFB_X26;
736 case 27: return OFFB_X27;
737 case 28: return OFFB_X28;
738 case 29: return OFFB_X29;
739 case 30: return OFFB_X30;
740 /* but not 31 */
741 default: vassert(0);
742 }
743}
744
745static Int offsetIReg64orSP ( UInt iregNo )
746{
sewardj60687882014-01-15 10:25:21 +0000747 return iregNo == 31 ? OFFB_XSP : offsetIReg64(iregNo);
sewardjbbcf1882014-01-12 12:49:10 +0000748}
749
750static const HChar* nameIReg64orZR ( UInt iregNo )
751{
752 vassert(iregNo < 32);
753 static const HChar* names[32]
754 = { "x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7",
755 "x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15",
756 "x16", "x17", "x18", "x19", "x20", "x21", "x22", "x23",
757 "x24", "x25", "x26", "x27", "x28", "x29", "x30", "xzr" };
758 return names[iregNo];
759}
760
761static const HChar* nameIReg64orSP ( UInt iregNo )
762{
763 if (iregNo == 31) {
764 return "sp";
765 }
766 vassert(iregNo < 31);
767 return nameIReg64orZR(iregNo);
768}
769
770static IRExpr* getIReg64orSP ( UInt iregNo )
771{
772 vassert(iregNo < 32);
773 return IRExpr_Get( offsetIReg64orSP(iregNo), Ity_I64 );
774}
775
776static IRExpr* getIReg64orZR ( UInt iregNo )
777{
778 if (iregNo == 31) {
779 return mkU64(0);
780 }
781 vassert(iregNo < 31);
782 return IRExpr_Get( offsetIReg64orSP(iregNo), Ity_I64 );
783}
784
785static void putIReg64orSP ( UInt iregNo, IRExpr* e )
786{
787 vassert(typeOfIRExpr(irsb->tyenv, e) == Ity_I64);
788 stmt( IRStmt_Put(offsetIReg64orSP(iregNo), e) );
789}
790
791static void putIReg64orZR ( UInt iregNo, IRExpr* e )
792{
793 vassert(typeOfIRExpr(irsb->tyenv, e) == Ity_I64);
794 if (iregNo == 31) {
795 return;
796 }
797 vassert(iregNo < 31);
798 stmt( IRStmt_Put(offsetIReg64orSP(iregNo), e) );
799}
800
801static const HChar* nameIReg32orZR ( UInt iregNo )
802{
803 vassert(iregNo < 32);
804 static const HChar* names[32]
805 = { "w0", "w1", "w2", "w3", "w4", "w5", "w6", "w7",
806 "w8", "w9", "w10", "w11", "w12", "w13", "w14", "w15",
807 "w16", "w17", "w18", "w19", "w20", "w21", "w22", "w23",
808 "w24", "w25", "w26", "w27", "w28", "w29", "w30", "wzr" };
809 return names[iregNo];
810}
811
812static const HChar* nameIReg32orSP ( UInt iregNo )
813{
814 if (iregNo == 31) {
815 return "wsp";
816 }
817 vassert(iregNo < 31);
818 return nameIReg32orZR(iregNo);
819}
820
821static IRExpr* getIReg32orSP ( UInt iregNo )
822{
823 vassert(iregNo < 32);
824 return unop(Iop_64to32,
825 IRExpr_Get( offsetIReg64orSP(iregNo), Ity_I64 ));
826}
827
828static IRExpr* getIReg32orZR ( UInt iregNo )
829{
830 if (iregNo == 31) {
831 return mkU32(0);
832 }
833 vassert(iregNo < 31);
834 return unop(Iop_64to32,
835 IRExpr_Get( offsetIReg64orSP(iregNo), Ity_I64 ));
836}
837
838static void putIReg32orSP ( UInt iregNo, IRExpr* e )
839{
840 vassert(typeOfIRExpr(irsb->tyenv, e) == Ity_I32);
841 stmt( IRStmt_Put(offsetIReg64orSP(iregNo), unop(Iop_32Uto64, e)) );
842}
843
844static void putIReg32orZR ( UInt iregNo, IRExpr* e )
845{
846 vassert(typeOfIRExpr(irsb->tyenv, e) == Ity_I32);
847 if (iregNo == 31) {
848 return;
849 }
850 vassert(iregNo < 31);
851 stmt( IRStmt_Put(offsetIReg64orSP(iregNo), unop(Iop_32Uto64, e)) );
852}
853
854static const HChar* nameIRegOrSP ( Bool is64, UInt iregNo )
855{
856 vassert(is64 == True || is64 == False);
857 return is64 ? nameIReg64orSP(iregNo) : nameIReg32orSP(iregNo);
858}
859
860static const HChar* nameIRegOrZR ( Bool is64, UInt iregNo )
861{
862 vassert(is64 == True || is64 == False);
863 return is64 ? nameIReg64orZR(iregNo) : nameIReg32orZR(iregNo);
864}
865
866static IRExpr* getIRegOrZR ( Bool is64, UInt iregNo )
867{
868 vassert(is64 == True || is64 == False);
869 return is64 ? getIReg64orZR(iregNo) : getIReg32orZR(iregNo);
870}
871
872static void putIRegOrZR ( Bool is64, UInt iregNo, IRExpr* e )
873{
874 vassert(is64 == True || is64 == False);
875 if (is64) putIReg64orZR(iregNo, e); else putIReg32orZR(iregNo, e);
876}
877
878static void putPC ( IRExpr* e )
879{
880 vassert(typeOfIRExpr(irsb->tyenv, e) == Ity_I64);
881 stmt( IRStmt_Put(OFFB_PC, e) );
882}
883
884
885/* ---------------- Vector (Q) registers ---------------- */
886
887static Int offsetQReg128 ( UInt qregNo )
888{
889 /* We don't care about endianness at this point. It only becomes
890 relevant when dealing with sections of these registers.*/
891 switch (qregNo) {
892 case 0: return OFFB_Q0;
893 case 1: return OFFB_Q1;
894 case 2: return OFFB_Q2;
895 case 3: return OFFB_Q3;
896 case 4: return OFFB_Q4;
897 case 5: return OFFB_Q5;
898 case 6: return OFFB_Q6;
899 case 7: return OFFB_Q7;
900 case 8: return OFFB_Q8;
901 case 9: return OFFB_Q9;
902 case 10: return OFFB_Q10;
903 case 11: return OFFB_Q11;
904 case 12: return OFFB_Q12;
905 case 13: return OFFB_Q13;
906 case 14: return OFFB_Q14;
907 case 15: return OFFB_Q15;
908 case 16: return OFFB_Q16;
909 case 17: return OFFB_Q17;
910 case 18: return OFFB_Q18;
911 case 19: return OFFB_Q19;
912 case 20: return OFFB_Q20;
913 case 21: return OFFB_Q21;
914 case 22: return OFFB_Q22;
915 case 23: return OFFB_Q23;
916 case 24: return OFFB_Q24;
917 case 25: return OFFB_Q25;
918 case 26: return OFFB_Q26;
919 case 27: return OFFB_Q27;
920 case 28: return OFFB_Q28;
921 case 29: return OFFB_Q29;
922 case 30: return OFFB_Q30;
923 case 31: return OFFB_Q31;
924 default: vassert(0);
925 }
926}
927
sewardjbbcf1882014-01-12 12:49:10 +0000928/* Write to a complete Qreg. */
929static void putQReg128 ( UInt qregNo, IRExpr* e )
930{
931 vassert(qregNo < 32);
932 vassert(typeOfIRExpr(irsb->tyenv, e) == Ity_V128);
933 stmt( IRStmt_Put(offsetQReg128(qregNo), e) );
934}
935
936/* Read a complete Qreg. */
937static IRExpr* getQReg128 ( UInt qregNo )
938{
939 vassert(qregNo < 32);
940 return IRExpr_Get(offsetQReg128(qregNo), Ity_V128);
941}
942
943/* Produce the IR type for some sub-part of a vector. For 32- and 64-
944 bit sub-parts we can choose either integer or float types, and
945 choose float on the basis that that is the common use case and so
946 will give least interference with Put-to-Get forwarding later
947 on. */
948static IRType preferredVectorSubTypeFromSize ( UInt szB )
949{
950 switch (szB) {
951 case 1: return Ity_I8;
952 case 2: return Ity_I16;
953 case 4: return Ity_I32; //Ity_F32;
954 case 8: return Ity_F64;
955 case 16: return Ity_V128;
956 default: vassert(0);
957 }
958}
959
sewardj606c4ba2014-01-26 19:11:14 +0000960/* Find the offset of the laneNo'th lane of type laneTy in the given
961 Qreg. Since the host is little-endian, the least significant lane
962 has the lowest offset. */
963static Int offsetQRegLane ( UInt qregNo, IRType laneTy, UInt laneNo )
sewardjbbcf1882014-01-12 12:49:10 +0000964{
965 vassert(!host_is_bigendian);
966 Int base = offsetQReg128(qregNo);
sewardj606c4ba2014-01-26 19:11:14 +0000967 /* Since the host is little-endian, the least significant lane
968 will be at the lowest address. */
969 /* Restrict this to known types, so as to avoid silently accepting
970 stupid types. */
971 UInt laneSzB = 0;
972 switch (laneTy) {
973 case Ity_F32: case Ity_I32: laneSzB = 4; break;
974 case Ity_F64: case Ity_I64: laneSzB = 8; break;
975 case Ity_V128: laneSzB = 16; break;
976 default: break;
sewardjbbcf1882014-01-12 12:49:10 +0000977 }
sewardj606c4ba2014-01-26 19:11:14 +0000978 vassert(laneSzB > 0);
979 UInt minOff = laneNo * laneSzB;
980 UInt maxOff = minOff + laneSzB - 1;
981 vassert(maxOff < 16);
982 return base + minOff;
sewardjbbcf1882014-01-12 12:49:10 +0000983}
984
sewardj606c4ba2014-01-26 19:11:14 +0000985/* Put to the least significant lane of a Qreg. */
986static void putQRegLO ( UInt qregNo, IRExpr* e )
sewardjbbcf1882014-01-12 12:49:10 +0000987{
988 IRType ty = typeOfIRExpr(irsb->tyenv, e);
sewardj606c4ba2014-01-26 19:11:14 +0000989 Int off = offsetQRegLane(qregNo, ty, 0);
sewardjbbcf1882014-01-12 12:49:10 +0000990 switch (ty) {
sewardj606c4ba2014-01-26 19:11:14 +0000991 case Ity_I8: case Ity_I16: case Ity_I32: case Ity_I64:
992 case Ity_F32: case Ity_F64: case Ity_V128:
993 break;
994 default:
995 vassert(0); // Other cases are probably invalid
sewardjbbcf1882014-01-12 12:49:10 +0000996 }
997 stmt(IRStmt_Put(off, e));
998}
999
sewardj606c4ba2014-01-26 19:11:14 +00001000/* Get from the least significant lane of a Qreg. */
1001static IRExpr* getQRegLO ( UInt qregNo, IRType ty )
sewardjbbcf1882014-01-12 12:49:10 +00001002{
sewardj606c4ba2014-01-26 19:11:14 +00001003 Int off = offsetQRegLane(qregNo, ty, 0);
sewardjbbcf1882014-01-12 12:49:10 +00001004 switch (ty) {
sewardj606c4ba2014-01-26 19:11:14 +00001005 case Ity_I32: case Ity_I64:
1006 case Ity_F32: case Ity_F64: case Ity_V128:
1007 break;
1008 default:
1009 vassert(0); // Other cases are ATC
sewardjbbcf1882014-01-12 12:49:10 +00001010 }
1011 return IRExpr_Get(off, ty);
1012}
1013
sewardj606c4ba2014-01-26 19:11:14 +00001014static const HChar* nameQRegLO ( UInt qregNo, IRType laneTy )
sewardjbbcf1882014-01-12 12:49:10 +00001015{
1016 static const HChar* namesQ[32]
1017 = { "q0", "q1", "q2", "q3", "q4", "q5", "q6", "q7",
1018 "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15",
1019 "q16", "q17", "q18", "q19", "q20", "q21", "q22", "q23",
1020 "q24", "q25", "q26", "q27", "q28", "q29", "q30", "q31" };
1021 static const HChar* namesD[32]
1022 = { "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7",
1023 "d8", "d9", "d10", "d11", "d12", "d13", "d14", "d15",
1024 "d16", "d17", "d18", "d19", "d20", "d21", "d22", "d23",
1025 "d24", "d25", "d26", "d27", "d28", "d29", "d30", "d31" };
1026 static const HChar* namesS[32]
1027 = { "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
1028 "s8", "s9", "s10", "s11", "s12", "s13", "s14", "s15",
1029 "s16", "s17", "s18", "s19", "s20", "s21", "s22", "s23",
1030 "s24", "s25", "s26", "s27", "s28", "s29", "s30", "s31" };
1031 static const HChar* namesH[32]
1032 = { "h0", "h1", "h2", "h3", "h4", "h5", "h6", "h7",
1033 "h8", "h9", "h10", "h11", "h12", "h13", "h14", "h15",
1034 "h16", "h17", "h18", "h19", "h20", "h21", "h22", "h23",
1035 "h24", "h25", "h26", "h27", "h28", "h29", "h30", "h31" };
1036 static const HChar* namesB[32]
1037 = { "b0", "b1", "b2", "b3", "b4", "b5", "b6", "b7",
1038 "b8", "b9", "b10", "b11", "b12", "b13", "b14", "b15",
1039 "b16", "b17", "b18", "b19", "b20", "b21", "b22", "b23",
1040 "b24", "b25", "b26", "b27", "b28", "b29", "b30", "b31" };
1041 vassert(qregNo < 32);
sewardj606c4ba2014-01-26 19:11:14 +00001042 switch (sizeofIRType(laneTy)) {
sewardjbbcf1882014-01-12 12:49:10 +00001043 case 1: return namesB[qregNo];
1044 case 2: return namesH[qregNo];
1045 case 4: return namesS[qregNo];
1046 case 8: return namesD[qregNo];
1047 case 16: return namesQ[qregNo];
1048 default: vassert(0);
1049 }
1050 /*NOTREACHED*/
1051}
1052
sewardj606c4ba2014-01-26 19:11:14 +00001053static const HChar* nameQReg128 ( UInt qregNo )
1054{
1055 return nameQRegLO(qregNo, Ity_V128);
1056}
1057
sewardjbbcf1882014-01-12 12:49:10 +00001058/* Find the offset of the most significant half (8 bytes) of the given
1059 Qreg. This requires knowing the endianness of the host. */
sewardj606c4ba2014-01-26 19:11:14 +00001060static Int offsetQRegHI64 ( UInt qregNo )
sewardjbbcf1882014-01-12 12:49:10 +00001061{
sewardj606c4ba2014-01-26 19:11:14 +00001062 return offsetQRegLane(qregNo, Ity_I64, 1);
sewardjbbcf1882014-01-12 12:49:10 +00001063}
1064
sewardj606c4ba2014-01-26 19:11:14 +00001065static IRExpr* getQRegHI64 ( UInt qregNo )
sewardjbbcf1882014-01-12 12:49:10 +00001066{
sewardj606c4ba2014-01-26 19:11:14 +00001067 return IRExpr_Get(offsetQRegHI64(qregNo), Ity_I64);
sewardjbbcf1882014-01-12 12:49:10 +00001068}
1069
sewardj606c4ba2014-01-26 19:11:14 +00001070static void putQRegHI64 ( UInt qregNo, IRExpr* e )
sewardjbbcf1882014-01-12 12:49:10 +00001071{
1072 IRType ty = typeOfIRExpr(irsb->tyenv, e);
sewardj606c4ba2014-01-26 19:11:14 +00001073 Int off = offsetQRegHI64(qregNo);
sewardjbbcf1882014-01-12 12:49:10 +00001074 switch (ty) {
sewardj606c4ba2014-01-26 19:11:14 +00001075 case Ity_I64: case Ity_F64:
1076 break;
1077 default:
1078 vassert(0); // Other cases are plain wrong
sewardjbbcf1882014-01-12 12:49:10 +00001079 }
1080 stmt(IRStmt_Put(off, e));
1081}
1082
sewardj606c4ba2014-01-26 19:11:14 +00001083/* Put to a specified lane of a Qreg. */
1084static void putQRegLane ( UInt qregNo, UInt laneNo, IRExpr* e )
1085{
1086 IRType laneTy = typeOfIRExpr(irsb->tyenv, e);
1087 Int off = offsetQRegLane(qregNo, laneTy, laneNo);
1088 switch (laneTy) {
1089 case Ity_F64: case Ity_I64:
1090 break;
1091 default:
1092 vassert(0); // Other cases are ATC
1093 }
1094 stmt(IRStmt_Put(off, e));
1095}
1096
1097/* Get from the least significant lane of a Qreg. */
1098static IRExpr* getQRegLane ( UInt qregNo, UInt laneNo, IRType laneTy )
1099{
1100 Int off = offsetQRegLane(qregNo, laneTy, laneNo);
1101 switch (laneTy) {
1102 case Ity_I64: case Ity_I32:
1103 break;
1104 default:
1105 vassert(0); // Other cases are ATC
1106 }
1107 return IRExpr_Get(off, laneTy);
1108}
1109
1110
sewardjbbcf1882014-01-12 12:49:10 +00001111//ZZ /* ---------------- Misc registers ---------------- */
1112//ZZ
1113//ZZ static void putMiscReg32 ( UInt gsoffset,
1114//ZZ IRExpr* e, /* :: Ity_I32 */
1115//ZZ IRTemp guardT /* :: Ity_I32, 0 or 1 */)
1116//ZZ {
1117//ZZ switch (gsoffset) {
1118//ZZ case OFFB_FPSCR: break;
1119//ZZ case OFFB_QFLAG32: break;
1120//ZZ case OFFB_GEFLAG0: break;
1121//ZZ case OFFB_GEFLAG1: break;
1122//ZZ case OFFB_GEFLAG2: break;
1123//ZZ case OFFB_GEFLAG3: break;
1124//ZZ default: vassert(0); /* awaiting more cases */
1125//ZZ }
1126//ZZ vassert(typeOfIRExpr(irsb->tyenv, e) == Ity_I32);
1127//ZZ
1128//ZZ if (guardT == IRTemp_INVALID) {
1129//ZZ /* unconditional write */
1130//ZZ stmt(IRStmt_Put(gsoffset, e));
1131//ZZ } else {
1132//ZZ stmt(IRStmt_Put(
1133//ZZ gsoffset,
1134//ZZ IRExpr_ITE( binop(Iop_CmpNE32, mkexpr(guardT), mkU32(0)),
1135//ZZ e, IRExpr_Get(gsoffset, Ity_I32) )
1136//ZZ ));
1137//ZZ }
1138//ZZ }
1139//ZZ
1140//ZZ static IRTemp get_ITSTATE ( void )
1141//ZZ {
1142//ZZ ASSERT_IS_THUMB;
1143//ZZ IRTemp t = newTemp(Ity_I32);
1144//ZZ assign(t, IRExpr_Get( OFFB_ITSTATE, Ity_I32));
1145//ZZ return t;
1146//ZZ }
1147//ZZ
1148//ZZ static void put_ITSTATE ( IRTemp t )
1149//ZZ {
1150//ZZ ASSERT_IS_THUMB;
1151//ZZ stmt( IRStmt_Put( OFFB_ITSTATE, mkexpr(t)) );
1152//ZZ }
1153//ZZ
1154//ZZ static IRTemp get_QFLAG32 ( void )
1155//ZZ {
1156//ZZ IRTemp t = newTemp(Ity_I32);
1157//ZZ assign(t, IRExpr_Get( OFFB_QFLAG32, Ity_I32));
1158//ZZ return t;
1159//ZZ }
1160//ZZ
1161//ZZ static void put_QFLAG32 ( IRTemp t, IRTemp condT )
1162//ZZ {
1163//ZZ putMiscReg32( OFFB_QFLAG32, mkexpr(t), condT );
1164//ZZ }
1165//ZZ
1166//ZZ /* Stickily set the 'Q' flag (APSR bit 27) of the APSR (Application Program
1167//ZZ Status Register) to indicate that overflow or saturation occurred.
1168//ZZ Nb: t must be zero to denote no saturation, and any nonzero
1169//ZZ value to indicate saturation. */
1170//ZZ static void or_into_QFLAG32 ( IRExpr* e, IRTemp condT )
1171//ZZ {
1172//ZZ IRTemp old = get_QFLAG32();
1173//ZZ IRTemp nyu = newTemp(Ity_I32);
1174//ZZ assign(nyu, binop(Iop_Or32, mkexpr(old), e) );
1175//ZZ put_QFLAG32(nyu, condT);
1176//ZZ }
1177
1178
1179/* ---------------- FPCR stuff ---------------- */
1180
1181/* Generate IR to get hold of the rounding mode bits in FPCR, and
1182 convert them to IR format. Bind the final result to the
1183 returned temp. */
1184static IRTemp /* :: Ity_I32 */ mk_get_IR_rounding_mode ( void )
1185{
1186 /* The ARMvfp encoding for rounding mode bits is:
1187 00 to nearest
1188 01 to +infinity
1189 10 to -infinity
1190 11 to zero
1191 We need to convert that to the IR encoding:
1192 00 to nearest (the default)
1193 10 to +infinity
1194 01 to -infinity
1195 11 to zero
1196 Which can be done by swapping bits 0 and 1.
1197 The rmode bits are at 23:22 in FPSCR.
1198 */
1199 IRTemp armEncd = newTemp(Ity_I32);
1200 IRTemp swapped = newTemp(Ity_I32);
1201 /* Fish FPCR[23:22] out, and slide to bottom. Doesn't matter that
1202 we don't zero out bits 24 and above, since the assignment to
1203 'swapped' will mask them out anyway. */
1204 assign(armEncd,
1205 binop(Iop_Shr32, IRExpr_Get(OFFB_FPCR, Ity_I32), mkU8(22)));
1206 /* Now swap them. */
1207 assign(swapped,
1208 binop(Iop_Or32,
1209 binop(Iop_And32,
1210 binop(Iop_Shl32, mkexpr(armEncd), mkU8(1)),
1211 mkU32(2)),
1212 binop(Iop_And32,
1213 binop(Iop_Shr32, mkexpr(armEncd), mkU8(1)),
1214 mkU32(1))
1215 ));
1216 return swapped;
1217}
1218
1219
1220/*------------------------------------------------------------*/
1221/*--- Helpers for flag handling and conditional insns ---*/
1222/*------------------------------------------------------------*/
1223
1224static const HChar* nameARM64Condcode ( ARM64Condcode cond )
1225{
1226 switch (cond) {
1227 case ARM64CondEQ: return "eq";
1228 case ARM64CondNE: return "ne";
1229 case ARM64CondCS: return "cs"; // or 'hs'
1230 case ARM64CondCC: return "cc"; // or 'lo'
1231 case ARM64CondMI: return "mi";
1232 case ARM64CondPL: return "pl";
1233 case ARM64CondVS: return "vs";
1234 case ARM64CondVC: return "vc";
1235 case ARM64CondHI: return "hi";
1236 case ARM64CondLS: return "ls";
1237 case ARM64CondGE: return "ge";
1238 case ARM64CondLT: return "lt";
1239 case ARM64CondGT: return "gt";
1240 case ARM64CondLE: return "le";
1241 case ARM64CondAL: return "al";
1242 case ARM64CondNV: return "nv";
1243 default: vpanic("name_ARM64Condcode");
1244 }
1245}
1246
1247/* and a handy shorthand for it */
1248static const HChar* nameCC ( ARM64Condcode cond ) {
1249 return nameARM64Condcode(cond);
1250}
1251
1252
1253/* Build IR to calculate some particular condition from stored
1254 CC_OP/CC_DEP1/CC_DEP2/CC_NDEP. Returns an expression of type
1255 Ity_I64, suitable for narrowing. Although the return type is
1256 Ity_I64, the returned value is either 0 or 1. 'cond' must be
1257 :: Ity_I64 and must denote the condition to compute in
1258 bits 7:4, and be zero everywhere else.
1259*/
1260static IRExpr* mk_arm64g_calculate_condition_dyn ( IRExpr* cond )
1261{
1262 vassert(typeOfIRExpr(irsb->tyenv, cond) == Ity_I64);
1263 /* And 'cond' had better produce a value in which only bits 7:4 are
1264 nonzero. However, obviously we can't assert for that. */
1265
1266 /* So what we're constructing for the first argument is
1267 "(cond << 4) | stored-operation".
1268 However, as per comments above, 'cond' must be supplied
1269 pre-shifted to this function.
1270
1271 This pairing scheme requires that the ARM64_CC_OP_ values all fit
1272 in 4 bits. Hence we are passing a (COND, OP) pair in the lowest
1273 8 bits of the first argument. */
1274 IRExpr** args
1275 = mkIRExprVec_4(
1276 binop(Iop_Or64, IRExpr_Get(OFFB_CC_OP, Ity_I64), cond),
1277 IRExpr_Get(OFFB_CC_DEP1, Ity_I64),
1278 IRExpr_Get(OFFB_CC_DEP2, Ity_I64),
1279 IRExpr_Get(OFFB_CC_NDEP, Ity_I64)
1280 );
1281 IRExpr* call
1282 = mkIRExprCCall(
1283 Ity_I64,
1284 0/*regparm*/,
1285 "arm64g_calculate_condition", &arm64g_calculate_condition,
1286 args
1287 );
1288
1289 /* Exclude the requested condition, OP and NDEP from definedness
1290 checking. We're only interested in DEP1 and DEP2. */
1291 call->Iex.CCall.cee->mcx_mask = (1<<0) | (1<<3);
1292 return call;
1293}
1294
1295
1296/* Build IR to calculate some particular condition from stored
1297 CC_OP/CC_DEP1/CC_DEP2/CC_NDEP. Returns an expression of type
1298 Ity_I64, suitable for narrowing. Although the return type is
1299 Ity_I64, the returned value is either 0 or 1.
1300*/
1301static IRExpr* mk_arm64g_calculate_condition ( ARM64Condcode cond )
1302{
1303 /* First arg is "(cond << 4) | condition". This requires that the
1304 ARM64_CC_OP_ values all fit in 4 bits. Hence we are passing a
1305 (COND, OP) pair in the lowest 8 bits of the first argument. */
1306 vassert(cond >= 0 && cond <= 15);
1307 return mk_arm64g_calculate_condition_dyn( mkU64(cond << 4) );
1308}
1309
1310
1311//ZZ /* Build IR to calculate just the carry flag from stored
1312//ZZ CC_OP/CC_DEP1/CC_DEP2/CC_NDEP. Returns an expression ::
1313//ZZ Ity_I32. */
1314//ZZ static IRExpr* mk_armg_calculate_flag_c ( void )
1315//ZZ {
1316//ZZ IRExpr** args
1317//ZZ = mkIRExprVec_4( IRExpr_Get(OFFB_CC_OP, Ity_I32),
1318//ZZ IRExpr_Get(OFFB_CC_DEP1, Ity_I32),
1319//ZZ IRExpr_Get(OFFB_CC_DEP2, Ity_I32),
1320//ZZ IRExpr_Get(OFFB_CC_NDEP, Ity_I32) );
1321//ZZ IRExpr* call
1322//ZZ = mkIRExprCCall(
1323//ZZ Ity_I32,
1324//ZZ 0/*regparm*/,
1325//ZZ "armg_calculate_flag_c", &armg_calculate_flag_c,
1326//ZZ args
1327//ZZ );
1328//ZZ /* Exclude OP and NDEP from definedness checking. We're only
1329//ZZ interested in DEP1 and DEP2. */
1330//ZZ call->Iex.CCall.cee->mcx_mask = (1<<0) | (1<<3);
1331//ZZ return call;
1332//ZZ }
1333//ZZ
1334//ZZ
1335//ZZ /* Build IR to calculate just the overflow flag from stored
1336//ZZ CC_OP/CC_DEP1/CC_DEP2/CC_NDEP. Returns an expression ::
1337//ZZ Ity_I32. */
1338//ZZ static IRExpr* mk_armg_calculate_flag_v ( void )
1339//ZZ {
1340//ZZ IRExpr** args
1341//ZZ = mkIRExprVec_4( IRExpr_Get(OFFB_CC_OP, Ity_I32),
1342//ZZ IRExpr_Get(OFFB_CC_DEP1, Ity_I32),
1343//ZZ IRExpr_Get(OFFB_CC_DEP2, Ity_I32),
1344//ZZ IRExpr_Get(OFFB_CC_NDEP, Ity_I32) );
1345//ZZ IRExpr* call
1346//ZZ = mkIRExprCCall(
1347//ZZ Ity_I32,
1348//ZZ 0/*regparm*/,
1349//ZZ "armg_calculate_flag_v", &armg_calculate_flag_v,
1350//ZZ args
1351//ZZ );
1352//ZZ /* Exclude OP and NDEP from definedness checking. We're only
1353//ZZ interested in DEP1 and DEP2. */
1354//ZZ call->Iex.CCall.cee->mcx_mask = (1<<0) | (1<<3);
1355//ZZ return call;
1356//ZZ }
1357
1358
1359/* Build IR to calculate N Z C V in bits 31:28 of the
1360 returned word. */
1361static IRExpr* mk_arm64g_calculate_flags_nzcv ( void )
1362{
1363 IRExpr** args
1364 = mkIRExprVec_4( IRExpr_Get(OFFB_CC_OP, Ity_I64),
1365 IRExpr_Get(OFFB_CC_DEP1, Ity_I64),
1366 IRExpr_Get(OFFB_CC_DEP2, Ity_I64),
1367 IRExpr_Get(OFFB_CC_NDEP, Ity_I64) );
1368 IRExpr* call
1369 = mkIRExprCCall(
1370 Ity_I64,
1371 0/*regparm*/,
1372 "arm64g_calculate_flags_nzcv", &arm64g_calculate_flags_nzcv,
1373 args
1374 );
1375 /* Exclude OP and NDEP from definedness checking. We're only
1376 interested in DEP1 and DEP2. */
1377 call->Iex.CCall.cee->mcx_mask = (1<<0) | (1<<3);
1378 return call;
1379}
1380
1381
1382/* Build IR to set the flags thunk, in the most general case. */
1383static
1384void setFlags_D1_D2_ND ( UInt cc_op,
1385 IRTemp t_dep1, IRTemp t_dep2, IRTemp t_ndep )
1386{
1387 vassert(typeOfIRTemp(irsb->tyenv, t_dep1 == Ity_I64));
1388 vassert(typeOfIRTemp(irsb->tyenv, t_dep2 == Ity_I64));
1389 vassert(typeOfIRTemp(irsb->tyenv, t_ndep == Ity_I64));
1390 vassert(cc_op >= ARM64G_CC_OP_COPY && cc_op < ARM64G_CC_OP_NUMBER);
1391 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(cc_op) ));
1392 stmt( IRStmt_Put( OFFB_CC_DEP1, mkexpr(t_dep1) ));
1393 stmt( IRStmt_Put( OFFB_CC_DEP2, mkexpr(t_dep2) ));
1394 stmt( IRStmt_Put( OFFB_CC_NDEP, mkexpr(t_ndep) ));
1395}
1396
1397/* Build IR to set the flags thunk after ADD or SUB. */
1398static
1399void setFlags_ADD_SUB ( Bool is64, Bool isSUB, IRTemp argL, IRTemp argR )
1400{
1401 IRTemp argL64 = IRTemp_INVALID;
1402 IRTemp argR64 = IRTemp_INVALID;
1403 IRTemp z64 = newTemp(Ity_I64);
1404 if (is64) {
1405 argL64 = argL;
1406 argR64 = argR;
1407 } else {
1408 argL64 = newTemp(Ity_I64);
1409 argR64 = newTemp(Ity_I64);
1410 assign(argL64, unop(Iop_32Uto64, mkexpr(argL)));
1411 assign(argR64, unop(Iop_32Uto64, mkexpr(argR)));
1412 }
1413 assign(z64, mkU64(0));
1414 UInt cc_op = ARM64G_CC_OP_NUMBER;
1415 /**/ if ( isSUB && is64) { cc_op = ARM64G_CC_OP_SUB64; }
1416 else if ( isSUB && !is64) { cc_op = ARM64G_CC_OP_SUB32; }
1417 else if (!isSUB && is64) { cc_op = ARM64G_CC_OP_ADD64; }
1418 else if (!isSUB && !is64) { cc_op = ARM64G_CC_OP_ADD32; }
1419 else { vassert(0); }
1420 setFlags_D1_D2_ND(cc_op, argL64, argR64, z64);
1421}
1422
1423/* Build IR to set the flags thunk after ADD or SUB, if the given
1424 condition evaluates to True at run time. If not, the flags are set
1425 to the specified NZCV value. */
1426static
1427void setFlags_ADD_SUB_conditionally (
1428 Bool is64, Bool isSUB,
1429 IRTemp cond, IRTemp argL, IRTemp argR, UInt nzcv
1430 )
1431{
1432 /* Generate IR as follows:
1433 CC_OP = ITE(cond, OP_{ADD,SUB}{32,64}, OP_COPY)
1434 CC_DEP1 = ITE(cond, argL64, nzcv << 28)
1435 CC_DEP2 = ITE(cond, argR64, 0)
1436 CC_NDEP = 0
1437 */
1438
1439 IRTemp z64 = newTemp(Ity_I64);
1440 assign(z64, mkU64(0));
1441
1442 /* Establish the operation and operands for the True case. */
1443 IRTemp t_dep1 = IRTemp_INVALID;
1444 IRTemp t_dep2 = IRTemp_INVALID;
1445 UInt t_op = ARM64G_CC_OP_NUMBER;
1446 /**/ if ( isSUB && is64) { t_op = ARM64G_CC_OP_SUB64; }
1447 else if ( isSUB && !is64) { t_op = ARM64G_CC_OP_SUB32; }
1448 else if (!isSUB && is64) { t_op = ARM64G_CC_OP_ADD64; }
1449 else if (!isSUB && !is64) { t_op = ARM64G_CC_OP_ADD32; }
1450 else { vassert(0); }
1451 /* */
1452 if (is64) {
1453 t_dep1 = argL;
1454 t_dep2 = argR;
1455 } else {
1456 t_dep1 = newTemp(Ity_I64);
1457 t_dep2 = newTemp(Ity_I64);
1458 assign(t_dep1, unop(Iop_32Uto64, mkexpr(argL)));
1459 assign(t_dep2, unop(Iop_32Uto64, mkexpr(argR)));
1460 }
1461
1462 /* Establish the operation and operands for the False case. */
1463 IRTemp f_dep1 = newTemp(Ity_I64);
1464 IRTemp f_dep2 = z64;
1465 UInt f_op = ARM64G_CC_OP_COPY;
1466 assign(f_dep1, mkU64(nzcv << 28));
1467
1468 /* Final thunk values */
1469 IRTemp dep1 = newTemp(Ity_I64);
1470 IRTemp dep2 = newTemp(Ity_I64);
1471 IRTemp op = newTemp(Ity_I64);
1472
1473 assign(op, IRExpr_ITE(mkexpr(cond), mkU64(t_op), mkU64(f_op)));
1474 assign(dep1, IRExpr_ITE(mkexpr(cond), mkexpr(t_dep1), mkexpr(f_dep1)));
1475 assign(dep2, IRExpr_ITE(mkexpr(cond), mkexpr(t_dep2), mkexpr(f_dep2)));
1476
1477 /* finally .. */
1478 stmt( IRStmt_Put( OFFB_CC_OP, mkexpr(op) ));
1479 stmt( IRStmt_Put( OFFB_CC_DEP1, mkexpr(dep1) ));
1480 stmt( IRStmt_Put( OFFB_CC_DEP2, mkexpr(dep2) ));
1481 stmt( IRStmt_Put( OFFB_CC_NDEP, mkexpr(z64) ));
1482}
1483
1484/* Build IR to set the flags thunk after AND/OR/XOR or variants thereof. */
1485static
1486void setFlags_LOGIC ( Bool is64, IRTemp res )
1487{
1488 IRTemp res64 = IRTemp_INVALID;
1489 IRTemp z64 = newTemp(Ity_I64);
1490 UInt cc_op = ARM64G_CC_OP_NUMBER;
1491 if (is64) {
1492 res64 = res;
1493 cc_op = ARM64G_CC_OP_LOGIC64;
1494 } else {
1495 res64 = newTemp(Ity_I64);
1496 assign(res64, unop(Iop_32Uto64, mkexpr(res)));
1497 cc_op = ARM64G_CC_OP_LOGIC32;
1498 }
1499 assign(z64, mkU64(0));
1500 setFlags_D1_D2_ND(cc_op, res64, z64, z64);
1501}
1502
1503/* Build IR to set the flags thunk to a given NZCV value. NZCV is
1504 located in bits 31:28 of the supplied value. */
1505static
1506void setFlags_COPY ( IRTemp nzcv_28x0 )
1507{
1508 IRTemp z64 = newTemp(Ity_I64);
1509 assign(z64, mkU64(0));
1510 setFlags_D1_D2_ND(ARM64G_CC_OP_COPY, nzcv_28x0, z64, z64);
1511}
1512
1513
1514//ZZ /* Minor variant of the above that sets NDEP to zero (if it
1515//ZZ sets it at all) */
1516//ZZ static void setFlags_D1_D2 ( UInt cc_op, IRTemp t_dep1,
1517//ZZ IRTemp t_dep2,
1518//ZZ IRTemp guardT /* :: Ity_I32, 0 or 1 */ )
1519//ZZ {
1520//ZZ IRTemp z32 = newTemp(Ity_I32);
1521//ZZ assign( z32, mkU32(0) );
1522//ZZ setFlags_D1_D2_ND( cc_op, t_dep1, t_dep2, z32, guardT );
1523//ZZ }
1524//ZZ
1525//ZZ
1526//ZZ /* Minor variant of the above that sets DEP2 to zero (if it
1527//ZZ sets it at all) */
1528//ZZ static void setFlags_D1_ND ( UInt cc_op, IRTemp t_dep1,
1529//ZZ IRTemp t_ndep,
1530//ZZ IRTemp guardT /* :: Ity_I32, 0 or 1 */ )
1531//ZZ {
1532//ZZ IRTemp z32 = newTemp(Ity_I32);
1533//ZZ assign( z32, mkU32(0) );
1534//ZZ setFlags_D1_D2_ND( cc_op, t_dep1, z32, t_ndep, guardT );
1535//ZZ }
1536//ZZ
1537//ZZ
1538//ZZ /* Minor variant of the above that sets DEP2 and NDEP to zero (if it
1539//ZZ sets them at all) */
1540//ZZ static void setFlags_D1 ( UInt cc_op, IRTemp t_dep1,
1541//ZZ IRTemp guardT /* :: Ity_I32, 0 or 1 */ )
1542//ZZ {
1543//ZZ IRTemp z32 = newTemp(Ity_I32);
1544//ZZ assign( z32, mkU32(0) );
1545//ZZ setFlags_D1_D2_ND( cc_op, t_dep1, z32, z32, guardT );
1546//ZZ }
1547
1548
1549/*------------------------------------------------------------*/
1550/*--- Misc math helpers ---*/
1551/*------------------------------------------------------------*/
1552
1553/* Generates a 64-bit byte swap. */
sewardjdc9259c2014-02-27 11:10:19 +00001554static IRTemp math_BYTESWAP64 ( IRTemp src )
sewardjbbcf1882014-01-12 12:49:10 +00001555{
sewardjbbcf1882014-01-12 12:49:10 +00001556 IRTemp m8 = newTemp(Ity_I64);
1557 IRTemp s8 = newTemp(Ity_I64);
1558 IRTemp m16 = newTemp(Ity_I64);
1559 IRTemp s16 = newTemp(Ity_I64);
1560 IRTemp m32 = newTemp(Ity_I64);
sewardjdc9259c2014-02-27 11:10:19 +00001561 IRTemp res = newTemp(Ity_I64);
sewardjbbcf1882014-01-12 12:49:10 +00001562 assign( m8, mkU64(0xFF00FF00FF00FF00ULL) );
1563 assign( s8,
1564 binop(Iop_Or64,
1565 binop(Iop_Shr64,
sewardjdc9259c2014-02-27 11:10:19 +00001566 binop(Iop_And64,mkexpr(src),mkexpr(m8)),
sewardjbbcf1882014-01-12 12:49:10 +00001567 mkU8(8)),
1568 binop(Iop_And64,
sewardjdc9259c2014-02-27 11:10:19 +00001569 binop(Iop_Shl64,mkexpr(src),mkU8(8)),
sewardjbbcf1882014-01-12 12:49:10 +00001570 mkexpr(m8))
1571 )
1572 );
1573
1574 assign( m16, mkU64(0xFFFF0000FFFF0000ULL) );
1575 assign( s16,
1576 binop(Iop_Or64,
1577 binop(Iop_Shr64,
1578 binop(Iop_And64,mkexpr(s8),mkexpr(m16)),
1579 mkU8(16)),
1580 binop(Iop_And64,
1581 binop(Iop_Shl64,mkexpr(s8),mkU8(16)),
1582 mkexpr(m16))
1583 )
1584 );
1585
1586 assign( m32, mkU64(0xFFFFFFFF00000000ULL) );
sewardjdc9259c2014-02-27 11:10:19 +00001587 assign( res,
sewardjbbcf1882014-01-12 12:49:10 +00001588 binop(Iop_Or64,
1589 binop(Iop_Shr64,
1590 binop(Iop_And64,mkexpr(s16),mkexpr(m32)),
1591 mkU8(32)),
1592 binop(Iop_And64,
1593 binop(Iop_Shl64,mkexpr(s16),mkU8(32)),
1594 mkexpr(m32))
1595 )
1596 );
sewardjdc9259c2014-02-27 11:10:19 +00001597 return res;
1598}
1599
1600
1601/* Generates a 64-bit bit swap. */
1602static IRTemp math_BITSWAP64 ( IRTemp src )
1603{
1604 IRTemp m1 = newTemp(Ity_I64);
1605 IRTemp s1 = newTemp(Ity_I64);
1606 IRTemp m2 = newTemp(Ity_I64);
1607 IRTemp s2 = newTemp(Ity_I64);
1608 IRTemp m4 = newTemp(Ity_I64);
1609 IRTemp s4 = newTemp(Ity_I64);
1610 assign( m1, mkU64(0xAAAAAAAAAAAAAAAAULL) );
1611 assign( s1,
1612 binop(Iop_Or64,
1613 binop(Iop_Shr64,
1614 binop(Iop_And64,mkexpr(src),mkexpr(m1)),
1615 mkU8(1)),
1616 binop(Iop_And64,
1617 binop(Iop_Shl64,mkexpr(src),mkU8(1)),
1618 mkexpr(m1))
1619 )
1620 );
1621
1622 assign( m2, mkU64(0xCCCCCCCCCCCCCCCCULL) );
1623 assign( s2,
1624 binop(Iop_Or64,
1625 binop(Iop_Shr64,
1626 binop(Iop_And64,mkexpr(s1),mkexpr(m2)),
1627 mkU8(2)),
1628 binop(Iop_And64,
1629 binop(Iop_Shl64,mkexpr(s1),mkU8(2)),
1630 mkexpr(m2))
1631 )
1632 );
1633
1634 assign( m4, mkU64(0xF0F0F0F0F0F0F0F0ULL) );
1635 assign( s4,
1636 binop(Iop_Or64,
1637 binop(Iop_Shr64,
1638 binop(Iop_And64,mkexpr(s2),mkexpr(m4)),
1639 mkU8(4)),
1640 binop(Iop_And64,
1641 binop(Iop_Shl64,mkexpr(s2),mkU8(4)),
1642 mkexpr(m4))
1643 )
1644 );
1645 return math_BYTESWAP64(s4);
sewardjbbcf1882014-01-12 12:49:10 +00001646}
1647
1648
sewardj606c4ba2014-01-26 19:11:14 +00001649/* Duplicates the bits at the bottom of the given word to fill the
1650 whole word. src :: Ity_I64 is assumed to have zeroes everywhere
1651 except for the bottom bits. */
1652static IRTemp math_DUP_TO_64 ( IRTemp src, IRType srcTy )
1653{
1654 if (srcTy == Ity_I8) {
1655 IRTemp t16 = newTemp(Ity_I64);
1656 assign(t16, binop(Iop_Or64, mkexpr(src),
1657 binop(Iop_Shl64, mkexpr(src), mkU8(8))));
1658 IRTemp t32 = newTemp(Ity_I64);
1659 assign(t32, binop(Iop_Or64, mkexpr(t16),
1660 binop(Iop_Shl64, mkexpr(t16), mkU8(16))));
1661 IRTemp t64 = newTemp(Ity_I64);
1662 assign(t64, binop(Iop_Or64, mkexpr(t32),
1663 binop(Iop_Shl64, mkexpr(t32), mkU8(32))));
1664 return t64;
1665 }
1666 if (srcTy == Ity_I16) {
1667 IRTemp t32 = newTemp(Ity_I64);
1668 assign(t32, binop(Iop_Or64, mkexpr(src),
1669 binop(Iop_Shl64, mkexpr(src), 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_I32) {
1676 IRTemp t64 = newTemp(Ity_I64);
1677 assign(t64, binop(Iop_Or64, mkexpr(src),
1678 binop(Iop_Shl64, mkexpr(src), mkU8(32))));
1679 return t64;
1680 }
1681 if (srcTy == Ity_I64) {
1682 return src;
1683 }
1684 vassert(0);
1685}
1686
1687
sewardjbbcf1882014-01-12 12:49:10 +00001688/*------------------------------------------------------------*/
1689/*--- FP comparison helpers ---*/
1690/*------------------------------------------------------------*/
1691
1692/* irRes :: Ity_I32 holds a floating point comparison result encoded
1693 as an IRCmpF64Result. Generate code to convert it to an
1694 ARM64-encoded (N,Z,C,V) group in the lowest 4 bits of an I64 value.
1695 Assign a new temp to hold that value, and return the temp. */
1696static
1697IRTemp mk_convert_IRCmpF64Result_to_NZCV ( IRTemp irRes32 )
1698{
1699 IRTemp ix = newTemp(Ity_I64);
1700 IRTemp termL = newTemp(Ity_I64);
1701 IRTemp termR = newTemp(Ity_I64);
1702 IRTemp nzcv = newTemp(Ity_I64);
1703 IRTemp irRes = newTemp(Ity_I64);
1704
1705 /* This is where the fun starts. We have to convert 'irRes' from
1706 an IR-convention return result (IRCmpF64Result) to an
1707 ARM-encoded (N,Z,C,V) group. The final result is in the bottom
1708 4 bits of 'nzcv'. */
1709 /* Map compare result from IR to ARM(nzcv) */
1710 /*
1711 FP cmp result | IR | ARM(nzcv)
1712 --------------------------------
1713 UN 0x45 0011
1714 LT 0x01 1000
1715 GT 0x00 0010
1716 EQ 0x40 0110
1717 */
1718 /* Now since you're probably wondering WTF ..
1719
1720 ix fishes the useful bits out of the IR value, bits 6 and 0, and
1721 places them side by side, giving a number which is 0, 1, 2 or 3.
1722
1723 termL is a sequence cooked up by GNU superopt. It converts ix
1724 into an almost correct value NZCV value (incredibly), except
1725 for the case of UN, where it produces 0100 instead of the
1726 required 0011.
1727
1728 termR is therefore a correction term, also computed from ix. It
1729 is 1 in the UN case and 0 for LT, GT and UN. Hence, to get
1730 the final correct value, we subtract termR from termL.
1731
1732 Don't take my word for it. There's a test program at the bottom
1733 of guest_arm_toIR.c, to try this out with.
1734 */
1735 assign(irRes, unop(Iop_32Uto64, mkexpr(irRes32)));
1736
1737 assign(
1738 ix,
1739 binop(Iop_Or64,
1740 binop(Iop_And64,
1741 binop(Iop_Shr64, mkexpr(irRes), mkU8(5)),
1742 mkU64(3)),
1743 binop(Iop_And64, mkexpr(irRes), mkU64(1))));
1744
1745 assign(
1746 termL,
1747 binop(Iop_Add64,
1748 binop(Iop_Shr64,
1749 binop(Iop_Sub64,
1750 binop(Iop_Shl64,
1751 binop(Iop_Xor64, mkexpr(ix), mkU64(1)),
1752 mkU8(62)),
1753 mkU64(1)),
1754 mkU8(61)),
1755 mkU64(1)));
1756
1757 assign(
1758 termR,
1759 binop(Iop_And64,
1760 binop(Iop_And64,
1761 mkexpr(ix),
1762 binop(Iop_Shr64, mkexpr(ix), mkU8(1))),
1763 mkU64(1)));
1764
1765 assign(nzcv, binop(Iop_Sub64, mkexpr(termL), mkexpr(termR)));
1766 return nzcv;
1767}
1768
1769
1770/*------------------------------------------------------------*/
1771/*--- Data processing (immediate) ---*/
1772/*------------------------------------------------------------*/
1773
1774/* Helper functions for supporting "DecodeBitMasks" */
1775
1776static ULong dbm_ROR ( Int width, ULong x, Int rot )
1777{
1778 vassert(width > 0 && width <= 64);
1779 vassert(rot >= 0 && rot < width);
1780 if (rot == 0) return x;
1781 ULong res = x >> rot;
1782 res |= (x << (width - rot));
1783 if (width < 64)
1784 res &= ((1ULL << width) - 1);
1785 return res;
1786}
1787
1788static ULong dbm_RepTo64( Int esize, ULong x )
1789{
1790 switch (esize) {
1791 case 64:
1792 return x;
1793 case 32:
1794 x &= 0xFFFFFFFF; x |= (x << 32);
1795 return x;
1796 case 16:
1797 x &= 0xFFFF; x |= (x << 16); x |= (x << 32);
1798 return x;
1799 case 8:
1800 x &= 0xFF; x |= (x << 8); x |= (x << 16); x |= (x << 32);
1801 return x;
1802 case 4:
1803 x &= 0xF; x |= (x << 4); x |= (x << 8);
1804 x |= (x << 16); x |= (x << 32);
1805 return x;
1806 case 2:
1807 x &= 0x3; x |= (x << 2); x |= (x << 4); x |= (x << 8);
1808 x |= (x << 16); x |= (x << 32);
1809 return x;
1810 default:
1811 break;
1812 }
1813 vpanic("dbm_RepTo64");
1814 /*NOTREACHED*/
1815 return 0;
1816}
1817
1818static Int dbm_highestSetBit ( ULong x )
1819{
1820 Int i;
1821 for (i = 63; i >= 0; i--) {
1822 if (x & (1ULL << i))
1823 return i;
1824 }
1825 vassert(x == 0);
1826 return -1;
1827}
1828
1829static
1830Bool dbm_DecodeBitMasks ( /*OUT*/ULong* wmask, /*OUT*/ULong* tmask,
1831 ULong immN, ULong imms, ULong immr, Bool immediate,
1832 UInt M /*32 or 64*/)
1833{
1834 vassert(immN < (1ULL << 1));
1835 vassert(imms < (1ULL << 6));
1836 vassert(immr < (1ULL << 6));
1837 vassert(immediate == False || immediate == True);
1838 vassert(M == 32 || M == 64);
1839
1840 Int len = dbm_highestSetBit( ((immN << 6) & 64) | ((~imms) & 63) );
1841 if (len < 1) { /* printf("fail1\n"); */ return False; }
1842 vassert(len <= 6);
1843 vassert(M >= (1 << len));
1844
1845 vassert(len >= 1 && len <= 6);
1846 ULong levels = // (zeroes(6 - len) << (6-len)) | ones(len);
1847 (1 << len) - 1;
1848 vassert(levels >= 1 && levels <= 63);
1849
1850 if (immediate && ((imms & levels) == levels)) {
1851 /* printf("fail2 imms %llu levels %llu len %d\n", imms, levels, len); */
1852 return False;
1853 }
1854
1855 ULong S = imms & levels;
1856 ULong R = immr & levels;
1857 Int diff = S - R;
1858 diff &= 63;
1859 Int esize = 1 << len;
1860 vassert(2 <= esize && esize <= 64);
1861
1862 /* Be careful of these (1ULL << (S+1)) - 1 expressions, and the
1863 same below with d. S can be 63 in which case we have an out of
1864 range and hence undefined shift. */
1865 vassert(S >= 0 && S <= 63);
1866 vassert(esize >= (S+1));
1867 ULong elem_s = // Zeroes(esize-(S+1)):Ones(S+1)
1868 //(1ULL << (S+1)) - 1;
1869 ((1ULL << S) - 1) + (1ULL << S);
1870
1871 Int d = // diff<len-1:0>
1872 diff & ((1 << len)-1);
1873 vassert(esize >= (d+1));
1874 vassert(d >= 0 && d <= 63);
1875
1876 ULong elem_d = // Zeroes(esize-(d+1)):Ones(d+1)
1877 //(1ULL << (d+1)) - 1;
1878 ((1ULL << d) - 1) + (1ULL << d);
1879
1880 if (esize != 64) vassert(elem_s < (1ULL << esize));
1881 if (esize != 64) vassert(elem_d < (1ULL << esize));
1882
1883 if (wmask) *wmask = dbm_RepTo64(esize, dbm_ROR(esize, elem_s, R));
1884 if (tmask) *tmask = dbm_RepTo64(esize, elem_d);
1885
1886 return True;
1887}
1888
1889
1890static
1891Bool dis_ARM64_data_processing_immediate(/*MB_OUT*/DisResult* dres,
1892 UInt insn)
1893{
1894# define INSN(_bMax,_bMin) SLICE_UInt(insn, (_bMax), (_bMin))
1895
1896 /* insn[28:23]
1897 10000x PC-rel addressing
1898 10001x Add/subtract (immediate)
1899 100100 Logical (immediate)
1900 100101 Move Wide (immediate)
1901 100110 Bitfield
1902 100111 Extract
1903 */
1904
1905 /* ------------------ ADD/SUB{,S} imm12 ------------------ */
1906 if (INSN(28,24) == BITS5(1,0,0,0,1)) {
1907 Bool is64 = INSN(31,31) == 1;
1908 Bool isSub = INSN(30,30) == 1;
1909 Bool setCC = INSN(29,29) == 1;
1910 UInt sh = INSN(23,22);
1911 UInt uimm12 = INSN(21,10);
1912 UInt nn = INSN(9,5);
1913 UInt dd = INSN(4,0);
1914 const HChar* nm = isSub ? "sub" : "add";
1915 if (sh >= 2) {
1916 /* Invalid; fall through */
1917 } else {
1918 vassert(sh <= 1);
1919 uimm12 <<= (12 * sh);
1920 if (is64) {
1921 IRTemp argL = newTemp(Ity_I64);
1922 IRTemp argR = newTemp(Ity_I64);
1923 IRTemp res = newTemp(Ity_I64);
1924 assign(argL, getIReg64orSP(nn));
1925 assign(argR, mkU64(uimm12));
1926 assign(res, binop(isSub ? Iop_Sub64 : Iop_Add64,
1927 mkexpr(argL), mkexpr(argR)));
1928 if (setCC) {
1929 putIReg64orZR(dd, mkexpr(res));
1930 setFlags_ADD_SUB(True/*is64*/, isSub, argL, argR);
1931 DIP("%ss %s, %s, 0x%x\n",
1932 nm, nameIReg64orZR(dd), nameIReg64orSP(nn), uimm12);
1933 } else {
1934 putIReg64orSP(dd, mkexpr(res));
1935 DIP("%s %s, %s, 0x%x\n",
1936 nm, nameIReg64orSP(dd), nameIReg64orSP(nn), uimm12);
1937 }
1938 } else {
1939 IRTemp argL = newTemp(Ity_I32);
1940 IRTemp argR = newTemp(Ity_I32);
1941 IRTemp res = newTemp(Ity_I32);
1942 assign(argL, getIReg32orSP(nn));
1943 assign(argR, mkU32(uimm12));
1944 assign(res, binop(isSub ? Iop_Sub32 : Iop_Add32,
1945 mkexpr(argL), mkexpr(argR)));
1946 if (setCC) {
1947 putIReg32orZR(dd, mkexpr(res));
1948 setFlags_ADD_SUB(False/*!is64*/, isSub, argL, argR);
1949 DIP("%ss %s, %s, 0x%x\n",
1950 nm, nameIReg32orZR(dd), nameIReg32orSP(nn), uimm12);
1951 } else {
1952 putIReg32orSP(dd, mkexpr(res));
1953 DIP("%s %s, %s, 0x%x\n",
1954 nm, nameIReg32orSP(dd), nameIReg32orSP(nn), uimm12);
1955 }
1956 }
1957 return True;
1958 }
1959 }
1960
1961 /* -------------------- ADR/ADRP -------------------- */
1962 if (INSN(28,24) == BITS5(1,0,0,0,0)) {
1963 UInt bP = INSN(31,31);
1964 UInt immLo = INSN(30,29);
1965 UInt immHi = INSN(23,5);
1966 UInt rD = INSN(4,0);
1967 ULong uimm = (immHi << 2) | immLo;
1968 ULong simm = sx_to_64(uimm, 21);
1969 ULong val;
1970 if (bP) {
1971 val = (guest_PC_curr_instr & 0xFFFFFFFFFFFFF000ULL) + (simm << 12);
1972 } else {
1973 val = guest_PC_curr_instr + simm;
1974 }
1975 putIReg64orZR(rD, mkU64(val));
1976 DIP("adr%s %s, 0x%llx\n", bP ? "p" : "", nameIReg64orZR(rD), val);
1977 return True;
1978 }
1979
1980 /* -------------------- LOGIC(imm) -------------------- */
1981 if (INSN(28,23) == BITS6(1,0,0,1,0,0)) {
1982 /* 31 30 28 22 21 15 9 4
1983 sf op 100100 N immr imms Rn Rd
1984 op=00: AND Rd|SP, Rn, #imm
1985 op=01: ORR Rd|SP, Rn, #imm
1986 op=10: EOR Rd|SP, Rn, #imm
1987 op=11: ANDS Rd|ZR, Rn, #imm
1988 */
1989 Bool is64 = INSN(31,31) == 1;
1990 UInt op = INSN(30,29);
1991 UInt N = INSN(22,22);
1992 UInt immR = INSN(21,16);
1993 UInt immS = INSN(15,10);
1994 UInt nn = INSN(9,5);
1995 UInt dd = INSN(4,0);
1996 ULong imm = 0;
1997 Bool ok;
1998 if (N == 1 && !is64)
1999 goto after_logic_imm; /* not allowed; fall through */
2000 ok = dbm_DecodeBitMasks(&imm, NULL,
2001 N, immS, immR, True, is64 ? 64 : 32);
2002 if (!ok)
2003 goto after_logic_imm;
2004
2005 const HChar* names[4] = { "and", "orr", "eor", "ands" };
2006 const IROp ops64[4] = { Iop_And64, Iop_Or64, Iop_Xor64, Iop_And64 };
2007 const IROp ops32[4] = { Iop_And32, Iop_Or32, Iop_Xor32, Iop_And32 };
2008
2009 vassert(op < 4);
2010 if (is64) {
2011 IRExpr* argL = getIReg64orZR(nn);
2012 IRExpr* argR = mkU64(imm);
2013 IRTemp res = newTemp(Ity_I64);
2014 assign(res, binop(ops64[op], argL, argR));
2015 if (op < 3) {
2016 putIReg64orSP(dd, mkexpr(res));
2017 DIP("%s %s, %s, 0x%llx\n", names[op],
2018 nameIReg64orSP(dd), nameIReg64orZR(nn), imm);
2019 } else {
2020 putIReg64orZR(dd, mkexpr(res));
2021 setFlags_LOGIC(True/*is64*/, res);
2022 DIP("%s %s, %s, 0x%llx\n", names[op],
2023 nameIReg64orZR(dd), nameIReg64orZR(nn), imm);
2024 }
2025 } else {
2026 IRExpr* argL = getIReg32orZR(nn);
2027 IRExpr* argR = mkU32((UInt)imm);
2028 IRTemp res = newTemp(Ity_I32);
2029 assign(res, binop(ops32[op], argL, argR));
2030 if (op < 3) {
2031 putIReg32orSP(dd, mkexpr(res));
2032 DIP("%s %s, %s, 0x%x\n", names[op],
2033 nameIReg32orSP(dd), nameIReg32orZR(nn), (UInt)imm);
2034 } else {
2035 putIReg32orZR(dd, mkexpr(res));
2036 setFlags_LOGIC(False/*!is64*/, res);
2037 DIP("%s %s, %s, 0x%x\n", names[op],
2038 nameIReg32orZR(dd), nameIReg32orZR(nn), (UInt)imm);
2039 }
2040 }
2041 return True;
2042 }
2043 after_logic_imm:
2044
2045 /* -------------------- MOV{Z,N,K} -------------------- */
2046 if (INSN(28,23) == BITS6(1,0,0,1,0,1)) {
2047 /* 31 30 28 22 20 4
2048 | | | | | |
2049 sf 10 100 101 hw imm16 Rd MOV(Z) Rd, (imm16 << (16*hw))
2050 sf 00 100 101 hw imm16 Rd MOV(N) Rd, ~(imm16 << (16*hw))
2051 sf 11 100 101 hw imm16 Rd MOV(K) Rd, (imm16 << (16*hw))
2052 */
2053 Bool is64 = INSN(31,31) == 1;
2054 UInt subopc = INSN(30,29);
2055 UInt hw = INSN(22,21);
2056 UInt imm16 = INSN(20,5);
2057 UInt dd = INSN(4,0);
2058 if (subopc == BITS2(0,1) || (!is64 && hw >= 2)) {
2059 /* invalid; fall through */
2060 } else {
2061 ULong imm64 = ((ULong)imm16) << (16 * hw);
2062 if (!is64)
2063 vassert(imm64 < 0x100000000ULL);
2064 switch (subopc) {
2065 case BITS2(1,0): // MOVZ
2066 putIRegOrZR(is64, dd, is64 ? mkU64(imm64) : mkU32((UInt)imm64));
2067 DIP("movz %s, 0x%llx\n", nameIRegOrZR(is64, dd), imm64);
2068 break;
2069 case BITS2(0,0): // MOVN
2070 imm64 = ~imm64;
2071 if (!is64)
2072 imm64 &= 0xFFFFFFFFULL;
2073 putIRegOrZR(is64, dd, is64 ? mkU64(imm64) : mkU32((UInt)imm64));
2074 DIP("movn %s, 0x%llx\n", nameIRegOrZR(is64, dd), imm64);
2075 break;
2076 case BITS2(1,1): // MOVK
2077 /* This is more complex. We are inserting a slice into
2078 the destination register, so we need to have the old
2079 value of it. */
2080 if (is64) {
2081 IRTemp old = newTemp(Ity_I64);
2082 assign(old, getIReg64orZR(dd));
2083 ULong mask = 0xFFFFULL << (16 * hw);
2084 IRExpr* res
2085 = binop(Iop_Or64,
2086 binop(Iop_And64, mkexpr(old), mkU64(~mask)),
2087 mkU64(imm64));
2088 putIReg64orZR(dd, res);
2089 DIP("movk %s, 0x%x, lsl %u\n",
2090 nameIReg64orZR(dd), imm16, 16*hw);
2091 } else {
2092 IRTemp old = newTemp(Ity_I32);
2093 assign(old, getIReg32orZR(dd));
2094 vassert(hw <= 1);
2095 UInt mask = 0xFFFF << (16 * hw);
2096 IRExpr* res
2097 = binop(Iop_Or32,
2098 binop(Iop_And32, mkexpr(old), mkU32(~mask)),
2099 mkU32((UInt)imm64));
2100 putIReg32orZR(dd, res);
2101 DIP("movk %s, 0x%x, lsl %u\n",
2102 nameIReg32orZR(dd), imm16, 16*hw);
2103 }
2104 break;
2105 default:
2106 vassert(0);
2107 }
2108 return True;
2109 }
2110 }
2111
2112 /* -------------------- {U,S,}BFM -------------------- */
2113 /* 30 28 22 21 15 9 4
2114
2115 sf 10 100110 N immr imms nn dd
2116 UBFM Wd, Wn, #immr, #imms when sf=0, N=0, immr[5]=0, imms[5]=0
2117 UBFM Xd, Xn, #immr, #imms when sf=1, N=1
2118
2119 sf 00 100110 N immr imms nn dd
2120 SBFM Wd, Wn, #immr, #imms when sf=0, N=0, immr[5]=0, imms[5]=0
2121 SBFM Xd, Xn, #immr, #imms when sf=1, N=1
2122
2123 sf 01 100110 N immr imms nn dd
2124 BFM Wd, Wn, #immr, #imms when sf=0, N=0, immr[5]=0, imms[5]=0
2125 BFM Xd, Xn, #immr, #imms when sf=1, N=1
2126 */
2127 if (INSN(28,23) == BITS6(1,0,0,1,1,0)) {
2128 UInt sf = INSN(31,31);
2129 UInt opc = INSN(30,29);
2130 UInt N = INSN(22,22);
2131 UInt immR = INSN(21,16);
2132 UInt immS = INSN(15,10);
2133 UInt nn = INSN(9,5);
2134 UInt dd = INSN(4,0);
2135 Bool inZero = False;
2136 Bool extend = False;
2137 const HChar* nm = "???";
2138 /* skip invalid combinations */
2139 switch (opc) {
2140 case BITS2(0,0):
2141 inZero = True; extend = True; nm = "sbfm"; break;
2142 case BITS2(0,1):
2143 inZero = False; extend = False; nm = "bfm"; break;
2144 case BITS2(1,0):
2145 inZero = True; extend = False; nm = "ubfm"; break;
2146 case BITS2(1,1):
2147 goto after_bfm; /* invalid */
2148 default:
2149 vassert(0);
2150 }
2151 if (sf == 1 && N != 1) goto after_bfm;
2152 if (sf == 0 && (N != 0 || ((immR >> 5) & 1) != 0
2153 || ((immS >> 5) & 1) != 0)) goto after_bfm;
2154 ULong wmask = 0, tmask = 0;
2155 Bool ok = dbm_DecodeBitMasks(&wmask, &tmask,
2156 N, immS, immR, False, sf == 1 ? 64 : 32);
2157 if (!ok) goto after_bfm; /* hmmm */
2158
2159 Bool is64 = sf == 1;
2160 IRType ty = is64 ? Ity_I64 : Ity_I32;
2161
2162 IRTemp dst = newTemp(ty);
2163 IRTemp src = newTemp(ty);
2164 IRTemp bot = newTemp(ty);
2165 IRTemp top = newTemp(ty);
2166 IRTemp res = newTemp(ty);
2167 assign(dst, inZero ? mkU(ty,0) : getIRegOrZR(is64, dd));
2168 assign(src, getIRegOrZR(is64, nn));
2169 /* perform bitfield move on low bits */
2170 assign(bot, binop(mkOR(ty),
2171 binop(mkAND(ty), mkexpr(dst), mkU(ty, ~wmask)),
2172 binop(mkAND(ty), mkexpr(mathROR(ty, src, immR)),
2173 mkU(ty, wmask))));
2174 /* determine extension bits (sign, zero or dest register) */
2175 assign(top, mkexpr(extend ? mathREPLICATE(ty, src, immS) : dst));
2176 /* combine extension bits and result bits */
2177 assign(res, binop(mkOR(ty),
2178 binop(mkAND(ty), mkexpr(top), mkU(ty, ~tmask)),
2179 binop(mkAND(ty), mkexpr(bot), mkU(ty, tmask))));
2180 putIRegOrZR(is64, dd, mkexpr(res));
2181 DIP("%s %s, %s, immR=%u, immS=%u\n",
2182 nm, nameIRegOrZR(is64, dd), nameIRegOrZR(is64, nn), immR, immS);
2183 return True;
2184 }
2185 after_bfm:
2186
2187 /* ---------------------- EXTR ---------------------- */
2188 /* 30 28 22 20 15 9 4
2189 1 00 100111 10 m imm6 n d EXTR Xd, Xn, Xm, #imm6
2190 0 00 100111 00 m imm6 n d EXTR Wd, Wn, Wm, #imm6 when #imm6 < 32
2191 */
2192 if (INSN(30,23) == BITS8(0,0,1,0,0,1,1,1) && INSN(21,21) == 0) {
2193 Bool is64 = INSN(31,31) == 1;
2194 UInt mm = INSN(20,16);
2195 UInt imm6 = INSN(15,10);
2196 UInt nn = INSN(9,5);
2197 UInt dd = INSN(4,0);
2198 Bool valid = True;
2199 if (INSN(31,31) != INSN(22,22))
2200 valid = False;
2201 if (!is64 && imm6 >= 32)
2202 valid = False;
2203 if (!valid) goto after_extr;
2204 IRType ty = is64 ? Ity_I64 : Ity_I32;
2205 IRTemp srcHi = newTemp(ty);
2206 IRTemp srcLo = newTemp(ty);
2207 IRTemp res = newTemp(ty);
2208 assign(srcHi, getIRegOrZR(is64, nn));
2209 assign(srcLo, getIRegOrZR(is64, mm));
2210 if (imm6 == 0) {
2211 assign(res, mkexpr(srcLo));
2212 } else {
2213 UInt szBits = 8 * sizeofIRType(ty);
2214 vassert(imm6 > 0 && imm6 < szBits);
2215 assign(res, binop(mkOR(ty),
2216 binop(mkSHL(ty), mkexpr(srcHi), mkU8(szBits-imm6)),
2217 binop(mkSHR(ty), mkexpr(srcLo), mkU8(imm6))));
2218 }
2219 putIRegOrZR(is64, dd, mkexpr(res));
2220 DIP("extr %s, %s, %s, #%u\n",
2221 nameIRegOrZR(is64,dd),
2222 nameIRegOrZR(is64,nn), nameIRegOrZR(is64,mm), imm6);
2223 return True;
2224 }
2225 after_extr:
2226
2227 vex_printf("ARM64 front end: data_processing_immediate\n");
2228 return False;
2229# undef INSN
2230}
2231
2232
2233/*------------------------------------------------------------*/
2234/*--- Data processing (register) instructions ---*/
2235/*------------------------------------------------------------*/
2236
2237static const HChar* nameSH ( UInt sh ) {
2238 switch (sh) {
2239 case 0: return "lsl";
2240 case 1: return "lsr";
2241 case 2: return "asr";
2242 case 3: return "ror";
2243 default: vassert(0);
2244 }
2245}
2246
2247/* Generate IR to get a register value, possibly shifted by an
2248 immediate. Returns either a 32- or 64-bit temporary holding the
2249 result. After the shift, the value can optionally be NOT-ed
2250 too.
2251
2252 sh_how coding: 00=SHL, 01=SHR, 10=SAR, 11=ROR. sh_amt may only be
2253 in the range 0 to (is64 ? 64 : 32)-1. For some instructions, ROR
2254 isn't allowed, but it's the job of the caller to check that.
2255*/
2256static IRTemp getShiftedIRegOrZR ( Bool is64,
2257 UInt sh_how, UInt sh_amt, UInt regNo,
2258 Bool invert )
2259{
2260 vassert(sh_how < 4);
2261 vassert(sh_amt < (is64 ? 64 : 32));
2262 IRType ty = is64 ? Ity_I64 : Ity_I32;
2263 IRTemp t0 = newTemp(ty);
2264 assign(t0, getIRegOrZR(is64, regNo));
2265 IRTemp t1 = newTemp(ty);
2266 switch (sh_how) {
2267 case BITS2(0,0):
2268 assign(t1, binop(mkSHL(ty), mkexpr(t0), mkU8(sh_amt)));
2269 break;
2270 case BITS2(0,1):
2271 assign(t1, binop(mkSHR(ty), mkexpr(t0), mkU8(sh_amt)));
2272 break;
2273 case BITS2(1,0):
2274 assign(t1, binop(mkSAR(ty), mkexpr(t0), mkU8(sh_amt)));
2275 break;
2276 case BITS2(1,1):
2277 assign(t1, mkexpr(mathROR(ty, t0, sh_amt)));
2278 break;
2279 default:
2280 vassert(0);
2281 }
2282 if (invert) {
2283 IRTemp t2 = newTemp(ty);
2284 assign(t2, unop(mkNOT(ty), mkexpr(t1)));
2285 return t2;
2286 } else {
2287 return t1;
2288 }
2289}
2290
2291
2292static
2293Bool dis_ARM64_data_processing_register(/*MB_OUT*/DisResult* dres,
2294 UInt insn)
2295{
2296# define INSN(_bMax,_bMin) SLICE_UInt(insn, (_bMax), (_bMin))
2297
2298 /* ------------------- ADD/SUB(reg) ------------------- */
2299 /* x==0 => 32 bit op x==1 => 64 bit op
2300 sh: 00=LSL, 01=LSR, 10=ASR, 11=ROR(NOT ALLOWED)
2301
2302 31 30 29 28 23 21 20 15 9 4
2303 | | | | | | | | | |
2304 x 0 0 01011 sh 0 Rm imm6 Rn Rd ADD Rd,Rn, sh(Rm,imm6)
2305 x 0 1 01011 sh 0 Rm imm6 Rn Rd ADDS Rd,Rn, sh(Rm,imm6)
2306 x 1 0 01011 sh 0 Rm imm6 Rn Rd SUB Rd,Rn, sh(Rm,imm6)
2307 x 1 1 01011 sh 0 Rm imm6 Rn Rd SUBS Rd,Rn, sh(Rm,imm6)
2308 */
2309 if (INSN(28,24) == BITS5(0,1,0,1,1) && INSN(21,21) == 0) {
2310 UInt bX = INSN(31,31);
2311 UInt bOP = INSN(30,30); /* 0: ADD, 1: SUB */
2312 UInt bS = INSN(29, 29); /* set flags? */
2313 UInt sh = INSN(23,22);
2314 UInt rM = INSN(20,16);
2315 UInt imm6 = INSN(15,10);
2316 UInt rN = INSN(9,5);
2317 UInt rD = INSN(4,0);
2318 Bool isSUB = bOP == 1;
2319 Bool is64 = bX == 1;
2320 IRType ty = is64 ? Ity_I64 : Ity_I32;
2321 if ((!is64 && imm6 > 31) || sh == BITS2(1,1)) {
2322 /* invalid; fall through */
2323 } else {
2324 IRTemp argL = newTemp(ty);
2325 assign(argL, getIRegOrZR(is64, rN));
2326 IRTemp argR = getShiftedIRegOrZR(is64, sh, imm6, rM, False);
2327 IROp op = isSUB ? mkSUB(ty) : mkADD(ty);
2328 IRTemp res = newTemp(ty);
2329 assign(res, binop(op, mkexpr(argL), mkexpr(argR)));
2330 if (rD != 31) putIRegOrZR(is64, rD, mkexpr(res));
2331 if (bS) {
2332 setFlags_ADD_SUB(is64, isSUB, argL, argR);
2333 }
2334 DIP("%s%s %s, %s, %s, %s #%u\n",
2335 bOP ? "sub" : "add", bS ? "s" : "",
2336 nameIRegOrZR(is64, rD), nameIRegOrZR(is64, rN),
2337 nameIRegOrZR(is64, rM), nameSH(sh), imm6);
2338 return True;
2339 }
2340 }
2341
2342 /* -------------------- LOGIC(reg) -------------------- */
2343 /* x==0 => 32 bit op x==1 => 64 bit op
2344 N==0 => inv? is no-op (no inversion)
2345 N==1 => inv? is NOT
2346 sh: 00=LSL, 01=LSR, 10=ASR, 11=ROR
2347
2348 31 30 28 23 21 20 15 9 4
2349 | | | | | | | | |
2350 x 00 01010 sh N Rm imm6 Rn Rd AND Rd,Rn, inv?(sh(Rm,imm6))
2351 x 01 01010 sh N Rm imm6 Rn Rd ORR Rd,Rn, inv?(sh(Rm,imm6))
2352 x 10 01010 sh N Rm imm6 Rn Rd EOR Rd,Rn, inv?(sh(Rm,imm6))
2353 x 11 01010 sh N Rm imm6 Rn Rd ANDS Rd,Rn, inv?(sh(Rm,imm6))
2354 With N=1, the names are: BIC ORN EON BICS
2355 */
2356 if (INSN(28,24) == BITS5(0,1,0,1,0)) {
2357 UInt bX = INSN(31,31);
2358 UInt sh = INSN(23,22);
2359 UInt bN = INSN(21,21);
2360 UInt rM = INSN(20,16);
2361 UInt imm6 = INSN(15,10);
2362 UInt rN = INSN(9,5);
2363 UInt rD = INSN(4,0);
2364 Bool is64 = bX == 1;
2365 IRType ty = is64 ? Ity_I64 : Ity_I32;
2366 if (!is64 && imm6 > 31) {
2367 /* invalid; fall though */
2368 } else {
2369 IRTemp argL = newTemp(ty);
2370 assign(argL, getIRegOrZR(is64, rN));
2371 IRTemp argR = getShiftedIRegOrZR(is64, sh, imm6, rM, bN == 1);
2372 IROp op = Iop_INVALID;
2373 switch (INSN(30,29)) {
2374 case BITS2(0,0): case BITS2(1,1): op = mkAND(ty); break;
2375 case BITS2(0,1): op = mkOR(ty); break;
2376 case BITS2(1,0): op = mkXOR(ty); break;
2377 default: vassert(0);
2378 }
2379 IRTemp res = newTemp(ty);
2380 assign(res, binop(op, mkexpr(argL), mkexpr(argR)));
2381 if (INSN(30,29) == BITS2(1,1)) {
2382 setFlags_LOGIC(is64, res);
2383 }
2384 putIRegOrZR(is64, rD, mkexpr(res));
2385
2386 static const HChar* names_op[8]
2387 = { "and", "orr", "eor", "ands", "bic", "orn", "eon", "bics" };
2388 vassert(((bN << 2) | INSN(30,29)) < 8);
2389 const HChar* nm_op = names_op[(bN << 2) | INSN(30,29)];
2390 /* Special-case the printing of "MOV" */
2391 if (rN == 31/*zr*/ && sh == 0/*LSL*/ && imm6 == 0 && bN == 0) {
2392 DIP("mov %s, %s\n", nameIRegOrZR(is64, rD),
2393 nameIRegOrZR(is64, rM));
2394 } else {
2395 DIP("%s %s, %s, %s, %s #%u\n", nm_op,
2396 nameIRegOrZR(is64, rD), nameIRegOrZR(is64, rN),
2397 nameIRegOrZR(is64, rM), nameSH(sh), imm6);
2398 }
2399 return True;
2400 }
2401 }
2402
2403 /* -------------------- {U,S}MULH -------------------- */
2404 /* 31 23 22 20 15 9 4
2405 10011011 1 10 Rm 011111 Rn Rd UMULH Xd,Xn,Xm
2406 10011011 0 10 Rm 011111 Rn Rd SMULH Xd,Xn,Xm
2407 */
2408 if (INSN(31,24) == BITS8(1,0,0,1,1,0,1,1)
2409 && INSN(22,21) == BITS2(1,0) && INSN(15,10) == BITS6(0,1,1,1,1,1)
2410 && INSN(23,23) == 1/*ATC*/) {
2411 Bool isU = INSN(23,23) == 1;
2412 UInt mm = INSN(20,16);
2413 UInt nn = INSN(9,5);
2414 UInt dd = INSN(4,0);
2415 putIReg64orZR(dd, unop(Iop_128HIto64,
2416 binop(isU ? Iop_MullU64 : Iop_MullS64,
2417 getIReg64orZR(nn), getIReg64orZR(mm))));
2418 DIP("%cmulh %s, %s, %s\n",
2419 isU ? 'u' : 's',
2420 nameIReg64orZR(dd), nameIReg64orZR(nn), nameIReg64orZR(mm));
2421 return True;
2422 }
2423
2424 /* -------------------- M{ADD,SUB} -------------------- */
2425 /* 31 30 20 15 14 9 4
2426 sf 00 11011 000 m 0 a n r MADD Rd,Rn,Rm,Ra d = a+m*n
2427 sf 00 11011 000 m 1 a n r MADD Rd,Rn,Rm,Ra d = a-m*n
2428 */
2429 if (INSN(30,21) == BITS10(0,0,1,1,0,1,1,0,0,0)) {
2430 Bool is64 = INSN(31,31) == 1;
2431 UInt mm = INSN(20,16);
2432 Bool isAdd = INSN(15,15) == 0;
2433 UInt aa = INSN(14,10);
2434 UInt nn = INSN(9,5);
2435 UInt dd = INSN(4,0);
2436 if (is64) {
2437 putIReg64orZR(
2438 dd,
2439 binop(isAdd ? Iop_Add64 : Iop_Sub64,
2440 getIReg64orZR(aa),
2441 binop(Iop_Mul64, getIReg64orZR(mm), getIReg64orZR(nn))));
2442 } else {
2443 putIReg32orZR(
2444 dd,
2445 binop(isAdd ? Iop_Add32 : Iop_Sub32,
2446 getIReg32orZR(aa),
2447 binop(Iop_Mul32, getIReg32orZR(mm), getIReg32orZR(nn))));
2448 }
2449 DIP("%s %s, %s, %s, %s\n",
2450 isAdd ? "madd" : "msub",
2451 nameIRegOrZR(is64, dd), nameIRegOrZR(is64, nn),
2452 nameIRegOrZR(is64, mm), nameIRegOrZR(is64, aa));
2453 return True;
2454 }
2455
2456 /* ---------------- CS{EL,INC,INV,NEG} ---------------- */
2457 /* 31 30 28 20 15 11 9 4
2458 sf 00 1101 0100 mm cond 00 nn dd CSEL Rd,Rn,Rm
2459 sf 00 1101 0100 mm cond 01 nn dd CSINC Rd,Rn,Rm
2460 sf 10 1101 0100 mm cond 00 nn dd CSINV Rd,Rn,Rm
2461 sf 10 1101 0100 mm cond 01 nn dd CSNEG Rd,Rn,Rm
2462 In all cases, the operation is: Rd = if cond then Rn else OP(Rm)
2463 */
2464 if (INSN(29,21) == BITS9(0, 1,1,0,1, 0,1,0,0) && INSN(11,11) == 0) {
2465 Bool is64 = INSN(31,31) == 1;
2466 UInt b30 = INSN(30,30);
2467 UInt mm = INSN(20,16);
2468 UInt cond = INSN(15,12);
2469 UInt b10 = INSN(10,10);
2470 UInt nn = INSN(9,5);
2471 UInt dd = INSN(4,0);
2472 UInt op = (b30 << 1) | b10; /* 00=id 01=inc 10=inv 11=neg */
2473 IRType ty = is64 ? Ity_I64 : Ity_I32;
2474 IRExpr* argL = getIRegOrZR(is64, nn);
2475 IRExpr* argR = getIRegOrZR(is64, mm);
2476 switch (op) {
2477 case BITS2(0,0):
2478 break;
2479 case BITS2(0,1):
2480 argR = binop(mkADD(ty), argR, mkU(ty,1));
2481 break;
2482 case BITS2(1,0):
2483 argR = unop(mkNOT(ty), argR);
2484 break;
2485 case BITS2(1,1):
2486 argR = binop(mkSUB(ty), mkU(ty,0), argR);
2487 break;
2488 default:
2489 vassert(0);
2490 }
2491 putIRegOrZR(
2492 is64, dd,
2493 IRExpr_ITE(unop(Iop_64to1, mk_arm64g_calculate_condition(cond)),
2494 argL, argR)
2495 );
2496 const HChar* op_nm[4] = { "csel", "csinc", "csinv", "csneg" };
2497 DIP("%s %s, %s, %s, %s\n", op_nm[op],
2498 nameIRegOrZR(is64, dd), nameIRegOrZR(is64, nn),
2499 nameIRegOrZR(is64, mm), nameCC(cond));
2500 return True;
2501 }
2502
2503 /* -------------- ADD/SUB(extended reg) -------------- */
2504 /* 28 20 15 12 9 4
2505 000 01011 00 1 m opt imm3 n d ADD Wd|SP, Wn|SP, Wm ext&lsld
2506 100 01011 00 1 m opt imm3 n d ADD Xd|SP, Xn|SP, Rm ext&lsld
2507
2508 001 01011 00 1 m opt imm3 n d ADDS Wd, Wn|SP, Wm ext&lsld
2509 101 01011 00 1 m opt imm3 n d ADDS Xd, Xn|SP, Rm ext&lsld
2510
2511 010 01011 00 1 m opt imm3 n d SUB Wd|SP, Wn|SP, Wm ext&lsld
2512 110 01011 00 1 m opt imm3 n d SUB Xd|SP, Xn|SP, Rm ext&lsld
2513
2514 011 01011 00 1 m opt imm3 n d SUBS Wd, Wn|SP, Wm ext&lsld
2515 111 01011 00 1 m opt imm3 n d SUBS Xd, Xn|SP, Rm ext&lsld
2516
2517 The 'm' operand is extended per opt, thusly:
2518
2519 000 Xm & 0xFF UXTB
2520 001 Xm & 0xFFFF UXTH
2521 010 Xm & (2^32)-1 UXTW
2522 011 Xm UXTX
2523
2524 100 Xm sx from bit 7 SXTB
2525 101 Xm sx from bit 15 SXTH
2526 110 Xm sx from bit 31 SXTW
2527 111 Xm SXTX
2528
2529 In the 64 bit case (bit31 == 1), UXTX and SXTX are the identity
2530 operation on Xm. In the 32 bit case, UXTW, UXTX, SXTW and SXTX
2531 are the identity operation on Wm.
2532
2533 After extension, the value is shifted left by imm3 bits, which
2534 may only be in the range 0 .. 4 inclusive.
2535 */
2536 if (INSN(28,21) == BITS8(0,1,0,1,1,0,0,1) && INSN(12,10) <= 4) {
2537 Bool is64 = INSN(31,31) == 1;
2538 Bool isSub = INSN(30,30) == 1;
2539 Bool setCC = INSN(29,29) == 1;
2540 UInt mm = INSN(20,16);
2541 UInt opt = INSN(15,13);
2542 UInt imm3 = INSN(12,10);
2543 UInt nn = INSN(9,5);
2544 UInt dd = INSN(4,0);
2545 const HChar* nameExt[8] = { "uxtb", "uxth", "uxtw", "uxtx",
2546 "sxtb", "sxth", "sxtw", "sxtx" };
2547 /* Do almost the same thing in the 32- and 64-bit cases. */
2548 IRTemp xN = newTemp(Ity_I64);
2549 IRTemp xM = newTemp(Ity_I64);
2550 assign(xN, getIReg64orSP(nn));
2551 assign(xM, getIReg64orZR(mm));
2552 IRExpr* xMw = mkexpr(xM); /* "xM widened" */
2553 Int shSX = 0;
2554 /* widen Xm .. */
2555 switch (opt) {
2556 case BITS3(0,0,0): // UXTB
2557 xMw = binop(Iop_And64, xMw, mkU64(0xFF)); break;
2558 case BITS3(0,0,1): // UXTH
2559 xMw = binop(Iop_And64, xMw, mkU64(0xFFFF)); break;
2560 case BITS3(0,1,0): // UXTW -- noop for the 32bit case
2561 if (is64) {
2562 xMw = unop(Iop_32Uto64, unop(Iop_64to32, xMw));
2563 }
2564 break;
2565 case BITS3(0,1,1): // UXTX -- always a noop
2566 break;
2567 case BITS3(1,0,0): // SXTB
2568 shSX = 56; goto sxTo64;
2569 case BITS3(1,0,1): // SXTH
2570 shSX = 48; goto sxTo64;
2571 case BITS3(1,1,0): // SXTW -- noop for the 32bit case
2572 if (is64) {
2573 shSX = 32; goto sxTo64;
2574 }
2575 break;
2576 case BITS3(1,1,1): // SXTX -- always a noop
2577 break;
2578 sxTo64:
2579 vassert(shSX >= 32);
2580 xMw = binop(Iop_Sar64, binop(Iop_Shl64, xMw, mkU8(shSX)),
2581 mkU8(shSX));
2582 break;
2583 default:
2584 vassert(0);
2585 }
2586 /* and now shift */
2587 IRTemp argL = xN;
2588 IRTemp argR = newTemp(Ity_I64);
2589 assign(argR, binop(Iop_Shl64, xMw, mkU8(imm3)));
2590 IRTemp res = newTemp(Ity_I64);
2591 assign(res, binop(isSub ? Iop_Sub64 : Iop_Add64,
2592 mkexpr(argL), mkexpr(argR)));
2593 if (is64) {
2594 if (setCC) {
2595 putIReg64orZR(dd, mkexpr(res));
2596 setFlags_ADD_SUB(True/*is64*/, isSub, argL, argR);
2597 } else {
2598 putIReg64orSP(dd, mkexpr(res));
2599 }
2600 } else {
2601 if (setCC) {
2602 IRTemp argL32 = newTemp(Ity_I32);
2603 IRTemp argR32 = newTemp(Ity_I32);
2604 putIReg32orZR(dd, unop(Iop_64to32, mkexpr(res)));
2605 assign(argL32, unop(Iop_64to32, mkexpr(argL)));
2606 assign(argR32, unop(Iop_64to32, mkexpr(argR)));
2607 setFlags_ADD_SUB(False/*!is64*/, isSub, argL32, argR32);
2608 } else {
2609 putIReg32orSP(dd, unop(Iop_64to32, mkexpr(res)));
2610 }
2611 }
2612 DIP("%s%s %s, %s, %s %s lsl %u\n",
2613 isSub ? "sub" : "add", setCC ? "s" : "",
2614 setCC ? nameIRegOrZR(is64, dd) : nameIRegOrSP(is64, dd),
2615 nameIRegOrSP(is64, nn), nameIRegOrSP(is64, mm),
2616 nameExt[opt], imm3);
2617 return True;
2618 }
2619
2620 /* ---------------- CCMP/CCMN(imm) ---------------- */
2621 /* Bizarrely, these appear in the "data processing register"
2622 category, even though they are operations against an
2623 immediate. */
2624 /* 31 29 20 15 11 9 3
2625 sf 1 111010010 imm5 cond 10 Rn 0 nzcv CCMP Rn, #imm5, #nzcv, cond
2626 sf 0 111010010 imm5 cond 10 Rn 0 nzcv CCMN Rn, #imm5, #nzcv, cond
2627
2628 Operation is:
2629 (CCMP) flags = if cond then flags-after-sub(Rn,imm5) else nzcv
2630 (CCMN) flags = if cond then flags-after-add(Rn,imm5) else nzcv
2631 */
2632 if (INSN(29,21) == BITS9(1,1,1,0,1,0,0,1,0)
2633 && INSN(11,10) == BITS2(1,0) && INSN(4,4) == 0) {
2634 Bool is64 = INSN(31,31) == 1;
2635 Bool isSUB = INSN(30,30) == 1;
2636 UInt imm5 = INSN(20,16);
2637 UInt cond = INSN(15,12);
2638 UInt nn = INSN(9,5);
2639 UInt nzcv = INSN(3,0);
2640
2641 IRTemp condT = newTemp(Ity_I1);
2642 assign(condT, unop(Iop_64to1, mk_arm64g_calculate_condition(cond)));
2643
2644 IRType ty = is64 ? Ity_I64 : Ity_I32;
2645 IRTemp argL = newTemp(ty);
2646 IRTemp argR = newTemp(ty);
2647
2648 if (is64) {
2649 assign(argL, getIReg64orZR(nn));
2650 assign(argR, mkU64(imm5));
2651 } else {
2652 assign(argL, getIReg32orZR(nn));
2653 assign(argR, mkU32(imm5));
2654 }
2655 setFlags_ADD_SUB_conditionally(is64, isSUB, condT, argL, argR, nzcv);
2656
2657 DIP("ccm%c %s, #%u, #%u, %s\n",
2658 isSUB ? 'p' : 'n', nameIRegOrZR(is64, nn),
2659 imm5, nzcv, nameCC(cond));
2660 return True;
2661 }
2662
2663 /* ---------------- CCMP/CCMN(reg) ---------------- */
2664 /* 31 29 20 15 11 9 3
2665 sf 1 111010010 Rm cond 00 Rn 0 nzcv CCMP Rn, Rm, #nzcv, cond
2666 sf 0 111010010 Rm cond 00 Rn 0 nzcv CCMN Rn, Rm, #nzcv, cond
2667 Operation is:
2668 (CCMP) flags = if cond then flags-after-sub(Rn,Rm) else nzcv
2669 (CCMN) flags = if cond then flags-after-add(Rn,Rm) else nzcv
2670 */
2671 if (INSN(29,21) == BITS9(1,1,1,0,1,0,0,1,0)
2672 && INSN(11,10) == BITS2(0,0) && INSN(4,4) == 0) {
2673 Bool is64 = INSN(31,31) == 1;
2674 Bool isSUB = INSN(30,30) == 1;
2675 UInt mm = INSN(20,16);
2676 UInt cond = INSN(15,12);
2677 UInt nn = INSN(9,5);
2678 UInt nzcv = INSN(3,0);
2679
2680 IRTemp condT = newTemp(Ity_I1);
2681 assign(condT, unop(Iop_64to1, mk_arm64g_calculate_condition(cond)));
2682
2683 IRType ty = is64 ? Ity_I64 : Ity_I32;
2684 IRTemp argL = newTemp(ty);
2685 IRTemp argR = newTemp(ty);
2686
2687 if (is64) {
2688 assign(argL, getIReg64orZR(nn));
2689 assign(argR, getIReg64orZR(mm));
2690 } else {
2691 assign(argL, getIReg32orZR(nn));
2692 assign(argR, getIReg32orZR(mm));
2693 }
2694 setFlags_ADD_SUB_conditionally(is64, isSUB, condT, argL, argR, nzcv);
2695
2696 DIP("ccm%c %s, %s, #%u, %s\n",
2697 isSUB ? 'p' : 'n', nameIRegOrZR(is64, nn),
2698 nameIRegOrZR(is64, mm), nzcv, nameCC(cond));
2699 return True;
2700 }
2701
2702
2703 /* -------------- REV/REV16/REV32/RBIT -------------- */
2704 /* 31 30 28 20 15 11 9 4
2705
sewardjdc9259c2014-02-27 11:10:19 +00002706 1 10 11010110 00000 0000 11 n d (1) REV Xd, Xn
2707 0 10 11010110 00000 0000 10 n d (2) REV Wd, Wn
sewardjbbcf1882014-01-12 12:49:10 +00002708
sewardjdc9259c2014-02-27 11:10:19 +00002709 1 10 11010110 00000 0000 00 n d (3) RBIT Xd, Xn
2710 0 10 11010110 00000 0000 00 n d (4) RBIT Wd, Wn
sewardjbbcf1882014-01-12 12:49:10 +00002711
sewardjdc9259c2014-02-27 11:10:19 +00002712 1 10 11010110 00000 0000 01 n d (5) REV16 Xd, Xn
2713 0 10 11010110 00000 0000 01 n d (6) REV16 Wd, Wn
sewardjbbcf1882014-01-12 12:49:10 +00002714
sewardjdc9259c2014-02-27 11:10:19 +00002715 1 10 11010110 00000 0000 10 n d (7) REV32 Xd, Xn
2716
sewardjbbcf1882014-01-12 12:49:10 +00002717 */
sewardjdc9259c2014-02-27 11:10:19 +00002718 /* Only REV and RBIT are currently implemented. */
sewardjbbcf1882014-01-12 12:49:10 +00002719 if (INSN(30,21) == BITS10(1,0,1,1,0,1,0,1,1,0)
sewardjdc9259c2014-02-27 11:10:19 +00002720 && INSN(20,12) == BITS9(0,0,0,0,0,0,0,0,0)) {
2721 UInt b31 = INSN(31,31);
2722 UInt opc = INSN(11,10);
2723
2724 UInt ix = 0;
2725 /**/ if (b31 == 1 && opc == BITS2(1,1)) ix = 1;
2726 else if (b31 == 0 && opc == BITS2(1,0)) ix = 2;
2727 else if (b31 == 1 && opc == BITS2(0,0)) ix = 3;
2728 else if (b31 == 0 && opc == BITS2(0,0)) ix = 4;
2729 else if (b31 == 1 && opc == BITS2(0,1)) ix = 5;
2730 else if (b31 == 0 && opc == BITS2(0,1)) ix = 6;
2731 else if (b31 == 1 && opc == BITS2(1,0)) ix = 7;
2732 if (ix >= 1 && ix <= 4) {
2733 Bool is64 = ix == 1 || ix == 3;
2734 Bool isBIT = ix == 3 || ix == 4;
2735 UInt nn = INSN(9,5);
2736 UInt dd = INSN(4,0);
2737 IRTemp src = newTemp(Ity_I64);
2738 IRTemp dst = IRTemp_INVALID;
2739 if (is64) {
2740 assign(src, getIReg64orZR(nn));
2741 dst = isBIT ? math_BITSWAP64(src) : math_BYTESWAP64(src);
2742 putIReg64orZR(dd, mkexpr(dst));
2743 } else {
2744 assign(src, binop(Iop_Shl64, getIReg64orZR(nn), mkU8(32)));
2745 dst = isBIT ? math_BITSWAP64(src) : math_BYTESWAP64(src);
2746 putIReg32orZR(dd, unop(Iop_64to32, mkexpr(dst)));
2747 }
2748 DIP("%s %s, %s\n", isBIT ? "rbit" : "rev",
2749 nameIRegOrZR(is64,dd), nameIRegOrZR(is64,nn));
2750 return True;
sewardjbbcf1882014-01-12 12:49:10 +00002751 }
sewardjdc9259c2014-02-27 11:10:19 +00002752 /* else fall through */
sewardjbbcf1882014-01-12 12:49:10 +00002753 }
2754
2755 /* -------------------- CLZ/CLS -------------------- */
2756 /* 30 28 24 20 15 9 4
2757 sf 10 1101 0110 00000 00010 0 n d CLZ Rd, Rn
2758 sf 10 1101 0110 00000 00010 1 n d CLS Rd, Rn
2759 */
2760 if (INSN(30,21) == BITS10(1,0,1,1,0,1,0,1,1,0)
2761 && INSN(20,11) == BITS10(0,0,0,0,0,0,0,0,1,0)) {
2762 Bool is64 = INSN(31,31) == 1;
2763 Bool isCLS = INSN(10,10) == 1;
2764 UInt nn = INSN(9,5);
2765 UInt dd = INSN(4,0);
2766 IRTemp src = newTemp(Ity_I64);
2767 IRTemp dst = newTemp(Ity_I64);
2768 if (!isCLS) { // CLS not yet supported
2769 if (is64) {
2770 assign(src, getIReg64orZR(nn));
2771 assign(dst, IRExpr_ITE(binop(Iop_CmpEQ64, mkexpr(src), mkU64(0)),
2772 mkU64(64),
2773 unop(Iop_Clz64, mkexpr(src))));
2774 putIReg64orZR(dd, mkexpr(dst));
2775 } else {
2776 assign(src, binop(Iop_Shl64,
2777 unop(Iop_32Uto64, getIReg32orZR(nn)), mkU8(32)));
2778 assign(dst, IRExpr_ITE(binop(Iop_CmpEQ64, mkexpr(src), mkU64(0)),
2779 mkU64(32),
2780 unop(Iop_Clz64, mkexpr(src))));
2781 putIReg32orZR(dd, unop(Iop_64to32, mkexpr(dst)));
2782 }
2783 DIP("cl%c %s, %s\n",
2784 isCLS ? 's' : 'z', nameIRegOrZR(is64, dd), nameIRegOrZR(is64, nn));
2785 return True;
2786 }
2787 }
2788
2789 /* -------------------- LSLV/LSRV/ASRV -------------------- */
2790 /* 30 28 20 15 11 9 4
2791 sf 00 1101 0110 m 0010 00 n d LSLV Rd,Rn,Rm
2792 sf 00 1101 0110 m 0010 01 n d LSRV Rd,Rn,Rm
2793 sf 00 1101 0110 m 0010 10 n d ASRV Rd,Rn,Rm
2794 */
2795 if (INSN(30,21) == BITS10(0,0,1,1,0,1,0,1,1,0)
2796 && INSN(15,12) == BITS4(0,0,1,0) && INSN(11,10) < BITS2(1,1)) {
2797 Bool is64 = INSN(31,31) == 1;
2798 UInt mm = INSN(20,16);
2799 UInt op = INSN(11,10);
2800 UInt nn = INSN(9,5);
2801 UInt dd = INSN(4,0);
2802 IRType ty = is64 ? Ity_I64 : Ity_I32;
2803 IRTemp srcL = newTemp(ty);
2804 IRTemp srcR = newTemp(Ity_I8);
2805 IRTemp res = newTemp(ty);
2806 IROp iop = Iop_INVALID;
2807 assign(srcL, getIRegOrZR(is64, nn));
2808 assign(srcR,
2809 unop(Iop_64to8,
2810 binop(Iop_And64,
2811 getIReg64orZR(mm), mkU64(is64 ? 63 : 31))));
2812 switch (op) {
2813 case BITS2(0,0): iop = mkSHL(ty); break;
2814 case BITS2(0,1): iop = mkSHR(ty); break;
2815 case BITS2(1,0): iop = mkSAR(ty); break;
2816 default: vassert(0);
2817 }
2818 assign(res, binop(iop, mkexpr(srcL), mkexpr(srcR)));
2819 putIRegOrZR(is64, dd, mkexpr(res));
2820 vassert(op < 3);
2821 const HChar* names[3] = { "lslv", "lsrv", "asrv" };
2822 DIP("%s %s, %s, %s\n",
2823 names[op], nameIRegOrZR(is64,dd),
2824 nameIRegOrZR(is64,nn), nameIRegOrZR(is64,mm));
2825 return True;
2826 }
2827
2828 /* -------------------- SDIV/UDIV -------------------- */
2829 /* 30 28 20 15 10 9 4
2830 sf 00 1101 0110 m 00001 1 n d SDIV Rd,Rn,Rm
2831 sf 00 1101 0110 m 00001 0 n d UDIV Rd,Rn,Rm
2832 */
2833 if (INSN(30,21) == BITS10(0,0,1,1,0,1,0,1,1,0)
2834 && INSN(15,11) == BITS5(0,0,0,0,1)) {
2835 Bool is64 = INSN(31,31) == 1;
2836 UInt mm = INSN(20,16);
2837 Bool isS = INSN(10,10) == 1;
2838 UInt nn = INSN(9,5);
2839 UInt dd = INSN(4,0);
2840 if (isS) {
2841 putIRegOrZR(is64, dd, binop(is64 ? Iop_DivS64 : Iop_DivS32,
2842 getIRegOrZR(is64, nn),
2843 getIRegOrZR(is64, mm)));
2844 } else {
2845 putIRegOrZR(is64, dd, binop(is64 ? Iop_DivU64 : Iop_DivU32,
2846 getIRegOrZR(is64, nn),
2847 getIRegOrZR(is64, mm)));
2848 }
2849 DIP("%cdiv %s, %s, %s\n", isS ? 's' : 'u',
2850 nameIRegOrZR(is64, dd),
2851 nameIRegOrZR(is64, nn), nameIRegOrZR(is64, mm));
2852 return True;
2853 }
2854
2855 /* ------------------ {S,U}M{ADD,SUB}L ------------------ */
2856 /* 31 23 20 15 14 9 4
2857 1001 1011 101 m 0 a n d UMADDL Xd,Wn,Wm,Xa
2858 1001 1011 001 m 0 a n d SMADDL Xd,Wn,Wm,Xa
2859 1001 1011 101 m 1 a n d UMSUBL Xd,Wn,Wm,Xa
2860 1001 1011 001 m 1 a n d SMSUBL Xd,Wn,Wm,Xa
2861 with operation
2862 Xd = Xa +/- (Wn *u/s Wm)
2863 */
2864 if (INSN(31,24) == BITS8(1,0,0,1,1,0,1,1) && INSN(22,21) == BITS2(0,1)) {
2865 Bool isU = INSN(23,23) == 1;
2866 UInt mm = INSN(20,16);
2867 Bool isAdd = INSN(15,15) == 0;
2868 UInt aa = INSN(14,10);
2869 UInt nn = INSN(9,5);
2870 UInt dd = INSN(4,0);
2871 IRTemp wN = newTemp(Ity_I32);
2872 IRTemp wM = newTemp(Ity_I32);
2873 IRTemp xA = newTemp(Ity_I64);
2874 IRTemp muld = newTemp(Ity_I64);
2875 IRTemp res = newTemp(Ity_I64);
2876 assign(wN, getIReg32orZR(nn));
2877 assign(wM, getIReg32orZR(mm));
2878 assign(xA, getIReg64orZR(aa));
2879 assign(muld, binop(isU ? Iop_MullU32 : Iop_MullS32,
2880 mkexpr(wN), mkexpr(wM)));
2881 assign(res, binop(isAdd ? Iop_Add64 : Iop_Sub64,
2882 mkexpr(xA), mkexpr(muld)));
2883 putIReg64orZR(dd, mkexpr(res));
2884 DIP("%cm%sl %s, %s, %s, %s\n", isU ? 'u' : 's', isAdd ? "add" : "sub",
2885 nameIReg64orZR(dd), nameIReg32orZR(nn),
2886 nameIReg32orZR(mm), nameIReg64orZR(aa));
2887 return True;
2888 }
2889 vex_printf("ARM64 front end: data_processing_register\n");
2890 return False;
2891# undef INSN
2892}
2893
2894
2895/*------------------------------------------------------------*/
2896/*--- Load and Store instructions ---*/
2897/*------------------------------------------------------------*/
2898
2899/* Generate the EA for a "reg + reg" style amode. This is done from
2900 parts of the insn, but for sanity checking sake it takes the whole
2901 insn. This appears to depend on insn[15:12], with opt=insn[15:13]
2902 and S=insn[12]:
2903
2904 The possible forms, along with their opt:S values, are:
2905 011:0 Xn|SP + Xm
2906 111:0 Xn|SP + Xm
2907 011:1 Xn|SP + Xm * transfer_szB
2908 111:1 Xn|SP + Xm * transfer_szB
2909 010:0 Xn|SP + 32Uto64(Wm)
2910 010:1 Xn|SP + 32Uto64(Wm) * transfer_szB
2911 110:0 Xn|SP + 32Sto64(Wm)
2912 110:1 Xn|SP + 32Sto64(Wm) * transfer_szB
2913
2914 Rm is insn[20:16]. Rn is insn[9:5]. Rt is insn[4:0]. Log2 of
2915 the transfer size is insn[23,31,30]. For integer loads/stores,
2916 insn[23] is zero, hence szLg2 can be at most 3 in such cases.
2917
2918 If the decoding fails, it returns IRTemp_INVALID.
2919
2920 isInt is True iff this is decoding is for transfers to/from integer
2921 registers. If False it is for transfers to/from vector registers.
2922*/
2923static IRTemp gen_indexed_EA ( /*OUT*/HChar* buf, UInt insn, Bool isInt )
2924{
2925 UInt optS = SLICE_UInt(insn, 15, 12);
2926 UInt mm = SLICE_UInt(insn, 20, 16);
2927 UInt nn = SLICE_UInt(insn, 9, 5);
2928 UInt szLg2 = (isInt ? 0 : (SLICE_UInt(insn, 23, 23) << 2))
2929 | SLICE_UInt(insn, 31, 30); // Log2 of the size
2930
2931 buf[0] = 0;
2932
2933 /* Sanity checks, that this really is a load/store insn. */
2934 if (SLICE_UInt(insn, 11, 10) != BITS2(1,0))
2935 goto fail;
2936
2937 if (isInt
2938 && SLICE_UInt(insn, 29, 21) != BITS9(1,1,1,0,0,0,0,1,1)/*LDR*/
2939 && SLICE_UInt(insn, 29, 21) != BITS9(1,1,1,0,0,0,0,0,1)/*STR*/
2940 && SLICE_UInt(insn, 29, 21) != BITS9(1,1,1,0,0,0,1,0,1)/*LDRSbhw Xt*/
2941 && SLICE_UInt(insn, 29, 21) != BITS9(1,1,1,0,0,0,1,1,1))/*LDRSbhw Wt*/
2942 goto fail;
2943
2944 if (!isInt
2945 && SLICE_UInt(insn, 29, 24) != BITS6(1,1,1,1,0,0)) /*LDR/STR*/
2946 goto fail;
2947
2948 /* Throw out non-verified but possibly valid cases. */
2949 switch (szLg2) {
2950 case BITS3(0,0,0): break; // 8 bit, valid for both int and vec
2951 case BITS3(0,0,1): break; // 16 bit, valid for both int and vec
2952 case BITS3(0,1,0): break; // 32 bit, valid for both int and vec
2953 case BITS3(0,1,1): break; // 64 bit, valid for both int and vec
2954 case BITS3(1,0,0): // can only ever be valid for the vector case
2955 if (isInt) goto fail; else goto fail;
2956 case BITS3(1,0,1): // these sizes are never valid
2957 case BITS3(1,1,0):
2958 case BITS3(1,1,1): goto fail;
2959
2960 default: vassert(0);
2961 }
2962
2963 IRExpr* rhs = NULL;
2964 switch (optS) {
2965 case BITS4(1,1,1,0): goto fail; //ATC
2966 case BITS4(0,1,1,0):
2967 rhs = getIReg64orZR(mm);
2968 vex_sprintf(buf, "[%s, %s]",
2969 nameIReg64orZR(nn), nameIReg64orZR(mm));
2970 break;
2971 case BITS4(1,1,1,1): goto fail; //ATC
2972 case BITS4(0,1,1,1):
2973 rhs = binop(Iop_Shl64, getIReg64orZR(mm), mkU8(szLg2));
2974 vex_sprintf(buf, "[%s, %s lsl %u]",
2975 nameIReg64orZR(nn), nameIReg64orZR(mm), szLg2);
2976 break;
2977 case BITS4(0,1,0,0):
2978 rhs = unop(Iop_32Uto64, getIReg32orZR(mm));
2979 vex_sprintf(buf, "[%s, %s uxtx]",
2980 nameIReg64orZR(nn), nameIReg32orZR(mm));
2981 break;
2982 case BITS4(0,1,0,1):
2983 rhs = binop(Iop_Shl64,
2984 unop(Iop_32Uto64, getIReg32orZR(mm)), mkU8(szLg2));
2985 vex_sprintf(buf, "[%s, %s uxtx, lsl %u]",
2986 nameIReg64orZR(nn), nameIReg32orZR(mm), szLg2);
2987 break;
2988 case BITS4(1,1,0,0):
2989 rhs = unop(Iop_32Sto64, getIReg32orZR(mm));
2990 vex_sprintf(buf, "[%s, %s sxtx]",
2991 nameIReg64orZR(nn), nameIReg32orZR(mm));
2992 break;
2993 case BITS4(1,1,0,1):
2994 rhs = binop(Iop_Shl64,
2995 unop(Iop_32Sto64, getIReg32orZR(mm)), mkU8(szLg2));
2996 vex_sprintf(buf, "[%s, %s sxtx, lsl %u]",
2997 nameIReg64orZR(nn), nameIReg32orZR(mm), szLg2);
2998 break;
2999 default:
3000 /* The rest appear to be genuinely invalid */
3001 goto fail;
3002 }
3003
3004 vassert(rhs);
3005 IRTemp res = newTemp(Ity_I64);
3006 assign(res, binop(Iop_Add64, getIReg64orSP(nn), rhs));
3007 return res;
3008
3009 fail:
3010 vex_printf("gen_indexed_EA: unhandled case optS == 0x%x\n", optS);
3011 return IRTemp_INVALID;
3012}
3013
3014
3015/* Generate an 8/16/32/64 bit integer store to ADDR for the lowest
3016 bits of DATAE :: Ity_I64. */
3017static void gen_narrowing_store ( UInt szB, IRTemp addr, IRExpr* dataE )
3018{
3019 IRExpr* addrE = mkexpr(addr);
3020 switch (szB) {
3021 case 8:
3022 storeLE(addrE, dataE);
3023 break;
3024 case 4:
3025 storeLE(addrE, unop(Iop_64to32, dataE));
3026 break;
3027 case 2:
3028 storeLE(addrE, unop(Iop_64to16, dataE));
3029 break;
3030 case 1:
3031 storeLE(addrE, unop(Iop_64to8, dataE));
3032 break;
3033 default:
3034 vassert(0);
3035 }
3036}
3037
3038
3039/* Generate an 8/16/32/64 bit unsigned widening load from ADDR,
3040 placing the result in an Ity_I64 temporary. */
3041static IRTemp gen_zwidening_load ( UInt szB, IRTemp addr )
3042{
3043 IRTemp res = newTemp(Ity_I64);
3044 IRExpr* addrE = mkexpr(addr);
3045 switch (szB) {
3046 case 8:
3047 assign(res, loadLE(Ity_I64,addrE));
3048 break;
3049 case 4:
3050 assign(res, unop(Iop_32Uto64, loadLE(Ity_I32,addrE)));
3051 break;
3052 case 2:
3053 assign(res, unop(Iop_16Uto64, loadLE(Ity_I16,addrE)));
3054 break;
3055 case 1:
3056 assign(res, unop(Iop_8Uto64, loadLE(Ity_I8,addrE)));
3057 break;
3058 default:
3059 vassert(0);
3060 }
3061 return res;
3062}
3063
3064
3065static
3066Bool dis_ARM64_load_store(/*MB_OUT*/DisResult* dres, UInt insn)
3067{
3068# define INSN(_bMax,_bMin) SLICE_UInt(insn, (_bMax), (_bMin))
3069
3070 /* ------------ LDR,STR (immediate, uimm12) ----------- */
3071 /* uimm12 is scaled by the transfer size
3072
3073 31 29 26 21 9 4
3074 | | | | | |
3075 11 111 00100 imm12 nn tt STR Xt, [Xn|SP, #imm12 * 8]
3076 11 111 00101 imm12 nn tt LDR Xt, [Xn|SP, #imm12 * 8]
3077
3078 10 111 00100 imm12 nn tt STR Wt, [Xn|SP, #imm12 * 4]
3079 10 111 00101 imm12 nn tt LDR Wt, [Xn|SP, #imm12 * 4]
3080
3081 01 111 00100 imm12 nn tt STRH Wt, [Xn|SP, #imm12 * 2]
3082 01 111 00101 imm12 nn tt LDRH Wt, [Xn|SP, #imm12 * 2]
3083
3084 00 111 00100 imm12 nn tt STRB Wt, [Xn|SP, #imm12 * 1]
3085 00 111 00101 imm12 nn tt LDRB Wt, [Xn|SP, #imm12 * 1]
3086 */
3087 if (INSN(29,23) == BITS7(1,1,1,0,0,1,0)) {
3088 UInt szLg2 = INSN(31,30);
3089 UInt szB = 1 << szLg2;
3090 Bool isLD = INSN(22,22) == 1;
3091 UInt offs = INSN(21,10) * szB;
3092 UInt nn = INSN(9,5);
3093 UInt tt = INSN(4,0);
3094 IRTemp ta = newTemp(Ity_I64);
3095 assign(ta, binop(Iop_Add64, getIReg64orSP(nn), mkU64(offs)));
3096 if (nn == 31) { /* FIXME generate stack alignment check */ }
3097 vassert(szLg2 < 4);
3098 if (isLD) {
3099 putIReg64orZR(tt, mkexpr(gen_zwidening_load(szB, ta)));
3100 } else {
3101 gen_narrowing_store(szB, ta, getIReg64orZR(tt));
3102 }
3103 const HChar* ld_name[4] = { "ldrb", "ldrh", "ldr", "ldr" };
3104 const HChar* st_name[4] = { "strb", "strh", "str", "str" };
3105 DIP("%s %s, [%s, #%u]\n",
3106 (isLD ? ld_name : st_name)[szLg2], nameIRegOrZR(szB == 8, tt),
3107 nameIReg64orSP(nn), offs);
3108 return True;
3109 }
3110
3111 /* ------------ LDUR,STUR (immediate, simm9) ----------- */
3112 /*
3113 31 29 26 20 11 9 4
3114 | | | | | | |
3115 (at-Rn-then-Rn=EA) | | |
3116 sz 111 00000 0 imm9 01 Rn Rt STR Rt, [Xn|SP], #simm9
3117 sz 111 00001 0 imm9 01 Rn Rt LDR Rt, [Xn|SP], #simm9
3118
3119 (at-EA-then-Rn=EA)
3120 sz 111 00000 0 imm9 11 Rn Rt STR Rt, [Xn|SP, #simm9]!
3121 sz 111 00001 0 imm9 11 Rn Rt LDR Rt, [Xn|SP, #simm9]!
3122
3123 (at-EA)
3124 sz 111 00000 0 imm9 00 Rn Rt STR Rt, [Xn|SP, #simm9]
3125 sz 111 00001 0 imm9 00 Rn Rt LDR Rt, [Xn|SP, #simm9]
3126
3127 simm9 is unscaled.
3128
3129 The case 'wback && Rn == Rt && Rt != 31' is disallowed. In the
3130 load case this is because would create two competing values for
3131 Rt. In the store case the reason is unclear, but the spec
3132 disallows it anyway.
3133
3134 Stores are narrowing, loads are unsigned widening. sz encodes
3135 the transfer size in the normal way: 00=1, 01=2, 10=4, 11=8.
3136 */
3137 if ((INSN(29,21) & BITS9(1,1,1, 1,1,1,1,0, 1))
3138 == BITS9(1,1,1, 0,0,0,0,0, 0)) {
3139 UInt szLg2 = INSN(31,30);
3140 UInt szB = 1 << szLg2;
3141 Bool isLoad = INSN(22,22) == 1;
3142 UInt imm9 = INSN(20,12);
3143 UInt nn = INSN(9,5);
3144 UInt tt = INSN(4,0);
3145 Bool wBack = INSN(10,10) == 1;
3146 UInt how = INSN(11,10);
3147 if (how == BITS2(1,0) || (wBack && nn == tt && tt != 31)) {
3148 /* undecodable; fall through */
3149 } else {
3150 if (nn == 31) { /* FIXME generate stack alignment check */ }
3151
3152 // Compute the transfer address TA and the writeback address WA.
3153 IRTemp tRN = newTemp(Ity_I64);
3154 assign(tRN, getIReg64orSP(nn));
3155 IRTemp tEA = newTemp(Ity_I64);
3156 Long simm9 = (Long)sx_to_64(imm9, 9);
3157 assign(tEA, binop(Iop_Add64, mkexpr(tRN), mkU64(simm9)));
3158
3159 IRTemp tTA = newTemp(Ity_I64);
3160 IRTemp tWA = newTemp(Ity_I64);
3161 switch (how) {
3162 case BITS2(0,1):
3163 assign(tTA, mkexpr(tRN)); assign(tWA, mkexpr(tEA)); break;
3164 case BITS2(1,1):
3165 assign(tTA, mkexpr(tEA)); assign(tWA, mkexpr(tEA)); break;
3166 case BITS2(0,0):
3167 assign(tTA, mkexpr(tEA)); /* tWA is unused */ break;
3168 default:
3169 vassert(0); /* NOTREACHED */
3170 }
3171
3172 if (isLoad) {
3173 putIReg64orZR(tt, mkexpr(gen_zwidening_load(szB, tTA)));
3174 } else {
3175 gen_narrowing_store(szB, tTA, getIReg64orZR(tt));
3176 }
3177
3178 if (wBack)
3179 putIReg64orSP(nn, mkexpr(tEA));
3180
3181 const HChar* ld_name[4] = { "ldurb", "ldurh", "ldur", "ldur" };
3182 const HChar* st_name[4] = { "sturb", "sturh", "stur", "stur" };
3183 const HChar* fmt_str = NULL;
3184 switch (how) {
3185 case BITS2(0,1):
3186 fmt_str = "%s %s, [%s], #%lld (at-Rn-then-Rn=EA)\n";
3187 break;
3188 case BITS2(1,1):
3189 fmt_str = "%s %s, [%s, #%lld]! (at-EA-then-Rn=EA)\n";
3190 break;
3191 case BITS2(0,0):
3192 fmt_str = "%s %s, [%s, #%lld] (at-Rn)\n";
3193 break;
3194 default:
3195 vassert(0);
3196 }
3197 DIP(fmt_str, (isLoad ? ld_name : st_name)[szLg2],
3198 nameIRegOrZR(szB == 8, tt),
3199 nameIReg64orSP(nn), simm9);
3200 return True;
3201 }
3202 }
3203
3204 /* -------- LDP,STP (immediate, simm7) (INT REGS) -------- */
3205 /* L==1 => mm==LD
3206 L==0 => mm==ST
3207 x==0 => 32 bit transfers, and zero extended loads
3208 x==1 => 64 bit transfers
3209 simm7 is scaled by the (single-register) transfer size
3210
3211 (at-Rn-then-Rn=EA)
3212 x0 101 0001 L imm7 Rt2 Rn Rt1 mmP Rt1,Rt2, [Xn|SP], #imm
3213
3214 (at-EA-then-Rn=EA)
3215 x0 101 0011 L imm7 Rt2 Rn Rt1 mmP Rt1,Rt2, [Xn|SP, #imm]!
3216
3217 (at-EA)
3218 x0 101 0010 L imm7 Rt2 Rn Rt1 mmP Rt1,Rt2, [Xn|SP, #imm]
3219 */
3220
3221 UInt insn_30_23 = INSN(30,23);
3222 if (insn_30_23 == BITS8(0,1,0,1,0,0,0,1)
3223 || insn_30_23 == BITS8(0,1,0,1,0,0,1,1)
3224 || insn_30_23 == BITS8(0,1,0,1,0,0,1,0)) {
3225 UInt bL = INSN(22,22);
3226 UInt bX = INSN(31,31);
3227 UInt bWBack = INSN(23,23);
3228 UInt rT1 = INSN(4,0);
3229 UInt rN = INSN(9,5);
3230 UInt rT2 = INSN(14,10);
3231 Long simm7 = (Long)sx_to_64(INSN(21,15), 7);
3232 if ((bWBack && (rT1 == rN || rT2 == rN) && rN != 31)
3233 || (bL && rT1 == rT2)) {
3234 /* undecodable; fall through */
3235 } else {
3236 if (rN == 31) { /* FIXME generate stack alignment check */ }
3237
3238 // Compute the transfer address TA and the writeback address WA.
3239 IRTemp tRN = newTemp(Ity_I64);
3240 assign(tRN, getIReg64orSP(rN));
3241 IRTemp tEA = newTemp(Ity_I64);
3242 simm7 = (bX ? 8 : 4) * simm7;
3243 assign(tEA, binop(Iop_Add64, mkexpr(tRN), mkU64(simm7)));
3244
3245 IRTemp tTA = newTemp(Ity_I64);
3246 IRTemp tWA = newTemp(Ity_I64);
3247 switch (INSN(24,23)) {
3248 case BITS2(0,1):
3249 assign(tTA, mkexpr(tRN)); assign(tWA, mkexpr(tEA)); break;
3250 case BITS2(1,1):
3251 assign(tTA, mkexpr(tEA)); assign(tWA, mkexpr(tEA)); break;
3252 case BITS2(1,0):
3253 assign(tTA, mkexpr(tEA)); /* tWA is unused */ break;
3254 default:
3255 vassert(0); /* NOTREACHED */
3256 }
3257
3258 /* Normally rN would be updated after the transfer. However, in
3259 the special case typifed by
3260 stp x29, x30, [sp,#-112]!
3261 it is necessary to update SP before the transfer, (1)
3262 because Memcheck will otherwise complain about a write
3263 below the stack pointer, and (2) because the segfault
3264 stack extension mechanism will otherwise extend the stack
3265 only down to SP before the instruction, which might not be
3266 far enough, if the -112 bit takes the actual access
3267 address to the next page.
3268 */
3269 Bool earlyWBack
3270 = bWBack && simm7 < 0
3271 && INSN(24,23) == BITS2(1,1) && rN == 31 && bL == 0;
3272
3273 if (bWBack && earlyWBack)
3274 putIReg64orSP(rN, mkexpr(tEA));
3275
3276 /**/ if (bL == 1 && bX == 1) {
3277 // 64 bit load
3278 putIReg64orZR(rT1, loadLE(Ity_I64,
3279 binop(Iop_Add64,mkexpr(tTA),mkU64(0))));
3280 putIReg64orZR(rT2, loadLE(Ity_I64,
3281 binop(Iop_Add64,mkexpr(tTA),mkU64(8))));
3282 } else if (bL == 1 && bX == 0) {
3283 vassert(0); //ATC
3284 // 32 bit load
3285 putIReg32orZR(rT1, loadLE(Ity_I32,
3286 binop(Iop_Add64,mkexpr(tTA),mkU64(0))));
3287 putIReg32orZR(rT2, loadLE(Ity_I32,
3288 binop(Iop_Add64,mkexpr(tTA),mkU64(4))));
3289 } else if (bL == 0 && bX == 1) {
3290 // 64 bit store
3291 storeLE(binop(Iop_Add64,mkexpr(tTA),mkU64(0)),
3292 getIReg64orZR(rT1));
3293 storeLE(binop(Iop_Add64,mkexpr(tTA),mkU64(8)),
3294 getIReg64orZR(rT2));
3295 } else {
3296 vassert(bL == 0 && bX == 0);
3297 vassert(0); //ATC
3298 // 32 bit store
3299 storeLE(binop(Iop_Add64,mkexpr(tTA),mkU64(0)),
3300 getIReg32orZR(rT1));
3301 storeLE(binop(Iop_Add64,mkexpr(tTA),mkU64(4)),
3302 getIReg32orZR(rT2));
3303 }
3304
3305 if (bWBack && !earlyWBack)
3306 putIReg64orSP(rN, mkexpr(tEA));
3307
3308 const HChar* fmt_str = NULL;
3309 switch (INSN(24,23)) {
3310 case BITS2(0,1):
3311 fmt_str = "%sp %s, %s, [%s], #%lld (at-Rn-then-Rn=EA)\n";
3312 break;
3313 case BITS2(1,1):
3314 fmt_str = "%sp %s, %s, [%s, #%lld]! (at-EA-then-Rn=EA)\n";
3315 break;
3316 case BITS2(1,0):
3317 fmt_str = "%sp %s, %s, [%s, #%lld] (at-Rn)\n";
3318 break;
3319 default:
3320 vassert(0);
3321 }
3322 DIP(fmt_str, bL == 0 ? "st" : "ld",
3323 nameIRegOrZR(bX == 1, rT1),
3324 nameIRegOrZR(bX == 1, rT2),
3325 nameIReg64orSP(rN), simm7);
3326 return True;
3327 }
3328 }
3329
3330 /* ---------------- LDR (literal, int reg) ---------------- */
3331 /* 31 29 23 4
3332 00 011 000 imm19 Rt LDR Wt, [PC + sxTo64(imm19 << 2)]
3333 01 011 000 imm19 Rt LDR Xt, [PC + sxTo64(imm19 << 2)]
3334 10 011 000 imm19 Rt LDRSW Xt, [PC + sxTo64(imm19 << 2)]
3335 11 011 000 imm19 Rt prefetch [PC + sxTo64(imm19 << 2)]
3336 Just handles the first two cases for now.
3337 */
3338 if (INSN(29,24) == BITS6(0,1,1,0,0,0) && INSN(31,31) == 0) {
3339 UInt imm19 = INSN(23,5);
3340 UInt rT = INSN(4,0);
3341 UInt bX = INSN(30,30);
3342 ULong ea = guest_PC_curr_instr + sx_to_64(imm19 << 2, 21);
3343 if (bX) {
3344 putIReg64orZR(rT, loadLE(Ity_I64, mkU64(ea)));
3345 } else {
3346 putIReg32orZR(rT, loadLE(Ity_I32, mkU64(ea)));
3347 }
3348 DIP("ldr %s, 0x%llx (literal)\n", nameIRegOrZR(bX == 1, rT), ea);
3349 return True;
3350 }
3351
3352 /* -------------- {LD,ST}R (integer register) --------------- */
3353 /* 31 29 20 15 12 11 9 4
3354 | | | | | | | |
3355 11 111000011 Rm option S 10 Rn Rt LDR Xt, [Xn|SP, R<m>{ext/sh}]
3356 10 111000011 Rm option S 10 Rn Rt LDR Wt, [Xn|SP, R<m>{ext/sh}]
3357 01 111000011 Rm option S 10 Rn Rt LDRH Wt, [Xn|SP, R<m>{ext/sh}]
3358 00 111000011 Rm option S 10 Rn Rt LDRB Wt, [Xn|SP, R<m>{ext/sh}]
3359
3360 11 111000001 Rm option S 10 Rn Rt STR Xt, [Xn|SP, R<m>{ext/sh}]
3361 10 111000001 Rm option S 10 Rn Rt STR Wt, [Xn|SP, R<m>{ext/sh}]
3362 01 111000001 Rm option S 10 Rn Rt STRH Wt, [Xn|SP, R<m>{ext/sh}]
3363 00 111000001 Rm option S 10 Rn Rt STRB Wt, [Xn|SP, R<m>{ext/sh}]
3364 */
3365 if (INSN(29,23) == BITS7(1,1,1,0,0,0,0)
3366 && INSN(21,21) == 1 && INSN(11,10) == BITS2(1,0)) {
3367 HChar dis_buf[64];
3368 UInt szLg2 = INSN(31,30);
3369 Bool isLD = INSN(22,22) == 1;
3370 UInt tt = INSN(4,0);
3371 IRTemp ea = gen_indexed_EA(dis_buf, insn, True/*to/from int regs*/);
3372 if (ea != IRTemp_INVALID) {
3373 switch (szLg2) {
3374 case 3: /* 64 bit */
3375 if (isLD) {
3376 putIReg64orZR(tt, loadLE(Ity_I64, mkexpr(ea)));
3377 DIP("ldr %s, %s\n", nameIReg64orZR(tt), dis_buf);
3378 } else {
3379 storeLE(mkexpr(ea), getIReg64orZR(tt));
3380 DIP("str %s, %s\n", nameIReg64orZR(tt), dis_buf);
3381 }
3382 break;
3383 case 2: /* 32 bit */
3384 if (isLD) {
3385 putIReg32orZR(tt, loadLE(Ity_I32, mkexpr(ea)));
3386 DIP("ldr %s, %s\n", nameIReg32orZR(tt), dis_buf);
3387 } else {
3388 storeLE(mkexpr(ea), getIReg32orZR(tt));
3389 DIP("str %s, %s\n", nameIReg32orZR(tt), dis_buf);
3390 }
3391 break;
3392 case 1: /* 16 bit */
3393 if (isLD) {
3394 putIReg64orZR(tt, unop(Iop_16Uto64,
3395 loadLE(Ity_I16, mkexpr(ea))));
3396 DIP("ldruh %s, %s\n", nameIReg32orZR(tt), dis_buf);
3397 } else {
3398 storeLE(mkexpr(ea), unop(Iop_64to16, getIReg64orZR(tt)));
3399 DIP("strh %s, %s\n", nameIReg32orZR(tt), dis_buf);
3400 }
3401 break;
3402 case 0: /* 8 bit */
3403 if (isLD) {
3404 putIReg64orZR(tt, unop(Iop_8Uto64,
3405 loadLE(Ity_I8, mkexpr(ea))));
3406 DIP("ldrub %s, %s\n", nameIReg32orZR(tt), dis_buf);
3407 } else {
3408 storeLE(mkexpr(ea), unop(Iop_64to8, getIReg64orZR(tt)));
3409 DIP("strb %s, %s\n", nameIReg32orZR(tt), dis_buf);
3410 }
3411 break;
3412 default:
3413 vassert(0);
3414 }
3415 return True;
3416 }
3417 }
3418
3419 /* -------------- LDRS{B,H,W} (uimm12) -------------- */
3420 /* 31 29 26 23 21 9 4
3421 10 111 001 10 imm12 n t LDRSW Xt, [Xn|SP, #pimm12 * 4]
3422 01 111 001 1x imm12 n t LDRSH Rt, [Xn|SP, #pimm12 * 2]
3423 00 111 001 1x imm12 n t LDRSB Rt, [Xn|SP, #pimm12 * 1]
3424 where
3425 Rt is Wt when x==1, Xt when x==0
3426 */
3427 if (INSN(29,23) == BITS7(1,1,1,0,0,1,1)) {
3428 /* Further checks on bits 31:30 and 22 */
3429 Bool valid = False;
3430 switch ((INSN(31,30) << 1) | INSN(22,22)) {
3431 case BITS3(1,0,0):
3432 case BITS3(0,1,0): case BITS3(0,1,1):
3433 case BITS3(0,0,0): case BITS3(0,0,1):
3434 valid = True;
3435 break;
3436 }
3437 if (valid) {
3438 UInt szLg2 = INSN(31,30);
3439 UInt bitX = INSN(22,22);
3440 UInt imm12 = INSN(21,10);
3441 UInt nn = INSN(9,5);
3442 UInt tt = INSN(4,0);
3443 UInt szB = 1 << szLg2;
3444 IRExpr* ea = binop(Iop_Add64,
3445 getIReg64orSP(nn), mkU64(imm12 * szB));
3446 switch (szB) {
3447 case 4:
3448 vassert(bitX == 0);
3449 putIReg64orZR(tt, unop(Iop_32Sto64, loadLE(Ity_I32, ea)));
3450 DIP("ldrsw %s, [%s, #%u]\n", nameIReg64orZR(tt),
3451 nameIReg64orSP(nn), imm12 * szB);
3452 break;
3453 case 2:
3454 if (bitX == 1) {
3455 putIReg32orZR(tt, unop(Iop_16Sto32, loadLE(Ity_I16, ea)));
3456 } else {
3457 putIReg64orZR(tt, unop(Iop_16Sto64, loadLE(Ity_I16, ea)));
3458 }
3459 DIP("ldrsh %s, [%s, #%u]\n",
3460 nameIRegOrZR(bitX == 0, tt),
3461 nameIReg64orSP(nn), imm12 * szB);
3462 break;
3463 case 1:
3464 if (bitX == 1) {
3465 putIReg32orZR(tt, unop(Iop_8Sto32, loadLE(Ity_I8, ea)));
3466 } else {
3467 putIReg64orZR(tt, unop(Iop_8Sto64, loadLE(Ity_I8, ea)));
3468 }
3469 DIP("ldrsb %s, [%s, #%u]\n",
3470 nameIRegOrZR(bitX == 0, tt),
3471 nameIReg64orSP(nn), imm12 * szB);
3472 break;
3473 default:
3474 vassert(0);
3475 }
3476 return True;
3477 }
3478 /* else fall through */
3479 }
3480
3481 /* -------------- LDRS{B,H,W} (simm9, upd) -------------- */
3482 /* (at-Rn-then-Rn=EA)
3483 31 29 23 21 20 11 9 4
3484 00 111 000 1x 0 imm9 01 n t LDRSB Rt, [Xn|SP], #simm9
3485 01 111 000 1x 0 imm9 01 n t LDRSH Rt, [Xn|SP], #simm9
3486 10 111 000 10 0 imm9 01 n t LDRSW Xt, [Xn|SP], #simm9
3487
3488 (at-EA-then-Rn=EA)
3489 00 111 000 1x 0 imm9 11 n t LDRSB Rt, [Xn|SP, #simm9]!
3490 01 111 000 1x 0 imm9 11 n t LDRSH Rt, [Xn|SP, #simm9]!
3491 10 111 000 10 0 imm9 11 n t LDRSW Xt, [Xn|SP, #simm9]!
3492 where
3493 Rt is Wt when x==1, Xt when x==0
3494 transfer-at-Rn when [11]==0, at EA when [11]==1
3495 */
3496 if (INSN(29,23) == BITS7(1,1,1,0,0,0,1)
3497 && INSN(21,21) == 0 && INSN(10,10) == 1) {
3498 /* Further checks on bits 31:30 and 22 */
3499 Bool valid = False;
3500 switch ((INSN(31,30) << 1) | INSN(22,22)) {
3501 case BITS3(1,0,0): // LDRSW Xt
3502 case BITS3(0,1,0): case BITS3(0,1,1): // LDRSH Xt, Wt
3503 case BITS3(0,0,0): case BITS3(0,0,1): // LDRSB Xt, Wt
3504 valid = True;
3505 break;
3506 }
3507 if (valid) {
3508 UInt szLg2 = INSN(31,30);
3509 UInt imm9 = INSN(20,12);
3510 Bool atRN = INSN(11,11) == 0;
3511 UInt nn = INSN(9,5);
3512 UInt tt = INSN(4,0);
3513 IRTemp tRN = newTemp(Ity_I64);
3514 IRTemp tEA = newTemp(Ity_I64);
3515 IRTemp tTA = IRTemp_INVALID;
3516 ULong simm9 = sx_to_64(imm9, 9);
3517 Bool is64 = INSN(22,22) == 0;
3518 assign(tRN, getIReg64orSP(nn));
3519 assign(tEA, binop(Iop_Add64, mkexpr(tRN), mkU64(simm9)));
3520 tTA = atRN ? tRN : tEA;
3521 HChar ch = '?';
3522 /* There are 5 cases:
3523 byte load, SX to 64
3524 byte load, SX to 32, ZX to 64
3525 halfword load, SX to 64
3526 halfword load, SX to 32, ZX to 64
3527 word load, SX to 64
3528 The ifs below handle them in the listed order.
3529 */
3530 if (szLg2 == 0) {
3531 ch = 'b';
3532 if (is64) {
3533 putIReg64orZR(tt, unop(Iop_8Sto64,
3534 loadLE(Ity_I8, mkexpr(tTA))));
3535 } else {
3536 putIReg32orZR(tt, unop(Iop_8Sto32,
3537 loadLE(Ity_I8, mkexpr(tTA))));
3538 }
3539 }
3540 else if (szLg2 == 1) {
3541 ch = 'h';
3542 if (is64) {
3543 putIReg64orZR(tt, unop(Iop_16Sto64,
3544 loadLE(Ity_I16, mkexpr(tTA))));
3545 } else {
3546 putIReg32orZR(tt, unop(Iop_16Sto32,
3547 loadLE(Ity_I16, mkexpr(tTA))));
3548 }
3549 }
3550 else if (szLg2 == 2 && is64) {
3551 ch = 'w';
3552 putIReg64orZR(tt, unop(Iop_32Sto64,
3553 loadLE(Ity_I32, mkexpr(tTA))));
3554 }
3555 else {
3556 vassert(0);
3557 }
3558 putIReg64orSP(nn, mkexpr(tEA));
3559 DIP(atRN ? "ldrs%c %s, [%s], #%lld\n" : "ldrs%c %s, [%s, #%lld]!",
3560 ch, nameIRegOrZR(is64, tt), nameIReg64orSP(nn), simm9);
3561 return True;
3562 }
3563 /* else fall through */
3564 }
3565
3566 /* -------------- LDRS{B,H,W} (simm9, noUpd) -------------- */
3567 /* 31 29 23 21 20 11 9 4
3568 00 111 000 1x 0 imm9 00 n t LDURSB Rt, [Xn|SP, #simm9]
3569 01 111 000 1x 0 imm9 00 n t LDURSH Rt, [Xn|SP, #simm9]
3570 10 111 000 10 0 imm9 00 n t LDURSW Xt, [Xn|SP, #simm9]
3571 where
3572 Rt is Wt when x==1, Xt when x==0
3573 */
3574 if (INSN(29,23) == BITS7(1,1,1,0,0,0,1)
3575 && INSN(21,21) == 0 && INSN(11,10) == BITS2(0,0)) {
3576 /* Further checks on bits 31:30 and 22 */
3577 Bool valid = False;
3578 switch ((INSN(31,30) << 1) | INSN(22,22)) {
3579 case BITS3(1,0,0): // LDURSW Xt
3580 case BITS3(0,1,0): case BITS3(0,1,1): // LDURSH Xt, Wt
3581 case BITS3(0,0,0): case BITS3(0,0,1): // LDURSB Xt, Wt
3582 valid = True;
3583 break;
3584 }
3585 if (valid) {
3586 UInt szLg2 = INSN(31,30);
3587 UInt imm9 = INSN(20,12);
3588 UInt nn = INSN(9,5);
3589 UInt tt = INSN(4,0);
3590 IRTemp tRN = newTemp(Ity_I64);
3591 IRTemp tEA = newTemp(Ity_I64);
3592 ULong simm9 = sx_to_64(imm9, 9);
3593 Bool is64 = INSN(22,22) == 0;
3594 assign(tRN, getIReg64orSP(nn));
3595 assign(tEA, binop(Iop_Add64, mkexpr(tRN), mkU64(simm9)));
3596 HChar ch = '?';
3597 /* There are 5 cases:
3598 byte load, SX to 64
3599 byte load, SX to 32, ZX to 64
3600 halfword load, SX to 64
3601 halfword load, SX to 32, ZX to 64
3602 word load, SX to 64
3603 The ifs below handle them in the listed order.
3604 */
3605 if (szLg2 == 0) {
3606 ch = 'b';
3607 if (is64) {
3608 putIReg64orZR(tt, unop(Iop_8Sto64,
3609 loadLE(Ity_I8, mkexpr(tEA))));
3610 } else {
3611 putIReg32orZR(tt, unop(Iop_8Sto32,
3612 loadLE(Ity_I8, mkexpr(tEA))));
3613 }
3614 }
3615 else if (szLg2 == 1) {
3616 ch = 'h';
3617 if (is64) {
3618 putIReg64orZR(tt, unop(Iop_16Sto64,
3619 loadLE(Ity_I16, mkexpr(tEA))));
3620 } else {
3621 putIReg32orZR(tt, unop(Iop_16Sto32,
3622 loadLE(Ity_I16, mkexpr(tEA))));
3623 }
3624 }
3625 else if (szLg2 == 2 && is64) {
3626 ch = 'w';
3627 putIReg64orZR(tt, unop(Iop_32Sto64,
3628 loadLE(Ity_I32, mkexpr(tEA))));
3629 }
3630 else {
3631 vassert(0);
3632 }
3633 DIP("ldurs%c %s, [%s, #%lld]",
3634 ch, nameIRegOrZR(is64, tt), nameIReg64orSP(nn), simm9);
3635 return True;
3636 }
3637 /* else fall through */
3638 }
3639
3640 /* -------- LDP,STP (immediate, simm7) (FP&VEC) -------- */
3641 /* L==1 => mm==LD
3642 L==0 => mm==ST
3643 sz==00 => 32 bit (S) transfers
3644 sz==01 => 64 bit (D) transfers
3645 sz==10 => 128 bit (Q) transfers
3646 sz==11 isn't allowed
3647 simm7 is scaled by the (single-register) transfer size
3648
3649 31 29 22 21 14 9 4
3650 sz 101 1001 L imm7 t2 n t1 mmP SDQt1, SDQt2, [Xn|SP], #imm
3651 (at-Rn-then-Rn=EA)
3652
3653 sz 101 1011 L imm7 t2 n t1 mmP SDQt1, SDQt2, [Xn|SP, #imm]!
3654 (at-EA-then-Rn=EA)
3655
3656 sz 101 1010 L imm7 t2 n t1 mmP SDQt1, SDQt2, [Xn|SP, #imm]
3657 (at-EA)
3658 */
3659
3660 UInt insn_29_23 = INSN(29,23);
3661 if (insn_29_23 == BITS7(1,0,1,1,0,0,1)
3662 || insn_29_23 == BITS7(1,0,1,1,0,1,1)
3663 || insn_29_23 == BITS7(1,0,1,1,0,1,0)) {
3664 UInt szSlg2 = INSN(31,30); // log2 of the xfer size in 32-bit units
3665 Bool isLD = INSN(22,22) == 1;
3666 Bool wBack = INSN(23,23) == 1;
3667 Long simm7 = (Long)sx_to_64(INSN(21,15), 7);
3668 UInt tt2 = INSN(14,10);
3669 UInt nn = INSN(9,5);
3670 UInt tt1 = INSN(4,0);
3671 if (szSlg2 == BITS2(1,1) || (isLD && tt1 == tt2)) {
3672 /* undecodable; fall through */
3673 } else {
3674 if (nn == 31) { /* FIXME generate stack alignment check */ }
3675
3676 // Compute the transfer address TA and the writeback address WA.
3677 UInt szB = 4 << szSlg2; /* szB is the per-register size */
3678 IRTemp tRN = newTemp(Ity_I64);
3679 assign(tRN, getIReg64orSP(nn));
3680 IRTemp tEA = newTemp(Ity_I64);
3681 simm7 = szB * simm7;
3682 assign(tEA, binop(Iop_Add64, mkexpr(tRN), mkU64(simm7)));
3683
3684 IRTemp tTA = newTemp(Ity_I64);
3685 IRTemp tWA = newTemp(Ity_I64);
3686 switch (INSN(24,23)) {
3687 case BITS2(0,1):
3688 assign(tTA, mkexpr(tRN)); assign(tWA, mkexpr(tEA)); break;
3689 case BITS2(1,1):
3690 assign(tTA, mkexpr(tEA)); assign(tWA, mkexpr(tEA)); break;
3691 case BITS2(1,0):
3692 assign(tTA, mkexpr(tEA)); /* tWA is unused */ break;
3693 default:
3694 vassert(0); /* NOTREACHED */
3695 }
3696
3697 IRType ty = Ity_INVALID;
3698 switch (szB) {
3699 case 4: ty = Ity_F32; break;
3700 case 8: ty = Ity_F64; break;
3701 case 16: ty = Ity_V128; break;
3702 default: vassert(0);
3703 }
3704
3705 if (isLD) {
sewardj606c4ba2014-01-26 19:11:14 +00003706 putQRegLO(tt1,
3707 loadLE(ty, binop(Iop_Add64, mkexpr(tTA), mkU64(0))));
3708 putQRegLO(tt2,
3709 loadLE(ty, binop(Iop_Add64, mkexpr(tTA), mkU64(szB))));
sewardjbbcf1882014-01-12 12:49:10 +00003710 } else {
3711 storeLE(binop(Iop_Add64, mkexpr(tTA), mkU64(0)),
sewardj606c4ba2014-01-26 19:11:14 +00003712 getQRegLO(tt1, ty));
sewardjbbcf1882014-01-12 12:49:10 +00003713 storeLE(binop(Iop_Add64, mkexpr(tTA), mkU64(szB)),
sewardj606c4ba2014-01-26 19:11:14 +00003714 getQRegLO(tt2, ty));
sewardjbbcf1882014-01-12 12:49:10 +00003715 }
3716
3717 if (wBack)
3718 putIReg64orSP(nn, mkexpr(tEA));
3719
3720 const HChar* fmt_str = NULL;
3721 switch (INSN(24,23)) {
3722 case BITS2(0,1):
3723 fmt_str = "%sp %s, %s, [%s], #%lld (at-Rn-then-Rn=EA)\n";
3724 break;
3725 case BITS2(1,1):
3726 fmt_str = "%sp %s, %s, [%s, #%lld]! (at-EA-then-Rn=EA)\n";
3727 break;
3728 case BITS2(1,0):
3729 fmt_str = "%sp %s, %s, [%s, #%lld] (at-Rn)\n";
3730 break;
3731 default:
3732 vassert(0);
3733 }
3734 DIP(fmt_str, isLD ? "ld" : "st",
sewardj606c4ba2014-01-26 19:11:14 +00003735 nameQRegLO(tt1, ty), nameQRegLO(tt2, ty),
sewardjbbcf1882014-01-12 12:49:10 +00003736 nameIReg64orSP(nn), simm7);
3737 return True;
3738 }
3739 }
3740
3741 /* -------------- {LD,ST}R (vector register) --------------- */
3742 /* 31 29 23 20 15 12 11 9 4
3743 | | | | | | | | |
3744 00 111100 011 Rm option S 10 Rn Rt LDR Bt, [Xn|SP, R<m>{ext/sh}]
3745 01 111100 011 Rm option S 10 Rn Rt LDR Ht, [Xn|SP, R<m>{ext/sh}]
3746 10 111100 011 Rm option S 10 Rn Rt LDR St, [Xn|SP, R<m>{ext/sh}]
3747 11 111100 011 Rm option S 10 Rn Rt LDR Dt, [Xn|SP, R<m>{ext/sh}]
3748 00 111100 111 Rm option S 10 Rn Rt LDR Qt, [Xn|SP, R<m>{ext/sh}]
3749
3750 00 111100 001 Rm option S 10 Rn Rt STR Bt, [Xn|SP, R<m>{ext/sh}]
3751 01 111100 001 Rm option S 10 Rn Rt STR Ht, [Xn|SP, R<m>{ext/sh}]
3752 10 111100 001 Rm option S 10 Rn Rt STR St, [Xn|SP, R<m>{ext/sh}]
3753 11 111100 001 Rm option S 10 Rn Rt STR Dt, [Xn|SP, R<m>{ext/sh}]
3754 00 111100 101 Rm option S 10 Rn Rt STR Qt, [Xn|SP, R<m>{ext/sh}]
3755 */
3756 if (INSN(29,24) == BITS6(1,1,1,1,0,0)
3757 && INSN(21,21) == 1 && INSN(11,10) == BITS2(1,0)) {
3758 HChar dis_buf[64];
3759 UInt szLg2 = (INSN(23,23) << 2) | INSN(31,30);
3760 Bool isLD = INSN(22,22) == 1;
3761 UInt tt = INSN(4,0);
3762 if (szLg2 >= 4) goto after_LDR_STR_vector_register;
3763 IRTemp ea = gen_indexed_EA(dis_buf, insn, False/*to/from vec regs*/);
3764 if (ea == IRTemp_INVALID) goto after_LDR_STR_vector_register;
3765 switch (szLg2) {
3766 case 0: /* 8 bit */
3767 if (isLD) {
3768 putQReg128(tt, mkV128(0x0000));
sewardj606c4ba2014-01-26 19:11:14 +00003769 putQRegLO(tt, loadLE(Ity_I8, mkexpr(ea)));
3770 DIP("ldr %s, %s\n", nameQRegLO(tt, Ity_I8), dis_buf);
sewardjbbcf1882014-01-12 12:49:10 +00003771 } else {
3772 vassert(0); //ATC
sewardj606c4ba2014-01-26 19:11:14 +00003773 storeLE(mkexpr(ea), getQRegLO(tt, Ity_I8));
3774 DIP("str %s, %s\n", nameQRegLO(tt, Ity_I8), dis_buf);
sewardjbbcf1882014-01-12 12:49:10 +00003775 }
3776 break;
3777 case 1:
3778 if (isLD) {
3779 putQReg128(tt, mkV128(0x0000));
sewardj606c4ba2014-01-26 19:11:14 +00003780 putQRegLO(tt, loadLE(Ity_I16, mkexpr(ea)));
3781 DIP("ldr %s, %s\n", nameQRegLO(tt, Ity_I16), dis_buf);
sewardjbbcf1882014-01-12 12:49:10 +00003782 } else {
3783 vassert(0); //ATC
sewardj606c4ba2014-01-26 19:11:14 +00003784 storeLE(mkexpr(ea), getQRegLO(tt, Ity_I16));
3785 DIP("str %s, %s\n", nameQRegLO(tt, Ity_I16), dis_buf);
sewardjbbcf1882014-01-12 12:49:10 +00003786 }
3787 break;
3788 case 2: /* 32 bit */
3789 if (isLD) {
3790 putQReg128(tt, mkV128(0x0000));
sewardj606c4ba2014-01-26 19:11:14 +00003791 putQRegLO(tt, loadLE(Ity_I32, mkexpr(ea)));
3792 DIP("ldr %s, %s\n", nameQRegLO(tt, Ity_I32), dis_buf);
sewardjbbcf1882014-01-12 12:49:10 +00003793 } else {
sewardj606c4ba2014-01-26 19:11:14 +00003794 storeLE(mkexpr(ea), getQRegLO(tt, Ity_I32));
3795 DIP("str %s, %s\n", nameQRegLO(tt, Ity_I32), dis_buf);
sewardjbbcf1882014-01-12 12:49:10 +00003796 }
3797 break;
3798 case 3: /* 64 bit */
3799 if (isLD) {
3800 putQReg128(tt, mkV128(0x0000));
sewardj606c4ba2014-01-26 19:11:14 +00003801 putQRegLO(tt, loadLE(Ity_I64, mkexpr(ea)));
3802 DIP("ldr %s, %s\n", nameQRegLO(tt, Ity_I64), dis_buf);
sewardjbbcf1882014-01-12 12:49:10 +00003803 } else {
sewardj606c4ba2014-01-26 19:11:14 +00003804 storeLE(mkexpr(ea), getQRegLO(tt, Ity_I64));
3805 DIP("str %s, %s\n", nameQRegLO(tt, Ity_I64), dis_buf);
sewardjbbcf1882014-01-12 12:49:10 +00003806 }
3807 break;
3808 case 4: return False; //ATC
3809 default: vassert(0);
3810 }
3811 return True;
3812 }
3813 after_LDR_STR_vector_register:
3814
3815 /* ---------- LDRS{B,H,W} (integer register, SX) ---------- */
3816 /* 31 29 22 20 15 12 11 9 4
3817 | | | | | | | | |
3818 10 1110001 01 Rm opt S 10 Rn Rt LDRSW Xt, [Xn|SP, R<m>{ext/sh}]
3819
3820 01 1110001 01 Rm opt S 10 Rn Rt LDRSH Xt, [Xn|SP, R<m>{ext/sh}]
3821 01 1110001 11 Rm opt S 10 Rn Rt LDRSH Wt, [Xn|SP, R<m>{ext/sh}]
3822
3823 00 1110001 01 Rm opt S 10 Rn Rt LDRSB Xt, [Xn|SP, R<m>{ext/sh}]
3824 00 1110001 11 Rm opt S 10 Rn Rt LDRSB Wt, [Xn|SP, R<m>{ext/sh}]
3825 */
3826 if (INSN(29,23) == BITS7(1,1,1,0,0,0,1)
3827 && INSN(21,21) == 1 && INSN(11,10) == BITS2(1,0)) {
3828 HChar dis_buf[64];
3829 UInt szLg2 = INSN(31,30);
3830 Bool sxTo64 = INSN(22,22) == 0; // else sx to 32 and zx to 64
3831 UInt tt = INSN(4,0);
3832 if (szLg2 == 3) goto after_LDRS_integer_register;
3833 IRTemp ea = gen_indexed_EA(dis_buf, insn, True/*to/from int regs*/);
3834 if (ea == IRTemp_INVALID) goto after_LDRS_integer_register;
3835 /* Enumerate the 5 variants explicitly. */
3836 if (szLg2 == 2/*32 bit*/ && sxTo64) {
3837 putIReg64orZR(tt, unop(Iop_32Sto64, loadLE(Ity_I32, mkexpr(ea))));
3838 DIP("ldrsw %s, %s\n", nameIReg64orZR(tt), dis_buf);
3839 return True;
3840 }
3841 else
3842 if (szLg2 == 1/*16 bit*/) {
3843 if (sxTo64) {
3844 putIReg64orZR(tt, unop(Iop_16Sto64, loadLE(Ity_I16, mkexpr(ea))));
3845 DIP("ldrsh %s, %s\n", nameIReg64orZR(tt), dis_buf);
3846 } else {
3847 putIReg32orZR(tt, unop(Iop_16Sto32, loadLE(Ity_I16, mkexpr(ea))));
3848 DIP("ldrsh %s, %s\n", nameIReg32orZR(tt), dis_buf);
3849 }
3850 return True;
3851 }
3852 else
3853 if (szLg2 == 0/*8 bit*/) {
3854 if (sxTo64) {
3855 putIReg64orZR(tt, unop(Iop_8Sto64, loadLE(Ity_I8, mkexpr(ea))));
3856 DIP("ldrsb %s, %s\n", nameIReg64orZR(tt), dis_buf);
3857 } else {
3858 putIReg32orZR(tt, unop(Iop_8Sto32, loadLE(Ity_I8, mkexpr(ea))));
3859 DIP("ldrsb %s, %s\n", nameIReg32orZR(tt), dis_buf);
3860 }
3861 return True;
3862 }
3863 /* else it's an invalid combination */
3864 }
3865 after_LDRS_integer_register:
3866
3867 /* -------- LDR/STR (immediate, SIMD&FP, unsigned offset) -------- */
3868 /* This is the Unsigned offset variant only. The Post-Index and
3869 Pre-Index variants are below.
3870
3871 31 29 23 21 9 4
3872 00 111 101 01 imm12 n t LDR Bt, [Xn|SP + imm12 * 1]
3873 01 111 101 01 imm12 n t LDR Ht, [Xn|SP + imm12 * 2]
3874 10 111 101 01 imm12 n t LDR St, [Xn|SP + imm12 * 4]
3875 11 111 101 01 imm12 n t LDR Dt, [Xn|SP + imm12 * 8]
3876 00 111 101 11 imm12 n t LDR Qt, [Xn|SP + imm12 * 16]
3877
3878 00 111 101 00 imm12 n t STR Bt, [Xn|SP + imm12 * 1]
3879 01 111 101 00 imm12 n t STR Ht, [Xn|SP + imm12 * 2]
3880 10 111 101 00 imm12 n t STR St, [Xn|SP + imm12 * 4]
3881 11 111 101 00 imm12 n t STR Dt, [Xn|SP + imm12 * 8]
3882 00 111 101 10 imm12 n t STR Qt, [Xn|SP + imm12 * 16]
3883 */
3884 if (INSN(29,24) == BITS6(1,1,1,1,0,1)
3885 && ((INSN(23,23) << 2) | INSN(31,30)) <= 4) {
3886 UInt szLg2 = (INSN(23,23) << 2) | INSN(31,30);
3887 Bool isLD = INSN(22,22) == 1;
3888 UInt pimm12 = INSN(21,10) << szLg2;
3889 UInt nn = INSN(9,5);
3890 UInt tt = INSN(4,0);
3891 IRTemp tEA = newTemp(Ity_I64);
3892 IRType ty = preferredVectorSubTypeFromSize(1 << szLg2);
3893 assign(tEA, binop(Iop_Add64, getIReg64orSP(nn), mkU64(pimm12)));
3894 if (isLD) {
3895 if (szLg2 < 4) {
3896 putQReg128(tt, mkV128(0x0000));
3897 }
sewardj606c4ba2014-01-26 19:11:14 +00003898 putQRegLO(tt, loadLE(ty, mkexpr(tEA)));
sewardjbbcf1882014-01-12 12:49:10 +00003899 } else {
sewardj606c4ba2014-01-26 19:11:14 +00003900 storeLE(mkexpr(tEA), getQRegLO(tt, ty));
sewardjbbcf1882014-01-12 12:49:10 +00003901 }
3902 DIP("%s %s, [%s, #%u]\n",
3903 isLD ? "ldr" : "str",
sewardj606c4ba2014-01-26 19:11:14 +00003904 nameQRegLO(tt, ty), nameIReg64orSP(nn), pimm12);
sewardjbbcf1882014-01-12 12:49:10 +00003905 return True;
3906 }
3907
3908 /* -------- LDR/STR (immediate, SIMD&FP, pre/post index) -------- */
3909 /* These are the Post-Index and Pre-Index variants.
3910
3911 31 29 23 20 11 9 4
3912 (at-Rn-then-Rn=EA)
3913 00 111 100 01 0 imm9 01 n t LDR Bt, [Xn|SP], #simm
3914 01 111 100 01 0 imm9 01 n t LDR Ht, [Xn|SP], #simm
3915 10 111 100 01 0 imm9 01 n t LDR St, [Xn|SP], #simm
3916 11 111 100 01 0 imm9 01 n t LDR Dt, [Xn|SP], #simm
3917 00 111 100 11 0 imm9 01 n t LDR Qt, [Xn|SP], #simm
3918
3919 (at-EA-then-Rn=EA)
3920 00 111 100 01 0 imm9 11 n t LDR Bt, [Xn|SP, #simm]!
3921 01 111 100 01 0 imm9 11 n t LDR Ht, [Xn|SP, #simm]!
3922 10 111 100 01 0 imm9 11 n t LDR St, [Xn|SP, #simm]!
3923 11 111 100 01 0 imm9 11 n t LDR Dt, [Xn|SP, #simm]!
3924 00 111 100 11 0 imm9 11 n t LDR Qt, [Xn|SP, #simm]!
3925
3926 Stores are the same except with bit 22 set to 0.
3927 */
3928 if (INSN(29,24) == BITS6(1,1,1,1,0,0)
3929 && ((INSN(23,23) << 2) | INSN(31,30)) <= 4
3930 && INSN(21,21) == 0 && INSN(10,10) == 1) {
3931 UInt szLg2 = (INSN(23,23) << 2) | INSN(31,30);
3932 Bool isLD = INSN(22,22) == 1;
3933 UInt imm9 = INSN(20,12);
3934 Bool atRN = INSN(11,11) == 0;
3935 UInt nn = INSN(9,5);
3936 UInt tt = INSN(4,0);
3937 IRTemp tRN = newTemp(Ity_I64);
3938 IRTemp tEA = newTemp(Ity_I64);
3939 IRTemp tTA = IRTemp_INVALID;
3940 IRType ty = preferredVectorSubTypeFromSize(1 << szLg2);
3941 ULong simm9 = sx_to_64(imm9, 9);
3942 assign(tRN, getIReg64orSP(nn));
3943 assign(tEA, binop(Iop_Add64, mkexpr(tRN), mkU64(simm9)));
3944 tTA = atRN ? tRN : tEA;
3945 if (isLD) {
3946 if (szLg2 < 4) {
3947 putQReg128(tt, mkV128(0x0000));
3948 }
sewardj606c4ba2014-01-26 19:11:14 +00003949 putQRegLO(tt, loadLE(ty, mkexpr(tTA)));
sewardjbbcf1882014-01-12 12:49:10 +00003950 } else {
sewardj606c4ba2014-01-26 19:11:14 +00003951 storeLE(mkexpr(tTA), getQRegLO(tt, ty));
sewardjbbcf1882014-01-12 12:49:10 +00003952 }
3953 putIReg64orSP(nn, mkexpr(tEA));
3954 DIP(atRN ? "%s %s, [%s], #%lld\n" : "%s %s, [%s, #%lld]!\n",
3955 isLD ? "ldr" : "str",
sewardj606c4ba2014-01-26 19:11:14 +00003956 nameQRegLO(tt, ty), nameIReg64orSP(nn), simm9);
sewardjbbcf1882014-01-12 12:49:10 +00003957 return True;
3958 }
3959
3960 /* -------- LDUR/STUR (unscaled offset, SIMD&FP) -------- */
3961 /* 31 29 23 20 11 9 4
3962 00 111 100 01 0 imm9 00 n t LDR Bt, [Xn|SP, #simm]
3963 01 111 100 01 0 imm9 00 n t LDR Ht, [Xn|SP, #simm]
3964 10 111 100 01 0 imm9 00 n t LDR St, [Xn|SP, #simm]
3965 11 111 100 01 0 imm9 00 n t LDR Dt, [Xn|SP, #simm]
3966 00 111 100 11 0 imm9 00 n t LDR Qt, [Xn|SP, #simm]
3967
3968 00 111 100 00 0 imm9 00 n t STR Bt, [Xn|SP, #simm]
3969 01 111 100 00 0 imm9 00 n t STR Ht, [Xn|SP, #simm]
3970 10 111 100 00 0 imm9 00 n t STR St, [Xn|SP, #simm]
3971 11 111 100 00 0 imm9 00 n t STR Dt, [Xn|SP, #simm]
3972 00 111 100 10 0 imm9 00 n t STR Qt, [Xn|SP, #simm]
3973 */
3974 if (INSN(29,24) == BITS6(1,1,1,1,0,0)
3975 && ((INSN(23,23) << 2) | INSN(31,30)) <= 4
3976 && INSN(21,21) == 0 && INSN(11,10) == BITS2(0,0)) {
3977 UInt szLg2 = (INSN(23,23) << 2) | INSN(31,30);
3978 Bool isLD = INSN(22,22) == 1;
3979 UInt imm9 = INSN(20,12);
3980 UInt nn = INSN(9,5);
3981 UInt tt = INSN(4,0);
3982 ULong simm9 = sx_to_64(imm9, 9);
3983 IRTemp tEA = newTemp(Ity_I64);
3984 IRType ty = preferredVectorSubTypeFromSize(1 << szLg2);
3985 assign(tEA, binop(Iop_Add64, getIReg64orSP(nn), mkU64(simm9)));
3986 if (isLD) {
sewardj606c4ba2014-01-26 19:11:14 +00003987 if (szLg2 < 4) {
3988 putQReg128(tt, mkV128(0x0000));
3989 }
3990 putQRegLO(tt, loadLE(ty, mkexpr(tEA)));
sewardjbbcf1882014-01-12 12:49:10 +00003991 } else {
sewardj606c4ba2014-01-26 19:11:14 +00003992 storeLE(mkexpr(tEA), getQRegLO(tt, ty));
sewardjbbcf1882014-01-12 12:49:10 +00003993 }
3994 DIP("%s %s, [%s, #%lld]\n",
3995 isLD ? "ldur" : "stur",
sewardj606c4ba2014-01-26 19:11:14 +00003996 nameQRegLO(tt, ty), nameIReg64orSP(nn), (Long)simm9);
sewardjbbcf1882014-01-12 12:49:10 +00003997 return True;
3998 }
3999
4000 /* ---------------- LDR (literal, SIMD&FP) ---------------- */
4001 /* 31 29 23 4
4002 00 011 100 imm19 t LDR St, [PC + sxTo64(imm19 << 2)]
4003 01 011 100 imm19 t LDR Dt, [PC + sxTo64(imm19 << 2)]
4004 10 011 100 imm19 t LDR Qt, [PC + sxTo64(imm19 << 2)]
4005 */
4006 if (INSN(29,24) == BITS6(0,1,1,1,0,0) && INSN(31,30) < BITS2(1,1)) {
4007 UInt szB = 4 << INSN(31,30);
4008 UInt imm19 = INSN(23,5);
4009 UInt tt = INSN(4,0);
4010 ULong ea = guest_PC_curr_instr + sx_to_64(imm19 << 2, 21);
4011 IRType ty = preferredVectorSubTypeFromSize(szB);
sewardj606c4ba2014-01-26 19:11:14 +00004012 putQReg128(tt, mkV128(0x0000));
4013 putQRegLO(tt, loadLE(ty, mkU64(ea)));
4014 DIP("ldr %s, 0x%llx (literal)\n", nameQRegLO(tt, ty), ea);
sewardjbbcf1882014-01-12 12:49:10 +00004015 return True;
4016 }
4017
sewardj606c4ba2014-01-26 19:11:14 +00004018 /* ---------- LD1/ST1 (single structure, no offset) ---------- */
sewardjbbcf1882014-01-12 12:49:10 +00004019 /* 31 23
sewardj606c4ba2014-01-26 19:11:14 +00004020 0100 1100 0100 0000 0111 11 N T LD1 {vT.2d}, [Xn|SP]
4021 0100 1100 0000 0000 0111 11 N T ST1 {vT.2d}, [Xn|SP]
4022 0100 1100 0100 0000 0111 10 N T LD1 {vT.4s}, [Xn|SP]
4023 0100 1100 0000 0000 0111 10 N T ST1 {vT.4s}, [Xn|SP]
4024 0100 1100 0100 0000 0111 01 N T LD1 {vT.8h}, [Xn|SP]
4025 0100 1100 0000 0000 0111 01 N T ST1 {vT.8h}, [Xn|SP]
sewardjbbcf1882014-01-12 12:49:10 +00004026 0100 1100 0100 0000 0111 00 N T LD1 {vT.16b}, [Xn|SP]
4027 0100 1100 0000 0000 0111 00 N T ST1 {vT.16b}, [Xn|SP]
sewardj606c4ba2014-01-26 19:11:14 +00004028 FIXME does this assume that the host is little endian?
sewardjbbcf1882014-01-12 12:49:10 +00004029 */
sewardj606c4ba2014-01-26 19:11:14 +00004030 if ( (insn & 0xFFFFF000) == 0x4C407000 // LD1 cases
4031 || (insn & 0xFFFFF000) == 0x4C007000 // ST1 cases
sewardjbbcf1882014-01-12 12:49:10 +00004032 ) {
4033 Bool isLD = INSN(22,22) == 1;
4034 UInt rN = INSN(9,5);
4035 UInt vT = INSN(4,0);
4036 IRTemp tEA = newTemp(Ity_I64);
sewardj606c4ba2014-01-26 19:11:14 +00004037 const HChar* names[4] = { "2d", "4s", "8h", "16b" };
4038 const HChar* name = names[INSN(11,10)];
sewardjbbcf1882014-01-12 12:49:10 +00004039 assign(tEA, getIReg64orSP(rN));
4040 if (rN == 31) { /* FIXME generate stack alignment check */ }
4041 if (isLD) {
4042 putQReg128(vT, loadLE(Ity_V128, mkexpr(tEA)));
4043 } else {
4044 storeLE(mkexpr(tEA), getQReg128(vT));
4045 }
4046 DIP("%s {v%u.%s}, [%s]\n", isLD ? "ld1" : "st1",
sewardj606c4ba2014-01-26 19:11:14 +00004047 vT, name, nameIReg64orSP(rN));
sewardjbbcf1882014-01-12 12:49:10 +00004048 return True;
4049 }
4050
sewardj606c4ba2014-01-26 19:11:14 +00004051 /* 31 23
4052 0000 1100 0100 0000 0111 11 N T LD1 {vT.1d}, [Xn|SP]
4053 0000 1100 0000 0000 0111 11 N T ST1 {vT.1d}, [Xn|SP]
4054 0000 1100 0100 0000 0111 10 N T LD1 {vT.2s}, [Xn|SP]
4055 0000 1100 0000 0000 0111 10 N T ST1 {vT.2s}, [Xn|SP]
4056 0000 1100 0100 0000 0111 01 N T LD1 {vT.4h}, [Xn|SP]
4057 0000 1100 0000 0000 0111 01 N T ST1 {vT.4h}, [Xn|SP]
4058 0000 1100 0100 0000 0111 00 N T LD1 {vT.8b}, [Xn|SP]
4059 0000 1100 0000 0000 0111 00 N T ST1 {vT.8b}, [Xn|SP]
4060 FIXME does this assume that the host is little endian?
4061 */
4062 if ( (insn & 0xFFFFF000) == 0x0C407000 // LD1 cases
4063 || (insn & 0xFFFFF000) == 0x0C007000 // ST1 cases
4064 ) {
4065 Bool isLD = INSN(22,22) == 1;
4066 UInt rN = INSN(9,5);
4067 UInt vT = INSN(4,0);
4068 IRTemp tEA = newTemp(Ity_I64);
4069 const HChar* names[4] = { "1d", "2s", "4h", "8b" };
4070 const HChar* name = names[INSN(11,10)];
4071 assign(tEA, getIReg64orSP(rN));
4072 if (rN == 31) { /* FIXME generate stack alignment check */ }
4073 if (isLD) {
4074 putQRegLane(vT, 0, loadLE(Ity_I64, mkexpr(tEA)));
4075 putQRegLane(vT, 1, mkU64(0));
4076 } else {
4077 storeLE(mkexpr(tEA), getQRegLane(vT, 0, Ity_I64));
4078 }
4079 DIP("%s {v%u.%s}, [%s]\n", isLD ? "ld1" : "st1",
4080 vT, name, nameIReg64orSP(rN));
4081 return True;
4082 }
4083
4084 /* ---------- LD1/ST1 (single structure, post index) ---------- */
4085 /* 31 23
sewardj7d009132014-02-20 17:43:38 +00004086 0100 1100 1001 1111 0111 11 N T ST1 {vT.2d}, [xN|SP], #16
4087 0100 1100 1101 1111 0111 11 N T LD1 {vT.2d}, [xN|SP], #16
4088 0100 1100 1001 1111 0111 10 N T ST1 {vT.4s}, [xN|SP], #16
4089 0100 1100 1101 1111 0111 10 N T LD1 {vT.4s}, [xN|SP], #16
4090 0100 1100 1001 1111 0111 01 N T ST1 {vT.8h}, [xN|SP], #16
4091 0100 1100 1101 1111 0111 01 N T LD1 {vT.8h}, [xN|SP], #16
4092 0100 1100 1001 1111 0111 00 N T ST1 {vT.16b}, [xN|SP], #16
sewardjf5b08912014-02-06 12:57:58 +00004093 0100 1100 1101 1111 0111 00 N T LD1 {vT.16b}, [xN|SP], #16
sewardj606c4ba2014-01-26 19:11:14 +00004094 Note that #16 is implied and cannot be any other value.
4095 FIXME does this assume that the host is little endian?
4096 */
sewardj7d009132014-02-20 17:43:38 +00004097 if ( (insn & 0xFFFFF000) == 0x4CDF7000 // LD1 cases
4098 || (insn & 0xFFFFF000) == 0x4C9F7000 // ST1 cases
sewardj606c4ba2014-01-26 19:11:14 +00004099 ) {
4100 Bool isLD = INSN(22,22) == 1;
4101 UInt rN = INSN(9,5);
4102 UInt vT = INSN(4,0);
4103 IRTemp tEA = newTemp(Ity_I64);
4104 const HChar* names[4] = { "2d", "4s", "8h", "16b" };
4105 const HChar* name = names[INSN(11,10)];
4106 assign(tEA, getIReg64orSP(rN));
4107 if (rN == 31) { /* FIXME generate stack alignment check */ }
4108 if (isLD) {
4109 putQReg128(vT, loadLE(Ity_V128, mkexpr(tEA)));
4110 } else {
4111 storeLE(mkexpr(tEA), getQReg128(vT));
4112 }
4113 putIReg64orSP(rN, binop(Iop_Add64, mkexpr(tEA), mkU64(16)));
4114 DIP("%s {v%u.%s}, [%s], #16\n", isLD ? "ld1" : "st1",
4115 vT, name, nameIReg64orSP(rN));
4116 return True;
4117 }
4118
4119 /*
4120 0000 1100 1001 1111 0111 10 N T ST1 {vT.2s}, [xN|SP], #8
sewardjf5b08912014-02-06 12:57:58 +00004121 0000 1100 1001 1111 0111 01 N T ST1 {vT.4h}, [xN|SP], #8
sewardj606c4ba2014-01-26 19:11:14 +00004122 Note that #8 is implied and cannot be any other value.
4123 FIXME does this assume that the host is little endian?
4124 */
4125 if ( (insn & 0xFFFFFC00) == 0x0C9F7800 // st1 {vT.2s}, [xN|SP], #8
sewardjf5b08912014-02-06 12:57:58 +00004126 || (insn & 0xFFFFFC00) == 0x0C9F7400 // st1 {vT.4h}, [xN|SP], #8
sewardj606c4ba2014-01-26 19:11:14 +00004127 ) {
4128 UInt rN = INSN(9,5);
4129 UInt vT = INSN(4,0);
4130 IRTemp tEA = newTemp(Ity_I64);
4131 const HChar* names[4] = { "1d", "2s", "4h", "8b" };
4132 const HChar* name = names[INSN(11,10)];
4133 assign(tEA, getIReg64orSP(rN));
4134 if (rN == 31) { /* FIXME generate stack alignment check */ }
4135 storeLE(mkexpr(tEA), getQRegLane(vT, 0, Ity_I64));
4136 putIReg64orSP(rN, binop(Iop_Add64, mkexpr(tEA), mkU64(8)));
4137 DIP("st1 {v%u.%s}, [%s], #8\n", vT, name, nameIReg64orSP(rN));
4138 return True;
4139 }
4140
sewardj7d009132014-02-20 17:43:38 +00004141 /* ------------------ LD{,A}X{R,RH,RB} ------------------ */
4142 /* ------------------ ST{,L}X{R,RH,RB} ------------------ */
4143 /* 31 29 23 20 14 9 4
4144 sz 001000 010 11111 0 11111 n t LDX{R,RH,RB} Rt, [Xn|SP]
4145 sz 001000 010 11111 1 11111 n t LDAX{R,RH,RB} Rt, [Xn|SP]
4146 sz 001000 000 s 0 11111 n t STX{R,RH,RB} Ws, Rt, [Xn|SP]
4147 sz 001000 000 s 1 11111 n t STLX{R,RH,RB} Ws, Rt, [Xn|SP]
sewardjbbcf1882014-01-12 12:49:10 +00004148 */
sewardj7d009132014-02-20 17:43:38 +00004149 if (INSN(29,23) == BITS7(0,0,1,0,0,0,0)
4150 && (INSN(23,21) & BITS3(1,0,1)) == BITS3(0,0,0)
4151 && INSN(14,10) == BITS5(1,1,1,1,1)) {
sewardjdc9259c2014-02-27 11:10:19 +00004152 UInt szBlg2 = INSN(31,30);
4153 Bool isLD = INSN(22,22) == 1;
4154 Bool isAcqOrRel = INSN(15,15) == 1;
4155 UInt ss = INSN(20,16);
4156 UInt nn = INSN(9,5);
4157 UInt tt = INSN(4,0);
sewardjbbcf1882014-01-12 12:49:10 +00004158
sewardjdc9259c2014-02-27 11:10:19 +00004159 vassert(szBlg2 < 4);
4160 UInt szB = 1 << szBlg2; /* 1, 2, 4 or 8 */
4161 IRType ty = integerIRTypeOfSize(szB);
4162 const HChar* suffix[4] = { "rb", "rh", "r", "r" };
sewardj7d009132014-02-20 17:43:38 +00004163
sewardjdc9259c2014-02-27 11:10:19 +00004164 IRTemp ea = newTemp(Ity_I64);
4165 assign(ea, getIReg64orSP(nn));
4166 /* FIXME generate check that ea is szB-aligned */
sewardj7d009132014-02-20 17:43:38 +00004167
sewardjdc9259c2014-02-27 11:10:19 +00004168 if (isLD && ss == BITS5(1,1,1,1,1)) {
4169 IRTemp res = newTemp(ty);
4170 stmt(IRStmt_LLSC(Iend_LE, res, mkexpr(ea), NULL/*LL*/));
4171 putIReg64orZR(tt, widenUto64(ty, mkexpr(res)));
4172 if (isAcqOrRel) {
4173 stmt(IRStmt_MBE(Imbe_Fence));
4174 }
4175 DIP("ld%sx%s %s, [%s]\n", isAcqOrRel ? "a" : "", suffix[szBlg2],
4176 nameIRegOrZR(szB == 8, tt), nameIReg64orSP(nn));
4177 return True;
4178 }
4179 if (!isLD) {
4180 if (isAcqOrRel) {
4181 stmt(IRStmt_MBE(Imbe_Fence));
4182 }
4183 IRTemp res = newTemp(Ity_I1);
4184 IRExpr* data = narrowFrom64(ty, getIReg64orZR(tt));
4185 stmt(IRStmt_LLSC(Iend_LE, res, mkexpr(ea), data));
4186 /* IR semantics: res is 1 if store succeeds, 0 if it fails.
4187 Need to set rS to 1 on failure, 0 on success. */
4188 putIReg64orZR(ss, binop(Iop_Xor64, unop(Iop_1Uto64, mkexpr(res)),
4189 mkU64(1)));
4190 DIP("st%sx%s %s, %s, [%s]\n", isAcqOrRel ? "a" : "", suffix[szBlg2],
4191 nameIRegOrZR(False, ss),
4192 nameIRegOrZR(szB == 8, tt), nameIReg64orSP(nn));
4193 return True;
4194 }
4195 /* else fall through */
4196 }
4197
4198 /* ------------------ LDA{R,RH,RB} ------------------ */
4199 /* ------------------ STL{R,RH,RB} ------------------ */
4200 /* 31 29 23 20 14 9 4
4201 sz 001000 110 11111 1 11111 n t LDAR<sz> Rt, [Xn|SP]
4202 sz 001000 100 11111 1 11111 n t STLR<sz> Rt, [Xn|SP]
4203 */
4204 if (INSN(29,23) == BITS7(0,0,1,0,0,0,1)
4205 && INSN(21,10) == BITS12(0,1,1,1,1,1,1,1,1,1,1,1)) {
4206 UInt szBlg2 = INSN(31,30);
4207 Bool isLD = INSN(22,22) == 1;
4208 UInt nn = INSN(9,5);
4209 UInt tt = INSN(4,0);
4210
4211 vassert(szBlg2 < 4);
4212 UInt szB = 1 << szBlg2; /* 1, 2, 4 or 8 */
4213 IRType ty = integerIRTypeOfSize(szB);
4214 const HChar* suffix[4] = { "rb", "rh", "r", "r" };
4215
4216 IRTemp ea = newTemp(Ity_I64);
4217 assign(ea, getIReg64orSP(nn));
4218 /* FIXME generate check that ea is szB-aligned */
4219
4220 if (isLD) {
4221 IRTemp res = newTemp(ty);
4222 assign(res, loadLE(ty, mkexpr(ea)));
4223 putIReg64orZR(tt, widenUto64(ty, mkexpr(res)));
4224 stmt(IRStmt_MBE(Imbe_Fence));
4225 DIP("lda%s %s, [%s]\n", suffix[szBlg2],
4226 nameIRegOrZR(szB == 8, tt), nameIReg64orSP(nn));
4227 } else {
4228 stmt(IRStmt_MBE(Imbe_Fence));
4229 IRExpr* data = narrowFrom64(ty, getIReg64orZR(tt));
4230 storeLE(mkexpr(ea), data);
4231 DIP("stl%s %s, [%s]\n", suffix[szBlg2],
4232 nameIRegOrZR(szB == 8, tt), nameIReg64orSP(nn));
4233 }
4234 return True;
sewardjbbcf1882014-01-12 12:49:10 +00004235 }
4236
4237 vex_printf("ARM64 front end: load_store\n");
4238 return False;
4239# undef INSN
4240}
4241
4242
4243/*------------------------------------------------------------*/
4244/*--- Control flow and misc instructions ---*/
4245/*------------------------------------------------------------*/
4246
4247static
4248Bool dis_ARM64_branch_etc(/*MB_OUT*/DisResult* dres, UInt insn)
4249{
4250# define INSN(_bMax,_bMin) SLICE_UInt(insn, (_bMax), (_bMin))
4251
4252 /* ---------------------- B cond ----------------------- */
4253 /* 31 24 4 3
4254 0101010 0 imm19 0 cond */
4255 if (INSN(31,24) == BITS8(0,1,0,1,0,1,0,0) && INSN(4,4) == 0) {
4256 UInt cond = INSN(3,0);
4257 ULong uimm64 = INSN(23,5) << 2;
4258 Long simm64 = (Long)sx_to_64(uimm64, 21);
4259 vassert(dres->whatNext == Dis_Continue);
4260 vassert(dres->len == 4);
4261 vassert(dres->continueAt == 0);
4262 vassert(dres->jk_StopHere == Ijk_INVALID);
4263 stmt( IRStmt_Exit(unop(Iop_64to1, mk_arm64g_calculate_condition(cond)),
4264 Ijk_Boring,
4265 IRConst_U64(guest_PC_curr_instr + simm64),
4266 OFFB_PC) );
4267 putPC(mkU64(guest_PC_curr_instr + 4));
4268 dres->whatNext = Dis_StopHere;
4269 dres->jk_StopHere = Ijk_Boring;
4270 DIP("b.%s 0x%llx\n", nameCC(cond), guest_PC_curr_instr + simm64);
4271 return True;
4272 }
4273
4274 /* -------------------- B{L} uncond -------------------- */
4275 if (INSN(30,26) == BITS5(0,0,1,0,1)) {
4276 /* 000101 imm26 B (PC + sxTo64(imm26 << 2))
4277 100101 imm26 B (PC + sxTo64(imm26 << 2))
4278 */
4279 UInt bLink = INSN(31,31);
4280 ULong uimm64 = INSN(25,0) << 2;
4281 Long simm64 = (Long)sx_to_64(uimm64, 28);
4282 if (bLink) {
4283 putIReg64orSP(30, mkU64(guest_PC_curr_instr + 4));
4284 }
4285 putPC(mkU64(guest_PC_curr_instr + simm64));
4286 dres->whatNext = Dis_StopHere;
4287 dres->jk_StopHere = Ijk_Call;
4288 DIP("b%s 0x%llx\n", bLink == 1 ? "l" : "",
4289 guest_PC_curr_instr + simm64);
4290 return True;
4291 }
4292
4293 /* --------------------- B{L} reg --------------------- */
4294 /* 31 24 22 20 15 9 4
4295 1101011 00 10 11111 000000 nn 00000 RET Rn
4296 1101011 00 01 11111 000000 nn 00000 CALL Rn
4297 1101011 00 00 11111 000000 nn 00000 JMP Rn
4298 */
4299 if (INSN(31,23) == BITS9(1,1,0,1,0,1,1,0,0)
4300 && INSN(20,16) == BITS5(1,1,1,1,1)
4301 && INSN(15,10) == BITS6(0,0,0,0,0,0)
4302 && INSN(4,0) == BITS5(0,0,0,0,0)) {
4303 UInt branch_type = INSN(22,21);
4304 UInt nn = INSN(9,5);
4305 if (branch_type == BITS2(1,0) /* RET */) {
4306 putPC(getIReg64orZR(nn));
4307 dres->whatNext = Dis_StopHere;
4308 dres->jk_StopHere = Ijk_Ret;
4309 DIP("ret %s\n", nameIReg64orZR(nn));
4310 return True;
4311 }
4312 if (branch_type == BITS2(0,1) /* CALL */) {
4313 putIReg64orSP(30, mkU64(guest_PC_curr_instr + 4));
4314 putPC(getIReg64orZR(nn));
4315 dres->whatNext = Dis_StopHere;
4316 dres->jk_StopHere = Ijk_Call;
4317 DIP("blr %s\n", nameIReg64orZR(nn));
4318 return True;
4319 }
4320 if (branch_type == BITS2(0,0) /* JMP */) {
4321 putPC(getIReg64orZR(nn));
4322 dres->whatNext = Dis_StopHere;
4323 dres->jk_StopHere = Ijk_Boring;
4324 DIP("jmp %s\n", nameIReg64orZR(nn));
4325 return True;
4326 }
4327 }
4328
4329 /* -------------------- CB{N}Z -------------------- */
4330 /* sf 011 010 1 imm19 Rt CBNZ Xt|Wt, (PC + sxTo64(imm19 << 2))
4331 sf 011 010 0 imm19 Rt CBZ Xt|Wt, (PC + sxTo64(imm19 << 2))
4332 */
4333 if (INSN(30,25) == BITS6(0,1,1,0,1,0)) {
4334 Bool is64 = INSN(31,31) == 1;
4335 Bool bIfZ = INSN(24,24) == 0;
4336 ULong uimm64 = INSN(23,5) << 2;
4337 UInt rT = INSN(4,0);
4338 Long simm64 = (Long)sx_to_64(uimm64, 21);
4339 IRExpr* cond = NULL;
4340 if (is64) {
4341 cond = binop(bIfZ ? Iop_CmpEQ64 : Iop_CmpNE64,
4342 getIReg64orZR(rT), mkU64(0));
4343 } else {
4344 cond = binop(bIfZ ? Iop_CmpEQ32 : Iop_CmpNE32,
4345 getIReg32orZR(rT), mkU32(0));
4346 }
4347 stmt( IRStmt_Exit(cond,
4348 Ijk_Boring,
4349 IRConst_U64(guest_PC_curr_instr + simm64),
4350 OFFB_PC) );
4351 putPC(mkU64(guest_PC_curr_instr + 4));
4352 dres->whatNext = Dis_StopHere;
4353 dres->jk_StopHere = Ijk_Boring;
4354 DIP("cb%sz %s, 0x%llx\n",
4355 bIfZ ? "" : "n", nameIRegOrZR(is64, rT),
4356 guest_PC_curr_instr + simm64);
4357 return True;
4358 }
4359
4360 /* -------------------- TB{N}Z -------------------- */
4361 /* 31 30 24 23 18 5 4
4362 b5 011 011 1 b40 imm14 t TBNZ Xt, #(b5:b40), (PC + sxTo64(imm14 << 2))
4363 b5 011 011 0 b40 imm14 t TBZ Xt, #(b5:b40), (PC + sxTo64(imm14 << 2))
4364 */
4365 if (INSN(30,25) == BITS6(0,1,1,0,1,1)) {
4366 UInt b5 = INSN(31,31);
4367 Bool bIfZ = INSN(24,24) == 0;
4368 UInt b40 = INSN(23,19);
4369 UInt imm14 = INSN(18,5);
4370 UInt tt = INSN(4,0);
4371 UInt bitNo = (b5 << 5) | b40;
4372 ULong uimm64 = imm14 << 2;
4373 Long simm64 = sx_to_64(uimm64, 16);
4374 IRExpr* cond
4375 = binop(bIfZ ? Iop_CmpEQ64 : Iop_CmpNE64,
4376 binop(Iop_And64,
4377 binop(Iop_Shr64, getIReg64orZR(tt), mkU8(bitNo)),
4378 mkU64(1)),
4379 mkU64(0));
4380 stmt( IRStmt_Exit(cond,
4381 Ijk_Boring,
4382 IRConst_U64(guest_PC_curr_instr + simm64),
4383 OFFB_PC) );
4384 putPC(mkU64(guest_PC_curr_instr + 4));
4385 dres->whatNext = Dis_StopHere;
4386 dres->jk_StopHere = Ijk_Boring;
4387 DIP("tb%sz %s, #%u, 0x%llx\n",
4388 bIfZ ? "" : "n", nameIReg64orZR(tt), bitNo,
4389 guest_PC_curr_instr + simm64);
4390 return True;
4391 }
4392
4393 /* -------------------- SVC -------------------- */
4394 /* 11010100 000 imm16 000 01
4395 Don't bother with anything except the imm16==0 case.
4396 */
4397 if (INSN(31,0) == 0xD4000001) {
4398 putPC(mkU64(guest_PC_curr_instr + 4));
4399 dres->whatNext = Dis_StopHere;
4400 dres->jk_StopHere = Ijk_Sys_syscall;
4401 DIP("svc #0\n");
4402 return True;
4403 }
4404
4405 /* ------------------ M{SR,RS} ------------------ */
4406 /* Only handles the case where the system register is TPIDR_EL0.
4407 0xD51BD0 010 Rt MSR tpidr_el0, rT
4408 0xD53BD0 010 Rt MRS rT, tpidr_el0
4409 */
4410 if ( (INSN(31,0) & 0xFFFFFFE0) == 0xD51BD040 /*MSR*/
4411 || (INSN(31,0) & 0xFFFFFFE0) == 0xD53BD040 /*MRS*/) {
4412 Bool toSys = INSN(21,21) == 0;
4413 UInt tt = INSN(4,0);
4414 if (toSys) {
4415 stmt( IRStmt_Put( OFFB_TPIDR_EL0, getIReg64orZR(tt)) );
4416 DIP("msr tpidr_el0, %s\n", nameIReg64orZR(tt));
4417 } else {
4418 putIReg64orZR(tt, IRExpr_Get( OFFB_TPIDR_EL0, Ity_I64 ));
4419 DIP("mrs %s, tpidr_el0\n", nameIReg64orZR(tt));
4420 }
4421 return True;
4422 }
4423 /* Cases for FPCR
4424 0xD51B44 000 Rt MSR fpcr, rT
4425 0xD53B44 000 Rt MSR rT, fpcr
4426 */
4427 if ( (INSN(31,0) & 0xFFFFFFE0) == 0xD51B4400 /*MSR*/
4428 || (INSN(31,0) & 0xFFFFFFE0) == 0xD53B4400 /*MRS*/) {
4429 Bool toSys = INSN(21,21) == 0;
4430 UInt tt = INSN(4,0);
4431 if (toSys) {
4432 stmt( IRStmt_Put( OFFB_FPCR, getIReg32orZR(tt)) );
4433 DIP("msr fpcr, %s\n", nameIReg64orZR(tt));
4434 } else {
4435 putIReg32orZR(tt, IRExpr_Get(OFFB_FPCR, Ity_I32));
4436 DIP("mrs %s, fpcr\n", nameIReg64orZR(tt));
4437 }
4438 return True;
4439 }
4440 /* Cases for FPSR
sewardj7d009132014-02-20 17:43:38 +00004441 0xD51B44 001 Rt MSR fpsr, rT
4442 0xD53B44 001 Rt MSR rT, fpsr
sewardjbbcf1882014-01-12 12:49:10 +00004443 */
4444 if ( (INSN(31,0) & 0xFFFFFFE0) == 0xD51B4420 /*MSR*/
4445 || (INSN(31,0) & 0xFFFFFFE0) == 0xD53B4420 /*MRS*/) {
4446 Bool toSys = INSN(21,21) == 0;
4447 UInt tt = INSN(4,0);
4448 if (toSys) {
4449 stmt( IRStmt_Put( OFFB_FPSR, getIReg32orZR(tt)) );
4450 DIP("msr fpsr, %s\n", nameIReg64orZR(tt));
4451 } else {
4452 putIReg32orZR(tt, IRExpr_Get(OFFB_FPSR, Ity_I32));
4453 DIP("mrs %s, fpsr\n", nameIReg64orZR(tt));
4454 }
4455 return True;
4456 }
4457 /* Cases for NZCV
4458 D51B42 000 Rt MSR nzcv, rT
4459 D53B42 000 Rt MRS rT, nzcv
4460 */
4461 if ( (INSN(31,0) & 0xFFFFFFE0) == 0xD51B4200 /*MSR*/
4462 || (INSN(31,0) & 0xFFFFFFE0) == 0xD53B4200 /*MRS*/) {
4463 Bool toSys = INSN(21,21) == 0;
4464 UInt tt = INSN(4,0);
4465 if (toSys) {
4466 IRTemp t = newTemp(Ity_I64);
4467 assign(t, binop(Iop_And64, getIReg64orZR(tt), mkU64(0xF0000000ULL)));
4468 setFlags_COPY(t);
4469 DIP("msr %s, nzcv\n", nameIReg32orZR(tt));
4470 } else {
4471 IRTemp res = newTemp(Ity_I64);
4472 assign(res, mk_arm64g_calculate_flags_nzcv());
4473 putIReg32orZR(tt, unop(Iop_64to32, mkexpr(res)));
4474 DIP("mrs %s, nzcv\n", nameIReg64orZR(tt));
4475 }
4476 return True;
4477 }
sewardjd512d102014-02-21 14:49:44 +00004478 /* Cases for DCZID_EL0
4479 Don't support arbitrary reads and writes to this register. Just
4480 return the value 16, which indicates that the DC ZVA instruction
4481 is not permitted, so we don't have to emulate it.
4482 D5 3B 00 111 Rt MRS rT, dczid_el0
4483 */
4484 if ((INSN(31,0) & 0xFFFFFFE0) == 0xD53B00E0) {
4485 UInt tt = INSN(4,0);
4486 putIReg64orZR(tt, mkU64(1<<4));
4487 DIP("mrs %s, dczid_el0 (FAKED)\n", nameIReg64orZR(tt));
4488 return True;
4489 }
sewardjbbcf1882014-01-12 12:49:10 +00004490
sewardjd512d102014-02-21 14:49:44 +00004491 /* ------------------ ISB, DSB ------------------ */
sewardjbbcf1882014-01-12 12:49:10 +00004492 if (INSN(31,0) == 0xD5033FDF) {
sewardjd512d102014-02-21 14:49:44 +00004493 stmt(IRStmt_MBE(Imbe_Fence));
sewardjbbcf1882014-01-12 12:49:10 +00004494 DIP("isb\n");
4495 return True;
4496 }
4497 if (INSN(31,0) == 0xD5033BBF) {
sewardjd512d102014-02-21 14:49:44 +00004498 stmt(IRStmt_MBE(Imbe_Fence));
sewardjbbcf1882014-01-12 12:49:10 +00004499 DIP("dmb ish\n");
4500 return True;
4501 }
4502
sewardjdc9259c2014-02-27 11:10:19 +00004503 /* -------------------- NOP -------------------- */
4504 if (INSN(31,0) == 0xD503201F) {
4505 DIP("nop\n");
4506 return True;
4507 }
4508
sewardjbbcf1882014-01-12 12:49:10 +00004509 //fail:
4510 vex_printf("ARM64 front end: branch_etc\n");
4511 return False;
4512# undef INSN
4513}
4514
4515
4516/*------------------------------------------------------------*/
4517/*--- SIMD and FP instructions ---*/
4518/*------------------------------------------------------------*/
4519
sewardjecde6972014-02-05 11:01:19 +00004520/* begin FIXME -- rm temp scaffolding */
4521static IRExpr* mk_CatEvenLanes64x2 ( IRTemp, IRTemp );
4522static IRExpr* mk_CatOddLanes64x2 ( IRTemp, IRTemp );
sewardje520bb32014-02-17 11:00:53 +00004523
sewardjecde6972014-02-05 11:01:19 +00004524static IRExpr* mk_CatEvenLanes32x4 ( IRTemp, IRTemp );
4525static IRExpr* mk_CatOddLanes32x4 ( IRTemp, IRTemp );
sewardje520bb32014-02-17 11:00:53 +00004526static IRExpr* mk_InterleaveLO32x4 ( IRTemp, IRTemp );
4527static IRExpr* mk_InterleaveHI32x4 ( IRTemp, IRTemp );
4528
sewardjecde6972014-02-05 11:01:19 +00004529static IRExpr* mk_CatEvenLanes16x8 ( IRTemp, IRTemp );
4530static IRExpr* mk_CatOddLanes16x8 ( IRTemp, IRTemp );
sewardje520bb32014-02-17 11:00:53 +00004531static IRExpr* mk_InterleaveLO16x8 ( IRTemp, IRTemp );
4532static IRExpr* mk_InterleaveHI16x8 ( IRTemp, IRTemp );
4533
sewardjfab09142014-02-10 10:28:13 +00004534static IRExpr* mk_CatEvenLanes8x16 ( IRTemp, IRTemp );
4535static IRExpr* mk_CatOddLanes8x16 ( IRTemp, IRTemp );
sewardje520bb32014-02-17 11:00:53 +00004536static IRExpr* mk_InterleaveLO8x16 ( IRTemp, IRTemp );
4537static IRExpr* mk_InterleaveHI8x16 ( IRTemp, IRTemp );
sewardjecde6972014-02-05 11:01:19 +00004538/* end FIXME -- rm temp scaffolding */
4539
sewardjbbcf1882014-01-12 12:49:10 +00004540/* Generate N copies of |bit| in the bottom of a ULong. */
4541static ULong Replicate ( ULong bit, Int N )
4542{
sewardj606c4ba2014-01-26 19:11:14 +00004543 vassert(bit <= 1 && N >= 1 && N < 64);
4544 if (bit == 0) {
4545 return 0;
4546 } else {
4547 /* Careful. This won't work for N == 64. */
4548 return (1ULL << N) - 1;
4549 }
sewardjbbcf1882014-01-12 12:49:10 +00004550}
4551
sewardjfab09142014-02-10 10:28:13 +00004552static ULong Replicate32x2 ( ULong bits32 )
4553{
4554 vassert(0 == (bits32 & ~0xFFFFFFFFULL));
4555 return (bits32 << 32) | bits32;
4556}
4557
4558static ULong Replicate16x4 ( ULong bits16 )
4559{
4560 vassert(0 == (bits16 & ~0xFFFFULL));
4561 return Replicate32x2((bits16 << 16) | bits16);
4562}
4563
4564static ULong Replicate8x8 ( ULong bits8 )
4565{
4566 vassert(0 == (bits8 & ~0xFFULL));
4567 return Replicate16x4((bits8 << 8) | bits8);
4568}
4569
4570/* Expand the VFPExpandImm-style encoding in the bottom 8 bits of
4571 |imm8| to either a 32-bit value if N is 32 or a 64 bit value if N
4572 is 64. In the former case, the upper 32 bits of the returned value
4573 are guaranteed to be zero. */
sewardjbbcf1882014-01-12 12:49:10 +00004574static ULong VFPExpandImm ( ULong imm8, Int N )
4575{
sewardj606c4ba2014-01-26 19:11:14 +00004576 vassert(imm8 <= 0xFF);
4577 vassert(N == 32 || N == 64);
4578 Int E = ((N == 32) ? 8 : 11) - 2; // The spec incorrectly omits the -2.
4579 Int F = N - E - 1;
4580 ULong imm8_6 = (imm8 >> 6) & 1;
4581 /* sign: 1 bit */
4582 /* exp: E bits */
4583 /* frac: F bits */
4584 ULong sign = (imm8 >> 7) & 1;
4585 ULong exp = ((imm8_6 ^ 1) << (E-1)) | Replicate(imm8_6, E-1);
4586 ULong frac = ((imm8 & 63) << (F-6)) | Replicate(0, F-6);
4587 vassert(sign < (1ULL << 1));
4588 vassert(exp < (1ULL << E));
4589 vassert(frac < (1ULL << F));
4590 vassert(1 + E + F == N);
4591 ULong res = (sign << (E+F)) | (exp << F) | frac;
4592 return res;
sewardjbbcf1882014-01-12 12:49:10 +00004593}
4594
sewardjfab09142014-02-10 10:28:13 +00004595/* Expand an AdvSIMDExpandImm-style encoding into a 64-bit value.
4596 This might fail, as indicated by the returned Bool. Page 2530 of
4597 the manual. */
4598static Bool AdvSIMDExpandImm ( /*OUT*/ULong* res,
4599 UInt op, UInt cmode, UInt imm8 )
4600{
4601 vassert(op <= 1);
4602 vassert(cmode <= 15);
4603 vassert(imm8 <= 255);
4604
4605 *res = 0; /* will overwrite iff returning True */
4606
4607 ULong imm64 = 0;
4608 Bool testimm8 = False;
4609
4610 switch (cmode >> 1) {
4611 case 0:
4612 testimm8 = False; imm64 = Replicate32x2(imm8); break;
4613 case 1:
4614 testimm8 = True; imm64 = Replicate32x2(imm8 << 8); break;
4615 case 2:
4616 testimm8 = True; imm64 = Replicate32x2(imm8 << 16); break;
4617 case 3:
4618 testimm8 = True; imm64 = Replicate32x2(imm8 << 24); break;
4619 case 4:
4620 testimm8 = False; imm64 = Replicate16x4(imm8); break;
4621 case 5:
4622 testimm8 = True; imm64 = Replicate16x4(imm8 << 8); break;
4623 case 6:
4624 testimm8 = True;
4625 if ((cmode & 1) == 0)
4626 imm64 = Replicate32x2((imm8 << 8) | 0xFF);
4627 else
4628 imm64 = Replicate32x2((imm8 << 16) | 0xFFFF);
4629 break;
4630 case 7:
4631 testimm8 = False;
4632 if ((cmode & 1) == 0 && op == 0)
4633 imm64 = Replicate8x8(imm8);
4634 if ((cmode & 1) == 0 && op == 1) {
4635 imm64 = 0; imm64 |= (imm8 & 0x80) ? 0xFF : 0x00;
4636 imm64 <<= 8; imm64 |= (imm8 & 0x40) ? 0xFF : 0x00;
4637 imm64 <<= 8; imm64 |= (imm8 & 0x20) ? 0xFF : 0x00;
4638 imm64 <<= 8; imm64 |= (imm8 & 0x10) ? 0xFF : 0x00;
4639 imm64 <<= 8; imm64 |= (imm8 & 0x08) ? 0xFF : 0x00;
4640 imm64 <<= 8; imm64 |= (imm8 & 0x04) ? 0xFF : 0x00;
4641 imm64 <<= 8; imm64 |= (imm8 & 0x02) ? 0xFF : 0x00;
4642 imm64 <<= 8; imm64 |= (imm8 & 0x01) ? 0xFF : 0x00;
4643 }
4644 if ((cmode & 1) == 1 && op == 0) {
4645 ULong imm8_7 = (imm8 >> 7) & 1;
4646 ULong imm8_6 = (imm8 >> 6) & 1;
4647 ULong imm8_50 = imm8 & 63;
4648 ULong imm32 = (imm8_7 << (1 + 5 + 6 + 19))
4649 | ((imm8_6 ^ 1) << (5 + 6 + 19))
4650 | (Replicate(imm8_6, 5) << (6 + 19))
4651 | (imm8_50 << 19);
4652 imm64 = Replicate32x2(imm32);
4653 }
4654 if ((cmode & 1) == 1 && op == 1) {
4655 // imm64 = imm8<7>:NOT(imm8<6>)
4656 // :Replicate(imm8<6>,8):imm8<5:0>:Zeros(48);
4657 ULong imm8_7 = (imm8 >> 7) & 1;
4658 ULong imm8_6 = (imm8 >> 6) & 1;
4659 ULong imm8_50 = imm8 & 63;
4660 imm64 = (imm8_7 << 63) | ((imm8_6 ^ 1) << 62)
4661 | (Replicate(imm8_6, 8) << 54)
4662 | (imm8_50 << 48);
4663 }
4664 break;
4665 default:
4666 vassert(0);
4667 }
4668
4669 if (testimm8 && imm8 == 0)
4670 return False;
4671
4672 *res = imm64;
4673 return True;
4674}
4675
4676
sewardj606c4ba2014-01-26 19:11:14 +00004677/* Help a bit for decoding laneage for vector operations that can be
4678 of the form 4x32, 2x64 or 2x32-and-zero-upper-half, as encoded by Q
4679 and SZ bits, typically for vector floating point. */
4680static Bool getLaneInfo_Q_SZ ( /*OUT*/IRType* tyI, /*OUT*/IRType* tyF,
4681 /*OUT*/UInt* nLanes, /*OUT*/Bool* zeroUpper,
4682 /*OUT*/const HChar** arrSpec,
4683 Bool bitQ, Bool bitSZ )
4684{
4685 vassert(bitQ == True || bitQ == False);
4686 vassert(bitSZ == True || bitSZ == False);
4687 if (bitQ && bitSZ) { // 2x64
4688 if (tyI) *tyI = Ity_I64;
4689 if (tyF) *tyF = Ity_F64;
4690 if (nLanes) *nLanes = 2;
4691 if (zeroUpper) *zeroUpper = False;
4692 if (arrSpec) *arrSpec = "2d";
4693 return True;
4694 }
4695 if (bitQ && !bitSZ) { // 4x32
4696 if (tyI) *tyI = Ity_I32;
4697 if (tyF) *tyF = Ity_F32;
4698 if (nLanes) *nLanes = 4;
4699 if (zeroUpper) *zeroUpper = False;
4700 if (arrSpec) *arrSpec = "4s";
4701 return True;
4702 }
4703 if (!bitQ && !bitSZ) { // 2x32
4704 if (tyI) *tyI = Ity_I32;
4705 if (tyF) *tyF = Ity_F32;
4706 if (nLanes) *nLanes = 2;
4707 if (zeroUpper) *zeroUpper = True;
4708 if (arrSpec) *arrSpec = "2s";
4709 return True;
4710 }
4711 // Else impliedly 1x64, which isn't allowed.
4712 return False;
4713}
4714
4715/* Helper for decoding laneage for simple vector operations,
4716 eg integer add. */
4717static Bool getLaneInfo_SIMPLE ( /*OUT*/Bool* zeroUpper,
4718 /*OUT*/const HChar** arrSpec,
4719 Bool bitQ, UInt szBlg2 )
4720{
4721 vassert(bitQ == True || bitQ == False);
4722 vassert(szBlg2 < 4);
4723 Bool zu = False;
4724 const HChar* as = NULL;
4725 switch ((szBlg2 << 1) | (bitQ ? 1 : 0)) {
4726 case 0: zu = True; as = "8b"; break;
4727 case 1: zu = False; as = "16b"; break;
4728 case 2: zu = True; as = "4h"; break;
4729 case 3: zu = False; as = "8h"; break;
4730 case 4: zu = True; as = "2s"; break;
4731 case 5: zu = False; as = "4s"; break;
4732 case 6: return False; // impliedly 1x64
4733 case 7: zu = False; as = "2d"; break;
4734 default: vassert(0);
4735 }
4736 vassert(as);
4737 if (arrSpec) *arrSpec = as;
4738 if (zeroUpper) *zeroUpper = zu;
4739 return True;
4740}
4741
4742
sewardje520bb32014-02-17 11:00:53 +00004743/* Helper for decoding laneage for shift-style vector operations
4744 that involve an immediate shift amount. */
4745static Bool getLaneInfo_IMMH_IMMB ( /*OUT*/UInt* shift, /*OUT*/UInt* szBlg2,
4746 UInt immh, UInt immb )
4747{
4748 vassert(immh < (1<<4));
4749 vassert(immb < (1<<3));
4750 UInt immhb = (immh << 3) | immb;
4751 if (immh & 8) {
4752 if (shift) *shift = 128 - immhb;
4753 if (szBlg2) *szBlg2 = 3;
4754 return True;
4755 }
4756 if (immh & 4) {
4757 if (shift) *shift = 64 - immhb;
4758 if (szBlg2) *szBlg2 = 2;
4759 return True;
4760 }
4761 if (immh & 2) {
4762 if (shift) *shift = 32 - immhb;
4763 if (szBlg2) *szBlg2 = 1;
4764 return True;
4765 }
4766 if (immh & 1) {
4767 if (shift) *shift = 16 - immhb;
4768 if (szBlg2) *szBlg2 = 0;
4769 return True;
4770 }
4771 return False;
4772}
4773
4774
sewardjecde6972014-02-05 11:01:19 +00004775/* Generate IR to fold all lanes of the V128 value in 'src' as
4776 characterised by the operator 'op', and return the result in the
4777 bottom bits of a V128, with all other bits set to zero. */
4778static IRTemp math_MINMAXV ( IRTemp src, IROp op )
4779{
4780 /* The basic idea is to use repeated applications of Iop_CatEven*
4781 and Iop_CatOdd* operators to 'src' so as to clone each lane into
4782 a complete vector. Then fold all those vectors with 'op' and
4783 zero out all but the least significant lane. */
4784 switch (op) {
4785 case Iop_Min8Sx16: case Iop_Min8Ux16:
4786 case Iop_Max8Sx16: case Iop_Max8Ux16: {
sewardjfab09142014-02-10 10:28:13 +00004787 /* NB: temp naming here is misleading -- the naming is for 8
4788 lanes of 16 bit, whereas what is being operated on is 16
4789 lanes of 8 bits. */
4790 IRTemp x76543210 = src;
4791 IRTemp x76547654 = newTemp(Ity_V128);
4792 IRTemp x32103210 = newTemp(Ity_V128);
4793 assign(x76547654, mk_CatOddLanes64x2 (x76543210, x76543210));
4794 assign(x32103210, mk_CatEvenLanes64x2(x76543210, x76543210));
4795 IRTemp x76767676 = newTemp(Ity_V128);
4796 IRTemp x54545454 = newTemp(Ity_V128);
4797 IRTemp x32323232 = newTemp(Ity_V128);
4798 IRTemp x10101010 = newTemp(Ity_V128);
4799 assign(x76767676, mk_CatOddLanes32x4 (x76547654, x76547654));
4800 assign(x54545454, mk_CatEvenLanes32x4(x76547654, x76547654));
4801 assign(x32323232, mk_CatOddLanes32x4 (x32103210, x32103210));
4802 assign(x10101010, mk_CatEvenLanes32x4(x32103210, x32103210));
4803 IRTemp x77777777 = newTemp(Ity_V128);
4804 IRTemp x66666666 = newTemp(Ity_V128);
4805 IRTemp x55555555 = newTemp(Ity_V128);
4806 IRTemp x44444444 = newTemp(Ity_V128);
4807 IRTemp x33333333 = newTemp(Ity_V128);
4808 IRTemp x22222222 = newTemp(Ity_V128);
4809 IRTemp x11111111 = newTemp(Ity_V128);
4810 IRTemp x00000000 = newTemp(Ity_V128);
4811 assign(x77777777, mk_CatOddLanes16x8 (x76767676, x76767676));
4812 assign(x66666666, mk_CatEvenLanes16x8(x76767676, x76767676));
4813 assign(x55555555, mk_CatOddLanes16x8 (x54545454, x54545454));
4814 assign(x44444444, mk_CatEvenLanes16x8(x54545454, x54545454));
4815 assign(x33333333, mk_CatOddLanes16x8 (x32323232, x32323232));
4816 assign(x22222222, mk_CatEvenLanes16x8(x32323232, x32323232));
4817 assign(x11111111, mk_CatOddLanes16x8 (x10101010, x10101010));
4818 assign(x00000000, mk_CatEvenLanes16x8(x10101010, x10101010));
4819 /* Naming not misleading after here. */
4820 IRTemp xAllF = newTemp(Ity_V128);
4821 IRTemp xAllE = newTemp(Ity_V128);
4822 IRTemp xAllD = newTemp(Ity_V128);
4823 IRTemp xAllC = newTemp(Ity_V128);
4824 IRTemp xAllB = newTemp(Ity_V128);
4825 IRTemp xAllA = newTemp(Ity_V128);
4826 IRTemp xAll9 = newTemp(Ity_V128);
4827 IRTemp xAll8 = newTemp(Ity_V128);
4828 IRTemp xAll7 = newTemp(Ity_V128);
4829 IRTemp xAll6 = newTemp(Ity_V128);
4830 IRTemp xAll5 = newTemp(Ity_V128);
4831 IRTemp xAll4 = newTemp(Ity_V128);
4832 IRTemp xAll3 = newTemp(Ity_V128);
4833 IRTemp xAll2 = newTemp(Ity_V128);
4834 IRTemp xAll1 = newTemp(Ity_V128);
4835 IRTemp xAll0 = newTemp(Ity_V128);
4836 assign(xAllF, mk_CatOddLanes8x16 (x77777777, x77777777));
4837 assign(xAllE, mk_CatEvenLanes8x16(x77777777, x77777777));
4838 assign(xAllD, mk_CatOddLanes8x16 (x66666666, x66666666));
4839 assign(xAllC, mk_CatEvenLanes8x16(x66666666, x66666666));
4840 assign(xAllB, mk_CatOddLanes8x16 (x55555555, x55555555));
4841 assign(xAllA, mk_CatEvenLanes8x16(x55555555, x55555555));
4842 assign(xAll9, mk_CatOddLanes8x16 (x44444444, x44444444));
4843 assign(xAll8, mk_CatEvenLanes8x16(x44444444, x44444444));
4844 assign(xAll7, mk_CatOddLanes8x16 (x33333333, x33333333));
4845 assign(xAll6, mk_CatEvenLanes8x16(x33333333, x33333333));
4846 assign(xAll5, mk_CatOddLanes8x16 (x22222222, x22222222));
4847 assign(xAll4, mk_CatEvenLanes8x16(x22222222, x22222222));
4848 assign(xAll3, mk_CatOddLanes8x16 (x11111111, x11111111));
4849 assign(xAll2, mk_CatEvenLanes8x16(x11111111, x11111111));
4850 assign(xAll1, mk_CatOddLanes8x16 (x00000000, x00000000));
4851 assign(xAll0, mk_CatEvenLanes8x16(x00000000, x00000000));
4852 IRTemp maxFE = newTemp(Ity_V128);
4853 IRTemp maxDC = newTemp(Ity_V128);
4854 IRTemp maxBA = newTemp(Ity_V128);
4855 IRTemp max98 = newTemp(Ity_V128);
4856 IRTemp max76 = newTemp(Ity_V128);
4857 IRTemp max54 = newTemp(Ity_V128);
4858 IRTemp max32 = newTemp(Ity_V128);
4859 IRTemp max10 = newTemp(Ity_V128);
4860 assign(maxFE, binop(op, mkexpr(xAllF), mkexpr(xAllE)));
4861 assign(maxDC, binop(op, mkexpr(xAllD), mkexpr(xAllC)));
4862 assign(maxBA, binop(op, mkexpr(xAllB), mkexpr(xAllA)));
4863 assign(max98, binop(op, mkexpr(xAll9), mkexpr(xAll8)));
4864 assign(max76, binop(op, mkexpr(xAll7), mkexpr(xAll6)));
4865 assign(max54, binop(op, mkexpr(xAll5), mkexpr(xAll4)));
4866 assign(max32, binop(op, mkexpr(xAll3), mkexpr(xAll2)));
4867 assign(max10, binop(op, mkexpr(xAll1), mkexpr(xAll0)));
4868 IRTemp maxFEDC = newTemp(Ity_V128);
4869 IRTemp maxBA98 = newTemp(Ity_V128);
4870 IRTemp max7654 = newTemp(Ity_V128);
4871 IRTemp max3210 = newTemp(Ity_V128);
4872 assign(maxFEDC, binop(op, mkexpr(maxFE), mkexpr(maxDC)));
4873 assign(maxBA98, binop(op, mkexpr(maxBA), mkexpr(max98)));
4874 assign(max7654, binop(op, mkexpr(max76), mkexpr(max54)));
4875 assign(max3210, binop(op, mkexpr(max32), mkexpr(max10)));
4876 IRTemp maxFEDCBA98 = newTemp(Ity_V128);
4877 IRTemp max76543210 = newTemp(Ity_V128);
4878 assign(maxFEDCBA98, binop(op, mkexpr(maxFEDC), mkexpr(maxBA98)));
4879 assign(max76543210, binop(op, mkexpr(max7654), mkexpr(max3210)));
4880 IRTemp maxAllLanes = newTemp(Ity_V128);
4881 assign(maxAllLanes, binop(op, mkexpr(maxFEDCBA98),
4882 mkexpr(max76543210)));
4883 IRTemp res = newTemp(Ity_V128);
4884 assign(res, unop(Iop_ZeroHI120ofV128, mkexpr(maxAllLanes)));
4885 return res;
sewardjecde6972014-02-05 11:01:19 +00004886 }
4887 case Iop_Min16Sx8: case Iop_Min16Ux8:
4888 case Iop_Max16Sx8: case Iop_Max16Ux8: {
4889 IRTemp x76543210 = src;
4890 IRTemp x76547654 = newTemp(Ity_V128);
4891 IRTemp x32103210 = newTemp(Ity_V128);
4892 assign(x76547654, mk_CatOddLanes64x2 (x76543210, x76543210));
4893 assign(x32103210, mk_CatEvenLanes64x2(x76543210, x76543210));
4894 IRTemp x76767676 = newTemp(Ity_V128);
4895 IRTemp x54545454 = newTemp(Ity_V128);
4896 IRTemp x32323232 = newTemp(Ity_V128);
4897 IRTemp x10101010 = newTemp(Ity_V128);
4898 assign(x76767676, mk_CatOddLanes32x4 (x76547654, x76547654));
4899 assign(x54545454, mk_CatEvenLanes32x4(x76547654, x76547654));
4900 assign(x32323232, mk_CatOddLanes32x4 (x32103210, x32103210));
4901 assign(x10101010, mk_CatEvenLanes32x4(x32103210, x32103210));
4902 IRTemp x77777777 = newTemp(Ity_V128);
4903 IRTemp x66666666 = newTemp(Ity_V128);
4904 IRTemp x55555555 = newTemp(Ity_V128);
4905 IRTemp x44444444 = newTemp(Ity_V128);
4906 IRTemp x33333333 = newTemp(Ity_V128);
4907 IRTemp x22222222 = newTemp(Ity_V128);
4908 IRTemp x11111111 = newTemp(Ity_V128);
4909 IRTemp x00000000 = newTemp(Ity_V128);
4910 assign(x77777777, mk_CatOddLanes16x8 (x76767676, x76767676));
4911 assign(x66666666, mk_CatEvenLanes16x8(x76767676, x76767676));
4912 assign(x55555555, mk_CatOddLanes16x8 (x54545454, x54545454));
4913 assign(x44444444, mk_CatEvenLanes16x8(x54545454, x54545454));
4914 assign(x33333333, mk_CatOddLanes16x8 (x32323232, x32323232));
4915 assign(x22222222, mk_CatEvenLanes16x8(x32323232, x32323232));
4916 assign(x11111111, mk_CatOddLanes16x8 (x10101010, x10101010));
4917 assign(x00000000, mk_CatEvenLanes16x8(x10101010, x10101010));
4918 IRTemp max76 = newTemp(Ity_V128);
4919 IRTemp max54 = newTemp(Ity_V128);
4920 IRTemp max32 = newTemp(Ity_V128);
4921 IRTemp max10 = newTemp(Ity_V128);
4922 assign(max76, binop(op, mkexpr(x77777777), mkexpr(x66666666)));
4923 assign(max54, binop(op, mkexpr(x55555555), mkexpr(x44444444)));
4924 assign(max32, binop(op, mkexpr(x33333333), mkexpr(x22222222)));
4925 assign(max10, binop(op, mkexpr(x11111111), mkexpr(x00000000)));
4926 IRTemp max7654 = newTemp(Ity_V128);
4927 IRTemp max3210 = newTemp(Ity_V128);
4928 assign(max7654, binop(op, mkexpr(max76), mkexpr(max54)));
4929 assign(max3210, binop(op, mkexpr(max32), mkexpr(max10)));
4930 IRTemp max76543210 = newTemp(Ity_V128);
4931 assign(max76543210, binop(op, mkexpr(max7654), mkexpr(max3210)));
4932 IRTemp res = newTemp(Ity_V128);
4933 assign(res, unop(Iop_ZeroHI112ofV128, mkexpr(max76543210)));
4934 return res;
4935 }
4936 case Iop_Min32Sx4: case Iop_Min32Ux4:
4937 case Iop_Max32Sx4: case Iop_Max32Ux4: {
4938 IRTemp x3210 = src;
4939 IRTemp x3232 = newTemp(Ity_V128);
4940 IRTemp x1010 = newTemp(Ity_V128);
4941 assign(x3232, mk_CatOddLanes64x2 (x3210, x3210));
4942 assign(x1010, mk_CatEvenLanes64x2(x3210, x3210));
4943 IRTemp x3333 = newTemp(Ity_V128);
4944 IRTemp x2222 = newTemp(Ity_V128);
4945 IRTemp x1111 = newTemp(Ity_V128);
4946 IRTemp x0000 = newTemp(Ity_V128);
4947 assign(x3333, mk_CatOddLanes32x4 (x3232, x3232));
4948 assign(x2222, mk_CatEvenLanes32x4(x3232, x3232));
4949 assign(x1111, mk_CatOddLanes32x4 (x1010, x1010));
4950 assign(x0000, mk_CatEvenLanes32x4(x1010, x1010));
4951 IRTemp max32 = newTemp(Ity_V128);
4952 IRTemp max10 = newTemp(Ity_V128);
4953 assign(max32, binop(op, mkexpr(x3333), mkexpr(x2222)));
4954 assign(max10, binop(op, mkexpr(x1111), mkexpr(x0000)));
4955 IRTemp max3210 = newTemp(Ity_V128);
4956 assign(max3210, binop(op, mkexpr(max32), mkexpr(max10)));
4957 IRTemp res = newTemp(Ity_V128);
4958 assign(res, unop(Iop_ZeroHI96ofV128, mkexpr(max3210)));
4959 return res;
4960 }
4961 default:
4962 vassert(0);
4963 }
4964}
4965
4966
sewardjbbcf1882014-01-12 12:49:10 +00004967static
4968Bool dis_ARM64_simd_and_fp(/*MB_OUT*/DisResult* dres, UInt insn)
4969{
4970# define INSN(_bMax,_bMin) SLICE_UInt(insn, (_bMax), (_bMin))
4971
4972 /* ---------------- FMOV (general) ---------------- */
4973 /* case 30 23 20 18 15 9 4
4974 (1) 0 00 11110 00 1 00 111 000000 n d FMOV Sd, Wn
4975 (2) 1 00 11110 01 1 00 111 000000 n d FMOV Dd, Xn
4976 (3) 1 00 11110 10 1 01 111 000000 n d FMOV Vd.D[1], Xn
4977
4978 (4) 0 00 11110 00 1 00 110 000000 n d FMOV Wd, Sn
4979 (5) 1 00 11110 01 1 00 110 000000 n d FMOV Xd, Dn
4980 (6) 1 00 11110 10 1 01 110 000000 n d FMOV Xd, Vn.D[1]
4981 */
4982 if (INSN(30,24) == BITS7(0,0,1,1,1,1,0)
4983 && INSN(21,21) == 1 && INSN(15,10) == BITS6(0,0,0,0,0,0)) {
4984 UInt sf = INSN(31,31);
4985 UInt ty = INSN(23,22); // type
4986 UInt rm = INSN(20,19); // rmode
4987 UInt op = INSN(18,16); // opcode
4988 UInt nn = INSN(9,5);
4989 UInt dd = INSN(4,0);
4990 UInt ix = 0; // case
4991 if (sf == 0) {
4992 if (ty == BITS2(0,0) && rm == BITS2(0,0) && op == BITS3(1,1,1))
4993 ix = 1;
4994 else
4995 if (ty == BITS2(0,0) && rm == BITS2(0,0) && op == BITS3(1,1,0))
4996 ix = 4;
4997 } else {
4998 vassert(sf == 1);
4999 if (ty == BITS2(0,1) && rm == BITS2(0,0) && op == BITS3(1,1,1))
5000 ix = 2;
5001 else
5002 if (ty == BITS2(0,1) && rm == BITS2(0,0) && op == BITS3(1,1,0))
5003 ix = 5;
5004 else
5005 if (ty == BITS2(1,0) && rm == BITS2(0,1) && op == BITS3(1,1,1))
5006 ix = 3;
5007 else
5008 if (ty == BITS2(1,0) && rm == BITS2(0,1) && op == BITS3(1,1,0))
5009 ix = 6;
5010 }
5011 if (ix > 0) {
5012 switch (ix) {
5013 case 1:
5014 putQReg128(dd, mkV128(0));
sewardj606c4ba2014-01-26 19:11:14 +00005015 putQRegLO(dd, getIReg32orZR(nn));
sewardjbbcf1882014-01-12 12:49:10 +00005016 DIP("fmov s%u, w%u\n", dd, nn);
5017 break;
5018 case 2:
5019 putQReg128(dd, mkV128(0));
sewardj606c4ba2014-01-26 19:11:14 +00005020 putQRegLO(dd, getIReg64orZR(nn));
sewardjbbcf1882014-01-12 12:49:10 +00005021 DIP("fmov d%u, x%u\n", dd, nn);
5022 break;
5023 case 3:
sewardj606c4ba2014-01-26 19:11:14 +00005024 putQRegHI64(dd, getIReg64orZR(nn));
sewardjbbcf1882014-01-12 12:49:10 +00005025 DIP("fmov v%u.d[1], x%u\n", dd, nn);
5026 break;
5027 case 4:
sewardj606c4ba2014-01-26 19:11:14 +00005028 putIReg32orZR(dd, getQRegLO(nn, Ity_I32));
sewardjbbcf1882014-01-12 12:49:10 +00005029 DIP("fmov w%u, s%u\n", dd, nn);
5030 break;
5031 case 5:
sewardj606c4ba2014-01-26 19:11:14 +00005032 putIReg64orZR(dd, getQRegLO(nn, Ity_I64));
sewardjbbcf1882014-01-12 12:49:10 +00005033 DIP("fmov x%u, d%u\n", dd, nn);
5034 break;
5035 case 6:
sewardj606c4ba2014-01-26 19:11:14 +00005036 putIReg64orZR(dd, getQRegHI64(nn));
sewardjbbcf1882014-01-12 12:49:10 +00005037 DIP("fmov x%u, v%u.d[1]\n", dd, nn);
5038 break;
5039 default:
5040 vassert(0);
5041 }
5042 return True;
5043 }
5044 /* undecodable; fall through */
5045 }
5046
5047 /* -------------- FMOV (scalar, immediate) -------------- */
5048 /* 31 28 23 20 12 9 4
5049 000 11110 00 1 imm8 100 00000 d FMOV Sd, #imm
5050 000 11110 01 1 imm8 100 00000 d FMOV Dd, #imm
5051 */
5052 if (INSN(31,23) == BITS9(0,0,0,1,1,1,1,0,0)
5053 && INSN(21,21) == 1 && INSN(12,5) == BITS8(1,0,0,0,0,0,0,0)) {
5054 Bool isD = INSN(22,22) == 1;
5055 UInt imm8 = INSN(20,13);
5056 UInt dd = INSN(4,0);
5057 ULong imm = VFPExpandImm(imm8, isD ? 64 : 32);
5058 if (!isD) {
sewardjaeeb31d2014-01-12 18:23:45 +00005059 vassert(0 == (imm & 0xFFFFFFFF00000000ULL));
sewardjbbcf1882014-01-12 12:49:10 +00005060 }
5061 putQReg128(dd, mkV128(0));
sewardj606c4ba2014-01-26 19:11:14 +00005062 putQRegLO(dd, isD ? mkU64(imm) : mkU32(imm & 0xFFFFFFFFULL));
5063 DIP("fmov %s, #0x%llx\n",
5064 nameQRegLO(dd, isD ? Ity_F64 : Ity_F32), imm);
sewardjbbcf1882014-01-12 12:49:10 +00005065 return True;
5066 }
5067
sewardjfab09142014-02-10 10:28:13 +00005068#if 0
5069 /* -------------- FMOV (vector, immediate) -------------- */
5070 /* 31 28 18 15 9 4
5071 011 01111 00000 abc 111101 defgh d FMOV Vd.2d, #imm
5072 0q0 01111 00000 abc 111101 defgh d FMOV Vd.2s, #imm (q=0)
5073 FMOV Vd.4s, #imm (q=1)
5074 */
5075 if (INSN(31,31) == 0
5076 && INSN(28,19) == BITS10(0,1,1,1,1,0,0,0,0,0)
5077 && INSN(15,10) == BITS6(1,1,1,1,0,1)
5078 && INSN(30,29) != BITS2(0,1)) {
5079 UInt bitQ = INSN(30,30);
5080 UInt bitOP = INSN(29,29);
5081 UInt cmode = INSN(15,12);
5082 UInt imm8 = (INSN(18,16) << 5) | INSN(9,5);
5083 UInt dd = INSN(4,0);
5084 ULong imm64lo = 0;
5085 Bool ok = AdvSIMDExpandImm(&imm64lo, bitOP, cmode, imm8);
5086 vassert(! (bitOP == 1 && bitQ == 0) );
5087 if (ok) {
5088 ULong imm64hi = (bitQ == 0 && bitOP == 0) ? 0 : imm64lo;
5089 putQReg128(dd, binop(Iop_64HLtoV128, mkU64(imm64hi), mkU64(imm64lo)));
5090 const HChar* ar[4] = { "2s", "??", "4s", "2d" };
5091 DIP("fmov %s.%s, #0x%llx\n",
5092 nameQReg128(dd), ar[INSN(30,29)], imm64lo);
5093 return True;
5094 }
5095 /* else fall through */
5096 }
5097#else
5098 /* -------------- {FMOV,MOVI} (vector, immediate) -------------- */
5099 /* 31 28 18 15 11 9 4
5100 0q op 01111 00000 abc cmode 01 defgh d MOV Dd, #imm (q=0)
5101 MOV Vd.2d #imm (q=1)
5102 Allowable op:cmode
5103 FMOV = 1:1111
5104 MOVI = 0:xx00, 1:0x00, 1:10x0, 1:110x, 11110
5105 */
5106 if (INSN(31,31) == 0
5107 && INSN(28,19) == BITS10(0,1,1,1,1,0,0,0,0,0)
5108 && INSN(11,10) == BITS2(0,1)) {
5109 UInt bitQ = INSN(30,30);
5110 UInt bitOP = INSN(29,29);
5111 UInt cmode = INSN(15,12);
5112 UInt imm8 = (INSN(18,16) << 5) | INSN(9,5);
5113 UInt dd = INSN(4,0);
5114 ULong imm64lo = 0;
5115 UInt op_cmode = (bitOP << 4) | cmode;
5116 Bool ok = False;
5117 switch (op_cmode) {
5118 case BITS5(1,1,1,1,1): // 1:1111
5119 case BITS5(0,0,0,0,0): case BITS5(0,0,1,0,0):
5120 case BITS5(0,1,0,0,0): case BITS5(0,1,1,0,0): // 0:xx00
5121 case BITS5(1,0,0,0,0): case BITS5(1,0,1,0,0): // 1:0x00
5122 case BITS5(1,1,0,0,0): case BITS5(1,1,0,1,0): // 1:10x0
5123 case BITS5(1,1,1,0,0): case BITS5(1,1,1,0,1): // 1:110x
5124 case BITS5(1,1,1,1,0): // 1:1110
5125 ok = True; break;
5126 default:
5127 break;
5128 }
5129 if (ok) {
5130 ok = AdvSIMDExpandImm(&imm64lo, bitOP, cmode, imm8);
5131 }
5132 if (ok) {
5133 ULong imm64hi = (bitQ == 0 && bitOP == 0) ? 0 : imm64lo;
5134 putQReg128(dd, binop(Iop_64HLtoV128, mkU64(imm64hi), mkU64(imm64lo)));
5135 DIP("mov %s, #0x016%llx'%016llx\n", nameQReg128(dd), imm64hi, imm64lo);
5136 return True;
5137 }
5138 /* else fall through */
5139 }
5140#endif
5141
sewardjbbcf1882014-01-12 12:49:10 +00005142 /* -------------- {S,U}CVTF (scalar, integer) -------------- */
5143 /* 31 28 23 21 20 18 15 9 4 ix
5144 000 11110 00 1 00 010 000000 n d SCVTF Sd, Wn 0
5145 000 11110 01 1 00 010 000000 n d SCVTF Dd, Wn 1
5146 100 11110 00 1 00 010 000000 n d SCVTF Sd, Xn 2
5147 100 11110 01 1 00 010 000000 n d SCVTF Dd, Xn 3
5148
5149 000 11110 00 1 00 011 000000 n d UCVTF Sd, Wn 4
5150 000 11110 01 1 00 011 000000 n d UCVTF Dd, Wn 5
5151 100 11110 00 1 00 011 000000 n d UCVTF Sd, Xn 6
5152 100 11110 01 1 00 011 000000 n d UCVTF Dd, Xn 7
5153
5154 These are signed/unsigned conversion from integer registers to
5155 FP registers, all 4 32/64-bit combinations, rounded per FPCR.
5156 */
5157 if (INSN(30,23) == BITS8(0,0,1,1,1,1,0,0) && INSN(21,17) == BITS5(1,0,0,0,1)
5158 && INSN(15,10) == BITS6(0,0,0,0,0,0)) {
5159 Bool isI64 = INSN(31,31) == 1;
5160 Bool isF64 = INSN(22,22) == 1;
5161 Bool isU = INSN(16,16) == 1;
5162 UInt nn = INSN(9,5);
5163 UInt dd = INSN(4,0);
5164 UInt ix = (isU ? 4 : 0) | (isI64 ? 2 : 0) | (isF64 ? 1 : 0);
5165 const IROp ops[8]
5166 = { Iop_I32StoF32, Iop_I32StoF64, Iop_I64StoF32, Iop_I64StoF64,
5167 Iop_I32UtoF32, Iop_I32UtoF64, Iop_I64UtoF32, Iop_I64UtoF64 };
5168 IRExpr* src = getIRegOrZR(isI64, nn);
5169 IRExpr* res = (isF64 && !isI64)
5170 ? unop(ops[ix], src)
5171 : binop(ops[ix], mkexpr(mk_get_IR_rounding_mode()), src);
5172 putQReg128(dd, mkV128(0));
sewardj606c4ba2014-01-26 19:11:14 +00005173 putQRegLO(dd, res);
sewardjbbcf1882014-01-12 12:49:10 +00005174 DIP("%ccvtf %s, %s\n",
sewardj606c4ba2014-01-26 19:11:14 +00005175 isU ? 'u' : 's', nameQRegLO(dd, isF64 ? Ity_F64 : Ity_F32),
sewardjbbcf1882014-01-12 12:49:10 +00005176 nameIRegOrZR(isI64, nn));
5177 return True;
5178 }
5179
5180 /* -------------- F{ADD,SUB,MUL,DIV} (scalar) -------------- */
5181 /* 31 23 20 15 11 9 4
5182 ---------------- 0000 ------ FMUL --------
5183 000 11110 001 m 0001 10 n d FDIV Sd,Sn,Sm
5184 000 11110 011 m 0001 10 n d FDIV Dd,Dn,Dm
5185 ---------------- 0010 ------ FADD --------
5186 ---------------- 0011 ------ FSUB --------
5187 ---------------- 1000 ------ FNMUL --------
5188 */
5189 if (INSN(31,23) == BITS9(0,0,0,1,1,1,1,0,0)
5190 && INSN(21,21) == 1 && INSN(11,10) == BITS2(1,0)) {
5191 Bool isD = INSN(22,22) == 1;
5192 UInt mm = INSN(20,16);
5193 UInt op = INSN(15,12);
5194 UInt nn = INSN(9,5);
5195 UInt dd = INSN(4,0);
5196 IROp iop = Iop_INVALID;
5197 IRType ty = isD ? Ity_F64 : Ity_F32;
sewardjbbcf1882014-01-12 12:49:10 +00005198 Bool neg = False;
5199 const HChar* nm = "???";
5200 switch (op) {
5201 case BITS4(0,0,0,0): nm = "fmul"; iop = mkMULF(ty); break;
5202 case BITS4(0,0,0,1): nm = "fdiv"; iop = mkDIVF(ty); break;
5203 case BITS4(0,0,1,0): nm = "fadd"; iop = mkADDF(ty); break;
5204 case BITS4(0,0,1,1): nm = "fsub"; iop = mkSUBF(ty); break;
5205 case BITS4(1,0,0,0): nm = "fnmul"; iop = mkMULF(ty);
5206 neg = True; break;
5207 default: return False;
5208 }
5209 vassert(iop != Iop_INVALID);
5210 IRExpr* resE = triop(iop, mkexpr(mk_get_IR_rounding_mode()),
sewardj606c4ba2014-01-26 19:11:14 +00005211 getQRegLO(nn, ty), getQRegLO(mm, ty));
sewardjbbcf1882014-01-12 12:49:10 +00005212 IRTemp res = newTemp(ty);
5213 assign(res, neg ? unop(mkNEGF(ty),resE) : resE);
5214 putQReg128(dd, mkV128(0));
sewardj606c4ba2014-01-26 19:11:14 +00005215 putQRegLO(dd, mkexpr(res));
sewardjbbcf1882014-01-12 12:49:10 +00005216 DIP("%s %s, %s, %s\n",
sewardj606c4ba2014-01-26 19:11:14 +00005217 nm, nameQRegLO(dd, ty), nameQRegLO(nn, ty), nameQRegLO(mm, ty));
sewardjbbcf1882014-01-12 12:49:10 +00005218 return True;
5219 }
5220
5221 /* ------------ F{MOV,ABS,NEG,SQRT} D/D or S/S ------------ */
5222 /* 31 23 21 16 14 9 4
5223 000 11110 00 10000 00 10000 n d FMOV Sd, Sn
5224 000 11110 01 10000 00 10000 n d FMOV Dd, Dn
5225 ------------------ 01 --------- FABS ------
5226 ------------------ 10 --------- FNEG ------
sewardjfab09142014-02-10 10:28:13 +00005227 ------------------ 11 --------- FSQRT -----
sewardjbbcf1882014-01-12 12:49:10 +00005228 */
5229 if (INSN(31,23) == BITS9(0,0,0,1,1,1,1,0,0)
5230 && INSN(21,17) == BITS5(1,0,0,0,0)
5231 && INSN(14,10) == BITS5(1,0,0,0,0)) {
5232 Bool isD = INSN(22,22) == 1;
5233 UInt opc = INSN(16,15);
5234 UInt nn = INSN(9,5);
5235 UInt dd = INSN(4,0);
5236 IRType ty = isD ? Ity_F64 : Ity_F32;
sewardjbbcf1882014-01-12 12:49:10 +00005237 IRTemp res = newTemp(ty);
5238 if (opc == BITS2(0,0)) {
sewardj606c4ba2014-01-26 19:11:14 +00005239 assign(res, getQRegLO(nn, ty));
sewardjbbcf1882014-01-12 12:49:10 +00005240 putQReg128(dd, mkV128(0x0000));
sewardj606c4ba2014-01-26 19:11:14 +00005241 putQRegLO(dd, mkexpr(res));
5242 DIP("fmov %s, %s\n",
5243 nameQRegLO(dd, ty), nameQRegLO(nn, ty));
sewardjbbcf1882014-01-12 12:49:10 +00005244 return True;
5245 }
5246 if (opc == BITS2(1,0) || opc == BITS2(0,1)) {
5247 Bool isAbs = opc == BITS2(0,1);
5248 IROp op = isAbs ? mkABSF(ty) : mkNEGF(ty);
sewardj606c4ba2014-01-26 19:11:14 +00005249 assign(res, unop(op, getQRegLO(nn, ty)));
sewardjbbcf1882014-01-12 12:49:10 +00005250 putQReg128(dd, mkV128(0x0000));
sewardj606c4ba2014-01-26 19:11:14 +00005251 putQRegLO(dd, mkexpr(res));
sewardjbbcf1882014-01-12 12:49:10 +00005252 DIP("%s %s, %s\n", isAbs ? "fabs" : "fneg",
sewardj606c4ba2014-01-26 19:11:14 +00005253 nameQRegLO(dd, ty), nameQRegLO(nn, ty));
sewardjbbcf1882014-01-12 12:49:10 +00005254 return True;
5255 }
5256 if (opc == BITS2(1,1)) {
5257 assign(res,
5258 binop(mkSQRTF(ty),
sewardj606c4ba2014-01-26 19:11:14 +00005259 mkexpr(mk_get_IR_rounding_mode()), getQRegLO(nn, ty)));
sewardjbbcf1882014-01-12 12:49:10 +00005260 putQReg128(dd, mkV128(0x0000));
sewardj606c4ba2014-01-26 19:11:14 +00005261 putQRegLO(dd, mkexpr(res));
5262 DIP("fsqrt %s, %s\n", nameQRegLO(dd, ty), nameQRegLO(nn, ty));
sewardjbbcf1882014-01-12 12:49:10 +00005263 return True;
5264 }
5265 /* else fall through; other cases are ATC */
5266 }
5267
sewardjfab09142014-02-10 10:28:13 +00005268 /* ---------------- F{ABS,NEG} (vector) ---------------- */
5269 /* 31 28 22 21 16 9 4
5270 0q0 01110 1 sz 10000 01111 10 n d FABS Vd.T, Vn.T
5271 0q1 01110 1 sz 10000 01111 10 n d FNEG Vd.T, Vn.T
5272 */
5273 if (INSN(31,31) == 0 && INSN(28,23) == BITS6(0,1,1,1,0,1)
5274 && INSN(21,17) == BITS5(1,0,0,0,0)
5275 && INSN(16,10) == BITS7(0,1,1,1,1,1,0)) {
5276 UInt bitQ = INSN(30,30);
5277 UInt bitSZ = INSN(22,22);
5278 Bool isFNEG = INSN(29,29) == 1;
5279 UInt nn = INSN(9,5);
5280 UInt dd = INSN(4,0);
5281 const HChar* ar = "??";
5282 IRType tyF = Ity_INVALID;
5283 Bool zeroHI = False;
5284 Bool ok = getLaneInfo_Q_SZ(NULL, &tyF, NULL, &zeroHI, &ar,
5285 (Bool)bitQ, (Bool)bitSZ);
5286 if (ok) {
5287 vassert(tyF == Ity_F64 || tyF == Ity_I32);
5288 IROp op = (tyF == Ity_F64) ? (isFNEG ? Iop_Neg64Fx2 : Iop_Abs64Fx2)
5289 : (isFNEG ? Iop_Neg32Fx4 : Iop_Abs32Fx4);
5290 IRTemp res = newTemp(Ity_V128);
5291 assign(res, unop(op, getQReg128(nn)));
5292 putQReg128(dd, zeroHI ? unop(Iop_ZeroHI64ofV128, mkexpr(res))
5293 : mkexpr(res));
5294 DIP("%s %s.%s, %s.%s\n", isFNEG ? "fneg" : "fabs",
5295 nameQReg128(dd), ar, nameQReg128(nn), ar);
5296 return True;
5297 }
5298 /* else fall through */
5299 }
5300
sewardjbbcf1882014-01-12 12:49:10 +00005301 /* -------------------- FCMP,FCMPE -------------------- */
5302 /* 31 23 20 15 9 4
5303 000 11110 01 1 m 00 1000 n 10 000 FCMPE Dn, Dm
5304 000 11110 01 1 00000 00 1000 n 11 000 FCMPE Dn, #0.0
5305 000 11110 01 1 m 00 1000 n 00 000 FCMP Dn, Dm
5306 000 11110 01 1 00000 00 1000 n 01 000 FCMP Dn, #0.0
5307
5308 000 11110 00 1 m 00 1000 n 10 000 FCMPE Sn, Sm
5309 000 11110 00 1 00000 00 1000 n 11 000 FCMPE Sn, #0.0
5310 000 11110 00 1 m 00 1000 n 00 000 FCMP Sn, Sm
5311 000 11110 00 1 00000 00 1000 n 01 000 FCMP Sn, #0.0
5312
5313 FCMPE generates Invalid Operation exn if either arg is any kind
5314 of NaN. FCMP generates Invalid Operation exn if either arg is a
5315 signalling NaN. We ignore this detail here and produce the same
5316 IR for both.
5317 */
5318 if (INSN(31,23) == BITS9(0,0,0,1,1,1,1,0,0) && INSN(21,21) == 1
5319 && INSN(15,10) == BITS6(0,0,1,0,0,0) && INSN(2,0) == BITS3(0,0,0)) {
5320 Bool isD = INSN(22,22) == 1;
5321 UInt mm = INSN(20,16);
5322 UInt nn = INSN(9,5);
5323 Bool isCMPE = INSN(4,4) == 1;
5324 Bool cmpZero = INSN(3,3) == 1;
5325 IRType ty = isD ? Ity_F64 : Ity_F32;
sewardjbbcf1882014-01-12 12:49:10 +00005326 Bool valid = True;
5327 if (cmpZero && mm != 0) valid = False;
5328 if (valid) {
5329 IRTemp argL = newTemp(ty);
5330 IRTemp argR = newTemp(ty);
5331 IRTemp irRes = newTemp(Ity_I32);
sewardj606c4ba2014-01-26 19:11:14 +00005332 assign(argL, getQRegLO(nn, ty));
sewardjbbcf1882014-01-12 12:49:10 +00005333 assign(argR,
5334 cmpZero
5335 ? (IRExpr_Const(isD ? IRConst_F64i(0) : IRConst_F32i(0)))
sewardj606c4ba2014-01-26 19:11:14 +00005336 : getQRegLO(mm, ty));
sewardjbbcf1882014-01-12 12:49:10 +00005337 assign(irRes, binop(isD ? Iop_CmpF64 : Iop_CmpF32,
5338 mkexpr(argL), mkexpr(argR)));
5339 IRTemp nzcv = mk_convert_IRCmpF64Result_to_NZCV(irRes);
5340 IRTemp nzcv_28x0 = newTemp(Ity_I64);
5341 assign(nzcv_28x0, binop(Iop_Shl64, mkexpr(nzcv), mkU8(28)));
5342 setFlags_COPY(nzcv_28x0);
sewardj606c4ba2014-01-26 19:11:14 +00005343 DIP("fcmp%s %s, %s\n", isCMPE ? "e" : "", nameQRegLO(nn, ty),
5344 cmpZero ? "#0.0" : nameQRegLO(mm, ty));
sewardjbbcf1882014-01-12 12:49:10 +00005345 return True;
5346 }
5347 }
5348
5349 /* -------------------- F{N}M{ADD,SUB} -------------------- */
5350 /* 31 22 20 15 14 9 4 ix
5351 000 11111 0 sz 0 m 0 a n d 0 FMADD Fd,Fn,Fm,Fa
5352 000 11111 0 sz 0 m 1 a n d 1 FMSUB Fd,Fn,Fm,Fa
5353 000 11111 0 sz 1 m 0 a n d 2 FNMADD Fd,Fn,Fm,Fa
5354 000 11111 0 sz 1 m 1 a n d 3 FNMSUB Fd,Fn,Fm,Fa
5355 where Fx=Dx when sz=1, Fx=Sx when sz=0
5356
5357 -----SPEC------ ----IMPL----
5358 fmadd a + n * m a + n * m
5359 fmsub a + (-n) * m a - n * m
5360 fnmadd (-a) + (-n) * m -(a + n * m)
5361 fnmsub (-a) + n * m -(a - n * m)
5362 */
5363 if (INSN(31,23) == BITS9(0,0,0,1,1,1,1,1,0)) {
5364 Bool isD = INSN(22,22) == 1;
5365 UInt mm = INSN(20,16);
5366 UInt aa = INSN(14,10);
5367 UInt nn = INSN(9,5);
5368 UInt dd = INSN(4,0);
5369 UInt ix = (INSN(21,21) << 1) | INSN(15,15);
5370 IRType ty = isD ? Ity_F64 : Ity_F32;
sewardjbbcf1882014-01-12 12:49:10 +00005371 IROp opADD = mkADDF(ty);
5372 IROp opSUB = mkSUBF(ty);
5373 IROp opMUL = mkMULF(ty);
5374 IROp opNEG = mkNEGF(ty);
5375 IRTemp res = newTemp(ty);
sewardj606c4ba2014-01-26 19:11:14 +00005376 IRExpr* eA = getQRegLO(aa, ty);
5377 IRExpr* eN = getQRegLO(nn, ty);
5378 IRExpr* eM = getQRegLO(mm, ty);
sewardjbbcf1882014-01-12 12:49:10 +00005379 IRExpr* rm = mkexpr(mk_get_IR_rounding_mode());
5380 IRExpr* eNxM = triop(opMUL, rm, eN, eM);
5381 switch (ix) {
5382 case 0: assign(res, triop(opADD, rm, eA, eNxM)); break;
5383 case 1: assign(res, triop(opSUB, rm, eA, eNxM)); break;
5384 case 2: assign(res, unop(opNEG, triop(opADD, rm, eA, eNxM))); break;
5385 case 3: assign(res, unop(opNEG, triop(opSUB, rm, eA, eNxM))); break;
5386 default: vassert(0);
5387 }
5388 putQReg128(dd, mkV128(0x0000));
sewardj606c4ba2014-01-26 19:11:14 +00005389 putQRegLO(dd, mkexpr(res));
sewardjbbcf1882014-01-12 12:49:10 +00005390 const HChar* names[4] = { "fmadd", "fmsub", "fnmadd", "fnmsub" };
5391 DIP("%s %s, %s, %s, %s\n",
sewardj606c4ba2014-01-26 19:11:14 +00005392 names[ix], nameQRegLO(dd, ty), nameQRegLO(nn, ty),
5393 nameQRegLO(mm, ty), nameQRegLO(aa, ty));
sewardjbbcf1882014-01-12 12:49:10 +00005394 return True;
5395 }
5396
5397 /* -------- FCVT{N,P,M,Z}{S,U} (scalar, integer) -------- */
5398 /* 30 23 20 18 15 9 4
5399 sf 00 11110 0x 1 00 000 000000 n d FCVTNS Rd, Fn (round to
5400 sf 00 11110 0x 1 00 001 000000 n d FCVTNU Rd, Fn nearest)
5401 ---------------- 01 -------------- FCVTP-------- (round to +inf)
5402 ---------------- 10 -------------- FCVTM-------- (round to -inf)
5403 ---------------- 11 -------------- FCVTZ-------- (round to zero)
5404
5405 Rd is Xd when sf==1, Wd when sf==0
5406 Fn is Dn when x==1, Sn when x==0
5407 20:19 carry the rounding mode, using the same encoding as FPCR
5408 */
5409 if (INSN(30,23) == BITS8(0,0,1,1,1,1,0,0) && INSN(21,21) == 1
5410 && INSN(18,17) == BITS2(0,0) && INSN(15,10) == BITS6(0,0,0,0,0,0)) {
5411 Bool isI64 = INSN(31,31) == 1;
5412 Bool isF64 = INSN(22,22) == 1;
5413 UInt rm = INSN(20,19);
5414 Bool isU = INSN(16,16) == 1;
5415 UInt nn = INSN(9,5);
5416 UInt dd = INSN(4,0);
5417 /* Decide on the IR rounding mode to use. */
5418 IRRoundingMode irrm = 8; /*impossible*/
5419 HChar ch = '?';
5420 switch (rm) {
5421 case BITS2(0,0): ch = 'n'; irrm = Irrm_NEAREST; break;
5422 case BITS2(0,1): ch = 'p'; irrm = Irrm_PosINF; break;
5423 case BITS2(1,0): ch = 'm'; irrm = Irrm_NegINF; break;
5424 case BITS2(1,1): ch = 'z'; irrm = Irrm_ZERO; break;
5425 default: vassert(0);
5426 }
5427 vassert(irrm != 8);
5428 /* Decide on the conversion primop, based on the source size,
5429 dest size and signedness (8 possibilities). Case coding:
5430 F32 ->s I32 0
5431 F32 ->u I32 1
5432 F32 ->s I64 2
5433 F32 ->u I64 3
5434 F64 ->s I32 4
5435 F64 ->u I32 5
5436 F64 ->s I64 6
5437 F64 ->u I64 7
5438 */
5439 UInt ix = (isF64 ? 4 : 0) | (isI64 ? 2 : 0) | (isU ? 1 : 0);
5440 vassert(ix < 8);
5441 const IROp ops[8]
5442 = { Iop_F32toI32S, Iop_F32toI32U, Iop_F32toI64S, Iop_F32toI64U,
5443 Iop_F64toI32S, Iop_F64toI32U, Iop_F64toI64S, Iop_F64toI64U };
5444 IROp op = ops[ix];
5445 // A bit of ATCery: bounce all cases we haven't seen an example of.
5446 if (/* F32toI32S */
5447 (op == Iop_F32toI32S && irrm == Irrm_ZERO) /* FCVTZS Wd,Sn */
5448 /* F32toI32U */
5449 /* F32toI64S */
5450 /* F32toI64U */
5451 || (op == Iop_F32toI64U && irrm == Irrm_ZERO) /* FCVTZU Xd,Sn */
5452 /* F64toI32S */
5453 || (op == Iop_F64toI32S && irrm == Irrm_ZERO) /* FCVTZS Wd,Dn */
5454 || (op == Iop_F64toI32S && irrm == Irrm_NegINF) /* FCVTMS Wd,Dn */
5455 || (op == Iop_F64toI32S && irrm == Irrm_PosINF) /* FCVTPS Wd,Dn */
5456 /* F64toI32U */
5457 || (op == Iop_F64toI32U && irrm == Irrm_NegINF) /* FCVTMU Wd,Dn */
5458 || (op == Iop_F64toI32U && irrm == Irrm_ZERO) /* FCVTZU Wd,Dn */
5459 /* F64toI64S */
5460 || (op == Iop_F64toI64S && irrm == Irrm_ZERO) /* FCVTZS Xd,Dn */
5461 /* F64toI64U */
5462 || (op == Iop_F64toI64U && irrm == Irrm_ZERO) /* FCVTZU Xd,Dn */
5463 ) {
5464 /* validated */
5465 } else {
5466 return False;
5467 }
sewardjbbcf1882014-01-12 12:49:10 +00005468 IRType srcTy = isF64 ? Ity_F64 : Ity_F32;
5469 IRType dstTy = isI64 ? Ity_I64 : Ity_I32;
5470 IRTemp src = newTemp(srcTy);
5471 IRTemp dst = newTemp(dstTy);
sewardj606c4ba2014-01-26 19:11:14 +00005472 assign(src, getQRegLO(nn, srcTy));
sewardjbbcf1882014-01-12 12:49:10 +00005473 assign(dst, binop(op, mkU32(irrm), mkexpr(src)));
5474 putIRegOrZR(isI64, dd, mkexpr(dst));
5475 DIP("fcvt%c%c %s, %s\n", ch, isU ? 'u' : 's',
sewardj606c4ba2014-01-26 19:11:14 +00005476 nameIRegOrZR(isI64, dd), nameQRegLO(nn, srcTy));
sewardjbbcf1882014-01-12 12:49:10 +00005477 return True;
5478 }
5479
5480 /* ---------------- FRINT{I,M,P,Z} (scalar) ---------------- */
5481 /* 31 23 21 17 14 9 4
5482 000 11110 0x 1001 111 10000 n d FRINTI Fd, Fm (round per FPCR)
5483 rm
5484 x==0 => S-registers, x==1 => D-registers
5485 rm (17:15) encodings:
5486 111 per FPCR (FRINTI)
5487 001 +inf (FRINTP)
5488 010 -inf (FRINTM)
5489 011 zero (FRINTZ)
5490 000 tieeven
5491 100 tieaway
5492 110 per FPCR + "exact = TRUE"
5493 101 unallocated
5494 */
5495 if (INSN(31,23) == BITS9(0,0,0,1,1,1,1,0,0)
5496 && INSN(21,18) == BITS4(1,0,0,1) && INSN(14,10) == BITS5(1,0,0,0,0)) {
5497 Bool isD = INSN(22,22) == 1;
5498 UInt rm = INSN(17,15);
5499 UInt nn = INSN(9,5);
5500 UInt dd = INSN(4,0);
5501 IRType ty = isD ? Ity_F64 : Ity_F32;
sewardjbbcf1882014-01-12 12:49:10 +00005502 IRExpr* irrmE = NULL;
5503 UChar ch = '?';
5504 switch (rm) {
5505 case BITS3(0,1,1): ch = 'z'; irrmE = mkU32(Irrm_ZERO); break;
5506 case BITS3(0,1,0): ch = 'm'; irrmE = mkU32(Irrm_NegINF); break;
5507 case BITS3(0,0,1): ch = 'p'; irrmE = mkU32(Irrm_PosINF); break;
5508 default: break;
5509 }
5510 if (irrmE) {
5511 IRTemp src = newTemp(ty);
5512 IRTemp dst = newTemp(ty);
sewardj606c4ba2014-01-26 19:11:14 +00005513 assign(src, getQRegLO(nn, ty));
sewardjbbcf1882014-01-12 12:49:10 +00005514 assign(dst, binop(isD ? Iop_RoundF64toInt : Iop_RoundF32toInt,
5515 irrmE, mkexpr(src)));
5516 putQReg128(dd, mkV128(0x0000));
sewardj606c4ba2014-01-26 19:11:14 +00005517 putQRegLO(dd, mkexpr(dst));
5518 DIP("frint%c %s, %s\n",
5519 ch, nameQRegLO(dd, ty), nameQRegLO(nn, ty));
sewardjbbcf1882014-01-12 12:49:10 +00005520 return True;
5521 }
5522 /* else unhandled rounding mode case -- fall through */
5523 }
5524
5525 /* ------------------ FCVT (scalar) ------------------ */
5526 /* 31 23 21 16 14 9 4
5527 000 11110 11 10001 00 10000 n d FCVT Sd, Hn (unimp)
5528 --------- 11 ----- 01 --------- FCVT Dd, Hn (unimp)
5529 --------- 00 ----- 11 --------- FCVT Hd, Sn (unimp)
5530 --------- 00 ----- 01 --------- FCVT Dd, Sn (unimp)
5531 --------- 01 ----- 11 --------- FCVT Hd, Dn (unimp)
5532 --------- 01 ----- 00 --------- FCVT Sd, Dn (unimp)
5533 Rounding, when dst is smaller than src, is per the FPCR.
5534 */
5535 if (INSN(31,24) == BITS8(0,0,0,1,1,1,1,0)
5536 && INSN(21,17) == BITS5(1,0,0,0,1)
5537 && INSN(14,10) == BITS5(1,0,0,0,0)) {
5538 UInt b2322 = INSN(23,22);
5539 UInt b1615 = INSN(16,15);
5540 UInt nn = INSN(9,5);
5541 UInt dd = INSN(4,0);
5542 if (b2322 == BITS2(0,0) && b1615 == BITS2(0,1)) {
5543 /* Convert S to D */
5544 IRTemp res = newTemp(Ity_F64);
sewardj606c4ba2014-01-26 19:11:14 +00005545 assign(res, unop(Iop_F32toF64, getQRegLO(nn, Ity_F32)));
sewardjbbcf1882014-01-12 12:49:10 +00005546 putQReg128(dd, mkV128(0x0000));
sewardj606c4ba2014-01-26 19:11:14 +00005547 putQRegLO(dd, mkexpr(res));
5548 DIP("fcvt %s, %s\n",
5549 nameQRegLO(dd, Ity_F64), nameQRegLO(nn, Ity_F32));
sewardjbbcf1882014-01-12 12:49:10 +00005550 return True;
5551 }
5552 if (b2322 == BITS2(0,1) && b1615 == BITS2(0,0)) {
5553 /* Convert D to S */
5554 IRTemp res = newTemp(Ity_F32);
5555 assign(res, binop(Iop_F64toF32, mkexpr(mk_get_IR_rounding_mode()),
sewardj606c4ba2014-01-26 19:11:14 +00005556 getQRegLO(nn, Ity_F64)));
sewardjbbcf1882014-01-12 12:49:10 +00005557 putQReg128(dd, mkV128(0x0000));
sewardj606c4ba2014-01-26 19:11:14 +00005558 putQRegLO(dd, mkexpr(res));
5559 DIP("fcvt %s, %s\n",
5560 nameQRegLO(dd, Ity_F32), nameQRegLO(nn, Ity_F64));
sewardjbbcf1882014-01-12 12:49:10 +00005561 return True;
5562 }
5563 /* else unhandled */
5564 }
5565
5566 /* ------------------ FABD (scalar) ------------------ */
5567 /* 31 23 20 15 9 4
5568 011 11110 111 m 110101 n d FABD Dd, Dn, Dm
5569 011 11110 101 m 110101 n d FABD Sd, Sn, Sm
5570 */
5571 if (INSN(31,23) == BITS9(0,1,1,1,1,1,1,0,1) && INSN(21,21) == 1
5572 && INSN(15,10) == BITS6(1,1,0,1,0,1)) {
5573 Bool isD = INSN(22,22) == 1;
5574 UInt mm = INSN(20,16);
5575 UInt nn = INSN(9,5);
5576 UInt dd = INSN(4,0);
5577 IRType ty = isD ? Ity_F64 : Ity_F32;
sewardjbbcf1882014-01-12 12:49:10 +00005578 IRTemp res = newTemp(ty);
sewardj606c4ba2014-01-26 19:11:14 +00005579 assign(res, unop(mkABSF(ty),
5580 triop(mkSUBF(ty),
5581 mkexpr(mk_get_IR_rounding_mode()),
5582 getQRegLO(nn,ty), getQRegLO(mm,ty))));
sewardjbbcf1882014-01-12 12:49:10 +00005583 putQReg128(dd, mkV128(0x0000));
sewardj606c4ba2014-01-26 19:11:14 +00005584 putQRegLO(dd, mkexpr(res));
sewardjbbcf1882014-01-12 12:49:10 +00005585 DIP("fabd %s, %s, %s\n",
sewardj606c4ba2014-01-26 19:11:14 +00005586 nameQRegLO(dd, ty), nameQRegLO(nn, ty), nameQRegLO(mm, ty));
sewardjbbcf1882014-01-12 12:49:10 +00005587 return True;
5588 }
5589
sewardj606c4ba2014-01-26 19:11:14 +00005590 /* -------------- {S,U}CVTF (vector, integer) -------------- */
5591 /* 31 28 22 21 15 9 4
5592 0q0 01110 0 sz 1 00001 110110 n d SCVTF Vd, Vn
5593 0q1 01110 0 sz 1 00001 110110 n d UCVTF Vd, Vn
5594 with laneage:
5595 case sz:Q of 00 -> 2S, zero upper, 01 -> 4S, 10 -> illegal, 11 -> 2D
5596 */
5597 if (INSN(31,31) == 0 && INSN(28,23) == BITS6(0,1,1,1,0,0)
5598 && INSN(21,16) == BITS6(1,0,0,0,0,1)
5599 && INSN(15,10) == BITS6(1,1,0,1,1,0)) {
5600 Bool isQ = INSN(30,30) == 1;
5601 Bool isU = INSN(29,29) == 1;
5602 Bool isF64 = INSN(22,22) == 1;
5603 UInt nn = INSN(9,5);
5604 UInt dd = INSN(4,0);
5605 if (isQ || !isF64) {
5606 IRType tyF = Ity_INVALID, tyI = Ity_INVALID;
5607 UInt nLanes = 0;
5608 Bool zeroHI = False;
5609 const HChar* arrSpec = NULL;
5610 Bool ok = getLaneInfo_Q_SZ(&tyI, &tyF, &nLanes, &zeroHI, &arrSpec,
5611 isQ, isF64 );
5612 IROp op = isU ? (isF64 ? Iop_I64UtoF64 : Iop_I32UtoF32)
5613 : (isF64 ? Iop_I64StoF64 : Iop_I32StoF32);
5614 IRTemp rm = mk_get_IR_rounding_mode();
5615 UInt i;
5616 vassert(ok); /* the 'if' above should ensure this */
5617 for (i = 0; i < nLanes; i++) {
5618 putQRegLane(dd, i,
5619 binop(op, mkexpr(rm), getQRegLane(nn, i, tyI)));
5620 }
5621 if (zeroHI) {
5622 putQRegLane(dd, 1, mkU64(0));
5623 }
5624 DIP("%ccvtf %s.%s, %s.%s\n", isU ? 'u' : 's',
5625 nameQReg128(dd), arrSpec, nameQReg128(nn), arrSpec);
5626 return True;
5627 }
5628 /* else fall through */
5629 }
5630
5631 /* ---------- F{ADD,SUB,MUL,DIV,MLA,MLS} (vector) ---------- */
5632 /* 31 28 22 21 20 15 9 4 case
5633 0q0 01110 0 sz 1 m 110101 n d FADD Vd,Vn,Vm 1
5634 0q0 01110 1 sz 1 m 110101 n d FSUB Vd,Vn,Vm 2
5635 0q1 01110 0 sz 1 m 110111 n d FMUL Vd,Vn,Vm 3
5636 0q1 01110 0 sz 1 m 111111 n d FDIV Vd,Vn,Vm 4
5637 0q0 01110 0 sz 1 m 110011 n d FMLA Vd,Vn,Vm 5
5638 0q0 01110 1 sz 1 m 110011 n d FMLS Vd,Vn,Vm 6
sewardje520bb32014-02-17 11:00:53 +00005639 0q1 01110 1 sz 1 m 110101 n d FABD Vd,Vn,Vm 7
sewardj606c4ba2014-01-26 19:11:14 +00005640 */
5641 if (INSN(31,31) == 0
5642 && INSN(28,24) == BITS5(0,1,1,1,0) && INSN(21,21) == 1) {
5643 Bool isQ = INSN(30,30) == 1;
5644 UInt b29 = INSN(29,29);
5645 UInt b23 = INSN(23,23);
5646 Bool isF64 = INSN(22,22) == 1;
5647 UInt mm = INSN(20,16);
5648 UInt b1510 = INSN(15,10);
5649 UInt nn = INSN(9,5);
5650 UInt dd = INSN(4,0);
5651 UInt ix = 0;
5652 /**/ if (b29 == 0 && b23 == 0 && b1510 == BITS6(1,1,0,1,0,1)) ix = 1;
5653 else if (b29 == 0 && b23 == 1 && b1510 == BITS6(1,1,0,1,0,1)) ix = 2;
5654 else if (b29 == 1 && b23 == 0 && b1510 == BITS6(1,1,0,1,1,1)) ix = 3;
5655 else if (b29 == 1 && b23 == 0 && b1510 == BITS6(1,1,1,1,1,1)) ix = 4;
5656 else if (b29 == 0 && b23 == 0 && b1510 == BITS6(1,1,0,0,1,1)) ix = 5;
5657 else if (b29 == 0 && b23 == 1 && b1510 == BITS6(1,1,0,0,1,1)) ix = 6;
sewardje520bb32014-02-17 11:00:53 +00005658 else if (b29 == 1 && b23 == 1 && b1510 == BITS6(1,1,0,1,0,1)) ix = 7;
sewardj606c4ba2014-01-26 19:11:14 +00005659 IRType laneTy = Ity_INVALID;
5660 Bool zeroHI = False;
5661 const HChar* arr = "??";
5662 Bool ok
5663 = getLaneInfo_Q_SZ(NULL, &laneTy, NULL, &zeroHI, &arr, isQ, isF64);
5664 /* Skip MLA/MLS for the time being */
5665 if (ok && ix >= 1 && ix <= 4) {
5666 const IROp ops64[4]
5667 = { Iop_Add64Fx2, Iop_Sub64Fx2, Iop_Mul64Fx2, Iop_Div64Fx2 };
5668 const IROp ops32[4]
5669 = { Iop_Add32Fx4, Iop_Sub32Fx4, Iop_Mul32Fx4, Iop_Div32Fx4 };
5670 const HChar* names[4]
5671 = { "fadd", "fsub", "fmul", "fdiv" };
5672 IROp op = laneTy==Ity_F64 ? ops64[ix-1] : ops32[ix-1];
5673 IRTemp rm = mk_get_IR_rounding_mode();
5674 IRTemp t1 = newTemp(Ity_V128);
5675 IRTemp t2 = newTemp(Ity_V128);
5676 assign(t1, triop(op, mkexpr(rm), getQReg128(nn), getQReg128(mm)));
sewardjecde6972014-02-05 11:01:19 +00005677 assign(t2, zeroHI ? unop(Iop_ZeroHI64ofV128, mkexpr(t1))
5678 : mkexpr(t1));
sewardj606c4ba2014-01-26 19:11:14 +00005679 putQReg128(dd, mkexpr(t2));
5680 DIP("%s %s.%s, %s.%s, %s.%s\n", names[ix-1],
5681 nameQReg128(dd), arr, nameQReg128(nn), arr, nameQReg128(mm), arr);
5682 return True;
5683 }
sewardjfab09142014-02-10 10:28:13 +00005684 if (ok && ix >= 5 && ix <= 6) {
5685 IROp opADD = laneTy==Ity_F64 ? Iop_Add64Fx2 : Iop_Add32Fx4;
5686 IROp opSUB = laneTy==Ity_F64 ? Iop_Sub64Fx2 : Iop_Sub32Fx4;
5687 IROp opMUL = laneTy==Ity_F64 ? Iop_Mul64Fx2 : Iop_Mul32Fx4;
5688 IRTemp rm = mk_get_IR_rounding_mode();
5689 IRTemp t1 = newTemp(Ity_V128);
5690 IRTemp t2 = newTemp(Ity_V128);
5691 // FIXME: double rounding; use FMA primops instead
5692 assign(t1, triop(opMUL,
5693 mkexpr(rm), getQReg128(nn), getQReg128(mm)));
5694 assign(t2, triop(ix == 5 ? opADD : opSUB,
5695 mkexpr(rm), getQReg128(dd), mkexpr(t1)));
sewardje520bb32014-02-17 11:00:53 +00005696 putQReg128(dd, zeroHI ? unop(Iop_ZeroHI64ofV128, mkexpr(t2))
5697 : mkexpr(t2));
sewardjfab09142014-02-10 10:28:13 +00005698 DIP("%s %s.%s, %s.%s, %s.%s\n", ix == 5 ? "fmla" : "fmls",
5699 nameQReg128(dd), arr, nameQReg128(nn), arr, nameQReg128(mm), arr);
5700 return True;
5701 }
sewardje520bb32014-02-17 11:00:53 +00005702 if (ok && ix == 7) {
5703 IROp opSUB = laneTy==Ity_F64 ? Iop_Sub64Fx2 : Iop_Sub32Fx4;
5704 IROp opABS = laneTy==Ity_F64 ? Iop_Abs64Fx2 : Iop_Abs32Fx4;
5705 IRTemp rm = mk_get_IR_rounding_mode();
5706 IRTemp t1 = newTemp(Ity_V128);
5707 IRTemp t2 = newTemp(Ity_V128);
5708 // FIXME: use Abd primop instead?
5709 assign(t1, triop(opSUB,
5710 mkexpr(rm), getQReg128(nn), getQReg128(mm)));
5711 assign(t2, unop(opABS, mkexpr(t1)));
5712 putQReg128(dd, zeroHI ? unop(Iop_ZeroHI64ofV128, mkexpr(t2))
5713 : mkexpr(t2));
5714 DIP("fabd %s.%s, %s.%s, %s.%s\n",
5715 nameQReg128(dd), arr, nameQReg128(nn), arr, nameQReg128(mm), arr);
5716 return True;
5717 }
sewardj606c4ba2014-01-26 19:11:14 +00005718 }
5719
5720 /* ---------------- ADD/SUB (vector) ---------------- */
5721 /* 31 28 23 21 20 15 9 4
5722 0q0 01110 size 1 m 100001 n d ADD Vd.T, Vn.T, Vm.T
5723 0q1 01110 size 1 m 100001 n d SUB Vd.T, Vn.T, Vm.T
5724 */
5725 if (INSN(31,31) == 0 && INSN(28,24) == BITS5(0,1,1,1,0)
5726 && INSN(21,21) == 1 && INSN(15,10) == BITS6(1,0,0,0,0,1)) {
5727 Bool isQ = INSN(30,30) == 1;
5728 UInt szBlg2 = INSN(23,22);
5729 Bool isSUB = INSN(29,29) == 1;
5730 UInt mm = INSN(20,16);
5731 UInt nn = INSN(9,5);
5732 UInt dd = INSN(4,0);
5733 Bool zeroHI = False;
5734 const HChar* arrSpec = "";
5735 Bool ok = getLaneInfo_SIMPLE(&zeroHI, &arrSpec, isQ, szBlg2 );
5736 if (ok) {
sewardjf5b08912014-02-06 12:57:58 +00005737 const IROp opsADD[4]
sewardj606c4ba2014-01-26 19:11:14 +00005738 = { Iop_Add8x16, Iop_Add16x8, Iop_Add32x4, Iop_Add64x2 };
sewardjf5b08912014-02-06 12:57:58 +00005739 const IROp opsSUB[4]
sewardj606c4ba2014-01-26 19:11:14 +00005740 = { Iop_Sub8x16, Iop_Sub16x8, Iop_Sub32x4, Iop_Sub64x2 };
5741 vassert(szBlg2 < 4);
sewardjf5b08912014-02-06 12:57:58 +00005742 IROp op = isSUB ? opsSUB[szBlg2] : opsADD[szBlg2];
5743 IRTemp t = newTemp(Ity_V128);
sewardj606c4ba2014-01-26 19:11:14 +00005744 assign(t, binop(op, getQReg128(nn), getQReg128(mm)));
sewardjecde6972014-02-05 11:01:19 +00005745 putQReg128(dd, zeroHI ? unop(Iop_ZeroHI64ofV128, mkexpr(t))
5746 : mkexpr(t));
sewardj606c4ba2014-01-26 19:11:14 +00005747 const HChar* nm = isSUB ? "sub" : "add";
5748 DIP("%s %s.%s, %s.%s, %s.%s\n", nm,
5749 nameQReg128(dd), arrSpec,
5750 nameQReg128(nn), arrSpec, nameQReg128(mm), arrSpec);
5751 return True;
5752 }
5753 /* else fall through */
5754 }
5755
sewardjecde6972014-02-05 11:01:19 +00005756 /* ---------------- ADD/SUB (scalar) ---------------- */
5757 /* 31 28 23 21 20 15 9 4
5758 010 11110 11 1 m 100001 n d ADD Dd, Dn, Dm
5759 011 11110 11 1 m 100001 n d SUB Dd, Dn, Dm
5760 */
5761 if (INSN(31,30) == BITS2(0,1) && INSN(28,21) == BITS8(1,1,1,1,0,1,1,1)
5762 && INSN(15,10) == BITS6(1,0,0,0,0,1)) {
5763 Bool isSUB = INSN(29,29) == 1;
5764 UInt mm = INSN(20,16);
5765 UInt nn = INSN(9,5);
5766 UInt dd = INSN(4,0);
5767 IRTemp res = newTemp(Ity_I64);
5768 assign(res, binop(isSUB ? Iop_Sub64 : Iop_Add64,
5769 getQRegLane(nn, 0, Ity_I64),
5770 getQRegLane(mm, 0, Ity_I64)));
5771 putQRegLane(dd, 0, mkexpr(res));
5772 putQRegLane(dd, 1, mkU64(0));
5773 DIP("%s %s, %s, %s\n", isSUB ? "sub" : "add",
5774 nameQRegLO(dd, Ity_I64),
5775 nameQRegLO(nn, Ity_I64), nameQRegLO(mm, Ity_I64));
5776 return True;
5777 }
5778
sewardjf5b08912014-02-06 12:57:58 +00005779 /* ------------ MUL/PMUL/MLA/MLS (vector) ------------ */
5780 /* 31 28 23 21 20 15 9 4
5781 0q0 01110 size 1 m 100111 n d MUL Vd.T, Vn.T, Vm.T B/H/S only
5782 0q1 01110 size 1 m 100111 n d PMUL Vd.T, Vn.T, Vm.T B only
5783 0q0 01110 size 1 m 100101 n d MLA Vd.T, Vn.T, Vm.T B/H/S only
5784 0q1 01110 size 1 m 100101 n d MLS Vd.T, Vn.T, Vm.T B/H/S only
5785 */
5786 if (INSN(31,31) == 0 && INSN(28,24) == BITS5(0,1,1,1,0)
5787 && INSN(21,21) == 1
5788 && (INSN(15,10) & BITS6(1,1,1,1,0,1)) == BITS6(1,0,0,1,0,1)) {
5789 Bool isQ = INSN(30,30) == 1;
5790 UInt szBlg2 = INSN(23,22);
5791 UInt bit29 = INSN(29,29);
5792 UInt mm = INSN(20,16);
5793 UInt nn = INSN(9,5);
5794 UInt dd = INSN(4,0);
5795 Bool isMLAS = INSN(11,11) == 0;
5796 const IROp opsADD[4]
5797 = { Iop_Add8x16, Iop_Add16x8, Iop_Add32x4, Iop_INVALID };
5798 const IROp opsSUB[4]
5799 = { Iop_Sub8x16, Iop_Sub16x8, Iop_Sub32x4, Iop_INVALID };
5800 const IROp opsMUL[4]
5801 = { Iop_Mul8x16, Iop_Mul16x8, Iop_Mul32x4, Iop_INVALID };
5802 const IROp opsPMUL[4]
5803 = { Iop_PolynomialMul8x16, Iop_INVALID, Iop_INVALID, Iop_INVALID };
5804 /* Set opMUL and, if necessary, opACC. A result value of
5805 Iop_INVALID for opMUL indicates that the instruction is
5806 invalid. */
5807 Bool zeroHI = False;
5808 const HChar* arrSpec = "";
5809 Bool ok = getLaneInfo_SIMPLE(&zeroHI, &arrSpec, isQ, szBlg2 );
5810 vassert(szBlg2 < 4);
5811 IROp opACC = Iop_INVALID;
5812 IROp opMUL = Iop_INVALID;
5813 if (ok) {
5814 opMUL = (bit29 == 1 && !isMLAS) ? opsPMUL[szBlg2]
5815 : opsMUL[szBlg2];
5816 opACC = isMLAS ? (bit29 == 1 ? opsSUB[szBlg2] : opsADD[szBlg2])
5817 : Iop_INVALID;
5818 }
5819 if (ok && opMUL != Iop_INVALID) {
5820 IRTemp t1 = newTemp(Ity_V128);
5821 assign(t1, binop(opMUL, getQReg128(nn), getQReg128(mm)));
5822 IRTemp t2 = newTemp(Ity_V128);
5823 assign(t2, opACC == Iop_INVALID
5824 ? mkexpr(t1)
5825 : binop(opACC, getQReg128(dd), mkexpr(t1)));
5826 putQReg128(dd, zeroHI ? unop(Iop_ZeroHI64ofV128, mkexpr(t2))
5827 : mkexpr(t2));
5828 const HChar* nm = isMLAS ? (bit29 == 1 ? "mls" : "mla")
5829 : (bit29 == 1 ? "pmul" : "mul");
5830 DIP("%s %s.%s, %s.%s, %s.%s\n", nm,
5831 nameQReg128(dd), arrSpec,
5832 nameQReg128(nn), arrSpec, nameQReg128(mm), arrSpec);
5833 return True;
5834 }
5835 /* else fall through */
5836 }
5837
sewardjecde6972014-02-05 11:01:19 +00005838 /* ---------------- {S,U}{MIN,MAX} (vector) ---------------- */
5839 /* 31 28 23 21 20 15 9 4
5840 0q0 01110 size 1 m 011011 n d SMIN Vd.T, Vn.T, Vm.T
5841 0q1 01110 size 1 m 011011 n d UMIN Vd.T, Vn.T, Vm.T
5842 0q0 01110 size 1 m 011001 n d SMAX Vd.T, Vn.T, Vm.T
5843 0q1 01110 size 1 m 011001 n d UMAX Vd.T, Vn.T, Vm.T
5844 */
5845 if (INSN(31,31) == 0 && INSN(28,24) == BITS5(0,1,1,1,0)
5846 && INSN(21,21) == 1
5847 && ((INSN(15,10) & BITS6(1,1,1,1,0,1)) == BITS6(0,1,1,0,0,1))) {
5848 Bool isQ = INSN(30,30) == 1;
5849 Bool isU = INSN(29,29) == 1;
5850 UInt szBlg2 = INSN(23,22);
5851 Bool isMAX = INSN(12,12) == 0;
5852 UInt mm = INSN(20,16);
5853 UInt nn = INSN(9,5);
5854 UInt dd = INSN(4,0);
5855 Bool zeroHI = False;
5856 const HChar* arrSpec = "";
5857 Bool ok = getLaneInfo_SIMPLE(&zeroHI, &arrSpec, isQ, szBlg2 );
5858 if (ok) {
5859 const IROp opMINS[4]
5860 = { Iop_Min8Sx16, Iop_Min16Sx8, Iop_Min32Sx4, Iop_Min64Sx2 };
5861 const IROp opMINU[4]
5862 = { Iop_Min8Ux16, Iop_Min16Ux8, Iop_Min32Ux4, Iop_Min64Ux2 };
5863 const IROp opMAXS[4]
5864 = { Iop_Max8Sx16, Iop_Max16Sx8, Iop_Max32Sx4, Iop_Max64Sx2 };
5865 const IROp opMAXU[4]
5866 = { Iop_Max8Ux16, Iop_Max16Ux8, Iop_Max32Ux4, Iop_Max64Ux2 };
5867 vassert(szBlg2 < 4);
5868 IROp op = isMAX ? (isU ? opMAXU[szBlg2] : opMAXS[szBlg2])
5869 : (isU ? opMINU[szBlg2] : opMINS[szBlg2]);
5870 IRTemp t = newTemp(Ity_V128);
5871 assign(t, binop(op, getQReg128(nn), getQReg128(mm)));
5872 putQReg128(dd, zeroHI ? unop(Iop_ZeroHI64ofV128, mkexpr(t))
5873 : mkexpr(t));
5874 const HChar* nm = isMAX ? (isU ? "umax" : "smax")
5875 : (isU ? "umin" : "smin");
5876 DIP("%s %s.%s, %s.%s, %s.%s\n", nm,
5877 nameQReg128(dd), arrSpec,
5878 nameQReg128(nn), arrSpec, nameQReg128(mm), arrSpec);
5879 return True;
5880 }
5881 /* else fall through */
5882 }
5883
5884 /* -------------------- {S,U}{MIN,MAX}V -------------------- */
5885 /* 31 28 23 21 16 15 9 4
5886 0q0 01110 size 11000 1 101010 n d SMINV Vd, Vn.T
5887 0q1 01110 size 11000 1 101010 n d UMINV Vd, Vn.T
5888 0q0 01110 size 11000 0 101010 n d SMAXV Vd, Vn.T
5889 0q1 01110 size 11000 0 101010 n d UMAXV Vd, Vn.T
5890 */
5891 if (INSN(31,31) == 0 && INSN(28,24) == BITS5(0,1,1,1,0)
5892 && INSN(21,17) == BITS5(1,1,0,0,0)
5893 && INSN(15,10) == BITS6(1,0,1,0,1,0)) {
5894 Bool isQ = INSN(30,30) == 1;
5895 Bool isU = INSN(29,29) == 1;
5896 UInt szBlg2 = INSN(23,22);
5897 Bool isMAX = INSN(16,16) == 0;
5898 UInt nn = INSN(9,5);
5899 UInt dd = INSN(4,0);
5900 Bool zeroHI = False;
5901 const HChar* arrSpec = "";
5902 Bool ok = getLaneInfo_SIMPLE(&zeroHI, &arrSpec, isQ, szBlg2);
5903 if (ok) {
5904 if (szBlg2 == 3) ok = False;
5905 if (szBlg2 == 2 && !isQ) ok = False;
5906 }
5907 if (ok) {
5908 const IROp opMINS[3]
5909 = { Iop_Min8Sx16, Iop_Min16Sx8, Iop_Min32Sx4 };
5910 const IROp opMINU[3]
5911 = { Iop_Min8Ux16, Iop_Min16Ux8, Iop_Min32Ux4 };
5912 const IROp opMAXS[3]
5913 = { Iop_Max8Sx16, Iop_Max16Sx8, Iop_Max32Sx4 };
5914 const IROp opMAXU[3]
5915 = { Iop_Max8Ux16, Iop_Max16Ux8, Iop_Max32Ux4 };
5916 vassert(szBlg2 < 3);
5917 IROp op = isMAX ? (isU ? opMAXU[szBlg2] : opMAXS[szBlg2])
5918 : (isU ? opMINU[szBlg2] : opMINS[szBlg2]);
5919 IRTemp tN1 = newTemp(Ity_V128);
5920 assign(tN1, getQReg128(nn));
5921 /* If Q == 0, we're just folding lanes in the lower half of
5922 the value. In which case, copy the lower half of the
5923 source into the upper half, so we can then treat it the
5924 same as the full width case. */
5925 IRTemp tN2 = newTemp(Ity_V128);
5926 assign(tN2, zeroHI ? mk_CatOddLanes64x2(tN1,tN1) : mkexpr(tN1));
5927 IRTemp res = math_MINMAXV(tN2, op);
5928 if (res == IRTemp_INVALID)
5929 return False; /* means math_MINMAXV
5930 doesn't handle this case yet */
5931 putQReg128(dd, mkexpr(res));
5932 const HChar* nm = isMAX ? (isU ? "umaxv" : "smaxv")
5933 : (isU ? "uminv" : "sminv");
5934 const IRType tys[3] = { Ity_I8, Ity_I16, Ity_I32 };
5935 IRType laneTy = tys[szBlg2];
5936 DIP("%s %s, %s.%s\n", nm,
5937 nameQRegLO(dd, laneTy), nameQReg128(nn), arrSpec);
5938 return True;
5939 }
5940 /* else fall through */
5941 }
5942
sewardjfab09142014-02-10 10:28:13 +00005943 /* ------------ {AND,BIC,ORR,ORN} (vector) ------------ */
5944 /* 31 28 23 20 15 9 4
5945 0q0 01110 001 m 000111 n d AND Vd.T, Vn.T, Vm.T
5946 0q0 01110 011 m 000111 n d BIC Vd.T, Vn.T, Vm.T
5947 0q0 01110 101 m 000111 n d ORR Vd.T, Vn.T, Vm.T
5948 0q0 01110 111 m 000111 n d ORN Vd.T, Vn.T, Vm.T
5949 T is 16b when q==1, 8b when q==0
5950 */
5951 if (INSN(31,31) == 0 && INSN(29,24) == BITS6(0,0,1,1,1,0)
5952 && INSN(21,21) == 1 && INSN(15,10) == BITS6(0,0,0,1,1,1)) {
5953 Bool isQ = INSN(30,30) == 1;
5954 Bool isORR = INSN(23,23) == 1;
5955 Bool invert = INSN(22,22) == 1;
5956 UInt mm = INSN(20,16);
5957 UInt nn = INSN(9,5);
5958 UInt dd = INSN(4,0);
5959 IRTemp res = newTemp(Ity_V128);
5960 assign(res, binop(isORR ? Iop_OrV128 : Iop_AndV128,
5961 getQReg128(nn),
5962 invert ? unop(Iop_NotV128, getQReg128(mm))
5963 : getQReg128(mm)));
5964 putQReg128(dd, isQ ? mkexpr(res)
5965 : unop(Iop_ZeroHI64ofV128, mkexpr(res)));
5966 const HChar* names[4] = { "and", "bic", "orr", "orn" };
5967 const HChar* ar = isQ ? "16b" : "8b";
5968 DIP("%s %s.%s, %s.%s, %s.%s\n", names[INSN(23,22)],
5969 nameQReg128(dd), ar, nameQReg128(nn), ar, nameQReg128(mm), ar);
5970 return True;
5971 }
5972
sewardje520bb32014-02-17 11:00:53 +00005973 /* ---------- CM{EQ,HI,HS,GE,GT,TST,LE,LT} (vector) ---------- */
5974 /* 31 28 23 21 15 9 4 ix
5975 0q1 01110 size 1 m 100011 n d CMEQ Vd.T, Vn.T, Vm.T (1) ==
5976 0q0 01110 size 1 m 100011 n d CMTST Vd.T, Vn.T, Vm.T (2) &, == 0
5977
5978 0q1 01110 size 1 m 001101 n d CMHI Vd.T, Vn.T, Vm.T (3) >u
5979 0q0 01110 size 1 m 001101 n d CMGT Vd.T, Vn.T, Vm.T (4) >s
5980
5981 0q1 01110 size 1 m 001111 n d CMHS Vd.T, Vn.T, Vm.T (5) >=u
5982 0q0 01110 size 1 m 001111 n d CMGE Vd.T, Vn.T, Vm.T (6) >=s
5983
5984 0q1 01110 size 100000 100010 n d CMGE Vd.T, Vn.T, #0 (7) >=s 0
5985 0q0 01110 size 100000 100010 n d CMGT Vd.T, Vn.T, #0 (8) >s 0
5986
5987 0q1 01110 size 100000 100110 n d CMLE Vd.T, Vn.T, #0 (9) <=s 0
5988 0q0 01110 size 100000 100110 n d CMEQ Vd.T, Vn.T, #0 (10) == 0
5989
5990 0q0 01110 size 100000 101010 n d CMLT Vd.T, Vn.T, #0 (11) <s 0
5991 */
5992 if (INSN(31,31) == 0
5993 && INSN(28,24) == BITS5(0,1,1,1,0) && INSN(21,21) == 1) {
5994 Bool isQ = INSN(30,30) == 1;
5995 UInt bit29 = INSN(29,29);
5996 UInt szBlg2 = INSN(23,22);
5997 UInt mm = INSN(20,16);
5998 UInt b1510 = INSN(15,10);
5999 UInt nn = INSN(9,5);
6000 UInt dd = INSN(4,0);
6001 const IROp opsEQ[4]
6002 = { Iop_CmpEQ8x16, Iop_CmpEQ16x8, Iop_CmpEQ32x4, Iop_CmpEQ64x2 };
6003 const IROp opsGTS[4]
6004 = { Iop_CmpGT8Sx16, Iop_CmpGT16Sx8, Iop_CmpGT32Sx4, Iop_CmpGT64Sx2 };
6005 const IROp opsGTU[4]
6006 = { Iop_CmpGT8Ux16, Iop_CmpGT16Ux8, Iop_CmpGT32Ux4, Iop_CmpGT64Ux2 };
6007 Bool zeroHI = False;
6008 const HChar* arrSpec = "??";
6009 Bool ok = getLaneInfo_SIMPLE(&zeroHI, &arrSpec, isQ, szBlg2);
6010 UInt ix = 0;
6011 if (ok) {
6012 switch (b1510) {
6013 case BITS6(1,0,0,0,1,1): ix = bit29 ? 1 : 2; break;
6014 case BITS6(0,0,1,1,0,1): ix = bit29 ? 3 : 4; break;
6015 case BITS6(0,0,1,1,1,1): ix = bit29 ? 5 : 6; break;
6016 case BITS6(1,0,0,0,1,0):
6017 if (mm == 0) { ix = bit29 ? 7 : 8; }; break;
6018 case BITS6(1,0,0,1,1,0):
6019 if (mm == 0) { ix = bit29 ? 9 : 10; }; break;
6020 case BITS6(1,0,1,0,1,0):
6021 if (mm == 0 && bit29 == 0) { ix = 11; }; break;
6022 default: break;
6023 }
6024 }
6025 if (ix != 0) {
6026 vassert(ok && szBlg2 < 4);
6027 IRExpr* argL = getQReg128(nn);
6028 IRExpr* argR = (ix <= 6) ? getQReg128(mm) : mkV128(0x0000);
6029 IRExpr* res = NULL;
6030 /* Some useful identities:
6031 x > y can be expressed directly
6032 x < y == y > x
6033 x <= y == not (x > y)
6034 x >= y == not (y > x)
6035 */
6036 switch (ix) {
6037 case 1: res = binop(opsEQ[szBlg2], argL, argR); break;
6038 case 2: binop(opsEQ[szBlg2],
6039 binop(Iop_AndV128, argL, argR),
6040 mkV128(0x0000));
6041 break;
6042 case 3: res = binop(opsGTU[szBlg2], argL, argR); break;
6043 case 4: res = binop(opsGTS[szBlg2], argL, argR); break;
6044 case 5: res = unop(Iop_NotV128, binop(opsGTU[szBlg2], argR, argL));
6045 break;
6046 case 6: res = unop(Iop_NotV128, binop(opsGTS[szBlg2], argR, argL));
6047 break;
6048 case 7: res = unop(Iop_NotV128, binop(opsGTS[szBlg2], argR, argL));
6049 break;
6050 case 8: res = binop(opsGTS[szBlg2], argL, argR); break;
6051 case 9: res = unop(Iop_NotV128,
6052 binop(opsGTS[szBlg2], argL, argR));
6053 break;
6054 case 10: res = binop(opsEQ[szBlg2], argL, argR); break;
6055 case 11: res = binop(opsGTS[szBlg2], argR, argL); break;
6056 default: vassert(0);
6057 }
6058 vassert(res);
6059 putQReg128(dd, zeroHI ? unop(Iop_ZeroHI64ofV128, res) : res);
6060 const HChar* nms[11] = { "eq", "tst", "hi", "gt", "hs", "ge",
6061 "ge", "gt", "le", "eq", "lt" };
6062 if (ix <= 6) {
6063 DIP("cm%s %s.%s, %s.%s, %s.%s\n", nms[ix-1],
6064 nameQReg128(dd), arrSpec,
6065 nameQReg128(nn), arrSpec, nameQReg128(mm), arrSpec);
6066 } else {
6067 DIP("cm%s %s.%s, %s.%s, #0\n", nms[ix-1],
6068 nameQReg128(dd), arrSpec, nameQReg128(nn), arrSpec);
6069 }
6070 return True;
6071 }
6072 /* else fall through */
6073 }
6074
6075 /* -------------- {EOR,BSL,BIT,BIF} (vector) -------------- */
6076 /* 31 28 23 20 15 9 4
6077 0q1 01110 00 1 m 000111 n d EOR Vd.T, Vm.T, Vn.T
6078 0q1 01110 01 1 m 000111 n d BSL Vd.T, Vm.T, Vn.T
6079 0q1 01110 10 1 m 000111 n d BIT Vd.T, Vm.T, Vn.T
6080 0q1 01110 11 1 m 000111 n d BIF Vd.T, Vm.T, Vn.T
6081 */
6082 if (INSN(31,31) == 0 && INSN(29,24) == BITS6(1,0,1,1,1,0)
6083 && INSN(21,21) == 1 && INSN(15,10) == BITS6(0,0,0,1,1,1)) {
6084 Bool isQ = INSN(30,30) == 1;
6085 UInt op = INSN(23,22);
6086 UInt mm = INSN(20,16);
6087 UInt nn = INSN(9,5);
6088 UInt dd = INSN(4,0);
6089 IRTemp argD = newTemp(Ity_V128);
6090 IRTemp argN = newTemp(Ity_V128);
6091 IRTemp argM = newTemp(Ity_V128);
6092 assign(argD, getQReg128(dd));
6093 assign(argN, getQReg128(nn));
6094 assign(argM, getQReg128(mm));
6095 const IROp opXOR = Iop_XorV128;
6096 const IROp opAND = Iop_AndV128;
6097 const IROp opNOT = Iop_NotV128;
6098 IRExpr* res = NULL;
6099 switch (op) {
6100 case BITS2(0,0):
6101 res = binop(opXOR, mkexpr(argM), mkexpr(argN));
6102 break;
6103 case BITS2(0,1):
6104 res = binop(opXOR, mkexpr(argM),
6105 binop(opAND,
6106 binop(opXOR, mkexpr(argM), mkexpr(argN)),
6107 mkexpr(argD)));
6108 break;
6109 case BITS2(1,0):
6110 res = binop(opXOR, mkexpr(argD),
6111 binop(opAND,
6112 binop(opXOR, mkexpr(argD), mkexpr(argN)),
6113 mkexpr(argM)));
6114 break;
6115 case BITS2(1,1):
6116 res = binop(opXOR, mkexpr(argD),
6117 binop(opAND,
6118 binop(opXOR, mkexpr(argD), mkexpr(argN)),
6119 unop(opNOT, mkexpr(argM))));
6120 break;
6121 default:
6122 vassert(0);
6123 }
6124 vassert(res);
6125 putQReg128(dd, isQ ? res : unop(Iop_ZeroHI64ofV128, res));
6126 const HChar* nms[4] = { "eor", "bsl", "bit", "bif" };
6127 const HChar* arr = isQ ? "16b" : "8b";
6128 vassert(op < 4);
6129 DIP("%s %s.%s, %s.%s, %s.%s\n", nms[op],
6130 nameQReg128(dd), arr, nameQReg128(nn), arr, nameQReg128(mm), arr);
6131 return True;
6132 }
6133
6134 /* ------------ {USHR,SSHR} (vector, immediate) ------------ */
6135 /* 31 28 22 18 15 9 4
6136 0q1 011110 immh immb 000001 n d USHR Vd.T, Vn.T, #shift
6137 0q0 011110 immh immb 000001 n d SSHR Vd.T, Vn.T, #shift
6138 laneTy, shift = case immh:immb of
6139 0001:xxx -> B, 8-xxx
6140 001x:xxx -> H, 16-xxxx
6141 01xx:xxx -> S, 32-xxxxx
6142 1xxx:xxx -> D, 64-xxxxxx
6143 other -> invalid
6144 As usual the case laneTy==D && q==0 is not allowed.
6145 */
6146 if (INSN(31,31) == 0 && INSN(28,23) == BITS6(0,1,1,1,1,0)
6147 && INSN(15,10) == BITS6(0,0,0,0,0,1)) {
6148 Bool isQ = INSN(30,30) == 1;
6149 Bool isU = INSN(29,29) == 1;
6150 UInt immh = INSN(22,19);
6151 UInt immb = INSN(18,16);
6152 UInt nn = INSN(9,5);
6153 UInt dd = INSN(4,0);
6154 const IROp opsSHRN[4]
6155 = { Iop_ShrN8x16, Iop_ShrN16x8, Iop_ShrN32x4, Iop_ShrN64x2 };
6156 const IROp opsSARN[4]
6157 = { Iop_SarN8x16, Iop_SarN16x8, Iop_SarN32x4, Iop_SarN64x2 };
6158 UInt szBlg2 = 0;
6159 UInt shift = 0;
6160 Bool ok = getLaneInfo_IMMH_IMMB(&shift, &szBlg2, immh, immb);
6161 if (ok && szBlg2 < 4 && shift > 0 && shift < (8 << szBlg2)
6162 && !(szBlg2 == 3/*64bit*/ && !isQ)) {
6163 IROp op = isU ? opsSHRN[szBlg2] : opsSARN[szBlg2];
6164 IRExpr* src = getQReg128(nn);
6165 IRExpr* res = binop(op, src, mkU8(shift));
6166 putQReg128(dd, isQ ? res : unop(Iop_ZeroHI64ofV128, res));
6167 HChar laneCh = "bhsd"[szBlg2];
6168 UInt nLanes = (isQ ? 128 : 64) / (8 << szBlg2);
6169 DIP("%s %s.%u%c, %s.%u%c, #%u\n", isU ? "ushr" : "sshr",
6170 nameQReg128(dd), nLanes, laneCh,
6171 nameQReg128(nn), nLanes, laneCh, shift);
6172 return True;
6173 }
6174 /* else fall through */
6175 }
6176
6177 /* -------------------- {U,S}SHLL{,2} -------------------- */
6178 /* 31 28 22 18 15 9 4
6179 0q0 011110 immh immb 101001 n d SSHLL Vd.Ta, Vn.Tb, #sh
6180 0q1 011110 immh immb 101001 n d USHLL Vd.Ta, Vn.Tb, #sh
6181 where Ta,Tb,sh
6182 = case immh of 0001 -> 8h, 8b(q0)/16b(q1), immh:immb - 8 (0..7)
6183 001x -> 4s, 4h(q0)/8h(q1), immh:immb - 16 (0..15)
6184 01xx -> 2d, 2s(q0)/4s(q1), immh:immb - 32 (0..31)
6185 */
6186 if (INSN(31,31) == 0 && INSN(28,23) == BITS6(0,1,1,1,1,0)
6187 && INSN(15,10) == BITS6(1,0,1,0,0,1)) {
6188 Bool isQ = INSN(30,30) == 1;
6189 Bool isU = INSN(29,29) == 1;
6190 UInt immh = INSN(22,19);
6191 UInt immb = INSN(18,16);
6192 UInt nn = INSN(9,5);
6193 UInt dd = INSN(4,0);
6194 UInt immhb = (immh << 3) | immb;
6195 IRTemp src = newTemp(Ity_V128);
6196 IRTemp zero = newTemp(Ity_V128);
6197 IRExpr* res = NULL;
6198 UInt sh = 0;
6199 const HChar* ta = "??";
6200 const HChar* tb = "??";
6201 assign(src, getQReg128(nn));
6202 assign(zero, mkV128(0x0000));
6203 if (immh & 1) {
6204 sh = immhb - 8;
6205 vassert(sh < 8); /* so 8-sh is 1..8 */
6206 ta = "8h";
6207 tb = isQ ? "16b" : "8b";
6208 IRExpr* tmp = isQ ? mk_InterleaveHI8x16(src, zero)
6209 : mk_InterleaveLO8x16(src, zero);
6210 res = binop(isU ? Iop_ShrN16x8 : Iop_SarN16x8, tmp, mkU8(8-sh));
6211 }
6212 else if (immh & 2) {
6213 sh = immhb - 16;
6214 vassert(sh < 16); /* so 16-sh is 1..16 */
6215 ta = "4s";
6216 tb = isQ ? "8h" : "4h";
6217 IRExpr* tmp = isQ ? mk_InterleaveHI16x8(src, zero)
6218 : mk_InterleaveLO16x8(src, zero);
6219 res = binop(isU ? Iop_ShrN32x4 : Iop_SarN32x4, tmp, mkU8(16-sh));
6220 }
6221 else if (immh & 4) {
6222 sh = immhb - 32;
6223 vassert(sh < 32); /* so 32-sh is 1..32 */
6224 ta = "2d";
6225 tb = isQ ? "4s" : "2s";
6226 IRExpr* tmp = isQ ? mk_InterleaveHI32x4(src, zero)
6227 : mk_InterleaveLO32x4(src, zero);
6228 res = binop(isU ? Iop_ShrN64x2 : Iop_SarN64x2, tmp, mkU8(32-sh));
6229 }
6230 /* */
6231 if (res) {
6232 putQReg128(dd, res);
6233 DIP("%cshll%s %s.%s, %s.%s, #%d\n",
6234 isU ? 'u' : 's', isQ ? "2" : "",
6235 nameQReg128(dd), ta, nameQReg128(nn), tb, sh);
6236 return True;
6237 }
6238 /* else fall through */
6239 }
6240
sewardj606c4ba2014-01-26 19:11:14 +00006241 /* -------------------- XTN{,2} -------------------- */
sewardjecde6972014-02-05 11:01:19 +00006242 /* 31 28 23 21 15 9 4 XTN{,2} Vd.Tb, Vn.Ta
sewardj606c4ba2014-01-26 19:11:14 +00006243 0q0 01110 size 100001 001010 n d
6244 */
6245 if (INSN(31,31) == 0 && INSN(29,24) == BITS6(0,0,1,1,1,0)
6246 && INSN(21,16) == BITS6(1,0,0,0,0,1)
6247 && INSN(15,10) == BITS6(0,0,1,0,1,0)) {
6248 Bool isQ = INSN(30,30) == 1;
6249 UInt size = INSN(23,22);
6250 UInt nn = INSN(9,5);
6251 UInt dd = INSN(4,0);
6252 IROp op = Iop_INVALID;
6253 const HChar* tb = NULL;
6254 const HChar* ta = NULL;
6255 switch ((size << 1) | (isQ ? 1 : 0)) {
6256 case 0: tb = "8b"; ta = "8h"; op = Iop_NarrowUn16to8x8; break;
6257 case 1: tb = "16b"; ta = "8h"; op = Iop_NarrowUn16to8x8; break;
6258 case 2: tb = "4h"; ta = "4s"; op = Iop_NarrowUn32to16x4; break;
6259 case 3: tb = "8h"; ta = "4s"; op = Iop_NarrowUn32to16x4; break;
6260 case 4: tb = "2s"; ta = "2d"; op = Iop_NarrowUn64to32x2; break;
6261 case 5: tb = "4s"; ta = "2d"; op = Iop_NarrowUn64to32x2; break;
6262 case 6: break;
6263 case 7: break;
6264 default: vassert(0);
6265 }
6266 if (op != Iop_INVALID) {
6267 if (!isQ) {
6268 putQRegLane(dd, 1, mkU64(0));
6269 }
6270 putQRegLane(dd, isQ ? 1 : 0, unop(op, getQReg128(nn)));
6271 DIP("xtn%s %s.%s, %s.%s\n", isQ ? "2" : "",
6272 nameQReg128(dd), tb, nameQReg128(nn), ta);
6273 return True;
6274 }
6275 /* else fall through */
6276 }
6277
6278 /* ---------------- DUP (element, vector) ---------------- */
6279 /* 31 28 20 15 9 4
6280 0q0 01110000 imm5 000001 n d DUP Vd.T, Vn.Ts[index]
6281 */
6282 if (INSN(31,31) == 0 && INSN(29,21) == BITS9(0,0,1,1,1,0,0,0,0)
6283 && INSN(15,10) == BITS6(0,0,0,0,0,1)) {
6284 Bool isQ = INSN(30,30) == 1;
6285 UInt imm5 = INSN(20,16);
6286 UInt nn = INSN(9,5);
6287 UInt dd = INSN(4,0);
6288 IRTemp w0 = newTemp(Ity_I64);
6289 const HChar* arT = "??";
6290 const HChar* arTs = "??";
6291 IRType laneTy = Ity_INVALID;
6292 UInt laneNo = 16; /* invalid */
6293 if (imm5 & 1) {
6294 arT = isQ ? "16b" : "8b";
6295 arTs = "b";
6296 laneNo = (imm5 >> 1) & 15;
6297 laneTy = Ity_I8;
6298 assign(w0, unop(Iop_8Uto64, getQRegLane(nn, laneNo, laneTy)));
6299 }
6300 else if (imm5 & 2) {
6301 arT = isQ ? "8h" : "4h";
6302 arTs = "h";
6303 laneNo = (imm5 >> 2) & 7;
6304 laneTy = Ity_I16;
6305 assign(w0, unop(Iop_16Uto64, getQRegLane(nn, laneNo, laneTy)));
6306 }
6307 else if (imm5 & 4) {
6308 arT = isQ ? "4s" : "2s";
6309 arTs = "s";
6310 laneNo = (imm5 >> 3) & 3;
6311 laneTy = Ity_I32;
6312 assign(w0, unop(Iop_32Uto64, getQRegLane(nn, laneNo, laneTy)));
6313 }
6314 else if ((imm5 & 8) && isQ) {
6315 arT = "2d";
6316 arTs = "d";
6317 laneNo = (imm5 >> 4) & 1;
6318 laneTy = Ity_I64;
6319 assign(w0, getQRegLane(nn, laneNo, laneTy));
6320 }
6321 else {
6322 /* invalid; leave laneTy unchanged. */
6323 }
6324 /* */
6325 if (laneTy != Ity_INVALID) {
6326 vassert(laneNo < 16);
6327 IRTemp w1 = math_DUP_TO_64(w0, laneTy);
6328 putQReg128(dd, binop(Iop_64HLtoV128,
6329 isQ ? mkexpr(w1) : mkU64(0), mkexpr(w1)));
6330 DIP("dup %s.%s, %s.%s[%u]\n",
6331 nameQReg128(dd), arT, nameQReg128(nn), arTs, laneNo);
6332 return True;
6333 }
6334 /* else fall through */
6335 }
6336
sewardjecde6972014-02-05 11:01:19 +00006337 /* ---------------- DUP (general, vector) ---------------- */
6338 /* 31 28 23 20 15 9 4
6339 0q0 01110 000 imm5 000011 n d DUP Vd.T, Rn
6340 Q=0 writes 64, Q=1 writes 128
6341 imm5: xxxx1 8B(q=0) or 16b(q=1), R=W
6342 xxx10 4H(q=0) or 8H(q=1), R=W
6343 xx100 2S(q=0) or 4S(q=1), R=W
6344 x1000 Invalid(q=0) or 2D(q=1), R=X
6345 x0000 Invalid(q=0) or Invalid(q=1)
6346 */
6347 if (INSN(31,31) == 0 && INSN(29,21) == BITS9(0,0,1,1,1,0,0,0,0)
6348 && INSN(15,10) == BITS6(0,0,0,0,1,1)) {
6349 Bool isQ = INSN(30,30) == 1;
6350 UInt imm5 = INSN(20,16);
6351 UInt nn = INSN(9,5);
6352 UInt dd = INSN(4,0);
6353 IRTemp w0 = newTemp(Ity_I64);
6354 const HChar* arT = "??";
6355 IRType laneTy = Ity_INVALID;
6356 if (imm5 & 1) {
6357 arT = isQ ? "16b" : "8b";
6358 laneTy = Ity_I8;
6359 assign(w0, unop(Iop_8Uto64, unop(Iop_64to8, getIReg64orZR(nn))));
6360 }
6361 else if (imm5 & 2) {
6362 arT = isQ ? "8h" : "4h";
6363 laneTy = Ity_I16;
6364 assign(w0, unop(Iop_16Uto64, unop(Iop_64to16, getIReg64orZR(nn))));
6365 }
6366 else if (imm5 & 4) {
6367 arT = isQ ? "4s" : "2s";
6368 laneTy = Ity_I32;
6369 assign(w0, unop(Iop_32Uto64, unop(Iop_64to32, getIReg64orZR(nn))));
6370 }
6371 else if ((imm5 & 8) && isQ) {
6372 arT = "2d";
6373 laneTy = Ity_I64;
6374 assign(w0, getIReg64orZR(nn));
6375 }
6376 else {
6377 /* invalid; leave laneTy unchanged. */
6378 }
6379 /* */
6380 if (laneTy != Ity_INVALID) {
6381 IRTemp w1 = math_DUP_TO_64(w0, laneTy);
6382 putQReg128(dd, binop(Iop_64HLtoV128,
6383 isQ ? mkexpr(w1) : mkU64(0), mkexpr(w1)));
6384 DIP("dup %s.%s, %s\n",
6385 nameQReg128(dd), arT, nameIRegOrZR(laneTy == Ity_I64, nn));
6386 return True;
6387 }
6388 /* else fall through */
6389 }
6390
sewardjf5b08912014-02-06 12:57:58 +00006391 /* ---------------------- {S,U}MOV ---------------------- */
6392 /* 31 28 20 15 9 4
6393 0q0 01110 000 imm5 001111 n d UMOV Xd/Wd, Vn.Ts[index]
6394 0q0 01110 000 imm5 001011 n d SMOV Xd/Wd, Vn.Ts[index]
6395 dest is Xd when q==1, Wd when q==0
6396 UMOV:
6397 Ts,index,ops = case q:imm5 of
6398 0:xxxx1 -> B, xxxx, 8Uto64
6399 1:xxxx1 -> invalid
6400 0:xxx10 -> H, xxx, 16Uto64
6401 1:xxx10 -> invalid
6402 0:xx100 -> S, xx, 32Uto64
6403 1:xx100 -> invalid
6404 1:x1000 -> D, x, copy64
6405 other -> invalid
6406 SMOV:
6407 Ts,index,ops = case q:imm5 of
6408 0:xxxx1 -> B, xxxx, (32Uto64 . 8Sto32)
6409 1:xxxx1 -> B, xxxx, 8Sto64
6410 0:xxx10 -> H, xxx, (32Uto64 . 16Sto32)
6411 1:xxx10 -> H, xxx, 16Sto64
6412 0:xx100 -> invalid
6413 1:xx100 -> S, xx, 32Sto64
6414 1:x1000 -> invalid
6415 other -> invalid
6416 */
6417 if (INSN(31,31) == 0 && INSN(29,21) == BITS9(0,0,1,1,1,0,0,0,0)
6418 && (INSN(15,10) & BITS6(1,1,1,0,1,1)) == BITS6(0,0,1,0,1,1)) {
6419 UInt bitQ = INSN(30,30) == 1;
6420 UInt imm5 = INSN(20,16);
6421 UInt nn = INSN(9,5);
6422 UInt dd = INSN(4,0);
6423 Bool isU = INSN(12,12) == 1;
6424 const HChar* arTs = "??";
6425 UInt laneNo = 16; /* invalid */
6426 // Setting 'res' to non-NULL determines valid/invalid
6427 IRExpr* res = NULL;
6428 if (!bitQ && (imm5 & 1)) { // 0:xxxx1
6429 laneNo = (imm5 >> 1) & 15;
6430 IRExpr* lane = getQRegLane(nn, laneNo, Ity_I8);
6431 res = isU ? unop(Iop_8Uto64, lane)
6432 : unop(Iop_32Uto64, unop(Iop_8Sto32, lane));
6433 arTs = "b";
6434 }
6435 else if (bitQ && (imm5 & 1)) { // 1:xxxx1
6436 laneNo = (imm5 >> 1) & 15;
6437 IRExpr* lane = getQRegLane(nn, laneNo, Ity_I8);
6438 res = isU ? NULL
6439 : unop(Iop_8Sto64, lane);
6440 arTs = "b";
6441 }
6442 else if (!bitQ && (imm5 & 2)) { // 0:xxx10
6443 laneNo = (imm5 >> 2) & 7;
6444 IRExpr* lane = getQRegLane(nn, laneNo, Ity_I16);
6445 res = isU ? unop(Iop_16Uto64, lane)
6446 : unop(Iop_32Uto64, unop(Iop_16Sto32, lane));
6447 arTs = "h";
6448 }
6449 else if (bitQ && (imm5 & 2)) { // 1:xxx10
6450 laneNo = (imm5 >> 2) & 7;
6451 IRExpr* lane = getQRegLane(nn, laneNo, Ity_I16);
6452 res = isU ? NULL
6453 : unop(Iop_16Sto64, lane);
6454 arTs = "h";
6455 }
6456 else if (!bitQ && (imm5 & 4)) { // 0:xx100
6457 laneNo = (imm5 >> 3) & 3;
6458 IRExpr* lane = getQRegLane(nn, laneNo, Ity_I32);
6459 res = isU ? unop(Iop_32Uto64, lane)
6460 : NULL;
6461 arTs = "s";
6462 }
6463 else if (bitQ && (imm5 & 4)) { // 1:xxx10
6464 laneNo = (imm5 >> 3) & 3;
6465 IRExpr* lane = getQRegLane(nn, laneNo, Ity_I32);
6466 res = isU ? NULL
6467 : unop(Iop_32Sto64, lane);
6468 arTs = "s";
6469 }
6470 else if (bitQ && (imm5 & 8)) { // 1:x1000
6471 laneNo = (imm5 >> 4) & 1;
6472 IRExpr* lane = getQRegLane(nn, laneNo, Ity_I64);
6473 res = isU ? lane
6474 : NULL;
6475 arTs = "d";
6476 }
6477 /* */
6478 if (res) {
6479 vassert(laneNo < 16);
6480 putIReg64orZR(dd, res);
6481 DIP("%cmov %s, %s.%s[%u]\n", isU ? 'u' : 's',
6482 nameIRegOrZR(bitQ == 1, dd),
6483 nameQReg128(nn), arTs, laneNo);
6484 return True;
6485 }
6486 /* else fall through */
6487 }
6488
sewardje520bb32014-02-17 11:00:53 +00006489 /* -------------------- INS (general) -------------------- */
6490 /* 31 28 20 15 9 4
6491 010 01110000 imm5 000111 n d INS Vd.Ts[ix], Rn
6492 where Ts,ix = case imm5 of xxxx1 -> B, xxxx
6493 xxx10 -> H, xxx
6494 xx100 -> S, xx
6495 x1000 -> D, x
6496 */
6497 if (INSN(31,21) == BITS11(0,1,0,0,1,1,1,0,0,0,0)
6498 && INSN(15,10) == BITS6(0,0,0,1,1,1)) {
6499 UInt imm5 = INSN(20,16);
6500 UInt nn = INSN(9,5);
6501 UInt dd = INSN(4,0);
6502 HChar ts = '?';
6503 UInt laneNo = 16;
6504 IRExpr* src = NULL;
6505 if (imm5 & 1) {
6506 src = unop(Iop_64to8, getIReg64orZR(nn));
6507 laneNo = (imm5 >> 1) & 15;
6508 ts = 'b';
6509 }
6510 else if (imm5 & 2) {
6511 src = unop(Iop_64to16, getIReg64orZR(nn));
6512 laneNo = (imm5 >> 2) & 7;
6513 ts = 'h';
6514 }
6515 else if (imm5 & 4) {
6516 src = unop(Iop_64to32, getIReg64orZR(nn));
6517 laneNo = (imm5 >> 3) & 3;
6518 ts = 's';
6519 }
6520 else if (imm5 & 8) {
6521 src = getIReg64orZR(nn);
6522 laneNo = (imm5 >> 4) & 1;
6523 ts = 'd';
6524 }
6525 /* */
6526 if (src) {
6527 vassert(laneNo < 16);
6528 putQRegLane(dd, laneNo, src);
6529 DIP("ins %s.%c[%u], %s\n",
6530 nameQReg128(dd), ts, laneNo, nameIReg64orZR(nn));
6531 return True;
6532 }
6533 /* else invalid; fall through */
6534 }
6535
sewardjbbcf1882014-01-12 12:49:10 +00006536 /* FIXME Temporary hacks to get through ld.so FIXME */
6537
6538 /* ------------------ movi vD.4s, #0x0 ------------------ */
6539 /* 0x4F 0x00 0x04 000 vD */
6540 if ((insn & 0xFFFFFFE0) == 0x4F000400) {
6541 UInt vD = INSN(4,0);
6542 putQReg128(vD, mkV128(0x0000));
6543 DIP("movi v%u.4s, #0x0\n", vD);
6544 return True;
6545 }
6546
sewardjbbcf1882014-01-12 12:49:10 +00006547 /* ---------------- MOV vD.16b, vN.16b ---------------- */
6548 /* 31 23 20 15 9 4
6549 010 01110 101 m 000111 n d ORR vD.16b, vN.16b, vM.16b
6550 This only handles the N == M case.
6551 */
6552 if (INSN(31,24) == BITS8(0,1,0,0,1,1,1,0)
6553 && INSN(23,21) == BITS3(1,0,1) && INSN(15,10) == BITS6(0,0,0,1,1,1)) {
6554 UInt mm = INSN(20,16);
6555 UInt nn = INSN(9,5);
6556 UInt dd = INSN(4,0);
6557 if (mm == nn) {
6558 putQReg128(dd, getQReg128(nn));
6559 DIP("mov v%u.16b, v%u.16b\n", dd, nn);
6560 return True;
6561 }
6562 /* else it's really an ORR; fall through. */
6563 }
6564
6565 vex_printf("ARM64 front end: simd_and_fp\n");
6566 return False;
6567# undef INSN
6568}
6569
6570
6571/*------------------------------------------------------------*/
6572/*--- Disassemble a single ARM64 instruction ---*/
6573/*------------------------------------------------------------*/
6574
6575/* Disassemble a single ARM64 instruction into IR. The instruction
6576 has is located at |guest_instr| and has guest IP of
6577 |guest_PC_curr_instr|, which will have been set before the call
6578 here. Returns True iff the instruction was decoded, in which case
6579 *dres will be set accordingly, or False, in which case *dres should
6580 be ignored by the caller. */
6581
6582static
6583Bool disInstr_ARM64_WRK (
6584 /*MB_OUT*/DisResult* dres,
6585 Bool (*resteerOkFn) ( /*opaque*/void*, Addr64 ),
6586 Bool resteerCisOk,
6587 void* callback_opaque,
6588 UChar* guest_instr,
6589 VexArchInfo* archinfo,
6590 VexAbiInfo* abiinfo
6591 )
6592{
6593 // A macro to fish bits out of 'insn'.
6594# define INSN(_bMax,_bMin) SLICE_UInt(insn, (_bMax), (_bMin))
6595
6596//ZZ DisResult dres;
6597//ZZ UInt insn;
6598//ZZ //Bool allow_VFP = False;
6599//ZZ //UInt hwcaps = archinfo->hwcaps;
6600//ZZ IRTemp condT; /* :: Ity_I32 */
6601//ZZ UInt summary;
6602//ZZ HChar dis_buf[128]; // big enough to hold LDMIA etc text
6603//ZZ
6604//ZZ /* What insn variants are we supporting today? */
6605//ZZ //allow_VFP = (0 != (hwcaps & VEX_HWCAPS_ARM_VFP));
6606//ZZ // etc etc
6607
6608 /* Set result defaults. */
6609 dres->whatNext = Dis_Continue;
6610 dres->len = 4;
6611 dres->continueAt = 0;
6612 dres->jk_StopHere = Ijk_INVALID;
6613
6614 /* At least this is simple on ARM64: insns are all 4 bytes long, and
6615 4-aligned. So just fish the whole thing out of memory right now
6616 and have done. */
6617 UInt insn = getUIntLittleEndianly( guest_instr );
6618
6619 if (0) vex_printf("insn: 0x%x\n", insn);
6620
6621 DIP("\t(arm64) 0x%llx: ", (ULong)guest_PC_curr_instr);
6622
6623 vassert(0 == (guest_PC_curr_instr & 3ULL));
6624
6625 /* ----------------------------------------------------------- */
6626
6627 /* Spot "Special" instructions (see comment at top of file). */
6628 {
6629 UChar* code = (UChar*)guest_instr;
6630 /* Spot the 16-byte preamble:
6631 93CC0D8C ror x12, x12, #3
6632 93CC358C ror x12, x12, #13
6633 93CCCD8C ror x12, x12, #51
6634 93CCF58C ror x12, x12, #61
6635 */
6636 UInt word1 = 0x93CC0D8C;
6637 UInt word2 = 0x93CC358C;
6638 UInt word3 = 0x93CCCD8C;
6639 UInt word4 = 0x93CCF58C;
6640 if (getUIntLittleEndianly(code+ 0) == word1 &&
6641 getUIntLittleEndianly(code+ 4) == word2 &&
6642 getUIntLittleEndianly(code+ 8) == word3 &&
6643 getUIntLittleEndianly(code+12) == word4) {
6644 /* Got a "Special" instruction preamble. Which one is it? */
6645 if (getUIntLittleEndianly(code+16) == 0xAA0A014A
6646 /* orr x10,x10,x10 */) {
6647 /* X3 = client_request ( X4 ) */
6648 DIP("x3 = client_request ( x4 )\n");
6649 putPC(mkU64( guest_PC_curr_instr + 20 ));
6650 dres->jk_StopHere = Ijk_ClientReq;
6651 dres->whatNext = Dis_StopHere;
6652 return True;
6653 }
6654 else
6655 if (getUIntLittleEndianly(code+16) == 0xAA0B016B
6656 /* orr x11,x11,x11 */) {
6657 /* X3 = guest_NRADDR */
6658 DIP("x3 = guest_NRADDR\n");
6659 dres->len = 20;
6660 putIReg64orZR(3, IRExpr_Get( OFFB_NRADDR, Ity_I64 ));
6661 return True;
6662 }
6663 else
6664 if (getUIntLittleEndianly(code+16) == 0xAA0C018C
6665 /* orr x12,x12,x12 */) {
6666 /* branch-and-link-to-noredir X8 */
6667 DIP("branch-and-link-to-noredir x8\n");
6668 putIReg64orZR(30, mkU64(guest_PC_curr_instr + 20));
6669 putPC(getIReg64orZR(8));
6670 dres->jk_StopHere = Ijk_NoRedir;
6671 dres->whatNext = Dis_StopHere;
6672 return True;
6673 }
6674 else
6675 if (getUIntLittleEndianly(code+16) == 0xAA090129
6676 /* orr x9,x9,x9 */) {
6677 /* IR injection */
6678 DIP("IR injection\n");
6679 vex_inject_ir(irsb, Iend_LE);
6680 // Invalidate the current insn. The reason is that the IRop we're
6681 // injecting here can change. In which case the translation has to
6682 // be redone. For ease of handling, we simply invalidate all the
6683 // time.
6684 stmt(IRStmt_Put(OFFB_TISTART, mkU64(guest_PC_curr_instr)));
6685 stmt(IRStmt_Put(OFFB_TILEN, mkU64(20)));
6686 putPC(mkU64( guest_PC_curr_instr + 20 ));
6687 dres->whatNext = Dis_StopHere;
6688 dres->jk_StopHere = Ijk_TInval;
6689 return True;
6690 }
6691 /* We don't know what it is. */
6692 return False;
6693 /*NOTREACHED*/
6694 }
6695 }
6696
6697 /* ----------------------------------------------------------- */
6698
6699 /* Main ARM64 instruction decoder starts here. */
6700
6701 Bool ok = False;
6702
6703 /* insn[28:25] determines the top-level grouping, so let's start
6704 off with that.
6705
6706 For all of these dis_ARM64_ functions, we pass *dres with the
6707 normal default results "insn OK, 4 bytes long, keep decoding" so
6708 they don't need to change it. However, decodes of control-flow
6709 insns may cause *dres to change.
6710 */
6711 switch (INSN(28,25)) {
6712 case BITS4(1,0,0,0): case BITS4(1,0,0,1):
6713 // Data processing - immediate
6714 ok = dis_ARM64_data_processing_immediate(dres, insn);
6715 break;
6716 case BITS4(1,0,1,0): case BITS4(1,0,1,1):
6717 // Branch, exception generation and system instructions
6718 ok = dis_ARM64_branch_etc(dres, insn);
6719 break;
6720 case BITS4(0,1,0,0): case BITS4(0,1,1,0):
6721 case BITS4(1,1,0,0): case BITS4(1,1,1,0):
6722 // Loads and stores
6723 ok = dis_ARM64_load_store(dres, insn);
6724 break;
6725 case BITS4(0,1,0,1): case BITS4(1,1,0,1):
6726 // Data processing - register
6727 ok = dis_ARM64_data_processing_register(dres, insn);
6728 break;
6729 case BITS4(0,1,1,1): case BITS4(1,1,1,1):
6730 // Data processing - SIMD and floating point
6731 ok = dis_ARM64_simd_and_fp(dres, insn);
6732 break;
6733 case BITS4(0,0,0,0): case BITS4(0,0,0,1):
6734 case BITS4(0,0,1,0): case BITS4(0,0,1,1):
6735 // UNALLOCATED
6736 break;
6737 default:
6738 vassert(0); /* Can't happen */
6739 }
6740
6741 /* If the next-level down decoders failed, make sure |dres| didn't
6742 get changed. */
6743 if (!ok) {
6744 vassert(dres->whatNext == Dis_Continue);
6745 vassert(dres->len == 4);
6746 vassert(dres->continueAt == 0);
6747 vassert(dres->jk_StopHere == Ijk_INVALID);
6748 }
6749
6750 return ok;
6751
6752# undef INSN
6753}
6754
6755
6756/*------------------------------------------------------------*/
6757/*--- Top-level fn ---*/
6758/*------------------------------------------------------------*/
6759
6760/* Disassemble a single instruction into IR. The instruction
6761 is located in host memory at &guest_code[delta]. */
6762
6763DisResult disInstr_ARM64 ( IRSB* irsb_IN,
6764 Bool (*resteerOkFn) ( void*, Addr64 ),
6765 Bool resteerCisOk,
6766 void* callback_opaque,
6767 UChar* guest_code_IN,
6768 Long delta_IN,
6769 Addr64 guest_IP,
6770 VexArch guest_arch,
6771 VexArchInfo* archinfo,
6772 VexAbiInfo* abiinfo,
6773 Bool host_bigendian_IN,
6774 Bool sigill_diag_IN )
6775{
6776 DisResult dres;
6777 vex_bzero(&dres, sizeof(dres));
6778
6779 /* Set globals (see top of this file) */
6780 vassert(guest_arch == VexArchARM64);
6781
6782 irsb = irsb_IN;
6783 host_is_bigendian = host_bigendian_IN;
6784 guest_PC_curr_instr = (Addr64)guest_IP;
6785
6786 /* Try to decode */
6787 Bool ok = disInstr_ARM64_WRK( &dres,
6788 resteerOkFn, resteerCisOk, callback_opaque,
6789 (UChar*)&guest_code_IN[delta_IN],
6790 archinfo, abiinfo );
6791 if (ok) {
6792 /* All decode successes end up here. */
sewardjdc9259c2014-02-27 11:10:19 +00006793 vassert(dres.len == 4 || dres.len == 20);
sewardjbbcf1882014-01-12 12:49:10 +00006794 switch (dres.whatNext) {
6795 case Dis_Continue:
6796 putPC( mkU64(dres.len + guest_PC_curr_instr) );
6797 break;
6798 case Dis_ResteerU:
6799 case Dis_ResteerC:
6800 putPC(mkU64(dres.continueAt));
6801 break;
6802 case Dis_StopHere:
6803 break;
6804 default:
6805 vassert(0);
6806 }
6807 DIP("\n");
6808 } else {
6809 /* All decode failures end up here. */
6810 if (sigill_diag_IN) {
6811 Int i, j;
6812 UChar buf[64];
6813 UInt insn
6814 = getUIntLittleEndianly( (UChar*)&guest_code_IN[delta_IN] );
6815 vex_bzero(buf, sizeof(buf));
6816 for (i = j = 0; i < 32; i++) {
6817 if (i > 0) {
6818 if ((i & 7) == 0) buf[j++] = ' ';
6819 else if ((i & 3) == 0) buf[j++] = '\'';
6820 }
6821 buf[j++] = (insn & (1<<(31-i))) ? '1' : '0';
6822 }
6823 vex_printf("disInstr(arm64): unhandled instruction 0x%08x\n", insn);
6824 vex_printf("disInstr(arm64): %s\n", buf);
6825 }
6826
6827 /* Tell the dispatcher that this insn cannot be decoded, and so
6828 has not been executed, and (is currently) the next to be
6829 executed. PC should be up-to-date since it is made so at the
6830 start of each insn, but nevertheless be paranoid and update
6831 it again right now. */
6832 putPC( mkU64(guest_PC_curr_instr) );
6833 dres.whatNext = Dis_StopHere;
6834 dres.len = 0;
6835 dres.continueAt = 0;
6836 dres.jk_StopHere = Ijk_NoDecode;
6837 }
6838 return dres;
6839}
6840
sewardjecde6972014-02-05 11:01:19 +00006841////////////////////////////////////////////////////////////////////////
6842////////////////////////////////////////////////////////////////////////
6843
6844/* Spare code for doing reference implementations of various 128-bit
6845 SIMD interleaves/deinterleaves/concatenation ops. For 64-bit
6846 equivalents see the end of guest_arm_toIR.c. */
6847
6848////////////////////////////////////////////////////////////////
6849// 64x2 operations
6850//
6851static IRExpr* mk_CatEvenLanes64x2 ( IRTemp a10, IRTemp b10 )
6852{
6853 // returns a0 b0
6854 return binop(Iop_64HLtoV128, unop(Iop_V128to64, mkexpr(a10)),
6855 unop(Iop_V128to64, mkexpr(b10)));
6856}
6857
6858static IRExpr* mk_CatOddLanes64x2 ( IRTemp a10, IRTemp b10 )
6859{
6860 // returns a1 b1
6861 return binop(Iop_64HLtoV128, unop(Iop_V128HIto64, mkexpr(a10)),
6862 unop(Iop_V128HIto64, mkexpr(b10)));
6863}
6864
6865
6866////////////////////////////////////////////////////////////////
6867// 32x4 operations
6868//
6869
6870// Split a 128 bit value into 4 32 bit ones, in 64-bit IRTemps with
6871// the top halves guaranteed to be zero.
6872static void breakV128to32s ( IRTemp* out3, IRTemp* out2, IRTemp* out1,
6873 IRTemp* out0, IRTemp v128 )
6874{
6875 if (out3) *out3 = newTemp(Ity_I64);
6876 if (out2) *out2 = newTemp(Ity_I64);
6877 if (out1) *out1 = newTemp(Ity_I64);
6878 if (out0) *out0 = newTemp(Ity_I64);
6879 IRTemp hi64 = newTemp(Ity_I64);
6880 IRTemp lo64 = newTemp(Ity_I64);
6881 assign(hi64, unop(Iop_V128HIto64, mkexpr(v128)) );
6882 assign(lo64, unop(Iop_V128to64, mkexpr(v128)) );
6883 if (out3) assign(*out3, binop(Iop_Shr64, mkexpr(hi64), mkU8(32)));
6884 if (out2) assign(*out2, binop(Iop_And64, mkexpr(hi64), mkU64(0xFFFFFFFF)));
6885 if (out1) assign(*out1, binop(Iop_Shr64, mkexpr(lo64), mkU8(32)));
6886 if (out0) assign(*out0, binop(Iop_And64, mkexpr(lo64), mkU64(0xFFFFFFFF)));
6887}
6888
6889// Make a V128 bit value from 4 32 bit ones, each of which is in a 64 bit
6890// IRTemp.
6891static IRTemp mkV128from32s ( IRTemp in3, IRTemp in2, IRTemp in1, IRTemp in0 )
6892{
6893 IRTemp hi64 = newTemp(Ity_I64);
6894 IRTemp lo64 = newTemp(Ity_I64);
6895 assign(hi64,
6896 binop(Iop_Or64,
6897 binop(Iop_Shl64, mkexpr(in3), mkU8(32)),
6898 binop(Iop_And64, mkexpr(in2), mkU64(0xFFFFFFFF))));
6899 assign(lo64,
6900 binop(Iop_Or64,
6901 binop(Iop_Shl64, mkexpr(in1), mkU8(32)),
6902 binop(Iop_And64, mkexpr(in0), mkU64(0xFFFFFFFF))));
6903 IRTemp res = newTemp(Ity_V128);
6904 assign(res, binop(Iop_64HLtoV128, mkexpr(hi64), mkexpr(lo64)));
6905 return res;
6906}
6907
6908static IRExpr* mk_CatEvenLanes32x4 ( IRTemp a3210, IRTemp b3210 )
6909{
6910 // returns a2 a0 b2 b0
6911 IRTemp a2, a0, b2, b0;
6912 breakV128to32s(NULL, &a2, NULL, &a0, a3210);
6913 breakV128to32s(NULL, &b2, NULL, &b0, b3210);
6914 return mkexpr(mkV128from32s(a2, a0, b2, b0));
6915}
6916
6917static IRExpr* mk_CatOddLanes32x4 ( IRTemp a3210, IRTemp b3210 )
6918{
6919 // returns a3 a1 b3 b1
6920 IRTemp a3, a1, b3, b1;
6921 breakV128to32s(&a3, NULL, &a1, NULL, a3210);
6922 breakV128to32s(&b3, NULL, &b1, NULL, b3210);
6923 return mkexpr(mkV128from32s(a3, a1, b3, b1));
6924}
6925
sewardje520bb32014-02-17 11:00:53 +00006926static IRExpr* mk_InterleaveLO32x4 ( IRTemp a3210, IRTemp b3210 )
6927{
6928 // returns a1 b1 a0 b0
6929 IRTemp a1, a0, b1, b0;
6930 breakV128to32s(NULL, NULL, &a1, &a0, a3210);
6931 breakV128to32s(NULL, NULL, &b1, &b0, b3210);
6932 return mkexpr(mkV128from32s(a1, b1, a0, b0));
6933}
6934
6935static IRExpr* mk_InterleaveHI32x4 ( IRTemp a3210, IRTemp b3210 )
6936{
6937 // returns a3 b3 a2 b2
6938 IRTemp a3, a2, b3, b2;
6939 breakV128to32s(&a3, &a2, NULL, NULL, a3210);
6940 breakV128to32s(&b3, &b2, NULL, NULL, b3210);
6941 return mkexpr(mkV128from32s(a3, b3, a2, b2));
6942}
sewardjecde6972014-02-05 11:01:19 +00006943
6944////////////////////////////////////////////////////////////////
6945// 16x8 operations
6946//
6947
6948static void breakV128to16s ( IRTemp* out7, IRTemp* out6, IRTemp* out5,
6949 IRTemp* out4, IRTemp* out3, IRTemp* out2,
6950 IRTemp* out1,IRTemp* out0, IRTemp v128 )
6951{
6952 if (out7) *out7 = newTemp(Ity_I64);
6953 if (out6) *out6 = newTemp(Ity_I64);
6954 if (out5) *out5 = newTemp(Ity_I64);
6955 if (out4) *out4 = newTemp(Ity_I64);
6956 if (out3) *out3 = newTemp(Ity_I64);
6957 if (out2) *out2 = newTemp(Ity_I64);
6958 if (out1) *out1 = newTemp(Ity_I64);
6959 if (out0) *out0 = newTemp(Ity_I64);
6960 IRTemp hi64 = newTemp(Ity_I64);
6961 IRTemp lo64 = newTemp(Ity_I64);
6962 assign(hi64, unop(Iop_V128HIto64, mkexpr(v128)) );
6963 assign(lo64, unop(Iop_V128to64, mkexpr(v128)) );
6964 if (out7)
6965 assign(*out7, binop(Iop_And64,
6966 binop(Iop_Shr64, mkexpr(hi64), mkU8(48)),
6967 mkU64(0xFFFF)));
6968 if (out6)
6969 assign(*out6, binop(Iop_And64,
6970 binop(Iop_Shr64, mkexpr(hi64), mkU8(32)),
6971 mkU64(0xFFFF)));
6972 if (out5)
6973 assign(*out5, binop(Iop_And64,
6974 binop(Iop_Shr64, mkexpr(hi64), mkU8(16)),
6975 mkU64(0xFFFF)));
6976 if (out4)
6977 assign(*out4, binop(Iop_And64, mkexpr(hi64), mkU64(0xFFFF)));
6978 if (out3)
6979 assign(*out3, binop(Iop_And64,
6980 binop(Iop_Shr64, mkexpr(lo64), mkU8(48)),
6981 mkU64(0xFFFF)));
6982 if (out2)
6983 assign(*out2, binop(Iop_And64,
6984 binop(Iop_Shr64, mkexpr(lo64), mkU8(32)),
6985 mkU64(0xFFFF)));
6986 if (out1)
6987 assign(*out1, binop(Iop_And64,
6988 binop(Iop_Shr64, mkexpr(lo64), mkU8(16)),
6989 mkU64(0xFFFF)));
6990 if (out0)
6991 assign(*out0, binop(Iop_And64, mkexpr(lo64), mkU64(0xFFFF)));
6992}
6993
6994static IRTemp mkV128from16s ( IRTemp in7, IRTemp in6, IRTemp in5, IRTemp in4,
6995 IRTemp in3, IRTemp in2, IRTemp in1, IRTemp in0 )
6996{
6997 IRTemp hi64 = newTemp(Ity_I64);
6998 IRTemp lo64 = newTemp(Ity_I64);
6999 assign(hi64,
7000 binop(Iop_Or64,
7001 binop(Iop_Or64,
7002 binop(Iop_Shl64,
7003 binop(Iop_And64, mkexpr(in7), mkU64(0xFFFF)),
7004 mkU8(48)),
7005 binop(Iop_Shl64,
7006 binop(Iop_And64, mkexpr(in6), mkU64(0xFFFF)),
7007 mkU8(32))),
7008 binop(Iop_Or64,
7009 binop(Iop_Shl64,
7010 binop(Iop_And64, mkexpr(in5), mkU64(0xFFFF)),
7011 mkU8(16)),
7012 binop(Iop_And64,
7013 mkexpr(in4), mkU64(0xFFFF)))));
7014 assign(lo64,
7015 binop(Iop_Or64,
7016 binop(Iop_Or64,
7017 binop(Iop_Shl64,
7018 binop(Iop_And64, mkexpr(in3), mkU64(0xFFFF)),
7019 mkU8(48)),
7020 binop(Iop_Shl64,
7021 binop(Iop_And64, mkexpr(in2), mkU64(0xFFFF)),
7022 mkU8(32))),
7023 binop(Iop_Or64,
7024 binop(Iop_Shl64,
7025 binop(Iop_And64, mkexpr(in1), mkU64(0xFFFF)),
7026 mkU8(16)),
7027 binop(Iop_And64,
7028 mkexpr(in0), mkU64(0xFFFF)))));
7029 IRTemp res = newTemp(Ity_V128);
7030 assign(res, binop(Iop_64HLtoV128, mkexpr(hi64), mkexpr(lo64)));
7031 return res;
7032}
7033
7034static IRExpr* mk_CatEvenLanes16x8 ( IRTemp a76543210, IRTemp b76543210 )
7035{
7036 // returns a6 a4 a2 a0 b6 b4 b2 b0
7037 IRTemp a6, a4, a2, a0, b6, b4, b2, b0;
7038 breakV128to16s(NULL, &a6, NULL, &a4, NULL, &a2, NULL, &a0, a76543210);
7039 breakV128to16s(NULL, &b6, NULL, &b4, NULL, &b2, NULL, &b0, b76543210);
7040 return mkexpr(mkV128from16s(a6, a4, a2, a0, b6, b4, b2, b0));
7041}
7042
7043static IRExpr* mk_CatOddLanes16x8 ( IRTemp a76543210, IRTemp b76543210 )
7044{
7045 // returns a7 a5 a3 a1 b7 b5 b3 b1
7046 IRTemp a7, a5, a3, a1, b7, b5, b3, b1;
7047 breakV128to16s(&a7, NULL, &a5, NULL, &a3, NULL, &a1, NULL, a76543210);
7048 breakV128to16s(&b7, NULL, &b5, NULL, &b3, NULL, &b1, NULL, b76543210);
7049 return mkexpr(mkV128from16s(a7, a5, a3, a1, b7, b5, b3, b1));
7050}
7051
sewardje520bb32014-02-17 11:00:53 +00007052static IRExpr* mk_InterleaveLO16x8 ( IRTemp a76543210, IRTemp b76543210 )
7053{
7054 // returns a3 b3 a2 b2 a1 b1 a0 b0
7055 IRTemp a3, b3, a2, b2, a1, a0, b1, b0;
7056 breakV128to16s(NULL, NULL, NULL, NULL, &a3, &a2, &a1, &a0, a76543210);
7057 breakV128to16s(NULL, NULL, NULL, NULL, &b3, &b2, &b1, &b0, b76543210);
7058 return mkexpr(mkV128from16s(a3, b3, a2, b2, a1, b1, a0, b0));
7059}
7060
7061static IRExpr* mk_InterleaveHI16x8 ( IRTemp a76543210, IRTemp b76543210 )
7062{
7063 // returns a7 b7 a6 b6 a5 b5 a4 b4
7064 IRTemp a7, b7, a6, b6, a5, b5, a4, b4;
7065 breakV128to16s(&a7, &a6, &a5, &a4, NULL, NULL, NULL, NULL, a76543210);
7066 breakV128to16s(&b7, &b6, &b5, &b4, NULL, NULL, NULL, NULL, b76543210);
7067 return mkexpr(mkV128from16s(a7, b7, a6, b6, a5, b5, a4, b4));
7068}
7069
sewardjfab09142014-02-10 10:28:13 +00007070////////////////////////////////////////////////////////////////
7071// 8x16 operations
7072//
7073
7074static void breakV128to8s ( IRTemp* outF, IRTemp* outE, IRTemp* outD,
7075 IRTemp* outC, IRTemp* outB, IRTemp* outA,
7076 IRTemp* out9, IRTemp* out8,
7077 IRTemp* out7, IRTemp* out6, IRTemp* out5,
7078 IRTemp* out4, IRTemp* out3, IRTemp* out2,
7079 IRTemp* out1,IRTemp* out0, IRTemp v128 )
7080{
7081 if (outF) *outF = newTemp(Ity_I64);
7082 if (outE) *outE = newTemp(Ity_I64);
7083 if (outD) *outD = newTemp(Ity_I64);
7084 if (outC) *outC = newTemp(Ity_I64);
7085 if (outB) *outB = newTemp(Ity_I64);
7086 if (outA) *outA = newTemp(Ity_I64);
7087 if (out9) *out9 = newTemp(Ity_I64);
7088 if (out8) *out8 = newTemp(Ity_I64);
7089 if (out7) *out7 = newTemp(Ity_I64);
7090 if (out6) *out6 = newTemp(Ity_I64);
7091 if (out5) *out5 = newTemp(Ity_I64);
7092 if (out4) *out4 = newTemp(Ity_I64);
7093 if (out3) *out3 = newTemp(Ity_I64);
7094 if (out2) *out2 = newTemp(Ity_I64);
7095 if (out1) *out1 = newTemp(Ity_I64);
7096 if (out0) *out0 = newTemp(Ity_I64);
7097 IRTemp hi64 = newTemp(Ity_I64);
7098 IRTemp lo64 = newTemp(Ity_I64);
7099 assign(hi64, unop(Iop_V128HIto64, mkexpr(v128)) );
7100 assign(lo64, unop(Iop_V128to64, mkexpr(v128)) );
7101 if (outF)
7102 assign(*outF, binop(Iop_And64,
7103 binop(Iop_Shr64, mkexpr(hi64), mkU8(56)),
7104 mkU64(0xFF)));
7105 if (outE)
7106 assign(*outE, binop(Iop_And64,
7107 binop(Iop_Shr64, mkexpr(hi64), mkU8(48)),
7108 mkU64(0xFF)));
7109 if (outD)
7110 assign(*outD, binop(Iop_And64,
7111 binop(Iop_Shr64, mkexpr(hi64), mkU8(40)),
7112 mkU64(0xFF)));
7113 if (outC)
7114 assign(*outC, binop(Iop_And64,
7115 binop(Iop_Shr64, mkexpr(hi64), mkU8(32)),
7116 mkU64(0xFF)));
7117 if (outB)
7118 assign(*outB, binop(Iop_And64,
7119 binop(Iop_Shr64, mkexpr(hi64), mkU8(24)),
7120 mkU64(0xFF)));
7121 if (outA)
7122 assign(*outA, binop(Iop_And64,
7123 binop(Iop_Shr64, mkexpr(hi64), mkU8(16)),
7124 mkU64(0xFF)));
7125 if (out9)
7126 assign(*out9, binop(Iop_And64,
7127 binop(Iop_Shr64, mkexpr(hi64), mkU8(8)),
7128 mkU64(0xFF)));
7129 if (out8)
7130 assign(*out8, binop(Iop_And64,
7131 binop(Iop_Shr64, mkexpr(hi64), mkU8(0)),
7132 mkU64(0xFF)));
7133 if (out7)
7134 assign(*out7, binop(Iop_And64,
7135 binop(Iop_Shr64, mkexpr(lo64), mkU8(56)),
7136 mkU64(0xFF)));
7137 if (out6)
7138 assign(*out6, binop(Iop_And64,
7139 binop(Iop_Shr64, mkexpr(lo64), mkU8(48)),
7140 mkU64(0xFF)));
7141 if (out5)
7142 assign(*out5, binop(Iop_And64,
7143 binop(Iop_Shr64, mkexpr(lo64), mkU8(40)),
7144 mkU64(0xFF)));
7145 if (out4)
7146 assign(*out4, binop(Iop_And64,
7147 binop(Iop_Shr64, mkexpr(lo64), mkU8(32)),
7148 mkU64(0xFF)));
7149 if (out3)
7150 assign(*out3, binop(Iop_And64,
7151 binop(Iop_Shr64, mkexpr(lo64), mkU8(24)),
7152 mkU64(0xFF)));
7153 if (out2)
7154 assign(*out2, binop(Iop_And64,
7155 binop(Iop_Shr64, mkexpr(lo64), mkU8(16)),
7156 mkU64(0xFF)));
7157 if (out1)
7158 assign(*out1, binop(Iop_And64,
7159 binop(Iop_Shr64, mkexpr(lo64), mkU8(8)),
7160 mkU64(0xFF)));
7161 if (out0)
7162 assign(*out0, binop(Iop_And64,
7163 binop(Iop_Shr64, mkexpr(lo64), mkU8(0)),
7164 mkU64(0xFF)));
7165}
7166
7167static IRTemp mkV128from8s ( IRTemp inF, IRTemp inE, IRTemp inD, IRTemp inC,
7168 IRTemp inB, IRTemp inA, IRTemp in9, IRTemp in8,
7169 IRTemp in7, IRTemp in6, IRTemp in5, IRTemp in4,
7170 IRTemp in3, IRTemp in2, IRTemp in1, IRTemp in0 )
7171{
7172 IRTemp vFE = newTemp(Ity_I64);
7173 IRTemp vDC = newTemp(Ity_I64);
7174 IRTemp vBA = newTemp(Ity_I64);
7175 IRTemp v98 = newTemp(Ity_I64);
7176 IRTemp v76 = newTemp(Ity_I64);
7177 IRTemp v54 = newTemp(Ity_I64);
7178 IRTemp v32 = newTemp(Ity_I64);
7179 IRTemp v10 = newTemp(Ity_I64);
7180 assign(vFE, binop(Iop_Or64,
7181 binop(Iop_Shl64,
7182 binop(Iop_And64, mkexpr(inF), mkU64(0xFF)), mkU8(8)),
7183 binop(Iop_And64, mkexpr(inE), mkU64(0xFF))));
7184 assign(vDC, binop(Iop_Or64,
7185 binop(Iop_Shl64,
7186 binop(Iop_And64, mkexpr(inD), mkU64(0xFF)), mkU8(8)),
7187 binop(Iop_And64, mkexpr(inC), mkU64(0xFF))));
7188 assign(vBA, binop(Iop_Or64,
7189 binop(Iop_Shl64,
7190 binop(Iop_And64, mkexpr(inB), mkU64(0xFF)), mkU8(8)),
7191 binop(Iop_And64, mkexpr(inA), mkU64(0xFF))));
7192 assign(v98, binop(Iop_Or64,
7193 binop(Iop_Shl64,
7194 binop(Iop_And64, mkexpr(in9), mkU64(0xFF)), mkU8(8)),
7195 binop(Iop_And64, mkexpr(in8), mkU64(0xFF))));
7196 assign(v76, binop(Iop_Or64,
7197 binop(Iop_Shl64,
7198 binop(Iop_And64, mkexpr(in7), mkU64(0xFF)), mkU8(8)),
7199 binop(Iop_And64, mkexpr(in6), mkU64(0xFF))));
7200 assign(v54, binop(Iop_Or64,
7201 binop(Iop_Shl64,
7202 binop(Iop_And64, mkexpr(in5), mkU64(0xFF)), mkU8(8)),
7203 binop(Iop_And64, mkexpr(in4), mkU64(0xFF))));
7204 assign(v32, binop(Iop_Or64,
7205 binop(Iop_Shl64,
7206 binop(Iop_And64, mkexpr(in3), mkU64(0xFF)), mkU8(8)),
7207 binop(Iop_And64, mkexpr(in2), mkU64(0xFF))));
7208 assign(v10, binop(Iop_Or64,
7209 binop(Iop_Shl64,
7210 binop(Iop_And64, mkexpr(in1), mkU64(0xFF)), mkU8(8)),
7211 binop(Iop_And64, mkexpr(in0), mkU64(0xFF))));
7212 return mkV128from16s(vFE, vDC, vBA, v98, v76, v54, v32, v10);
7213}
7214
7215static IRExpr* mk_CatEvenLanes8x16 ( IRTemp aFEDCBA9876543210,
7216 IRTemp bFEDCBA9876543210 )
7217{
7218 // returns aE aC aA a8 a6 a4 a2 a0 bE bC bA b8 b6 b4 b2 b0
7219 IRTemp aE, aC, aA, a8, a6, a4, a2, a0, bE, bC, bA, b8, b6, b4, b2, b0;
7220 breakV128to8s(NULL, &aE, NULL, &aC, NULL, &aA, NULL, &a8,
7221 NULL, &a6, NULL, &a4, NULL, &a2, NULL, &a0,
7222 aFEDCBA9876543210);
7223 breakV128to8s(NULL, &bE, NULL, &bC, NULL, &bA, NULL, &b8,
7224 NULL, &b6, NULL, &b4, NULL, &b2, NULL, &b0,
7225 bFEDCBA9876543210);
7226 return mkexpr(mkV128from8s(aE, aC, aA, a8, a6, a4, a2, a0,
7227 bE, bC, bA, b8, b6, b4, b2, b0));
7228}
7229
7230static IRExpr* mk_CatOddLanes8x16 ( IRTemp aFEDCBA9876543210,
7231 IRTemp bFEDCBA9876543210 )
7232{
7233 // returns aF aD aB a9 a7 a5 a3 a1 bF bD bB b9 b7 b5 b3 b1
7234 IRTemp aF, aD, aB, a9, a7, a5, a3, a1, bF, bD, bB, b9, b7, b5, b3, b1;
7235 breakV128to8s(&aF, NULL, &aD, NULL, &aB, NULL, &a9, NULL,
7236 &a7, NULL, &a5, NULL, &a3, NULL, &a1, NULL,
7237 aFEDCBA9876543210);
7238
7239 breakV128to8s(&bF, NULL, &bD, NULL, &bB, NULL, &b9, NULL,
7240 &b7, NULL, &b5, NULL, &b3, NULL, &b1, NULL,
7241 aFEDCBA9876543210);
7242
7243 return mkexpr(mkV128from8s(aF, aD, aB, a9, a7, a5, a3, a1,
7244 bF, bD, bB, b9, b7, b5, b3, b1));
7245}
7246
sewardje520bb32014-02-17 11:00:53 +00007247static IRExpr* mk_InterleaveLO8x16 ( IRTemp aFEDCBA9876543210,
7248 IRTemp bFEDCBA9876543210 )
7249{
7250 // returns a7 b7 a6 b6 a5 b5 a4 b4 a3 b3 a2 b2 a1 b1 a0 b0
7251 IRTemp a7, b7, a6, b6, a5, b5, a4, b4, a3, b3, a2, b2, a1, b1, a0, b0;
7252 breakV128to8s(NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
7253 &a7, &a6, &a5, &a4, &a3, &a2, &a1, &a0,
7254 aFEDCBA9876543210);
7255 breakV128to8s(NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
7256 &b7, &b6, &b5, &b4, &b3, &b2, &b1, &b0,
7257 bFEDCBA9876543210);
7258 return mkexpr(mkV128from8s(a7, b7, a6, b6, a5, b5, a4, b4,
7259 a3, b3, a2, b2, a1, b1, a0, b0));
7260}
7261
7262static IRExpr* mk_InterleaveHI8x16 ( IRTemp aFEDCBA9876543210,
7263 IRTemp bFEDCBA9876543210 )
7264{
7265 // returns aF bF aE bE aD bD aC bC aB bB aA bA a9 b9 a8 b8
7266 IRTemp aF, bF, aE, bE, aD, bD, aC, bC, aB, bB, aA, bA, a9, b9, a8, b8;
7267 breakV128to8s(&aF, &aE, &aD, &aC, &aB, &aA, &a9, &a8,
7268 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
7269 aFEDCBA9876543210);
7270 breakV128to8s(&bF, &bE, &bD, &bC, &bB, &bA, &b9, &b8,
7271 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
7272 bFEDCBA9876543210);
7273 return mkexpr(mkV128from8s(aF, bF, aE, bE, aD, bD, aC, bC,
7274 aB, bB, aA, bA, a9, b9, a8, b8));
7275}
sewardjecde6972014-02-05 11:01:19 +00007276
sewardjbbcf1882014-01-12 12:49:10 +00007277/*--------------------------------------------------------------------*/
7278/*--- end guest_arm64_toIR.c ---*/
7279/*--------------------------------------------------------------------*/