1ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--------------------------------------------------------------------*/
3ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- begin                                       guest_arm_toIR.c ---*/
4ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--------------------------------------------------------------------*/
5ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*
7ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   This file is part of Valgrind, a dynamic binary instrumentation
8ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   framework.
9ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   Copyright (C) 2004-2011 OpenWorks LLP
11ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      info@open-works.net
12ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   NEON support is
14b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   Copyright (C) 2010-2011 Samsung Electronics
15ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   contributed by Dmitry Zhurikhin <zhur@ispras.ru>
16ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              and Kirill Batuzov <batuzovk@ispras.ru>
17ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
18ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   This program is free software; you can redistribute it and/or
19ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   modify it under the terms of the GNU General Public License as
20ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   published by the Free Software Foundation; either version 2 of the
21ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   License, or (at your option) any later version.
22ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
23ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   This program is distributed in the hope that it will be useful, but
24ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   WITHOUT ANY WARRANTY; without even the implied warranty of
25ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
26ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   General Public License for more details.
27ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
28ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   You should have received a copy of the GNU General Public License
29ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   along with this program; if not, write to the Free Software
30ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
31ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   02110-1301, USA.
32ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
33ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   The GNU General Public License is contained in the file COPYING.
34ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
35ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
36ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* XXXX thumb to check:
37ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   that all cases where putIRegT writes r15, we generate a jump.
38ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
39ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   All uses of newTemp assign to an IRTemp and not a UInt
40ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
41ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   For all thumb loads and stores, including VFP ones, new-ITSTATE is
42ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   backed out before the memory op, and restored afterwards.  This
43ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   needs to happen even after we go uncond.  (and for sure it doesn't
44ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   happen for VFP loads/stores right now).
45ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
46ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VFP on thumb: check that we exclude all r13/r15 cases that we
47ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   should.
48ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
49ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   XXXX thumb to do: improve the ITSTATE-zeroing optimisation by
50ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   taking into account the number of insns guarded by an IT.
51ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
52ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   remove the nasty hack, in the spechelper, of looking for Or32(...,
53ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   0xE0) in as the first arg to armg_calculate_condition, and instead
54ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   use Slice44 as specified in comments in the spechelper.
55ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
56ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   add specialisations for armg_calculate_flag_c and _v, as they
57ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   are moderately often needed in Thumb code.
58ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
59ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Correctness: ITSTATE handling in Thumb SVCs is wrong.
60ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
61ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Correctness (obscure): in m_transtab, when invalidating code
62ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   address ranges, invalidate up to 18 bytes after the end of the
63ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   range.  This is because the ITSTATE optimisation at the top of
64ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   _THUMB_WRK below analyses up to 18 bytes before the start of any
65ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   given instruction, and so might depend on the invalidated area.
66ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
67ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
68ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Limitations, etc
69ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
70ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   - pretty dodgy exception semantics for {LD,ST}Mxx, no doubt
71ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
72ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   - SWP: the restart jump back is Ijk_Boring; it should be
73ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     Ijk_NoRedir but that's expensive.  See comments on casLE() in
74ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     guest_x86_toIR.c.
75ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
76ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
77ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* "Special" instructions.
78ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
79ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   This instruction decoder can decode four special instructions
80ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   which mean nothing natively (are no-ops as far as regs/mem are
81ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   concerned) but have meaning for supporting Valgrind.  A special
82ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   instruction is flagged by a 16-byte preamble:
83ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
84ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      E1A0C1EC E1A0C6EC E1A0CEEC E1A0C9EC
85ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      (mov r12, r12, ROR #3;   mov r12, r12, ROR #13;
86ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       mov r12, r12, ROR #29;  mov r12, r12, ROR #19)
87ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
88ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Following that, one of the following 3 are allowed
89ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   (standard interpretation in parentheses):
90ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
91ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      E18AA00A (orr r10,r10,r10)   R3 = client_request ( R4 )
92ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      E18BB00B (orr r11,r11,r11)   R3 = guest_NRADDR
93ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      E18CC00C (orr r12,r12,r12)   branch-and-link-to-noredir R4
94ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
95ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Any other bytes following the 16-byte preamble are illegal and
96ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   constitute a failure in instruction decoding.  This all assumes
97ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   that the preamble will never occur except in specific code
98ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   fragments designed for Valgrind to catch.
99ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
100ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
101ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Translates ARM(v5) code to IR. */
102ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
103ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "libvex_basictypes.h"
104ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "libvex_ir.h"
105ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "libvex.h"
106ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "libvex_guest_arm.h"
107ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
108ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "main_util.h"
109ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "main_globals.h"
110ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "guest_generic_bb_to_IR.h"
111ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "guest_arm_defs.h"
112ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
113ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
114ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
115ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- Globals                                              ---*/
116ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
117ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
118ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* These are set at the start of the translation of a instruction, so
119ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   that we don't have to pass them around endlessly.  CONST means does
120ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   not change during translation of the instruction.
121ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
122ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
123ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* CONST: is the host bigendian?  This has to do with float vs double
124ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   register accesses on VFP, but it's complex and not properly thought
125ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   out. */
126ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Bool host_is_bigendian;
127ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
128ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* CONST: The guest address for the instruction currently being
129ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   translated.  This is the real, "decoded" address (not subject
130ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   to the CPSR.T kludge). */
131ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Addr32 guest_R15_curr_instr_notENC;
132ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
133ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* CONST, FOR ASSERTIONS ONLY.  Indicates whether currently processed
134ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   insn is Thumb (True) or ARM (False). */
135ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Bool __curr_is_Thumb;
136ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
137ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* MOD: The IRSB* into which we're generating code. */
138ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRSB* irsb;
139ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
140ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* These are to do with handling writes to r15.  They are initially
141ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   set at the start of disInstr_ARM_WRK to indicate no update,
142ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   possibly updated during the routine, and examined again at the end.
143ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   If they have been set to indicate a r15 update then a jump is
144ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   generated.  Note, "explicit" jumps (b, bx, etc) are generated
145ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   directly, not using this mechanism -- this is intended to handle
146ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   the implicit-style jumps resulting from (eg) assigning to r15 as
147ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   the result of insns we wouldn't normally consider branchy. */
148ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
149ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* MOD.  Initially False; set to True iff abovementioned handling is
150ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   required. */
151ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Bool r15written;
152ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
153ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* MOD.  Initially IRTemp_INVALID.  If the r15 branch to be generated
154ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   is conditional, this holds the gating IRTemp :: Ity_I32.  If the
155ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   branch to be generated is unconditional, this remains
156ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp_INVALID. */
157ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRTemp r15guard; /* :: Ity_I32, 0 or 1 */
158ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
159ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* MOD.  Initially Ijk_Boring.  If an r15 branch is to be generated,
160ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   this holds the jump kind. */
161ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRTemp r15kind;
162ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
163ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
164ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
165ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- Debugging output                                     ---*/
166ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
167ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
168ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define DIP(format, args...)           \
169ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (vex_traceflags & VEX_TRACE_FE)  \
170ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vex_printf(format, ## args)
171ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
172ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define DIS(buf, format, args...)      \
173ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (vex_traceflags & VEX_TRACE_FE)  \
174ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vex_sprintf(buf, format, ## args)
175ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
176ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define ASSERT_IS_THUMB \
177ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   do { vassert(__curr_is_Thumb); } while (0)
178ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
179ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define ASSERT_IS_ARM \
180ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   do { vassert(! __curr_is_Thumb); } while (0)
181ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
182ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
183ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
184ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- Helper bits and pieces for deconstructing the        ---*/
185ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- arm insn stream.                                     ---*/
186ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
187ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
188ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Do a little-endian load of a 32-bit word, regardless of the
189ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   endianness of the underlying host. */
190ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic inline UInt getUIntLittleEndianly ( UChar* p )
191ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
192ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt w = 0;
193ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   w = (w << 8) | p[3];
194ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   w = (w << 8) | p[2];
195ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   w = (w << 8) | p[1];
196ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   w = (w << 8) | p[0];
197ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return w;
198ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
199ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
200ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Do a little-endian load of a 16-bit word, regardless of the
201ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   endianness of the underlying host. */
202ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic inline UShort getUShortLittleEndianly ( UChar* p )
203ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
204ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UShort w = 0;
205ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   w = (w << 8) | p[1];
206ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   w = (w << 8) | p[0];
207ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return w;
208ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
209ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
210ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic UInt ROR32 ( UInt x, UInt sh ) {
211ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(sh >= 0 && sh < 32);
212ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sh == 0)
213ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return x;
214ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else
215ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return (x << (32-sh)) | (x >> sh);
216ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
217ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
218ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Int popcount32 ( UInt x )
219ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
220ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int res = 0, i;
221ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (i = 0; i < 32; i++) {
222ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      res += (x & 1);
223ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      x >>= 1;
224ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
225ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return res;
226ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
227ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
228ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic UInt setbit32 ( UInt x, Int ix, UInt b )
229ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
230ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt mask = 1 << ix;
231ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   x &= ~mask;
232ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   x |= ((b << ix) & mask);
233ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return x;
234ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
235ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
236ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define BITS2(_b1,_b0) \
237ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   (((_b1) << 1) | (_b0))
238ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
239ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define BITS3(_b2,_b1,_b0)                      \
240ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  (((_b2) << 2) | ((_b1) << 1) | (_b0))
241ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
242ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define BITS4(_b3,_b2,_b1,_b0) \
243ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   (((_b3) << 3) | ((_b2) << 2) | ((_b1) << 1) | (_b0))
244ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
245ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define BITS8(_b7,_b6,_b5,_b4,_b3,_b2,_b1,_b0)  \
246ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ((BITS4((_b7),(_b6),(_b5),(_b4)) << 4) \
247ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    | BITS4((_b3),(_b2),(_b1),(_b0)))
248ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
249ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define BITS5(_b4,_b3,_b2,_b1,_b0)  \
250ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   (BITS8(0,0,0,(_b4),(_b3),(_b2),(_b1),(_b0)))
251ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define BITS6(_b5,_b4,_b3,_b2,_b1,_b0)  \
252ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   (BITS8(0,0,(_b5),(_b4),(_b3),(_b2),(_b1),(_b0)))
253ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define BITS7(_b6,_b5,_b4,_b3,_b2,_b1,_b0)  \
254ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   (BITS8(0,(_b6),(_b5),(_b4),(_b3),(_b2),(_b1),(_b0)))
255ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
256ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define BITS9(_b8,_b7,_b6,_b5,_b4,_b3,_b2,_b1,_b0)      \
257ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   (((_b8) << 8) \
258ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    | BITS8((_b7),(_b6),(_b5),(_b4),(_b3),(_b2),(_b1),(_b0)))
259ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
260ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define BITS10(_b9,_b8,_b7,_b6,_b5,_b4,_b3,_b2,_b1,_b0)  \
261ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   (((_b9) << 9) | ((_b8) << 8)                                \
262ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    | BITS8((_b7),(_b6),(_b5),(_b4),(_b3),(_b2),(_b1),(_b0)))
263ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
264ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* produces _uint[_bMax:_bMin] */
265ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define SLICE_UInt(_uint,_bMax,_bMin) \
266ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   (( ((UInt)(_uint)) >> (_bMin)) \
267ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    & (UInt)((1ULL << ((_bMax) - (_bMin) + 1)) - 1ULL))
268ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
269ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
270ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
271ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- Helper bits and pieces for creating IR fragments.    ---*/
272ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
273ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
274ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* mkU64 ( ULong i )
275ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
276ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return IRExpr_Const(IRConst_U64(i));
277ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
278ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
279ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* mkU32 ( UInt i )
280ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
281ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return IRExpr_Const(IRConst_U32(i));
282ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
283ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
284ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* mkU8 ( UInt i )
285ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
286ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(i < 256);
287ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return IRExpr_Const(IRConst_U8( (UChar)i ));
288ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
289ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
290ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* mkexpr ( IRTemp tmp )
291ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
292ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return IRExpr_RdTmp(tmp);
293ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
294ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
295ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* unop ( IROp op, IRExpr* a )
296ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
297ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return IRExpr_Unop(op, a);
298ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
299ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
300ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* binop ( IROp op, IRExpr* a1, IRExpr* a2 )
301ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
302ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return IRExpr_Binop(op, a1, a2);
303ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
304ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
305ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* triop ( IROp op, IRExpr* a1, IRExpr* a2, IRExpr* a3 )
306ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
307ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return IRExpr_Triop(op, a1, a2, a3);
308ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
309ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
310ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* loadLE ( IRType ty, IRExpr* addr )
311ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
312ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return IRExpr_Load(Iend_LE, ty, addr);
313ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
314ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
315ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Add a statement to the list held by "irbb". */
316ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void stmt ( IRStmt* st )
317ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
318ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   addStmtToIRSB( irsb, st );
319ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
320ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
321ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void assign ( IRTemp dst, IRExpr* e )
322ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
323ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_WrTmp(dst, e) );
324ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
325ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
326ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void storeLE ( IRExpr* addr, IRExpr* data )
327ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
328ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Store(Iend_LE, addr, data) );
329ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
330ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
331ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Generate a new temporary of the given type. */
332ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRTemp newTemp ( IRType ty )
333ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
334ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(isPlausibleIRType(ty));
335ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return newIRTemp( irsb->tyenv, ty );
336ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
337ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
338ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Produces a value in 0 .. 3, which is encoded as per the type
339ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRRoundingMode. */
340ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* /* :: Ity_I32 */ get_FAKE_roundingmode ( void )
341ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
342ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return mkU32(Irrm_NEAREST);
343ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
344ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
345ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Generate an expression for SRC rotated right by ROT. */
346ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* genROR32( IRTemp src, Int rot )
347ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
348ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(rot >= 0 && rot < 32);
349ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (rot == 0)
350ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return mkexpr(src);
351ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return
352ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      binop(Iop_Or32,
353ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            binop(Iop_Shl32, mkexpr(src), mkU8(32 - rot)),
354ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            binop(Iop_Shr32, mkexpr(src), mkU8(rot)));
355ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
356ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
357ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* mkU128 ( ULong i )
358ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
359ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return binop(Iop_64HLtoV128, mkU64(i), mkU64(i));
360ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
361ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
362ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Generate a 4-aligned version of the given expression if
363ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   the given condition is true.  Else return it unchanged. */
364ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* align4if ( IRExpr* e, Bool b )
365ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
366ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (b)
367ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return binop(Iop_And32, e, mkU32(~3));
368ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else
369ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return e;
370ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
371ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
372ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
373ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
374ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- Helpers for accessing guest registers.               ---*/
375ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
376ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
377ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_R0       offsetof(VexGuestARMState,guest_R0)
378ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_R1       offsetof(VexGuestARMState,guest_R1)
379ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_R2       offsetof(VexGuestARMState,guest_R2)
380ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_R3       offsetof(VexGuestARMState,guest_R3)
381ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_R4       offsetof(VexGuestARMState,guest_R4)
382ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_R5       offsetof(VexGuestARMState,guest_R5)
383ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_R6       offsetof(VexGuestARMState,guest_R6)
384ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_R7       offsetof(VexGuestARMState,guest_R7)
385ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_R8       offsetof(VexGuestARMState,guest_R8)
386ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_R9       offsetof(VexGuestARMState,guest_R9)
387ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_R10      offsetof(VexGuestARMState,guest_R10)
388ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_R11      offsetof(VexGuestARMState,guest_R11)
389ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_R12      offsetof(VexGuestARMState,guest_R12)
390ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_R13      offsetof(VexGuestARMState,guest_R13)
391ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_R14      offsetof(VexGuestARMState,guest_R14)
392ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_R15T     offsetof(VexGuestARMState,guest_R15T)
393ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
394ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_CC_OP    offsetof(VexGuestARMState,guest_CC_OP)
395ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_CC_DEP1  offsetof(VexGuestARMState,guest_CC_DEP1)
396ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_CC_DEP2  offsetof(VexGuestARMState,guest_CC_DEP2)
397ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_CC_NDEP  offsetof(VexGuestARMState,guest_CC_NDEP)
398ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_NRADDR   offsetof(VexGuestARMState,guest_NRADDR)
399ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
400ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_D0       offsetof(VexGuestARMState,guest_D0)
401ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_D1       offsetof(VexGuestARMState,guest_D1)
402ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_D2       offsetof(VexGuestARMState,guest_D2)
403ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_D3       offsetof(VexGuestARMState,guest_D3)
404ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_D4       offsetof(VexGuestARMState,guest_D4)
405ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_D5       offsetof(VexGuestARMState,guest_D5)
406ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_D6       offsetof(VexGuestARMState,guest_D6)
407ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_D7       offsetof(VexGuestARMState,guest_D7)
408ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_D8       offsetof(VexGuestARMState,guest_D8)
409ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_D9       offsetof(VexGuestARMState,guest_D9)
410ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_D10      offsetof(VexGuestARMState,guest_D10)
411ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_D11      offsetof(VexGuestARMState,guest_D11)
412ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_D12      offsetof(VexGuestARMState,guest_D12)
413ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_D13      offsetof(VexGuestARMState,guest_D13)
414ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_D14      offsetof(VexGuestARMState,guest_D14)
415ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_D15      offsetof(VexGuestARMState,guest_D15)
416ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_D16      offsetof(VexGuestARMState,guest_D16)
417ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_D17      offsetof(VexGuestARMState,guest_D17)
418ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_D18      offsetof(VexGuestARMState,guest_D18)
419ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_D19      offsetof(VexGuestARMState,guest_D19)
420ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_D20      offsetof(VexGuestARMState,guest_D20)
421ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_D21      offsetof(VexGuestARMState,guest_D21)
422ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_D22      offsetof(VexGuestARMState,guest_D22)
423ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_D23      offsetof(VexGuestARMState,guest_D23)
424ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_D24      offsetof(VexGuestARMState,guest_D24)
425ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_D25      offsetof(VexGuestARMState,guest_D25)
426ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_D26      offsetof(VexGuestARMState,guest_D26)
427ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_D27      offsetof(VexGuestARMState,guest_D27)
428ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_D28      offsetof(VexGuestARMState,guest_D28)
429ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_D29      offsetof(VexGuestARMState,guest_D29)
430ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_D30      offsetof(VexGuestARMState,guest_D30)
431ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_D31      offsetof(VexGuestARMState,guest_D31)
432ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
433ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_FPSCR    offsetof(VexGuestARMState,guest_FPSCR)
434ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_TPIDRURO offsetof(VexGuestARMState,guest_TPIDRURO)
435ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_ITSTATE  offsetof(VexGuestARMState,guest_ITSTATE)
436ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_QFLAG32  offsetof(VexGuestARMState,guest_QFLAG32)
437ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_GEFLAG0  offsetof(VexGuestARMState,guest_GEFLAG0)
438ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_GEFLAG1  offsetof(VexGuestARMState,guest_GEFLAG1)
439ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_GEFLAG2  offsetof(VexGuestARMState,guest_GEFLAG2)
440ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_GEFLAG3  offsetof(VexGuestARMState,guest_GEFLAG3)
441ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
442ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
443ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* ---------------- Integer registers ---------------- */
444ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
445ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Int integerGuestRegOffset ( UInt iregNo )
446ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
447ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Do we care about endianness here?  We do if sub-parts of integer
448ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      registers are accessed, but I don't think that ever happens on
449ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ARM. */
450ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (iregNo) {
451ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0:  return OFFB_R0;
452ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 1:  return OFFB_R1;
453ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 2:  return OFFB_R2;
454ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 3:  return OFFB_R3;
455ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 4:  return OFFB_R4;
456ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 5:  return OFFB_R5;
457ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 6:  return OFFB_R6;
458ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 7:  return OFFB_R7;
459ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 8:  return OFFB_R8;
460ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 9:  return OFFB_R9;
461ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 10: return OFFB_R10;
462ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 11: return OFFB_R11;
463ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 12: return OFFB_R12;
464ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 13: return OFFB_R13;
465ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 14: return OFFB_R14;
466ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 15: return OFFB_R15T;
467ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default: vassert(0);
468ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
469ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
470ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
471ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Plain ("low level") read from a reg; no +8 offset magic for r15. */
472ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* llGetIReg ( UInt iregNo )
473ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
474ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(iregNo < 16);
475ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return IRExpr_Get( integerGuestRegOffset(iregNo), Ity_I32 );
476ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
477ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
478ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Architected read from a reg in ARM mode.  This automagically adds 8
479ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   to all reads of r15. */
480ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* getIRegA ( UInt iregNo )
481ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
482ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRExpr* e;
483ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ASSERT_IS_ARM;
484ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(iregNo < 16);
485ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (iregNo == 15) {
486ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* If asked for r15, don't read the guest state value, as that
487ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         may not be up to date in the case where loop unrolling has
488ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         happened, because the first insn's write to the block is
489ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         omitted; hence in the 2nd and subsequent unrollings we don't
490ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         have a correct value in guest r15.  Instead produce the
491ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         constant that we know would be produced at this point. */
492ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(0 == (guest_R15_curr_instr_notENC & 3));
493ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      e = mkU32(guest_R15_curr_instr_notENC + 8);
494ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
495ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      e = IRExpr_Get( integerGuestRegOffset(iregNo), Ity_I32 );
496ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
497ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return e;
498ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
499ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
500ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Architected read from a reg in Thumb mode.  This automagically adds
501ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   4 to all reads of r15. */
502ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* getIRegT ( UInt iregNo )
503ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
504ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRExpr* e;
505ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ASSERT_IS_THUMB;
506ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(iregNo < 16);
507ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (iregNo == 15) {
508ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Ditto comment in getIReg. */
509ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(0 == (guest_R15_curr_instr_notENC & 1));
510ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      e = mkU32(guest_R15_curr_instr_notENC + 4);
511ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
512ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      e = IRExpr_Get( integerGuestRegOffset(iregNo), Ity_I32 );
513ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
514ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return e;
515ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
516ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
517ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Plain ("low level") write to a reg; no jump or alignment magic for
518ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   r15. */
519ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void llPutIReg ( UInt iregNo, IRExpr* e )
520ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
521ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(iregNo < 16);
522ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(typeOfIRExpr(irsb->tyenv, e) == Ity_I32);
523ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put(integerGuestRegOffset(iregNo), e) );
524ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
525ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
526ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Architected write to an integer register in ARM mode.  If it is to
527ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   r15, record info so at the end of this insn's translation, a branch
528ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   to it can be made.  Also handles conditional writes to the
529ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   register: if guardT == IRTemp_INVALID then the write is
530ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   unconditional.  If writing r15, also 4-align it. */
531ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void putIRegA ( UInt       iregNo,
532ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       IRExpr*    e,
533ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       IRTemp     guardT /* :: Ity_I32, 0 or 1 */,
534ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       IRJumpKind jk /* if a jump is generated */ )
535ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
536ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* if writing r15, force e to be 4-aligned. */
537ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // INTERWORKING FIXME.  this needs to be relaxed so that
538ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // puts caused by LDMxx which load r15 interwork right.
539ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // but is no aligned too relaxed?
540ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   //if (iregNo == 15)
541ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   //   e = binop(Iop_And32, e, mkU32(~3));
542ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ASSERT_IS_ARM;
543ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* So, generate either an unconditional or a conditional write to
544ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      the reg. */
545ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (guardT == IRTemp_INVALID) {
546ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* unconditional write */
547ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      llPutIReg( iregNo, e );
548ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
549ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      llPutIReg( iregNo,
550ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 IRExpr_Mux0X( unop(Iop_32to8, mkexpr(guardT)),
551ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               llGetIReg(iregNo),
552ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               e ));
553ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
554ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (iregNo == 15) {
555ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // assert against competing r15 updates.  Shouldn't
556ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // happen; should be ruled out by the instr matching
557ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // logic.
558ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(r15written == False);
559ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(r15guard   == IRTemp_INVALID);
560ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(r15kind    == Ijk_Boring);
561ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      r15written = True;
562ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      r15guard   = guardT;
563ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      r15kind    = jk;
564ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
565ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
566ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
567ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
568ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Architected write to an integer register in Thumb mode.  Writes to
569ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   r15 are not allowed.  Handles conditional writes to the register:
570ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if guardT == IRTemp_INVALID then the write is unconditional. */
571ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void putIRegT ( UInt       iregNo,
572ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       IRExpr*    e,
573ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       IRTemp     guardT /* :: Ity_I32, 0 or 1 */ )
574ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
575ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* So, generate either an unconditional or a conditional write to
576ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      the reg. */
577ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ASSERT_IS_THUMB;
578ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(iregNo >= 0 && iregNo <= 14);
579ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (guardT == IRTemp_INVALID) {
580ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* unconditional write */
581ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      llPutIReg( iregNo, e );
582ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
583ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      llPutIReg( iregNo,
584ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 IRExpr_Mux0X( unop(Iop_32to8, mkexpr(guardT)),
585ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               llGetIReg(iregNo),
586ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               e ));
587ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
588ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
589ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
590ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
591ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Thumb16 and Thumb32 only.
592ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Returns true if reg is 13 or 15.  Implements the BadReg
593ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   predicate in the ARM ARM. */
594ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Bool isBadRegT ( UInt r )
595ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
596ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(r <= 15);
597ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ASSERT_IS_THUMB;
598ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return r == 13 || r == 15;
599ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
600ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
601ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
602ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* ---------------- Double registers ---------------- */
603ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
604ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Int doubleGuestRegOffset ( UInt dregNo )
605ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
606ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Do we care about endianness here?  Probably do if we ever get
607ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      into the situation of dealing with the single-precision VFP
608ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      registers. */
609ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (dregNo) {
610ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0:  return OFFB_D0;
611ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 1:  return OFFB_D1;
612ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 2:  return OFFB_D2;
613ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 3:  return OFFB_D3;
614ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 4:  return OFFB_D4;
615ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 5:  return OFFB_D5;
616ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 6:  return OFFB_D6;
617ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 7:  return OFFB_D7;
618ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 8:  return OFFB_D8;
619ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 9:  return OFFB_D9;
620ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 10: return OFFB_D10;
621ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 11: return OFFB_D11;
622ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 12: return OFFB_D12;
623ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 13: return OFFB_D13;
624ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 14: return OFFB_D14;
625ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 15: return OFFB_D15;
626ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 16: return OFFB_D16;
627ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 17: return OFFB_D17;
628ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 18: return OFFB_D18;
629ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 19: return OFFB_D19;
630ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 20: return OFFB_D20;
631ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 21: return OFFB_D21;
632ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 22: return OFFB_D22;
633ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 23: return OFFB_D23;
634ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 24: return OFFB_D24;
635ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 25: return OFFB_D25;
636ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 26: return OFFB_D26;
637ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 27: return OFFB_D27;
638ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 28: return OFFB_D28;
639ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 29: return OFFB_D29;
640ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 30: return OFFB_D30;
641ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 31: return OFFB_D31;
642ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default: vassert(0);
643ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
644ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
645ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
646ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Plain ("low level") read from a VFP Dreg. */
647ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* llGetDReg ( UInt dregNo )
648ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
649ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(dregNo < 32);
650ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return IRExpr_Get( doubleGuestRegOffset(dregNo), Ity_F64 );
651ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
652ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
653ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Architected read from a VFP Dreg. */
654ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* getDReg ( UInt dregNo ) {
655ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return llGetDReg( dregNo );
656ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
657ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
658ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Plain ("low level") write to a VFP Dreg. */
659ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void llPutDReg ( UInt dregNo, IRExpr* e )
660ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
661ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(dregNo < 32);
662ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(typeOfIRExpr(irsb->tyenv, e) == Ity_F64);
663ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put(doubleGuestRegOffset(dregNo), e) );
664ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
665ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
666ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Architected write to a VFP Dreg.  Handles conditional writes to the
667ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   register: if guardT == IRTemp_INVALID then the write is
668ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   unconditional. */
669ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void putDReg ( UInt    dregNo,
670ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      IRExpr* e,
671ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      IRTemp  guardT /* :: Ity_I32, 0 or 1 */)
672ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
673ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* So, generate either an unconditional or a conditional write to
674ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      the reg. */
675ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (guardT == IRTemp_INVALID) {
676ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* unconditional write */
677ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      llPutDReg( dregNo, e );
678ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
679ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      llPutDReg( dregNo,
680ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 IRExpr_Mux0X( unop(Iop_32to8, mkexpr(guardT)),
681ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               llGetDReg(dregNo),
682ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               e ));
683ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
684ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
685ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
686ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* And now exactly the same stuff all over again, but this time
687ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   taking/returning I64 rather than F64, to support 64-bit Neon
688ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ops. */
689ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
690ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Plain ("low level") read from a Neon Integer Dreg. */
691ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* llGetDRegI64 ( UInt dregNo )
692ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
693ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(dregNo < 32);
694ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return IRExpr_Get( doubleGuestRegOffset(dregNo), Ity_I64 );
695ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
696ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
697ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Architected read from a Neon Integer Dreg. */
698ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* getDRegI64 ( UInt dregNo ) {
699ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return llGetDRegI64( dregNo );
700ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
701ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
702ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Plain ("low level") write to a Neon Integer Dreg. */
703ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void llPutDRegI64 ( UInt dregNo, IRExpr* e )
704ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
705ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(dregNo < 32);
706ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(typeOfIRExpr(irsb->tyenv, e) == Ity_I64);
707ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put(doubleGuestRegOffset(dregNo), e) );
708ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
709ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
710ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Architected write to a Neon Integer Dreg.  Handles conditional
711ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   writes to the register: if guardT == IRTemp_INVALID then the write
712ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   is unconditional. */
713ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void putDRegI64 ( UInt    dregNo,
714ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         IRExpr* e,
715ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         IRTemp  guardT /* :: Ity_I32, 0 or 1 */)
716ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
717ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* So, generate either an unconditional or a conditional write to
718ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      the reg. */
719ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (guardT == IRTemp_INVALID) {
720ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* unconditional write */
721ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      llPutDRegI64( dregNo, e );
722ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
723ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      llPutDRegI64( dregNo,
724ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    IRExpr_Mux0X( unop(Iop_32to8, mkexpr(guardT)),
725ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  llGetDRegI64(dregNo),
726ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  e ));
727ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
728ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
729ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
730ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* ---------------- Quad registers ---------------- */
731ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
732ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Int quadGuestRegOffset ( UInt qregNo )
733ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
734ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Do we care about endianness here?  Probably do if we ever get
735ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      into the situation of dealing with the 64 bit Neon registers. */
736ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (qregNo) {
737ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0:  return OFFB_D0;
738ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 1:  return OFFB_D2;
739ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 2:  return OFFB_D4;
740ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 3:  return OFFB_D6;
741ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 4:  return OFFB_D8;
742ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 5:  return OFFB_D10;
743ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 6:  return OFFB_D12;
744ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 7:  return OFFB_D14;
745ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 8:  return OFFB_D16;
746ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 9:  return OFFB_D18;
747ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 10: return OFFB_D20;
748ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 11: return OFFB_D22;
749ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 12: return OFFB_D24;
750ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 13: return OFFB_D26;
751ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 14: return OFFB_D28;
752ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 15: return OFFB_D30;
753ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default: vassert(0);
754ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
755ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
756ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
757ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Plain ("low level") read from a Neon Qreg. */
758ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* llGetQReg ( UInt qregNo )
759ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
760ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(qregNo < 16);
761ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return IRExpr_Get( quadGuestRegOffset(qregNo), Ity_V128 );
762ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
763ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
764ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Architected read from a Neon Qreg. */
765ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* getQReg ( UInt qregNo ) {
766ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return llGetQReg( qregNo );
767ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
768ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
769ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Plain ("low level") write to a Neon Qreg. */
770ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void llPutQReg ( UInt qregNo, IRExpr* e )
771ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
772ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(qregNo < 16);
773ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(typeOfIRExpr(irsb->tyenv, e) == Ity_V128);
774ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put(quadGuestRegOffset(qregNo), e) );
775ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
776ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
777ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Architected write to a Neon Qreg.  Handles conditional writes to the
778ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   register: if guardT == IRTemp_INVALID then the write is
779ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   unconditional. */
780ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void putQReg ( UInt    qregNo,
781ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      IRExpr* e,
782ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      IRTemp  guardT /* :: Ity_I32, 0 or 1 */)
783ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
784ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* So, generate either an unconditional or a conditional write to
785ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      the reg. */
786ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (guardT == IRTemp_INVALID) {
787ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* unconditional write */
788ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      llPutQReg( qregNo, e );
789ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
790ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      llPutQReg( qregNo,
791ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 IRExpr_Mux0X( unop(Iop_32to8, mkexpr(guardT)),
792ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               llGetQReg(qregNo),
793ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               e ));
794ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
795ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
796ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
797ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
798ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* ---------------- Float registers ---------------- */
799ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
800ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Int floatGuestRegOffset ( UInt fregNo )
801ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
802ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Start with the offset of the containing double, and then correct
803ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      for endianness.  Actually this is completely bogus and needs
804ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      careful thought. */
805ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int off;
806ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(fregNo < 32);
807ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   off = doubleGuestRegOffset(fregNo >> 1);
808ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (host_is_bigendian) {
809ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(0);
810ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
811ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (fregNo & 1)
812ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         off += 4;
813ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
814ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return off;
815ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
816ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
817ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Plain ("low level") read from a VFP Freg. */
818ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* llGetFReg ( UInt fregNo )
819ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
820ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(fregNo < 32);
821ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return IRExpr_Get( floatGuestRegOffset(fregNo), Ity_F32 );
822ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
823ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
824ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Architected read from a VFP Freg. */
825ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* getFReg ( UInt fregNo ) {
826ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return llGetFReg( fregNo );
827ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
828ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
829ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Plain ("low level") write to a VFP Freg. */
830ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void llPutFReg ( UInt fregNo, IRExpr* e )
831ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
832ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(fregNo < 32);
833ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(typeOfIRExpr(irsb->tyenv, e) == Ity_F32);
834ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put(floatGuestRegOffset(fregNo), e) );
835ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
836ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
837ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Architected write to a VFP Freg.  Handles conditional writes to the
838ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   register: if guardT == IRTemp_INVALID then the write is
839ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   unconditional. */
840ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void putFReg ( UInt    fregNo,
841ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      IRExpr* e,
842ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      IRTemp  guardT /* :: Ity_I32, 0 or 1 */)
843ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
844ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* So, generate either an unconditional or a conditional write to
845ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      the reg. */
846ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (guardT == IRTemp_INVALID) {
847ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* unconditional write */
848ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      llPutFReg( fregNo, e );
849ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
850ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      llPutFReg( fregNo,
851ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 IRExpr_Mux0X( unop(Iop_32to8, mkexpr(guardT)),
852ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               llGetFReg(fregNo),
853ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               e ));
854ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
855ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
856ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
857ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
858ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* ---------------- Misc registers ---------------- */
859ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
860ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void putMiscReg32 ( UInt    gsoffset,
861ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           IRExpr* e, /* :: Ity_I32 */
862ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           IRTemp  guardT /* :: Ity_I32, 0 or 1 */)
863ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
864ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (gsoffset) {
865ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case OFFB_FPSCR:   break;
866ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case OFFB_QFLAG32: break;
867ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case OFFB_GEFLAG0: break;
868ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case OFFB_GEFLAG1: break;
869ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case OFFB_GEFLAG2: break;
870ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case OFFB_GEFLAG3: break;
871ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default: vassert(0); /* awaiting more cases */
872ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
873ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(typeOfIRExpr(irsb->tyenv, e) == Ity_I32);
874ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
875ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (guardT == IRTemp_INVALID) {
876ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* unconditional write */
877ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt(IRStmt_Put(gsoffset, e));
878ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
879ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt(IRStmt_Put(
880ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         gsoffset,
881ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRExpr_Mux0X( unop(Iop_32to8, mkexpr(guardT)),
882ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       IRExpr_Get(gsoffset, Ity_I32),
883ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       e
884ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         )
885ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ));
886ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
887ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
888ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
889ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRTemp get_ITSTATE ( void )
890ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
891ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ASSERT_IS_THUMB;
892ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp t = newTemp(Ity_I32);
893ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign(t, IRExpr_Get( OFFB_ITSTATE, Ity_I32));
894ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return t;
895ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
896ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
897ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void put_ITSTATE ( IRTemp t )
898ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
899ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ASSERT_IS_THUMB;
900ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_ITSTATE, mkexpr(t)) );
901ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
902ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
903ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRTemp get_QFLAG32 ( void )
904ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
905ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp t = newTemp(Ity_I32);
906ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign(t, IRExpr_Get( OFFB_QFLAG32, Ity_I32));
907ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return t;
908ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
909ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
910ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void put_QFLAG32 ( IRTemp t, IRTemp condT )
911ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
912ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   putMiscReg32( OFFB_QFLAG32, mkexpr(t), condT );
913ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
914ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
915ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Stickily set the 'Q' flag (APSR bit 27) of the APSR (Application Program
916ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Status Register) to indicate that overflow or saturation occurred.
917ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Nb: t must be zero to denote no saturation, and any nonzero
918ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   value to indicate saturation. */
919ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void or_into_QFLAG32 ( IRExpr* e, IRTemp condT )
920ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
921ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp old = get_QFLAG32();
922ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp nyu = newTemp(Ity_I32);
923ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign(nyu, binop(Iop_Or32, mkexpr(old), e) );
924ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   put_QFLAG32(nyu, condT);
925ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
926ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
927ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Generate code to set APSR.GE[flagNo]. Each fn call sets 1 bit.
928ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   flagNo: which flag bit to set [3...0]
929ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   lowbits_to_ignore:  0 = look at all 32 bits
930ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       8 = look at top 24 bits only
931ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      16 = look at top 16 bits only
932ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      31 = look at the top bit only
933ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   e: input value to be evaluated.
934ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   The new value is taken from 'e' with the lowest 'lowbits_to_ignore'
935ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   masked out.  If the resulting value is zero then the GE flag is
936ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   set to 0; any other value sets the flag to 1. */
937ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void put_GEFLAG32 ( Int flagNo,            /* 0, 1, 2 or 3 */
938ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           Int lowbits_to_ignore, /* 0, 8, 16 or 31   */
939ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           IRExpr* e,             /* Ity_I32 */
940ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           IRTemp condT )
941ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
942ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert( flagNo >= 0 && flagNo <= 3 );
943ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert( lowbits_to_ignore == 0  ||
944ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            lowbits_to_ignore == 8  ||
945ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            lowbits_to_ignore == 16 ||
946ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            lowbits_to_ignore == 31 );
947ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp masked = newTemp(Ity_I32);
948ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign(masked, binop(Iop_Shr32, e, mkU8(lowbits_to_ignore)));
949ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
950ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (flagNo) {
951ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0: putMiscReg32(OFFB_GEFLAG0, mkexpr(masked), condT); break;
952ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 1: putMiscReg32(OFFB_GEFLAG1, mkexpr(masked), condT); break;
953ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 2: putMiscReg32(OFFB_GEFLAG2, mkexpr(masked), condT); break;
954ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 3: putMiscReg32(OFFB_GEFLAG3, mkexpr(masked), condT); break;
955ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default: vassert(0);
956ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
957ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
958ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
959ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Return the (32-bit, zero-or-nonzero representation scheme) of
960ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   the specified GE flag. */
961ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* get_GEFLAG32( Int flagNo /* 0, 1, 2, 3 */ )
962ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
963ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (flagNo) {
964ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0: return IRExpr_Get( OFFB_GEFLAG0, Ity_I32 );
965ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 1: return IRExpr_Get( OFFB_GEFLAG1, Ity_I32 );
966ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 2: return IRExpr_Get( OFFB_GEFLAG2, Ity_I32 );
967ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 3: return IRExpr_Get( OFFB_GEFLAG3, Ity_I32 );
968ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default: vassert(0);
969ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
970ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
971ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
972ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Set all 4 GE flags from the given 32-bit value as follows: GE 3 and
973ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   2 are set from bit 31 of the value, and GE 1 and 0 are set from bit
974ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   15 of the value.  All other bits are ignored. */
975ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void set_GE_32_10_from_bits_31_15 ( IRTemp t32, IRTemp condT )
976ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
977ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp ge10 = newTemp(Ity_I32);
978ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp ge32 = newTemp(Ity_I32);
979ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign(ge10, binop(Iop_And32, mkexpr(t32), mkU32(0x00008000)));
980ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign(ge32, binop(Iop_And32, mkexpr(t32), mkU32(0x80000000)));
981ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   put_GEFLAG32( 0, 0, mkexpr(ge10), condT );
982ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   put_GEFLAG32( 1, 0, mkexpr(ge10), condT );
983ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   put_GEFLAG32( 2, 0, mkexpr(ge32), condT );
984ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   put_GEFLAG32( 3, 0, mkexpr(ge32), condT );
985ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
986ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
987ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
988ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Set all 4 GE flags from the given 32-bit value as follows: GE 3
989ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   from bit 31, GE 2 from bit 23, GE 1 from bit 15, and GE0 from
990ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   bit 7.  All other bits are ignored. */
991ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void set_GE_3_2_1_0_from_bits_31_23_15_7 ( IRTemp t32, IRTemp condT )
992ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
993ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp ge0 = newTemp(Ity_I32);
994ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp ge1 = newTemp(Ity_I32);
995ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp ge2 = newTemp(Ity_I32);
996ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp ge3 = newTemp(Ity_I32);
997ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign(ge0, binop(Iop_And32, mkexpr(t32), mkU32(0x00000080)));
998ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign(ge1, binop(Iop_And32, mkexpr(t32), mkU32(0x00008000)));
999ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign(ge2, binop(Iop_And32, mkexpr(t32), mkU32(0x00800000)));
1000ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign(ge3, binop(Iop_And32, mkexpr(t32), mkU32(0x80000000)));
1001ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   put_GEFLAG32( 0, 0, mkexpr(ge0), condT );
1002ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   put_GEFLAG32( 1, 0, mkexpr(ge1), condT );
1003ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   put_GEFLAG32( 2, 0, mkexpr(ge2), condT );
1004ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   put_GEFLAG32( 3, 0, mkexpr(ge3), condT );
1005ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1006ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1007ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1008ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* ---------------- FPSCR stuff ---------------- */
1009ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1010ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Generate IR to get hold of the rounding mode bits in FPSCR, and
1011ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   convert them to IR format.  Bind the final result to the
1012ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   returned temp. */
1013ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRTemp /* :: Ity_I32 */ mk_get_IR_rounding_mode ( void )
1014ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1015ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* The ARMvfp encoding for rounding mode bits is:
1016ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         00  to nearest
1017ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         01  to +infinity
1018ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         10  to -infinity
1019ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         11  to zero
1020ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      We need to convert that to the IR encoding:
1021ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         00  to nearest (the default)
1022ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         10  to +infinity
1023ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         01  to -infinity
1024ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         11  to zero
1025ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Which can be done by swapping bits 0 and 1.
1026ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      The rmode bits are at 23:22 in FPSCR.
1027ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   */
1028ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp armEncd = newTemp(Ity_I32);
1029ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp swapped = newTemp(Ity_I32);
1030ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Fish FPSCR[23:22] out, and slide to bottom.  Doesn't matter that
1031ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      we don't zero out bits 24 and above, since the assignment to
1032ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      'swapped' will mask them out anyway. */
1033ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign(armEncd,
1034ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          binop(Iop_Shr32, IRExpr_Get(OFFB_FPSCR, Ity_I32), mkU8(22)));
1035ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Now swap them. */
1036ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign(swapped,
1037ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          binop(Iop_Or32,
1038ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                binop(Iop_And32,
1039ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      binop(Iop_Shl32, mkexpr(armEncd), mkU8(1)),
1040ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      mkU32(2)),
1041ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                binop(Iop_And32,
1042ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      binop(Iop_Shr32, mkexpr(armEncd), mkU8(1)),
1043ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      mkU32(1))
1044ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         ));
1045ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return swapped;
1046ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1047ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1048ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1049ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
1050ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- Helpers for flag handling and conditional insns      ---*/
1051ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
1052ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1053ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic HChar* name_ARMCondcode ( ARMCondcode cond )
1054ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1055ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (cond) {
1056ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case ARMCondEQ:  return "{eq}";
1057ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case ARMCondNE:  return "{ne}";
1058ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case ARMCondHS:  return "{hs}";  // or 'cs'
1059ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case ARMCondLO:  return "{lo}";  // or 'cc'
1060ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case ARMCondMI:  return "{mi}";
1061ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case ARMCondPL:  return "{pl}";
1062ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case ARMCondVS:  return "{vs}";
1063ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case ARMCondVC:  return "{vc}";
1064ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case ARMCondHI:  return "{hi}";
1065ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case ARMCondLS:  return "{ls}";
1066ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case ARMCondGE:  return "{ge}";
1067ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case ARMCondLT:  return "{lt}";
1068ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case ARMCondGT:  return "{gt}";
1069ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case ARMCondLE:  return "{le}";
1070ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case ARMCondAL:  return ""; // {al}: is the default
1071ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case ARMCondNV:  return "{nv}";
1072ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default: vpanic("name_ARMCondcode");
1073ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1074ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1075ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* and a handy shorthand for it */
1076ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic HChar* nCC ( ARMCondcode cond ) {
1077ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return name_ARMCondcode(cond);
1078ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1079ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1080ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1081ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Build IR to calculate some particular condition from stored
1082ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   CC_OP/CC_DEP1/CC_DEP2/CC_NDEP.  Returns an expression of type
1083ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Ity_I32, suitable for narrowing.  Although the return type is
1084ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Ity_I32, the returned value is either 0 or 1.  'cond' must be
1085ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   :: Ity_I32 and must denote the condition to compute in
1086ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   bits 7:4, and be zero everywhere else.
1087ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
1088ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* mk_armg_calculate_condition_dyn ( IRExpr* cond )
1089ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1090ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(typeOfIRExpr(irsb->tyenv, cond) == Ity_I32);
1091b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   /* And 'cond' had better produce a value in which only bits 7:4 are
1092b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      nonzero.  However, obviously we can't assert for that. */
1093ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1094ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* So what we're constructing for the first argument is
1095b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      "(cond << 4) | stored-operation".
1096b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      However, as per comments above, 'cond' must be supplied
1097b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      pre-shifted to this function.
1098ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1099ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      This pairing scheme requires that the ARM_CC_OP_ values all fit
1100ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      in 4 bits.  Hence we are passing a (COND, OP) pair in the lowest
1101ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      8 bits of the first argument. */
1102ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRExpr** args
1103ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      = mkIRExprVec_4(
1104ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           binop(Iop_Or32, IRExpr_Get(OFFB_CC_OP, Ity_I32), cond),
1105ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           IRExpr_Get(OFFB_CC_DEP1, Ity_I32),
1106ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           IRExpr_Get(OFFB_CC_DEP2, Ity_I32),
1107ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           IRExpr_Get(OFFB_CC_NDEP, Ity_I32)
1108ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        );
1109ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRExpr* call
1110ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      = mkIRExprCCall(
1111ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           Ity_I32,
1112ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           0/*regparm*/,
1113ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           "armg_calculate_condition", &armg_calculate_condition,
1114ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           args
1115ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        );
1116ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1117ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Exclude the requested condition, OP and NDEP from definedness
1118ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      checking.  We're only interested in DEP1 and DEP2. */
1119ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   call->Iex.CCall.cee->mcx_mask = (1<<0) | (1<<3);
1120ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return call;
1121ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1122ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1123ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1124ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Build IR to calculate some particular condition from stored
1125ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   CC_OP/CC_DEP1/CC_DEP2/CC_NDEP.  Returns an expression of type
1126ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Ity_I32, suitable for narrowing.  Although the return type is
1127ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Ity_I32, the returned value is either 0 or 1.
1128ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
1129ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* mk_armg_calculate_condition ( ARMCondcode cond )
1130ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1131ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  /* First arg is "(cond << 4) | condition".  This requires that the
1132ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     ARM_CC_OP_ values all fit in 4 bits.  Hence we are passing a
1133ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     (COND, OP) pair in the lowest 8 bits of the first argument. */
1134ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(cond >= 0 && cond <= 15);
1135ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return mk_armg_calculate_condition_dyn( mkU32(cond << 4) );
1136ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1137ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1138ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1139ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Build IR to calculate just the carry flag from stored
1140ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   CC_OP/CC_DEP1/CC_DEP2/CC_NDEP.  Returns an expression ::
1141ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Ity_I32. */
1142ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* mk_armg_calculate_flag_c ( void )
1143ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1144ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRExpr** args
1145ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      = mkIRExprVec_4( IRExpr_Get(OFFB_CC_OP,   Ity_I32),
1146ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       IRExpr_Get(OFFB_CC_DEP1, Ity_I32),
1147ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       IRExpr_Get(OFFB_CC_DEP2, Ity_I32),
1148ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       IRExpr_Get(OFFB_CC_NDEP, Ity_I32) );
1149ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRExpr* call
1150ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      = mkIRExprCCall(
1151ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           Ity_I32,
1152ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           0/*regparm*/,
1153ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           "armg_calculate_flag_c", &armg_calculate_flag_c,
1154ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           args
1155ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        );
1156ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Exclude OP and NDEP from definedness checking.  We're only
1157ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      interested in DEP1 and DEP2. */
1158ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   call->Iex.CCall.cee->mcx_mask = (1<<0) | (1<<3);
1159ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return call;
1160ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1161ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1162ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1163ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Build IR to calculate just the overflow flag from stored
1164ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   CC_OP/CC_DEP1/CC_DEP2/CC_NDEP.  Returns an expression ::
1165ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Ity_I32. */
1166ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* mk_armg_calculate_flag_v ( void )
1167ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1168ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRExpr** args
1169ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      = mkIRExprVec_4( IRExpr_Get(OFFB_CC_OP,   Ity_I32),
1170ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       IRExpr_Get(OFFB_CC_DEP1, Ity_I32),
1171ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       IRExpr_Get(OFFB_CC_DEP2, Ity_I32),
1172ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       IRExpr_Get(OFFB_CC_NDEP, Ity_I32) );
1173ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRExpr* call
1174ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      = mkIRExprCCall(
1175ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           Ity_I32,
1176ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           0/*regparm*/,
1177ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           "armg_calculate_flag_v", &armg_calculate_flag_v,
1178ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           args
1179ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        );
1180ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Exclude OP and NDEP from definedness checking.  We're only
1181ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      interested in DEP1 and DEP2. */
1182ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   call->Iex.CCall.cee->mcx_mask = (1<<0) | (1<<3);
1183ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return call;
1184ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1185ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1186ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1187ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Build IR to calculate N Z C V in bits 31:28 of the
1188ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   returned word. */
1189ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* mk_armg_calculate_flags_nzcv ( void )
1190ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1191ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRExpr** args
1192ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      = mkIRExprVec_4( IRExpr_Get(OFFB_CC_OP,   Ity_I32),
1193ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       IRExpr_Get(OFFB_CC_DEP1, Ity_I32),
1194ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       IRExpr_Get(OFFB_CC_DEP2, Ity_I32),
1195ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       IRExpr_Get(OFFB_CC_NDEP, Ity_I32) );
1196ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRExpr* call
1197ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      = mkIRExprCCall(
1198ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           Ity_I32,
1199ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           0/*regparm*/,
1200ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           "armg_calculate_flags_nzcv", &armg_calculate_flags_nzcv,
1201ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           args
1202ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        );
1203ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Exclude OP and NDEP from definedness checking.  We're only
1204ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      interested in DEP1 and DEP2. */
1205ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   call->Iex.CCall.cee->mcx_mask = (1<<0) | (1<<3);
1206ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return call;
1207ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1208ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1209ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* mk_armg_calculate_flag_qc ( IRExpr* resL, IRExpr* resR, Bool Q )
1210ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1211ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRExpr** args1;
1212ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRExpr** args2;
1213ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRExpr *call1, *call2, *res;
1214ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1215ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (Q) {
1216ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      args1 = mkIRExprVec_4 ( binop(Iop_GetElem32x4, resL, mkU8(0)),
1217ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              binop(Iop_GetElem32x4, resL, mkU8(1)),
1218ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              binop(Iop_GetElem32x4, resR, mkU8(0)),
1219ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              binop(Iop_GetElem32x4, resR, mkU8(1)) );
1220ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      args2 = mkIRExprVec_4 ( binop(Iop_GetElem32x4, resL, mkU8(2)),
1221ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              binop(Iop_GetElem32x4, resL, mkU8(3)),
1222ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              binop(Iop_GetElem32x4, resR, mkU8(2)),
1223ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              binop(Iop_GetElem32x4, resR, mkU8(3)) );
1224ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
1225ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      args1 = mkIRExprVec_4 ( binop(Iop_GetElem32x2, resL, mkU8(0)),
1226ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              binop(Iop_GetElem32x2, resL, mkU8(1)),
1227ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              binop(Iop_GetElem32x2, resR, mkU8(0)),
1228ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              binop(Iop_GetElem32x2, resR, mkU8(1)) );
1229ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1230ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1231ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#if 1
1232ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   call1 = mkIRExprCCall(
1233ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             Ity_I32,
1234ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             0/*regparm*/,
1235ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             "armg_calculate_flag_qc", &armg_calculate_flag_qc,
1236ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             args1
1237ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          );
1238ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (Q) {
1239ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      call2 = mkIRExprCCall(
1240ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                Ity_I32,
1241ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                0/*regparm*/,
1242ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                "armg_calculate_flag_qc", &armg_calculate_flag_qc,
1243ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                args2
1244ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             );
1245ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1246ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (Q) {
1247ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      res = binop(Iop_Or32, call1, call2);
1248ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
1249ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      res = call1;
1250ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1251ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#else
1252ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (Q) {
1253ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      res = unop(Iop_1Uto32,
1254ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 binop(Iop_CmpNE32,
1255ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       binop(Iop_Or32,
1256ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             binop(Iop_Or32,
1257ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   binop(Iop_Xor32,
1258ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                         args1[0],
1259ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                         args1[2]),
1260ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   binop(Iop_Xor32,
1261ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                         args1[1],
1262ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                         args1[3])),
1263ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             binop(Iop_Or32,
1264ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   binop(Iop_Xor32,
1265ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                         args2[0],
1266ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                         args2[2]),
1267ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   binop(Iop_Xor32,
1268ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                         args2[1],
1269ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                         args2[3]))),
1270ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       mkU32(0)));
1271ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
1272ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      res = unop(Iop_1Uto32,
1273ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 binop(Iop_CmpNE32,
1274ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       binop(Iop_Or32,
1275ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             binop(Iop_Xor32,
1276ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   args1[0],
1277ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   args1[2]),
1278ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             binop(Iop_Xor32,
1279ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   args1[1],
1280ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   args1[3])),
1281ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       mkU32(0)));
1282ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1283ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#endif
1284ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return res;
1285ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1286ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1287ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// FIXME: this is named wrongly .. looks like a sticky set of
1288ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// QC, not a write to it.
1289ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void setFlag_QC ( IRExpr* resL, IRExpr* resR, Bool Q,
1290ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         IRTemp condT )
1291ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1292ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   putMiscReg32 (OFFB_FPSCR,
1293ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 binop(Iop_Or32,
1294ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       IRExpr_Get(OFFB_FPSCR, Ity_I32),
1295ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       binop(Iop_Shl32,
1296ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             mk_armg_calculate_flag_qc(resL, resR, Q),
1297ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             mkU8(27))),
1298ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 condT);
1299ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1300ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1301ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Build IR to conditionally set the flags thunk.  As with putIReg, if
1302ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   guard is IRTemp_INVALID then it's unconditional, else it holds a
1303ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   condition :: Ity_I32. */
1304ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
1305ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid setFlags_D1_D2_ND ( UInt cc_op, IRTemp t_dep1,
1306ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         IRTemp t_dep2, IRTemp t_ndep,
1307ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         IRTemp guardT /* :: Ity_I32, 0 or 1 */ )
1308ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1309ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp c8;
1310ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(typeOfIRTemp(irsb->tyenv, t_dep1 == Ity_I32));
1311ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(typeOfIRTemp(irsb->tyenv, t_dep2 == Ity_I32));
1312ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(typeOfIRTemp(irsb->tyenv, t_ndep == Ity_I32));
1313ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(cc_op >= ARMG_CC_OP_COPY && cc_op < ARMG_CC_OP_NUMBER);
1314ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (guardT == IRTemp_INVALID) {
1315ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* unconditional */
1316ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_Put( OFFB_CC_OP,   mkU32(cc_op) ));
1317ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_Put( OFFB_CC_DEP1, mkexpr(t_dep1) ));
1318ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_Put( OFFB_CC_DEP2, mkexpr(t_dep2) ));
1319ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_Put( OFFB_CC_NDEP, mkexpr(t_ndep) ));
1320ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
1321ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* conditional */
1322ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      c8 = newTemp(Ity_I8);
1323ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( c8, unop(Iop_32to8, mkexpr(guardT)) );
1324ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_Put(
1325ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               OFFB_CC_OP,
1326ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRExpr_Mux0X( mkexpr(c8),
1327ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             IRExpr_Get(OFFB_CC_OP, Ity_I32),
1328ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             mkU32(cc_op) )));
1329ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_Put(
1330ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               OFFB_CC_DEP1,
1331ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRExpr_Mux0X( mkexpr(c8),
1332ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             IRExpr_Get(OFFB_CC_DEP1, Ity_I32),
1333ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             mkexpr(t_dep1) )));
1334ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_Put(
1335ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               OFFB_CC_DEP2,
1336ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRExpr_Mux0X( mkexpr(c8),
1337ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             IRExpr_Get(OFFB_CC_DEP2, Ity_I32),
1338ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             mkexpr(t_dep2) )));
1339ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_Put(
1340ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               OFFB_CC_NDEP,
1341ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRExpr_Mux0X( mkexpr(c8),
1342ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             IRExpr_Get(OFFB_CC_NDEP, Ity_I32),
1343ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             mkexpr(t_ndep) )));
1344ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1345ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1346ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1347ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1348ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Minor variant of the above that sets NDEP to zero (if it
1349ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   sets it at all) */
1350ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void setFlags_D1_D2 ( UInt cc_op, IRTemp t_dep1,
1351ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             IRTemp t_dep2,
1352ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             IRTemp guardT /* :: Ity_I32, 0 or 1 */ )
1353ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1354ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp z32 = newTemp(Ity_I32);
1355ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( z32, mkU32(0) );
1356ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   setFlags_D1_D2_ND( cc_op, t_dep1, t_dep2, z32, guardT );
1357ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1358ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1359ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1360ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Minor variant of the above that sets DEP2 to zero (if it
1361ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   sets it at all) */
1362ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void setFlags_D1_ND ( UInt cc_op, IRTemp t_dep1,
1363ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             IRTemp t_ndep,
1364ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             IRTemp guardT /* :: Ity_I32, 0 or 1 */ )
1365ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1366ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp z32 = newTemp(Ity_I32);
1367ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( z32, mkU32(0) );
1368ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   setFlags_D1_D2_ND( cc_op, t_dep1, z32, t_ndep, guardT );
1369ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1370ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1371ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1372ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Minor variant of the above that sets DEP2 and NDEP to zero (if it
1373ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   sets them at all) */
1374ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void setFlags_D1 ( UInt cc_op, IRTemp t_dep1,
1375ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          IRTemp guardT /* :: Ity_I32, 0 or 1 */ )
1376ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1377ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp z32 = newTemp(Ity_I32);
1378ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( z32, mkU32(0) );
1379ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   setFlags_D1_D2_ND( cc_op, t_dep1, z32, z32, guardT );
1380ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1381ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1382ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1383ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* ARM only */
1384ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Generate a side-exit to the next instruction, if the given guard
1385ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   expression :: Ity_I32 is 0 (note!  the side exit is taken if the
1386ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   condition is false!)  This is used to skip over conditional
1387ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   instructions which we can't generate straight-line code for, either
1388ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   because they are too complex or (more likely) they potentially
1389ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   generate exceptions.
1390ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
1391ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void mk_skip_over_A32_if_cond_is_false (
1392ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRTemp guardT /* :: Ity_I32, 0 or 1 */
1393ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            )
1394ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1395ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ASSERT_IS_ARM;
1396ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(guardT != IRTemp_INVALID);
1397ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(0 == (guest_R15_curr_instr_notENC & 3));
1398ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Exit(
1399ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            unop(Iop_Not1, unop(Iop_32to1, mkexpr(guardT))),
1400ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            Ijk_Boring,
1401ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            IRConst_U32(toUInt(guest_R15_curr_instr_notENC + 4))
1402ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       ));
1403ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1404ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1405ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Thumb16 only */
1406ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* ditto, but jump over a 16-bit thumb insn */
1407ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void mk_skip_over_T16_if_cond_is_false (
1408ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRTemp guardT /* :: Ity_I32, 0 or 1 */
1409ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            )
1410ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1411ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ASSERT_IS_THUMB;
1412ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(guardT != IRTemp_INVALID);
1413ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(0 == (guest_R15_curr_instr_notENC & 1));
1414ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Exit(
1415ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            unop(Iop_Not1, unop(Iop_32to1, mkexpr(guardT))),
1416ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            Ijk_Boring,
1417ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            IRConst_U32(toUInt((guest_R15_curr_instr_notENC + 2) | 1))
1418ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       ));
1419ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1420ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1421ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1422ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Thumb32 only */
1423ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* ditto, but jump over a 32-bit thumb insn */
1424ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void mk_skip_over_T32_if_cond_is_false (
1425ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRTemp guardT /* :: Ity_I32, 0 or 1 */
1426ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            )
1427ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1428ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ASSERT_IS_THUMB;
1429ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(guardT != IRTemp_INVALID);
1430ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(0 == (guest_R15_curr_instr_notENC & 1));
1431ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Exit(
1432ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            unop(Iop_Not1, unop(Iop_32to1, mkexpr(guardT))),
1433ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            Ijk_Boring,
1434ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            IRConst_U32(toUInt((guest_R15_curr_instr_notENC + 4) | 1))
1435ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       ));
1436ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1437ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1438ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1439ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Thumb16 and Thumb32 only
1440ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Generate a SIGILL followed by a restart of the current instruction
1441ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if the given temp is nonzero. */
1442ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void gen_SIGILL_T_if_nonzero ( IRTemp t /* :: Ity_I32 */ )
1443ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1444ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ASSERT_IS_THUMB;
1445ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(t != IRTemp_INVALID);
1446ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(0 == (guest_R15_curr_instr_notENC & 1));
1447ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt(
1448ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRStmt_Exit(
1449ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         binop(Iop_CmpNE32, mkexpr(t), mkU32(0)),
1450ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Ijk_NoDecode,
1451ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRConst_U32(toUInt(guest_R15_curr_instr_notENC | 1))
1452ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      )
1453ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   );
1454ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1455ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1456ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1457ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Inspect the old_itstate, and generate a SIGILL if it indicates that
1458ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   we are currently in an IT block and are not the last in the block.
1459ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   This also rolls back guest_ITSTATE to its old value before the exit
1460ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   and restores it to its new value afterwards.  This is so that if
1461ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   the exit is taken, we have an up to date version of ITSTATE
1462ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   available.  Without doing that, we have no hope of making precise
1463ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   exceptions work. */
1464ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void gen_SIGILL_T_if_in_but_NLI_ITBlock (
1465ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRTemp old_itstate /* :: Ity_I32 */,
1466ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRTemp new_itstate /* :: Ity_I32 */
1467ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            )
1468ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1469ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ASSERT_IS_THUMB;
1470ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   put_ITSTATE(old_itstate); // backout
1471ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp guards_for_next3 = newTemp(Ity_I32);
1472ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign(guards_for_next3,
1473ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          binop(Iop_Shr32, mkexpr(old_itstate), mkU8(8)));
1474ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   gen_SIGILL_T_if_nonzero(guards_for_next3);
1475ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   put_ITSTATE(new_itstate); //restore
1476ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1477ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1478ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1479ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Simpler version of the above, which generates a SIGILL if
1480ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   we're anywhere within an IT block. */
1481ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void gen_SIGILL_T_if_in_ITBlock (
1482ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRTemp old_itstate /* :: Ity_I32 */,
1483ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRTemp new_itstate /* :: Ity_I32 */
1484ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            )
1485ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1486ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   put_ITSTATE(old_itstate); // backout
1487ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   gen_SIGILL_T_if_nonzero(old_itstate);
1488ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   put_ITSTATE(new_itstate); //restore
1489ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1490ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1491ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1492ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Generate an APSR value, from the NZCV thunk, and
1493ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   from QFLAG32 and GEFLAG0 .. GEFLAG3. */
1494ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRTemp synthesise_APSR ( void )
1495ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1496ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp res1 = newTemp(Ity_I32);
1497ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Get NZCV
1498ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( res1, mk_armg_calculate_flags_nzcv() );
1499ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // OR in the Q value
1500ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp res2 = newTemp(Ity_I32);
1501ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign(
1502ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      res2,
1503ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      binop(Iop_Or32,
1504ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            mkexpr(res1),
1505ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            binop(Iop_Shl32,
1506ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  unop(Iop_1Uto32,
1507ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       binop(Iop_CmpNE32,
1508ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             mkexpr(get_QFLAG32()),
1509ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             mkU32(0))),
1510ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  mkU8(ARMG_CC_SHIFT_Q)))
1511ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   );
1512ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // OR in GE0 .. GE3
1513ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRExpr* ge0
1514ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      = unop(Iop_1Uto32, binop(Iop_CmpNE32, get_GEFLAG32(0), mkU32(0)));
1515ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRExpr* ge1
1516ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      = unop(Iop_1Uto32, binop(Iop_CmpNE32, get_GEFLAG32(1), mkU32(0)));
1517ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRExpr* ge2
1518ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      = unop(Iop_1Uto32, binop(Iop_CmpNE32, get_GEFLAG32(2), mkU32(0)));
1519ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRExpr* ge3
1520ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      = unop(Iop_1Uto32, binop(Iop_CmpNE32, get_GEFLAG32(3), mkU32(0)));
1521ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp res3 = newTemp(Ity_I32);
1522ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign(res3,
1523ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          binop(Iop_Or32,
1524ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                mkexpr(res2),
1525ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                binop(Iop_Or32,
1526ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      binop(Iop_Or32,
1527ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            binop(Iop_Shl32, ge0, mkU8(16)),
1528ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            binop(Iop_Shl32, ge1, mkU8(17))),
1529ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      binop(Iop_Or32,
1530ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            binop(Iop_Shl32, ge2, mkU8(18)),
1531ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            binop(Iop_Shl32, ge3, mkU8(19))) )));
1532ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return res3;
1533ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1534ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1535ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1536ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* and the inverse transformation: given an APSR value,
1537ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   set the NZCV thunk, the Q flag, and the GE flags. */
1538ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void desynthesise_APSR ( Bool write_nzcvq, Bool write_ge,
1539ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                IRTemp apsrT, IRTemp condT )
1540ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1541ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(write_nzcvq || write_ge);
1542ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (write_nzcvq) {
1543ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // Do NZCV
1544ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp immT = newTemp(Ity_I32);
1545ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(immT, binop(Iop_And32, mkexpr(apsrT), mkU32(0xF0000000)) );
1546ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      setFlags_D1(ARMG_CC_OP_COPY, immT, condT);
1547ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // Do Q
1548ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp qnewT = newTemp(Ity_I32);
1549ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(qnewT, binop(Iop_And32, mkexpr(apsrT), mkU32(ARMG_CC_MASK_Q)));
1550ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      put_QFLAG32(qnewT, condT);
1551ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1552ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (write_ge) {
1553ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // Do GE3..0
1554ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      put_GEFLAG32(0, 0, binop(Iop_And32, mkexpr(apsrT), mkU32(1<<16)),
1555ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   condT);
1556ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      put_GEFLAG32(1, 0, binop(Iop_And32, mkexpr(apsrT), mkU32(1<<17)),
1557ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   condT);
1558ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      put_GEFLAG32(2, 0, binop(Iop_And32, mkexpr(apsrT), mkU32(1<<18)),
1559ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   condT);
1560ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      put_GEFLAG32(3, 0, binop(Iop_And32, mkexpr(apsrT), mkU32(1<<19)),
1561ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   condT);
1562ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1563ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1564ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1565ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1566ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
1567ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- Helpers for saturation                               ---*/
1568ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
1569ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1570ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* FIXME: absolutely the only diff. between (a) armUnsignedSatQ and
1571ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   (b) armSignedSatQ is that in (a) the floor is set to 0, whereas in
1572ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   (b) the floor is computed from the value of imm5.  these two fnsn
1573ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   should be commoned up. */
1574ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1575ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* UnsignedSatQ(): 'clamp' each value so it lies between 0 <= x <= (2^N)-1
1576ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Optionally return flag resQ saying whether saturation occurred.
1577ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   See definition in manual, section A2.2.1, page 41
1578ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   (bits(N), boolean) UnsignedSatQ( integer i, integer N )
1579ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   {
1580ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     if ( i > (2^N)-1 ) { result = (2^N)-1; saturated = TRUE; }
1581ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     elsif ( i < 0 )    { result = 0; saturated = TRUE; }
1582ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     else               { result = i; saturated = FALSE; }
1583ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     return ( result<N-1:0>, saturated );
1584ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1585ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
1586ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void armUnsignedSatQ( IRTemp* res,  /* OUT - Ity_I32 */
1587ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             IRTemp* resQ, /* OUT - Ity_I32  */
1588ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             IRTemp regT,  /* value to clamp - Ity_I32 */
1589ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             UInt imm5 )   /* saturation ceiling */
1590ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1591ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt ceil  = (1 << imm5) - 1;    // (2^imm5)-1
1592ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt floor = 0;
1593ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1594ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp node0 = newTemp(Ity_I32);
1595ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp node1 = newTemp(Ity_I32);
1596ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp node2 = newTemp(Ity_I1);
1597ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp node3 = newTemp(Ity_I32);
1598ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp node4 = newTemp(Ity_I32);
1599ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp node5 = newTemp(Ity_I1);
1600ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp node6 = newTemp(Ity_I32);
1601ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1602ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( node0, mkexpr(regT) );
1603ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( node1, mkU32(ceil) );
1604ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( node2, binop( Iop_CmpLT32S, mkexpr(node1), mkexpr(node0) ) );
1605ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( node3, IRExpr_Mux0X( unop(Iop_1Uto8, mkexpr(node2)),
1606ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                mkexpr(node0),
1607ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                mkexpr(node1) ) );
1608ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( node4, mkU32(floor) );
1609ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( node5, binop( Iop_CmpLT32S, mkexpr(node3), mkexpr(node4) ) );
1610ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( node6, IRExpr_Mux0X( unop(Iop_1Uto8, mkexpr(node5)),
1611ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                mkexpr(node3),
1612ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                mkexpr(node4) ) );
1613ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( *res, mkexpr(node6) );
1614ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1615ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* if saturation occurred, then resQ is set to some nonzero value
1616ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if sat did not occur, resQ is guaranteed to be zero. */
1617ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (resQ) {
1618ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( *resQ, binop(Iop_Xor32, mkexpr(*res), mkexpr(regT)) );
1619ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1620ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1621ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1622ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1623ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* SignedSatQ(): 'clamp' each value so it lies between  -2^N <= x <= (2^N) - 1
1624ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Optionally return flag resQ saying whether saturation occurred.
1625ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   - see definition in manual, section A2.2.1, page 41
1626ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   (bits(N), boolean ) SignedSatQ( integer i, integer N )
1627ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   {
1628ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     if ( i > 2^(N-1) - 1 )    { result = 2^(N-1) - 1; saturated = TRUE; }
1629ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     elsif ( i < -(2^(N-1)) )  { result = -(2^(N-1));  saturated = FALSE; }
1630ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     else                      { result = i;           saturated = FALSE; }
1631ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     return ( result[N-1:0], saturated );
1632ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1633ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
1634ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void armSignedSatQ( IRTemp regT,    /* value to clamp - Ity_I32 */
1635ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           UInt imm5,      /* saturation ceiling */
1636ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           IRTemp* res,    /* OUT - Ity_I32 */
1637ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           IRTemp* resQ )  /* OUT - Ity_I32  */
1638ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1639ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int ceil  =  (1 << (imm5-1)) - 1;  //  (2^(imm5-1))-1
1640ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int floor = -(1 << (imm5-1));      // -(2^(imm5-1))
1641ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1642ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp node0 = newTemp(Ity_I32);
1643ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp node1 = newTemp(Ity_I32);
1644ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp node2 = newTemp(Ity_I1);
1645ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp node3 = newTemp(Ity_I32);
1646ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp node4 = newTemp(Ity_I32);
1647ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp node5 = newTemp(Ity_I1);
1648ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp node6 = newTemp(Ity_I32);
1649ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1650ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( node0, mkexpr(regT) );
1651ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( node1, mkU32(ceil) );
1652ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( node2, binop( Iop_CmpLT32S, mkexpr(node1), mkexpr(node0) ) );
1653ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( node3, IRExpr_Mux0X( unop(Iop_1Uto8, mkexpr(node2)),
1654ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                mkexpr(node0),  mkexpr(node1) ) );
1655ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( node4, mkU32(floor) );
1656ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( node5, binop( Iop_CmpLT32S, mkexpr(node3), mkexpr(node4) ) );
1657ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( node6, IRExpr_Mux0X( unop(Iop_1Uto8, mkexpr(node5)),
1658ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                mkexpr(node3),  mkexpr(node4) ) );
1659ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( *res, mkexpr(node6) );
1660ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1661ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* if saturation occurred, then resQ is set to some nonzero value
1662ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if sat did not occur, resQ is guaranteed to be zero. */
1663ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (resQ) {
1664ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     assign( *resQ, binop(Iop_Xor32, mkexpr(*res), mkexpr(regT)) );
1665ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1666ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1667ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1668ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1669ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Compute a value 0 :: I32 or 1 :: I32, indicating whether signed
1670ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   overflow occurred for 32-bit addition.  Needs both args and the
1671ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   result.  HD p27. */
1672ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
1673ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownIRExpr* signed_overflow_after_Add32 ( IRExpr* resE,
1674ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                      IRTemp argL, IRTemp argR )
1675ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1676ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp res = newTemp(Ity_I32);
1677ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign(res, resE);
1678ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return
1679ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      binop( Iop_Shr32,
1680ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             binop( Iop_And32,
1681ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    binop( Iop_Xor32, mkexpr(res), mkexpr(argL) ),
1682ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    binop( Iop_Xor32, mkexpr(res), mkexpr(argR) )),
1683ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             mkU8(31) );
1684ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1685ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1686ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1687ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
1688ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- Larger helpers                                       ---*/
1689ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
1690ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1691ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Compute both the result and new C flag value for a LSL by an imm5
1692ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   or by a register operand.  May generate reads of the old C value
1693ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   (hence only safe to use before any writes to guest state happen).
1694ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Are factored out so can be used by both ARM and Thumb.
1695ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1696ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Note that in compute_result_and_C_after_{LSL,LSR,ASR}_by{imm5,reg},
1697ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   "res" (the result)  is a.k.a. "shop", shifter operand
1698ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   "newC" (the new C)  is a.k.a. "shco", shifter carry out
1699ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1700ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   The calling convention for res and newC is a bit funny.  They could
1701ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   be passed by value, but instead are passed by ref.
1702b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
1703b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   The C (shco) value computed must be zero in bits 31:1, as the IR
1704b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   optimisations for flag handling (guest_arm_spechelper) rely on
1705b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   that, and the slow-path handlers (armg_calculate_flags_nzcv) assert
1706b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   for it.  Same applies to all these functions that compute shco
1707b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   after a shift or rotate, not just this one.
1708ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
1709ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1710ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void compute_result_and_C_after_LSL_by_imm5 (
1711ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /*OUT*/HChar* buf,
1712ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRTemp* res,
1713ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRTemp* newC,
1714ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRTemp rMt, UInt shift_amt, /* operands */
1715ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               UInt rM      /* only for debug printing */
1716ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            )
1717ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1718ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (shift_amt == 0) {
1719ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (newC) {
1720ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( *newC, mk_armg_calculate_flag_c() );
1721ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
1722ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( *res, mkexpr(rMt) );
1723ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIS(buf, "r%u", rM);
1724ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
1725ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(shift_amt >= 1 && shift_amt <= 31);
1726ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (newC) {
1727ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( *newC,
1728ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 binop(Iop_And32,
1729ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       binop(Iop_Shr32, mkexpr(rMt),
1730ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                        mkU8(32 - shift_amt)),
1731ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       mkU32(1)));
1732ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
1733ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( *res,
1734ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              binop(Iop_Shl32, mkexpr(rMt), mkU8(shift_amt)) );
1735ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIS(buf, "r%u, LSL #%u", rM, shift_amt);
1736ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1737ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1738ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1739ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1740ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void compute_result_and_C_after_LSL_by_reg (
1741ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /*OUT*/HChar* buf,
1742ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRTemp* res,
1743ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRTemp* newC,
1744ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRTemp rMt, IRTemp rSt,  /* operands */
1745ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               UInt rM,    UInt rS      /* only for debug printing */
1746ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            )
1747ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1748ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // shift left in range 0 .. 255
1749ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // amt  = rS & 255
1750ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // res  = amt < 32 ?  Rm << amt  : 0
1751ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // newC = amt == 0     ? oldC  :
1752ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   //        amt in 1..32 ?  Rm[32-amt]  : 0
1753ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp amtT = newTemp(Ity_I32);
1754ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( amtT, binop(Iop_And32, mkexpr(rSt), mkU32(255)) );
1755ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (newC) {
1756ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* mux0X(amt == 0,
1757ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               mux0X(amt < 32,
1758ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     0,
1759b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                     Rm[(32-amt) & 31]),
1760ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               oldC)
1761ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      */
1762ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* About the best you can do is pray that iropt is able
1763ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         to nuke most or all of the following junk. */
1764ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp oldC = newTemp(Ity_I32);
1765ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(oldC, mk_armg_calculate_flag_c() );
1766ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(
1767ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         *newC,
1768ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRExpr_Mux0X(
1769ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            unop(Iop_1Uto8,
1770ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 binop(Iop_CmpEQ32, mkexpr(amtT), mkU32(0))),
1771ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            IRExpr_Mux0X(
1772ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               unop(Iop_1Uto8,
1773ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    binop(Iop_CmpLE32U, mkexpr(amtT), mkU32(32))),
1774ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               mkU32(0),
1775b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               binop(Iop_And32,
1776b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                     binop(Iop_Shr32,
1777b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                           mkexpr(rMt),
1778b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                           unop(Iop_32to8,
1779b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                                binop(Iop_And32,
1780b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                                      binop(Iop_Sub32,
1781b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                                            mkU32(32),
1782b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                                            mkexpr(amtT)),
1783b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                                      mkU32(31)
1784b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                                )
1785b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                           )
1786b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                     ),
1787b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                     mkU32(1)
1788ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               )
1789ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            ),
1790ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            mkexpr(oldC)
1791ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         )
1792ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      );
1793ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1794ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // (Rm << (Rs & 31))  &  (((Rs & 255) - 32) >>s 31)
1795ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Lhs of the & limits the shift to 31 bits, so as to
1796ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // give known IR semantics.  Rhs of the & is all 1s for
1797ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Rs <= 31 and all 0s for Rs >= 32.
1798ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign(
1799ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      *res,
1800ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      binop(
1801ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Iop_And32,
1802ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         binop(Iop_Shl32,
1803ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               mkexpr(rMt),
1804ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               unop(Iop_32to8,
1805ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    binop(Iop_And32, mkexpr(rSt), mkU32(31)))),
1806ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         binop(Iop_Sar32,
1807ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               binop(Iop_Sub32,
1808ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     mkexpr(amtT),
1809ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     mkU32(32)),
1810ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               mkU8(31))));
1811ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    DIS(buf, "r%u, LSL r%u", rM, rS);
1812ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1813ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1814ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1815ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void compute_result_and_C_after_LSR_by_imm5 (
1816ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /*OUT*/HChar* buf,
1817ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRTemp* res,
1818ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRTemp* newC,
1819ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRTemp rMt, UInt shift_amt, /* operands */
1820ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               UInt rM      /* only for debug printing */
1821ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            )
1822ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1823ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (shift_amt == 0) {
1824ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // conceptually a 32-bit shift, however:
1825ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // res  = 0
1826ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // newC = Rm[31]
1827ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (newC) {
1828ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( *newC,
1829ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 binop(Iop_And32,
1830ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       binop(Iop_Shr32, mkexpr(rMt), mkU8(31)),
1831ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       mkU32(1)));
1832ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
1833ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( *res, mkU32(0) );
1834ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIS(buf, "r%u, LSR #0(a.k.a. 32)", rM);
1835ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
1836ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // shift in range 1..31
1837ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // res  = Rm >>u shift_amt
1838ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // newC = Rm[shift_amt - 1]
1839ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(shift_amt >= 1 && shift_amt <= 31);
1840ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (newC) {
1841ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( *newC,
1842ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 binop(Iop_And32,
1843ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       binop(Iop_Shr32, mkexpr(rMt),
1844ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                        mkU8(shift_amt - 1)),
1845ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       mkU32(1)));
1846ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
1847ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( *res,
1848ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              binop(Iop_Shr32, mkexpr(rMt), mkU8(shift_amt)) );
1849ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIS(buf, "r%u, LSR #%u", rM, shift_amt);
1850ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1851ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1852ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1853ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1854ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void compute_result_and_C_after_LSR_by_reg (
1855ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /*OUT*/HChar* buf,
1856ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRTemp* res,
1857ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRTemp* newC,
1858ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRTemp rMt, IRTemp rSt,  /* operands */
1859ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               UInt rM,    UInt rS      /* only for debug printing */
1860ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            )
1861ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1862ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // shift right in range 0 .. 255
1863ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // amt = rS & 255
1864ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // res  = amt < 32 ?  Rm >>u amt  : 0
1865ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // newC = amt == 0     ? oldC  :
1866ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   //        amt in 1..32 ?  Rm[amt-1]  : 0
1867ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp amtT = newTemp(Ity_I32);
1868ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( amtT, binop(Iop_And32, mkexpr(rSt), mkU32(255)) );
1869ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (newC) {
1870ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* mux0X(amt == 0,
1871ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               mux0X(amt < 32,
1872ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     0,
1873b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                     Rm[(amt-1) & 31]),
1874ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               oldC)
1875ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      */
1876ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp oldC = newTemp(Ity_I32);
1877ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(oldC, mk_armg_calculate_flag_c() );
1878ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(
1879ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         *newC,
1880ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRExpr_Mux0X(
1881ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            unop(Iop_1Uto8,
1882ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 binop(Iop_CmpEQ32, mkexpr(amtT), mkU32(0))),
1883ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            IRExpr_Mux0X(
1884ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               unop(Iop_1Uto8,
1885ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    binop(Iop_CmpLE32U, mkexpr(amtT), mkU32(32))),
1886ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               mkU32(0),
1887b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               binop(Iop_And32,
1888b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                     binop(Iop_Shr32,
1889b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                           mkexpr(rMt),
1890b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                           unop(Iop_32to8,
1891b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                                binop(Iop_And32,
1892b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                                      binop(Iop_Sub32,
1893b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                                            mkexpr(amtT),
1894b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                                            mkU32(1)),
1895b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                                      mkU32(31)
1896b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                                )
1897b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                           )
1898b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                     ),
1899b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                     mkU32(1)
1900ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               )
1901ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            ),
1902ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            mkexpr(oldC)
1903ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         )
1904ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      );
1905ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1906ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // (Rm >>u (Rs & 31))  &  (((Rs & 255) - 32) >>s 31)
1907ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Lhs of the & limits the shift to 31 bits, so as to
1908ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // give known IR semantics.  Rhs of the & is all 1s for
1909ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Rs <= 31 and all 0s for Rs >= 32.
1910ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign(
1911ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      *res,
1912ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      binop(
1913ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Iop_And32,
1914ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         binop(Iop_Shr32,
1915ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               mkexpr(rMt),
1916ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               unop(Iop_32to8,
1917ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    binop(Iop_And32, mkexpr(rSt), mkU32(31)))),
1918ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         binop(Iop_Sar32,
1919ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               binop(Iop_Sub32,
1920ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     mkexpr(amtT),
1921ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     mkU32(32)),
1922ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               mkU8(31))));
1923ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    DIS(buf, "r%u, LSR r%u", rM, rS);
1924ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1925ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1926ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1927ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void compute_result_and_C_after_ASR_by_imm5 (
1928ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /*OUT*/HChar* buf,
1929ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRTemp* res,
1930ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRTemp* newC,
1931ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRTemp rMt, UInt shift_amt, /* operands */
1932ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               UInt rM      /* only for debug printing */
1933ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            )
1934ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1935ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (shift_amt == 0) {
1936ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // conceptually a 32-bit shift, however:
1937ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // res  = Rm >>s 31
1938ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // newC = Rm[31]
1939ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (newC) {
1940ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( *newC,
1941ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 binop(Iop_And32,
1942ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       binop(Iop_Shr32, mkexpr(rMt), mkU8(31)),
1943ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       mkU32(1)));
1944ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
1945ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( *res, binop(Iop_Sar32, mkexpr(rMt), mkU8(31)) );
1946ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIS(buf, "r%u, ASR #0(a.k.a. 32)", rM);
1947ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
1948ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // shift in range 1..31
1949ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // res = Rm >>s shift_amt
1950ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // newC = Rm[shift_amt - 1]
1951ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(shift_amt >= 1 && shift_amt <= 31);
1952ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (newC) {
1953ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( *newC,
1954ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 binop(Iop_And32,
1955ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       binop(Iop_Shr32, mkexpr(rMt),
1956ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                        mkU8(shift_amt - 1)),
1957ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       mkU32(1)));
1958ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
1959ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( *res,
1960ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              binop(Iop_Sar32, mkexpr(rMt), mkU8(shift_amt)) );
1961ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIS(buf, "r%u, ASR #%u", rM, shift_amt);
1962ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1963ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1964ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1965ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1966ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void compute_result_and_C_after_ASR_by_reg (
1967ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /*OUT*/HChar* buf,
1968ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRTemp* res,
1969ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRTemp* newC,
1970ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRTemp rMt, IRTemp rSt,  /* operands */
1971ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               UInt rM,    UInt rS      /* only for debug printing */
1972ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            )
1973ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1974ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // arithmetic shift right in range 0 .. 255
1975ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // amt = rS & 255
1976ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // res  = amt < 32 ?  Rm >>s amt  : Rm >>s 31
1977ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // newC = amt == 0     ? oldC  :
1978ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   //        amt in 1..32 ?  Rm[amt-1]  : Rm[31]
1979ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp amtT = newTemp(Ity_I32);
1980ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( amtT, binop(Iop_And32, mkexpr(rSt), mkU32(255)) );
1981ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (newC) {
1982ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* mux0X(amt == 0,
1983ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               mux0X(amt < 32,
1984ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     Rm[31],
1985ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     Rm[(amt-1) & 31])
1986ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               oldC)
1987ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      */
1988ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp oldC = newTemp(Ity_I32);
1989ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(oldC, mk_armg_calculate_flag_c() );
1990ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(
1991ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         *newC,
1992ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRExpr_Mux0X(
1993ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            unop(Iop_1Uto8,
1994ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 binop(Iop_CmpEQ32, mkexpr(amtT), mkU32(0))),
1995ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            IRExpr_Mux0X(
1996ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               unop(Iop_1Uto8,
1997ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    binop(Iop_CmpLE32U, mkexpr(amtT), mkU32(32))),
1998b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               binop(Iop_And32,
1999b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                     binop(Iop_Shr32,
2000b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                           mkexpr(rMt),
2001b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                           mkU8(31)
2002b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                     ),
2003b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                     mkU32(1)
2004ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               ),
2005b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               binop(Iop_And32,
2006b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                     binop(Iop_Shr32,
2007b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                           mkexpr(rMt),
2008b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                           unop(Iop_32to8,
2009b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                                binop(Iop_And32,
2010b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                                      binop(Iop_Sub32,
2011b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                                            mkexpr(amtT),
2012b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                                            mkU32(1)),
2013b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                                      mkU32(31)
2014b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                                )
2015b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                           )
2016b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                     ),
2017b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                     mkU32(1)
2018ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               )
2019ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            ),
2020ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            mkexpr(oldC)
2021ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         )
2022ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      );
2023ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2024ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // (Rm >>s (amt <u 32 ? amt : 31))
2025ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign(
2026ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      *res,
2027ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      binop(
2028ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Iop_Sar32,
2029ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         mkexpr(rMt),
2030ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         unop(
2031ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            Iop_32to8,
2032ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            IRExpr_Mux0X(
2033ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               unop(
2034ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 Iop_1Uto8,
2035ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 binop(Iop_CmpLT32U, mkexpr(amtT), mkU32(32))),
2036ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               mkU32(31),
2037ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               mkexpr(amtT)))));
2038ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    DIS(buf, "r%u, ASR r%u", rM, rS);
2039ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
2040ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2041ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2042ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void compute_result_and_C_after_ROR_by_reg (
2043ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /*OUT*/HChar* buf,
2044ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRTemp* res,
2045ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRTemp* newC,
2046ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRTemp rMt, IRTemp rSt,  /* operands */
2047ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               UInt rM,    UInt rS      /* only for debug printing */
2048ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            )
2049ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
2050ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // rotate right in range 0 .. 255
2051ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // amt = rS & 255
2052ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // shop =  Rm `ror` (amt & 31)
2053ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // shco =  amt == 0 ? oldC : Rm[(amt-1) & 31]
2054ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp amtT = newTemp(Ity_I32);
2055ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( amtT, binop(Iop_And32, mkexpr(rSt), mkU32(255)) );
2056ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp amt5T = newTemp(Ity_I32);
2057ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( amt5T, binop(Iop_And32, mkexpr(rSt), mkU32(31)) );
2058ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp oldC = newTemp(Ity_I32);
2059ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign(oldC, mk_armg_calculate_flag_c() );
2060ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (newC) {
2061ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(
2062ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         *newC,
2063ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRExpr_Mux0X(
2064ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            unop(Iop_32to8, mkexpr(amtT)),
2065ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            mkexpr(oldC),
2066ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            binop(Iop_And32,
2067ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  binop(Iop_Shr32,
2068ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        mkexpr(rMt),
2069ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        unop(Iop_32to8,
2070ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             binop(Iop_And32,
2071ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   binop(Iop_Sub32,
2072ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                         mkexpr(amtT),
2073ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                         mkU32(1)
2074ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   ),
2075ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   mkU32(31)
2076ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             )
2077ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        )
2078ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  ),
2079ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  mkU32(1)
2080ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            )
2081ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         )
2082ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      );
2083ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2084ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign(
2085ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      *res,
2086ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRExpr_Mux0X(
2087ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         unop(Iop_32to8, mkexpr(amt5T)), mkexpr(rMt),
2088ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         binop(Iop_Or32,
2089ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               binop(Iop_Shr32,
2090ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     mkexpr(rMt),
2091ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     unop(Iop_32to8, mkexpr(amt5T))
2092ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               ),
2093ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               binop(Iop_Shl32,
2094ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     mkexpr(rMt),
2095ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     unop(Iop_32to8,
2096ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          binop(Iop_Sub32, mkU32(32), mkexpr(amt5T))
2097ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     )
2098ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               )
2099ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         )
2100ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      )
2101ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   );
2102ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DIS(buf, "r%u, ROR r#%u", rM, rS);
2103ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
2104ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2105ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2106ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Generate an expression corresponding to the immediate-shift case of
2107ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   a shifter operand.  This is used both for ARM and Thumb2.
2108ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2109ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Bind it to a temporary, and return that via *res.  If newC is
2110ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   non-NULL, also compute a value for the shifter's carry out (in the
2111ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   LSB of a word), bind it to a temporary, and return that via *shco.
2112ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2113ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Generates GETs from the guest state and is therefore not safe to
2114ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   use once we start doing PUTs to it, for any given instruction.
2115ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2116ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   'how' is encoded thusly:
2117ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      00b LSL,  01b LSR,  10b ASR,  11b ROR
2118ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Most but not all ARM and Thumb integer insns use this encoding.
2119ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Be careful to ensure the right value is passed here.
2120ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
2121ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void compute_result_and_C_after_shift_by_imm5 (
2122ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /*OUT*/HChar* buf,
2123ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /*OUT*/IRTemp* res,
2124ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /*OUT*/IRTemp* newC,
2125ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRTemp  rMt,       /* reg to shift */
2126ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               UInt    how,       /* what kind of shift */
2127ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               UInt    shift_amt, /* shift amount (0..31) */
2128ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               UInt    rM         /* only for debug printing */
2129ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            )
2130ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
2131ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(shift_amt < 32);
2132ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(how < 4);
2133ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2134ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (how) {
2135ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2136ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0:
2137ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         compute_result_and_C_after_LSL_by_imm5(
2138ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            buf, res, newC, rMt, shift_amt, rM
2139ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         );
2140ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
2141ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2142ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 1:
2143ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         compute_result_and_C_after_LSR_by_imm5(
2144ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            buf, res, newC, rMt, shift_amt, rM
2145ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         );
2146ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
2147ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2148ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 2:
2149ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         compute_result_and_C_after_ASR_by_imm5(
2150ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            buf, res, newC, rMt, shift_amt, rM
2151ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         );
2152ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
2153ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2154ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 3:
2155ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (shift_amt == 0) {
2156ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            IRTemp oldcT = newTemp(Ity_I32);
2157ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            // rotate right 1 bit through carry (?)
2158ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            // RRX -- described at ARM ARM A5-17
2159ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            // res  = (oldC << 31) | (Rm >>u 1)
2160ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            // newC = Rm[0]
2161ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (newC) {
2162ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign( *newC,
2163ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       binop(Iop_And32, mkexpr(rMt), mkU32(1)));
2164ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
2165ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign( oldcT, mk_armg_calculate_flag_c() );
2166ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign( *res,
2167ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    binop(Iop_Or32,
2168ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          binop(Iop_Shl32, mkexpr(oldcT), mkU8(31)),
2169ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          binop(Iop_Shr32, mkexpr(rMt), mkU8(1))) );
2170ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIS(buf, "r%u, RRX", rM);
2171ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
2172ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            // rotate right in range 1..31
2173ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            // res  = Rm `ror` shift_amt
2174ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            // newC = Rm[shift_amt - 1]
2175ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            vassert(shift_amt >= 1 && shift_amt <= 31);
2176ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (newC) {
2177ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign( *newC,
2178ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       binop(Iop_And32,
2179ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             binop(Iop_Shr32, mkexpr(rMt),
2180ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                              mkU8(shift_amt - 1)),
2181ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             mkU32(1)));
2182ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
2183ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign( *res,
2184ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    binop(Iop_Or32,
2185ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          binop(Iop_Shr32, mkexpr(rMt), mkU8(shift_amt)),
2186ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          binop(Iop_Shl32, mkexpr(rMt),
2187ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                           mkU8(32-shift_amt))));
2188ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIS(buf, "r%u, ROR #%u", rM, shift_amt);
2189ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
2190ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
2191ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2192ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default:
2193ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /*NOTREACHED*/
2194ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vassert(0);
2195ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2196ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
2197ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2198ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2199ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Generate an expression corresponding to the register-shift case of
2200ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   a shifter operand.  This is used both for ARM and Thumb2.
2201ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2202ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Bind it to a temporary, and return that via *res.  If newC is
2203ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   non-NULL, also compute a value for the shifter's carry out (in the
2204ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   LSB of a word), bind it to a temporary, and return that via *shco.
2205ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2206ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Generates GETs from the guest state and is therefore not safe to
2207ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   use once we start doing PUTs to it, for any given instruction.
2208ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2209ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   'how' is encoded thusly:
2210ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      00b LSL,  01b LSR,  10b ASR,  11b ROR
2211ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Most but not all ARM and Thumb integer insns use this encoding.
2212ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Be careful to ensure the right value is passed here.
2213ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
2214ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void compute_result_and_C_after_shift_by_reg (
2215ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /*OUT*/HChar*  buf,
2216ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /*OUT*/IRTemp* res,
2217ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /*OUT*/IRTemp* newC,
2218ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRTemp  rMt,       /* reg to shift */
2219ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               UInt    how,       /* what kind of shift */
2220ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRTemp  rSt,       /* shift amount */
2221ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               UInt    rM,        /* only for debug printing */
2222ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               UInt    rS         /* only for debug printing */
2223ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            )
2224ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
2225ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(how < 4);
2226ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (how) {
2227ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0: { /* LSL */
2228ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         compute_result_and_C_after_LSL_by_reg(
2229ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            buf, res, newC, rMt, rSt, rM, rS
2230ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         );
2231ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
2232ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
2233ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 1: { /* LSR */
2234ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         compute_result_and_C_after_LSR_by_reg(
2235ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            buf, res, newC, rMt, rSt, rM, rS
2236ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         );
2237ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
2238ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
2239ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 2: { /* ASR */
2240ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         compute_result_and_C_after_ASR_by_reg(
2241ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            buf, res, newC, rMt, rSt, rM, rS
2242ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         );
2243ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
2244ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
2245ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 3: { /* ROR */
2246ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         compute_result_and_C_after_ROR_by_reg(
2247ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             buf, res, newC, rMt, rSt, rM, rS
2248ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         );
2249ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
2250ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
2251ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default:
2252ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /*NOTREACHED*/
2253ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vassert(0);
2254ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2255ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
2256ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2257ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2258ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Generate an expression corresponding to a shifter_operand, bind it
2259ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   to a temporary, and return that via *shop.  If shco is non-NULL,
2260ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   also compute a value for the shifter's carry out (in the LSB of a
2261ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   word), bind it to a temporary, and return that via *shco.
2262ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2263ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   If for some reason we can't come up with a shifter operand (missing
2264ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case?  not really a shifter operand?) return False.
2265ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2266ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Generates GETs from the guest state and is therefore not safe to
2267ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   use once we start doing PUTs to it, for any given instruction.
2268ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2269ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   For ARM insns only; not for Thumb.
2270ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
2271ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Bool mk_shifter_operand ( UInt insn_25, UInt insn_11_0,
2272ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 /*OUT*/IRTemp* shop,
2273ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 /*OUT*/IRTemp* shco,
2274ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 /*OUT*/HChar* buf )
2275ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
2276ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt insn_4 = (insn_11_0 >> 4) & 1;
2277ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt insn_7 = (insn_11_0 >> 7) & 1;
2278ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(insn_25 <= 0x1);
2279ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(insn_11_0 <= 0xFFF);
2280ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2281ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(shop && *shop == IRTemp_INVALID);
2282ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   *shop = newTemp(Ity_I32);
2283ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2284ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (shco) {
2285ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(*shco == IRTemp_INVALID);
2286ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      *shco = newTemp(Ity_I32);
2287ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2288ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2289ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 32-bit immediate */
2290ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2291ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (insn_25 == 1) {
2292ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* immediate: (7:0) rotated right by 2 * (11:8) */
2293ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt imm = (insn_11_0 >> 0) & 0xFF;
2294ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rot = 2 * ((insn_11_0 >> 8) & 0xF);
2295ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(rot <= 30);
2296ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      imm = ROR32(imm, rot);
2297ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (shco) {
2298ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (rot == 0) {
2299ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign( *shco, mk_armg_calculate_flag_c() );
2300ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
2301ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign( *shco, mkU32( (imm >> 31) & 1 ) );
2302ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
2303ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
2304ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIS(buf, "#0x%x", imm);
2305ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( *shop, mkU32(imm) );
2306ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return True;
2307ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2308ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2309ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Shift/rotate by immediate */
2310ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2311ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (insn_25 == 0 && insn_4 == 0) {
2312ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Rm (3:0) shifted (6:5) by immediate (11:7) */
2313ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt shift_amt = (insn_11_0 >> 7) & 0x1F;
2314ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rM        = (insn_11_0 >> 0) & 0xF;
2315ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt how       = (insn_11_0 >> 5) & 3;
2316ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* how: 00 = Shl, 01 = Shr, 10 = Sar, 11 = Ror */
2317ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp rMt = newTemp(Ity_I32);
2318ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(rMt, getIRegA(rM));
2319ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2320ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(shift_amt <= 31);
2321ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2322ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      compute_result_and_C_after_shift_by_imm5(
2323ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         buf, shop, shco, rMt, how, shift_amt, rM
2324ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      );
2325ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return True;
2326ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2327ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2328ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Shift/rotate by register */
2329ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (insn_25 == 0 && insn_4 == 1) {
2330ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Rm (3:0) shifted (6:5) by Rs (11:8) */
2331ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rM  = (insn_11_0 >> 0) & 0xF;
2332ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rS  = (insn_11_0 >> 8) & 0xF;
2333ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt how = (insn_11_0 >> 5) & 3;
2334ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* how: 00 = Shl, 01 = Shr, 10 = Sar, 11 = Ror */
2335ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp rMt = newTemp(Ity_I32);
2336ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp rSt = newTemp(Ity_I32);
2337ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2338ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (insn_7 == 1)
2339ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         return False; /* not really a shifter operand */
2340ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2341ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(rMt, getIRegA(rM));
2342ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(rSt, getIRegA(rS));
2343ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2344ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      compute_result_and_C_after_shift_by_reg(
2345ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         buf, shop, shco, rMt, how, rSt, rM, rS
2346ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      );
2347ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return True;
2348ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2349ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2350ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vex_printf("mk_shifter_operand(0x%x,0x%x)\n", insn_25, insn_11_0 );
2351ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return False;
2352ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
2353ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2354ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2355ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* ARM only */
2356ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
2357ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownIRExpr* mk_EA_reg_plusminus_imm12 ( UInt rN, UInt bU, UInt imm12,
2358ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    /*OUT*/HChar* buf )
2359ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
2360ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(rN < 16);
2361ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(bU < 2);
2362ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(imm12 < 0x1000);
2363ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UChar opChar = bU == 1 ? '+' : '-';
2364ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DIS(buf, "[r%u, #%c%u]", rN, opChar, imm12);
2365ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return
2366ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      binop( (bU == 1 ? Iop_Add32 : Iop_Sub32),
2367ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             getIRegA(rN),
2368ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             mkU32(imm12) );
2369ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
2370ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2371ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2372ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* ARM only.
2373ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   NB: This is "DecodeImmShift" in newer versions of the the ARM ARM.
2374ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
2375ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
2376ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownIRExpr* mk_EA_reg_plusminus_shifted_reg ( UInt rN, UInt bU, UInt rM,
2377ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                          UInt sh2, UInt imm5,
2378ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                          /*OUT*/HChar* buf )
2379ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
2380ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(rN < 16);
2381ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(bU < 2);
2382ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(rM < 16);
2383ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(sh2 < 4);
2384ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(imm5 < 32);
2385ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UChar   opChar = bU == 1 ? '+' : '-';
2386ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRExpr* index  = NULL;
2387ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (sh2) {
2388ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0: /* LSL */
2389ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* imm5 can be in the range 0 .. 31 inclusive. */
2390ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         index = binop(Iop_Shl32, getIRegA(rM), mkU8(imm5));
2391ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIS(buf, "[r%u, %c r%u LSL #%u]", rN, opChar, rM, imm5);
2392ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
2393ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 1: /* LSR */
2394ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (imm5 == 0) {
2395ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            index = mkU32(0);
2396ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            vassert(0); // ATC
2397ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
2398ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            index = binop(Iop_Shr32, getIRegA(rM), mkU8(imm5));
2399ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
2400ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIS(buf, "[r%u, %cr%u, LSR #%u]",
2401ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  rN, opChar, rM, imm5 == 0 ? 32 : imm5);
2402ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
2403ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 2: /* ASR */
2404ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Doesn't this just mean that the behaviour with imm5 == 0
2405ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            is the same as if it had been 31 ? */
2406ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (imm5 == 0) {
2407ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            index = binop(Iop_Sar32, getIRegA(rM), mkU8(31));
2408ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            vassert(0); // ATC
2409ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
2410ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            index = binop(Iop_Sar32, getIRegA(rM), mkU8(imm5));
2411ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
2412ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIS(buf, "[r%u, %cr%u, ASR #%u]",
2413ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  rN, opChar, rM, imm5 == 0 ? 32 : imm5);
2414ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
2415ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 3: /* ROR or RRX */
2416ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (imm5 == 0) {
2417ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            IRTemp rmT    = newTemp(Ity_I32);
2418ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            IRTemp cflagT = newTemp(Ity_I32);
2419ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(rmT, getIRegA(rM));
2420ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(cflagT, mk_armg_calculate_flag_c());
2421ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            index = binop(Iop_Or32,
2422ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          binop(Iop_Shl32, mkexpr(cflagT), mkU8(31)),
2423ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          binop(Iop_Shr32, mkexpr(rmT), mkU8(1)));
2424ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIS(buf, "[r%u, %cr%u, RRX]", rN, opChar, rM);
2425ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
2426ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            IRTemp rmT = newTemp(Ity_I32);
2427ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(rmT, getIRegA(rM));
2428ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            vassert(imm5 >= 1 && imm5 <= 31);
2429ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            index = binop(Iop_Or32,
2430ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          binop(Iop_Shl32, mkexpr(rmT), mkU8(32-imm5)),
2431ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          binop(Iop_Shr32, mkexpr(rmT), mkU8(imm5)));
2432ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIS(buf, "[r%u, %cr%u, ROR #%u]", rN, opChar, rM, imm5);
2433ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
2434ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
2435ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default:
2436ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vassert(0);
2437ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2438ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(index);
2439ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return binop(bU == 1 ? Iop_Add32 : Iop_Sub32,
2440ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                getIRegA(rN), index);
2441ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
2442ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2443ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2444ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* ARM only */
2445ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
2446ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownIRExpr* mk_EA_reg_plusminus_imm8 ( UInt rN, UInt bU, UInt imm8,
2447ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   /*OUT*/HChar* buf )
2448ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
2449ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(rN < 16);
2450ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(bU < 2);
2451ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(imm8 < 0x100);
2452ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UChar opChar = bU == 1 ? '+' : '-';
2453ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DIS(buf, "[r%u, #%c%u]", rN, opChar, imm8);
2454ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return
2455ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      binop( (bU == 1 ? Iop_Add32 : Iop_Sub32),
2456ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             getIRegA(rN),
2457ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             mkU32(imm8) );
2458ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
2459ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2460ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2461ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* ARM only */
2462ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
2463ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownIRExpr* mk_EA_reg_plusminus_reg ( UInt rN, UInt bU, UInt rM,
2464ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  /*OUT*/HChar* buf )
2465ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
2466ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(rN < 16);
2467ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(bU < 2);
2468ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(rM < 16);
2469ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UChar   opChar = bU == 1 ? '+' : '-';
2470ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRExpr* index  = getIRegA(rM);
2471ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DIS(buf, "[r%u, %c r%u]", rN, opChar, rM);
2472ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return binop(bU == 1 ? Iop_Add32 : Iop_Sub32,
2473ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                getIRegA(rN), index);
2474ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
2475ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2476ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2477ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* irRes :: Ity_I32 holds a floating point comparison result encoded
2478ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   as an IRCmpF64Result.  Generate code to convert it to an
2479ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ARM-encoded (N,Z,C,V) group in the lowest 4 bits of an I32 value.
2480ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Assign a new temp to hold that value, and return the temp. */
2481ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
2482ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownIRTemp mk_convert_IRCmpF64Result_to_NZCV ( IRTemp irRes )
2483ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
2484ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp ix       = newTemp(Ity_I32);
2485ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp termL    = newTemp(Ity_I32);
2486ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp termR    = newTemp(Ity_I32);
2487ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp nzcv     = newTemp(Ity_I32);
2488ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2489ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* This is where the fun starts.  We have to convert 'irRes' from
2490ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      an IR-convention return result (IRCmpF64Result) to an
2491ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ARM-encoded (N,Z,C,V) group.  The final result is in the bottom
2492ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      4 bits of 'nzcv'. */
2493ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Map compare result from IR to ARM(nzcv) */
2494ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /*
2495ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      FP cmp result | IR   | ARM(nzcv)
2496ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      --------------------------------
2497ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UN              0x45   0011
2498ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      LT              0x01   1000
2499ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      GT              0x00   0010
2500ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      EQ              0x40   0110
2501ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   */
2502ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Now since you're probably wondering WTF ..
2503ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2504ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ix fishes the useful bits out of the IR value, bits 6 and 0, and
2505ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      places them side by side, giving a number which is 0, 1, 2 or 3.
2506ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2507ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      termL is a sequence cooked up by GNU superopt.  It converts ix
2508ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         into an almost correct value NZCV value (incredibly), except
2509ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         for the case of UN, where it produces 0100 instead of the
2510ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         required 0011.
2511ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2512ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      termR is therefore a correction term, also computed from ix.  It
2513ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         is 1 in the UN case and 0 for LT, GT and UN.  Hence, to get
2514ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         the final correct value, we subtract termR from termL.
2515ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2516ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Don't take my word for it.  There's a test program at the bottom
2517ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      of this file, to try this out with.
2518ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   */
2519ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign(
2520ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ix,
2521ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      binop(Iop_Or32,
2522ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            binop(Iop_And32,
2523ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  binop(Iop_Shr32, mkexpr(irRes), mkU8(5)),
2524ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  mkU32(3)),
2525ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            binop(Iop_And32, mkexpr(irRes), mkU32(1))));
2526ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2527ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign(
2528ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      termL,
2529ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      binop(Iop_Add32,
2530ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            binop(Iop_Shr32,
2531ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  binop(Iop_Sub32,
2532ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        binop(Iop_Shl32,
2533ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              binop(Iop_Xor32, mkexpr(ix), mkU32(1)),
2534ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              mkU8(30)),
2535ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        mkU32(1)),
2536ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  mkU8(29)),
2537ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            mkU32(1)));
2538ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2539ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign(
2540ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      termR,
2541ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      binop(Iop_And32,
2542ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            binop(Iop_And32,
2543ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  mkexpr(ix),
2544ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  binop(Iop_Shr32, mkexpr(ix), mkU8(1))),
2545ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            mkU32(1)));
2546ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2547ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign(nzcv, binop(Iop_Sub32, mkexpr(termL), mkexpr(termR)));
2548ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return nzcv;
2549ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
2550ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2551ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2552ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Thumb32 only.  This is "ThumbExpandImm" in the ARM ARM.  If
2553ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   updatesC is non-NULL, a boolean is written to it indicating whether
2554ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   or not the C flag is updated, as per ARM ARM "ThumbExpandImm_C".
2555ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
2556ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic UInt thumbExpandImm ( Bool* updatesC,
2557ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             UInt imm1, UInt imm3, UInt imm8 )
2558ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
2559ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(imm1 < (1<<1));
2560ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(imm3 < (1<<3));
2561ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(imm8 < (1<<8));
2562ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt i_imm3_a = (imm1 << 4) | (imm3 << 1) | ((imm8 >> 7) & 1);
2563ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt abcdefgh = imm8;
2564ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt lbcdefgh = imm8 | 0x80;
2565ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (updatesC) {
2566ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      *updatesC = i_imm3_a >= 8;
2567ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2568ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (i_imm3_a) {
2569ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0: case 1:
2570ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         return abcdefgh;
2571ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 2: case 3:
2572ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         return (abcdefgh << 16) | abcdefgh;
2573ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 4: case 5:
2574ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         return (abcdefgh << 24) | (abcdefgh << 8);
2575ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 6: case 7:
2576ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         return (abcdefgh << 24) | (abcdefgh << 16)
2577ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                | (abcdefgh << 8) | abcdefgh;
2578ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 8 ... 31:
2579ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         return lbcdefgh << (32 - i_imm3_a);
2580ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default:
2581ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
2582ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2583ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /*NOTREACHED*/vassert(0);
2584ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
2585ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2586ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2587ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Version of thumbExpandImm where we simply feed it the
2588ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   instruction halfwords (the lowest addressed one is I0). */
2589ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic UInt thumbExpandImm_from_I0_I1 ( Bool* updatesC,
2590ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                        UShort i0s, UShort i1s )
2591ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
2592ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt i0    = (UInt)i0s;
2593ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt i1    = (UInt)i1s;
2594ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt imm1  = SLICE_UInt(i0,10,10);
2595ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt imm3  = SLICE_UInt(i1,14,12);
2596ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt imm8  = SLICE_UInt(i1,7,0);
2597ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return thumbExpandImm(updatesC, imm1, imm3, imm8);
2598ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
2599ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2600ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2601ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Thumb16 only.  Given the firstcond and mask fields from an IT
2602ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   instruction, compute the 32-bit ITSTATE value implied, as described
2603ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   in libvex_guest_arm.h.  This is not the ARM ARM representation.
2604ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Also produce the t/e chars for the 2nd, 3rd, 4th insns, for
2605ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   disassembly printing.  Returns False if firstcond or mask
2606ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   denote something invalid.
2607ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2608ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   The number and conditions for the instructions to be
2609ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   conditionalised depend on firstcond and mask:
2610ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2611ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   mask      cond 1    cond 2      cond 3      cond 4
2612ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2613ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   1000      fc[3:0]
2614ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   x100      fc[3:0]   fc[3:1]:x
2615ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   xy10      fc[3:0]   fc[3:1]:x   fc[3:1]:y
2616ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   xyz1      fc[3:0]   fc[3:1]:x   fc[3:1]:y   fc[3:1]:z
2617ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2618ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   The condition fields are assembled in *itstate backwards (cond 4 at
2619ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   the top, cond 1 at the bottom).  Conditions are << 4'd and then
2620ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ^0xE'd, and those fields that correspond to instructions in the IT
2621ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   block are tagged with a 1 bit.
2622ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
2623ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Bool compute_ITSTATE ( /*OUT*/UInt*  itstate,
2624ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              /*OUT*/UChar* ch1,
2625ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              /*OUT*/UChar* ch2,
2626ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              /*OUT*/UChar* ch3,
2627ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              UInt firstcond, UInt mask )
2628ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
2629ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(firstcond <= 0xF);
2630ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(mask <= 0xF);
2631ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   *itstate = 0;
2632ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   *ch1 = *ch2 = *ch3 = '.';
2633ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (mask == 0)
2634ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return False; /* the logic below actually ensures this anyway,
2635ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       but clearer to make it explicit. */
2636ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (firstcond == 0xF)
2637ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return False; /* NV is not allowed */
2638ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (firstcond == 0xE && popcount32(mask) != 1)
2639ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return False; /* if firstcond is AL then all the rest must be too */
2640ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2641ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt m3 = (mask >> 3) & 1;
2642ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt m2 = (mask >> 2) & 1;
2643ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt m1 = (mask >> 1) & 1;
2644ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt m0 = (mask >> 0) & 1;
2645ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2646ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt fc = (firstcond << 4) | 1/*in-IT-block*/;
2647ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt ni = (0xE/*AL*/ << 4) | 0/*not-in-IT-block*/;
2648ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2649ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (m3 == 1 && (m2|m1|m0) == 0) {
2650ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      *itstate = (ni << 24) | (ni << 16) | (ni << 8) | fc;
2651ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      *itstate ^= 0xE0E0E0E0;
2652ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return True;
2653ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2654ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2655ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (m2 == 1 && (m1|m0) == 0) {
2656ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      *itstate = (ni << 24) | (ni << 16) | (setbit32(fc, 4, m3) << 8) | fc;
2657ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      *itstate ^= 0xE0E0E0E0;
2658ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      *ch1 = m3 == (firstcond & 1) ? 't' : 'e';
2659ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return True;
2660ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2661ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2662ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (m1 == 1 && m0 == 0) {
2663ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      *itstate = (ni << 24)
2664ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 | (setbit32(fc, 4, m2) << 16)
2665ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 | (setbit32(fc, 4, m3) << 8) | fc;
2666ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      *itstate ^= 0xE0E0E0E0;
2667ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      *ch1 = m3 == (firstcond & 1) ? 't' : 'e';
2668ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      *ch2 = m2 == (firstcond & 1) ? 't' : 'e';
2669ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return True;
2670ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2671ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2672ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (m0 == 1) {
2673ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      *itstate = (setbit32(fc, 4, m1) << 24)
2674ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 | (setbit32(fc, 4, m2) << 16)
2675ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 | (setbit32(fc, 4, m3) << 8) | fc;
2676ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      *itstate ^= 0xE0E0E0E0;
2677ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      *ch1 = m3 == (firstcond & 1) ? 't' : 'e';
2678ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      *ch2 = m2 == (firstcond & 1) ? 't' : 'e';
2679ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      *ch3 = m1 == (firstcond & 1) ? 't' : 'e';
2680ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return True;
2681ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2682ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2683ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return False;
2684ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
2685ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2686ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2687ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Generate IR to do 32-bit bit reversal, a la Hacker's Delight
2688ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Chapter 7 Section 1. */
2689ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRTemp gen_BITREV ( IRTemp x0 )
2690ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
2691ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp x1 = newTemp(Ity_I32);
2692ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp x2 = newTemp(Ity_I32);
2693ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp x3 = newTemp(Ity_I32);
2694ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp x4 = newTemp(Ity_I32);
2695ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp x5 = newTemp(Ity_I32);
2696ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt   c1 = 0x55555555;
2697ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt   c2 = 0x33333333;
2698ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt   c3 = 0x0F0F0F0F;
2699ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt   c4 = 0x00FF00FF;
2700ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt   c5 = 0x0000FFFF;
2701ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign(x1,
2702ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          binop(Iop_Or32,
2703ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                binop(Iop_Shl32,
2704ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      binop(Iop_And32, mkexpr(x0), mkU32(c1)),
2705ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      mkU8(1)),
2706ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                binop(Iop_Shr32,
2707ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      binop(Iop_And32, mkexpr(x0), mkU32(~c1)),
2708ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      mkU8(1))
2709ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ));
2710ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign(x2,
2711ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          binop(Iop_Or32,
2712ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                binop(Iop_Shl32,
2713ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      binop(Iop_And32, mkexpr(x1), mkU32(c2)),
2714ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      mkU8(2)),
2715ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                binop(Iop_Shr32,
2716ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      binop(Iop_And32, mkexpr(x1), mkU32(~c2)),
2717ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      mkU8(2))
2718ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ));
2719ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign(x3,
2720ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          binop(Iop_Or32,
2721ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                binop(Iop_Shl32,
2722ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      binop(Iop_And32, mkexpr(x2), mkU32(c3)),
2723ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      mkU8(4)),
2724ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                binop(Iop_Shr32,
2725ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      binop(Iop_And32, mkexpr(x2), mkU32(~c3)),
2726ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      mkU8(4))
2727ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ));
2728ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign(x4,
2729ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          binop(Iop_Or32,
2730ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                binop(Iop_Shl32,
2731ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      binop(Iop_And32, mkexpr(x3), mkU32(c4)),
2732ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      mkU8(8)),
2733ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                binop(Iop_Shr32,
2734ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      binop(Iop_And32, mkexpr(x3), mkU32(~c4)),
2735ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      mkU8(8))
2736ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ));
2737ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign(x5,
2738ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          binop(Iop_Or32,
2739ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                binop(Iop_Shl32,
2740ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      binop(Iop_And32, mkexpr(x4), mkU32(c5)),
2741ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      mkU8(16)),
2742ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                binop(Iop_Shr32,
2743ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      binop(Iop_And32, mkexpr(x4), mkU32(~c5)),
2744ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      mkU8(16))
2745ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ));
2746ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return x5;
2747ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
2748ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2749ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2750ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Generate IR to do rearrange bytes 3:2:1:0 in a word in to the order
2751ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   0:1:2:3 (aka byte-swap). */
2752ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRTemp gen_REV ( IRTemp arg )
2753ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
2754ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp res = newTemp(Ity_I32);
2755ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign(res,
2756ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          binop(Iop_Or32,
2757ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                binop(Iop_Shl32, mkexpr(arg), mkU8(24)),
2758ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          binop(Iop_Or32,
2759ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                binop(Iop_And32, binop(Iop_Shl32, mkexpr(arg), mkU8(8)),
2760ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 mkU32(0x00FF0000)),
2761ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          binop(Iop_Or32,
2762ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                binop(Iop_And32, binop(Iop_Shr32, mkexpr(arg), mkU8(8)),
2763ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                       mkU32(0x0000FF00)),
2764ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                binop(Iop_And32, binop(Iop_Shr32, mkexpr(arg), mkU8(24)),
2765ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                       mkU32(0x000000FF) )
2766ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ))));
2767ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return res;
2768ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
2769ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2770ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2771ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Generate IR to do rearrange bytes 3:2:1:0 in a word in to the order
2772ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   2:3:0:1 (swap within lo and hi halves). */
2773ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRTemp gen_REV16 ( IRTemp arg )
2774ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
2775ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp res = newTemp(Ity_I32);
2776ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign(res,
2777ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          binop(Iop_Or32,
2778ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                binop(Iop_And32,
2779ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      binop(Iop_Shl32, mkexpr(arg), mkU8(8)),
2780ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      mkU32(0xFF00FF00)),
2781ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                binop(Iop_And32,
2782ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      binop(Iop_Shr32, mkexpr(arg), mkU8(8)),
2783ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      mkU32(0x00FF00FF))));
2784ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return res;
2785ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
2786ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2787ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2788ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
2789ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- Advanced SIMD (NEON) instructions                    ---*/
2790ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
2791ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2792ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
2793ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- NEON data processing                                 ---*/
2794ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
2795ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2796ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* For all NEON DP ops, we use the normal scheme to handle conditional
2797ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   writes to registers -- pass in condT and hand that on to the
2798ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   put*Reg functions.  In ARM mode condT is always IRTemp_INVALID
2799ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   since NEON is unconditional for ARM.  In Thumb mode condT is
2800ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   derived from the ITSTATE shift register in the normal way. */
2801ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2802ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
2803ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownUInt get_neon_d_regno(UInt theInstr)
2804ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
2805ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt x = ((theInstr >> 18) & 0x10) | ((theInstr >> 12) & 0xF);
2806ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (theInstr & 0x40) {
2807ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (x & 1) {
2808ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         x = x + 0x100;
2809ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
2810ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         x = x >> 1;
2811ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
2812ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2813ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return x;
2814ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
2815ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2816ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
2817ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownUInt get_neon_n_regno(UInt theInstr)
2818ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
2819ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt x = ((theInstr >> 3) & 0x10) | ((theInstr >> 16) & 0xF);
2820ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (theInstr & 0x40) {
2821ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (x & 1) {
2822ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         x = x + 0x100;
2823ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
2824ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         x = x >> 1;
2825ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
2826ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2827ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return x;
2828ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
2829ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2830ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
2831ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownUInt get_neon_m_regno(UInt theInstr)
2832ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
2833ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt x = ((theInstr >> 1) & 0x10) | (theInstr & 0xF);
2834ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (theInstr & 0x40) {
2835ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (x & 1) {
2836ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         x = x + 0x100;
2837ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
2838ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         x = x >> 1;
2839ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
2840ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2841ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return x;
2842ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
2843ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2844ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
2845ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownBool dis_neon_vext ( UInt theInstr, IRTemp condT )
2846ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
2847ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt dreg = get_neon_d_regno(theInstr);
2848ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt mreg = get_neon_m_regno(theInstr);
2849ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt nreg = get_neon_n_regno(theInstr);
2850ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt imm4 = (theInstr >> 8) & 0xf;
2851ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt Q = (theInstr >> 6) & 1;
2852ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HChar reg_t = Q ? 'q' : 'd';
2853ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2854ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (Q) {
2855ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putQReg(dreg, triop(Iop_ExtractV128, getQReg(nreg),
2856ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               getQReg(mreg), mkU8(imm4)), condT);
2857ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
2858ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putDRegI64(dreg, triop(Iop_Extract64, getDRegI64(nreg),
2859ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 getDRegI64(mreg), mkU8(imm4)), condT);
2860ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2861ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DIP("vext.8 %c%d, %c%d, %c%d, #%d\n", reg_t, dreg, reg_t, nreg,
2862ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                         reg_t, mreg, imm4);
2863ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return True;
2864ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
2865ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2866ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* VTBL, VTBX */
2867ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
2868ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownBool dis_neon_vtb ( UInt theInstr, IRTemp condT )
2869ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
2870ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt op = (theInstr >> 6) & 1;
2871ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt dreg = get_neon_d_regno(theInstr & ~(1 << 6));
2872ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt nreg = get_neon_n_regno(theInstr & ~(1 << 6));
2873ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt mreg = get_neon_m_regno(theInstr & ~(1 << 6));
2874ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt len = (theInstr >> 8) & 3;
2875ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int i;
2876ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IROp cmp;
2877ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ULong imm;
2878ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp arg_l;
2879ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp old_mask, new_mask, cur_mask;
2880ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp old_res, new_res;
2881ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp old_arg, new_arg;
2882ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2883ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (dreg >= 0x100 || mreg >= 0x100 || nreg >= 0x100)
2884ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return False;
2885ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (nreg + len > 31)
2886ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return False;
2887ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2888ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   cmp = Iop_CmpGT8Ux8;
2889ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2890ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   old_mask = newTemp(Ity_I64);
2891ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   old_res = newTemp(Ity_I64);
2892ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   old_arg = newTemp(Ity_I64);
2893ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign(old_mask, mkU64(0));
2894ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign(old_res, mkU64(0));
2895ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign(old_arg, getDRegI64(mreg));
2896ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   imm = 8;
2897ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   imm = (imm <<  8) | imm;
2898ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   imm = (imm << 16) | imm;
2899ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   imm = (imm << 32) | imm;
2900ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2901ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (i = 0; i <= len; i++) {
2902ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      arg_l = newTemp(Ity_I64);
2903ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      new_mask = newTemp(Ity_I64);
2904ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      cur_mask = newTemp(Ity_I64);
2905ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      new_res = newTemp(Ity_I64);
2906ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      new_arg = newTemp(Ity_I64);
2907ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(arg_l, getDRegI64(nreg+i));
2908ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(new_arg, binop(Iop_Sub8x8, mkexpr(old_arg), mkU64(imm)));
2909ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(cur_mask, binop(cmp, mkU64(imm), mkexpr(old_arg)));
2910ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(new_mask, binop(Iop_Or64, mkexpr(old_mask), mkexpr(cur_mask)));
2911ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(new_res, binop(Iop_Or64,
2912ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            mkexpr(old_res),
2913ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            binop(Iop_And64,
2914ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  binop(Iop_Perm8x8,
2915ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                        mkexpr(arg_l),
2916ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                        binop(Iop_And64,
2917ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                              mkexpr(old_arg),
2918ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                              mkexpr(cur_mask))),
2919ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  mkexpr(cur_mask))));
2920ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2921ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      old_arg = new_arg;
2922ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      old_mask = new_mask;
2923ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      old_res = new_res;
2924ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2925ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (op) {
2926ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      new_res = newTemp(Ity_I64);
2927ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(new_res, binop(Iop_Or64,
2928ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            binop(Iop_And64,
2929ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  getDRegI64(dreg),
2930ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  unop(Iop_Not64, mkexpr(old_mask))),
2931ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            mkexpr(old_res)));
2932ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      old_res = new_res;
2933ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2934ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2935ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   putDRegI64(dreg, mkexpr(old_res), condT);
2936ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DIP("vtb%c.8 d%u, {", op ? 'x' : 'l', dreg);
2937ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (len > 0) {
2938ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("d%u-d%u", nreg, nreg + len);
2939ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
2940ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("d%u", nreg);
2941ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2942ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DIP("}, d%u\n", mreg);
2943ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return True;
2944ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
2945ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2946ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* VDUP (scalar)  */
2947ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
2948ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownBool dis_neon_vdup ( UInt theInstr, IRTemp condT )
2949ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
2950ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt Q = (theInstr >> 6) & 1;
2951ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt dreg = ((theInstr >> 18) & 0x10) | ((theInstr >> 12) & 0xF);
2952ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt mreg = ((theInstr >> 1) & 0x10) | (theInstr & 0xF);
2953ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt imm4 = (theInstr >> 16) & 0xF;
2954ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt index;
2955ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt size;
2956ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp arg_m;
2957ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp res;
2958ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IROp op, op2;
2959ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2960ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if ((imm4 == 0) || (imm4 == 8))
2961ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return False;
2962ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if ((Q == 1) && ((dreg & 1) == 1))
2963ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return False;
2964ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (Q)
2965ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      dreg >>= 1;
2966ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   arg_m = newTemp(Ity_I64);
2967ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign(arg_m, getDRegI64(mreg));
2968ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (Q)
2969ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      res = newTemp(Ity_V128);
2970ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else
2971ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      res = newTemp(Ity_I64);
2972ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if ((imm4 & 1) == 1) {
2973ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      op = Q ? Iop_Dup8x16 : Iop_Dup8x8;
2974ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      op2 = Iop_GetElem8x8;
2975ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      index = imm4 >> 1;
2976ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      size = 8;
2977ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else if ((imm4 & 3) == 2) {
2978ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      op = Q ? Iop_Dup16x8 : Iop_Dup16x4;
2979ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      op2 = Iop_GetElem16x4;
2980ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      index = imm4 >> 2;
2981ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      size = 16;
2982ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else if ((imm4 & 7) == 4) {
2983ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      op = Q ? Iop_Dup32x4 : Iop_Dup32x2;
2984ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      op2 = Iop_GetElem32x2;
2985ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      index = imm4 >> 3;
2986ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      size = 32;
2987ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
2988ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return False; // can this ever happen?
2989ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2990ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign(res, unop(op, binop(op2, mkexpr(arg_m), mkU8(index))));
2991ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (Q) {
2992ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putQReg(dreg, mkexpr(res), condT);
2993ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
2994ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putDRegI64(dreg, mkexpr(res), condT);
2995ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2996ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DIP("vdup.%d %c%d, d%d[%d]\n", size, Q ? 'q' : 'd', dreg, mreg, index);
2997ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return True;
2998ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
2999ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3000ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* A7.4.1 Three registers of the same length */
3001ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
3002ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownBool dis_neon_data_3same ( UInt theInstr, IRTemp condT )
3003ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
3004ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt Q = (theInstr >> 6) & 1;
3005ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt dreg = get_neon_d_regno(theInstr);
3006ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt nreg = get_neon_n_regno(theInstr);
3007ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt mreg = get_neon_m_regno(theInstr);
3008ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt A = (theInstr >> 8) & 0xF;
3009ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt B = (theInstr >> 4) & 1;
3010ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt C = (theInstr >> 20) & 0x3;
3011ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt U = (theInstr >> 24) & 1;
3012ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt size = C;
3013ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3014ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp arg_n;
3015ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp arg_m;
3016ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp res;
3017ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3018ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (Q) {
3019ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      arg_n = newTemp(Ity_V128);
3020ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      arg_m = newTemp(Ity_V128);
3021ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      res = newTemp(Ity_V128);
3022ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(arg_n, getQReg(nreg));
3023ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(arg_m, getQReg(mreg));
3024ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
3025ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      arg_n = newTemp(Ity_I64);
3026ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      arg_m = newTemp(Ity_I64);
3027ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      res = newTemp(Ity_I64);
3028ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(arg_n, getDRegI64(nreg));
3029ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(arg_m, getDRegI64(mreg));
3030ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
3031ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3032ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch(A) {
3033ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0:
3034ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (B == 0) {
3035ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* VHADD */
3036ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            ULong imm = 0;
3037ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            IRExpr *imm_val;
3038ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            IROp addOp;
3039ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            IROp andOp;
3040ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            IROp shOp;
3041ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            char regType = Q ? 'q' : 'd';
3042ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3043ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (size == 3)
3044ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               return False;
3045ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            switch(size) {
3046ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               case 0: imm = 0x101010101010101LL; break;
3047ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               case 1: imm = 0x1000100010001LL; break;
3048ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               case 2: imm = 0x100000001LL; break;
3049ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               default: vassert(0);
3050ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
3051ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (Q) {
3052ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               imm_val = binop(Iop_64HLtoV128, mkU64(imm), mkU64(imm));
3053ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               andOp = Iop_AndV128;
3054ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            } else {
3055ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               imm_val = mkU64(imm);
3056ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               andOp = Iop_And64;
3057ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
3058ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (U) {
3059ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               switch(size) {
3060ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 0:
3061ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     addOp = Q ? Iop_Add8x16 : Iop_Add8x8;
3062ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     shOp = Q ? Iop_ShrN8x16 : Iop_ShrN8x8;
3063ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
3064ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 1:
3065ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     addOp = Q ? Iop_Add16x8 : Iop_Add16x4;
3066ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     shOp = Q ? Iop_ShrN16x8 : Iop_ShrN16x4;
3067ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
3068ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 2:
3069ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     addOp = Q ? Iop_Add32x4 : Iop_Add32x2;
3070ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     shOp = Q ? Iop_ShrN32x4 : Iop_ShrN32x2;
3071ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
3072ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  default:
3073ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     vassert(0);
3074ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               }
3075ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            } else {
3076ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               switch(size) {
3077ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 0:
3078ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     addOp = Q ? Iop_Add8x16 : Iop_Add8x8;
3079ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     shOp = Q ? Iop_SarN8x16 : Iop_SarN8x8;
3080ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
3081ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 1:
3082ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     addOp = Q ? Iop_Add16x8 : Iop_Add16x4;
3083ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     shOp = Q ? Iop_SarN16x8 : Iop_SarN16x4;
3084ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
3085ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 2:
3086ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     addOp = Q ? Iop_Add32x4 : Iop_Add32x2;
3087ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     shOp = Q ? Iop_SarN32x4 : Iop_SarN32x2;
3088ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
3089ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  default:
3090ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     vassert(0);
3091ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               }
3092ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
3093ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(res,
3094ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   binop(addOp,
3095ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         binop(addOp,
3096ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               binop(shOp, mkexpr(arg_m), mkU8(1)),
3097ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               binop(shOp, mkexpr(arg_n), mkU8(1))),
3098ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         binop(shOp,
3099ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               binop(addOp,
3100ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                     binop(andOp, mkexpr(arg_m), imm_val),
3101ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                     binop(andOp, mkexpr(arg_n), imm_val)),
3102ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               mkU8(1))));
3103ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("vhadd.%c%d %c%d, %c%d, %c%d\n",
3104ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                U ? 'u' : 's', 8 << size, regType,
3105ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                dreg, regType, nreg, regType, mreg);
3106ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
3107ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* VQADD */
3108ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            IROp op, op2;
3109ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            IRTemp tmp;
3110ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            char reg_t = Q ? 'q' : 'd';
3111ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (Q) {
3112ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               switch (size) {
3113ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 0:
3114ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op = U ? Iop_QAdd8Ux16 : Iop_QAdd8Sx16;
3115ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op2 = Iop_Add8x16;
3116ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
3117ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 1:
3118ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op = U ? Iop_QAdd16Ux8 : Iop_QAdd16Sx8;
3119ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op2 = Iop_Add16x8;
3120ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
3121ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 2:
3122ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op = U ? Iop_QAdd32Ux4 : Iop_QAdd32Sx4;
3123ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op2 = Iop_Add32x4;
3124ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
3125ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 3:
3126ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op = U ? Iop_QAdd64Ux2 : Iop_QAdd64Sx2;
3127ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op2 = Iop_Add64x2;
3128ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
3129ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  default:
3130ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     vassert(0);
3131ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               }
3132ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            } else {
3133ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               switch (size) {
3134ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 0:
3135ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op = U ? Iop_QAdd8Ux8 : Iop_QAdd8Sx8;
3136ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op2 = Iop_Add8x8;
3137ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
3138ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 1:
3139ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op = U ? Iop_QAdd16Ux4 : Iop_QAdd16Sx4;
3140ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op2 = Iop_Add16x4;
3141ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
3142ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 2:
3143ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op = U ? Iop_QAdd32Ux2 : Iop_QAdd32Sx2;
3144ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op2 = Iop_Add32x2;
3145ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
3146ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 3:
3147ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op = U ? Iop_QAdd64Ux1 : Iop_QAdd64Sx1;
3148ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op2 = Iop_Add64;
3149ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
3150ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  default:
3151ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     vassert(0);
3152ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               }
3153ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
3154ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (Q) {
3155ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               tmp = newTemp(Ity_V128);
3156ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            } else {
3157ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               tmp = newTemp(Ity_I64);
3158ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
3159ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(res, binop(op, mkexpr(arg_n), mkexpr(arg_m)));
3160ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#ifndef DISABLE_QC_FLAG
3161ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(tmp, binop(op2, mkexpr(arg_n), mkexpr(arg_m)));
3162ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            setFlag_QC(mkexpr(res), mkexpr(tmp), Q, condT);
3163ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#endif
3164ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("vqadd.%c%d %c%d, %c%d, %c%d\n",
3165ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                U ? 'u' : 's',
3166ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                8 << size, reg_t, dreg, reg_t, nreg, reg_t, mreg);
3167ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
3168ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
3169ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 1:
3170ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (B == 0) {
3171ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* VRHADD */
3172ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* VRHADD C, A, B ::=
3173ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 C = (A >> 1) + (B >> 1) + (((A & 1) + (B & 1) + 1) >> 1) */
3174ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            IROp shift_op, add_op;
3175ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            IRTemp cc;
3176ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            ULong one = 1;
3177ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            HChar reg_t = Q ? 'q' : 'd';
3178ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            switch (size) {
3179ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               case 0: one = (one <<  8) | one; /* fall through */
3180ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               case 1: one = (one << 16) | one; /* fall through */
3181ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               case 2: one = (one << 32) | one; break;
3182ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               case 3: return False;
3183ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               default: vassert(0);
3184ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
3185ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (Q) {
3186ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               switch (size) {
3187ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 0:
3188ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     shift_op = U ? Iop_ShrN8x16 : Iop_SarN8x16;
3189ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     add_op = Iop_Add8x16;
3190ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
3191ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 1:
3192ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     shift_op = U ? Iop_ShrN16x8 : Iop_SarN16x8;
3193ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     add_op = Iop_Add16x8;
3194ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
3195ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 2:
3196ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     shift_op = U ? Iop_ShrN32x4 : Iop_SarN32x4;
3197ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     add_op = Iop_Add32x4;
3198ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
3199ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 3:
3200ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     return False;
3201ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  default:
3202ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     vassert(0);
3203ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               }
3204ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            } else {
3205ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               switch (size) {
3206ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 0:
3207ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     shift_op = U ? Iop_ShrN8x8 : Iop_SarN8x8;
3208ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     add_op = Iop_Add8x8;
3209ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
3210ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 1:
3211ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     shift_op = U ? Iop_ShrN16x4 : Iop_SarN16x4;
3212ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     add_op = Iop_Add16x4;
3213ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
3214ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 2:
3215ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     shift_op = U ? Iop_ShrN32x2 : Iop_SarN32x2;
3216ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     add_op = Iop_Add32x2;
3217ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
3218ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 3:
3219ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     return False;
3220ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  default:
3221ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     vassert(0);
3222ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               }
3223ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
3224ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (Q) {
3225ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               cc = newTemp(Ity_V128);
3226ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign(cc, binop(shift_op,
3227ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                binop(add_op,
3228ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                      binop(add_op,
3229ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                            binop(Iop_AndV128,
3230ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                                  mkexpr(arg_n),
3231ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                                  binop(Iop_64HLtoV128,
3232ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                                        mkU64(one),
3233ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                                        mkU64(one))),
3234ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                            binop(Iop_AndV128,
3235ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                                  mkexpr(arg_m),
3236ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                                  binop(Iop_64HLtoV128,
3237ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                                        mkU64(one),
3238ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                                        mkU64(one)))),
3239ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                      binop(Iop_64HLtoV128,
3240ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                            mkU64(one),
3241ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                            mkU64(one))),
3242ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                mkU8(1)));
3243ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign(res, binop(add_op,
3244ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 binop(add_op,
3245ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                       binop(shift_op,
3246ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                             mkexpr(arg_n),
3247ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                             mkU8(1)),
3248ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                       binop(shift_op,
3249ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                             mkexpr(arg_m),
3250ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                             mkU8(1))),
3251ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 mkexpr(cc)));
3252ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            } else {
3253ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               cc = newTemp(Ity_I64);
3254ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign(cc, binop(shift_op,
3255ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                binop(add_op,
3256ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                      binop(add_op,
3257ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                            binop(Iop_And64,
3258ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                                  mkexpr(arg_n),
3259ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                                  mkU64(one)),
3260ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                            binop(Iop_And64,
3261ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                                  mkexpr(arg_m),
3262ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                                  mkU64(one))),
3263ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                      mkU64(one)),
3264ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                mkU8(1)));
3265ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign(res, binop(add_op,
3266ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 binop(add_op,
3267ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                       binop(shift_op,
3268ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                             mkexpr(arg_n),
3269ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                             mkU8(1)),
3270ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                       binop(shift_op,
3271ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                             mkexpr(arg_m),
3272ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                             mkU8(1))),
3273ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 mkexpr(cc)));
3274ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
3275ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("vrhadd.%c%d %c%d, %c%d, %c%d\n",
3276ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                U ? 'u' : 's',
3277ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                8 << size, reg_t, dreg, reg_t, nreg, reg_t, mreg);
3278ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
3279ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (U == 0)  {
3280ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               switch(C) {
3281ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 0: {
3282ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     /* VAND  */
3283ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     HChar reg_t = Q ? 'q' : 'd';
3284ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     if (Q) {
3285ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        assign(res, binop(Iop_AndV128, mkexpr(arg_n),
3286ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                                       mkexpr(arg_m)));
3287ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     } else {
3288ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        assign(res, binop(Iop_And64, mkexpr(arg_n),
3289ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                                     mkexpr(arg_m)));
3290ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     }
3291ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     DIP("vand %c%d, %c%d, %c%d\n",
3292ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         reg_t, dreg, reg_t, nreg, reg_t, mreg);
3293ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
3294ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  }
3295ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 1: {
3296ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     /* VBIC  */
3297ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     HChar reg_t = Q ? 'q' : 'd';
3298ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     if (Q) {
3299ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        assign(res, binop(Iop_AndV128,mkexpr(arg_n),
3300ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               unop(Iop_NotV128, mkexpr(arg_m))));
3301ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     } else {
3302ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        assign(res, binop(Iop_And64, mkexpr(arg_n),
3303ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               unop(Iop_Not64, mkexpr(arg_m))));
3304ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     }
3305ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     DIP("vbic %c%d, %c%d, %c%d\n",
3306ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         reg_t, dreg, reg_t, nreg, reg_t, mreg);
3307ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
3308ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  }
3309ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 2:
3310ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     if ( nreg != mreg) {
3311ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        /* VORR  */
3312ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        HChar reg_t = Q ? 'q' : 'd';
3313ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        if (Q) {
3314ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           assign(res, binop(Iop_OrV128, mkexpr(arg_n),
3315ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                                         mkexpr(arg_m)));
3316ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        } else {
3317ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           assign(res, binop(Iop_Or64, mkexpr(arg_n),
3318ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                                       mkexpr(arg_m)));
3319ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        }
3320ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        DIP("vorr %c%d, %c%d, %c%d\n",
3321ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            reg_t, dreg, reg_t, nreg, reg_t, mreg);
3322ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     } else {
3323ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        /* VMOV  */
3324ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        HChar reg_t = Q ? 'q' : 'd';
3325ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        assign(res, mkexpr(arg_m));
3326ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        DIP("vmov %c%d, %c%d\n", reg_t, dreg, reg_t, mreg);
3327ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     }
3328ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
3329ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 3:{
3330ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     /* VORN  */
3331ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     HChar reg_t = Q ? 'q' : 'd';
3332ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     if (Q) {
3333ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        assign(res, binop(Iop_OrV128,mkexpr(arg_n),
3334ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               unop(Iop_NotV128, mkexpr(arg_m))));
3335ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     } else {
3336ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        assign(res, binop(Iop_Or64, mkexpr(arg_n),
3337ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               unop(Iop_Not64, mkexpr(arg_m))));
3338ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     }
3339ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     DIP("vorn %c%d, %c%d, %c%d\n",
3340ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         reg_t, dreg, reg_t, nreg, reg_t, mreg);
3341ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
3342ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  }
3343ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               }
3344ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            } else {
3345ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               switch(C) {
3346ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 0:
3347ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     /* VEOR (XOR)  */
3348ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     if (Q) {
3349ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        assign(res, binop(Iop_XorV128, mkexpr(arg_n),
3350ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                                       mkexpr(arg_m)));
3351ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     } else {
3352ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        assign(res, binop(Iop_Xor64, mkexpr(arg_n),
3353ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                                     mkexpr(arg_m)));
3354ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     }
3355ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     DIP("veor %c%u, %c%u, %c%u\n", Q ? 'q' : 'd', dreg,
3356ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           Q ? 'q' : 'd', nreg, Q ? 'q' : 'd', mreg);
3357ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
3358ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 1:
3359ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     /* VBSL  */
3360ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     if (Q) {
3361ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        IRTemp reg_d = newTemp(Ity_V128);
3362ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        assign(reg_d, getQReg(dreg));
3363ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        assign(res,
3364ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               binop(Iop_OrV128,
3365ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                     binop(Iop_AndV128, mkexpr(arg_n),
3366ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                                        mkexpr(reg_d)),
3367ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                     binop(Iop_AndV128,
3368ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                           mkexpr(arg_m),
3369ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                           unop(Iop_NotV128,
3370ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                                 mkexpr(reg_d)) ) ) );
3371ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     } else {
3372ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        IRTemp reg_d = newTemp(Ity_I64);
3373ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        assign(reg_d, getDRegI64(dreg));
3374ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        assign(res,
3375ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               binop(Iop_Or64,
3376ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                     binop(Iop_And64, mkexpr(arg_n),
3377ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                                      mkexpr(reg_d)),
3378ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                     binop(Iop_And64,
3379ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                           mkexpr(arg_m),
3380ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                           unop(Iop_Not64, mkexpr(reg_d)))));
3381ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     }
3382ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     DIP("vbsl %c%u, %c%u, %c%u\n",
3383ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         Q ? 'q' : 'd', dreg,
3384ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         Q ? 'q' : 'd', nreg, Q ? 'q' : 'd', mreg);
3385ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
3386ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 2:
3387ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     /* VBIT  */
3388ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     if (Q) {
3389ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        IRTemp reg_d = newTemp(Ity_V128);
3390ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        assign(reg_d, getQReg(dreg));
3391ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        assign(res,
3392ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               binop(Iop_OrV128,
3393ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                     binop(Iop_AndV128, mkexpr(arg_n),
3394ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                                        mkexpr(arg_m)),
3395ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                     binop(Iop_AndV128,
3396ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                           mkexpr(reg_d),
3397ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                           unop(Iop_NotV128, mkexpr(arg_m)))));
3398ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     } else {
3399ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        IRTemp reg_d = newTemp(Ity_I64);
3400ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        assign(reg_d, getDRegI64(dreg));
3401ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        assign(res,
3402ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               binop(Iop_Or64,
3403ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                     binop(Iop_And64, mkexpr(arg_n),
3404ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                                      mkexpr(arg_m)),
3405ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                     binop(Iop_And64,
3406ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                           mkexpr(reg_d),
3407ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                           unop(Iop_Not64, mkexpr(arg_m)))));
3408ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     }
3409ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     DIP("vbit %c%u, %c%u, %c%u\n",
3410ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         Q ? 'q' : 'd', dreg,
3411ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         Q ? 'q' : 'd', nreg, Q ? 'q' : 'd', mreg);
3412ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
3413ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 3:
3414ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     /* VBIF  */
3415ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     if (Q) {
3416ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        IRTemp reg_d = newTemp(Ity_V128);
3417ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        assign(reg_d, getQReg(dreg));
3418ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        assign(res,
3419ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               binop(Iop_OrV128,
3420ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                     binop(Iop_AndV128, mkexpr(reg_d),
3421ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                                        mkexpr(arg_m)),
3422ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                     binop(Iop_AndV128,
3423ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                           mkexpr(arg_n),
3424ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                           unop(Iop_NotV128, mkexpr(arg_m)))));
3425ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     } else {
3426ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        IRTemp reg_d = newTemp(Ity_I64);
3427ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        assign(reg_d, getDRegI64(dreg));
3428ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        assign(res,
3429ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               binop(Iop_Or64,
3430ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                     binop(Iop_And64, mkexpr(reg_d),
3431ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                                      mkexpr(arg_m)),
3432ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                     binop(Iop_And64,
3433ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                           mkexpr(arg_n),
3434ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                           unop(Iop_Not64, mkexpr(arg_m)))));
3435ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     }
3436ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     DIP("vbif %c%u, %c%u, %c%u\n",
3437ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         Q ? 'q' : 'd', dreg,
3438ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         Q ? 'q' : 'd', nreg, Q ? 'q' : 'd', mreg);
3439ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
3440ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               }
3441ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
3442ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
3443ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
3444ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 2:
3445ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (B == 0) {
3446ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* VHSUB */
3447ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* (A >> 1) - (B >> 1) - (NOT (A) & B & 1)   */
3448ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            ULong imm = 0;
3449ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            IRExpr *imm_val;
3450ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            IROp subOp;
3451ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            IROp notOp;
3452ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            IROp andOp;
3453ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            IROp shOp;
3454ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (size == 3)
3455ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               return False;
3456ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            switch(size) {
3457ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               case 0: imm = 0x101010101010101LL; break;
3458ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               case 1: imm = 0x1000100010001LL; break;
3459ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               case 2: imm = 0x100000001LL; break;
3460ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               default: vassert(0);
3461ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
3462ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (Q) {
3463ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               imm_val = binop(Iop_64HLtoV128, mkU64(imm), mkU64(imm));
3464ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               andOp = Iop_AndV128;
3465ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               notOp = Iop_NotV128;
3466ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            } else {
3467ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               imm_val = mkU64(imm);
3468ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               andOp = Iop_And64;
3469ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               notOp = Iop_Not64;
3470ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
3471ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (U) {
3472ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               switch(size) {
3473ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 0:
3474ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     subOp = Q ? Iop_Sub8x16 : Iop_Sub8x8;
3475ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     shOp = Q ? Iop_ShrN8x16 : Iop_ShrN8x8;
3476ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
3477ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 1:
3478ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     subOp = Q ? Iop_Sub16x8 : Iop_Sub16x4;
3479ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     shOp = Q ? Iop_ShrN16x8 : Iop_ShrN16x4;
3480ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
3481ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 2:
3482ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     subOp = Q ? Iop_Sub32x4 : Iop_Sub32x2;
3483ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     shOp = Q ? Iop_ShrN32x4 : Iop_ShrN32x2;
3484ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
3485ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  default:
3486ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     vassert(0);
3487ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               }
3488ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            } else {
3489ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               switch(size) {
3490ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 0:
3491ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     subOp = Q ? Iop_Sub8x16 : Iop_Sub8x8;
3492ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     shOp = Q ? Iop_SarN8x16 : Iop_SarN8x8;
3493ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
3494ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 1:
3495ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     subOp = Q ? Iop_Sub16x8 : Iop_Sub16x4;
3496ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     shOp = Q ? Iop_SarN16x8 : Iop_SarN16x4;
3497ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
3498ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 2:
3499ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     subOp = Q ? Iop_Sub32x4 : Iop_Sub32x2;
3500ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     shOp = Q ? Iop_SarN32x4 : Iop_SarN32x2;
3501ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
3502ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  default:
3503ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     vassert(0);
3504ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               }
3505ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
3506ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(res,
3507ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   binop(subOp,
3508ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         binop(subOp,
3509ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               binop(shOp, mkexpr(arg_n), mkU8(1)),
3510ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               binop(shOp, mkexpr(arg_m), mkU8(1))),
3511ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         binop(andOp,
3512ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               binop(andOp,
3513ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                     unop(notOp, mkexpr(arg_n)),
3514ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                     mkexpr(arg_m)),
3515ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               imm_val)));
3516ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("vhsub.%c%u %c%u, %c%u, %c%u\n",
3517ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                U ? 'u' : 's', 8 << size,
3518ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', nreg, Q ? 'q' : 'd',
3519ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                mreg);
3520ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
3521ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* VQSUB */
3522ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            IROp op, op2;
3523ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            IRTemp tmp;
3524ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (Q) {
3525ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               switch (size) {
3526ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 0:
3527ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op = U ? Iop_QSub8Ux16 : Iop_QSub8Sx16;
3528ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op2 = Iop_Sub8x16;
3529ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
3530ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 1:
3531ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op = U ? Iop_QSub16Ux8 : Iop_QSub16Sx8;
3532ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op2 = Iop_Sub16x8;
3533ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
3534ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 2:
3535ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op = U ? Iop_QSub32Ux4 : Iop_QSub32Sx4;
3536ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op2 = Iop_Sub32x4;
3537ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
3538ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 3:
3539ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op = U ? Iop_QSub64Ux2 : Iop_QSub64Sx2;
3540ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op2 = Iop_Sub64x2;
3541ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
3542ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  default:
3543ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     vassert(0);
3544ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               }
3545ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            } else {
3546ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               switch (size) {
3547ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 0:
3548ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op = U ? Iop_QSub8Ux8 : Iop_QSub8Sx8;
3549ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op2 = Iop_Sub8x8;
3550ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
3551ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 1:
3552ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op = U ? Iop_QSub16Ux4 : Iop_QSub16Sx4;
3553ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op2 = Iop_Sub16x4;
3554ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
3555ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 2:
3556ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op = U ? Iop_QSub32Ux2 : Iop_QSub32Sx2;
3557ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op2 = Iop_Sub32x2;
3558ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
3559ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 3:
3560ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op = U ? Iop_QSub64Ux1 : Iop_QSub64Sx1;
3561ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op2 = Iop_Sub64;
3562ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
3563ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  default:
3564ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     vassert(0);
3565ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               }
3566ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
3567ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (Q)
3568ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               tmp = newTemp(Ity_V128);
3569ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            else
3570ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               tmp = newTemp(Ity_I64);
3571ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(res, binop(op, mkexpr(arg_n), mkexpr(arg_m)));
3572ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#ifndef DISABLE_QC_FLAG
3573ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(tmp, binop(op2, mkexpr(arg_n), mkexpr(arg_m)));
3574ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            setFlag_QC(mkexpr(res), mkexpr(tmp), Q, condT);
3575ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#endif
3576ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("vqsub.%c%u %c%u, %c%u, %c%u\n",
3577ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                U ? 'u' : 's', 8 << size,
3578ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', nreg, Q ? 'q' : 'd',
3579ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                mreg);
3580ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
3581ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
3582ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 3: {
3583ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            IROp op;
3584ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (Q) {
3585ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               switch (size) {
3586ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 0: op = U ? Iop_CmpGT8Ux16 : Iop_CmpGT8Sx16; break;
3587ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 1: op = U ? Iop_CmpGT16Ux8 : Iop_CmpGT16Sx8; break;
3588ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 2: op = U ? Iop_CmpGT32Ux4 : Iop_CmpGT32Sx4; break;
3589ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 3: return False;
3590ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  default: vassert(0);
3591ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               }
3592ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            } else {
3593ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               switch (size) {
3594ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 0: op = U ? Iop_CmpGT8Ux8 : Iop_CmpGT8Sx8; break;
3595ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 1: op = U ? Iop_CmpGT16Ux4 : Iop_CmpGT16Sx4; break;
3596ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 2: op = U ? Iop_CmpGT32Ux2: Iop_CmpGT32Sx2; break;
3597ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 3: return False;
3598ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  default: vassert(0);
3599ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               }
3600ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
3601ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (B == 0) {
3602ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* VCGT  */
3603ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign(res, binop(op, mkexpr(arg_n), mkexpr(arg_m)));
3604ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("vcgt.%c%u %c%u, %c%u, %c%u\n",
3605ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   U ? 'u' : 's', 8 << size,
3606ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', nreg, Q ? 'q' : 'd',
3607ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   mreg);
3608ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            } else {
3609ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* VCGE  */
3610ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* VCGE res, argn, argm
3611ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    is equal to
3612ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  VCGT tmp, argm, argn
3613ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  VNOT res, tmp */
3614ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign(res,
3615ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      unop(Q ? Iop_NotV128 : Iop_Not64,
3616ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           binop(op, mkexpr(arg_m), mkexpr(arg_n))));
3617ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("vcge.%c%u %c%u, %c%u, %c%u\n",
3618ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   U ? 'u' : 's', 8 << size,
3619ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', nreg, Q ? 'q' : 'd',
3620ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   mreg);
3621ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
3622ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
3623ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
3624ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 4:
3625ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (B == 0) {
3626ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* VSHL */
3627ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            IROp op, sub_op;
3628ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            IRTemp tmp;
3629ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (U) {
3630ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               switch (size) {
3631ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 0: op = Q ? Iop_Shl8x16 : Iop_Shl8x8; break;
3632ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 1: op = Q ? Iop_Shl16x8 : Iop_Shl16x4; break;
3633ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 2: op = Q ? Iop_Shl32x4 : Iop_Shl32x2; break;
3634ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 3: op = Q ? Iop_Shl64x2 : Iop_Shl64; break;
3635ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  default: vassert(0);
3636ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               }
3637ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            } else {
3638ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               tmp = newTemp(Q ? Ity_V128 : Ity_I64);
3639ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               switch (size) {
3640ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 0:
3641ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op = Q ? Iop_Sar8x16 : Iop_Sar8x8;
3642ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     sub_op = Q ? Iop_Sub8x16 : Iop_Sub8x8;
3643ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
3644ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 1:
3645ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op = Q ? Iop_Sar16x8 : Iop_Sar16x4;
3646ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     sub_op = Q ? Iop_Sub16x8 : Iop_Sub16x4;
3647ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
3648ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 2:
3649ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op = Q ? Iop_Sar32x4 : Iop_Sar32x2;
3650ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     sub_op = Q ? Iop_Sub32x4 : Iop_Sub32x2;
3651ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
3652ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 3:
3653ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op = Q ? Iop_Sar64x2 : Iop_Sar64;
3654ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     sub_op = Q ? Iop_Sub64x2 : Iop_Sub64;
3655ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
3656ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  default:
3657ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     vassert(0);
3658ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               }
3659ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
3660ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (U) {
3661ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               if (!Q && (size == 3))
3662ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  assign(res, binop(op, mkexpr(arg_m),
3663ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                        unop(Iop_64to8, mkexpr(arg_n))));
3664ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               else
3665ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  assign(res, binop(op, mkexpr(arg_m), mkexpr(arg_n)));
3666ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            } else {
3667ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               if (Q)
3668ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  assign(tmp, binop(sub_op,
3669ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    binop(Iop_64HLtoV128, mkU64(0), mkU64(0)),
3670ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    mkexpr(arg_n)));
3671ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               else
3672ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  assign(tmp, binop(sub_op, mkU64(0), mkexpr(arg_n)));
3673ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               if (!Q && (size == 3))
3674ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  assign(res, binop(op, mkexpr(arg_m),
3675ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                        unop(Iop_64to8, mkexpr(tmp))));
3676ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               else
3677ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  assign(res, binop(op, mkexpr(arg_m), mkexpr(tmp)));
3678ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
3679ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("vshl.%c%u %c%u, %c%u, %c%u\n",
3680ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                U ? 'u' : 's', 8 << size,
3681ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', mreg, Q ? 'q' : 'd',
3682ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                nreg);
3683ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
3684ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* VQSHL */
3685ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            IROp op, op_rev, op_shrn, op_shln, cmp_neq, cmp_gt;
3686ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            IRTemp tmp, shval, mask, old_shval;
3687ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            UInt i;
3688ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            ULong esize;
3689ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            cmp_neq = Q ? Iop_CmpNEZ8x16 : Iop_CmpNEZ8x8;
3690ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            cmp_gt = Q ? Iop_CmpGT8Sx16 : Iop_CmpGT8Sx8;
3691ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (U) {
3692ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               switch (size) {
3693ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 0:
3694ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op = Q ? Iop_QShl8x16 : Iop_QShl8x8;
3695ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op_rev = Q ? Iop_Shr8x16 : Iop_Shr8x8;
3696ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op_shrn = Q ? Iop_ShrN8x16 : Iop_ShrN8x8;
3697ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op_shln = Q ? Iop_ShlN8x16 : Iop_ShlN8x8;
3698ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
3699ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 1:
3700ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op = Q ? Iop_QShl16x8 : Iop_QShl16x4;
3701ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op_rev = Q ? Iop_Shr16x8 : Iop_Shr16x4;
3702ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op_shrn = Q ? Iop_ShrN16x8 : Iop_ShrN16x4;
3703ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op_shln = Q ? Iop_ShlN16x8 : Iop_ShlN16x4;
3704ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
3705ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 2:
3706ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op = Q ? Iop_QShl32x4 : Iop_QShl32x2;
3707ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op_rev = Q ? Iop_Shr32x4 : Iop_Shr32x2;
3708ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op_shrn = Q ? Iop_ShrN32x4 : Iop_ShrN32x2;
3709ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op_shln = Q ? Iop_ShlN32x4 : Iop_ShlN32x2;
3710ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
3711ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 3:
3712ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op = Q ? Iop_QShl64x2 : Iop_QShl64x1;
3713ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op_rev = Q ? Iop_Shr64x2 : Iop_Shr64;
3714ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op_shrn = Q ? Iop_ShrN64x2 : Iop_Shr64;
3715ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op_shln = Q ? Iop_ShlN64x2 : Iop_Shl64;
3716ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
3717ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  default:
3718ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     vassert(0);
3719ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               }
3720ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            } else {
3721ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               switch (size) {
3722ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 0:
3723ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op = Q ? Iop_QSal8x16 : Iop_QSal8x8;
3724ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op_rev = Q ? Iop_Sar8x16 : Iop_Sar8x8;
3725ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op_shrn = Q ? Iop_ShrN8x16 : Iop_ShrN8x8;
3726ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op_shln = Q ? Iop_ShlN8x16 : Iop_ShlN8x8;
3727ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
3728ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 1:
3729ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op = Q ? Iop_QSal16x8 : Iop_QSal16x4;
3730ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op_rev = Q ? Iop_Sar16x8 : Iop_Sar16x4;
3731ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op_shrn = Q ? Iop_ShrN16x8 : Iop_ShrN16x4;
3732ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op_shln = Q ? Iop_ShlN16x8 : Iop_ShlN16x4;
3733ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
3734ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 2:
3735ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op = Q ? Iop_QSal32x4 : Iop_QSal32x2;
3736ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op_rev = Q ? Iop_Sar32x4 : Iop_Sar32x2;
3737ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op_shrn = Q ? Iop_ShrN32x4 : Iop_ShrN32x2;
3738ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op_shln = Q ? Iop_ShlN32x4 : Iop_ShlN32x2;
3739ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
3740ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 3:
3741ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op = Q ? Iop_QSal64x2 : Iop_QSal64x1;
3742ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op_rev = Q ? Iop_Sar64x2 : Iop_Sar64;
3743ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op_shrn = Q ? Iop_ShrN64x2 : Iop_Shr64;
3744ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op_shln = Q ? Iop_ShlN64x2 : Iop_Shl64;
3745ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
3746ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  default:
3747ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     vassert(0);
3748ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               }
3749ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
3750ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (Q) {
3751ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               tmp = newTemp(Ity_V128);
3752ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               shval = newTemp(Ity_V128);
3753ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               mask = newTemp(Ity_V128);
3754ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            } else {
3755ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               tmp = newTemp(Ity_I64);
3756ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               shval = newTemp(Ity_I64);
3757ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               mask = newTemp(Ity_I64);
3758ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
3759ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(res, binop(op, mkexpr(arg_m), mkexpr(arg_n)));
3760ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#ifndef DISABLE_QC_FLAG
3761ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* Only least significant byte from second argument is used.
3762ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               Copy this byte to the whole vector element. */
3763ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(shval, binop(op_shrn,
3764ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                binop(op_shln,
3765ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                       mkexpr(arg_n),
3766ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                       mkU8((8 << size) - 8)),
3767ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                mkU8((8 << size) - 8)));
3768ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            for(i = 0; i < size; i++) {
3769ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               old_shval = shval;
3770ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               shval = newTemp(Q ? Ity_V128 : Ity_I64);
3771ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign(shval, binop(Q ? Iop_OrV128 : Iop_Or64,
3772ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   mkexpr(old_shval),
3773ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   binop(op_shln,
3774ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                         mkexpr(old_shval),
3775ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                         mkU8(8 << i))));
3776ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
3777ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* If shift is greater or equal to the element size and
3778ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               element is non-zero, then QC flag should be set. */
3779ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            esize = (8 << size) - 1;
3780ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            esize = (esize <<  8) | esize;
3781ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            esize = (esize << 16) | esize;
3782ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            esize = (esize << 32) | esize;
3783ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            setFlag_QC(binop(Q ? Iop_AndV128 : Iop_And64,
3784ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             binop(cmp_gt, mkexpr(shval),
3785ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                           Q ? mkU128(esize) : mkU64(esize)),
3786ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             unop(cmp_neq, mkexpr(arg_m))),
3787ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       Q ? mkU128(0) : mkU64(0),
3788ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       Q, condT);
3789ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* Othervise QC flag should be set if shift value is positive and
3790ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               result beign rightshifted the same value is not equal to left
3791ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               argument. */
3792ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(mask, binop(cmp_gt, mkexpr(shval),
3793ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                       Q ? mkU128(0) : mkU64(0)));
3794ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (!Q && size == 3)
3795ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign(tmp, binop(op_rev, mkexpr(res),
3796ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                         unop(Iop_64to8, mkexpr(arg_n))));
3797ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            else
3798ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign(tmp, binop(op_rev, mkexpr(res), mkexpr(arg_n)));
3799ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            setFlag_QC(binop(Q ? Iop_AndV128 : Iop_And64,
3800ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             mkexpr(tmp), mkexpr(mask)),
3801ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       binop(Q ? Iop_AndV128 : Iop_And64,
3802ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             mkexpr(arg_m), mkexpr(mask)),
3803ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       Q, condT);
3804ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#endif
3805ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("vqshl.%c%u %c%u, %c%u, %c%u\n",
3806ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                U ? 'u' : 's', 8 << size,
3807ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', mreg, Q ? 'q' : 'd',
3808ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                nreg);
3809ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
3810ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
3811ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 5:
3812ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (B == 0) {
3813ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* VRSHL */
3814b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            IROp op, op_shrn, op_shln, cmp_gt, op_add;
3815ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            IRTemp shval, old_shval, imm_val, round;
3816ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            UInt i;
3817ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            ULong imm;
3818ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            cmp_gt = Q ? Iop_CmpGT8Sx16 : Iop_CmpGT8Sx8;
3819ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            imm = 1L;
3820ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            switch (size) {
3821ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               case 0: imm = (imm <<  8) | imm; /* fall through */
3822ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               case 1: imm = (imm << 16) | imm; /* fall through */
3823ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               case 2: imm = (imm << 32) | imm; /* fall through */
3824ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               case 3: break;
3825ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               default: vassert(0);
3826ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
3827ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            imm_val = newTemp(Q ? Ity_V128 : Ity_I64);
3828ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            round = newTemp(Q ? Ity_V128 : Ity_I64);
3829ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(imm_val, Q ? mkU128(imm) : mkU64(imm));
3830ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (U) {
3831ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               switch (size) {
3832ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 0:
3833ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op = Q ? Iop_Shl8x16 : Iop_Shl8x8;
3834ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op_add = Q ? Iop_Add8x16 : Iop_Add8x8;
3835ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op_shrn = Q ? Iop_ShrN8x16 : Iop_ShrN8x8;
3836ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op_shln = Q ? Iop_ShlN8x16 : Iop_ShlN8x8;
3837ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
3838ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 1:
3839ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op = Q ? Iop_Shl16x8 : Iop_Shl16x4;
3840ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op_add = Q ? Iop_Add16x8 : Iop_Add16x4;
3841ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op_shrn = Q ? Iop_ShrN16x8 : Iop_ShrN16x4;
3842ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op_shln = Q ? Iop_ShlN16x8 : Iop_ShlN16x4;
3843ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
3844ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 2:
3845ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op = Q ? Iop_Shl32x4 : Iop_Shl32x2;
3846ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op_add = Q ? Iop_Add32x4 : Iop_Add32x2;
3847ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op_shrn = Q ? Iop_ShrN32x4 : Iop_ShrN32x2;
3848ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op_shln = Q ? Iop_ShlN32x4 : Iop_ShlN32x2;
3849ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
3850ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 3:
3851ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op = Q ? Iop_Shl64x2 : Iop_Shl64;
3852ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op_add = Q ? Iop_Add64x2 : Iop_Add64;
3853ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op_shrn = Q ? Iop_ShrN64x2 : Iop_Shr64;
3854ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op_shln = Q ? Iop_ShlN64x2 : Iop_Shl64;
3855ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
3856ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  default:
3857ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     vassert(0);
3858ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               }
3859ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            } else {
3860ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               switch (size) {
3861ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 0:
3862ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op = Q ? Iop_Sal8x16 : Iop_Sal8x8;
3863ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op_add = Q ? Iop_Add8x16 : Iop_Add8x8;
3864ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op_shrn = Q ? Iop_ShrN8x16 : Iop_ShrN8x8;
3865ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op_shln = Q ? Iop_ShlN8x16 : Iop_ShlN8x8;
3866ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
3867ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 1:
3868ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op = Q ? Iop_Sal16x8 : Iop_Sal16x4;
3869ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op_add = Q ? Iop_Add16x8 : Iop_Add16x4;
3870ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op_shrn = Q ? Iop_ShrN16x8 : Iop_ShrN16x4;
3871ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op_shln = Q ? Iop_ShlN16x8 : Iop_ShlN16x4;
3872ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
3873ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 2:
3874ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op = Q ? Iop_Sal32x4 : Iop_Sal32x2;
3875ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op_add = Q ? Iop_Add32x4 : Iop_Add32x2;
3876ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op_shrn = Q ? Iop_ShrN32x4 : Iop_ShrN32x2;
3877ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op_shln = Q ? Iop_ShlN32x4 : Iop_ShlN32x2;
3878ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
3879ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 3:
3880ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op = Q ? Iop_Sal64x2 : Iop_Sal64x1;
3881ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op_add = Q ? Iop_Add64x2 : Iop_Add64;
3882ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op_shrn = Q ? Iop_ShrN64x2 : Iop_Shr64;
3883ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op_shln = Q ? Iop_ShlN64x2 : Iop_Shl64;
3884ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
3885ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  default:
3886ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     vassert(0);
3887ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               }
3888ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
3889ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (Q) {
3890ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               shval = newTemp(Ity_V128);
3891ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            } else {
3892ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               shval = newTemp(Ity_I64);
3893ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
3894ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* Only least significant byte from second argument is used.
3895ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               Copy this byte to the whole vector element. */
3896ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(shval, binop(op_shrn,
3897ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                binop(op_shln,
3898ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                       mkexpr(arg_n),
3899ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                       mkU8((8 << size) - 8)),
3900ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                mkU8((8 << size) - 8)));
3901ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            for (i = 0; i < size; i++) {
3902ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               old_shval = shval;
3903ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               shval = newTemp(Q ? Ity_V128 : Ity_I64);
3904ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign(shval, binop(Q ? Iop_OrV128 : Iop_Or64,
3905ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   mkexpr(old_shval),
3906ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   binop(op_shln,
3907ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                         mkexpr(old_shval),
3908ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                         mkU8(8 << i))));
3909ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
3910ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* Compute the result */
3911ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (!Q && size == 3 && U) {
3912ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign(round, binop(Q ? Iop_AndV128 : Iop_And64,
3913ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   binop(op,
3914ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                         mkexpr(arg_m),
3915ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                         unop(Iop_64to8,
3916ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                              binop(op_add,
3917ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                                    mkexpr(arg_n),
3918ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                                    mkexpr(imm_val)))),
3919ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   binop(Q ? Iop_AndV128 : Iop_And64,
3920ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                         mkexpr(imm_val),
3921ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                         binop(cmp_gt,
3922ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                               Q ? mkU128(0) : mkU64(0),
3923ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                               mkexpr(arg_n)))));
3924ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign(res, binop(op_add,
3925ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 binop(op,
3926ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                       mkexpr(arg_m),
3927ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                       unop(Iop_64to8, mkexpr(arg_n))),
3928ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 mkexpr(round)));
3929ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            } else {
3930ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign(round, binop(Q ? Iop_AndV128 : Iop_And64,
3931ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   binop(op,
3932ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                         mkexpr(arg_m),
3933ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                         binop(op_add,
3934ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                               mkexpr(arg_n),
3935ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                               mkexpr(imm_val))),
3936ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   binop(Q ? Iop_AndV128 : Iop_And64,
3937ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                         mkexpr(imm_val),
3938ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                         binop(cmp_gt,
3939ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                               Q ? mkU128(0) : mkU64(0),
3940ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                               mkexpr(arg_n)))));
3941ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign(res, binop(op_add,
3942ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 binop(op, mkexpr(arg_m), mkexpr(arg_n)),
3943ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 mkexpr(round)));
3944ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
3945ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("vrshl.%c%u %c%u, %c%u, %c%u\n",
3946ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                U ? 'u' : 's', 8 << size,
3947ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', mreg, Q ? 'q' : 'd',
3948ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                nreg);
3949ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
3950ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* VQRSHL */
3951b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            IROp op, op_rev, op_shrn, op_shln, cmp_neq, cmp_gt, op_add;
3952ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            IRTemp tmp, shval, mask, old_shval, imm_val, round;
3953ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            UInt i;
3954ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            ULong esize, imm;
3955ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            cmp_neq = Q ? Iop_CmpNEZ8x16 : Iop_CmpNEZ8x8;
3956ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            cmp_gt = Q ? Iop_CmpGT8Sx16 : Iop_CmpGT8Sx8;
3957ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            imm = 1L;
3958ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            switch (size) {
3959ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               case 0: imm = (imm <<  8) | imm; /* fall through */
3960ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               case 1: imm = (imm << 16) | imm; /* fall through */
3961ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               case 2: imm = (imm << 32) | imm; /* fall through */
3962ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               case 3: break;
3963ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               default: vassert(0);
3964ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
3965ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            imm_val = newTemp(Q ? Ity_V128 : Ity_I64);
3966ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            round = newTemp(Q ? Ity_V128 : Ity_I64);
3967ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(imm_val, Q ? mkU128(imm) : mkU64(imm));
3968ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (U) {
3969ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               switch (size) {
3970ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 0:
3971ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op = Q ? Iop_QShl8x16 : Iop_QShl8x8;
3972ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op_add = Q ? Iop_Add8x16 : Iop_Add8x8;
3973ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op_rev = Q ? Iop_Shr8x16 : Iop_Shr8x8;
3974ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op_shrn = Q ? Iop_ShrN8x16 : Iop_ShrN8x8;
3975ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op_shln = Q ? Iop_ShlN8x16 : Iop_ShlN8x8;
3976ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
3977ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 1:
3978ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op = Q ? Iop_QShl16x8 : Iop_QShl16x4;
3979ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op_add = Q ? Iop_Add16x8 : Iop_Add16x4;
3980ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op_rev = Q ? Iop_Shr16x8 : Iop_Shr16x4;
3981ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op_shrn = Q ? Iop_ShrN16x8 : Iop_ShrN16x4;
3982ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op_shln = Q ? Iop_ShlN16x8 : Iop_ShlN16x4;
3983ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
3984ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 2:
3985ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op = Q ? Iop_QShl32x4 : Iop_QShl32x2;
3986ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op_add = Q ? Iop_Add32x4 : Iop_Add32x2;
3987ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op_rev = Q ? Iop_Shr32x4 : Iop_Shr32x2;
3988ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op_shrn = Q ? Iop_ShrN32x4 : Iop_ShrN32x2;
3989ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op_shln = Q ? Iop_ShlN32x4 : Iop_ShlN32x2;
3990ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
3991ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 3:
3992ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op = Q ? Iop_QShl64x2 : Iop_QShl64x1;
3993ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op_add = Q ? Iop_Add64x2 : Iop_Add64;
3994ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op_rev = Q ? Iop_Shr64x2 : Iop_Shr64;
3995ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op_shrn = Q ? Iop_ShrN64x2 : Iop_Shr64;
3996ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op_shln = Q ? Iop_ShlN64x2 : Iop_Shl64;
3997ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
3998ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  default:
3999ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     vassert(0);
4000ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               }
4001ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            } else {
4002ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               switch (size) {
4003ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 0:
4004ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op = Q ? Iop_QSal8x16 : Iop_QSal8x8;
4005ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op_add = Q ? Iop_Add8x16 : Iop_Add8x8;
4006ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op_rev = Q ? Iop_Sar8x16 : Iop_Sar8x8;
4007ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op_shrn = Q ? Iop_ShrN8x16 : Iop_ShrN8x8;
4008ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op_shln = Q ? Iop_ShlN8x16 : Iop_ShlN8x8;
4009ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
4010ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 1:
4011ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op = Q ? Iop_QSal16x8 : Iop_QSal16x4;
4012ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op_add = Q ? Iop_Add16x8 : Iop_Add16x4;
4013ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op_rev = Q ? Iop_Sar16x8 : Iop_Sar16x4;
4014ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op_shrn = Q ? Iop_ShrN16x8 : Iop_ShrN16x4;
4015ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op_shln = Q ? Iop_ShlN16x8 : Iop_ShlN16x4;
4016ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
4017ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 2:
4018ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op = Q ? Iop_QSal32x4 : Iop_QSal32x2;
4019ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op_add = Q ? Iop_Add32x4 : Iop_Add32x2;
4020ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op_rev = Q ? Iop_Sar32x4 : Iop_Sar32x2;
4021ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op_shrn = Q ? Iop_ShrN32x4 : Iop_ShrN32x2;
4022ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op_shln = Q ? Iop_ShlN32x4 : Iop_ShlN32x2;
4023ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
4024ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 3:
4025ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op = Q ? Iop_QSal64x2 : Iop_QSal64x1;
4026ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op_add = Q ? Iop_Add64x2 : Iop_Add64;
4027ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op_rev = Q ? Iop_Sar64x2 : Iop_Sar64;
4028ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op_shrn = Q ? Iop_ShrN64x2 : Iop_Shr64;
4029ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op_shln = Q ? Iop_ShlN64x2 : Iop_Shl64;
4030ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
4031ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  default:
4032ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     vassert(0);
4033ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               }
4034ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
4035ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (Q) {
4036ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               tmp = newTemp(Ity_V128);
4037ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               shval = newTemp(Ity_V128);
4038ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               mask = newTemp(Ity_V128);
4039ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            } else {
4040ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               tmp = newTemp(Ity_I64);
4041ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               shval = newTemp(Ity_I64);
4042ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               mask = newTemp(Ity_I64);
4043ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
4044ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* Only least significant byte from second argument is used.
4045ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               Copy this byte to the whole vector element. */
4046ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(shval, binop(op_shrn,
4047ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                binop(op_shln,
4048ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                       mkexpr(arg_n),
4049ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                       mkU8((8 << size) - 8)),
4050ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                mkU8((8 << size) - 8)));
4051ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            for (i = 0; i < size; i++) {
4052ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               old_shval = shval;
4053ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               shval = newTemp(Q ? Ity_V128 : Ity_I64);
4054ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign(shval, binop(Q ? Iop_OrV128 : Iop_Or64,
4055ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   mkexpr(old_shval),
4056ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   binop(op_shln,
4057ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                         mkexpr(old_shval),
4058ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                         mkU8(8 << i))));
4059ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
4060ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* Compute the result */
4061ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(round, binop(Q ? Iop_AndV128 : Iop_And64,
4062ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                binop(op,
4063ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                      mkexpr(arg_m),
4064ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                      binop(op_add,
4065ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                            mkexpr(arg_n),
4066ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                            mkexpr(imm_val))),
4067ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                binop(Q ? Iop_AndV128 : Iop_And64,
4068ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                      mkexpr(imm_val),
4069ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                      binop(cmp_gt,
4070ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                            Q ? mkU128(0) : mkU64(0),
4071ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                            mkexpr(arg_n)))));
4072ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(res, binop(op_add,
4073ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              binop(op, mkexpr(arg_m), mkexpr(arg_n)),
4074ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              mkexpr(round)));
4075ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#ifndef DISABLE_QC_FLAG
4076ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* If shift is greater or equal to the element size and element is
4077ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               non-zero, then QC flag should be set. */
4078ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            esize = (8 << size) - 1;
4079ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            esize = (esize <<  8) | esize;
4080ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            esize = (esize << 16) | esize;
4081ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            esize = (esize << 32) | esize;
4082ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            setFlag_QC(binop(Q ? Iop_AndV128 : Iop_And64,
4083ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             binop(cmp_gt, mkexpr(shval),
4084ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                           Q ? mkU128(esize) : mkU64(esize)),
4085ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             unop(cmp_neq, mkexpr(arg_m))),
4086ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       Q ? mkU128(0) : mkU64(0),
4087ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       Q, condT);
4088ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* Othervise QC flag should be set if shift value is positive and
4089ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               result beign rightshifted the same value is not equal to left
4090ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               argument. */
4091ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(mask, binop(cmp_gt, mkexpr(shval),
4092ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               Q ? mkU128(0) : mkU64(0)));
4093ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (!Q && size == 3)
4094ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign(tmp, binop(op_rev, mkexpr(res),
4095ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                         unop(Iop_64to8, mkexpr(arg_n))));
4096ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            else
4097ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign(tmp, binop(op_rev, mkexpr(res), mkexpr(arg_n)));
4098ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            setFlag_QC(binop(Q ? Iop_AndV128 : Iop_And64,
4099ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             mkexpr(tmp), mkexpr(mask)),
4100ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       binop(Q ? Iop_AndV128 : Iop_And64,
4101ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             mkexpr(arg_m), mkexpr(mask)),
4102ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       Q, condT);
4103ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#endif
4104ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("vqrshl.%c%u %c%u, %c%u, %c%u\n",
4105ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                U ? 'u' : 's', 8 << size,
4106ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', mreg, Q ? 'q' : 'd',
4107ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                nreg);
4108ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
4109ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
4110ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 6:
4111ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* VMAX, VMIN  */
4112ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (B == 0) {
4113ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* VMAX */
4114ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            IROp op;
4115ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (U == 0) {
4116ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               switch (size) {
4117ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 0: op = Q ? Iop_Max8Sx16 : Iop_Max8Sx8; break;
4118ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 1: op = Q ? Iop_Max16Sx8 : Iop_Max16Sx4; break;
4119ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 2: op = Q ? Iop_Max32Sx4 : Iop_Max32Sx2; break;
4120ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 3: return False;
4121ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  default: vassert(0);
4122ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               }
4123ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            } else {
4124ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               switch (size) {
4125ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 0: op = Q ? Iop_Max8Ux16 : Iop_Max8Ux8; break;
4126ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 1: op = Q ? Iop_Max16Ux8 : Iop_Max16Ux4; break;
4127ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 2: op = Q ? Iop_Max32Ux4 : Iop_Max32Ux2; break;
4128ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 3: return False;
4129ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  default: vassert(0);
4130ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               }
4131ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
4132ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(res, binop(op, mkexpr(arg_n), mkexpr(arg_m)));
4133ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("vmax.%c%u %c%u, %c%u, %c%u\n",
4134ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                U ? 'u' : 's', 8 << size,
4135ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', nreg, Q ? 'q' : 'd',
4136ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                mreg);
4137ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
4138ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* VMIN */
4139ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            IROp op;
4140ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (U == 0) {
4141ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               switch (size) {
4142ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 0: op = Q ? Iop_Min8Sx16 : Iop_Min8Sx8; break;
4143ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 1: op = Q ? Iop_Min16Sx8 : Iop_Min16Sx4; break;
4144ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 2: op = Q ? Iop_Min32Sx4 : Iop_Min32Sx2; break;
4145ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 3: return False;
4146ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  default: vassert(0);
4147ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               }
4148ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            } else {
4149ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               switch (size) {
4150ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 0: op = Q ? Iop_Min8Ux16 : Iop_Min8Ux8; break;
4151ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 1: op = Q ? Iop_Min16Ux8 : Iop_Min16Ux4; break;
4152ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 2: op = Q ? Iop_Min32Ux4 : Iop_Min32Ux2; break;
4153ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 3: return False;
4154ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  default: vassert(0);
4155ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               }
4156ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
4157ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(res, binop(op, mkexpr(arg_n), mkexpr(arg_m)));
4158ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("vmin.%c%u %c%u, %c%u, %c%u\n",
4159ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                U ? 'u' : 's', 8 << size,
4160ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', nreg, Q ? 'q' : 'd',
4161ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                mreg);
4162ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
4163ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
4164ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 7:
4165ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (B == 0) {
4166ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* VABD */
4167ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            IROp op_cmp, op_sub;
4168ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            IRTemp cond;
4169ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if ((theInstr >> 23) & 1) {
4170ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               vpanic("VABDL should not be in dis_neon_data_3same\n");
4171ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
4172ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (Q) {
4173ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               switch (size) {
4174ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 0:
4175ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op_cmp = U ? Iop_CmpGT8Ux16 : Iop_CmpGT8Sx16;
4176ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op_sub = Iop_Sub8x16;
4177ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
4178ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 1:
4179ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op_cmp = U ? Iop_CmpGT16Ux8 : Iop_CmpGT16Sx8;
4180ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op_sub = Iop_Sub16x8;
4181ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
4182ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 2:
4183ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op_cmp = U ? Iop_CmpGT32Ux4 : Iop_CmpGT32Sx4;
4184ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op_sub = Iop_Sub32x4;
4185ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
4186ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 3:
4187ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     return False;
4188ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  default:
4189ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     vassert(0);
4190ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               }
4191ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            } else {
4192ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               switch (size) {
4193ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 0:
4194ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op_cmp = U ? Iop_CmpGT8Ux8 : Iop_CmpGT8Sx8;
4195ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op_sub = Iop_Sub8x8;
4196ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
4197ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 1:
4198ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op_cmp = U ? Iop_CmpGT16Ux4 : Iop_CmpGT16Sx4;
4199ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op_sub = Iop_Sub16x4;
4200ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
4201ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 2:
4202ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op_cmp = U ? Iop_CmpGT32Ux2 : Iop_CmpGT32Sx2;
4203ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op_sub = Iop_Sub32x2;
4204ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
4205ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 3:
4206ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     return False;
4207ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  default:
4208ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     vassert(0);
4209ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               }
4210ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
4211ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (Q) {
4212ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               cond = newTemp(Ity_V128);
4213ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            } else {
4214ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               cond = newTemp(Ity_I64);
4215ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
4216ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(cond, binop(op_cmp, mkexpr(arg_n), mkexpr(arg_m)));
4217ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(res, binop(Q ? Iop_OrV128 : Iop_Or64,
4218ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              binop(Q ? Iop_AndV128 : Iop_And64,
4219ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    binop(op_sub, mkexpr(arg_n),
4220ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                                  mkexpr(arg_m)),
4221ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    mkexpr(cond)),
4222ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              binop(Q ? Iop_AndV128 : Iop_And64,
4223ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    binop(op_sub, mkexpr(arg_m),
4224ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                                  mkexpr(arg_n)),
4225ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    unop(Q ? Iop_NotV128 : Iop_Not64,
4226ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                         mkexpr(cond)))));
4227ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("vabd.%c%u %c%u, %c%u, %c%u\n",
4228ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                U ? 'u' : 's', 8 << size,
4229ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', nreg, Q ? 'q' : 'd',
4230ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                mreg);
4231ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
4232ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* VABA */
4233ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            IROp op_cmp, op_sub, op_add;
4234ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            IRTemp cond, acc, tmp;
4235ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if ((theInstr >> 23) & 1) {
4236ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               vpanic("VABAL should not be in dis_neon_data_3same");
4237ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
4238ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (Q) {
4239ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               switch (size) {
4240ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 0:
4241ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op_cmp = U ? Iop_CmpGT8Ux16 : Iop_CmpGT8Sx16;
4242ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op_sub = Iop_Sub8x16;
4243ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op_add = Iop_Add8x16;
4244ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
4245ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 1:
4246ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op_cmp = U ? Iop_CmpGT16Ux8 : Iop_CmpGT16Sx8;
4247ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op_sub = Iop_Sub16x8;
4248ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op_add = Iop_Add16x8;
4249ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
4250ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 2:
4251ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op_cmp = U ? Iop_CmpGT32Ux4 : Iop_CmpGT32Sx4;
4252ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op_sub = Iop_Sub32x4;
4253ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op_add = Iop_Add32x4;
4254ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
4255ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 3:
4256ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     return False;
4257ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  default:
4258ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     vassert(0);
4259ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               }
4260ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            } else {
4261ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               switch (size) {
4262ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 0:
4263ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op_cmp = U ? Iop_CmpGT8Ux8 : Iop_CmpGT8Sx8;
4264ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op_sub = Iop_Sub8x8;
4265ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op_add = Iop_Add8x8;
4266ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
4267ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 1:
4268ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op_cmp = U ? Iop_CmpGT16Ux4 : Iop_CmpGT16Sx4;
4269ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op_sub = Iop_Sub16x4;
4270ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op_add = Iop_Add16x4;
4271ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
4272ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 2:
4273ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op_cmp = U ? Iop_CmpGT32Ux2 : Iop_CmpGT32Sx2;
4274ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op_sub = Iop_Sub32x2;
4275ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op_add = Iop_Add32x2;
4276ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
4277ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 3:
4278ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     return False;
4279ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  default:
4280ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     vassert(0);
4281ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               }
4282ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
4283ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (Q) {
4284ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               cond = newTemp(Ity_V128);
4285ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               acc = newTemp(Ity_V128);
4286ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               tmp = newTemp(Ity_V128);
4287ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign(acc, getQReg(dreg));
4288ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            } else {
4289ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               cond = newTemp(Ity_I64);
4290ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               acc = newTemp(Ity_I64);
4291ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               tmp = newTemp(Ity_I64);
4292ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign(acc, getDRegI64(dreg));
4293ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
4294ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(cond, binop(op_cmp, mkexpr(arg_n), mkexpr(arg_m)));
4295ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(tmp, binop(Q ? Iop_OrV128 : Iop_Or64,
4296ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              binop(Q ? Iop_AndV128 : Iop_And64,
4297ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    binop(op_sub, mkexpr(arg_n),
4298ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                                  mkexpr(arg_m)),
4299ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    mkexpr(cond)),
4300ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              binop(Q ? Iop_AndV128 : Iop_And64,
4301ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    binop(op_sub, mkexpr(arg_m),
4302ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                                  mkexpr(arg_n)),
4303ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    unop(Q ? Iop_NotV128 : Iop_Not64,
4304ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                         mkexpr(cond)))));
4305ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(res, binop(op_add, mkexpr(acc), mkexpr(tmp)));
4306ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("vaba.%c%u %c%u, %c%u, %c%u\n",
4307ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                U ? 'u' : 's', 8 << size,
4308ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', nreg, Q ? 'q' : 'd',
4309ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                mreg);
4310ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
4311ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
4312ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 8:
4313ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (B == 0) {
4314ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            IROp op;
4315ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (U == 0) {
4316ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* VADD  */
4317ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               switch (size) {
4318ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 0: op = Q ? Iop_Add8x16 : Iop_Add8x8; break;
4319ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 1: op = Q ? Iop_Add16x8 : Iop_Add16x4; break;
4320ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 2: op = Q ? Iop_Add32x4 : Iop_Add32x2; break;
4321ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 3: op = Q ? Iop_Add64x2 : Iop_Add64; break;
4322ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  default: vassert(0);
4323ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               }
4324ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("vadd.i%u %c%u, %c%u, %c%u\n",
4325ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   8 << size, Q ? 'q' : 'd',
4326ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   dreg, Q ? 'q' : 'd', nreg, Q ? 'q' : 'd', mreg);
4327ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            } else {
4328ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* VSUB  */
4329ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               switch (size) {
4330ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 0: op = Q ? Iop_Sub8x16 : Iop_Sub8x8; break;
4331ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 1: op = Q ? Iop_Sub16x8 : Iop_Sub16x4; break;
4332ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 2: op = Q ? Iop_Sub32x4 : Iop_Sub32x2; break;
4333ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 3: op = Q ? Iop_Sub64x2 : Iop_Sub64; break;
4334ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  default: vassert(0);
4335ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               }
4336ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("vsub.i%u %c%u, %c%u, %c%u\n",
4337ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   8 << size, Q ? 'q' : 'd',
4338ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   dreg, Q ? 'q' : 'd', nreg, Q ? 'q' : 'd', mreg);
4339ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
4340ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(res, binop(op, mkexpr(arg_n), mkexpr(arg_m)));
4341ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
4342ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            IROp op;
4343ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            switch (size) {
4344ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               case 0: op = Q ? Iop_CmpNEZ8x16 : Iop_CmpNEZ8x8; break;
4345ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               case 1: op = Q ? Iop_CmpNEZ16x8 : Iop_CmpNEZ16x4; break;
4346ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               case 2: op = Q ? Iop_CmpNEZ32x4 : Iop_CmpNEZ32x2; break;
4347ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               case 3: op = Q ? Iop_CmpNEZ64x2 : Iop_CmpwNEZ64; break;
4348ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               default: vassert(0);
4349ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
4350ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (U == 0) {
4351ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* VTST  */
4352ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign(res, unop(op, binop(Q ? Iop_AndV128 : Iop_And64,
4353ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                          mkexpr(arg_n),
4354ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                          mkexpr(arg_m))));
4355ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("vtst.%u %c%u, %c%u, %c%u\n",
4356ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   8 << size, Q ? 'q' : 'd',
4357ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   dreg, Q ? 'q' : 'd', nreg, Q ? 'q' : 'd', mreg);
4358ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            } else {
4359ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* VCEQ  */
4360ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign(res, unop(Q ? Iop_NotV128 : Iop_Not64,
4361ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                unop(op,
4362ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                     binop(Q ? Iop_XorV128 : Iop_Xor64,
4363ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                           mkexpr(arg_n),
4364ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                           mkexpr(arg_m)))));
4365ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("vceq.i%u %c%u, %c%u, %c%u\n",
4366ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   8 << size, Q ? 'q' : 'd',
4367ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   dreg, Q ? 'q' : 'd', nreg, Q ? 'q' : 'd', mreg);
4368ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
4369ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
4370ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
4371ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 9:
4372ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (B == 0) {
4373ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* VMLA, VMLS (integer) */
4374ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            IROp op, op2;
4375ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            UInt P = (theInstr >> 24) & 1;
4376ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (P) {
4377ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               switch (size) {
4378ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 0:
4379ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op = Q ? Iop_Mul8x16 : Iop_Mul8x8;
4380ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op2 = Q ? Iop_Sub8x16 : Iop_Sub8x8;
4381ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
4382ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 1:
4383ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op = Q ? Iop_Mul16x8 : Iop_Mul16x4;
4384ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op2 = Q ? Iop_Sub16x8 : Iop_Sub16x4;
4385ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
4386ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 2:
4387ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op = Q ? Iop_Mul32x4 : Iop_Mul32x2;
4388ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op2 = Q ? Iop_Sub32x4 : Iop_Sub32x2;
4389ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
4390ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 3:
4391ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     return False;
4392ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  default:
4393ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     vassert(0);
4394ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               }
4395ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            } else {
4396ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               switch (size) {
4397ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 0:
4398ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op = Q ? Iop_Mul8x16 : Iop_Mul8x8;
4399ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op2 = Q ? Iop_Add8x16 : Iop_Add8x8;
4400ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
4401ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 1:
4402ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op = Q ? Iop_Mul16x8 : Iop_Mul16x4;
4403ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op2 = Q ? Iop_Add16x8 : Iop_Add16x4;
4404ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
4405ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 2:
4406ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op = Q ? Iop_Mul32x4 : Iop_Mul32x2;
4407ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op2 = Q ? Iop_Add32x4 : Iop_Add32x2;
4408ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
4409ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 3:
4410ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     return False;
4411ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  default:
4412ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     vassert(0);
4413ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               }
4414ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
4415ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(res, binop(op2,
4416ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              Q ? getQReg(dreg) : getDRegI64(dreg),
4417ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              binop(op, mkexpr(arg_n), mkexpr(arg_m))));
4418ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("vml%c.i%u %c%u, %c%u, %c%u\n",
4419ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                P ? 's' : 'a', 8 << size,
4420ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', nreg, Q ? 'q' : 'd',
4421ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                mreg);
4422ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
4423ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* VMUL */
4424ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            IROp op;
4425ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            UInt P = (theInstr >> 24) & 1;
4426ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (P) {
4427ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               switch (size) {
4428ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 0:
4429ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op = Q ? Iop_PolynomialMul8x16 : Iop_PolynomialMul8x8;
4430ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
4431ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 1: case 2: case 3: return False;
4432ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  default: vassert(0);
4433ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               }
4434ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            } else {
4435ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               switch (size) {
4436ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 0: op = Q ? Iop_Mul8x16 : Iop_Mul8x8; break;
4437ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 1: op = Q ? Iop_Mul16x8 : Iop_Mul16x4; break;
4438ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 2: op = Q ? Iop_Mul32x4 : Iop_Mul32x2; break;
4439ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 3: return False;
4440ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  default: vassert(0);
4441ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               }
4442ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
4443ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(res, binop(op, mkexpr(arg_n), mkexpr(arg_m)));
4444ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("vmul.%c%u %c%u, %c%u, %c%u\n",
4445ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                P ? 'p' : 'i', 8 << size,
4446ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', nreg, Q ? 'q' : 'd',
4447ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                mreg);
4448ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
4449ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
4450ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 10: {
4451ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* VPMAX, VPMIN  */
4452ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         UInt P = (theInstr >> 4) & 1;
4453ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IROp op;
4454ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (Q)
4455ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            return False;
4456ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (P) {
4457ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            switch (size) {
4458ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               case 0: op = U ? Iop_PwMin8Ux8  : Iop_PwMin8Sx8; break;
4459ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               case 1: op = U ? Iop_PwMin16Ux4 : Iop_PwMin16Sx4; break;
4460ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               case 2: op = U ? Iop_PwMin32Ux2 : Iop_PwMin32Sx2; break;
4461ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               case 3: return False;
4462ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               default: vassert(0);
4463ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
4464ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
4465ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            switch (size) {
4466ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               case 0: op = U ? Iop_PwMax8Ux8  : Iop_PwMax8Sx8; break;
4467ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               case 1: op = U ? Iop_PwMax16Ux4 : Iop_PwMax16Sx4; break;
4468ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               case 2: op = U ? Iop_PwMax32Ux2 : Iop_PwMax32Sx2; break;
4469ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               case 3: return False;
4470ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               default: vassert(0);
4471ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
4472ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
4473ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(res, binop(op, mkexpr(arg_n), mkexpr(arg_m)));
4474ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("vp%s.%c%u %c%u, %c%u, %c%u\n",
4475ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             P ? "min" : "max", U ? 'u' : 's',
4476ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             8 << size, Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', nreg,
4477ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             Q ? 'q' : 'd', mreg);
4478ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
4479ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
4480ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 11:
4481ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (B == 0) {
4482ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (U == 0) {
4483ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* VQDMULH  */
4484ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IROp op ,op2;
4485ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               ULong imm;
4486ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               switch (size) {
4487ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 0: case 3:
4488ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     return False;
4489ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 1:
4490ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op = Q ? Iop_QDMulHi16Sx8 : Iop_QDMulHi16Sx4;
4491ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op2 = Q ? Iop_CmpEQ16x8 : Iop_CmpEQ16x4;
4492ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     imm = 1LL << 15;
4493ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     imm = (imm << 16) | imm;
4494ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     imm = (imm << 32) | imm;
4495ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
4496ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 2:
4497ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op = Q ? Iop_QDMulHi32Sx4 : Iop_QDMulHi32Sx2;
4498ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op2 = Q ? Iop_CmpEQ32x4 : Iop_CmpEQ32x2;
4499ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     imm = 1LL << 31;
4500ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     imm = (imm << 32) | imm;
4501ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
4502ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  default:
4503ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     vassert(0);
4504ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               }
4505ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign(res, binop(op, mkexpr(arg_n), mkexpr(arg_m)));
4506ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#ifndef DISABLE_QC_FLAG
4507ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               setFlag_QC(binop(Q ? Iop_AndV128 : Iop_And64,
4508ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                binop(op2, mkexpr(arg_n),
4509ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                           Q ? mkU128(imm) : mkU64(imm)),
4510ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                binop(op2, mkexpr(arg_m),
4511ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                           Q ? mkU128(imm) : mkU64(imm))),
4512ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          Q ? mkU128(0) : mkU64(0),
4513ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          Q, condT);
4514ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#endif
4515ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("vqdmulh.s%u %c%u, %c%u, %c%u\n",
4516ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   8 << size, Q ? 'q' : 'd',
4517ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   dreg, Q ? 'q' : 'd', nreg, Q ? 'q' : 'd', mreg);
4518ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            } else {
4519ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* VQRDMULH */
4520ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IROp op ,op2;
4521ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               ULong imm;
4522ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               switch(size) {
4523ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 0: case 3:
4524ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     return False;
4525ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 1:
4526ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     imm = 1LL << 15;
4527ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     imm = (imm << 16) | imm;
4528ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     imm = (imm << 32) | imm;
4529ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op = Q ? Iop_QRDMulHi16Sx8 : Iop_QRDMulHi16Sx4;
4530ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op2 = Q ? Iop_CmpEQ16x8 : Iop_CmpEQ16x4;
4531ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
4532ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 2:
4533ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     imm = 1LL << 31;
4534ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     imm = (imm << 32) | imm;
4535ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op = Q ? Iop_QRDMulHi32Sx4 : Iop_QRDMulHi32Sx2;
4536ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op2 = Q ? Iop_CmpEQ32x4 : Iop_CmpEQ32x2;
4537ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
4538ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  default:
4539ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     vassert(0);
4540ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               }
4541ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign(res, binop(op, mkexpr(arg_n), mkexpr(arg_m)));
4542ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#ifndef DISABLE_QC_FLAG
4543ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               setFlag_QC(binop(Q ? Iop_AndV128 : Iop_And64,
4544ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                binop(op2, mkexpr(arg_n),
4545ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                           Q ? mkU128(imm) : mkU64(imm)),
4546ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                binop(op2, mkexpr(arg_m),
4547ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                           Q ? mkU128(imm) : mkU64(imm))),
4548ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          Q ? mkU128(0) : mkU64(0),
4549ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          Q, condT);
4550ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#endif
4551ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("vqrdmulh.s%u %c%u, %c%u, %c%u\n",
4552ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   8 << size, Q ? 'q' : 'd',
4553ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   dreg, Q ? 'q' : 'd', nreg, Q ? 'q' : 'd', mreg);
4554ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
4555ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
4556ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (U == 0) {
4557ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* VPADD */
4558ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IROp op;
4559ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               if (Q)
4560ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  return False;
4561ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               switch (size) {
4562ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 0: op = Q ? Iop_PwAdd8x16 : Iop_PwAdd8x8;  break;
4563ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 1: op = Q ? Iop_PwAdd16x8 : Iop_PwAdd16x4; break;
4564ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 2: op = Q ? Iop_PwAdd32x4 : Iop_PwAdd32x2; break;
4565ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 3: return False;
4566ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  default: vassert(0);
4567ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               }
4568ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign(res, binop(op, mkexpr(arg_n), mkexpr(arg_m)));
4569ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("vpadd.i%d %c%u, %c%u, %c%u\n",
4570ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   8 << size, Q ? 'q' : 'd',
4571ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   dreg, Q ? 'q' : 'd', nreg, Q ? 'q' : 'd', mreg);
4572ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
4573ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
4574ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
4575ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Starting from here these are FP SIMD cases */
4576ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 13:
4577ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (B == 0) {
4578ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            IROp op;
4579ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (U == 0) {
4580ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               if ((C >> 1) == 0) {
4581ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  /* VADD  */
4582ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  op = Q ? Iop_Add32Fx4 : Iop_Add32Fx2 ;
4583ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  DIP("vadd.f32 %c%u, %c%u, %c%u\n",
4584ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      Q ? 'q' : 'd', dreg,
4585ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      Q ? 'q' : 'd', nreg, Q ? 'q' : 'd', mreg);
4586ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               } else {
4587ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  /* VSUB  */
4588ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  op = Q ? Iop_Sub32Fx4 : Iop_Sub32Fx2 ;
4589ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  DIP("vsub.f32 %c%u, %c%u, %c%u\n",
4590ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      Q ? 'q' : 'd', dreg,
4591ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      Q ? 'q' : 'd', nreg, Q ? 'q' : 'd', mreg);
4592ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               }
4593ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            } else {
4594ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               if ((C >> 1) == 0) {
4595ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  /* VPADD */
4596ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  if (Q)
4597ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     return False;
4598ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  op = Iop_PwAdd32Fx2;
4599ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  DIP("vpadd.f32 d%u, d%u, d%u\n", dreg, nreg, mreg);
4600ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               } else {
4601ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  /* VABD  */
4602ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  if (Q) {
4603ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     assign(res, unop(Iop_Abs32Fx4,
4604ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                      binop(Iop_Sub32Fx4,
4605ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                            mkexpr(arg_n),
4606ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                            mkexpr(arg_m))));
4607ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  } else {
4608ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     assign(res, unop(Iop_Abs32Fx2,
4609ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                      binop(Iop_Sub32Fx2,
4610ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                            mkexpr(arg_n),
4611ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                            mkexpr(arg_m))));
4612ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  }
4613ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  DIP("vabd.f32 %c%u, %c%u, %c%u\n",
4614ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      Q ? 'q' : 'd', dreg,
4615ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      Q ? 'q' : 'd', nreg, Q ? 'q' : 'd', mreg);
4616ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  break;
4617ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               }
4618ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
4619ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(res, binop(op, mkexpr(arg_n), mkexpr(arg_m)));
4620ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
4621ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (U == 0) {
4622ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* VMLA, VMLS  */
4623ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IROp op, op2;
4624ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               UInt P = (theInstr >> 21) & 1;
4625ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               if (P) {
4626ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  switch (size & 1) {
4627ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     case 0:
4628ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        op = Q ? Iop_Mul32Fx4 : Iop_Mul32Fx2;
4629ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        op2 = Q ? Iop_Sub32Fx4 : Iop_Sub32Fx2;
4630ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        break;
4631ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     case 1: return False;
4632ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     default: vassert(0);
4633ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  }
4634ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               } else {
4635ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  switch (size & 1) {
4636ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     case 0:
4637ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        op = Q ? Iop_Mul32Fx4 : Iop_Mul32Fx2;
4638ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        op2 = Q ? Iop_Add32Fx4 : Iop_Add32Fx2;
4639ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        break;
4640ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     case 1: return False;
4641ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     default: vassert(0);
4642ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  }
4643ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               }
4644ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign(res, binop(op2,
4645ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 Q ? getQReg(dreg) : getDRegI64(dreg),
4646ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 binop(op, mkexpr(arg_n), mkexpr(arg_m))));
4647ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4648ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("vml%c.f32 %c%u, %c%u, %c%u\n",
4649ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   P ? 's' : 'a', Q ? 'q' : 'd',
4650ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   dreg, Q ? 'q' : 'd', nreg, Q ? 'q' : 'd', mreg);
4651ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            } else {
4652ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* VMUL  */
4653ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IROp op;
4654ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               if ((C >> 1) != 0)
4655ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  return False;
4656ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               op = Q ? Iop_Mul32Fx4 : Iop_Mul32Fx2 ;
4657ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign(res, binop(op, mkexpr(arg_n), mkexpr(arg_m)));
4658ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("vmul.f32 %c%u, %c%u, %c%u\n",
4659ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   Q ? 'q' : 'd', dreg,
4660ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   Q ? 'q' : 'd', nreg, Q ? 'q' : 'd', mreg);
4661ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
4662ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
4663ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
4664ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 14:
4665ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (B == 0) {
4666ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (U == 0) {
4667ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               if ((C >> 1) == 0) {
4668ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  /* VCEQ  */
4669ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  IROp op;
4670ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  if ((theInstr >> 20) & 1)
4671ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     return False;
4672ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  op = Q ? Iop_CmpEQ32Fx4 : Iop_CmpEQ32Fx2;
4673ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  assign(res, binop(op, mkexpr(arg_n), mkexpr(arg_m)));
4674ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  DIP("vceq.f32 %c%u, %c%u, %c%u\n",
4675ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      Q ? 'q' : 'd', dreg,
4676ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      Q ? 'q' : 'd', nreg, Q ? 'q' : 'd', mreg);
4677ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               } else {
4678ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  return False;
4679ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               }
4680ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            } else {
4681ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               if ((C >> 1) == 0) {
4682ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  /* VCGE  */
4683ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  IROp op;
4684ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  if ((theInstr >> 20) & 1)
4685ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     return False;
4686ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  op = Q ? Iop_CmpGE32Fx4 : Iop_CmpGE32Fx2;
4687ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  assign(res, binop(op, mkexpr(arg_n), mkexpr(arg_m)));
4688ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  DIP("vcge.f32 %c%u, %c%u, %c%u\n",
4689ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      Q ? 'q' : 'd', dreg,
4690ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      Q ? 'q' : 'd', nreg, Q ? 'q' : 'd', mreg);
4691ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               } else {
4692ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  /* VCGT  */
4693ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  IROp op;
4694ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  if ((theInstr >> 20) & 1)
4695ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     return False;
4696ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  op = Q ? Iop_CmpGT32Fx4 : Iop_CmpGT32Fx2;
4697ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  assign(res, binop(op, mkexpr(arg_n), mkexpr(arg_m)));
4698ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  DIP("vcgt.f32 %c%u, %c%u, %c%u\n",
4699ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      Q ? 'q' : 'd', dreg,
4700ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      Q ? 'q' : 'd', nreg, Q ? 'q' : 'd', mreg);
4701ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               }
4702ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
4703ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
4704ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (U == 1) {
4705ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* VACGE, VACGT */
4706ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               UInt op_bit = (theInstr >> 21) & 1;
4707ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IROp op, op2;
4708ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               op2 = Q ? Iop_Abs32Fx4 : Iop_Abs32Fx2;
4709ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               if (op_bit) {
4710ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  op = Q ? Iop_CmpGT32Fx4 : Iop_CmpGT32Fx2;
4711ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  assign(res, binop(op,
4712ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    unop(op2, mkexpr(arg_n)),
4713ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    unop(op2, mkexpr(arg_m))));
4714ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               } else {
4715ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  op = Q ? Iop_CmpGE32Fx4 : Iop_CmpGE32Fx2;
4716ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  assign(res, binop(op,
4717ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    unop(op2, mkexpr(arg_n)),
4718ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    unop(op2, mkexpr(arg_m))));
4719ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               }
4720ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("vacg%c.f32 %c%u, %c%u, %c%u\n", op_bit ? 't' : 'e',
4721ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', nreg,
4722ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   Q ? 'q' : 'd', mreg);
4723ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
4724ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
4725ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
4726ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 15:
4727ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (B == 0) {
4728ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (U == 0) {
4729ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* VMAX, VMIN  */
4730ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IROp op;
4731ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               if ((theInstr >> 20) & 1)
4732ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  return False;
4733ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               if ((theInstr >> 21) & 1) {
4734ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  op = Q ? Iop_Min32Fx4 : Iop_Min32Fx2;
4735ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  DIP("vmin.f32 %c%u, %c%u, %c%u\n", Q ? 'q' : 'd', dreg,
4736ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      Q ? 'q' : 'd', nreg, Q ? 'q' : 'd', mreg);
4737ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               } else {
4738ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  op = Q ? Iop_Max32Fx4 : Iop_Max32Fx2;
4739ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  DIP("vmax.f32 %c%u, %c%u, %c%u\n", Q ? 'q' : 'd', dreg,
4740ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      Q ? 'q' : 'd', nreg, Q ? 'q' : 'd', mreg);
4741ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               }
4742ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign(res, binop(op, mkexpr(arg_n), mkexpr(arg_m)));
4743ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            } else {
4744ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* VPMAX, VPMIN   */
4745ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IROp op;
4746ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               if (Q)
4747ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  return False;
4748ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               if ((theInstr >> 20) & 1)
4749ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  return False;
4750ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               if ((theInstr >> 21) & 1) {
4751ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  op = Iop_PwMin32Fx2;
4752ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  DIP("vpmin.f32 d%u, d%u, d%u\n", dreg, nreg, mreg);
4753ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               } else {
4754ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  op = Iop_PwMax32Fx2;
4755ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  DIP("vpmax.f32 d%u, d%u, d%u\n", dreg, nreg, mreg);
4756ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               }
4757ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign(res, binop(op, mkexpr(arg_n), mkexpr(arg_m)));
4758ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
4759ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
4760ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (U == 0) {
4761ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               if ((C >> 1) == 0) {
4762ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  /* VRECPS */
4763ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  if ((theInstr >> 20) & 1)
4764ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     return False;
4765ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  assign(res, binop(Q ? Iop_Recps32Fx4 : Iop_Recps32Fx2,
4766ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    mkexpr(arg_n),
4767ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    mkexpr(arg_m)));
4768ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  DIP("vrecps.f32 %c%u, %c%u, %c%u\n", Q ? 'q' : 'd', dreg,
4769ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      Q ? 'q' : 'd', nreg, Q ? 'q' : 'd', mreg);
4770ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               } else {
4771ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  /* VRSQRTS  */
4772ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  if ((theInstr >> 20) & 1)
4773ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     return False;
4774ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  assign(res, binop(Q ? Iop_Rsqrts32Fx4 : Iop_Rsqrts32Fx2,
4775ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    mkexpr(arg_n),
4776ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    mkexpr(arg_m)));
4777ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  DIP("vrsqrts.f32 %c%u, %c%u, %c%u\n", Q ? 'q' : 'd', dreg,
4778ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      Q ? 'q' : 'd', nreg, Q ? 'q' : 'd', mreg);
4779ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               }
4780ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
4781ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
4782ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
4783ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
4784ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4785ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (Q) {
4786ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putQReg(dreg, mkexpr(res), condT);
4787ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
4788ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putDRegI64(dreg, mkexpr(res), condT);
4789ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
4790ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4791ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return True;
4792ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
4793ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4794ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* A7.4.2 Three registers of different length */
4795ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
4796ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownBool dis_neon_data_3diff ( UInt theInstr, IRTemp condT )
4797ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
4798ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt A = (theInstr >> 8) & 0xf;
4799ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt B = (theInstr >> 20) & 3;
4800ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt U = (theInstr >> 24) & 1;
4801ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt P = (theInstr >> 9) & 1;
4802ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt mreg = get_neon_m_regno(theInstr);
4803ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt nreg = get_neon_n_regno(theInstr);
4804ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt dreg = get_neon_d_regno(theInstr);
4805ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt size = B;
4806ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ULong imm;
4807ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp res, arg_m, arg_n, cond, tmp;
4808ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IROp cvt, cvt2, cmp, op, op2, sh, add;
4809ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (A) {
4810ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0: case 1: case 2: case 3:
4811ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* VADDL, VADDW, VSUBL, VSUBW */
4812ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (dreg & 1)
4813ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            return False;
4814ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         dreg >>= 1;
4815ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         size = B;
4816ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         switch (size) {
4817ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0:
4818b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               cvt = U ? Iop_Widen8Uto16x8 : Iop_Widen8Sto16x8;
4819ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               op = (A & 2) ? Iop_Sub16x8 : Iop_Add16x8;
4820ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4821ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 1:
4822b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               cvt = U ? Iop_Widen16Uto32x4 : Iop_Widen16Sto32x4;
4823ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               op = (A & 2) ? Iop_Sub32x4 : Iop_Add32x4;
4824ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4825ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 2:
4826b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               cvt = U ? Iop_Widen32Uto64x2 : Iop_Widen32Sto64x2;
4827ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               op = (A & 2) ? Iop_Sub64x2 : Iop_Add64x2;
4828ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4829ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 3:
4830ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               return False;
4831ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            default:
4832ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               vassert(0);
4833ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
4834ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         arg_n = newTemp(Ity_V128);
4835ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         arg_m = newTemp(Ity_V128);
4836ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (A & 1) {
4837ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (nreg & 1)
4838ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               return False;
4839ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            nreg >>= 1;
4840ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(arg_n, getQReg(nreg));
4841ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
4842ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(arg_n, unop(cvt, getDRegI64(nreg)));
4843ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
4844ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(arg_m, unop(cvt, getDRegI64(mreg)));
4845ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putQReg(dreg, binop(op, mkexpr(arg_n), mkexpr(arg_m)),
4846ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       condT);
4847ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("v%s%c.%c%u q%u, %c%u, d%u\n", (A & 2) ? "sub" : "add",
4848ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             (A & 1) ? 'w' : 'l', U ? 'u' : 's', 8 << size, dreg,
4849ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             (A & 1) ? 'q' : 'd', nreg, mreg);
4850ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         return True;
4851ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 4:
4852ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* VADDHN, VRADDHN */
4853ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (mreg & 1)
4854ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            return False;
4855ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         mreg >>= 1;
4856ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (nreg & 1)
4857ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            return False;
4858ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         nreg >>= 1;
4859ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         size = B;
4860ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         switch (size) {
4861ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0:
4862ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               op = Iop_Add16x8;
4863b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               cvt = Iop_NarrowUn16to8x8;
4864ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               sh = Iop_ShrN16x8;
4865ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               imm = 1U << 7;
4866ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               imm = (imm << 16) | imm;
4867ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               imm = (imm << 32) | imm;
4868ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4869ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 1:
4870ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               op = Iop_Add32x4;
4871b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               cvt = Iop_NarrowUn32to16x4;
4872ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               sh = Iop_ShrN32x4;
4873ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               imm = 1U << 15;
4874ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               imm = (imm << 32) | imm;
4875ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4876ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 2:
4877ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               op = Iop_Add64x2;
4878b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               cvt = Iop_NarrowUn64to32x2;
4879ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               sh = Iop_ShrN64x2;
4880ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               imm = 1U << 31;
4881ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4882ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 3:
4883ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               return False;
4884ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            default:
4885ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               vassert(0);
4886ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
4887ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         tmp = newTemp(Ity_V128);
4888ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         res = newTemp(Ity_V128);
4889ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(tmp, binop(op, getQReg(nreg), getQReg(mreg)));
4890ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (U) {
4891ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* VRADDHN */
4892ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(res, binop(op, mkexpr(tmp),
4893ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     binop(Iop_64HLtoV128, mkU64(imm), mkU64(imm))));
4894ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
4895ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(res, mkexpr(tmp));
4896ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
4897ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putDRegI64(dreg, unop(cvt, binop(sh, mkexpr(res), mkU8(8 << size))),
4898ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    condT);
4899ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("v%saddhn.i%u d%u, q%u, q%u\n", U ? "r" : "", 16 << size, dreg,
4900ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             nreg, mreg);
4901ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         return True;
4902ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 5:
4903ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* VABAL */
4904ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (!((theInstr >> 23) & 1)) {
4905ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            vpanic("VABA should not be in dis_neon_data_3diff\n");
4906ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
4907ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (dreg & 1)
4908ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            return False;
4909ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         dreg >>= 1;
4910ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         switch (size) {
4911ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0:
4912ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               cmp = U ? Iop_CmpGT8Ux8 : Iop_CmpGT8Sx8;
4913b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               cvt = U ? Iop_Widen8Uto16x8 : Iop_Widen8Sto16x8;
4914b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               cvt2 = Iop_Widen8Sto16x8;
4915ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               op = Iop_Sub16x8;
4916ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               op2 = Iop_Add16x8;
4917ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4918ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 1:
4919ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               cmp = U ? Iop_CmpGT16Ux4 : Iop_CmpGT16Sx4;
4920b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               cvt = U ? Iop_Widen16Uto32x4 : Iop_Widen16Sto32x4;
4921b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               cvt2 = Iop_Widen16Sto32x4;
4922ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               op = Iop_Sub32x4;
4923ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               op2 = Iop_Add32x4;
4924ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4925ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 2:
4926ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               cmp = U ? Iop_CmpGT32Ux2 : Iop_CmpGT32Sx2;
4927b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               cvt = U ? Iop_Widen32Uto64x2 : Iop_Widen32Sto64x2;
4928b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               cvt2 = Iop_Widen32Sto64x2;
4929ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               op = Iop_Sub64x2;
4930ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               op2 = Iop_Add64x2;
4931ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4932ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 3:
4933ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               return False;
4934ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            default:
4935ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               vassert(0);
4936ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
4937ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         arg_n = newTemp(Ity_V128);
4938ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         arg_m = newTemp(Ity_V128);
4939ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         cond = newTemp(Ity_V128);
4940ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         res = newTemp(Ity_V128);
4941ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(arg_n, unop(cvt, getDRegI64(nreg)));
4942ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(arg_m, unop(cvt, getDRegI64(mreg)));
4943ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(cond, unop(cvt2, binop(cmp, getDRegI64(nreg),
4944ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                            getDRegI64(mreg))));
4945ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(res, binop(op2,
4946ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           binop(Iop_OrV128,
4947ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 binop(Iop_AndV128,
4948ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                       binop(op, mkexpr(arg_n), mkexpr(arg_m)),
4949ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                       mkexpr(cond)),
4950ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 binop(Iop_AndV128,
4951ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                       binop(op, mkexpr(arg_m), mkexpr(arg_n)),
4952ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                       unop(Iop_NotV128, mkexpr(cond)))),
4953ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           getQReg(dreg)));
4954ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putQReg(dreg, mkexpr(res), condT);
4955ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("vabal.%c%u q%u, d%u, d%u\n", U ? 'u' : 's', 8 << size, dreg,
4956ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             nreg, mreg);
4957ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         return True;
4958ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 6:
4959ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* VSUBHN, VRSUBHN */
4960ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (mreg & 1)
4961ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            return False;
4962ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         mreg >>= 1;
4963ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (nreg & 1)
4964ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            return False;
4965ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         nreg >>= 1;
4966ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         size = B;
4967ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         switch (size) {
4968ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0:
4969ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               op = Iop_Sub16x8;
4970ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               op2 = Iop_Add16x8;
4971b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               cvt = Iop_NarrowUn16to8x8;
4972ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               sh = Iop_ShrN16x8;
4973ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               imm = 1U << 7;
4974ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               imm = (imm << 16) | imm;
4975ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               imm = (imm << 32) | imm;
4976ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4977ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 1:
4978ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               op = Iop_Sub32x4;
4979ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               op2 = Iop_Add32x4;
4980b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               cvt = Iop_NarrowUn32to16x4;
4981ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               sh = Iop_ShrN32x4;
4982ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               imm = 1U << 15;
4983ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               imm = (imm << 32) | imm;
4984ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4985ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 2:
4986ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               op = Iop_Sub64x2;
4987ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               op2 = Iop_Add64x2;
4988b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               cvt = Iop_NarrowUn64to32x2;
4989ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               sh = Iop_ShrN64x2;
4990ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               imm = 1U << 31;
4991ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4992ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 3:
4993ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               return False;
4994ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            default:
4995ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               vassert(0);
4996ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
4997ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         tmp = newTemp(Ity_V128);
4998ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         res = newTemp(Ity_V128);
4999ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(tmp, binop(op, getQReg(nreg), getQReg(mreg)));
5000ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (U) {
5001ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* VRSUBHN */
5002ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(res, binop(op2, mkexpr(tmp),
5003ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     binop(Iop_64HLtoV128, mkU64(imm), mkU64(imm))));
5004ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
5005ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(res, mkexpr(tmp));
5006ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
5007ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putDRegI64(dreg, unop(cvt, binop(sh, mkexpr(res), mkU8(8 << size))),
5008ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    condT);
5009ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("v%ssubhn.i%u d%u, q%u, q%u\n", U ? "r" : "", 16 << size, dreg,
5010ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             nreg, mreg);
5011ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         return True;
5012ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 7:
5013ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* VABDL */
5014ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (!((theInstr >> 23) & 1)) {
5015ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            vpanic("VABL should not be in dis_neon_data_3diff\n");
5016ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
5017ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (dreg & 1)
5018ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            return False;
5019ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         dreg >>= 1;
5020ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         switch (size) {
5021ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0:
5022ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               cmp = U ? Iop_CmpGT8Ux8 : Iop_CmpGT8Sx8;
5023b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               cvt = U ? Iop_Widen8Uto16x8 : Iop_Widen8Sto16x8;
5024b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               cvt2 = Iop_Widen8Sto16x8;
5025ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               op = Iop_Sub16x8;
5026ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5027ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 1:
5028ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               cmp = U ? Iop_CmpGT16Ux4 : Iop_CmpGT16Sx4;
5029b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               cvt = U ? Iop_Widen16Uto32x4 : Iop_Widen16Sto32x4;
5030b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               cvt2 = Iop_Widen16Sto32x4;
5031ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               op = Iop_Sub32x4;
5032ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5033ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 2:
5034ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               cmp = U ? Iop_CmpGT32Ux2 : Iop_CmpGT32Sx2;
5035b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               cvt = U ? Iop_Widen32Uto64x2 : Iop_Widen32Sto64x2;
5036b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               cvt2 = Iop_Widen32Sto64x2;
5037ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               op = Iop_Sub64x2;
5038ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5039ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 3:
5040ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               return False;
5041ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            default:
5042ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               vassert(0);
5043ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
5044ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         arg_n = newTemp(Ity_V128);
5045ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         arg_m = newTemp(Ity_V128);
5046ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         cond = newTemp(Ity_V128);
5047ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         res = newTemp(Ity_V128);
5048ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(arg_n, unop(cvt, getDRegI64(nreg)));
5049ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(arg_m, unop(cvt, getDRegI64(mreg)));
5050ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(cond, unop(cvt2, binop(cmp, getDRegI64(nreg),
5051ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                            getDRegI64(mreg))));
5052ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(res, binop(Iop_OrV128,
5053ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           binop(Iop_AndV128,
5054ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 binop(op, mkexpr(arg_n), mkexpr(arg_m)),
5055ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 mkexpr(cond)),
5056ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           binop(Iop_AndV128,
5057ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 binop(op, mkexpr(arg_m), mkexpr(arg_n)),
5058ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 unop(Iop_NotV128, mkexpr(cond)))));
5059ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putQReg(dreg, mkexpr(res), condT);
5060ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("vabdl.%c%u q%u, d%u, d%u\n", U ? 'u' : 's', 8 << size, dreg,
5061ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             nreg, mreg);
5062ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         return True;
5063ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 8:
5064ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 10:
5065ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* VMLAL, VMLSL (integer) */
5066ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (dreg & 1)
5067ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            return False;
5068ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         dreg >>= 1;
5069ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         size = B;
5070ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         switch (size) {
5071ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0:
5072ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               op = U ? Iop_Mull8Ux8 : Iop_Mull8Sx8;
5073ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               op2 = P ? Iop_Sub16x8 : Iop_Add16x8;
5074ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5075ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 1:
5076ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               op = U ? Iop_Mull16Ux4 : Iop_Mull16Sx4;
5077ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               op2 = P ? Iop_Sub32x4 : Iop_Add32x4;
5078ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5079ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 2:
5080ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               op = U ? Iop_Mull32Ux2 : Iop_Mull32Sx2;
5081ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               op2 = P ? Iop_Sub64x2 : Iop_Add64x2;
5082ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5083ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 3:
5084ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               return False;
5085ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            default:
5086ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               vassert(0);
5087ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
5088ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         res = newTemp(Ity_V128);
5089ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(res, binop(op, getDRegI64(nreg),getDRegI64(mreg)));
5090ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putQReg(dreg, binop(op2, getQReg(dreg), mkexpr(res)), condT);
5091ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("vml%cl.%c%u q%u, d%u, d%u\n", P ? 's' : 'a', U ? 'u' : 's',
5092ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             8 << size, dreg, nreg, mreg);
5093ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         return True;
5094ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 9:
5095ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 11:
5096ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* VQDMLAL, VQDMLSL */
5097ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (U)
5098ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            return False;
5099ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (dreg & 1)
5100ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            return False;
5101ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         dreg >>= 1;
5102ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         size = B;
5103ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         switch (size) {
5104ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0: case 3:
5105ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               return False;
5106ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 1:
5107ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               op = Iop_QDMulLong16Sx4;
5108ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               cmp = Iop_CmpEQ16x4;
5109ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               add = P ? Iop_QSub32Sx4 : Iop_QAdd32Sx4;
5110ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               op2 = P ? Iop_Sub32x4 : Iop_Add32x4;
5111ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               imm = 1LL << 15;
5112ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               imm = (imm << 16) | imm;
5113ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               imm = (imm << 32) | imm;
5114ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5115ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 2:
5116ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               op = Iop_QDMulLong32Sx2;
5117ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               cmp = Iop_CmpEQ32x2;
5118ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               add = P ? Iop_QSub64Sx2 : Iop_QAdd64Sx2;
5119ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               op2 = P ? Iop_Sub64x2 : Iop_Add64x2;
5120ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               imm = 1LL << 31;
5121ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               imm = (imm << 32) | imm;
5122ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5123ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            default:
5124ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               vassert(0);
5125ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
5126ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         res = newTemp(Ity_V128);
5127ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         tmp = newTemp(Ity_V128);
5128ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(res, binop(op, getDRegI64(nreg), getDRegI64(mreg)));
5129ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#ifndef DISABLE_QC_FLAG
5130ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(tmp, binop(op2, getQReg(dreg), mkexpr(res)));
5131ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         setFlag_QC(mkexpr(tmp), binop(add, getQReg(dreg), mkexpr(res)),
5132ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    True, condT);
5133ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         setFlag_QC(binop(Iop_And64,
5134ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          binop(cmp, getDRegI64(nreg), mkU64(imm)),
5135ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          binop(cmp, getDRegI64(mreg), mkU64(imm))),
5136ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    mkU64(0),
5137ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    False, condT);
5138ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#endif
5139ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putQReg(dreg, binop(add, getQReg(dreg), mkexpr(res)), condT);
5140ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("vqdml%cl.s%u q%u, d%u, d%u\n", P ? 's' : 'a', 8 << size, dreg,
5141ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             nreg, mreg);
5142ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         return True;
5143ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 12:
5144ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 14:
5145ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* VMULL (integer or polynomial) */
5146ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (dreg & 1)
5147ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            return False;
5148ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         dreg >>= 1;
5149ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         size = B;
5150ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         switch (size) {
5151ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0:
5152ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               op = (U) ? Iop_Mull8Ux8 : Iop_Mull8Sx8;
5153ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               if (P)
5154ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  op = Iop_PolynomialMull8x8;
5155ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5156ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 1:
5157ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               op = (U) ? Iop_Mull16Ux4 : Iop_Mull16Sx4;
5158ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5159ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 2:
5160ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               op = (U) ? Iop_Mull32Ux2 : Iop_Mull32Sx2;
5161ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5162ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            default:
5163ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               vassert(0);
5164ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
5165ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putQReg(dreg, binop(op, getDRegI64(nreg),
5166ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 getDRegI64(mreg)), condT);
5167ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("vmull.%c%u q%u, d%u, d%u\n", P ? 'p' : (U ? 'u' : 's'),
5168ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               8 << size, dreg, nreg, mreg);
5169ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         return True;
5170ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 13:
5171ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* VQDMULL */
5172ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (U)
5173ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            return False;
5174ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (dreg & 1)
5175ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            return False;
5176ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         dreg >>= 1;
5177ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         size = B;
5178ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         switch (size) {
5179ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0:
5180ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 3:
5181ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               return False;
5182ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 1:
5183ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               op = Iop_QDMulLong16Sx4;
5184ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               op2 = Iop_CmpEQ16x4;
5185ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               imm = 1LL << 15;
5186ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               imm = (imm << 16) | imm;
5187ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               imm = (imm << 32) | imm;
5188ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5189ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 2:
5190ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               op = Iop_QDMulLong32Sx2;
5191ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               op2 = Iop_CmpEQ32x2;
5192ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               imm = 1LL << 31;
5193ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               imm = (imm << 32) | imm;
5194ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5195ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            default:
5196ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               vassert(0);
5197ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
5198ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putQReg(dreg, binop(op, getDRegI64(nreg), getDRegI64(mreg)),
5199ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               condT);
5200ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#ifndef DISABLE_QC_FLAG
5201ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         setFlag_QC(binop(Iop_And64,
5202ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          binop(op2, getDRegI64(nreg), mkU64(imm)),
5203ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          binop(op2, getDRegI64(mreg), mkU64(imm))),
5204ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    mkU64(0),
5205ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    False, condT);
5206ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#endif
5207ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("vqdmull.s%u q%u, d%u, d%u\n", 8 << size, dreg, nreg, mreg);
5208ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         return True;
5209ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default:
5210ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         return False;
5211ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
5212ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return False;
5213ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
5214ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5215ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* A7.4.3 Two registers and a scalar */
5216ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
5217ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownBool dis_neon_data_2reg_and_scalar ( UInt theInstr, IRTemp condT )
5218ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
5219ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  define INSN(_bMax,_bMin)  SLICE_UInt(theInstr, (_bMax), (_bMin))
5220ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt U = INSN(24,24);
5221ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt dreg = get_neon_d_regno(theInstr & ~(1 << 6));
5222ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt nreg = get_neon_n_regno(theInstr & ~(1 << 6));
5223ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt mreg = get_neon_m_regno(theInstr & ~(1 << 6));
5224ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt size = INSN(21,20);
5225ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt index;
5226ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt Q = INSN(24,24);
5227ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5228ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (INSN(27,25) != 1 || INSN(23,23) != 1
5229ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       || INSN(6,6) != 1 || INSN(4,4) != 0)
5230ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return False;
5231ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5232ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* VMLA, VMLS (scalar)  */
5233ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if ((INSN(11,8) & BITS4(1,0,1,0)) == BITS4(0,0,0,0)) {
5234ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp res, arg_m, arg_n;
5235ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IROp dup, get, op, op2, add, sub;
5236ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (Q) {
5237ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if ((dreg & 1) || (nreg & 1))
5238ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            return False;
5239ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         dreg >>= 1;
5240ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         nreg >>= 1;
5241ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         res = newTemp(Ity_V128);
5242ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         arg_m = newTemp(Ity_V128);
5243ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         arg_n = newTemp(Ity_V128);
5244ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(arg_n, getQReg(nreg));
5245ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         switch(size) {
5246ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 1:
5247ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               dup = Iop_Dup16x8;
5248ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               get = Iop_GetElem16x4;
5249ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               index = mreg >> 3;
5250ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               mreg &= 7;
5251ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5252ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 2:
5253ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               dup = Iop_Dup32x4;
5254ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               get = Iop_GetElem32x2;
5255ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               index = mreg >> 4;
5256ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               mreg &= 0xf;
5257ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5258ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0:
5259ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 3:
5260ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               return False;
5261ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            default:
5262ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               vassert(0);
5263ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
5264ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(arg_m, unop(dup, binop(get, getDRegI64(mreg), mkU8(index))));
5265ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
5266ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         res = newTemp(Ity_I64);
5267ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         arg_m = newTemp(Ity_I64);
5268ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         arg_n = newTemp(Ity_I64);
5269ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(arg_n, getDRegI64(nreg));
5270ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         switch(size) {
5271ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 1:
5272ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               dup = Iop_Dup16x4;
5273ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               get = Iop_GetElem16x4;
5274ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               index = mreg >> 3;
5275ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               mreg &= 7;
5276ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5277ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 2:
5278ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               dup = Iop_Dup32x2;
5279ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               get = Iop_GetElem32x2;
5280ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               index = mreg >> 4;
5281ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               mreg &= 0xf;
5282ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5283ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0:
5284ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 3:
5285ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               return False;
5286ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            default:
5287ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               vassert(0);
5288ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
5289ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(arg_m, unop(dup, binop(get, getDRegI64(mreg), mkU8(index))));
5290ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
5291ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (INSN(8,8)) {
5292ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         switch (size) {
5293ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 2:
5294ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               op = Q ? Iop_Mul32Fx4 : Iop_Mul32Fx2;
5295ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               add = Q ? Iop_Add32Fx4 : Iop_Add32Fx2;
5296ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               sub = Q ? Iop_Sub32Fx4 : Iop_Sub32Fx2;
5297ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5298ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0:
5299ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 1:
5300ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 3:
5301ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               return False;
5302ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            default:
5303ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               vassert(0);
5304ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
5305ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
5306ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         switch (size) {
5307ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 1:
5308ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               op = Q ? Iop_Mul16x8 : Iop_Mul16x4;
5309ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               add = Q ? Iop_Add16x8 : Iop_Add16x4;
5310ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               sub = Q ? Iop_Sub16x8 : Iop_Sub16x4;
5311ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5312ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 2:
5313ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               op = Q ? Iop_Mul32x4 : Iop_Mul32x2;
5314ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               add = Q ? Iop_Add32x4 : Iop_Add32x2;
5315ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               sub = Q ? Iop_Sub32x4 : Iop_Sub32x2;
5316ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5317ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0:
5318ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 3:
5319ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               return False;
5320ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            default:
5321ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               vassert(0);
5322ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
5323ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
5324ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      op2 = INSN(10,10) ? sub : add;
5325ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(res, binop(op, mkexpr(arg_n), mkexpr(arg_m)));
5326ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (Q)
5327ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putQReg(dreg, binop(op2, getQReg(dreg), mkexpr(res)),
5328ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               condT);
5329ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      else
5330ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putDRegI64(dreg, binop(op2, getDRegI64(dreg), mkexpr(res)),
5331ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    condT);
5332ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("vml%c.%c%u %c%u, %c%u, d%u[%u]\n", INSN(10,10) ? 's' : 'a',
5333ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            INSN(8,8) ? 'f' : 'i', 8 << size,
5334ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', nreg, mreg, index);
5335ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return True;
5336ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
5337ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5338ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* VMLAL, VMLSL (scalar)   */
5339ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if ((INSN(11,8) & BITS4(1,0,1,1)) == BITS4(0,0,1,0)) {
5340ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp res, arg_m, arg_n;
5341ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IROp dup, get, op, op2, add, sub;
5342ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (dreg & 1)
5343ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         return False;
5344ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      dreg >>= 1;
5345ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      res = newTemp(Ity_V128);
5346ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      arg_m = newTemp(Ity_I64);
5347ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      arg_n = newTemp(Ity_I64);
5348ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(arg_n, getDRegI64(nreg));
5349ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      switch(size) {
5350ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 1:
5351ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            dup = Iop_Dup16x4;
5352ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            get = Iop_GetElem16x4;
5353ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            index = mreg >> 3;
5354ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            mreg &= 7;
5355ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
5356ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 2:
5357ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            dup = Iop_Dup32x2;
5358ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            get = Iop_GetElem32x2;
5359ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            index = mreg >> 4;
5360ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            mreg &= 0xf;
5361ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
5362ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0:
5363ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 3:
5364ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            return False;
5365ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         default:
5366ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            vassert(0);
5367ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
5368ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(arg_m, unop(dup, binop(get, getDRegI64(mreg), mkU8(index))));
5369ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      switch (size) {
5370ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 1:
5371ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            op = U ? Iop_Mull16Ux4 : Iop_Mull16Sx4;
5372ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            add = Iop_Add32x4;
5373ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            sub = Iop_Sub32x4;
5374ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
5375ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 2:
5376ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            op = U ? Iop_Mull32Ux2 : Iop_Mull32Sx2;
5377ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            add = Iop_Add64x2;
5378ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            sub = Iop_Sub64x2;
5379ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
5380ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0:
5381ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 3:
5382ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            return False;
5383ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         default:
5384ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            vassert(0);
5385ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
5386ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      op2 = INSN(10,10) ? sub : add;
5387ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(res, binop(op, mkexpr(arg_n), mkexpr(arg_m)));
5388ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putQReg(dreg, binop(op2, getQReg(dreg), mkexpr(res)), condT);
5389ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("vml%cl.%c%u q%u, d%u, d%u[%u]\n",
5390ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          INSN(10,10) ? 's' : 'a', U ? 'u' : 's',
5391ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          8 << size, dreg, nreg, mreg, index);
5392ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return True;
5393ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
5394ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5395ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* VQDMLAL, VQDMLSL (scalar)  */
5396ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if ((INSN(11,8) & BITS4(1,0,1,1)) == BITS4(0,0,1,1) && !U) {
5397ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp res, arg_m, arg_n, tmp;
5398ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IROp dup, get, op, op2, add, cmp;
5399ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt P = INSN(10,10);
5400ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ULong imm;
5401ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (dreg & 1)
5402ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         return False;
5403ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      dreg >>= 1;
5404ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      res = newTemp(Ity_V128);
5405ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      arg_m = newTemp(Ity_I64);
5406ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      arg_n = newTemp(Ity_I64);
5407ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(arg_n, getDRegI64(nreg));
5408ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      switch(size) {
5409ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 1:
5410ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            dup = Iop_Dup16x4;
5411ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            get = Iop_GetElem16x4;
5412ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            index = mreg >> 3;
5413ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            mreg &= 7;
5414ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
5415ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 2:
5416ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            dup = Iop_Dup32x2;
5417ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            get = Iop_GetElem32x2;
5418ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            index = mreg >> 4;
5419ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            mreg &= 0xf;
5420ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
5421ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0:
5422ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 3:
5423ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            return False;
5424ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         default:
5425ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            vassert(0);
5426ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
5427ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(arg_m, unop(dup, binop(get, getDRegI64(mreg), mkU8(index))));
5428ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      switch (size) {
5429ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0:
5430ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 3:
5431ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            return False;
5432ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 1:
5433ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            op = Iop_QDMulLong16Sx4;
5434ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            cmp = Iop_CmpEQ16x4;
5435ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            add = P ? Iop_QSub32Sx4 : Iop_QAdd32Sx4;
5436ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            op2 = P ? Iop_Sub32x4 : Iop_Add32x4;
5437ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            imm = 1LL << 15;
5438ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            imm = (imm << 16) | imm;
5439ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            imm = (imm << 32) | imm;
5440ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
5441ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 2:
5442ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            op = Iop_QDMulLong32Sx2;
5443ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            cmp = Iop_CmpEQ32x2;
5444ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            add = P ? Iop_QSub64Sx2 : Iop_QAdd64Sx2;
5445ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            op2 = P ? Iop_Sub64x2 : Iop_Add64x2;
5446ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            imm = 1LL << 31;
5447ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            imm = (imm << 32) | imm;
5448ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
5449ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         default:
5450ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            vassert(0);
5451ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
5452ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      res = newTemp(Ity_V128);
5453ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tmp = newTemp(Ity_V128);
5454ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(res, binop(op, mkexpr(arg_n), mkexpr(arg_m)));
5455ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#ifndef DISABLE_QC_FLAG
5456ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(tmp, binop(op2, getQReg(dreg), mkexpr(res)));
5457ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      setFlag_QC(binop(Iop_And64,
5458ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       binop(cmp, mkexpr(arg_n), mkU64(imm)),
5459ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       binop(cmp, mkexpr(arg_m), mkU64(imm))),
5460ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 mkU64(0),
5461ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 False, condT);
5462ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      setFlag_QC(mkexpr(tmp), binop(add, getQReg(dreg), mkexpr(res)),
5463ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 True, condT);
5464ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#endif
5465ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putQReg(dreg, binop(add, getQReg(dreg), mkexpr(res)), condT);
5466ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("vqdml%cl.s%u q%u, d%u, d%u[%u]\n", P ? 's' : 'a', 8 << size,
5467ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          dreg, nreg, mreg, index);
5468ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return True;
5469ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
5470ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5471ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* VMUL (by scalar)  */
5472ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if ((INSN(11,8) & BITS4(1,1,1,0)) == BITS4(1,0,0,0)) {
5473ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp res, arg_m, arg_n;
5474ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IROp dup, get, op;
5475ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (Q) {
5476ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if ((dreg & 1) || (nreg & 1))
5477ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            return False;
5478ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         dreg >>= 1;
5479ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         nreg >>= 1;
5480ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         res = newTemp(Ity_V128);
5481ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         arg_m = newTemp(Ity_V128);
5482ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         arg_n = newTemp(Ity_V128);
5483ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(arg_n, getQReg(nreg));
5484ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         switch(size) {
5485ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 1:
5486ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               dup = Iop_Dup16x8;
5487ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               get = Iop_GetElem16x4;
5488ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               index = mreg >> 3;
5489ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               mreg &= 7;
5490ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5491ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 2:
5492ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               dup = Iop_Dup32x4;
5493ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               get = Iop_GetElem32x2;
5494ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               index = mreg >> 4;
5495ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               mreg &= 0xf;
5496ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5497ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0:
5498ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 3:
5499ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               return False;
5500ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            default:
5501ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               vassert(0);
5502ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
5503ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(arg_m, unop(dup, binop(get, getDRegI64(mreg), mkU8(index))));
5504ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
5505ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         res = newTemp(Ity_I64);
5506ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         arg_m = newTemp(Ity_I64);
5507ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         arg_n = newTemp(Ity_I64);
5508ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(arg_n, getDRegI64(nreg));
5509ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         switch(size) {
5510ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 1:
5511ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               dup = Iop_Dup16x4;
5512ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               get = Iop_GetElem16x4;
5513ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               index = mreg >> 3;
5514ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               mreg &= 7;
5515ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5516ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 2:
5517ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               dup = Iop_Dup32x2;
5518ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               get = Iop_GetElem32x2;
5519ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               index = mreg >> 4;
5520ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               mreg &= 0xf;
5521ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5522ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0:
5523ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 3:
5524ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               return False;
5525ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            default:
5526ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               vassert(0);
5527ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
5528ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(arg_m, unop(dup, binop(get, getDRegI64(mreg), mkU8(index))));
5529ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
5530b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      if (INSN(8,8)) {
5531b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         switch (size) {
5532b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            case 2:
5533b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               op = Q ? Iop_Mul32Fx4 : Iop_Mul32Fx2;
5534b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               break;
5535b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            case 0:
5536b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            case 1:
5537b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            case 3:
5538b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               return False;
5539b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            default:
5540b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               vassert(0);
5541b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         }
5542b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      } else {
5543b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         switch (size) {
5544b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            case 1:
5545b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               op = Q ? Iop_Mul16x8 : Iop_Mul16x4;
5546b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               break;
5547b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            case 2:
5548b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               op = Q ? Iop_Mul32x4 : Iop_Mul32x2;
5549b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               break;
5550b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            case 0:
5551b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            case 3:
5552b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               return False;
5553b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            default:
5554b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               vassert(0);
5555b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         }
5556ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
5557ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(res, binop(op, mkexpr(arg_n), mkexpr(arg_m)));
5558ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (Q)
5559ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putQReg(dreg, mkexpr(res), condT);
5560ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      else
5561ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putDRegI64(dreg, mkexpr(res), condT);
5562b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      DIP("vmul.%c%u %c%u, %c%u, d%u[%u]\n", INSN(8,8) ? 'f' : 'i',
5563b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov          8 << size, Q ? 'q' : 'd', dreg,
5564ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          Q ? 'q' : 'd', nreg, mreg, index);
5565ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return True;
5566ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
5567ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5568ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* VMULL (scalar) */
5569ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (INSN(11,8) == BITS4(1,0,1,0)) {
5570ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp res, arg_m, arg_n;
5571ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IROp dup, get, op;
5572ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (dreg & 1)
5573ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         return False;
5574ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      dreg >>= 1;
5575ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      res = newTemp(Ity_V128);
5576ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      arg_m = newTemp(Ity_I64);
5577ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      arg_n = newTemp(Ity_I64);
5578ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(arg_n, getDRegI64(nreg));
5579ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      switch(size) {
5580ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 1:
5581ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            dup = Iop_Dup16x4;
5582ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            get = Iop_GetElem16x4;
5583ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            index = mreg >> 3;
5584ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            mreg &= 7;
5585ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
5586ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 2:
5587ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            dup = Iop_Dup32x2;
5588ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            get = Iop_GetElem32x2;
5589ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            index = mreg >> 4;
5590ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            mreg &= 0xf;
5591ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
5592ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0:
5593ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 3:
5594ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            return False;
5595ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         default:
5596ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            vassert(0);
5597ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
5598ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(arg_m, unop(dup, binop(get, getDRegI64(mreg), mkU8(index))));
5599ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      switch (size) {
5600ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 1: op = U ? Iop_Mull16Ux4 : Iop_Mull16Sx4; break;
5601ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 2: op = U ? Iop_Mull32Ux2 : Iop_Mull32Sx2; break;
5602ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0: case 3: return False;
5603ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         default: vassert(0);
5604ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
5605ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(res, binop(op, mkexpr(arg_n), mkexpr(arg_m)));
5606ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putQReg(dreg, mkexpr(res), condT);
5607ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("vmull.%c%u q%u, d%u, d%u[%u]\n", U ? 'u' : 's', 8 << size, dreg,
5608ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          nreg, mreg, index);
5609ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return True;
5610ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
5611ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5612ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* VQDMULL */
5613ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (INSN(11,8) == BITS4(1,0,1,1) && !U) {
5614ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IROp op ,op2, dup, get;
5615ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ULong imm;
5616b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      IRTemp arg_m, arg_n;
5617ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (dreg & 1)
5618ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         return False;
5619ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      dreg >>= 1;
5620ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      arg_m = newTemp(Ity_I64);
5621ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      arg_n = newTemp(Ity_I64);
5622ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(arg_n, getDRegI64(nreg));
5623ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      switch(size) {
5624ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 1:
5625ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            dup = Iop_Dup16x4;
5626ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            get = Iop_GetElem16x4;
5627ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            index = mreg >> 3;
5628ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            mreg &= 7;
5629ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
5630ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 2:
5631ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            dup = Iop_Dup32x2;
5632ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            get = Iop_GetElem32x2;
5633ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            index = mreg >> 4;
5634ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            mreg &= 0xf;
5635ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
5636ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0:
5637ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 3:
5638ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            return False;
5639ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         default:
5640ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            vassert(0);
5641ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
5642ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(arg_m, unop(dup, binop(get, getDRegI64(mreg), mkU8(index))));
5643ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      switch (size) {
5644ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0:
5645ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 3:
5646ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            return False;
5647ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 1:
5648ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            op = Iop_QDMulLong16Sx4;
5649ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            op2 = Iop_CmpEQ16x4;
5650ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            imm = 1LL << 15;
5651ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            imm = (imm << 16) | imm;
5652ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            imm = (imm << 32) | imm;
5653ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
5654ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 2:
5655ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            op = Iop_QDMulLong32Sx2;
5656ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            op2 = Iop_CmpEQ32x2;
5657ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            imm = 1LL << 31;
5658ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            imm = (imm << 32) | imm;
5659ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
5660ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         default:
5661ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            vassert(0);
5662ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
5663ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putQReg(dreg, binop(op, mkexpr(arg_n), mkexpr(arg_m)),
5664ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            condT);
5665ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#ifndef DISABLE_QC_FLAG
5666ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      setFlag_QC(binop(Iop_And64,
5667ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       binop(op2, mkexpr(arg_n), mkU64(imm)),
5668ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       binop(op2, mkexpr(arg_m), mkU64(imm))),
5669ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 mkU64(0),
5670ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 False, condT);
5671ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#endif
5672ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("vqdmull.s%u q%u, d%u, d%u[%u]\n", 8 << size, dreg, nreg, mreg,
5673ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          index);
5674ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return True;
5675ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
5676ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5677ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* VQDMULH */
5678ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (INSN(11,8) == BITS4(1,1,0,0)) {
5679ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IROp op ,op2, dup, get;
5680ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ULong imm;
5681ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp res, arg_m, arg_n;
5682ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (Q) {
5683ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if ((dreg & 1) || (nreg & 1))
5684ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            return False;
5685ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         dreg >>= 1;
5686ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         nreg >>= 1;
5687ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         res = newTemp(Ity_V128);
5688ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         arg_m = newTemp(Ity_V128);
5689ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         arg_n = newTemp(Ity_V128);
5690ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(arg_n, getQReg(nreg));
5691ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         switch(size) {
5692ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 1:
5693ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               dup = Iop_Dup16x8;
5694ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               get = Iop_GetElem16x4;
5695ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               index = mreg >> 3;
5696ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               mreg &= 7;
5697ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5698ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 2:
5699ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               dup = Iop_Dup32x4;
5700ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               get = Iop_GetElem32x2;
5701ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               index = mreg >> 4;
5702ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               mreg &= 0xf;
5703ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5704ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0:
5705ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 3:
5706ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               return False;
5707ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            default:
5708ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               vassert(0);
5709ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
5710ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(arg_m, unop(dup, binop(get, getDRegI64(mreg), mkU8(index))));
5711ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
5712ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         res = newTemp(Ity_I64);
5713ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         arg_m = newTemp(Ity_I64);
5714ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         arg_n = newTemp(Ity_I64);
5715ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(arg_n, getDRegI64(nreg));
5716ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         switch(size) {
5717ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 1:
5718ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               dup = Iop_Dup16x4;
5719ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               get = Iop_GetElem16x4;
5720ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               index = mreg >> 3;
5721ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               mreg &= 7;
5722ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5723ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 2:
5724ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               dup = Iop_Dup32x2;
5725ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               get = Iop_GetElem32x2;
5726ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               index = mreg >> 4;
5727ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               mreg &= 0xf;
5728ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5729ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0:
5730ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 3:
5731ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               return False;
5732ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            default:
5733ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               vassert(0);
5734ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
5735ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(arg_m, unop(dup, binop(get, getDRegI64(mreg), mkU8(index))));
5736ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
5737ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      switch (size) {
5738ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0:
5739ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 3:
5740ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            return False;
5741ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 1:
5742ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            op = Q ? Iop_QDMulHi16Sx8 : Iop_QDMulHi16Sx4;
5743ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            op2 = Q ? Iop_CmpEQ16x8 : Iop_CmpEQ16x4;
5744ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            imm = 1LL << 15;
5745ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            imm = (imm << 16) | imm;
5746ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            imm = (imm << 32) | imm;
5747ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
5748ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 2:
5749ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            op = Q ? Iop_QDMulHi32Sx4 : Iop_QDMulHi32Sx2;
5750ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            op2 = Q ? Iop_CmpEQ32x4 : Iop_CmpEQ32x2;
5751ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            imm = 1LL << 31;
5752ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            imm = (imm << 32) | imm;
5753ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
5754ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         default:
5755ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            vassert(0);
5756ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
5757ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(res, binop(op, mkexpr(arg_n), mkexpr(arg_m)));
5758ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#ifndef DISABLE_QC_FLAG
5759ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      setFlag_QC(binop(Q ? Iop_AndV128 : Iop_And64,
5760ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       binop(op2, mkexpr(arg_n),
5761ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  Q ? mkU128(imm) : mkU64(imm)),
5762ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       binop(op2, mkexpr(arg_m),
5763ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             Q ? mkU128(imm) : mkU64(imm))),
5764ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 Q ? mkU128(0) : mkU64(0),
5765ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 Q, condT);
5766ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#endif
5767ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (Q)
5768ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putQReg(dreg, mkexpr(res), condT);
5769ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      else
5770ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putDRegI64(dreg, mkexpr(res), condT);
5771ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("vqdmulh.s%u %c%u, %c%u, d%u[%u]\n",
5772ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          8 << size, Q ? 'q' : 'd', dreg,
5773ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          Q ? 'q' : 'd', nreg, mreg, index);
5774ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return True;
5775ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
5776ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5777ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* VQRDMULH (scalar) */
5778ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (INSN(11,8) == BITS4(1,1,0,1)) {
5779ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IROp op ,op2, dup, get;
5780ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ULong imm;
5781ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp res, arg_m, arg_n;
5782ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (Q) {
5783ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if ((dreg & 1) || (nreg & 1))
5784ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            return False;
5785ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         dreg >>= 1;
5786ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         nreg >>= 1;
5787ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         res = newTemp(Ity_V128);
5788ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         arg_m = newTemp(Ity_V128);
5789ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         arg_n = newTemp(Ity_V128);
5790ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(arg_n, getQReg(nreg));
5791ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         switch(size) {
5792ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 1:
5793ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               dup = Iop_Dup16x8;
5794ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               get = Iop_GetElem16x4;
5795ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               index = mreg >> 3;
5796ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               mreg &= 7;
5797ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5798ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 2:
5799ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               dup = Iop_Dup32x4;
5800ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               get = Iop_GetElem32x2;
5801ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               index = mreg >> 4;
5802ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               mreg &= 0xf;
5803ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5804ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0:
5805ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 3:
5806ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               return False;
5807ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            default:
5808ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               vassert(0);
5809ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
5810ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(arg_m, unop(dup, binop(get, getDRegI64(mreg), mkU8(index))));
5811ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
5812ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         res = newTemp(Ity_I64);
5813ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         arg_m = newTemp(Ity_I64);
5814ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         arg_n = newTemp(Ity_I64);
5815ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(arg_n, getDRegI64(nreg));
5816ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         switch(size) {
5817ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 1:
5818ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               dup = Iop_Dup16x4;
5819ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               get = Iop_GetElem16x4;
5820ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               index = mreg >> 3;
5821ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               mreg &= 7;
5822ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5823ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 2:
5824ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               dup = Iop_Dup32x2;
5825ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               get = Iop_GetElem32x2;
5826ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               index = mreg >> 4;
5827ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               mreg &= 0xf;
5828ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5829ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0:
5830ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 3:
5831ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               return False;
5832ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            default:
5833ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               vassert(0);
5834ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
5835ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(arg_m, unop(dup, binop(get, getDRegI64(mreg), mkU8(index))));
5836ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
5837ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      switch (size) {
5838ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0:
5839ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 3:
5840ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            return False;
5841ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 1:
5842ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            op = Q ? Iop_QRDMulHi16Sx8 : Iop_QRDMulHi16Sx4;
5843ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            op2 = Q ? Iop_CmpEQ16x8 : Iop_CmpEQ16x4;
5844ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            imm = 1LL << 15;
5845ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            imm = (imm << 16) | imm;
5846ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            imm = (imm << 32) | imm;
5847ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
5848ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 2:
5849ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            op = Q ? Iop_QRDMulHi32Sx4 : Iop_QRDMulHi32Sx2;
5850ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            op2 = Q ? Iop_CmpEQ32x4 : Iop_CmpEQ32x2;
5851ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            imm = 1LL << 31;
5852ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            imm = (imm << 32) | imm;
5853ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
5854ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         default:
5855ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            vassert(0);
5856ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
5857ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(res, binop(op, mkexpr(arg_n), mkexpr(arg_m)));
5858ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#ifndef DISABLE_QC_FLAG
5859ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      setFlag_QC(binop(Q ? Iop_AndV128 : Iop_And64,
5860ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       binop(op2, mkexpr(arg_n),
5861ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  Q ? mkU128(imm) : mkU64(imm)),
5862ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       binop(op2, mkexpr(arg_m),
5863ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  Q ? mkU128(imm) : mkU64(imm))),
5864ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 Q ? mkU128(0) : mkU64(0),
5865ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 Q, condT);
5866ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#endif
5867ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (Q)
5868ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putQReg(dreg, mkexpr(res), condT);
5869ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      else
5870ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putDRegI64(dreg, mkexpr(res), condT);
5871ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("vqrdmulh.s%u %c%u, %c%u, d%u[%u]\n",
5872ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          8 << size, Q ? 'q' : 'd', dreg,
5873ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          Q ? 'q' : 'd', nreg, mreg, index);
5874ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return True;
5875ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
5876ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5877ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return False;
5878ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  undef INSN
5879ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
5880ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5881ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* A7.4.4 Two registers and a shift amount */
5882ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
5883ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownBool dis_neon_data_2reg_and_shift ( UInt theInstr, IRTemp condT )
5884ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
5885ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt A = (theInstr >> 8) & 0xf;
5886ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt B = (theInstr >> 6) & 1;
5887ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt L = (theInstr >> 7) & 1;
5888ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt U = (theInstr >> 24) & 1;
5889ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt Q = B;
5890ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt imm6 = (theInstr >> 16) & 0x3f;
5891ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt shift_imm;
5892ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt size = 4;
5893ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt tmp;
5894ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt mreg = get_neon_m_regno(theInstr);
5895ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt dreg = get_neon_d_regno(theInstr);
5896ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ULong imm = 0;
5897ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IROp op, cvt, add = Iop_INVALID, cvt2, op_rev;
5898ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp reg_m, res, mask;
5899ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5900ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (L == 0 && ((theInstr >> 19) & 7) == 0)
5901ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* It is one reg and immediate */
5902ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return False;
5903ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5904ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tmp = (L << 6) | imm6;
5905ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (tmp & 0x40) {
5906ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      size = 3;
5907ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      shift_imm = 64 - imm6;
5908ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else if (tmp & 0x20) {
5909ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      size = 2;
5910ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      shift_imm = 64 - imm6;
5911ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else if (tmp & 0x10) {
5912ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      size = 1;
5913ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      shift_imm = 32 - imm6;
5914ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else if (tmp & 0x8) {
5915ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      size = 0;
5916ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      shift_imm = 16 - imm6;
5917ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
5918ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return False;
5919ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
5920ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5921ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (A) {
5922ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 3:
5923ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 2:
5924ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* VRSHR, VRSRA */
5925ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (shift_imm > 0) {
5926ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            IRExpr *imm_val;
5927ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            imm = 1L;
5928ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            switch (size) {
5929ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               case 0:
5930ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  imm = (imm << 8) | imm;
5931ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  /* fall through */
5932ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               case 1:
5933ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  imm = (imm << 16) | imm;
5934ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  /* fall through */
5935ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               case 2:
5936ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  imm = (imm << 32) | imm;
5937ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  /* fall through */
5938ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               case 3:
5939ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  break;
5940ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               default:
5941ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  vassert(0);
5942ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
5943ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (Q) {
5944ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               reg_m = newTemp(Ity_V128);
5945ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               res = newTemp(Ity_V128);
5946ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               imm_val = binop(Iop_64HLtoV128, mkU64(imm), mkU64(imm));
5947ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign(reg_m, getQReg(mreg));
5948ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               switch (size) {
5949ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 0:
5950ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     add = Iop_Add8x16;
5951ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op = U ? Iop_ShrN8x16 : Iop_SarN8x16;
5952ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
5953ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 1:
5954ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     add = Iop_Add16x8;
5955ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op = U ? Iop_ShrN16x8 : Iop_SarN16x8;
5956ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
5957ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 2:
5958ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     add = Iop_Add32x4;
5959ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op = U ? Iop_ShrN32x4 : Iop_SarN32x4;
5960ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
5961ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 3:
5962ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     add = Iop_Add64x2;
5963ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op = U ? Iop_ShrN64x2 : Iop_SarN64x2;
5964ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
5965ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  default:
5966ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     vassert(0);
5967ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               }
5968ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            } else {
5969ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               reg_m = newTemp(Ity_I64);
5970ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               res = newTemp(Ity_I64);
5971ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               imm_val = mkU64(imm);
5972ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign(reg_m, getDRegI64(mreg));
5973ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               switch (size) {
5974ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 0:
5975ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     add = Iop_Add8x8;
5976ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op = U ? Iop_ShrN8x8 : Iop_SarN8x8;
5977ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
5978ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 1:
5979ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     add = Iop_Add16x4;
5980ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op = U ? Iop_ShrN16x4 : Iop_SarN16x4;
5981ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
5982ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 2:
5983ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     add = Iop_Add32x2;
5984ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op = U ? Iop_ShrN32x2 : Iop_SarN32x2;
5985ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
5986ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 3:
5987ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     add = Iop_Add64;
5988ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op = U ? Iop_Shr64 : Iop_Sar64;
5989ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
5990ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  default:
5991ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     vassert(0);
5992ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               }
5993ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
5994ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(res,
5995ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   binop(add,
5996ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         binop(op,
5997ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               mkexpr(reg_m),
5998ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               mkU8(shift_imm)),
5999ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         binop(Q ? Iop_AndV128 : Iop_And64,
6000ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               binop(op,
6001ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                     mkexpr(reg_m),
6002ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                     mkU8(shift_imm - 1)),
6003ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               imm_val)));
6004ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
6005ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (Q) {
6006ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               res = newTemp(Ity_V128);
6007ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign(res, getQReg(mreg));
6008ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            } else {
6009ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               res = newTemp(Ity_I64);
6010ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign(res, getDRegI64(mreg));
6011ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
6012ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
6013ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (A == 3) {
6014ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (Q) {
6015ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               putQReg(dreg, binop(add, mkexpr(res), getQReg(dreg)),
6016ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             condT);
6017ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            } else {
6018ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               putDRegI64(dreg, binop(add, mkexpr(res), getDRegI64(dreg)),
6019ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                condT);
6020ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
6021ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("vrsra.%c%u %c%u, %c%u, #%u\n",
6022ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                U ? 'u' : 's', 8 << size,
6023ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', mreg, shift_imm);
6024ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
6025ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (Q) {
6026ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               putQReg(dreg, mkexpr(res), condT);
6027ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            } else {
6028ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               putDRegI64(dreg, mkexpr(res), condT);
6029ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
6030ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("vrshr.%c%u %c%u, %c%u, #%u\n", U ? 'u' : 's', 8 << size,
6031ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', mreg, shift_imm);
6032ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
6033ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         return True;
6034ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 1:
6035ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0:
6036ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* VSHR, VSRA */
6037ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (Q) {
6038ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            reg_m = newTemp(Ity_V128);
6039ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(reg_m, getQReg(mreg));
6040ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            res = newTemp(Ity_V128);
6041ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
6042ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            reg_m = newTemp(Ity_I64);
6043ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(reg_m, getDRegI64(mreg));
6044ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            res = newTemp(Ity_I64);
6045ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
6046ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (Q) {
6047ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            switch (size) {
6048ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               case 0:
6049ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  op = U ? Iop_ShrN8x16 : Iop_SarN8x16;
6050ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  add = Iop_Add8x16;
6051ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  break;
6052ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               case 1:
6053ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  op = U ? Iop_ShrN16x8 : Iop_SarN16x8;
6054ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  add = Iop_Add16x8;
6055ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  break;
6056ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               case 2:
6057ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  op = U ? Iop_ShrN32x4 : Iop_SarN32x4;
6058ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  add = Iop_Add32x4;
6059ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  break;
6060ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               case 3:
6061ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  op = U ? Iop_ShrN64x2 : Iop_SarN64x2;
6062ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  add = Iop_Add64x2;
6063ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  break;
6064ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               default:
6065ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  vassert(0);
6066ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
6067ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
6068ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            switch (size) {
6069ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               case 0:
6070ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  op =  U ? Iop_ShrN8x8 : Iop_SarN8x8;
6071ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  add = Iop_Add8x8;
6072ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  break;
6073ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               case 1:
6074ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  op = U ? Iop_ShrN16x4 : Iop_SarN16x4;
6075ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  add = Iop_Add16x4;
6076ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  break;
6077ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               case 2:
6078ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  op = U ? Iop_ShrN32x2 : Iop_SarN32x2;
6079ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  add = Iop_Add32x2;
6080ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  break;
6081ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               case 3:
6082ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  op = U ? Iop_Shr64 : Iop_Sar64;
6083ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  add = Iop_Add64;
6084ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  break;
6085ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               default:
6086ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  vassert(0);
6087ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
6088ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
6089ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(res, binop(op, mkexpr(reg_m), mkU8(shift_imm)));
6090ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (A == 1) {
6091ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (Q) {
6092ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               putQReg(dreg, binop(add, mkexpr(res), getQReg(dreg)),
6093ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             condT);
6094ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            } else {
6095ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               putDRegI64(dreg, binop(add, mkexpr(res), getDRegI64(dreg)),
6096ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                condT);
6097ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
6098ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("vsra.%c%u %c%u, %c%u, #%u\n", U ? 'u' : 's', 8 << size,
6099ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', mreg, shift_imm);
6100ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
6101ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (Q) {
6102ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               putQReg(dreg, mkexpr(res), condT);
6103ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            } else {
6104ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               putDRegI64(dreg, mkexpr(res), condT);
6105ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
6106ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("vshr.%c%u %c%u, %c%u, #%u\n", U ? 'u' : 's', 8 << size,
6107ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', mreg, shift_imm);
6108ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
6109ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         return True;
6110ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 4:
6111ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* VSRI */
6112ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (!U)
6113ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            return False;
6114ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (Q) {
6115ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            res = newTemp(Ity_V128);
6116ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            mask = newTemp(Ity_V128);
6117ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
6118ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            res = newTemp(Ity_I64);
6119ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            mask = newTemp(Ity_I64);
6120ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
6121ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         switch (size) {
6122ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0: op = Q ? Iop_ShrN8x16 : Iop_ShrN8x8; break;
6123ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 1: op = Q ? Iop_ShrN16x8 : Iop_ShrN16x4; break;
6124ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 2: op = Q ? Iop_ShrN32x4 : Iop_ShrN32x2; break;
6125ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 3: op = Q ? Iop_ShrN64x2 : Iop_Shr64; break;
6126ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            default: vassert(0);
6127ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
6128ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (Q) {
6129ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(mask, binop(op, binop(Iop_64HLtoV128,
6130ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                         mkU64(0xFFFFFFFFFFFFFFFFLL),
6131ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                         mkU64(0xFFFFFFFFFFFFFFFFLL)),
6132ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               mkU8(shift_imm)));
6133ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(res, binop(Iop_OrV128,
6134ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              binop(Iop_AndV128,
6135ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    getQReg(dreg),
6136ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    unop(Iop_NotV128,
6137ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                         mkexpr(mask))),
6138ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              binop(op,
6139ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    getQReg(mreg),
6140ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    mkU8(shift_imm))));
6141ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putQReg(dreg, mkexpr(res), condT);
6142ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
6143ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(mask, binop(op, mkU64(0xFFFFFFFFFFFFFFFFLL),
6144ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               mkU8(shift_imm)));
6145ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(res, binop(Iop_Or64,
6146ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              binop(Iop_And64,
6147ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    getDRegI64(dreg),
6148ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    unop(Iop_Not64,
6149ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                         mkexpr(mask))),
6150ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              binop(op,
6151ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    getDRegI64(mreg),
6152ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    mkU8(shift_imm))));
6153ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putDRegI64(dreg, mkexpr(res), condT);
6154ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
6155ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("vsri.%u %c%u, %c%u, #%u\n",
6156ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             8 << size, Q ? 'q' : 'd', dreg,
6157ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             Q ? 'q' : 'd', mreg, shift_imm);
6158ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         return True;
6159ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 5:
6160ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (U) {
6161ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* VSLI */
6162ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            shift_imm = 8 * (1 << size) - shift_imm;
6163ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (Q) {
6164ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               res = newTemp(Ity_V128);
6165ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               mask = newTemp(Ity_V128);
6166ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            } else {
6167ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               res = newTemp(Ity_I64);
6168ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               mask = newTemp(Ity_I64);
6169ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
6170ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            switch (size) {
6171ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               case 0: op = Q ? Iop_ShlN8x16 : Iop_ShlN8x8; break;
6172ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               case 1: op = Q ? Iop_ShlN16x8 : Iop_ShlN16x4; break;
6173ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               case 2: op = Q ? Iop_ShlN32x4 : Iop_ShlN32x2; break;
6174ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               case 3: op = Q ? Iop_ShlN64x2 : Iop_Shl64; break;
6175ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               default: vassert(0);
6176ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
6177ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (Q) {
6178ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign(mask, binop(op, binop(Iop_64HLtoV128,
6179ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                            mkU64(0xFFFFFFFFFFFFFFFFLL),
6180ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                            mkU64(0xFFFFFFFFFFFFFFFFLL)),
6181ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  mkU8(shift_imm)));
6182ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign(res, binop(Iop_OrV128,
6183ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 binop(Iop_AndV128,
6184ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                       getQReg(dreg),
6185ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                       unop(Iop_NotV128,
6186ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                            mkexpr(mask))),
6187ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 binop(op,
6188ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                       getQReg(mreg),
6189ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                       mkU8(shift_imm))));
6190ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               putQReg(dreg, mkexpr(res), condT);
6191ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            } else {
6192ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign(mask, binop(op, mkU64(0xFFFFFFFFFFFFFFFFLL),
6193ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  mkU8(shift_imm)));
6194ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign(res, binop(Iop_Or64,
6195ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 binop(Iop_And64,
6196ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                       getDRegI64(dreg),
6197ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                       unop(Iop_Not64,
6198ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                            mkexpr(mask))),
6199ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 binop(op,
6200ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                       getDRegI64(mreg),
6201ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                       mkU8(shift_imm))));
6202ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               putDRegI64(dreg, mkexpr(res), condT);
6203ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
6204ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("vsli.%u %c%u, %c%u, #%u\n",
6205ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                8 << size, Q ? 'q' : 'd', dreg,
6206ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                Q ? 'q' : 'd', mreg, shift_imm);
6207ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            return True;
6208ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
6209ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* VSHL #imm */
6210ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            shift_imm = 8 * (1 << size) - shift_imm;
6211ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (Q) {
6212ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               res = newTemp(Ity_V128);
6213ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            } else {
6214ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               res = newTemp(Ity_I64);
6215ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
6216ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            switch (size) {
6217ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               case 0: op = Q ? Iop_ShlN8x16 : Iop_ShlN8x8; break;
6218ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               case 1: op = Q ? Iop_ShlN16x8 : Iop_ShlN16x4; break;
6219ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               case 2: op = Q ? Iop_ShlN32x4 : Iop_ShlN32x2; break;
6220ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               case 3: op = Q ? Iop_ShlN64x2 : Iop_Shl64; break;
6221ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               default: vassert(0);
6222ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
6223ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(res, binop(op, Q ? getQReg(mreg) : getDRegI64(mreg),
6224ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     mkU8(shift_imm)));
6225ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (Q) {
6226ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               putQReg(dreg, mkexpr(res), condT);
6227ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            } else {
6228ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               putDRegI64(dreg, mkexpr(res), condT);
6229ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
6230ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("vshl.i%u %c%u, %c%u, #%u\n",
6231ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                8 << size, Q ? 'q' : 'd', dreg,
6232ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                Q ? 'q' : 'd', mreg, shift_imm);
6233ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            return True;
6234ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
6235ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
6236ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 6:
6237ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 7:
6238ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* VQSHL, VQSHLU */
6239ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         shift_imm = 8 * (1 << size) - shift_imm;
6240ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (U) {
6241ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (A & 1) {
6242ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               switch (size) {
6243ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 0:
6244ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op = Q ? Iop_QShlN8x16 : Iop_QShlN8x8;
6245ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op_rev = Q ? Iop_ShrN8x16 : Iop_ShrN8x8;
6246ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
6247ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 1:
6248ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op = Q ? Iop_QShlN16x8 : Iop_QShlN16x4;
6249ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op_rev = Q ? Iop_ShrN16x8 : Iop_ShrN16x4;
6250ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
6251ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 2:
6252ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op = Q ? Iop_QShlN32x4 : Iop_QShlN32x2;
6253ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op_rev = Q ? Iop_ShrN32x4 : Iop_ShrN32x2;
6254ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
6255ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 3:
6256ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op = Q ? Iop_QShlN64x2 : Iop_QShlN64x1;
6257ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op_rev = Q ? Iop_ShrN64x2 : Iop_Shr64;
6258ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
6259ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  default:
6260ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     vassert(0);
6261ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               }
6262ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("vqshl.u%u %c%u, %c%u, #%u\n",
6263ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   8 << size,
6264ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', mreg, shift_imm);
6265ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            } else {
6266ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               switch (size) {
6267ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 0:
6268ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op = Q ? Iop_QShlN8Sx16 : Iop_QShlN8Sx8;
6269ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op_rev = Q ? Iop_ShrN8x16 : Iop_ShrN8x8;
6270ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
6271ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 1:
6272ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op = Q ? Iop_QShlN16Sx8 : Iop_QShlN16Sx4;
6273ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op_rev = Q ? Iop_ShrN16x8 : Iop_ShrN16x4;
6274ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
6275ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 2:
6276ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op = Q ? Iop_QShlN32Sx4 : Iop_QShlN32Sx2;
6277ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op_rev = Q ? Iop_ShrN32x4 : Iop_ShrN32x2;
6278ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
6279ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 3:
6280ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op = Q ? Iop_QShlN64Sx2 : Iop_QShlN64Sx1;
6281ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op_rev = Q ? Iop_ShrN64x2 : Iop_Shr64;
6282ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
6283ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  default:
6284ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     vassert(0);
6285ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               }
6286ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("vqshlu.s%u %c%u, %c%u, #%u\n",
6287ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   8 << size,
6288ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', mreg, shift_imm);
6289ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
6290ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
6291ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (!(A & 1))
6292ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               return False;
6293ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            switch (size) {
6294ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               case 0:
6295ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  op = Q ? Iop_QSalN8x16 : Iop_QSalN8x8;
6296ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  op_rev = Q ? Iop_SarN8x16 : Iop_SarN8x8;
6297ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  break;
6298ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               case 1:
6299ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  op = Q ? Iop_QSalN16x8 : Iop_QSalN16x4;
6300ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  op_rev = Q ? Iop_SarN16x8 : Iop_SarN16x4;
6301ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  break;
6302ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               case 2:
6303ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  op = Q ? Iop_QSalN32x4 : Iop_QSalN32x2;
6304ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  op_rev = Q ? Iop_SarN32x4 : Iop_SarN32x2;
6305ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  break;
6306ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               case 3:
6307ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  op = Q ? Iop_QSalN64x2 : Iop_QSalN64x1;
6308ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  op_rev = Q ? Iop_SarN64x2 : Iop_Sar64;
6309ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  break;
6310ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               default:
6311ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  vassert(0);
6312ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
6313ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("vqshl.s%u %c%u, %c%u, #%u\n",
6314ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                8 << size,
6315ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', mreg, shift_imm);
6316ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
6317ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (Q) {
6318ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            tmp = newTemp(Ity_V128);
6319ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            res = newTemp(Ity_V128);
6320ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            reg_m = newTemp(Ity_V128);
6321ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(reg_m, getQReg(mreg));
6322ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
6323ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            tmp = newTemp(Ity_I64);
6324ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            res = newTemp(Ity_I64);
6325ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            reg_m = newTemp(Ity_I64);
6326ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(reg_m, getDRegI64(mreg));
6327ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
6328ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(res, binop(op, mkexpr(reg_m), mkU8(shift_imm)));
6329ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#ifndef DISABLE_QC_FLAG
6330ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(tmp, binop(op_rev, mkexpr(res), mkU8(shift_imm)));
6331ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         setFlag_QC(mkexpr(tmp), mkexpr(reg_m), Q, condT);
6332ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#endif
6333ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (Q)
6334ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putQReg(dreg, mkexpr(res), condT);
6335ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         else
6336ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putDRegI64(dreg, mkexpr(res), condT);
6337ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         return True;
6338ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 8:
6339ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (!U) {
6340ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (L == 1)
6341ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               return False;
6342ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            size++;
6343ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            dreg = ((theInstr >> 18) & 0x10) | ((theInstr >> 12) & 0xF);
6344ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            mreg = ((theInstr >> 1) & 0x10) | (theInstr & 0xF);
6345ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (mreg & 1)
6346ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               return False;
6347ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            mreg >>= 1;
6348ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (!B) {
6349ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* VSHRN*/
6350ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IROp narOp;
6351ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               reg_m = newTemp(Ity_V128);
6352ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign(reg_m, getQReg(mreg));
6353ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               res = newTemp(Ity_I64);
6354ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               switch (size) {
6355ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 1:
6356ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op = Iop_ShrN16x8;
6357b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                     narOp = Iop_NarrowUn16to8x8;
6358ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
6359ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 2:
6360ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op = Iop_ShrN32x4;
6361b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                     narOp = Iop_NarrowUn32to16x4;
6362ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
6363ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 3:
6364ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op = Iop_ShrN64x2;
6365b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                     narOp = Iop_NarrowUn64to32x2;
6366ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
6367ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  default:
6368ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     vassert(0);
6369ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               }
6370ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign(res, unop(narOp,
6371ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                binop(op,
6372ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                      mkexpr(reg_m),
6373ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                      mkU8(shift_imm))));
6374ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               putDRegI64(dreg, mkexpr(res), condT);
6375ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("vshrn.i%u d%u, q%u, #%u\n", 8 << size, dreg, mreg,
6376ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   shift_imm);
6377ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               return True;
6378ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            } else {
6379ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* VRSHRN   */
6380ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IROp addOp, shOp, narOp;
6381ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRExpr *imm_val;
6382ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               reg_m = newTemp(Ity_V128);
6383ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign(reg_m, getQReg(mreg));
6384ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               res = newTemp(Ity_I64);
6385ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               imm = 1L;
6386ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               switch (size) {
6387ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 0: imm = (imm <<  8) | imm; /* fall through */
6388ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 1: imm = (imm << 16) | imm; /* fall through */
6389ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 2: imm = (imm << 32) | imm; /* fall through */
6390ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 3: break;
6391ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  default: vassert(0);
6392ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               }
6393ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               imm_val = binop(Iop_64HLtoV128, mkU64(imm), mkU64(imm));
6394ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               switch (size) {
6395ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 1:
6396ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     addOp = Iop_Add16x8;
6397ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     shOp = Iop_ShrN16x8;
6398b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                     narOp = Iop_NarrowUn16to8x8;
6399ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
6400ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 2:
6401ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     addOp = Iop_Add32x4;
6402ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     shOp = Iop_ShrN32x4;
6403b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                     narOp = Iop_NarrowUn32to16x4;
6404ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
6405ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 3:
6406ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     addOp = Iop_Add64x2;
6407ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     shOp = Iop_ShrN64x2;
6408b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                     narOp = Iop_NarrowUn64to32x2;
6409ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
6410ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  default:
6411ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     vassert(0);
6412ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               }
6413ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign(res, unop(narOp,
6414ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                binop(addOp,
6415ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                      binop(shOp,
6416ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                            mkexpr(reg_m),
6417ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                            mkU8(shift_imm)),
6418ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                      binop(Iop_AndV128,
6419ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                            binop(shOp,
6420ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                                  mkexpr(reg_m),
6421ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                                  mkU8(shift_imm - 1)),
6422ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                            imm_val))));
6423ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               putDRegI64(dreg, mkexpr(res), condT);
6424ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               if (shift_imm == 0) {
6425ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  DIP("vmov%u d%u, q%u, #%u\n", 8 << size, dreg, mreg,
6426ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      shift_imm);
6427ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               } else {
6428ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  DIP("vrshrn.i%u d%u, q%u, #%u\n", 8 << size, dreg, mreg,
6429ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      shift_imm);
6430ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               }
6431ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               return True;
6432ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
6433ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
6434ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* fall through */
6435ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
6436ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 9:
6437ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         dreg = ((theInstr >> 18) & 0x10) | ((theInstr >> 12) & 0xF);
6438ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         mreg = ((theInstr >>  1) & 0x10) | (theInstr & 0xF);
6439ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (mreg & 1)
6440ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            return False;
6441ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         mreg >>= 1;
6442ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         size++;
6443ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if ((theInstr >> 8) & 1) {
6444ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            switch (size) {
6445ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               case 1:
6446ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  op = U ? Iop_ShrN16x8 : Iop_SarN16x8;
6447b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                  cvt = U ? Iop_QNarrowUn16Uto8Ux8 : Iop_QNarrowUn16Sto8Sx8;
6448b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                  cvt2 = U ? Iop_Widen8Uto16x8 : Iop_Widen8Sto16x8;
6449ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  break;
6450ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               case 2:
6451ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  op = U ? Iop_ShrN32x4 : Iop_SarN32x4;
6452b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                  cvt = U ? Iop_QNarrowUn32Uto16Ux4 : Iop_QNarrowUn32Sto16Sx4;
6453b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                  cvt2 = U ? Iop_Widen16Uto32x4 : Iop_Widen16Sto32x4;
6454ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  break;
6455ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               case 3:
6456ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  op = U ? Iop_ShrN64x2 : Iop_SarN64x2;
6457b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                  cvt = U ? Iop_QNarrowUn64Uto32Ux2 : Iop_QNarrowUn64Sto32Sx2;
6458b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                  cvt2 = U ? Iop_Widen32Uto64x2 : Iop_Widen32Sto64x2;
6459ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  break;
6460ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               default:
6461ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  vassert(0);
6462ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
6463ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("vq%sshrn.%c%u d%u, q%u, #%u\n", B ? "r" : "",
6464ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                U ? 'u' : 's', 8 << size, dreg, mreg, shift_imm);
6465ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
6466ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            vassert(U);
6467ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            switch (size) {
6468ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               case 1:
6469ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  op = Iop_SarN16x8;
6470b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                  cvt = Iop_QNarrowUn16Sto8Ux8;
6471b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                  cvt2 = Iop_Widen8Uto16x8;
6472ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  break;
6473ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               case 2:
6474ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  op = Iop_SarN32x4;
6475b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                  cvt = Iop_QNarrowUn32Sto16Ux4;
6476b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                  cvt2 = Iop_Widen16Uto32x4;
6477ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  break;
6478ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               case 3:
6479ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  op = Iop_SarN64x2;
6480b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                  cvt = Iop_QNarrowUn64Sto32Ux2;
6481b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                  cvt2 = Iop_Widen32Uto64x2;
6482ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  break;
6483ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               default:
6484ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  vassert(0);
6485ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
6486ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("vq%sshrun.s%u d%u, q%u, #%u\n", B ? "r" : "",
6487ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                8 << size, dreg, mreg, shift_imm);
6488ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
6489ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (B) {
6490ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (shift_imm > 0) {
6491ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               imm = 1;
6492ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               switch (size) {
6493ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 1: imm = (imm << 16) | imm; /* fall through */
6494ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 2: imm = (imm << 32) | imm; /* fall through */
6495ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 3: break;
6496ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 0: default: vassert(0);
6497ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               }
6498ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               switch (size) {
6499ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 1: add = Iop_Add16x8; break;
6500ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 2: add = Iop_Add32x4; break;
6501ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 3: add = Iop_Add64x2; break;
6502ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 0: default: vassert(0);
6503ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               }
6504ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
6505ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
6506ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         reg_m = newTemp(Ity_V128);
6507ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         res = newTemp(Ity_V128);
6508ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(reg_m, getQReg(mreg));
6509ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (B) {
6510ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* VQRSHRN, VQRSHRUN */
6511ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(res, binop(add,
6512ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              binop(op, mkexpr(reg_m), mkU8(shift_imm)),
6513ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              binop(Iop_AndV128,
6514ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    binop(op,
6515ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                          mkexpr(reg_m),
6516ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                          mkU8(shift_imm - 1)),
6517ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    mkU128(imm))));
6518ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
6519ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* VQSHRN, VQSHRUN */
6520ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(res, binop(op, mkexpr(reg_m), mkU8(shift_imm)));
6521ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
6522ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#ifndef DISABLE_QC_FLAG
6523ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         setFlag_QC(unop(cvt2, unop(cvt, mkexpr(res))), mkexpr(res),
6524ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    True, condT);
6525ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#endif
6526ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putDRegI64(dreg, unop(cvt, mkexpr(res)), condT);
6527ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         return True;
6528ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 10:
6529ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* VSHLL
6530ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            VMOVL ::= VSHLL #0 */
6531ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (B)
6532ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            return False;
6533ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (dreg & 1)
6534ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            return False;
6535ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         dreg >>= 1;
6536ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         shift_imm = (8 << size) - shift_imm;
6537ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         res = newTemp(Ity_V128);
6538ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         switch (size) {
6539ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0:
6540ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               op = Iop_ShlN16x8;
6541b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               cvt = U ? Iop_Widen8Uto16x8 : Iop_Widen8Sto16x8;
6542ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
6543ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 1:
6544ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               op = Iop_ShlN32x4;
6545b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               cvt = U ? Iop_Widen16Uto32x4 : Iop_Widen16Sto32x4;
6546ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
6547ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 2:
6548ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               op = Iop_ShlN64x2;
6549b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               cvt = U ? Iop_Widen32Uto64x2 : Iop_Widen32Sto64x2;
6550ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
6551ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 3:
6552ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               return False;
6553ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            default:
6554ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               vassert(0);
6555ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
6556ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(res, binop(op, unop(cvt, getDRegI64(mreg)), mkU8(shift_imm)));
6557ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putQReg(dreg, mkexpr(res), condT);
6558ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (shift_imm == 0) {
6559ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("vmovl.%c%u q%u, d%u\n", U ? 'u' : 's', 8 << size,
6560ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                dreg, mreg);
6561ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
6562ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("vshll.%c%u q%u, d%u, #%u\n", U ? 'u' : 's', 8 << size,
6563ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                dreg, mreg, shift_imm);
6564ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
6565ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         return True;
6566ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 14:
6567ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 15:
6568ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* VCVT floating-point <-> fixed-point */
6569ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if ((theInstr >> 8) & 1) {
6570ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (U) {
6571ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               op = Q ? Iop_F32ToFixed32Ux4_RZ : Iop_F32ToFixed32Ux2_RZ;
6572ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            } else {
6573ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               op = Q ? Iop_F32ToFixed32Sx4_RZ : Iop_F32ToFixed32Sx2_RZ;
6574ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
6575ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("vcvt.%c32.f32 %c%u, %c%u, #%u\n", U ? 'u' : 's',
6576ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', mreg,
6577ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                64 - ((theInstr >> 16) & 0x3f));
6578ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
6579ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (U) {
6580ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               op = Q ? Iop_Fixed32UToF32x4_RN : Iop_Fixed32UToF32x2_RN;
6581ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            } else {
6582ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               op = Q ? Iop_Fixed32SToF32x4_RN : Iop_Fixed32SToF32x2_RN;
6583ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
6584ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("vcvt.f32.%c32 %c%u, %c%u, #%u\n", U ? 'u' : 's',
6585ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', mreg,
6586ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                64 - ((theInstr >> 16) & 0x3f));
6587ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
6588ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (((theInstr >> 21) & 1) == 0)
6589ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            return False;
6590ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (Q) {
6591ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putQReg(dreg, binop(op, getQReg(mreg),
6592ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     mkU8(64 - ((theInstr >> 16) & 0x3f))), condT);
6593ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
6594ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putDRegI64(dreg, binop(op, getDRegI64(mreg),
6595ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       mkU8(64 - ((theInstr >> 16) & 0x3f))), condT);
6596ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
6597ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         return True;
6598ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default:
6599ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         return False;
6600ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6601ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
6602ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return False;
6603ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
6604ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6605ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* A7.4.5 Two registers, miscellaneous */
6606ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
6607ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownBool dis_neon_data_2reg_misc ( UInt theInstr, IRTemp condT )
6608ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
6609ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt A = (theInstr >> 16) & 3;
6610ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt B = (theInstr >> 6) & 0x1f;
6611ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt Q = (theInstr >> 6) & 1;
6612ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt U = (theInstr >> 24) & 1;
6613ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt size = (theInstr >> 18) & 3;
6614ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt dreg = get_neon_d_regno(theInstr);
6615ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt mreg = get_neon_m_regno(theInstr);
6616ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt F = (theInstr >> 10) & 1;
6617ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp arg_d;
6618ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp arg_m;
6619ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp res;
6620ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (A) {
6621ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0:
6622ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (Q) {
6623ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            arg_m = newTemp(Ity_V128);
6624ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            res = newTemp(Ity_V128);
6625ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(arg_m, getQReg(mreg));
6626ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
6627ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            arg_m = newTemp(Ity_I64);
6628ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            res = newTemp(Ity_I64);
6629ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(arg_m, getDRegI64(mreg));
6630ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
6631ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         switch (B >> 1) {
6632ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0: {
6633ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* VREV64 */
6634ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IROp op;
6635ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               switch (size) {
6636ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 0:
6637ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op = Q ? Iop_Reverse64_8x16 : Iop_Reverse64_8x8;
6638ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
6639ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 1:
6640ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op = Q ? Iop_Reverse64_16x8 : Iop_Reverse64_16x4;
6641ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
6642ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 2:
6643ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op = Q ? Iop_Reverse64_32x4 : Iop_Reverse64_32x2;
6644ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
6645ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 3:
6646ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     return False;
6647ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  default:
6648ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     vassert(0);
6649ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               }
6650ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign(res, unop(op, mkexpr(arg_m)));
6651ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("vrev64.%u %c%u, %c%u\n", 8 << size,
6652ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', mreg);
6653ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
6654ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
6655ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 1: {
6656ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* VREV32 */
6657ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IROp op;
6658ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               switch (size) {
6659ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 0:
6660ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op = Q ? Iop_Reverse32_8x16 : Iop_Reverse32_8x8;
6661ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
6662ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 1:
6663ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op = Q ? Iop_Reverse32_16x8 : Iop_Reverse32_16x4;
6664ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
6665ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 2:
6666ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 3:
6667ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     return False;
6668ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  default:
6669ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     vassert(0);
6670ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               }
6671ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign(res, unop(op, mkexpr(arg_m)));
6672ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("vrev32.%u %c%u, %c%u\n", 8 << size,
6673ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', mreg);
6674ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
6675ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
6676ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 2: {
6677ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* VREV16 */
6678ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IROp op;
6679ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               switch (size) {
6680ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 0:
6681ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op = Q ? Iop_Reverse16_8x16 : Iop_Reverse16_8x8;
6682ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
6683ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 1:
6684ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 2:
6685ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 3:
6686ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     return False;
6687ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  default:
6688ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     vassert(0);
6689ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               }
6690ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign(res, unop(op, mkexpr(arg_m)));
6691ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("vrev16.%u %c%u, %c%u\n", 8 << size,
6692ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', mreg);
6693ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
6694ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
6695ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 3:
6696ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               return False;
6697ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 4:
6698ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 5: {
6699ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* VPADDL */
6700ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IROp op;
6701ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               U = (theInstr >> 7) & 1;
6702ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               if (Q) {
6703ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  switch (size) {
6704ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     case 0: op = U ? Iop_PwAddL8Ux16 : Iop_PwAddL8Sx16; break;
6705ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     case 1: op = U ? Iop_PwAddL16Ux8 : Iop_PwAddL16Sx8; break;
6706ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     case 2: op = U ? Iop_PwAddL32Ux4 : Iop_PwAddL32Sx4; break;
6707ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     case 3: return False;
6708ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     default: vassert(0);
6709ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  }
6710ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               } else {
6711ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  switch (size) {
6712ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     case 0: op = U ? Iop_PwAddL8Ux8  : Iop_PwAddL8Sx8;  break;
6713ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     case 1: op = U ? Iop_PwAddL16Ux4 : Iop_PwAddL16Sx4; break;
6714ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     case 2: op = U ? Iop_PwAddL32Ux2 : Iop_PwAddL32Sx2; break;
6715ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     case 3: return False;
6716ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     default: vassert(0);
6717ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  }
6718ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               }
6719ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign(res, unop(op, mkexpr(arg_m)));
6720ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("vpaddl.%c%u %c%u, %c%u\n", U ? 'u' : 's', 8 << size,
6721ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', mreg);
6722ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
6723ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
6724ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 6:
6725ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 7:
6726ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               return False;
6727ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 8: {
6728ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* VCLS */
6729ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IROp op;
6730ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               switch (size) {
6731ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 0: op = Q ? Iop_Cls8Sx16 : Iop_Cls8Sx8; break;
6732ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 1: op = Q ? Iop_Cls16Sx8 : Iop_Cls16Sx4; break;
6733ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 2: op = Q ? Iop_Cls32Sx4 : Iop_Cls32Sx2; break;
6734ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 3: return False;
6735ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  default: vassert(0);
6736ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               }
6737ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign(res, unop(op, mkexpr(arg_m)));
6738ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("vcls.s%u %c%u, %c%u\n", 8 << size, Q ? 'q' : 'd', dreg,
6739ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   Q ? 'q' : 'd', mreg);
6740ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
6741ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
6742ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 9: {
6743ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* VCLZ */
6744ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IROp op;
6745ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               switch (size) {
6746ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 0: op = Q ? Iop_Clz8Sx16 : Iop_Clz8Sx8; break;
6747ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 1: op = Q ? Iop_Clz16Sx8 : Iop_Clz16Sx4; break;
6748ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 2: op = Q ? Iop_Clz32Sx4 : Iop_Clz32Sx2; break;
6749ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 3: return False;
6750ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  default: vassert(0);
6751ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               }
6752ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign(res, unop(op, mkexpr(arg_m)));
6753ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("vclz.i%u %c%u, %c%u\n", 8 << size, Q ? 'q' : 'd', dreg,
6754ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   Q ? 'q' : 'd', mreg);
6755ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
6756ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
6757ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 10:
6758ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* VCNT */
6759ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign(res, unop(Q ? Iop_Cnt8x16 : Iop_Cnt8x8, mkexpr(arg_m)));
6760ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("vcnt.8 %c%u, %c%u\n", Q ? 'q' : 'd', dreg, Q ? 'q' : 'd',
6761ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   mreg);
6762ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
6763ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 11:
6764ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* VMVN */
6765ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               if (Q)
6766ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  assign(res, unop(Iop_NotV128, mkexpr(arg_m)));
6767ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               else
6768ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  assign(res, unop(Iop_Not64, mkexpr(arg_m)));
6769ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("vmvn %c%u, %c%u\n", Q ? 'q' : 'd', dreg, Q ? 'q' : 'd',
6770ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   mreg);
6771ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
6772ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 12:
6773ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 13: {
6774ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* VPADAL */
6775ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IROp op, add_op;
6776ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               U = (theInstr >> 7) & 1;
6777ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               if (Q) {
6778ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  switch (size) {
6779ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     case 0:
6780ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        op = U ? Iop_PwAddL8Ux16 : Iop_PwAddL8Sx16;
6781ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        add_op = Iop_Add16x8;
6782ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        break;
6783ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     case 1:
6784ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        op = U ? Iop_PwAddL16Ux8 : Iop_PwAddL16Sx8;
6785ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        add_op = Iop_Add32x4;
6786ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        break;
6787ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     case 2:
6788ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        op = U ? Iop_PwAddL32Ux4 : Iop_PwAddL32Sx4;
6789ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        add_op = Iop_Add64x2;
6790ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        break;
6791ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     case 3:
6792ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        return False;
6793ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     default:
6794ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        vassert(0);
6795ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  }
6796ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               } else {
6797ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  switch (size) {
6798ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     case 0:
6799ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        op = U ? Iop_PwAddL8Ux8 : Iop_PwAddL8Sx8;
6800ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        add_op = Iop_Add16x4;
6801ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        break;
6802ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     case 1:
6803ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        op = U ? Iop_PwAddL16Ux4 : Iop_PwAddL16Sx4;
6804ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        add_op = Iop_Add32x2;
6805ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        break;
6806ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     case 2:
6807ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        op = U ? Iop_PwAddL32Ux2 : Iop_PwAddL32Sx2;
6808ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        add_op = Iop_Add64;
6809ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        break;
6810ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     case 3:
6811ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        return False;
6812ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     default:
6813ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        vassert(0);
6814ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  }
6815ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               }
6816ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               if (Q) {
6817ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  arg_d = newTemp(Ity_V128);
6818ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  assign(arg_d, getQReg(dreg));
6819ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               } else {
6820ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  arg_d = newTemp(Ity_I64);
6821ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  assign(arg_d, getDRegI64(dreg));
6822ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               }
6823ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign(res, binop(add_op, unop(op, mkexpr(arg_m)),
6824ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                         mkexpr(arg_d)));
6825ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("vpadal.%c%u %c%u, %c%u\n", U ? 'u' : 's', 8 << size,
6826ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', mreg);
6827ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
6828ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
6829ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 14: {
6830ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* VQABS */
6831ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IROp op_sub, op_qsub, op_cmp;
6832ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRTemp mask, tmp;
6833ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRExpr *zero1, *zero2;
6834ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRExpr *neg, *neg2;
6835ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               if (Q) {
6836ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  zero1 = binop(Iop_64HLtoV128, mkU64(0), mkU64(0));
6837ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  zero2 = binop(Iop_64HLtoV128, mkU64(0), mkU64(0));
6838ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  mask = newTemp(Ity_V128);
6839ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  tmp = newTemp(Ity_V128);
6840ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               } else {
6841ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  zero1 = mkU64(0);
6842ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  zero2 = mkU64(0);
6843ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  mask = newTemp(Ity_I64);
6844ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  tmp = newTemp(Ity_I64);
6845ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               }
6846ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               switch (size) {
6847ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 0:
6848ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op_sub = Q ? Iop_Sub8x16 : Iop_Sub8x8;
6849ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op_qsub = Q ? Iop_QSub8Sx16 : Iop_QSub8Sx8;
6850ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op_cmp = Q ? Iop_CmpGT8Sx16 : Iop_CmpGT8Sx8;
6851ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
6852ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 1:
6853ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op_sub = Q ? Iop_Sub16x8 : Iop_Sub16x4;
6854ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op_qsub = Q ? Iop_QSub16Sx8 : Iop_QSub16Sx4;
6855ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op_cmp = Q ? Iop_CmpGT16Sx8 : Iop_CmpGT16Sx4;
6856ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
6857ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 2:
6858ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op_sub = Q ? Iop_Sub32x4 : Iop_Sub32x2;
6859ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op_qsub = Q ? Iop_QSub32Sx4 : Iop_QSub32Sx2;
6860ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op_cmp = Q ? Iop_CmpGT32Sx4 : Iop_CmpGT32Sx2;
6861ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
6862ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 3:
6863ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     return False;
6864ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  default:
6865ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     vassert(0);
6866ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               }
6867ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign(mask, binop(op_cmp, mkexpr(arg_m), zero1));
6868ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               neg = binop(op_qsub, zero2, mkexpr(arg_m));
6869ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               neg2 = binop(op_sub, zero2, mkexpr(arg_m));
6870ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign(res, binop(Q ? Iop_OrV128 : Iop_Or64,
6871ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 binop(Q ? Iop_AndV128 : Iop_And64,
6872ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                       mkexpr(mask),
6873ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                       mkexpr(arg_m)),
6874ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 binop(Q ? Iop_AndV128 : Iop_And64,
6875ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                       unop(Q ? Iop_NotV128 : Iop_Not64,
6876ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                            mkexpr(mask)),
6877ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                       neg)));
6878ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#ifndef DISABLE_QC_FLAG
6879ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign(tmp, binop(Q ? Iop_OrV128 : Iop_Or64,
6880ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 binop(Q ? Iop_AndV128 : Iop_And64,
6881ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                       mkexpr(mask),
6882ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                       mkexpr(arg_m)),
6883ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 binop(Q ? Iop_AndV128 : Iop_And64,
6884ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                       unop(Q ? Iop_NotV128 : Iop_Not64,
6885ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                            mkexpr(mask)),
6886ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                       neg2)));
6887ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               setFlag_QC(mkexpr(res), mkexpr(tmp), Q, condT);
6888ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#endif
6889ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("vqabs.s%u %c%u, %c%u\n", 8 << size, Q ? 'q' : 'd', dreg,
6890ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   Q ? 'q' : 'd', mreg);
6891ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
6892ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
6893ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 15: {
6894ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* VQNEG */
6895ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IROp op, op2;
6896ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRExpr *zero;
6897ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               if (Q) {
6898ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  zero = binop(Iop_64HLtoV128, mkU64(0), mkU64(0));
6899ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               } else {
6900ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  zero = mkU64(0);
6901ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               }
6902ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               switch (size) {
6903ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 0:
6904ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op = Q ? Iop_QSub8Sx16 : Iop_QSub8Sx8;
6905ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op2 = Q ? Iop_Sub8x16 : Iop_Sub8x8;
6906ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
6907ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 1:
6908ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op = Q ? Iop_QSub16Sx8 : Iop_QSub16Sx4;
6909ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op2 = Q ? Iop_Sub16x8 : Iop_Sub16x4;
6910ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
6911ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 2:
6912ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op = Q ? Iop_QSub32Sx4 : Iop_QSub32Sx2;
6913ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op2 = Q ? Iop_Sub32x4 : Iop_Sub32x2;
6914ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
6915ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 3:
6916ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     return False;
6917ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  default:
6918ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     vassert(0);
6919ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               }
6920ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign(res, binop(op, zero, mkexpr(arg_m)));
6921ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#ifndef DISABLE_QC_FLAG
6922ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               setFlag_QC(mkexpr(res), binop(op2, zero, mkexpr(arg_m)),
6923ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          Q, condT);
6924ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#endif
6925ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("vqneg.s%u %c%u, %c%u\n", 8 << size, Q ? 'q' : 'd', dreg,
6926ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   Q ? 'q' : 'd', mreg);
6927ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
6928ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
6929ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            default:
6930ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               vassert(0);
6931ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
6932ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (Q) {
6933ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putQReg(dreg, mkexpr(res), condT);
6934ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
6935ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putDRegI64(dreg, mkexpr(res), condT);
6936ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
6937ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         return True;
6938ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 1:
6939ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (Q) {
6940ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            arg_m = newTemp(Ity_V128);
6941ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            res = newTemp(Ity_V128);
6942ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(arg_m, getQReg(mreg));
6943ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
6944ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            arg_m = newTemp(Ity_I64);
6945ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            res = newTemp(Ity_I64);
6946ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(arg_m, getDRegI64(mreg));
6947ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
6948ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         switch ((B >> 1) & 0x7) {
6949ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0: {
6950ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* VCGT #0 */
6951ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRExpr *zero;
6952ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IROp op;
6953ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               if (Q) {
6954ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  zero = binop(Iop_64HLtoV128, mkU64(0), mkU64(0));
6955ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               } else {
6956ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  zero = mkU64(0);
6957ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               }
6958ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               if (F) {
6959ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  switch (size) {
6960ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     case 0: case 1: case 3: return False;
6961ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     case 2: op = Q ? Iop_CmpGT32Fx4 : Iop_CmpGT32Fx2; break;
6962ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     default: vassert(0);
6963ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  }
6964ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               } else {
6965ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  switch (size) {
6966ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     case 0: op = Q ? Iop_CmpGT8Sx16 : Iop_CmpGT8Sx8; break;
6967ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     case 1: op = Q ? Iop_CmpGT16Sx8 : Iop_CmpGT16Sx4; break;
6968ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     case 2: op = Q ? Iop_CmpGT32Sx4 : Iop_CmpGT32Sx2; break;
6969ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     case 3: return False;
6970ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     default: vassert(0);
6971ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  }
6972ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               }
6973ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign(res, binop(op, mkexpr(arg_m), zero));
6974ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("vcgt.%c%u %c%u, %c%u, #0\n", F ? 'f' : 's', 8 << size,
6975ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', mreg);
6976ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
6977ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
6978ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 1: {
6979ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* VCGE #0 */
6980ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IROp op;
6981ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRExpr *zero;
6982ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               if (Q) {
6983ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  zero = binop(Iop_64HLtoV128, mkU64(0), mkU64(0));
6984ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               } else {
6985ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  zero = mkU64(0);
6986ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               }
6987ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               if (F) {
6988ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  switch (size) {
6989ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     case 0: case 1: case 3: return False;
6990ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     case 2: op = Q ? Iop_CmpGE32Fx4 : Iop_CmpGE32Fx2; break;
6991ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     default: vassert(0);
6992ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  }
6993ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  assign(res, binop(op, mkexpr(arg_m), zero));
6994ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               } else {
6995ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  switch (size) {
6996ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     case 0: op = Q ? Iop_CmpGT8Sx16 : Iop_CmpGT8Sx8; break;
6997ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     case 1: op = Q ? Iop_CmpGT16Sx8 : Iop_CmpGT16Sx4; break;
6998ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     case 2: op = Q ? Iop_CmpGT32Sx4 : Iop_CmpGT32Sx2; break;
6999ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     case 3: return False;
7000ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     default: vassert(0);
7001ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  }
7002ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  assign(res, unop(Q ? Iop_NotV128 : Iop_Not64,
7003ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   binop(op, zero, mkexpr(arg_m))));
7004ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               }
7005ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("vcge.%c%u %c%u, %c%u, #0\n", F ? 'f' : 's', 8 << size,
7006ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', mreg);
7007ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
7008ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
7009ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 2: {
7010ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* VCEQ #0 */
7011ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IROp op;
7012ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRExpr *zero;
7013ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               if (F) {
7014ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  if (Q) {
7015ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     zero = binop(Iop_64HLtoV128, mkU64(0), mkU64(0));
7016ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  } else {
7017ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     zero = mkU64(0);
7018ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  }
7019ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  switch (size) {
7020ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     case 0: case 1: case 3: return False;
7021ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     case 2: op = Q ? Iop_CmpEQ32Fx4 : Iop_CmpEQ32Fx2; break;
7022ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     default: vassert(0);
7023ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  }
7024ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  assign(res, binop(op, zero, mkexpr(arg_m)));
7025ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               } else {
7026ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  switch (size) {
7027ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     case 0: op = Q ? Iop_CmpNEZ8x16 : Iop_CmpNEZ8x8; break;
7028ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     case 1: op = Q ? Iop_CmpNEZ16x8 : Iop_CmpNEZ16x4; break;
7029ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     case 2: op = Q ? Iop_CmpNEZ32x4 : Iop_CmpNEZ32x2; break;
7030ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     case 3: return False;
7031ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     default: vassert(0);
7032ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  }
7033ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  assign(res, unop(Q ? Iop_NotV128 : Iop_Not64,
7034ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   unop(op, mkexpr(arg_m))));
7035ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               }
7036ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("vceq.%c%u %c%u, %c%u, #0\n", F ? 'f' : 'i', 8 << size,
7037ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', mreg);
7038ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
7039ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
7040ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 3: {
7041ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* VCLE #0 */
7042ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRExpr *zero;
7043ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IROp op;
7044ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               if (Q) {
7045ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  zero = binop(Iop_64HLtoV128, mkU64(0), mkU64(0));
7046ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               } else {
7047ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  zero = mkU64(0);
7048ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               }
7049ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               if (F) {
7050ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  switch (size) {
7051ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     case 0: case 1: case 3: return False;
7052ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     case 2: op = Q ? Iop_CmpGE32Fx4 : Iop_CmpGE32Fx2; break;
7053ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     default: vassert(0);
7054ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  }
7055ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  assign(res, binop(op, zero, mkexpr(arg_m)));
7056ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               } else {
7057ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  switch (size) {
7058ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     case 0: op = Q ? Iop_CmpGT8Sx16 : Iop_CmpGT8Sx8; break;
7059ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     case 1: op = Q ? Iop_CmpGT16Sx8 : Iop_CmpGT16Sx4; break;
7060ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     case 2: op = Q ? Iop_CmpGT32Sx4 : Iop_CmpGT32Sx2; break;
7061ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     case 3: return False;
7062ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     default: vassert(0);
7063ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  }
7064ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  assign(res, unop(Q ? Iop_NotV128 : Iop_Not64,
7065ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   binop(op, mkexpr(arg_m), zero)));
7066ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               }
7067ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("vcle.%c%u %c%u, %c%u, #0\n", F ? 'f' : 's', 8 << size,
7068ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', mreg);
7069ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
7070ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
7071ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 4: {
7072ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* VCLT #0 */
7073ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IROp op;
7074ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRExpr *zero;
7075ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               if (Q) {
7076ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  zero = binop(Iop_64HLtoV128, mkU64(0), mkU64(0));
7077ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               } else {
7078ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  zero = mkU64(0);
7079ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               }
7080ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               if (F) {
7081ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  switch (size) {
7082ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     case 0: case 1: case 3: return False;
7083ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     case 2: op = Q ? Iop_CmpGT32Fx4 : Iop_CmpGT32Fx2; break;
7084ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     default: vassert(0);
7085ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  }
7086ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  assign(res, binop(op, zero, mkexpr(arg_m)));
7087ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               } else {
7088ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  switch (size) {
7089ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     case 0: op = Q ? Iop_CmpGT8Sx16 : Iop_CmpGT8Sx8; break;
7090ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     case 1: op = Q ? Iop_CmpGT16Sx8 : Iop_CmpGT16Sx4; break;
7091ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     case 2: op = Q ? Iop_CmpGT32Sx4 : Iop_CmpGT32Sx2; break;
7092ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     case 3: return False;
7093ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     default: vassert(0);
7094ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  }
7095ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  assign(res, binop(op, zero, mkexpr(arg_m)));
7096ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               }
7097ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("vclt.%c%u %c%u, %c%u, #0\n", F ? 'f' : 's', 8 << size,
7098ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', mreg);
7099ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
7100ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
7101ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 5:
7102ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               return False;
7103ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 6: {
7104ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* VABS */
7105ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               if (!F) {
7106ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  IROp op;
7107ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  switch(size) {
7108ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     case 0: op = Q ? Iop_Abs8x16 : Iop_Abs8x8; break;
7109ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     case 1: op = Q ? Iop_Abs16x8 : Iop_Abs16x4; break;
7110ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     case 2: op = Q ? Iop_Abs32x4 : Iop_Abs32x2; break;
7111ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     case 3: return False;
7112ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     default: vassert(0);
7113ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  }
7114ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  assign(res, unop(op, mkexpr(arg_m)));
7115ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               } else {
7116ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  assign(res, unop(Q ? Iop_Abs32Fx4 : Iop_Abs32Fx2,
7117ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   mkexpr(arg_m)));
7118ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               }
7119ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("vabs.%c%u %c%u, %c%u\n",
7120ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   F ? 'f' : 's', 8 << size, Q ? 'q' : 'd', dreg,
7121ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   Q ? 'q' : 'd', mreg);
7122ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
7123ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
7124ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 7: {
7125ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* VNEG */
7126ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IROp op;
7127ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRExpr *zero;
7128ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               if (F) {
7129ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  switch (size) {
7130ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     case 0: case 1: case 3: return False;
7131ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     case 2: op = Q ? Iop_Neg32Fx4 : Iop_Neg32Fx2; break;
7132ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     default: vassert(0);
7133ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  }
7134ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  assign(res, unop(op, mkexpr(arg_m)));
7135ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               } else {
7136ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  if (Q) {
7137ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     zero = binop(Iop_64HLtoV128, mkU64(0), mkU64(0));
7138ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  } else {
7139ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     zero = mkU64(0);
7140ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  }
7141ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  switch (size) {
7142ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     case 0: op = Q ? Iop_Sub8x16 : Iop_Sub8x8; break;
7143ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     case 1: op = Q ? Iop_Sub16x8 : Iop_Sub16x4; break;
7144ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     case 2: op = Q ? Iop_Sub32x4 : Iop_Sub32x2; break;
7145ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     case 3: return False;
7146ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     default: vassert(0);
7147ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  }
7148ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  assign(res, binop(op, zero, mkexpr(arg_m)));
7149ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               }
7150ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("vneg.%c%u %c%u, %c%u\n",
7151ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   F ? 'f' : 's', 8 << size, Q ? 'q' : 'd', dreg,
7152ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   Q ? 'q' : 'd', mreg);
7153ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
7154ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
7155ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            default:
7156ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               vassert(0);
7157ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
7158ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (Q) {
7159ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putQReg(dreg, mkexpr(res), condT);
7160ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
7161ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putDRegI64(dreg, mkexpr(res), condT);
7162ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
7163ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         return True;
7164ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 2:
7165ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if ((B >> 1) == 0) {
7166ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* VSWP */
7167ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (Q) {
7168ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               arg_m = newTemp(Ity_V128);
7169ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign(arg_m, getQReg(mreg));
7170ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               putQReg(mreg, getQReg(dreg), condT);
7171ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               putQReg(dreg, mkexpr(arg_m), condT);
7172ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            } else {
7173ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               arg_m = newTemp(Ity_I64);
7174ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign(arg_m, getDRegI64(mreg));
7175ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               putDRegI64(mreg, getDRegI64(dreg), condT);
7176ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               putDRegI64(dreg, mkexpr(arg_m), condT);
7177ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
7178ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("vswp %c%u, %c%u\n",
7179ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', mreg);
7180ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            return True;
7181ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else if ((B >> 1) == 1) {
7182ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* VTRN */
7183ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            IROp op_lo, op_hi;
7184ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            IRTemp res1, res2;
7185ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (Q) {
7186ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               arg_m = newTemp(Ity_V128);
7187ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               arg_d = newTemp(Ity_V128);
7188ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               res1 = newTemp(Ity_V128);
7189ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               res2 = newTemp(Ity_V128);
7190ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign(arg_m, getQReg(mreg));
7191ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign(arg_d, getQReg(dreg));
7192ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            } else {
7193ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               res1 = newTemp(Ity_I64);
7194ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               res2 = newTemp(Ity_I64);
7195ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               arg_m = newTemp(Ity_I64);
7196ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               arg_d = newTemp(Ity_I64);
7197ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign(arg_m, getDRegI64(mreg));
7198ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign(arg_d, getDRegI64(dreg));
7199ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
7200ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (Q) {
7201ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               switch (size) {
7202ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 0:
7203ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op_lo = Iop_InterleaveOddLanes8x16;
7204ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op_hi = Iop_InterleaveEvenLanes8x16;
7205ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
7206ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 1:
7207ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op_lo = Iop_InterleaveOddLanes16x8;
7208ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op_hi = Iop_InterleaveEvenLanes16x8;
7209ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
7210ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 2:
7211ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op_lo = Iop_InterleaveOddLanes32x4;
7212ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op_hi = Iop_InterleaveEvenLanes32x4;
7213ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
7214ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 3:
7215ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     return False;
7216ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  default:
7217ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     vassert(0);
7218ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               }
7219ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            } else {
7220ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               switch (size) {
7221ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 0:
7222ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op_lo = Iop_InterleaveOddLanes8x8;
7223ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op_hi = Iop_InterleaveEvenLanes8x8;
7224ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
7225ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 1:
7226ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op_lo = Iop_InterleaveOddLanes16x4;
7227ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op_hi = Iop_InterleaveEvenLanes16x4;
7228ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
7229ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 2:
7230ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op_lo = Iop_InterleaveLO32x2;
7231ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     op_hi = Iop_InterleaveHI32x2;
7232ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
7233ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 3:
7234ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     return False;
7235ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  default:
7236ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     vassert(0);
7237ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               }
7238ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
7239ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(res1, binop(op_lo, mkexpr(arg_m), mkexpr(arg_d)));
7240ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(res2, binop(op_hi, mkexpr(arg_m), mkexpr(arg_d)));
7241ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (Q) {
7242ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               putQReg(dreg, mkexpr(res1), condT);
7243ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               putQReg(mreg, mkexpr(res2), condT);
7244ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            } else {
7245ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               putDRegI64(dreg, mkexpr(res1), condT);
7246ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               putDRegI64(mreg, mkexpr(res2), condT);
7247ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
7248ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("vtrn.%u %c%u, %c%u\n",
7249ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                8 << size, Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', mreg);
7250ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            return True;
7251ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else if ((B >> 1) == 2) {
7252ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* VUZP */
7253ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            IROp op_lo, op_hi;
7254ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            IRTemp res1, res2;
7255ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (!Q && size == 2)
7256ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               return False;
7257ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (Q) {
7258ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               arg_m = newTemp(Ity_V128);
7259ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               arg_d = newTemp(Ity_V128);
7260ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               res1 = newTemp(Ity_V128);
7261ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               res2 = newTemp(Ity_V128);
7262ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign(arg_m, getQReg(mreg));
7263ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign(arg_d, getQReg(dreg));
7264ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            } else {
7265ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               res1 = newTemp(Ity_I64);
7266ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               res2 = newTemp(Ity_I64);
7267ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               arg_m = newTemp(Ity_I64);
7268ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               arg_d = newTemp(Ity_I64);
7269ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign(arg_m, getDRegI64(mreg));
7270ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign(arg_d, getDRegI64(dreg));
7271ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
7272ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            switch (size) {
7273ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               case 0:
7274ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  op_lo = Q ? Iop_CatOddLanes8x16 : Iop_CatOddLanes8x8;
7275ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  op_hi = Q ? Iop_CatEvenLanes8x16 : Iop_CatEvenLanes8x8;
7276ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  break;
7277ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               case 1:
7278ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  op_lo = Q ? Iop_CatOddLanes16x8 : Iop_CatOddLanes16x4;
7279ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  op_hi = Q ? Iop_CatEvenLanes16x8 : Iop_CatEvenLanes16x4;
7280ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  break;
7281ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               case 2:
7282ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  op_lo = Iop_CatOddLanes32x4;
7283ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  op_hi = Iop_CatEvenLanes32x4;
7284ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  break;
7285ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               case 3:
7286ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  return False;
7287ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               default:
7288ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  vassert(0);
7289ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
7290ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(res1, binop(op_lo, mkexpr(arg_m), mkexpr(arg_d)));
7291ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(res2, binop(op_hi, mkexpr(arg_m), mkexpr(arg_d)));
7292ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (Q) {
7293ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               putQReg(dreg, mkexpr(res1), condT);
7294ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               putQReg(mreg, mkexpr(res2), condT);
7295ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            } else {
7296ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               putDRegI64(dreg, mkexpr(res1), condT);
7297ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               putDRegI64(mreg, mkexpr(res2), condT);
7298ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
7299ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("vuzp.%u %c%u, %c%u\n",
7300ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                8 << size, Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', mreg);
7301ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            return True;
7302ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else if ((B >> 1) == 3) {
7303ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* VZIP */
7304ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            IROp op_lo, op_hi;
7305ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            IRTemp res1, res2;
7306ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (!Q && size == 2)
7307ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               return False;
7308ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (Q) {
7309ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               arg_m = newTemp(Ity_V128);
7310ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               arg_d = newTemp(Ity_V128);
7311ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               res1 = newTemp(Ity_V128);
7312ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               res2 = newTemp(Ity_V128);
7313ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign(arg_m, getQReg(mreg));
7314ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign(arg_d, getQReg(dreg));
7315ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            } else {
7316ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               res1 = newTemp(Ity_I64);
7317ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               res2 = newTemp(Ity_I64);
7318ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               arg_m = newTemp(Ity_I64);
7319ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               arg_d = newTemp(Ity_I64);
7320ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign(arg_m, getDRegI64(mreg));
7321ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign(arg_d, getDRegI64(dreg));
7322ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
7323ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            switch (size) {
7324ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               case 0:
7325ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  op_lo = Q ? Iop_InterleaveHI8x16 : Iop_InterleaveHI8x8;
7326ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  op_hi = Q ? Iop_InterleaveLO8x16 : Iop_InterleaveLO8x8;
7327ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  break;
7328ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               case 1:
7329ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  op_lo = Q ? Iop_InterleaveHI16x8 : Iop_InterleaveHI16x4;
7330ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  op_hi = Q ? Iop_InterleaveLO16x8 : Iop_InterleaveLO16x4;
7331ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  break;
7332ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               case 2:
7333ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  op_lo = Iop_InterleaveHI32x4;
7334ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  op_hi = Iop_InterleaveLO32x4;
7335ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  break;
7336ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               case 3:
7337ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  return False;
7338ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               default:
7339ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  vassert(0);
7340ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
7341ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(res1, binop(op_lo, mkexpr(arg_m), mkexpr(arg_d)));
7342ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(res2, binop(op_hi, mkexpr(arg_m), mkexpr(arg_d)));
7343ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (Q) {
7344ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               putQReg(dreg, mkexpr(res1), condT);
7345ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               putQReg(mreg, mkexpr(res2), condT);
7346ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            } else {
7347ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               putDRegI64(dreg, mkexpr(res1), condT);
7348ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               putDRegI64(mreg, mkexpr(res2), condT);
7349ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
7350ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("vzip.%u %c%u, %c%u\n",
7351ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                8 << size, Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', mreg);
7352ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            return True;
7353ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else if (B == 8) {
7354ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* VMOVN */
7355ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            IROp op;
7356ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            mreg >>= 1;
7357ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            switch (size) {
7358b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               case 0: op = Iop_NarrowUn16to8x8;  break;
7359b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               case 1: op = Iop_NarrowUn32to16x4; break;
7360b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               case 2: op = Iop_NarrowUn64to32x2; break;
7361ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               case 3: return False;
7362ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               default: vassert(0);
7363ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
7364ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putDRegI64(dreg, unop(op, getQReg(mreg)), condT);
7365ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("vmovn.i%u d%u, q%u\n", 16 << size, dreg, mreg);
7366ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            return True;
7367ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else if (B == 9 || (B >> 1) == 5) {
7368ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* VQMOVN, VQMOVUN */
7369ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            IROp op, op2;
7370ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            IRTemp tmp;
7371ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            dreg = ((theInstr >> 18) & 0x10) | ((theInstr >> 12) & 0xF);
7372ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            mreg = ((theInstr >> 1) & 0x10) | (theInstr & 0xF);
7373ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (mreg & 1)
7374ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               return False;
7375ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            mreg >>= 1;
7376ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            switch (size) {
7377b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               case 0: op2 = Iop_NarrowUn16to8x8;  break;
7378b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               case 1: op2 = Iop_NarrowUn32to16x4; break;
7379b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               case 2: op2 = Iop_NarrowUn64to32x2; break;
7380ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               case 3: return False;
7381ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               default: vassert(0);
7382ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
7383ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            switch (B & 3) {
7384ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               case 0:
7385ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  vassert(0);
7386ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               case 1:
7387ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  switch (size) {
7388b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                     case 0: op = Iop_QNarrowUn16Sto8Ux8;  break;
7389b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                     case 1: op = Iop_QNarrowUn32Sto16Ux4; break;
7390b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                     case 2: op = Iop_QNarrowUn64Sto32Ux2; break;
7391ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     case 3: return False;
7392ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     default: vassert(0);
7393ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  }
7394ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  DIP("vqmovun.s%u d%u, q%u\n", 16 << size, dreg, mreg);
7395ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  break;
7396ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               case 2:
7397ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  switch (size) {
7398b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                     case 0: op = Iop_QNarrowUn16Sto8Sx8;  break;
7399b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                     case 1: op = Iop_QNarrowUn32Sto16Sx4; break;
7400b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                     case 2: op = Iop_QNarrowUn64Sto32Sx2; break;
7401ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     case 3: return False;
7402ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     default: vassert(0);
7403ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  }
7404ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  DIP("vqmovn.s%u d%u, q%u\n", 16 << size, dreg, mreg);
7405ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  break;
7406ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               case 3:
7407ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  switch (size) {
7408b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                     case 0: op = Iop_QNarrowUn16Uto8Ux8;  break;
7409b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                     case 1: op = Iop_QNarrowUn32Uto16Ux4; break;
7410b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                     case 2: op = Iop_QNarrowUn64Uto32Ux2; break;
7411ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     case 3: return False;
7412ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     default: vassert(0);
7413ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  }
7414ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  DIP("vqmovn.u%u d%u, q%u\n", 16 << size, dreg, mreg);
7415ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  break;
7416ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               default:
7417ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  vassert(0);
7418ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
7419ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            res = newTemp(Ity_I64);
7420ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            tmp = newTemp(Ity_I64);
7421ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(res, unop(op, getQReg(mreg)));
7422ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#ifndef DISABLE_QC_FLAG
7423ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(tmp, unop(op2, getQReg(mreg)));
7424ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            setFlag_QC(mkexpr(res), mkexpr(tmp), False, condT);
7425ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#endif
7426ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putDRegI64(dreg, mkexpr(res), condT);
7427ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            return True;
7428ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else if (B == 12) {
7429ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* VSHLL (maximum shift) */
7430ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            IROp op, cvt;
7431ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            UInt shift_imm;
7432ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (Q)
7433ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               return False;
7434ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (dreg & 1)
7435ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               return False;
7436ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            dreg >>= 1;
7437ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            shift_imm = 8 << size;
7438ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            res = newTemp(Ity_V128);
7439ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            switch (size) {
7440b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               case 0: op = Iop_ShlN16x8; cvt = Iop_Widen8Uto16x8;  break;
7441b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               case 1: op = Iop_ShlN32x4; cvt = Iop_Widen16Uto32x4; break;
7442b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               case 2: op = Iop_ShlN64x2; cvt = Iop_Widen32Uto64x2; break;
7443ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               case 3: return False;
7444ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               default: vassert(0);
7445ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
7446ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(res, binop(op, unop(cvt, getDRegI64(mreg)),
7447ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  mkU8(shift_imm)));
7448ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putQReg(dreg, mkexpr(res), condT);
7449ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("vshll.i%u q%u, d%u, #%u\n", 8 << size, dreg, mreg, 8 << size);
7450ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            return True;
7451ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else if ((B >> 3) == 3 && (B & 3) == 0) {
7452ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* VCVT (half<->single) */
7453ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* Half-precision extensions are needed to run this */
7454ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            vassert(0); // ATC
7455ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (((theInstr >> 18) & 3) != 1)
7456ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               return False;
7457ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if ((theInstr >> 8) & 1) {
7458ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               if (dreg & 1)
7459ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  return False;
7460ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               dreg >>= 1;
7461ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               putQReg(dreg, unop(Iop_F16toF32x4, getDRegI64(mreg)),
7462ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     condT);
7463ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("vcvt.f32.f16 q%u, d%u\n", dreg, mreg);
7464ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            } else {
7465ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               if (mreg & 1)
7466ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  return False;
7467ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               mreg >>= 1;
7468ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               putDRegI64(dreg, unop(Iop_F32toF16x4, getQReg(mreg)),
7469ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                condT);
7470ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("vcvt.f16.f32 d%u, q%u\n", dreg, mreg);
7471ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
7472ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            return True;
7473ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
7474ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            return False;
7475ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
7476ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vassert(0);
7477ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         return True;
7478ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 3:
7479ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (((B >> 1) & BITS4(1,1,0,1)) == BITS4(1,0,0,0)) {
7480ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* VRECPE */
7481ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            IROp op;
7482ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            F = (theInstr >> 8) & 1;
7483ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (size != 2)
7484ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               return False;
7485ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (Q) {
7486ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               op = F ? Iop_Recip32Fx4 : Iop_Recip32x4;
7487ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               putQReg(dreg, unop(op, getQReg(mreg)), condT);
7488ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("vrecpe.%c32 q%u, q%u\n", F ? 'f' : 'u', dreg, mreg);
7489ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            } else {
7490ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               op = F ? Iop_Recip32Fx2 : Iop_Recip32x2;
7491ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               putDRegI64(dreg, unop(op, getDRegI64(mreg)), condT);
7492ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("vrecpe.%c32 d%u, d%u\n", F ? 'f' : 'u', dreg, mreg);
7493ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
7494ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            return True;
7495ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else if (((B >> 1) & BITS4(1,1,0,1)) == BITS4(1,0,0,1)) {
7496ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* VRSQRTE */
7497ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            IROp op;
7498ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            F = (B >> 2) & 1;
7499ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (size != 2)
7500ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               return False;
7501ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (F) {
7502ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* fp */
7503ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               op = Q ? Iop_Rsqrte32Fx4 : Iop_Rsqrte32Fx2;
7504ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            } else {
7505ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* unsigned int */
7506ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               op = Q ? Iop_Rsqrte32x4 : Iop_Rsqrte32x2;
7507ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
7508ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (Q) {
7509ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               putQReg(dreg, unop(op, getQReg(mreg)), condT);
7510ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("vrsqrte.%c32 q%u, q%u\n", F ? 'f' : 'u', dreg, mreg);
7511ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            } else {
7512ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               putDRegI64(dreg, unop(op, getDRegI64(mreg)), condT);
7513ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("vrsqrte.%c32 d%u, d%u\n", F ? 'f' : 'u', dreg, mreg);
7514ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
7515ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            return True;
7516ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else if ((B >> 3) == 3) {
7517ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* VCVT (fp<->integer) */
7518ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            IROp op;
7519ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (size != 2)
7520ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               return False;
7521ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            switch ((B >> 1) & 3) {
7522ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               case 0:
7523ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  op = Q ? Iop_I32StoFx4 : Iop_I32StoFx2;
7524ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  DIP("vcvt.f32.s32 %c%u, %c%u\n",
7525ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', mreg);
7526ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  break;
7527ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               case 1:
7528ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  op = Q ? Iop_I32UtoFx4 : Iop_I32UtoFx2;
7529ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  DIP("vcvt.f32.u32 %c%u, %c%u\n",
7530ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', mreg);
7531ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  break;
7532ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               case 2:
7533ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  op = Q ? Iop_FtoI32Sx4_RZ : Iop_FtoI32Sx2_RZ;
7534ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  DIP("vcvt.s32.f32 %c%u, %c%u\n",
7535ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', mreg);
7536ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  break;
7537ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               case 3:
7538ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  op = Q ? Iop_FtoI32Ux4_RZ : Iop_FtoI32Ux2_RZ;
7539ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  DIP("vcvt.u32.f32 %c%u, %c%u\n",
7540ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      Q ? 'q' : 'd', dreg, Q ? 'q' : 'd', mreg);
7541ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  break;
7542ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               default:
7543ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  vassert(0);
7544ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
7545ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (Q) {
7546ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               putQReg(dreg, unop(op, getQReg(mreg)), condT);
7547ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            } else {
7548ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               putDRegI64(dreg, unop(op, getDRegI64(mreg)), condT);
7549ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
7550ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            return True;
7551ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
7552ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            return False;
7553ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
7554ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vassert(0);
7555ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         return True;
7556ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default:
7557ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vassert(0);
7558ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
7559ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return False;
7560ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
7561ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7562ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* A7.4.6 One register and a modified immediate value */
7563ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
7564ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid ppNeonImm(UInt imm, UInt cmode, UInt op)
7565ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
7566ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   int i;
7567ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (cmode) {
7568ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0: case 1: case 8: case 9:
7569ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vex_printf("0x%x", imm);
7570ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
7571ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 2: case 3: case 10: case 11:
7572ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vex_printf("0x%x00", imm);
7573ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
7574ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 4: case 5:
7575ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vex_printf("0x%x0000", imm);
7576ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
7577ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 6: case 7:
7578ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vex_printf("0x%x000000", imm);
7579ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
7580ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 12:
7581ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vex_printf("0x%xff", imm);
7582ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
7583ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 13:
7584ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vex_printf("0x%xffff", imm);
7585ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
7586ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 14:
7587ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (op) {
7588ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            vex_printf("0x");
7589ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            for (i = 7; i >= 0; i--)
7590ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               vex_printf("%s", (imm & (1 << i)) ? "ff" : "00");
7591ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
7592ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            vex_printf("0x%x", imm);
7593ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
7594ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
7595ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 15:
7596ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vex_printf("0x%x", imm);
7597ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
7598ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
7599ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
7600ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7601ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
7602ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownconst char *ppNeonImmType(UInt cmode, UInt op)
7603ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
7604ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (cmode) {
7605ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0 ... 7:
7606ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 12: case 13:
7607ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         return "i32";
7608ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 8 ... 11:
7609ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         return "i16";
7610ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 14:
7611ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (op)
7612ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            return "i64";
7613ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         else
7614ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            return "i8";
7615ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 15:
7616ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (op)
7617ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            vassert(0);
7618ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         else
7619ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            return "f32";
7620ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default:
7621ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vassert(0);
7622ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
7623ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
7624ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7625ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
7626ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid DIPimm(UInt imm, UInt cmode, UInt op,
7627ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            const char *instr, UInt Q, UInt dreg)
7628ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
7629ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (vex_traceflags & VEX_TRACE_FE) {
7630ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vex_printf("%s.%s %c%u, #", instr,
7631ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 ppNeonImmType(cmode, op), Q ? 'q' : 'd', dreg);
7632ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ppNeonImm(imm, cmode, op);
7633ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vex_printf("\n");
7634ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
7635ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
7636ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7637ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
7638ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownBool dis_neon_data_1reg_and_imm ( UInt theInstr, IRTemp condT )
7639ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
7640ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt dreg = get_neon_d_regno(theInstr);
7641ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ULong imm_raw = ((theInstr >> 17) & 0x80) | ((theInstr >> 12) & 0x70) |
7642ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  (theInstr & 0xf);
7643ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ULong imm_raw_pp = imm_raw;
7644ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt cmode = (theInstr >> 8) & 0xf;
7645ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt op_bit = (theInstr >> 5) & 1;
7646ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ULong imm = 0;
7647ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt Q = (theInstr >> 6) & 1;
7648ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   int i, j;
7649ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt tmp;
7650ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRExpr *imm_val;
7651ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRExpr *expr;
7652ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp tmp_var;
7653ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch(cmode) {
7654ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 7: case 6:
7655ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         imm_raw = imm_raw << 8;
7656ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* fallthrough */
7657ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 5: case 4:
7658ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         imm_raw = imm_raw << 8;
7659ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* fallthrough */
7660ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 3: case 2:
7661ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         imm_raw = imm_raw << 8;
7662ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* fallthrough */
7663ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0: case 1:
7664ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         imm = (imm_raw << 32) | imm_raw;
7665ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
7666ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 11: case 10:
7667ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         imm_raw = imm_raw << 8;
7668ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* fallthrough */
7669ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 9: case 8:
7670ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         imm_raw = (imm_raw << 16) | imm_raw;
7671ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         imm = (imm_raw << 32) | imm_raw;
7672ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
7673ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 13:
7674ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         imm_raw = (imm_raw << 8) | 0xff;
7675ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* fallthrough */
7676ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 12:
7677ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         imm_raw = (imm_raw << 8) | 0xff;
7678ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         imm = (imm_raw << 32) | imm_raw;
7679ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
7680ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 14:
7681ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (! op_bit) {
7682ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            for(i = 0; i < 8; i++) {
7683ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               imm = (imm << 8) | imm_raw;
7684ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
7685ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
7686ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            for(i = 7; i >= 0; i--) {
7687ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               tmp = 0;
7688ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               for(j = 0; j < 8; j++) {
7689ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  tmp = (tmp << 1) | ((imm_raw >> i) & 1);
7690ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               }
7691ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               imm = (imm << 8) | tmp;
7692ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
7693ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
7694ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
7695ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 15:
7696ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         imm = (imm_raw & 0x80) << 5;
7697b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         imm |= ((~imm_raw & 0x40) << 5);
7698ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         for(i = 1; i <= 4; i++)
7699ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            imm |= (imm_raw & 0x40) << i;
7700ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         imm |= (imm_raw & 0x7f);
7701ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         imm = imm << 19;
7702ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         imm = (imm << 32) | imm;
7703ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
7704ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default:
7705ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         return False;
7706ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
7707ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (Q) {
7708ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      imm_val = binop(Iop_64HLtoV128, mkU64(imm), mkU64(imm));
7709ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
7710ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      imm_val = mkU64(imm);
7711ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
7712ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (((op_bit == 0) &&
7713ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      (((cmode & 9) == 0) || ((cmode & 13) == 8) || ((cmode & 12) == 12))) ||
7714ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ((op_bit == 1) && (cmode == 14))) {
7715ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* VMOV (immediate) */
7716ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (Q) {
7717ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putQReg(dreg, imm_val, condT);
7718ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
7719ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putDRegI64(dreg, imm_val, condT);
7720ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
7721ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIPimm(imm_raw_pp, cmode, op_bit, "vmov", Q, dreg);
7722ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return True;
7723ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
7724ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if ((op_bit == 1) &&
7725ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      (((cmode & 9) == 0) || ((cmode & 13) == 8) || ((cmode & 14) == 12))) {
7726ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* VMVN (immediate) */
7727ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (Q) {
7728ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putQReg(dreg, unop(Iop_NotV128, imm_val), condT);
7729ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
7730ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putDRegI64(dreg, unop(Iop_Not64, imm_val), condT);
7731ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
7732ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIPimm(imm_raw_pp, cmode, op_bit, "vmvn", Q, dreg);
7733ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return True;
7734ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
7735ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (Q) {
7736ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tmp_var = newTemp(Ity_V128);
7737ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(tmp_var, getQReg(dreg));
7738ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
7739ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tmp_var = newTemp(Ity_I64);
7740ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(tmp_var, getDRegI64(dreg));
7741ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
7742ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if ((op_bit == 0) && (((cmode & 9) == 1) || ((cmode & 13) == 9))) {
7743ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* VORR (immediate) */
7744ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (Q)
7745ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         expr = binop(Iop_OrV128, mkexpr(tmp_var), imm_val);
7746ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      else
7747ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         expr = binop(Iop_Or64, mkexpr(tmp_var), imm_val);
7748ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIPimm(imm_raw_pp, cmode, op_bit, "vorr", Q, dreg);
7749ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else if ((op_bit == 1) && (((cmode & 9) == 1) || ((cmode & 13) == 9))) {
7750ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* VBIC (immediate) */
7751ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (Q)
7752ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         expr = binop(Iop_AndV128, mkexpr(tmp_var),
7753ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   unop(Iop_NotV128, imm_val));
7754ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      else
7755ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         expr = binop(Iop_And64, mkexpr(tmp_var), unop(Iop_Not64, imm_val));
7756ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIPimm(imm_raw_pp, cmode, op_bit, "vbic", Q, dreg);
7757ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
7758ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return False;
7759ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
7760ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (Q)
7761ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putQReg(dreg, expr, condT);
7762ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else
7763ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putDRegI64(dreg, expr, condT);
7764ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return True;
7765ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
7766ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7767ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* A7.4 Advanced SIMD data-processing instructions */
7768ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
7769ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownBool dis_neon_data_processing ( UInt theInstr, IRTemp condT )
7770ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
7771ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt A = (theInstr >> 19) & 0x1F;
7772ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt B = (theInstr >>  8) & 0xF;
7773ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt C = (theInstr >>  4) & 0xF;
7774ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt U = (theInstr >> 24) & 0x1;
7775ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7776ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (! (A & 0x10)) {
7777ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return dis_neon_data_3same(theInstr, condT);
7778ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
7779ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (((A & 0x17) == 0x10) && ((C & 0x9) == 0x1)) {
7780ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return dis_neon_data_1reg_and_imm(theInstr, condT);
7781ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
7782ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if ((C & 1) == 1) {
7783ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return dis_neon_data_2reg_and_shift(theInstr, condT);
7784ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
7785ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (((C & 5) == 0) && (((A & 0x14) == 0x10) || ((A & 0x16) == 0x14))) {
7786ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return dis_neon_data_3diff(theInstr, condT);
7787ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
7788ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (((C & 5) == 4) && (((A & 0x14) == 0x10) || ((A & 0x16) == 0x14))) {
7789ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return dis_neon_data_2reg_and_scalar(theInstr, condT);
7790ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
7791ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if ((A & 0x16) == 0x16) {
7792ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if ((U == 0) && ((C & 1) == 0)) {
7793ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         return dis_neon_vext(theInstr, condT);
7794ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
7795ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if ((U != 1) || ((C & 1) == 1))
7796ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         return False;
7797ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if ((B & 8) == 0) {
7798ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         return dis_neon_data_2reg_misc(theInstr, condT);
7799ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
7800ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if ((B & 12) == 8) {
7801ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         return dis_neon_vtb(theInstr, condT);
7802ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
7803ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if ((B == 12) && ((C & 9) == 0)) {
7804ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         return dis_neon_vdup(theInstr, condT);
7805ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
7806ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
7807ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return False;
7808ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
7809ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7810ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7811ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
7812ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- NEON loads and stores                                ---*/
7813ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
7814ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7815ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* For NEON memory operations, we use the standard scheme to handle
7816ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   conditionalisation: generate a jump around the instruction if the
7817ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   condition is false.  That's only necessary in Thumb mode, however,
7818ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   since in ARM mode NEON instructions are unconditional. */
7819ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7820ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* A helper function for what follows.  It assumes we already went
7821ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   uncond as per comments at the top of this section. */
7822ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
7823ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid mk_neon_elem_load_to_one_lane( UInt rD, UInt inc, UInt index,
7824ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    UInt N, UInt size, IRTemp addr )
7825ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
7826ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt i;
7827ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (size) {
7828ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0:
7829ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putDRegI64(rD, triop(Iop_SetElem8x8, getDRegI64(rD), mkU8(index),
7830ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    loadLE(Ity_I8, mkexpr(addr))), IRTemp_INVALID);
7831ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
7832ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 1:
7833ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putDRegI64(rD, triop(Iop_SetElem16x4, getDRegI64(rD), mkU8(index),
7834ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    loadLE(Ity_I16, mkexpr(addr))), IRTemp_INVALID);
7835ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
7836ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 2:
7837ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putDRegI64(rD, triop(Iop_SetElem32x2, getDRegI64(rD), mkU8(index),
7838ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    loadLE(Ity_I32, mkexpr(addr))), IRTemp_INVALID);
7839ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
7840ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default:
7841ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vassert(0);
7842ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
7843ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (i = 1; i <= N; i++) {
7844ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      switch (size) {
7845ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0:
7846ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putDRegI64(rD + i * inc,
7847ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       triop(Iop_SetElem8x8,
7848ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             getDRegI64(rD + i * inc),
7849ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             mkU8(index),
7850ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             loadLE(Ity_I8, binop(Iop_Add32,
7851ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                                  mkexpr(addr),
7852ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                                  mkU32(i * 1)))),
7853ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       IRTemp_INVALID);
7854ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
7855ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 1:
7856ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putDRegI64(rD + i * inc,
7857ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       triop(Iop_SetElem16x4,
7858ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             getDRegI64(rD + i * inc),
7859ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             mkU8(index),
7860ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             loadLE(Ity_I16, binop(Iop_Add32,
7861ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                                   mkexpr(addr),
7862ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                                   mkU32(i * 2)))),
7863ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       IRTemp_INVALID);
7864ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
7865ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 2:
7866ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putDRegI64(rD + i * inc,
7867ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       triop(Iop_SetElem32x2,
7868ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             getDRegI64(rD + i * inc),
7869ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             mkU8(index),
7870ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             loadLE(Ity_I32, binop(Iop_Add32,
7871ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                                   mkexpr(addr),
7872ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                                   mkU32(i * 4)))),
7873ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       IRTemp_INVALID);
7874ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
7875ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         default:
7876ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            vassert(0);
7877ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
7878ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
7879ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
7880ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7881ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* A(nother) helper function for what follows.  It assumes we already
7882ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   went uncond as per comments at the top of this section. */
7883ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
7884ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid mk_neon_elem_store_from_one_lane( UInt rD, UInt inc, UInt index,
7885ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                       UInt N, UInt size, IRTemp addr )
7886ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
7887ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt i;
7888ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (size) {
7889ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0:
7890ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         storeLE(mkexpr(addr),
7891ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 binop(Iop_GetElem8x8, getDRegI64(rD), mkU8(index)));
7892ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
7893ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 1:
7894ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         storeLE(mkexpr(addr),
7895ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 binop(Iop_GetElem16x4, getDRegI64(rD), mkU8(index)));
7896ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
7897ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 2:
7898ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         storeLE(mkexpr(addr),
7899ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 binop(Iop_GetElem32x2, getDRegI64(rD), mkU8(index)));
7900ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
7901ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default:
7902ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vassert(0);
7903ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
7904ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (i = 1; i <= N; i++) {
7905ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      switch (size) {
7906ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0:
7907ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            storeLE(binop(Iop_Add32, mkexpr(addr), mkU32(i * 1)),
7908ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    binop(Iop_GetElem8x8, getDRegI64(rD + i * inc),
7909ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                          mkU8(index)));
7910ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
7911ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 1:
7912ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            storeLE(binop(Iop_Add32, mkexpr(addr), mkU32(i * 2)),
7913ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    binop(Iop_GetElem16x4, getDRegI64(rD + i * inc),
7914ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                           mkU8(index)));
7915ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
7916ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 2:
7917ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            storeLE(binop(Iop_Add32, mkexpr(addr), mkU32(i * 4)),
7918ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    binop(Iop_GetElem32x2, getDRegI64(rD + i * inc),
7919ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                           mkU8(index)));
7920ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
7921ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         default:
7922ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            vassert(0);
7923ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
7924ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
7925ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
7926ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7927ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* A7.7 Advanced SIMD element or structure load/store instructions */
7928ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
7929b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy StepanovBool dis_neon_load_or_store ( UInt theInstr,
7930b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                              Bool isT, IRTemp condT )
7931ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
7932ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  define INSN(_bMax,_bMin)  SLICE_UInt(theInstr, (_bMax), (_bMin))
7933b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   UInt bA = INSN(23,23);
7934b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   UInt fB = INSN(11,8);
7935b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   UInt bL = INSN(21,21);
7936ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt rD = (INSN(22,22) << 4) | INSN(15,12);
7937ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt rN = INSN(19,16);
7938ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt rM = INSN(3,0);
7939ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt N, size, i, j;
7940ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt inc;
7941ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt regs = 1;
7942ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7943ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (isT) {
7944ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(condT != IRTemp_INVALID);
7945ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
7946ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(condT == IRTemp_INVALID);
7947ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
7948ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* So now, if condT is not IRTemp_INVALID, we know we're
7949ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      dealing with Thumb code. */
7950ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7951ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (INSN(20,20) != 0)
7952ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return False;
7953ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7954ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp initialRn = newTemp(Ity_I32);
7955ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign(initialRn, isT ? getIRegT(rN) : getIRegA(rN));
7956ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7957ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp initialRm = newTemp(Ity_I32);
7958ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign(initialRm, isT ? getIRegT(rM) : getIRegA(rM));
7959ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7960b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   /* There are 3 cases:
7961b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      (1) VSTn / VLDn (n-element structure from/to one lane)
7962b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      (2) VLDn (single element to all lanes)
7963b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      (3) VSTn / VLDn (multiple n-element structures)
7964b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   */
7965b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   if (bA) {
7966b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      N = fB & 3;
7967b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      if ((fB >> 2) < 3) {
7968b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         /* ------------ Case (1) ------------
7969b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            VSTn / VLDn (n-element structure from/to one lane) */
7970ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7971b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         size = fB >> 2;
7972ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7973ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         switch (size) {
7974ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0: i = INSN(7,5); inc = 1; break;
7975ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 1: i = INSN(7,6); inc = INSN(5,5) ? 2 : 1; break;
7976ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 2: i = INSN(7,7); inc = INSN(6,6) ? 2 : 1; break;
7977ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 3: return False;
7978ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            default: vassert(0);
7979ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
7980ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7981ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp addr = newTemp(Ity_I32);
7982ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(addr, mkexpr(initialRn));
7983ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7984ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // go uncond
7985ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (condT != IRTemp_INVALID)
7986ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            mk_skip_over_T32_if_cond_is_false(condT);
7987ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // now uncond
7988ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7989b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         if (bL)
7990ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            mk_neon_elem_load_to_one_lane(rD, inc, i, N, size, addr);
7991ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         else
7992ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            mk_neon_elem_store_from_one_lane(rD, inc, i, N, size, addr);
7993b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         DIP("v%s%u.%u {", bL ? "ld" : "st", N + 1, 8 << size);
7994ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         for (j = 0; j <= N; j++) {
7995ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (j)
7996ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP(", ");
7997ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("d%u[%u]", rD + j * inc, i);
7998ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
7999ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("}, [r%u]", rN);
8000ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (rM != 13 && rM != 15) {
8001ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP(", r%u\n", rM);
8002ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
8003ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("%s\n", (rM != 15) ? "!" : "");
8004ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
8005ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
8006b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         /* ------------ Case (2) ------------
8007b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            VLDn (single element to all lanes) */
8008ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         UInt r;
8009b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         if (bL == 0)
8010ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            return False;
8011ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8012ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         inc = INSN(5,5) + 1;
8013ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         size = INSN(7,6);
8014ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8015ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* size == 3 and size == 2 cases differ in alignment constraints */
8016ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (size == 3 && N == 3 && INSN(4,4) == 1)
8017ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            size = 2;
8018ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8019ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (size == 0 && N == 0 && INSN(4,4) == 1)
8020ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            return False;
8021ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (N == 2 && INSN(4,4) == 1)
8022ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            return False;
8023ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (size == 3)
8024ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            return False;
8025ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8026ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // go uncond
8027ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (condT != IRTemp_INVALID)
8028ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            mk_skip_over_T32_if_cond_is_false(condT);
8029ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // now uncond
8030ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8031ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp addr = newTemp(Ity_I32);
8032ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(addr, mkexpr(initialRn));
8033ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8034ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (N == 0 && INSN(5,5))
8035ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            regs = 2;
8036ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8037ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         for (r = 0; r < regs; r++) {
8038ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            switch (size) {
8039ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               case 0:
8040ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  putDRegI64(rD + r, unop(Iop_Dup8x8,
8041ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                          loadLE(Ity_I8, mkexpr(addr))),
8042ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             IRTemp_INVALID);
8043ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  break;
8044ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               case 1:
8045ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  putDRegI64(rD + r, unop(Iop_Dup16x4,
8046ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                          loadLE(Ity_I16, mkexpr(addr))),
8047ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             IRTemp_INVALID);
8048ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  break;
8049ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               case 2:
8050ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  putDRegI64(rD + r, unop(Iop_Dup32x2,
8051ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                          loadLE(Ity_I32, mkexpr(addr))),
8052ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             IRTemp_INVALID);
8053ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  break;
8054ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               default:
8055ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  vassert(0);
8056ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
8057ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            for (i = 1; i <= N; i++) {
8058ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               switch (size) {
8059ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 0:
8060ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     putDRegI64(rD + r + i * inc,
8061ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                unop(Iop_Dup8x8,
8062ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                     loadLE(Ity_I8, binop(Iop_Add32,
8063ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                                          mkexpr(addr),
8064ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                                          mkU32(i * 1)))),
8065ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                IRTemp_INVALID);
8066ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
8067ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 1:
8068ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     putDRegI64(rD + r + i * inc,
8069ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                unop(Iop_Dup16x4,
8070ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                     loadLE(Ity_I16, binop(Iop_Add32,
8071ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                                           mkexpr(addr),
8072ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                                           mkU32(i * 2)))),
8073ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                IRTemp_INVALID);
8074ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
8075ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case 2:
8076ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     putDRegI64(rD + r + i * inc,
8077ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                unop(Iop_Dup32x2,
8078ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                     loadLE(Ity_I32, binop(Iop_Add32,
8079ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                                           mkexpr(addr),
8080ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                                           mkU32(i * 4)))),
8081ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                IRTemp_INVALID);
8082ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
8083ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  default:
8084ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     vassert(0);
8085ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               }
8086ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
8087ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
8088ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("vld%u.%u {", N + 1, 8 << size);
8089ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         for (r = 0; r < regs; r++) {
8090ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            for (i = 0; i <= N; i++) {
8091ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               if (i || r)
8092ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  DIP(", ");
8093ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("d%u[]", rD + r + i * inc);
8094ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
8095ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
8096ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("}, [r%u]", rN);
8097ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (rM != 13 && rM != 15) {
8098ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP(", r%u\n", rM);
8099ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
8100ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("%s\n", (rM != 15) ? "!" : "");
8101ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
8102ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
8103ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Writeback.  We're uncond here, so no condT-ing. */
8104ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (rM != 15) {
8105ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (rM == 13) {
8106ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            IRExpr* e = binop(Iop_Add32,
8107ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              mkexpr(initialRn),
8108ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              mkU32((1 << size) * (N + 1)));
8109ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (isT)
8110ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               putIRegT(rN, e, IRTemp_INVALID);
8111ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            else
8112ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               putIRegA(rN, e, IRTemp_INVALID, Ijk_Boring);
8113ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
8114ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            IRExpr* e = binop(Iop_Add32,
8115ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              mkexpr(initialRn),
8116ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              mkexpr(initialRm));
8117ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (isT)
8118ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               putIRegT(rN, e, IRTemp_INVALID);
8119ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            else
8120ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               putIRegA(rN, e, IRTemp_INVALID, Ijk_Boring);
8121ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
8122ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
8123ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return True;
8124ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
8125b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      /* ------------ Case (3) ------------
8126b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         VSTn / VLDn (multiple n-element structures) */
8127ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp tmp;
8128ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt r, elems;
8129b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      if (fB == BITS4(0,0,1,0) || fB == BITS4(0,1,1,0)
8130b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov          || fB == BITS4(0,1,1,1) || fB == BITS4(1,0,1,0)) {
8131ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         N = 0;
8132b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      } else if (fB == BITS4(0,0,1,1) || fB == BITS4(1,0,0,0)
8133b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                 || fB == BITS4(1,0,0,1)) {
8134ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         N = 1;
8135b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      } else if (fB == BITS4(0,1,0,0) || fB == BITS4(0,1,0,1)) {
8136ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         N = 2;
8137b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      } else if (fB == BITS4(0,0,0,0) || fB == BITS4(0,0,0,1)) {
8138ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         N = 3;
8139ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
8140ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         return False;
8141ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
8142b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      inc = (fB & 1) + 1;
8143b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      if (N == 1 && fB == BITS4(0,0,1,1)) {
8144ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         regs = 2;
8145ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else if (N == 0) {
8146b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         if (fB == BITS4(1,0,1,0)) {
8147ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            regs = 2;
8148b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         } else if (fB == BITS4(0,1,1,0)) {
8149ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            regs = 3;
8150b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         } else if (fB == BITS4(0,0,1,0)) {
8151ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            regs = 4;
8152ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
8153ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
8154ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8155ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      size = INSN(7,6);
8156ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (N == 0 && size == 3)
8157ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         size = 2;
8158ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (size == 3)
8159ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         return False;
8160ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8161ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      elems = 8 / (1 << size);
8162ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8163ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // go uncond
8164ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (condT != IRTemp_INVALID)
8165ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         mk_skip_over_T32_if_cond_is_false(condT);
8166ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // now uncond
8167ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8168ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp addr = newTemp(Ity_I32);
8169ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(addr, mkexpr(initialRn));
8170ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8171ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      for (r = 0; r < regs; r++) {
8172ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         for (i = 0; i < elems; i++) {
8173b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            if (bL)
8174ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               mk_neon_elem_load_to_one_lane(rD + r, inc, i, N, size, addr);
8175ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            else
8176ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               mk_neon_elem_store_from_one_lane(rD + r, inc, i, N, size, addr);
8177ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            tmp = newTemp(Ity_I32);
8178ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(tmp, binop(Iop_Add32, mkexpr(addr),
8179ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                         mkU32((1 << size) * (N + 1))));
8180ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            addr = tmp;
8181ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
8182ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
8183ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Writeback */
8184ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (rM != 15) {
8185ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (rM == 13) {
8186ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            IRExpr* e = binop(Iop_Add32,
8187ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              mkexpr(initialRn),
8188ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              mkU32(8 * (N + 1) * regs));
8189ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (isT)
8190ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               putIRegT(rN, e, IRTemp_INVALID);
8191ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            else
8192ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               putIRegA(rN, e, IRTemp_INVALID, Ijk_Boring);
8193ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
8194ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            IRExpr* e = binop(Iop_Add32,
8195ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              mkexpr(initialRn),
8196ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              mkexpr(initialRm));
8197ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (isT)
8198ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               putIRegT(rN, e, IRTemp_INVALID);
8199ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            else
8200ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               putIRegA(rN, e, IRTemp_INVALID, Ijk_Boring);
8201ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
8202ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
8203b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      DIP("v%s%u.%u {", bL ? "ld" : "st", N + 1, 8 << INSN(7,6));
8204ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if ((inc == 1 && regs * (N + 1) > 1)
8205ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          || (inc == 2 && regs > 1 && N > 0)) {
8206ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("d%u-d%u", rD, rD + regs * (N + 1) - 1);
8207ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
8208ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         for (r = 0; r < regs; r++) {
8209ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            for (i = 0; i <= N; i++) {
8210ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               if (i || r)
8211ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  DIP(", ");
8212ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("d%u", rD + r + i * inc);
8213ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
8214ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
8215ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
8216ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("}, [r%u]", rN);
8217ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (rM != 13 && rM != 15) {
8218ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP(", r%u\n", rM);
8219ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
8220ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("%s\n", (rM != 15) ? "!" : "");
8221ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
8222ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return True;
8223ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
8224ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  undef INSN
8225ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
8226ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8227ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8228ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
8229ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- NEON, top level control                              ---*/
8230ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
8231ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8232ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Both ARM and Thumb */
8233ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8234ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Translate a NEON instruction.    If successful, returns
8235ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   True and *dres may or may not be updated.  If failure, returns
8236ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   False and doesn't change *dres nor create any IR.
8237ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8238ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   The Thumb and ARM encodings are similar for the 24 bottom bits, but
8239ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   the top 8 bits are slightly different.  In both cases, the caller
8240ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   must pass the entire 32 bits.  Callers may pass any instruction;
8241ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   this ignores non-NEON ones.
8242ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8243ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Caller must supply an IRTemp 'condT' holding the gating condition,
8244ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   or IRTemp_INVALID indicating the insn is always executed.  In ARM
8245ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   code, this must always be IRTemp_INVALID because NEON insns are
8246ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   unconditional for ARM.
8247ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8248ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Finally, the caller must indicate whether this occurs in ARM or in
8249ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Thumb code.
8250ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
8251ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Bool decode_NEON_instruction (
8252ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /*MOD*/DisResult* dres,
8253ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               UInt              insn32,
8254ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRTemp            condT,
8255ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               Bool              isT
8256ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            )
8257ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
8258ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  define INSN(_bMax,_bMin)  SLICE_UInt(insn32, (_bMax), (_bMin))
8259ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8260ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* There are two kinds of instruction to deal with: load/store and
8261ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      data processing.  In each case, in ARM mode we merely identify
8262ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      the kind, and pass it on to the relevant sub-handler.  In Thumb
8263ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      mode we identify the kind, swizzle the bits around to make it
8264ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      have the same encoding as in ARM, and hand it on to the
8265ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      sub-handler.
8266ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   */
8267ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8268ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* In ARM mode, NEON instructions can't be conditional. */
8269ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (!isT)
8270ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(condT == IRTemp_INVALID);
8271ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8272ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Data processing:
8273ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Thumb: 111U 1111 AAAA Axxx xxxx BBBB CCCC xxxx
8274ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ARM:   1111 001U AAAA Axxx xxxx BBBB CCCC xxxx
8275ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   */
8276ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (!isT && INSN(31,25) == BITS7(1,1,1,1,0,0,1)) {
8277ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // ARM, DP
8278ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return dis_neon_data_processing(INSN(31,0), condT);
8279ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
8280ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (isT && INSN(31,29) == BITS3(1,1,1)
8281ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && INSN(27,24) == BITS4(1,1,1,1)) {
8282ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // Thumb, DP
8283ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt reformatted = INSN(23,0);
8284ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      reformatted |= (INSN(28,28) << 24); // U bit
8285ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      reformatted |= (BITS7(1,1,1,1,0,0,1) << 25);
8286ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return dis_neon_data_processing(reformatted, condT);
8287ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
8288ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8289ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Load/store:
8290ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Thumb: 1111 1001 AxL0 xxxx xxxx BBBB xxxx xxxx
8291ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ARM:   1111 0100 AxL0 xxxx xxxx BBBB xxxx xxxx
8292ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   */
8293ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (!isT && INSN(31,24) == BITS8(1,1,1,1,0,1,0,0)) {
8294ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // ARM, memory
8295b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      return dis_neon_load_or_store(INSN(31,0), isT, condT);
8296ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
8297ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (isT && INSN(31,24) == BITS8(1,1,1,1,1,0,0,1)) {
8298ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt reformatted = INSN(23,0);
8299ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      reformatted |= (BITS8(1,1,1,1,0,1,0,0) << 24);
8300b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      return dis_neon_load_or_store(reformatted, isT, condT);
8301ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
8302ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8303ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Doesn't match. */
8304ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return False;
8305ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8306ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  undef INSN
8307ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
8308ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8309ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8310ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
8311ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- V6 MEDIA instructions                                ---*/
8312ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
8313ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8314ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Both ARM and Thumb */
8315ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8316ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Translate a V6 media instruction.    If successful, returns
8317ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   True and *dres may or may not be updated.  If failure, returns
8318ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   False and doesn't change *dres nor create any IR.
8319ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8320ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   The Thumb and ARM encodings are completely different.  In Thumb
8321ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   mode, the caller must pass the entire 32 bits.  In ARM mode it must
8322ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   pass the lower 28 bits.  Apart from that, callers may pass any
8323ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   instruction; this function ignores anything it doesn't recognise.
8324ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8325ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Caller must supply an IRTemp 'condT' holding the gating condition,
8326ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   or IRTemp_INVALID indicating the insn is always executed.
8327ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8328ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Caller must also supply an ARMCondcode 'cond'.  This is only used
8329ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for debug printing, no other purpose.  For ARM, this is simply the
8330ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   top 4 bits of the original instruction.  For Thumb, the condition
8331ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   is not (really) known until run time, and so ARMCondAL should be
8332ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   passed, only so that printing of these instructions does not show
8333ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   any condition.
8334ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8335ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Finally, the caller must indicate whether this occurs in ARM or in
8336ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Thumb code.
8337ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
8338ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Bool decode_V6MEDIA_instruction (
8339ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /*MOD*/DisResult* dres,
8340ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               UInt              insnv6m,
8341ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRTemp            condT,
8342ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               ARMCondcode       conq,
8343ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               Bool              isT
8344ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            )
8345ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
8346ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  define INSNA(_bMax,_bMin)   SLICE_UInt(insnv6m, (_bMax), (_bMin))
8347ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  define INSNT0(_bMax,_bMin)  SLICE_UInt( ((insnv6m >> 16) & 0xFFFF), \
8348ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                           (_bMax), (_bMin) )
8349ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  define INSNT1(_bMax,_bMin)  SLICE_UInt( ((insnv6m >> 0)  & 0xFFFF), \
8350ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                           (_bMax), (_bMin) )
8351ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HChar dis_buf[128];
8352ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   dis_buf[0] = 0;
8353ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8354ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (isT) {
8355ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(conq == ARMCondAL);
8356ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
8357ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(INSNA(31,28) == BITS4(0,0,0,0)); // caller's obligation
8358ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(conq >= ARMCondEQ && conq <= ARMCondAL);
8359ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
8360ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8361ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ----------- smulbb, smulbt, smultb, smultt ----------- */
8362ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   {
8363ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     UInt regD = 99, regM = 99, regN = 99, bitM = 0, bitN = 0;
8364ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     Bool gate = False;
8365ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8366ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     if (isT) {
8367ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        if (INSNT0(15,4) == 0xFB1 && INSNT1(15,12) == BITS4(1,1,1,1)
8368ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            && INSNT1(7,6) == BITS2(0,0)) {
8369ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regD = INSNT1(11,8);
8370ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regM = INSNT1(3,0);
8371ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regN = INSNT0(3,0);
8372ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           bitM = INSNT1(4,4);
8373ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           bitN = INSNT1(5,5);
8374ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
8375ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              gate = True;
8376ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        }
8377ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     } else {
8378ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        if (BITS8(0,0,0,1,0,1,1,0) == INSNA(27,20) &&
8379ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            BITS4(0,0,0,0)         == INSNA(15,12) &&
8380ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            BITS4(1,0,0,0)         == (INSNA(7,4) & BITS4(1,0,0,1)) ) {
8381ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regD = INSNA(19,16);
8382ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regM = INSNA(11,8);
8383ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regN = INSNA(3,0);
8384ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           bitM = INSNA(6,6);
8385ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           bitN = INSNA(5,5);
8386ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           if (regD != 15 && regN != 15 && regM != 15)
8387ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              gate = True;
8388ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        }
8389ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     }
8390ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8391ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     if (gate) {
8392ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRTemp srcN = newTemp(Ity_I32);
8393ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRTemp srcM = newTemp(Ity_I32);
8394ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRTemp res  = newTemp(Ity_I32);
8395ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8396ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        assign( srcN, binop(Iop_Sar32,
8397ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            binop(Iop_Shl32,
8398ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  isT ? getIRegT(regN) : getIRegA(regN),
8399ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  mkU8(bitN ? 0 : 16)), mkU8(16)) );
8400ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        assign( srcM, binop(Iop_Sar32,
8401ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            binop(Iop_Shl32,
8402ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  isT ? getIRegT(regM) : getIRegA(regM),
8403ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  mkU8(bitM ? 0 : 16)), mkU8(16)) );
8404ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        assign( res, binop(Iop_Mul32, mkexpr(srcN), mkexpr(srcM)) );
8405ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8406ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        if (isT)
8407ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           putIRegT( regD, mkexpr(res), condT );
8408ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        else
8409ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           putIRegA( regD, mkexpr(res), condT, Ijk_Boring );
8410ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8411ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        DIP( "smul%c%c%s r%u, r%u, r%u\n", bitN ? 't' : 'b', bitM ? 't' : 'b',
8412ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             nCC(conq), regD, regN, regM );
8413ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        return True;
8414ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     }
8415ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     /* fall through */
8416ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
8417ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8418ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ------------ smulwb<y><c> <Rd>,<Rn>,<Rm> ------------- */
8419ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ------------ smulwt<y><c> <Rd>,<Rn>,<Rm> ------------- */
8420ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   {
8421ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     UInt regD = 99, regN = 99, regM = 99, bitM = 0;
8422ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     Bool gate = False;
8423ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8424ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     if (isT) {
8425ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        if (INSNT0(15,4) == 0xFB3 && INSNT1(15,12) == BITS4(1,1,1,1)
8426ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            && INSNT1(7,5) == BITS3(0,0,0)) {
8427ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          regN = INSNT0(3,0);
8428ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          regD = INSNT1(11,8);
8429ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          regM = INSNT1(3,0);
8430ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          bitM = INSNT1(4,4);
8431ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
8432ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             gate = True;
8433ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        }
8434ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     } else {
8435ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        if (INSNA(27,20) == BITS8(0,0,0,1,0,0,1,0) &&
8436ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            INSNA(15,12) == BITS4(0,0,0,0)         &&
8437ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            (INSNA(7,4) & BITS4(1,0,1,1)) == BITS4(1,0,1,0)) {
8438ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regD = INSNA(19,16);
8439ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regN = INSNA(3,0);
8440ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regM = INSNA(11,8);
8441ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           bitM = INSNA(6,6);
8442ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           if (regD != 15 && regN != 15 && regM != 15)
8443ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              gate = True;
8444ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        }
8445ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     }
8446ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8447ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     if (gate) {
8448ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRTemp irt_prod = newTemp(Ity_I64);
8449ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8450ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        assign( irt_prod,
8451ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                binop(Iop_MullS32,
8452ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      isT ? getIRegT(regN) : getIRegA(regN),
8453ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      binop(Iop_Sar32,
8454ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            binop(Iop_Shl32,
8455ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  isT ? getIRegT(regM) : getIRegA(regM),
8456ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  mkU8(bitM ? 0 : 16)),
8457ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            mkU8(16))) );
8458ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8459ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRExpr* ire_result = binop(Iop_Or32,
8460ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   binop( Iop_Shl32,
8461ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                          unop(Iop_64HIto32, mkexpr(irt_prod)),
8462ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                          mkU8(16) ),
8463ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   binop( Iop_Shr32,
8464ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                          unop(Iop_64to32, mkexpr(irt_prod)),
8465ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                          mkU8(16) ) );
8466ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8467ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        if (isT)
8468ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           putIRegT( regD, ire_result, condT );
8469ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        else
8470ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           putIRegA( regD, ire_result, condT, Ijk_Boring );
8471ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8472ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        DIP("smulw%c%s r%u, r%u, r%u\n",
8473ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            bitM ? 't' : 'b', nCC(conq),regD,regN,regM);
8474ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        return True;
8475ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     }
8476ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     /* fall through */
8477ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
8478ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8479ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ------------ pkhbt<c> Rd, Rn, Rm {,LSL #imm} ------------- */
8480ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ------------ pkhtb<c> Rd, Rn, Rm {,ASR #imm} ------------- */
8481ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   {
8482ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     UInt regD = 99, regN = 99, regM = 99, imm5 = 99, shift_type = 99;
8483ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     Bool tbform = False;
8484ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     Bool gate = False;
8485ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8486ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     if (isT) {
8487ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        if (INSNT0(15,4) == 0xEAC
8488ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            && INSNT1(15,15) == 0 && INSNT1(4,4) == 0) {
8489ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regN = INSNT0(3,0);
8490ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regD = INSNT1(11,8);
8491ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regM = INSNT1(3,0);
8492ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           imm5 = (INSNT1(14,12) << 2) | INSNT1(7,6);
8493ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           shift_type = (INSNT1(5,5) << 1) | 0;
8494ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           tbform = (INSNT1(5,5) == 0) ? False : True;
8495ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
8496ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              gate = True;
8497ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        }
8498ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     } else {
8499ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        if (INSNA(27,20) == BITS8(0,1,1,0,1,0,0,0) &&
8500ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            INSNA(5,4)   == BITS2(0,1)             &&
8501ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            (INSNA(6,6)  == 0 || INSNA(6,6) == 1) ) {
8502ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regD = INSNA(15,12);
8503ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regN = INSNA(19,16);
8504ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regM = INSNA(3,0);
8505ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           imm5 = INSNA(11,7);
8506ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           shift_type = (INSNA(6,6) << 1) | 0;
8507ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           tbform = (INSNA(6,6) == 0) ? False : True;
8508ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           if (regD != 15 && regN != 15 && regM != 15)
8509ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              gate = True;
8510ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        }
8511ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     }
8512ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8513ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     if (gate) {
8514ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRTemp irt_regM       = newTemp(Ity_I32);
8515ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRTemp irt_regM_shift = newTemp(Ity_I32);
8516ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        assign( irt_regM, isT ? getIRegT(regM) : getIRegA(regM) );
8517ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        compute_result_and_C_after_shift_by_imm5(
8518ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           dis_buf, &irt_regM_shift, NULL, irt_regM, shift_type, imm5, regM );
8519ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8520ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        UInt mask = (tbform == True) ? 0x0000FFFF : 0xFFFF0000;
8521ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRExpr* ire_result
8522ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          = binop( Iop_Or32,
8523ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   binop(Iop_And32, mkexpr(irt_regM_shift), mkU32(mask)),
8524ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   binop(Iop_And32, isT ? getIRegT(regN) : getIRegA(regN),
8525ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    unop(Iop_Not32, mkU32(mask))) );
8526ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8527ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        if (isT)
8528ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           putIRegT( regD, ire_result, condT );
8529ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        else
8530ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           putIRegA( regD, ire_result, condT, Ijk_Boring );
8531ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8532ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        DIP( "pkh%s%s r%u, r%u, r%u %s\n", tbform ? "tb" : "bt",
8533ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             nCC(conq), regD, regN, regM, dis_buf );
8534ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8535ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        return True;
8536ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     }
8537ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     /* fall through */
8538ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
8539ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8540ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ---------- usat<c> <Rd>,#<imm5>,<Rn>{,<shift>} ----------- */
8541ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   {
8542ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     UInt regD = 99, regN = 99, shift_type = 99, imm5 = 99, sat_imm = 99;
8543ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     Bool gate = False;
8544ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8545ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     if (isT) {
8546ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        if (INSNT0(15,6) == BITS10(1,1,1,1,0,0,1,1,1,0)
8547ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            && INSNT0(4,4) == 0
8548ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            && INSNT1(15,15) == 0 && INSNT1(5,5) == 0) {
8549ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regD       = INSNT1(11,8);
8550ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regN       = INSNT0(3,0);
8551ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           shift_type = (INSNT0(5,5) << 1) | 0;
8552ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           imm5       = (INSNT1(14,12) << 2) | INSNT1(7,6);
8553ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           sat_imm    = INSNT1(4,0);
8554ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           if (!isBadRegT(regD) && !isBadRegT(regN))
8555ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              gate = True;
8556ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           if (shift_type == BITS2(1,0) && imm5 == 0)
8557ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              gate = False;
8558ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        }
8559ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     } else {
8560ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        if (INSNA(27,21) == BITS7(0,1,1,0,1,1,1) &&
8561ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            INSNA(5,4)   == BITS2(0,1)) {
8562ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regD       = INSNA(15,12);
8563ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regN       = INSNA(3,0);
8564ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           shift_type = (INSNA(6,6) << 1) | 0;
8565ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           imm5       = INSNA(11,7);
8566ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           sat_imm    = INSNA(20,16);
8567ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           if (regD != 15 && regN != 15)
8568ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              gate = True;
8569ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        }
8570ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     }
8571ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8572ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     if (gate) {
8573ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRTemp irt_regN       = newTemp(Ity_I32);
8574ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRTemp irt_regN_shift = newTemp(Ity_I32);
8575ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRTemp irt_sat_Q      = newTemp(Ity_I32);
8576ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRTemp irt_result     = newTemp(Ity_I32);
8577ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8578ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        assign( irt_regN, isT ? getIRegT(regN) : getIRegA(regN) );
8579ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        compute_result_and_C_after_shift_by_imm5(
8580ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                dis_buf, &irt_regN_shift, NULL,
8581ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                irt_regN, shift_type, imm5, regN );
8582ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8583ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        armUnsignedSatQ( &irt_result, &irt_sat_Q, irt_regN_shift, sat_imm );
8584ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        or_into_QFLAG32( mkexpr(irt_sat_Q), condT );
8585ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8586ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        if (isT)
8587ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           putIRegT( regD, mkexpr(irt_result), condT );
8588ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        else
8589ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           putIRegA( regD, mkexpr(irt_result), condT, Ijk_Boring );
8590ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8591ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        DIP("usat%s r%u, #0x%04x, %s\n",
8592ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            nCC(conq), regD, imm5, dis_buf);
8593ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        return True;
8594ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     }
8595ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     /* fall through */
8596ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
8597ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8598ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  /* ----------- ssat<c> <Rd>,#<imm5>,<Rn>{,<shift>} ----------- */
8599ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   {
8600ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     UInt regD = 99, regN = 99, shift_type = 99, imm5 = 99, sat_imm = 99;
8601ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     Bool gate = False;
8602ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8603ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     if (isT) {
8604ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        if (INSNT0(15,6) == BITS10(1,1,1,1,0,0,1,1,0,0)
8605ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            && INSNT0(4,4) == 0
8606ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            && INSNT1(15,15) == 0 && INSNT1(5,5) == 0) {
8607ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regD       = INSNT1(11,8);
8608ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regN       = INSNT0(3,0);
8609ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           shift_type = (INSNT0(5,5) << 1) | 0;
8610ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           imm5       = (INSNT1(14,12) << 2) | INSNT1(7,6);
8611ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           sat_imm    = INSNT1(4,0) + 1;
8612ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           if (!isBadRegT(regD) && !isBadRegT(regN))
8613ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              gate = True;
8614ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           if (shift_type == BITS2(1,0) && imm5 == 0)
8615ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              gate = False;
8616ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        }
8617ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     } else {
8618ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        if (INSNA(27,21) == BITS7(0,1,1,0,1,0,1) &&
8619ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            INSNA(5,4)   == BITS2(0,1)) {
8620ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regD       = INSNA(15,12);
8621ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regN       = INSNA(3,0);
8622ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           shift_type = (INSNA(6,6) << 1) | 0;
8623ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           imm5       = INSNA(11,7);
8624ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           sat_imm    = INSNA(20,16) + 1;
8625ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           if (regD != 15 && regN != 15)
8626ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              gate = True;
8627ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        }
8628ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     }
8629ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8630ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     if (gate) {
8631ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRTemp irt_regN       = newTemp(Ity_I32);
8632ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRTemp irt_regN_shift = newTemp(Ity_I32);
8633ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRTemp irt_sat_Q      = newTemp(Ity_I32);
8634ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRTemp irt_result     = newTemp(Ity_I32);
8635ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8636ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        assign( irt_regN, isT ? getIRegT(regN) : getIRegA(regN) );
8637ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        compute_result_and_C_after_shift_by_imm5(
8638ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                dis_buf, &irt_regN_shift, NULL,
8639ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                irt_regN, shift_type, imm5, regN );
8640ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8641ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        armSignedSatQ( irt_regN_shift, sat_imm, &irt_result, &irt_sat_Q );
8642ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        or_into_QFLAG32( mkexpr(irt_sat_Q), condT );
8643ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8644ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        if (isT)
8645ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           putIRegT( regD, mkexpr(irt_result), condT );
8646ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        else
8647ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           putIRegA( regD, mkexpr(irt_result), condT, Ijk_Boring );
8648ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8649ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        DIP( "ssat%s r%u, #0x%04x, %s\n",
8650ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             nCC(conq), regD, imm5, dis_buf);
8651ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        return True;
8652ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    }
8653ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    /* fall through */
8654ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  }
8655ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8656ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* -------------- usat16<c> <Rd>,#<imm4>,<Rn> --------------- */
8657ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   {
8658ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     UInt regD = 99, regN = 99, sat_imm = 99;
8659ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     Bool gate = False;
8660ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8661ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     if (isT) {
8662ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        if (INSNT0(15,4) == 0xF3A && (INSNT1(15,0) & 0xF0F0) == 0x0000) {
8663ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regN = INSNT0(3,0);
8664ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regD = INSNT1(11,8);
8665ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           sat_imm = INSNT1(3,0);
8666ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           if (!isBadRegT(regD) && !isBadRegT(regN))
8667ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              gate = True;
8668ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       }
8669ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     } else {
8670ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        if (INSNA(27,20) == BITS8(0,1,1,0,1,1,1,0) &&
8671ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            INSNA(11,8)  == BITS4(1,1,1,1)         &&
8672ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            INSNA(7,4)   == BITS4(0,0,1,1)) {
8673ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regD    = INSNA(15,12);
8674ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regN    = INSNA(3,0);
8675ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           sat_imm = INSNA(19,16);
8676ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           if (regD != 15 && regN != 15)
8677ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              gate = True;
8678ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        }
8679ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     }
8680ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8681ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     if (gate) {
8682ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRTemp irt_regN    = newTemp(Ity_I32);
8683ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRTemp irt_regN_lo = newTemp(Ity_I32);
8684ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRTemp irt_regN_hi = newTemp(Ity_I32);
8685ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRTemp irt_Q_lo    = newTemp(Ity_I32);
8686ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRTemp irt_Q_hi    = newTemp(Ity_I32);
8687ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRTemp irt_res_lo  = newTemp(Ity_I32);
8688ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRTemp irt_res_hi  = newTemp(Ity_I32);
8689ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8690ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        assign( irt_regN, isT ? getIRegT(regN) : getIRegA(regN) );
8691ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        assign( irt_regN_lo, binop( Iop_Sar32,
8692ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    binop(Iop_Shl32, mkexpr(irt_regN), mkU8(16)),
8693ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    mkU8(16)) );
8694ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        assign( irt_regN_hi, binop(Iop_Sar32, mkexpr(irt_regN), mkU8(16)) );
8695ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8696ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        armUnsignedSatQ( &irt_res_lo, &irt_Q_lo, irt_regN_lo, sat_imm );
8697ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        or_into_QFLAG32( mkexpr(irt_Q_lo), condT );
8698ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8699ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        armUnsignedSatQ( &irt_res_hi, &irt_Q_hi, irt_regN_hi, sat_imm );
8700ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        or_into_QFLAG32( mkexpr(irt_Q_hi), condT );
8701ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8702ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRExpr* ire_result = binop( Iop_Or32,
8703ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    binop(Iop_Shl32, mkexpr(irt_res_hi), mkU8(16)),
8704ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    mkexpr(irt_res_lo) );
8705ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8706ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        if (isT)
8707ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           putIRegT( regD, ire_result, condT );
8708ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        else
8709ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           putIRegA( regD, ire_result, condT, Ijk_Boring );
8710ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8711ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        DIP( "usat16%s r%u, #0x%04x, r%u\n", nCC(conq), regD, sat_imm, regN );
8712ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        return True;
8713ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     }
8714ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     /* fall through */
8715ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
8716ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8717ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* -------------- uadd16<c> <Rd>,<Rn>,<Rm> -------------- */
8718ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   {
8719ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     UInt regD = 99, regN = 99, regM = 99;
8720ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     Bool gate = False;
8721ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8722ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     if (isT) {
8723ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        if (INSNT0(15,4) == 0xFA9 && (INSNT1(15,0) & 0xF0F0) == 0xF040) {
8724ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regN = INSNT0(3,0);
8725ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regD = INSNT1(11,8);
8726ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regM = INSNT1(3,0);
8727ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
8728ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              gate = True;
8729ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        }
8730ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     } else {
8731ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        if (INSNA(27,20) == BITS8(0,1,1,0,0,1,0,1) &&
8732ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            INSNA(11,8)  == BITS4(1,1,1,1)         &&
8733ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            INSNA(7,4)   == BITS4(0,0,0,1)) {
8734ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regD = INSNA(15,12);
8735ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regN = INSNA(19,16);
8736ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regM = INSNA(3,0);
8737ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           if (regD != 15 && regN != 15 && regM != 15)
8738ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              gate = True;
8739ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        }
8740ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     }
8741ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8742ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     if (gate) {
8743ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRTemp rNt  = newTemp(Ity_I32);
8744ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRTemp rMt  = newTemp(Ity_I32);
8745ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRTemp res  = newTemp(Ity_I32);
8746ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRTemp reso = newTemp(Ity_I32);
8747ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8748ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        assign( rNt, isT ? getIRegT(regN) : getIRegA(regN) );
8749ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        assign( rMt, isT ? getIRegT(regM) : getIRegA(regM) );
8750ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8751ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        assign(res, binop(Iop_Add16x2, mkexpr(rNt), mkexpr(rMt)));
8752ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        if (isT)
8753ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           putIRegT( regD, mkexpr(res), condT );
8754ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        else
8755ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           putIRegA( regD, mkexpr(res), condT, Ijk_Boring );
8756ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8757ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        assign(reso, binop(Iop_HAdd16Ux2, mkexpr(rNt), mkexpr(rMt)));
8758ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        set_GE_32_10_from_bits_31_15(reso, condT);
8759ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8760ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        DIP("uadd16%s r%u, r%u, r%u\n", nCC(conq),regD,regN,regM);
8761ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        return True;
8762ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     }
8763ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     /* fall through */
8764ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
8765ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8766ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* -------------- sadd16<c> <Rd>,<Rn>,<Rm> -------------- */
8767ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   {
8768ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     UInt regD = 99, regN = 99, regM = 99;
8769ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     Bool gate = False;
8770ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8771ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     if (isT) {
8772ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        if (INSNT0(15,4) == 0xFA9 && (INSNT1(15,0) & 0xF0F0) == 0xF000) {
8773ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regN = INSNT0(3,0);
8774ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regD = INSNT1(11,8);
8775ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regM = INSNT1(3,0);
8776ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
8777ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              gate = True;
8778ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        }
8779ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     } else {
8780ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        if (INSNA(27,20) == BITS8(0,1,1,0,0,0,0,1) &&
8781ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            INSNA(11,8)  == BITS4(1,1,1,1)         &&
8782ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            INSNA(7,4)   == BITS4(0,0,0,1)) {
8783ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regD = INSNA(15,12);
8784ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regN = INSNA(19,16);
8785ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regM = INSNA(3,0);
8786ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           if (regD != 15 && regN != 15 && regM != 15)
8787ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              gate = True;
8788ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        }
8789ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     }
8790ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8791ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     if (gate) {
8792ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRTemp rNt  = newTemp(Ity_I32);
8793ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRTemp rMt  = newTemp(Ity_I32);
8794ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRTemp res  = newTemp(Ity_I32);
8795ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRTemp reso = newTemp(Ity_I32);
8796ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8797ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        assign( rNt, isT ? getIRegT(regN) : getIRegA(regN) );
8798ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        assign( rMt, isT ? getIRegT(regM) : getIRegA(regM) );
8799ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8800ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        assign(res, binop(Iop_Add16x2, mkexpr(rNt), mkexpr(rMt)));
8801ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        if (isT)
8802ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           putIRegT( regD, mkexpr(res), condT );
8803ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        else
8804ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           putIRegA( regD, mkexpr(res), condT, Ijk_Boring );
8805ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8806ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        assign(reso, unop(Iop_Not32,
8807ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          binop(Iop_HAdd16Sx2, mkexpr(rNt), mkexpr(rMt))));
8808ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        set_GE_32_10_from_bits_31_15(reso, condT);
8809ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8810ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        DIP("sadd16%s r%u, r%u, r%u\n", nCC(conq),regD,regN,regM);
8811ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        return True;
8812ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     }
8813ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     /* fall through */
8814ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
8815ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8816ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ---------------- usub16<c> <Rd>,<Rn>,<Rm> ---------------- */
8817ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   {
8818ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     UInt regD = 99, regN = 99, regM = 99;
8819ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     Bool gate = False;
8820ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8821ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     if (isT) {
8822ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        if (INSNT0(15,4) == 0xFAD && (INSNT1(15,0) & 0xF0F0) == 0xF040) {
8823ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regN = INSNT0(3,0);
8824ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regD = INSNT1(11,8);
8825ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regM = INSNT1(3,0);
8826ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
8827ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              gate = True;
8828ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        }
8829ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     } else {
8830ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        if (INSNA(27,20) == BITS8(0,1,1,0,0,1,0,1) &&
8831ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            INSNA(11,8)  == BITS4(1,1,1,1)         &&
8832ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            INSNA(7,4)   == BITS4(0,1,1,1)) {
8833ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regD = INSNA(15,12);
8834ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regN = INSNA(19,16);
8835ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regM = INSNA(3,0);
8836ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           if (regD != 15 && regN != 15 && regM != 15)
8837ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             gate = True;
8838ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        }
8839ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     }
8840ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8841ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     if (gate) {
8842ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRTemp rNt  = newTemp(Ity_I32);
8843ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRTemp rMt  = newTemp(Ity_I32);
8844ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRTemp res  = newTemp(Ity_I32);
8845ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRTemp reso = newTemp(Ity_I32);
8846ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8847ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        assign( rNt, isT ? getIRegT(regN) : getIRegA(regN) );
8848ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        assign( rMt, isT ? getIRegT(regM) : getIRegA(regM) );
8849ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8850ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        assign(res, binop(Iop_Sub16x2, mkexpr(rNt), mkexpr(rMt)));
8851ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        if (isT)
8852ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           putIRegT( regD, mkexpr(res), condT );
8853ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        else
8854ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           putIRegA( regD, mkexpr(res), condT, Ijk_Boring );
8855ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8856ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        assign(reso, unop(Iop_Not32,
8857ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          binop(Iop_HSub16Ux2, mkexpr(rNt), mkexpr(rMt))));
8858ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        set_GE_32_10_from_bits_31_15(reso, condT);
8859ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8860ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        DIP("usub16%s r%u, r%u, r%u\n", nCC(conq),regD,regN,regM);
8861ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        return True;
8862ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     }
8863ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     /* fall through */
8864ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
8865ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8866ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* -------------- ssub16<c> <Rd>,<Rn>,<Rm> -------------- */
8867ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   {
8868ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     UInt regD = 99, regN = 99, regM = 99;
8869ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     Bool gate = False;
8870ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8871ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     if (isT) {
8872ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        if (INSNT0(15,4) == 0xFAD && (INSNT1(15,0) & 0xF0F0) == 0xF000) {
8873ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regN = INSNT0(3,0);
8874ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regD = INSNT1(11,8);
8875ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regM = INSNT1(3,0);
8876ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
8877ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              gate = True;
8878ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        }
8879ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     } else {
8880ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        if (INSNA(27,20) == BITS8(0,1,1,0,0,0,0,1) &&
8881ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            INSNA(11,8)  == BITS4(1,1,1,1)         &&
8882ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            INSNA(7,4)   == BITS4(0,1,1,1)) {
8883ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regD = INSNA(15,12);
8884ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regN = INSNA(19,16);
8885ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regM = INSNA(3,0);
8886ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           if (regD != 15 && regN != 15 && regM != 15)
8887ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              gate = True;
8888ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        }
8889ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     }
8890ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8891ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     if (gate) {
8892ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRTemp rNt  = newTemp(Ity_I32);
8893ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRTemp rMt  = newTemp(Ity_I32);
8894ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRTemp res  = newTemp(Ity_I32);
8895ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRTemp reso = newTemp(Ity_I32);
8896ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8897ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        assign( rNt, isT ? getIRegT(regN) : getIRegA(regN) );
8898ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        assign( rMt, isT ? getIRegT(regM) : getIRegA(regM) );
8899ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8900ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        assign(res, binop(Iop_Sub16x2, mkexpr(rNt), mkexpr(rMt)));
8901ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        if (isT)
8902ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           putIRegT( regD, mkexpr(res), condT );
8903ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        else
8904ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           putIRegA( regD, mkexpr(res), condT, Ijk_Boring );
8905ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8906ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        assign(reso, unop(Iop_Not32,
8907ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          binop(Iop_HSub16Sx2, mkexpr(rNt), mkexpr(rMt))));
8908ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        set_GE_32_10_from_bits_31_15(reso, condT);
8909ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8910ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        DIP("ssub16%s r%u, r%u, r%u\n", nCC(conq),regD,regN,regM);
8911ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        return True;
8912ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     }
8913ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     /* fall through */
8914ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
8915ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8916ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ----------------- uadd8<c> <Rd>,<Rn>,<Rm> ---------------- */
8917ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   {
8918ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     UInt regD = 99, regN = 99, regM = 99;
8919ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     Bool gate = False;
8920ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8921ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     if (isT) {
8922ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        if (INSNT0(15,4) == 0xFA8 && (INSNT1(15,0) & 0xF0F0) == 0xF040) {
8923ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regN = INSNT0(3,0);
8924ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regD = INSNT1(11,8);
8925ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regM = INSNT1(3,0);
8926ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
8927ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              gate = True;
8928ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        }
8929ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     } else {
8930ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        if (INSNA(27,20) == BITS8(0,1,1,0,0,1,0,1) &&
8931ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            INSNA(11,8)  == BITS4(1,1,1,1)         &&
8932ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            (INSNA(7,4)  == BITS4(1,0,0,1))) {
8933ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regD = INSNA(15,12);
8934ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regN = INSNA(19,16);
8935ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regM = INSNA(3,0);
8936ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           if (regD != 15 && regN != 15 && regM != 15)
8937ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              gate = True;
8938ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        }
8939ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     }
8940ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8941ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     if (gate) {
8942ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRTemp rNt  = newTemp(Ity_I32);
8943ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRTemp rMt  = newTemp(Ity_I32);
8944ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRTemp res  = newTemp(Ity_I32);
8945ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRTemp reso = newTemp(Ity_I32);
8946ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8947ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        assign( rNt, isT ? getIRegT(regN) : getIRegA(regN) );
8948ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        assign( rMt, isT ? getIRegT(regM) : getIRegA(regM) );
8949ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8950ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        assign(res, binop(Iop_Add8x4, mkexpr(rNt), mkexpr(rMt)));
8951ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        if (isT)
8952ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           putIRegT( regD, mkexpr(res), condT );
8953ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        else
8954ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           putIRegA( regD, mkexpr(res), condT, Ijk_Boring );
8955ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8956ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        assign(reso, binop(Iop_HAdd8Ux4, mkexpr(rNt), mkexpr(rMt)));
8957ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        set_GE_3_2_1_0_from_bits_31_23_15_7(reso, condT);
8958ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8959ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        DIP("uadd8%s r%u, r%u, r%u\n", nCC(conq),regD,regN,regM);
8960ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        return True;
8961ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     }
8962ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     /* fall through */
8963ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
8964ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8965ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ------------------- sadd8<c> <Rd>,<Rn>,<Rm> ------------------ */
8966ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   {
8967ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     UInt regD = 99, regN = 99, regM = 99;
8968ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     Bool gate = False;
8969ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8970ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     if (isT) {
8971ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        if (INSNT0(15,4) == 0xFA8 && (INSNT1(15,0) & 0xF0F0) == 0xF000) {
8972ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regN = INSNT0(3,0);
8973ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regD = INSNT1(11,8);
8974ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regM = INSNT1(3,0);
8975ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
8976ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              gate = True;
8977ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        }
8978ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     } else {
8979ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        if (INSNA(27,20) == BITS8(0,1,1,0,0,0,0,1) &&
8980ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            INSNA(11,8)  == BITS4(1,1,1,1)         &&
8981ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            (INSNA(7,4)  == BITS4(1,0,0,1))) {
8982ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regD = INSNA(15,12);
8983ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regN = INSNA(19,16);
8984ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regM = INSNA(3,0);
8985ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           if (regD != 15 && regN != 15 && regM != 15)
8986ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              gate = True;
8987ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        }
8988ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     }
8989ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8990ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     if (gate) {
8991ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRTemp rNt  = newTemp(Ity_I32);
8992ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRTemp rMt  = newTemp(Ity_I32);
8993ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRTemp res  = newTemp(Ity_I32);
8994ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRTemp reso = newTemp(Ity_I32);
8995ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8996ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        assign( rNt, isT ? getIRegT(regN) : getIRegA(regN) );
8997ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        assign( rMt, isT ? getIRegT(regM) : getIRegA(regM) );
8998ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8999ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        assign(res, binop(Iop_Add8x4, mkexpr(rNt), mkexpr(rMt)));
9000ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        if (isT)
9001ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           putIRegT( regD, mkexpr(res), condT );
9002ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        else
9003ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           putIRegA( regD, mkexpr(res), condT, Ijk_Boring );
9004ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9005ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        assign(reso, unop(Iop_Not32,
9006ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          binop(Iop_HAdd8Sx4, mkexpr(rNt), mkexpr(rMt))));
9007ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        set_GE_3_2_1_0_from_bits_31_23_15_7(reso, condT);
9008ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9009ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        DIP("sadd8%s r%u, r%u, r%u\n", nCC(conq),regD,regN,regM);
9010ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        return True;
9011ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     }
9012ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     /* fall through */
9013ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
9014ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9015ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ------------------- usub8<c> <Rd>,<Rn>,<Rm> ------------------ */
9016ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   {
9017ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     UInt regD = 99, regN = 99, regM = 99;
9018ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     Bool gate = False;
9019ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9020ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     if (isT) {
9021ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        if (INSNT0(15,4) == 0xFAC && (INSNT1(15,0) & 0xF0F0) == 0xF040) {
9022ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regN = INSNT0(3,0);
9023ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regD = INSNT1(11,8);
9024ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regM = INSNT1(3,0);
9025ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
9026ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              gate = True;
9027ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        }
9028ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     } else {
9029ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        if (INSNA(27,20) == BITS8(0,1,1,0,0,1,0,1) &&
9030ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            INSNA(11,8)  == BITS4(1,1,1,1)         &&
9031ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            (INSNA(7,4)  == BITS4(1,1,1,1))) {
9032ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regD = INSNA(15,12);
9033ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regN = INSNA(19,16);
9034ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regM = INSNA(3,0);
9035ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           if (regD != 15 && regN != 15 && regM != 15)
9036ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             gate = True;
9037ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        }
9038ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     }
9039ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9040ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     if (gate) {
9041ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRTemp rNt  = newTemp(Ity_I32);
9042ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRTemp rMt  = newTemp(Ity_I32);
9043ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRTemp res  = newTemp(Ity_I32);
9044ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRTemp reso = newTemp(Ity_I32);
9045ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9046ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        assign( rNt, isT ? getIRegT(regN) : getIRegA(regN) );
9047ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        assign( rMt, isT ? getIRegT(regM) : getIRegA(regM) );
9048ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9049ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        assign(res, binop(Iop_Sub8x4, mkexpr(rNt), mkexpr(rMt)));
9050ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        if (isT)
9051ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           putIRegT( regD, mkexpr(res), condT );
9052ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        else
9053ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           putIRegA( regD, mkexpr(res), condT, Ijk_Boring );
9054ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9055ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        assign(reso, unop(Iop_Not32,
9056ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          binop(Iop_HSub8Ux4, mkexpr(rNt), mkexpr(rMt))));
9057ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        set_GE_3_2_1_0_from_bits_31_23_15_7(reso, condT);
9058ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9059ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        DIP("usub8%s r%u, r%u, r%u\n", nCC(conq),regD,regN,regM);
9060ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        return True;
9061ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     }
9062ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     /* fall through */
9063ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
9064ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9065ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ------------------- ssub8<c> <Rd>,<Rn>,<Rm> ------------------ */
9066ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   {
9067ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     UInt regD = 99, regN = 99, regM = 99;
9068ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     Bool gate = False;
9069ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9070ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     if (isT) {
9071ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        if (INSNT0(15,4) == 0xFAC && (INSNT1(15,0) & 0xF0F0) == 0xF000) {
9072ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regN = INSNT0(3,0);
9073ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regD = INSNT1(11,8);
9074ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regM = INSNT1(3,0);
9075ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
9076ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              gate = True;
9077ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        }
9078ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     } else {
9079ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        if (INSNA(27,20) == BITS8(0,1,1,0,0,0,0,1) &&
9080ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            INSNA(11,8)  == BITS4(1,1,1,1)         &&
9081ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            INSNA(7,4)   == BITS4(1,1,1,1)) {
9082ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regD = INSNA(15,12);
9083ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regN = INSNA(19,16);
9084ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regM = INSNA(3,0);
9085ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           if (regD != 15 && regN != 15 && regM != 15)
9086ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              gate = True;
9087ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        }
9088ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     }
9089ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9090ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     if (gate) {
9091ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRTemp rNt  = newTemp(Ity_I32);
9092ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRTemp rMt  = newTemp(Ity_I32);
9093ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRTemp res  = newTemp(Ity_I32);
9094ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRTemp reso = newTemp(Ity_I32);
9095ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9096ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        assign( rNt, isT ? getIRegT(regN) : getIRegA(regN) );
9097ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        assign( rMt, isT ? getIRegT(regM) : getIRegA(regM) );
9098ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9099ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        assign(res, binop(Iop_Sub8x4, mkexpr(rNt), mkexpr(rMt)));
9100ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        if (isT)
9101ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           putIRegT( regD, mkexpr(res), condT );
9102ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        else
9103ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           putIRegA( regD, mkexpr(res), condT, Ijk_Boring );
9104ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9105ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        assign(reso, unop(Iop_Not32,
9106ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          binop(Iop_HSub8Sx4, mkexpr(rNt), mkexpr(rMt))));
9107ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        set_GE_3_2_1_0_from_bits_31_23_15_7(reso, condT);
9108ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9109ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        DIP("ssub8%s r%u, r%u, r%u\n", nCC(conq),regD,regN,regM);
9110ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        return True;
9111ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     }
9112ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     /* fall through */
9113ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
9114ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9115ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ------------------ qadd8<c> <Rd>,<Rn>,<Rm> ------------------- */
9116ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   {
9117ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     UInt regD = 99, regN = 99, regM = 99;
9118ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     Bool gate = False;
9119ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9120ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     if (isT) {
9121ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        if (INSNT0(15,4) == 0xFA8 && (INSNT1(15,0) & 0xF0F0) == 0xF010) {
9122ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regN = INSNT0(3,0);
9123ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regD = INSNT1(11,8);
9124ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regM = INSNT1(3,0);
9125ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
9126ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              gate = True;
9127ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        }
9128ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     } else {
9129ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        if (INSNA(27,20) == BITS8(0,1,1,0,0,0,1,0) &&
9130ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            INSNA(11,8)  == BITS4(1,1,1,1)         &&
9131ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            INSNA(7,4)   == BITS4(1,0,0,1)) {
9132ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regD = INSNA(15,12);
9133ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regN = INSNA(19,16);
9134ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regM = INSNA(3,0);
9135ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           if (regD != 15 && regN != 15 && regM != 15)
9136ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              gate = True;
9137ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        }
9138ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     }
9139ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9140ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     if (gate) {
9141ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRTemp rNt   = newTemp(Ity_I32);
9142ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRTemp rMt   = newTemp(Ity_I32);
9143ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRTemp res_q = newTemp(Ity_I32);
9144ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9145ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        assign( rNt, isT ? getIRegT(regN) : getIRegA(regN) );
9146ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        assign( rMt, isT ? getIRegT(regM) : getIRegA(regM) );
9147ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9148ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        assign(res_q, binop(Iop_QAdd8Sx4, mkexpr(rNt), mkexpr(rMt)));
9149ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        if (isT)
9150ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           putIRegT( regD, mkexpr(res_q), condT );
9151ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        else
9152ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           putIRegA( regD, mkexpr(res_q), condT, Ijk_Boring );
9153ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9154ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        DIP("qadd8%s r%u, r%u, r%u\n", nCC(conq),regD,regN,regM);
9155ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        return True;
9156ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     }
9157ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     /* fall through */
9158ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
9159ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9160ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ------------------ qsub8<c> <Rd>,<Rn>,<Rm> ------------------- */
9161ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   {
9162ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     UInt regD = 99, regN = 99, regM = 99;
9163ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     Bool gate = False;
9164ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9165ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     if (isT) {
9166ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        if (INSNT0(15,4) == 0xFAC && (INSNT1(15,0) & 0xF0F0) == 0xF010) {
9167ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regN = INSNT0(3,0);
9168ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regD = INSNT1(11,8);
9169ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regM = INSNT1(3,0);
9170ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
9171ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              gate = True;
9172ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        }
9173ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     } else {
9174ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        if (INSNA(27,20) == BITS8(0,1,1,0,0,0,1,0) &&
9175ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            INSNA(11,8)  == BITS4(1,1,1,1)         &&
9176ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            INSNA(7,4)   == BITS4(1,1,1,1)) {
9177ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regD = INSNA(15,12);
9178ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regN = INSNA(19,16);
9179ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regM = INSNA(3,0);
9180ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           if (regD != 15 && regN != 15 && regM != 15)
9181ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              gate = True;
9182ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        }
9183ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     }
9184ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9185ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     if (gate) {
9186ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRTemp rNt   = newTemp(Ity_I32);
9187ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRTemp rMt   = newTemp(Ity_I32);
9188ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRTemp res_q = newTemp(Ity_I32);
9189ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9190ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        assign( rNt, isT ? getIRegT(regN) : getIRegA(regN) );
9191ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        assign( rMt, isT ? getIRegT(regM) : getIRegA(regM) );
9192ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9193ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        assign(res_q, binop(Iop_QSub8Sx4, mkexpr(rNt), mkexpr(rMt)));
9194ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        if (isT)
9195ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           putIRegT( regD, mkexpr(res_q), condT );
9196ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        else
9197ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           putIRegA( regD, mkexpr(res_q), condT, Ijk_Boring );
9198ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9199ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        DIP("qsub8%s r%u, r%u, r%u\n", nCC(conq),regD,regN,regM);
9200ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        return True;
9201ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     }
9202ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     /* fall through */
9203ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
9204ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9205ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ------------------ uqadd8<c> <Rd>,<Rn>,<Rm> ------------------ */
9206ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   {
9207ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     UInt regD = 99, regN = 99, regM = 99;
9208ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     Bool gate = False;
9209ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9210ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     if (isT) {
9211ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        if (INSNT0(15,4) == 0xFA8 && (INSNT1(15,0) & 0xF0F0) == 0xF050) {
9212ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regN = INSNT0(3,0);
9213ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regD = INSNT1(11,8);
9214ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regM = INSNT1(3,0);
9215ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
9216ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              gate = True;
9217ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        }
9218ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     } else {
9219ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        if (INSNA(27,20) == BITS8(0,1,1,0,0,1,1,0) &&
9220ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            INSNA(11,8)  == BITS4(1,1,1,1)         &&
9221ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            (INSNA(7,4)  == BITS4(1,0,0,1))) {
9222ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regD = INSNA(15,12);
9223ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regN = INSNA(19,16);
9224ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regM = INSNA(3,0);
9225ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           if (regD != 15 && regN != 15 && regM != 15)
9226ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              gate = True;
9227ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        }
9228ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     }
9229ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9230ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     if (gate) {
9231ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRTemp rNt   = newTemp(Ity_I32);
9232ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRTemp rMt   = newTemp(Ity_I32);
9233ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRTemp res_q = newTemp(Ity_I32);
9234ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9235ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        assign( rNt, isT ? getIRegT(regN) : getIRegA(regN) );
9236ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        assign( rMt, isT ? getIRegT(regM) : getIRegA(regM) );
9237ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9238ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        assign(res_q, binop(Iop_QAdd8Ux4, mkexpr(rNt), mkexpr(rMt)));
9239ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        if (isT)
9240ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           putIRegT( regD, mkexpr(res_q), condT );
9241ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        else
9242ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           putIRegA( regD, mkexpr(res_q), condT, Ijk_Boring );
9243ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9244ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        DIP("uqadd8%s r%u, r%u, r%u\n", nCC(conq),regD,regN,regM);
9245ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        return True;
9246ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     }
9247ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     /* fall through */
9248ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
9249ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9250ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ------------------ uqsub8<c> <Rd>,<Rn>,<Rm> ------------------ */
9251ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   {
9252ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     UInt regD = 99, regN = 99, regM = 99;
9253ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     Bool gate = False;
9254ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9255ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     if (isT) {
9256ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        if (INSNT0(15,4) == 0xFAC && (INSNT1(15,0) & 0xF0F0) == 0xF050) {
9257ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regN = INSNT0(3,0);
9258ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regD = INSNT1(11,8);
9259ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regM = INSNT1(3,0);
9260ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
9261ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              gate = True;
9262ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        }
9263ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     } else {
9264ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        if (INSNA(27,20) == BITS8(0,1,1,0,0,1,1,0) &&
9265ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            INSNA(11,8)  == BITS4(1,1,1,1)         &&
9266ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            (INSNA(7,4)  == BITS4(1,1,1,1))) {
9267ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regD = INSNA(15,12);
9268ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regN = INSNA(19,16);
9269ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regM = INSNA(3,0);
9270ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           if (regD != 15 && regN != 15 && regM != 15)
9271ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             gate = True;
9272ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        }
9273ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     }
9274ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9275ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     if (gate) {
9276ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRTemp rNt   = newTemp(Ity_I32);
9277ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRTemp rMt   = newTemp(Ity_I32);
9278ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRTemp res_q = newTemp(Ity_I32);
9279ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9280ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        assign( rNt, isT ? getIRegT(regN) : getIRegA(regN) );
9281ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        assign( rMt, isT ? getIRegT(regM) : getIRegA(regM) );
9282ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9283ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        assign(res_q, binop(Iop_QSub8Ux4, mkexpr(rNt), mkexpr(rMt)));
9284ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        if (isT)
9285ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           putIRegT( regD, mkexpr(res_q), condT );
9286ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        else
9287ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           putIRegA( regD, mkexpr(res_q), condT, Ijk_Boring );
9288ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9289ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        DIP("uqsub8%s r%u, r%u, r%u\n", nCC(conq),regD,regN,regM);
9290ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        return True;
9291ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     }
9292ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     /* fall through */
9293ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
9294ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9295ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ----------------- uhadd8<c> <Rd>,<Rn>,<Rm> ------------------- */
9296ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   {
9297ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     UInt regD = 99, regN = 99, regM = 99;
9298ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     Bool gate = False;
9299ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9300ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     if (isT) {
9301ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        if (INSNT0(15,4) == 0xFA8 && (INSNT1(15,0) & 0xF0F0) == 0xF060) {
9302ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regN = INSNT0(3,0);
9303ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regD = INSNT1(11,8);
9304ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regM = INSNT1(3,0);
9305ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
9306ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              gate = True;
9307ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        }
9308ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     } else {
9309ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        if (INSNA(27,20) == BITS8(0,1,1,0,0,1,1,1) &&
9310ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            INSNA(11,8)  == BITS4(1,1,1,1)         &&
9311ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            INSNA(7,4)   == BITS4(1,0,0,1)) {
9312ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regD = INSNA(15,12);
9313ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regN = INSNA(19,16);
9314ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regM = INSNA(3,0);
9315ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           if (regD != 15 && regN != 15 && regM != 15)
9316ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              gate = True;
9317ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        }
9318ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     }
9319ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9320ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     if (gate) {
9321ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRTemp rNt   = newTemp(Ity_I32);
9322ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRTemp rMt   = newTemp(Ity_I32);
9323ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRTemp res_q = newTemp(Ity_I32);
9324ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9325ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        assign( rNt, isT ? getIRegT(regN) : getIRegA(regN) );
9326ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        assign( rMt, isT ? getIRegT(regM) : getIRegA(regM) );
9327ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9328ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        assign(res_q, binop(Iop_HAdd8Ux4, mkexpr(rNt), mkexpr(rMt)));
9329ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        if (isT)
9330ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           putIRegT( regD, mkexpr(res_q), condT );
9331ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        else
9332ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           putIRegA( regD, mkexpr(res_q), condT, Ijk_Boring );
9333ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9334ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        DIP("uhadd8%s r%u, r%u, r%u\n", nCC(conq),regD,regN,regM);
9335ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        return True;
9336ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     }
9337ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     /* fall through */
9338ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
9339ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9340ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ----------------- shadd8<c> <Rd>,<Rn>,<Rm> ------------------- */
9341ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   {
9342ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     UInt regD = 99, regN = 99, regM = 99;
9343ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     Bool gate = False;
9344ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9345ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     if (isT) {
9346ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        if (INSNT0(15,4) == 0xFA8 && (INSNT1(15,0) & 0xF0F0) == 0xF020) {
9347ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regN = INSNT0(3,0);
9348ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regD = INSNT1(11,8);
9349ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regM = INSNT1(3,0);
9350ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
9351ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              gate = True;
9352ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        }
9353ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     } else {
9354ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        if (INSNA(27,20) == BITS8(0,1,1,0,0,0,1,1) &&
9355ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            INSNA(11,8)  == BITS4(1,1,1,1)         &&
9356ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            INSNA(7,4)   == BITS4(1,0,0,1)) {
9357ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regD = INSNA(15,12);
9358ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regN = INSNA(19,16);
9359ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regM = INSNA(3,0);
9360ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           if (regD != 15 && regN != 15 && regM != 15)
9361ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              gate = True;
9362ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        }
9363ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     }
9364ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9365ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     if (gate) {
9366ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRTemp rNt   = newTemp(Ity_I32);
9367ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRTemp rMt   = newTemp(Ity_I32);
9368ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRTemp res_q = newTemp(Ity_I32);
9369ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9370ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        assign( rNt, isT ? getIRegT(regN) : getIRegA(regN) );
9371ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        assign( rMt, isT ? getIRegT(regM) : getIRegA(regM) );
9372ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9373ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        assign(res_q, binop(Iop_HAdd8Sx4, mkexpr(rNt), mkexpr(rMt)));
9374ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        if (isT)
9375ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           putIRegT( regD, mkexpr(res_q), condT );
9376ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        else
9377ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           putIRegA( regD, mkexpr(res_q), condT, Ijk_Boring );
9378ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9379ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        DIP("shadd8%s r%u, r%u, r%u\n", nCC(conq),regD,regN,regM);
9380ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        return True;
9381ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     }
9382ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     /* fall through */
9383ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
9384ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9385ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ------------------ qadd16<c> <Rd>,<Rn>,<Rm> ------------------ */
9386ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   {
9387ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     UInt regD = 99, regN = 99, regM = 99;
9388ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     Bool gate = False;
9389ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9390ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     if (isT) {
9391ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        if (INSNT0(15,4) == 0xFA9 && (INSNT1(15,0) & 0xF0F0) == 0xF010) {
9392ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regN = INSNT0(3,0);
9393ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regD = INSNT1(11,8);
9394ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regM = INSNT1(3,0);
9395ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
9396ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              gate = True;
9397ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        }
9398ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     } else {
9399ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        if (INSNA(27,20) == BITS8(0,1,1,0,0,0,1,0) &&
9400ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            INSNA(11,8)  == BITS4(1,1,1,1)         &&
9401ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            INSNA(7,4)   == BITS4(0,0,0,1)) {
9402ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regD = INSNA(15,12);
9403ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regN = INSNA(19,16);
9404ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regM = INSNA(3,0);
9405ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           if (regD != 15 && regN != 15 && regM != 15)
9406ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              gate = True;
9407ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        }
9408ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     }
9409ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9410ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     if (gate) {
9411ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRTemp rNt   = newTemp(Ity_I32);
9412ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRTemp rMt   = newTemp(Ity_I32);
9413ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRTemp res_q = newTemp(Ity_I32);
9414ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9415ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        assign( rNt, isT ? getIRegT(regN) : getIRegA(regN) );
9416ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        assign( rMt, isT ? getIRegT(regM) : getIRegA(regM) );
9417ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9418ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        assign(res_q, binop(Iop_QAdd16Sx2, mkexpr(rNt), mkexpr(rMt)));
9419ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        if (isT)
9420ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           putIRegT( regD, mkexpr(res_q), condT );
9421ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        else
9422ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           putIRegA( regD, mkexpr(res_q), condT, Ijk_Boring );
9423ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9424ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        DIP("qadd16%s r%u, r%u, r%u\n", nCC(conq),regD,regN,regM);
9425ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        return True;
9426ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     }
9427ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     /* fall through */
9428ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
9429ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9430ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ------------------ qsub16<c> <Rd>,<Rn>,<Rm> ------------------ */
9431ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   {
9432ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     UInt regD = 99, regN = 99, regM = 99;
9433ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     Bool gate = False;
9434ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9435ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (isT) {
9436ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        if (INSNT0(15,4) == 0xFAD && (INSNT1(15,0) & 0xF0F0) == 0xF010) {
9437ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regN = INSNT0(3,0);
9438ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regD = INSNT1(11,8);
9439ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regM = INSNT1(3,0);
9440ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
9441ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              gate = True;
9442ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        }
9443ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     } else {
9444ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        if (INSNA(27,20) == BITS8(0,1,1,0,0,0,1,0) &&
9445ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            INSNA(11,8)  == BITS4(1,1,1,1)         &&
9446ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            INSNA(7,4)   == BITS4(0,1,1,1)) {
9447ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regD = INSNA(15,12);
9448ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regN = INSNA(19,16);
9449ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regM = INSNA(3,0);
9450ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           if (regD != 15 && regN != 15 && regM != 15)
9451ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             gate = True;
9452ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        }
9453ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     }
9454ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9455ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     if (gate) {
9456ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRTemp rNt   = newTemp(Ity_I32);
9457ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRTemp rMt   = newTemp(Ity_I32);
9458ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRTemp res_q = newTemp(Ity_I32);
9459ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9460ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        assign( rNt, isT ? getIRegT(regN) : getIRegA(regN) );
9461ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        assign( rMt, isT ? getIRegT(regM) : getIRegA(regM) );
9462ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9463ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        assign(res_q, binop(Iop_QSub16Sx2, mkexpr(rNt), mkexpr(rMt)));
9464ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        if (isT)
9465ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           putIRegT( regD, mkexpr(res_q), condT );
9466ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        else
9467ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           putIRegA( regD, mkexpr(res_q), condT, Ijk_Boring );
9468ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9469ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        DIP("qsub16%s r%u, r%u, r%u\n", nCC(conq),regD,regN,regM);
9470ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        return True;
9471ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     }
9472ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     /* fall through */
9473ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
9474ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9475ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /////////////////////////////////////////////////////////////////
9476ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /////////////////////////////////////////////////////////////////
9477ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /////////////////////////////////////////////////////////////////
9478ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /////////////////////////////////////////////////////////////////
9479ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /////////////////////////////////////////////////////////////////
9480ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9481ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ------------------- qsax<c> <Rd>,<Rn>,<Rm> ------------------- */
9482ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* note: the hardware seems to construct the result differently
9483ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      from wot the manual says. */
9484ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   {
9485ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     UInt regD = 99, regN = 99, regM = 99;
9486ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     Bool gate = False;
9487ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9488ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     if (isT) {
9489ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        if (INSNT0(15,4) == 0xFAE && (INSNT1(15,0) & 0xF0F0) == 0xF010) {
9490ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regN = INSNT0(3,0);
9491ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regD = INSNT1(11,8);
9492ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regM = INSNT1(3,0);
9493ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
9494ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              gate = True;
9495ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        }
9496ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     } else {
9497ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        if (INSNA(27,20) == BITS8(0,1,1,0,0,0,1,0) &&
9498ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            INSNA(11,8)  == BITS4(1,1,1,1)         &&
9499ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            INSNA(7,4)   == BITS4(0,1,0,1)) {
9500ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regD = INSNA(15,12);
9501ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regN = INSNA(19,16);
9502ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regM = INSNA(3,0);
9503ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           if (regD != 15 && regN != 15 && regM != 15)
9504ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              gate = True;
9505ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        }
9506ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     }
9507ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9508ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     if (gate) {
9509ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRTemp irt_regN     = newTemp(Ity_I32);
9510ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRTemp irt_regM     = newTemp(Ity_I32);
9511ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRTemp irt_sum      = newTemp(Ity_I32);
9512ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRTemp irt_diff     = newTemp(Ity_I32);
9513ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRTemp irt_sum_res  = newTemp(Ity_I32);
9514ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRTemp irt_diff_res = newTemp(Ity_I32);
9515ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9516ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        assign( irt_regN, isT ? getIRegT(regN) : getIRegA(regN) );
9517ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        assign( irt_regM, isT ? getIRegT(regM) : getIRegA(regM) );
9518ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9519ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        assign( irt_diff,
9520ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                binop( Iop_Sub32,
9521ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       binop( Iop_Sar32, mkexpr(irt_regN), mkU8(16) ),
9522ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       binop( Iop_Sar32,
9523ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              binop(Iop_Shl32, mkexpr(irt_regM), mkU8(16)),
9524ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              mkU8(16) ) ) );
9525ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        armSignedSatQ( irt_diff, 0x10, &irt_diff_res, NULL);
9526ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9527ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        assign( irt_sum,
9528ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                binop( Iop_Add32,
9529ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       binop( Iop_Sar32,
9530ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              binop( Iop_Shl32, mkexpr(irt_regN), mkU8(16) ),
9531ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              mkU8(16) ),
9532ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       binop( Iop_Sar32, mkexpr(irt_regM), mkU8(16) )) );
9533ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        armSignedSatQ( irt_sum, 0x10, &irt_sum_res, NULL );
9534ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9535ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRExpr* ire_result = binop( Iop_Or32,
9536ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    binop( Iop_Shl32, mkexpr(irt_diff_res),
9537ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                           mkU8(16) ),
9538ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    binop( Iop_And32, mkexpr(irt_sum_res),
9539ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                           mkU32(0xFFFF)) );
9540ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9541ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        if (isT)
9542ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           putIRegT( regD, ire_result, condT );
9543ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        else
9544ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           putIRegA( regD, ire_result, condT, Ijk_Boring );
9545ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9546ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        DIP( "qsax%s r%u, r%u, r%u\n", nCC(conq), regD, regN, regM );
9547ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        return True;
9548ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     }
9549ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     /* fall through */
9550ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
9551ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9552ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ------------------- qasx<c> <Rd>,<Rn>,<Rm> ------------------- */
9553ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   {
9554ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     UInt regD = 99, regN = 99, regM = 99;
9555ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     Bool gate = False;
9556ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9557ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     if (isT) {
9558ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        if (INSNT0(15,4) == 0xFAA && (INSNT1(15,0) & 0xF0F0) == 0xF010) {
9559ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regN = INSNT0(3,0);
9560ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regD = INSNT1(11,8);
9561ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regM = INSNT1(3,0);
9562ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
9563ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              gate = True;
9564ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        }
9565ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     } else {
9566ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        if (INSNA(27,20) == BITS8(0,1,1,0,0,0,1,0) &&
9567ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            INSNA(11,8)  == BITS4(1,1,1,1)         &&
9568ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            INSNA(7,4)   == BITS4(0,0,1,1)) {
9569ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regD = INSNA(15,12);
9570ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regN = INSNA(19,16);
9571ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regM = INSNA(3,0);
9572ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           if (regD != 15 && regN != 15 && regM != 15)
9573ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              gate = True;
9574ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        }
9575ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     }
9576ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9577ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     if (gate) {
9578ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRTemp irt_regN     = newTemp(Ity_I32);
9579ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRTemp irt_regM     = newTemp(Ity_I32);
9580ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRTemp irt_sum      = newTemp(Ity_I32);
9581ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRTemp irt_diff     = newTemp(Ity_I32);
9582ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRTemp irt_res_sum  = newTemp(Ity_I32);
9583ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRTemp irt_res_diff = newTemp(Ity_I32);
9584ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9585ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        assign( irt_regN, isT ? getIRegT(regN) : getIRegA(regN) );
9586ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        assign( irt_regM, isT ? getIRegT(regM) : getIRegA(regM) );
9587ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9588ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        assign( irt_diff,
9589ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                binop( Iop_Sub32,
9590ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       binop( Iop_Sar32,
9591ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              binop( Iop_Shl32, mkexpr(irt_regN), mkU8(16) ),
9592ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              mkU8(16) ),
9593ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       binop( Iop_Sar32, mkexpr(irt_regM), mkU8(16) ) ) );
9594ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        armSignedSatQ( irt_diff, 0x10, &irt_res_diff, NULL );
9595ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9596ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        assign( irt_sum,
9597ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                binop( Iop_Add32,
9598ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       binop( Iop_Sar32, mkexpr(irt_regN), mkU8(16) ),
9599ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       binop( Iop_Sar32,
9600ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              binop( Iop_Shl32, mkexpr(irt_regM), mkU8(16) ),
9601ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              mkU8(16) ) ) );
9602ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        armSignedSatQ( irt_sum, 0x10, &irt_res_sum, NULL );
9603ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9604ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRExpr* ire_result
9605ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          = binop( Iop_Or32,
9606ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   binop( Iop_Shl32, mkexpr(irt_res_sum), mkU8(16) ),
9607ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   binop( Iop_And32, mkexpr(irt_res_diff), mkU32(0xFFFF) ) );
9608ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9609ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        if (isT)
9610ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           putIRegT( regD, ire_result, condT );
9611ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        else
9612ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           putIRegA( regD, ire_result, condT, Ijk_Boring );
9613ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9614ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        DIP( "qasx%s r%u, r%u, r%u\n", nCC(conq), regD, regN, regM );
9615ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        return True;
9616ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     }
9617ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     /* fall through */
9618ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
9619ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9620ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ------------------- sasx<c> <Rd>,<Rn>,<Rm> ------------------- */
9621ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   {
9622ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     UInt regD = 99, regN = 99, regM = 99;
9623ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     Bool gate = False;
9624ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9625ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     if (isT) {
9626ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        if (INSNT0(15,4) == 0xFAA && (INSNT1(15,0) & 0xF0F0) == 0xF000) {
9627ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regN = INSNT0(3,0);
9628ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regD = INSNT1(11,8);
9629ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regM = INSNT1(3,0);
9630ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
9631ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              gate = True;
9632ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        }
9633ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     } else {
9634ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        if (INSNA(27,20) == BITS8(0,1,1,0,0,0,0,1) &&
9635ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            INSNA(11,8)  == BITS4(1,1,1,1)         &&
9636ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            INSNA(7,4)   == BITS4(0,0,1,1)) {
9637ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regD = INSNA(15,12);
9638ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regN = INSNA(19,16);
9639ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regM = INSNA(3,0);
9640ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           if (regD != 15 && regN != 15 && regM != 15)
9641ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              gate = True;
9642ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        }
9643ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     }
9644ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9645ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     if (gate) {
9646ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRTemp irt_regN = newTemp(Ity_I32);
9647ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRTemp irt_regM = newTemp(Ity_I32);
9648ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRTemp irt_sum  = newTemp(Ity_I32);
9649ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRTemp irt_diff = newTemp(Ity_I32);
9650ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9651ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        assign( irt_regN, isT ? getIRegT(regN) : getIRegA(regN) );
9652ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        assign( irt_regM, isT ? getIRegT(regM) : getIRegA(regM) );
9653ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9654ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        assign( irt_diff,
9655ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                binop( Iop_Sub32,
9656ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       binop( Iop_Sar32,
9657ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              binop( Iop_Shl32, mkexpr(irt_regN), mkU8(16) ),
9658ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              mkU8(16) ),
9659ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       binop( Iop_Sar32, mkexpr(irt_regM), mkU8(16) ) ) );
9660ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9661ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        assign( irt_sum,
9662ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                binop( Iop_Add32,
9663ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       binop( Iop_Sar32, mkexpr(irt_regN), mkU8(16) ),
9664ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       binop( Iop_Sar32,
9665ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              binop( Iop_Shl32, mkexpr(irt_regM), mkU8(16) ),
9666ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              mkU8(16) ) ) );
9667ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9668ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRExpr* ire_result
9669ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          = binop( Iop_Or32,
9670ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   binop( Iop_Shl32, mkexpr(irt_sum), mkU8(16) ),
9671ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   binop( Iop_And32, mkexpr(irt_diff), mkU32(0xFFFF) ) );
9672ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9673ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRTemp ge10 = newTemp(Ity_I32);
9674ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        assign(ge10, unop(Iop_Not32, mkexpr(irt_diff)));
9675ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        put_GEFLAG32( 0, 31, mkexpr(ge10), condT );
9676ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        put_GEFLAG32( 1, 31, mkexpr(ge10), condT );
9677ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9678ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRTemp ge32 = newTemp(Ity_I32);
9679ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        assign(ge32, unop(Iop_Not32, mkexpr(irt_sum)));
9680ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        put_GEFLAG32( 2, 31, mkexpr(ge32), condT );
9681ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        put_GEFLAG32( 3, 31, mkexpr(ge32), condT );
9682ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9683ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        if (isT)
9684ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           putIRegT( regD, ire_result, condT );
9685ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        else
9686ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           putIRegA( regD, ire_result, condT, Ijk_Boring );
9687ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9688ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        DIP( "sasx%s r%u, r%u, r%u\n", nCC(conq), regD, regN, regM );
9689ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        return True;
9690ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     }
9691ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     /* fall through */
9692ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
9693ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9694ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* --------------- smuad, smuadx<c><Rd>,<Rn>,<Rm> --------------- */
9695ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* --------------- smsad, smsadx<c><Rd>,<Rn>,<Rm> --------------- */
9696ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   {
9697ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     UInt regD = 99, regN = 99, regM = 99, bitM = 99;
9698ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     Bool gate = False, isAD = False;
9699ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9700ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     if (isT) {
9701ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        if ((INSNT0(15,4) == 0xFB2 || INSNT0(15,4) == 0xFB4)
9702ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            && (INSNT1(15,0) & 0xF0E0) == 0xF000) {
9703ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regN = INSNT0(3,0);
9704ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regD = INSNT1(11,8);
9705ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regM = INSNT1(3,0);
9706ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           bitM = INSNT1(4,4);
9707ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           isAD = INSNT0(15,4) == 0xFB2;
9708ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
9709ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              gate = True;
9710ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        }
9711ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     } else {
9712ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        if (INSNA(27,20) == BITS8(0,1,1,1,0,0,0,0) &&
9713ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            INSNA(15,12) == BITS4(1,1,1,1)         &&
9714ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            (INSNA(7,4) & BITS4(1,0,0,1)) == BITS4(0,0,0,1) ) {
9715ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regD = INSNA(19,16);
9716ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regN = INSNA(3,0);
9717ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regM = INSNA(11,8);
9718ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           bitM = INSNA(5,5);
9719ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           isAD = INSNA(6,6) == 0;
9720ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           if (regD != 15 && regN != 15 && regM != 15)
9721ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              gate = True;
9722ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        }
9723ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     }
9724ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9725ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     if (gate) {
9726ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRTemp irt_regN    = newTemp(Ity_I32);
9727ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRTemp irt_regM    = newTemp(Ity_I32);
9728ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRTemp irt_prod_lo = newTemp(Ity_I32);
9729ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRTemp irt_prod_hi = newTemp(Ity_I32);
9730ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRTemp tmpM        = newTemp(Ity_I32);
9731ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9732ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        assign( irt_regN, isT ? getIRegT(regN) : getIRegA(regN) );
9733ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9734ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        assign( tmpM, isT ? getIRegT(regM) : getIRegA(regM) );
9735ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        assign( irt_regM, genROR32(tmpM, (bitM & 1) ? 16 : 0) );
9736ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9737ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        assign( irt_prod_lo,
9738ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                binop( Iop_Mul32,
9739ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       binop( Iop_Sar32,
9740ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              binop(Iop_Shl32, mkexpr(irt_regN), mkU8(16)),
9741ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              mkU8(16) ),
9742ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       binop( Iop_Sar32,
9743ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              binop(Iop_Shl32, mkexpr(irt_regM), mkU8(16)),
9744ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              mkU8(16) ) ) );
9745ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        assign( irt_prod_hi, binop(Iop_Mul32,
9746ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   binop(Iop_Sar32, mkexpr(irt_regN), mkU8(16)),
9747ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   binop(Iop_Sar32, mkexpr(irt_regM), mkU8(16))) );
9748ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRExpr* ire_result
9749ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           = binop( isAD ? Iop_Add32 : Iop_Sub32,
9750ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    mkexpr(irt_prod_lo), mkexpr(irt_prod_hi) );
9751ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9752ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        if (isT)
9753ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           putIRegT( regD, ire_result, condT );
9754ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        else
9755ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           putIRegA( regD, ire_result, condT, Ijk_Boring );
9756ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9757ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        if (isAD) {
9758ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           or_into_QFLAG32(
9759ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              signed_overflow_after_Add32( ire_result,
9760ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                           irt_prod_lo, irt_prod_hi ),
9761ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              condT
9762ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           );
9763ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        }
9764ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9765ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        DIP("smu%cd%s%s r%u, r%u, r%u\n",
9766ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            isAD ? 'a' : 's',
9767ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            bitM ? "x" : "", nCC(conq), regD, regN, regM);
9768ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        return True;
9769ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     }
9770ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     /* fall through */
9771ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
9772ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9773ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* --------------- smlad{X}<c> <Rd>,<Rn>,<Rm>,<Ra> -------------- */
9774ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* --------------- smlsd{X}<c> <Rd>,<Rn>,<Rm>,<Ra> -------------- */
9775ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   {
9776ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     UInt regD = 99, regN = 99, regM = 99, regA = 99, bitM = 99;
9777ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     Bool gate = False, isAD = False;
9778ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9779ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     if (isT) {
9780ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       if ((INSNT0(15,4) == 0xFB2 || INSNT0(15,4) == 0xFB4)
9781ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           && INSNT1(7,5) == BITS3(0,0,0)) {
9782ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regN = INSNT0(3,0);
9783ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regD = INSNT1(11,8);
9784ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regM = INSNT1(3,0);
9785ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regA = INSNT1(15,12);
9786ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           bitM = INSNT1(4,4);
9787ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           isAD = INSNT0(15,4) == 0xFB2;
9788ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM)
9789ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               && !isBadRegT(regA))
9790ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              gate = True;
9791ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        }
9792ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     } else {
9793ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        if (INSNA(27,20) == BITS8(0,1,1,1,0,0,0,0) &&
9794ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            (INSNA(7,4) & BITS4(1,0,0,1)) == BITS4(0,0,0,1)) {
9795ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regD = INSNA(19,16);
9796ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regA = INSNA(15,12);
9797ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regN = INSNA(3,0);
9798ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regM = INSNA(11,8);
9799ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           bitM = INSNA(5,5);
9800ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           isAD = INSNA(6,6) == 0;
9801ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           if (regD != 15 && regN != 15 && regM != 15 && regA != 15)
9802ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              gate = True;
9803ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        }
9804ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     }
9805ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9806ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     if (gate) {
9807ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRTemp irt_regN    = newTemp(Ity_I32);
9808ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRTemp irt_regM    = newTemp(Ity_I32);
9809ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRTemp irt_regA    = newTemp(Ity_I32);
9810ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRTemp irt_prod_lo = newTemp(Ity_I32);
9811ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRTemp irt_prod_hi = newTemp(Ity_I32);
9812ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRTemp irt_sum     = newTemp(Ity_I32);
9813ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRTemp tmpM        = newTemp(Ity_I32);
9814ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9815ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        assign( irt_regN, isT ? getIRegT(regN) : getIRegA(regN) );
9816ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        assign( irt_regA, isT ? getIRegT(regA) : getIRegA(regA) );
9817ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9818ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        assign( tmpM, isT ? getIRegT(regM) : getIRegA(regM) );
9819ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        assign( irt_regM, genROR32(tmpM, (bitM & 1) ? 16 : 0) );
9820ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9821ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        assign( irt_prod_lo,
9822ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                binop(Iop_Mul32,
9823ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      binop(Iop_Sar32,
9824ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            binop( Iop_Shl32, mkexpr(irt_regN), mkU8(16) ),
9825ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            mkU8(16)),
9826ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      binop(Iop_Sar32,
9827ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            binop( Iop_Shl32, mkexpr(irt_regM), mkU8(16) ),
9828ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            mkU8(16))) );
9829ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        assign( irt_prod_hi,
9830ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                binop( Iop_Mul32,
9831ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       binop( Iop_Sar32, mkexpr(irt_regN), mkU8(16) ),
9832ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       binop( Iop_Sar32, mkexpr(irt_regM), mkU8(16) ) ) );
9833ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        assign( irt_sum, binop( isAD ? Iop_Add32 : Iop_Sub32,
9834ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                mkexpr(irt_prod_lo), mkexpr(irt_prod_hi) ) );
9835ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9836ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRExpr* ire_result = binop(Iop_Add32, mkexpr(irt_sum), mkexpr(irt_regA));
9837ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9838ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        if (isT)
9839ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           putIRegT( regD, ire_result, condT );
9840ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        else
9841ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           putIRegA( regD, ire_result, condT, Ijk_Boring );
9842ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9843ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        if (isAD) {
9844ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           or_into_QFLAG32(
9845ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              signed_overflow_after_Add32( mkexpr(irt_sum),
9846ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                           irt_prod_lo, irt_prod_hi ),
9847ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              condT
9848ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           );
9849ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        }
9850ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9851ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        or_into_QFLAG32(
9852ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           signed_overflow_after_Add32( ire_result, irt_sum, irt_regA ),
9853ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           condT
9854ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        );
9855ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9856ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        DIP("sml%cd%s%s r%u, r%u, r%u, r%u\n",
9857ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            isAD ? 'a' : 's',
9858ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            bitM ? "x" : "", nCC(conq), regD, regN, regM, regA);
9859ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        return True;
9860ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     }
9861ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     /* fall through */
9862ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
9863ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9864ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ----- smlabb, smlabt, smlatb, smlatt <Rd>,<Rn>,<Rm>,<Ra> ----- */
9865ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   {
9866ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     UInt regD = 99, regN = 99, regM = 99, regA = 99, bitM = 99, bitN = 99;
9867ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     Bool gate = False;
9868ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9869ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     if (isT) {
9870ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        if (INSNT0(15,4) == 0xFB1 && INSNT1(7,6) == BITS2(0,0)) {
9871ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regN = INSNT0(3,0);
9872ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regD = INSNT1(11,8);
9873ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regM = INSNT1(3,0);
9874ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regA = INSNT1(15,12);
9875ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           bitM = INSNT1(4,4);
9876ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           bitN = INSNT1(5,5);
9877ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM)
9878ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               && !isBadRegT(regA))
9879ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              gate = True;
9880ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        }
9881ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     } else {
9882ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        if (INSNA(27,20) == BITS8(0,0,0,1,0,0,0,0) &&
9883ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            (INSNA(7,4) & BITS4(1,0,0,1)) == BITS4(1,0,0,0)) {
9884ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regD = INSNA(19,16);
9885ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regN = INSNA(3,0);
9886ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regM = INSNA(11,8);
9887ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regA = INSNA(15,12);
9888ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           bitM = INSNA(6,6);
9889ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           bitN = INSNA(5,5);
9890ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           if (regD != 15 && regN != 15 && regM != 15 && regA != 15)
9891ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              gate = True;
9892ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        }
9893ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     }
9894ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9895ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     if (gate) {
9896ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRTemp irt_regA = newTemp(Ity_I32);
9897ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRTemp irt_prod = newTemp(Ity_I32);
9898ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9899ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        assign( irt_prod,
9900ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                binop(Iop_Mul32,
9901ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      binop(Iop_Sar32,
9902ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            binop(Iop_Shl32,
9903ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  isT ? getIRegT(regN) : getIRegA(regN),
9904ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  mkU8(bitN ? 0 : 16)),
9905ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            mkU8(16)),
9906ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      binop(Iop_Sar32,
9907ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            binop(Iop_Shl32,
9908ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  isT ? getIRegT(regM) : getIRegA(regM),
9909ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  mkU8(bitM ? 0 : 16)),
9910ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            mkU8(16))) );
9911ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9912ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        assign( irt_regA, isT ? getIRegT(regA) : getIRegA(regA) );
9913ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9914ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRExpr* ire_result = binop(Iop_Add32, mkexpr(irt_prod), mkexpr(irt_regA));
9915ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9916ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        if (isT)
9917ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           putIRegT( regD, ire_result, condT );
9918ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        else
9919ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           putIRegA( regD, ire_result, condT, Ijk_Boring );
9920ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9921ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        or_into_QFLAG32(
9922ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           signed_overflow_after_Add32( ire_result, irt_prod, irt_regA ),
9923ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           condT
9924ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        );
9925ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9926ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        DIP( "smla%c%c%s r%u, r%u, r%u, r%u\n",
9927ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             bitN ? 't' : 'b', bitM ? 't' : 'b',
9928ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             nCC(conq), regD, regN, regM, regA );
9929ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        return True;
9930ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     }
9931ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     /* fall through */
9932ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
9933ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9934ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ----- smlawb, smlawt <Rd>,<Rn>,<Rm>,<Ra> ----- */
9935ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   {
9936ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     UInt regD = 99, regN = 99, regM = 99, regA = 99, bitM = 99;
9937ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     Bool gate = False;
9938ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9939ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     if (isT) {
9940ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        if (INSNT0(15,4) == 0xFB3 && INSNT1(7,5) == BITS3(0,0,0)) {
9941ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regN = INSNT0(3,0);
9942ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regD = INSNT1(11,8);
9943ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regM = INSNT1(3,0);
9944ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regA = INSNT1(15,12);
9945ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           bitM = INSNT1(4,4);
9946ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM)
9947ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               && !isBadRegT(regA))
9948ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              gate = True;
9949ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        }
9950ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     } else {
9951ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        if (INSNA(27,20) == BITS8(0,0,0,1,0,0,1,0) &&
9952ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            (INSNA(7,4) & BITS4(1,0,1,1)) == BITS4(1,0,0,0)) {
9953ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regD = INSNA(19,16);
9954ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regN = INSNA(3,0);
9955ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regM = INSNA(11,8);
9956ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regA = INSNA(15,12);
9957ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           bitM = INSNA(6,6);
9958ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           if (regD != 15 && regN != 15 && regM != 15 && regA != 15)
9959ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              gate = True;
9960ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        }
9961ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     }
9962ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9963ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     if (gate) {
9964ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRTemp irt_regA = newTemp(Ity_I32);
9965ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRTemp irt_prod = newTemp(Ity_I64);
9966ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9967ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        assign( irt_prod,
9968ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                binop(Iop_MullS32,
9969ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      isT ? getIRegT(regN) : getIRegA(regN),
9970ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      binop(Iop_Sar32,
9971ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            binop(Iop_Shl32,
9972ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  isT ? getIRegT(regM) : getIRegA(regM),
9973ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  mkU8(bitM ? 0 : 16)),
9974ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            mkU8(16))) );
9975ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9976ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        assign( irt_regA, isT ? getIRegT(regA) : getIRegA(regA) );
9977ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9978ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRTemp prod32 = newTemp(Ity_I32);
9979ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        assign(prod32,
9980ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               binop(Iop_Or32,
9981ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     binop(Iop_Shl32, unop(Iop_64HIto32, mkexpr(irt_prod)), mkU8(16)),
9982ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     binop(Iop_Shr32, unop(Iop_64to32, mkexpr(irt_prod)), mkU8(16))
9983ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        ));
9984ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9985ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRExpr* ire_result = binop(Iop_Add32, mkexpr(prod32), mkexpr(irt_regA));
9986ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9987ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        if (isT)
9988ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           putIRegT( regD, ire_result, condT );
9989ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        else
9990ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           putIRegA( regD, ire_result, condT, Ijk_Boring );
9991ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9992ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        or_into_QFLAG32(
9993ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           signed_overflow_after_Add32( ire_result, prod32, irt_regA ),
9994ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           condT
9995ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        );
9996ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9997ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        DIP( "smlaw%c%s r%u, r%u, r%u, r%u\n",
9998ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             bitM ? 't' : 'b',
9999ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             nCC(conq), regD, regN, regM, regA );
10000ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        return True;
10001ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     }
10002ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     /* fall through */
10003ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10004ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10005ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ------------------- sel<c> <Rd>,<Rn>,<Rm> -------------------- */
10006ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* fixme: fix up the test in v6media.c so that we can pass the ge
10007ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      flags as part of the test. */
10008ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   {
10009ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     UInt regD = 99, regN = 99, regM = 99;
10010ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     Bool gate = False;
10011ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10012ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     if (isT) {
10013ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        if (INSNT0(15,4) == 0xFAA && (INSNT1(15,0) & 0xF0F0) == 0xF080) {
10014ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regN = INSNT0(3,0);
10015ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regD = INSNT1(11,8);
10016ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regM = INSNT1(3,0);
10017ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
10018ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              gate = True;
10019ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        }
10020ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     } else {
10021ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        if (INSNA(27,20) == BITS8(0,1,1,0,1,0,0,0) &&
10022ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            INSNA(11,8)  == BITS4(1,1,1,1)         &&
10023ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            INSNA(7,4)   == BITS4(1,0,1,1)) {
10024ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regD = INSNA(15,12);
10025ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regN = INSNA(19,16);
10026ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regM = INSNA(3,0);
10027ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           if (regD != 15 && regN != 15 && regM != 15)
10028ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              gate = True;
10029ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        }
10030ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     }
10031ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10032ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     if (gate) {
10033ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRTemp irt_ge_flag0 = newTemp(Ity_I32);
10034ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRTemp irt_ge_flag1 = newTemp(Ity_I32);
10035ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRTemp irt_ge_flag2 = newTemp(Ity_I32);
10036ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRTemp irt_ge_flag3 = newTemp(Ity_I32);
10037ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10038ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        assign( irt_ge_flag0, get_GEFLAG32(0) );
10039ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        assign( irt_ge_flag1, get_GEFLAG32(1) );
10040ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        assign( irt_ge_flag2, get_GEFLAG32(2) );
10041ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        assign( irt_ge_flag3, get_GEFLAG32(3) );
10042ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10043ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRExpr* ire_ge_flag0_or
10044ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          = binop(Iop_Or32, mkexpr(irt_ge_flag0),
10045ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  binop(Iop_Sub32, mkU32(0), mkexpr(irt_ge_flag0)));
10046ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRExpr* ire_ge_flag1_or
10047ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          = binop(Iop_Or32, mkexpr(irt_ge_flag1),
10048ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  binop(Iop_Sub32, mkU32(0), mkexpr(irt_ge_flag1)));
10049ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRExpr* ire_ge_flag2_or
10050ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          = binop(Iop_Or32, mkexpr(irt_ge_flag2),
10051ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  binop(Iop_Sub32, mkU32(0), mkexpr(irt_ge_flag2)));
10052ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRExpr* ire_ge_flag3_or
10053ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          = binop(Iop_Or32, mkexpr(irt_ge_flag3),
10054ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  binop(Iop_Sub32, mkU32(0), mkexpr(irt_ge_flag3)));
10055ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10056ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRExpr* ire_ge_flags
10057ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          = binop( Iop_Or32,
10058ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   binop(Iop_Or32,
10059ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         binop(Iop_And32,
10060ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               binop(Iop_Sar32, ire_ge_flag0_or, mkU8(31)),
10061ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               mkU32(0x000000ff)),
10062ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         binop(Iop_And32,
10063ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               binop(Iop_Sar32, ire_ge_flag1_or, mkU8(31)),
10064ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               mkU32(0x0000ff00))),
10065ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   binop(Iop_Or32,
10066ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         binop(Iop_And32,
10067ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               binop(Iop_Sar32, ire_ge_flag2_or, mkU8(31)),
10068ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               mkU32(0x00ff0000)),
10069ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         binop(Iop_And32,
10070ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               binop(Iop_Sar32, ire_ge_flag3_or, mkU8(31)),
10071ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               mkU32(0xff000000))) );
10072ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10073ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRExpr* ire_result
10074ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          = binop(Iop_Or32,
10075ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  binop(Iop_And32,
10076ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        isT ? getIRegT(regN) : getIRegA(regN),
10077ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        ire_ge_flags ),
10078ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  binop(Iop_And32,
10079ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        isT ? getIRegT(regM) : getIRegA(regM),
10080ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        unop(Iop_Not32, ire_ge_flags)));
10081ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10082ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        if (isT)
10083ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           putIRegT( regD, ire_result, condT );
10084ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        else
10085ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           putIRegA( regD, ire_result, condT, Ijk_Boring );
10086ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10087ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        DIP("sel%s r%u, r%u, r%u\n", nCC(conq), regD, regN, regM );
10088ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        return True;
10089ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     }
10090ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     /* fall through */
10091ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10092ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10093ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ----------------- uxtab16<c> Rd,Rn,Rm{,rot} ------------------ */
10094ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   {
10095ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     UInt regD = 99, regN = 99, regM = 99, rotate = 99;
10096ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     Bool gate = False;
10097ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10098ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     if (isT) {
10099ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        if (INSNT0(15,4) == 0xFA3 && (INSNT1(15,0) & 0xF0C0) == 0xF080) {
10100ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regN   = INSNT0(3,0);
10101ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regD   = INSNT1(11,8);
10102ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regM   = INSNT1(3,0);
10103ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           rotate = INSNT1(5,4);
10104ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
10105ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              gate = True;
10106ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        }
10107ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     } else {
10108ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        if (INSNA(27,20) == BITS8(0,1,1,0,1,1,0,0) &&
10109ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            INSNA(9,4)   == BITS6(0,0,0,1,1,1) ) {
10110ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regD   = INSNA(15,12);
10111ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regN   = INSNA(19,16);
10112ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           regM   = INSNA(3,0);
10113ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           rotate = INSNA(11,10);
10114ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           if (regD != 15 && regN != 15 && regM != 15)
10115ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             gate = True;
10116ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        }
10117ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     }
10118ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10119ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     if (gate) {
10120ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRTemp irt_regN = newTemp(Ity_I32);
10121ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        assign( irt_regN, isT ? getIRegT(regN) : getIRegA(regN) );
10122ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10123ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRTemp irt_regM = newTemp(Ity_I32);
10124ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        assign( irt_regM, isT ? getIRegT(regM) : getIRegA(regM) );
10125ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10126ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRTemp irt_rot = newTemp(Ity_I32);
10127ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        assign( irt_rot, binop(Iop_And32,
10128ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               genROR32(irt_regM, 8 * rotate),
10129ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               mkU32(0x00FF00FF)) );
10130ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10131ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRExpr* resLo
10132ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           = binop(Iop_And32,
10133ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   binop(Iop_Add32, mkexpr(irt_regN), mkexpr(irt_rot)),
10134ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   mkU32(0x0000FFFF));
10135ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10136ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRExpr* resHi
10137ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           = binop(Iop_Add32,
10138ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   binop(Iop_And32, mkexpr(irt_regN), mkU32(0xFFFF0000)),
10139ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   binop(Iop_And32, mkexpr(irt_rot),  mkU32(0xFFFF0000)));
10140ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10141ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRExpr* ire_result
10142ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           = binop( Iop_Or32, resHi, resLo );
10143ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10144ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        if (isT)
10145ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           putIRegT( regD, ire_result, condT );
10146ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        else
10147ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           putIRegA( regD, ire_result, condT, Ijk_Boring );
10148ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10149ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        DIP( "uxtab16%s r%u, r%u, r%u, ROR #%u\n",
10150ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             nCC(conq), regD, regN, regM, 8 * rotate );
10151ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        return True;
10152ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     }
10153ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     /* fall through */
10154ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10155ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10156ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* --------------- usad8  Rd,Rn,Rm    ---------------- */
10157ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* --------------- usada8 Rd,Rn,Rm,Ra ---------------- */
10158ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   {
10159ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     UInt rD = 99, rN = 99, rM = 99, rA = 99;
10160ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     Bool gate = False;
10161ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10162ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     if (isT) {
10163ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       if (INSNT0(15,4) == 0xFB7 && INSNT1(7,4) == BITS4(0,0,0,0)) {
10164ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           rN = INSNT0(3,0);
10165ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           rA = INSNT1(15,12);
10166ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           rD = INSNT1(11,8);
10167ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           rM = INSNT1(3,0);
10168ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           if (!isBadRegT(rD) && !isBadRegT(rN) && !isBadRegT(rM) && rA != 13)
10169ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              gate = True;
10170ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        }
10171ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     } else {
10172ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        if (INSNA(27,20) == BITS8(0,1,1,1,1,0,0,0) &&
10173ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            INSNA(7,4)   == BITS4(0,0,0,1) ) {
10174ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           rD = INSNA(19,16);
10175ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           rA = INSNA(15,12);
10176ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           rM = INSNA(11,8);
10177ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           rN = INSNA(3,0);
10178ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           if (rD != 15 && rN != 15 && rM != 15 /* but rA can be 15 */)
10179ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              gate = True;
10180ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        }
10181ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     }
10182ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     /* We allow rA == 15, to denote the usad8 (no accumulator) case. */
10183ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10184ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     if (gate) {
10185ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRExpr* rNe = isT ? getIRegT(rN) : getIRegA(rN);
10186ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRExpr* rMe = isT ? getIRegT(rM) : getIRegA(rM);
10187ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRExpr* rAe = rA == 15 ? mkU32(0)
10188ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               : (isT ? getIRegT(rA) : getIRegA(rA));
10189ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRExpr* res = binop(Iop_Add32,
10190ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            binop(Iop_Sad8Ux4, rNe, rMe),
10191ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            rAe);
10192ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        if (isT)
10193ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           putIRegT( rD, res, condT );
10194ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        else
10195ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           putIRegA( rD, res, condT, Ijk_Boring );
10196ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10197ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        if (rA == 15) {
10198ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           DIP( "usad8%s r%u, r%u, r%u\n",
10199ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                nCC(conq), rD, rN, rM );
10200ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        } else {
10201ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           DIP( "usada8%s r%u, r%u, r%u, r%u\n",
10202ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                nCC(conq), rD, rN, rM, rA );
10203ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        }
10204ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        return True;
10205ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     }
10206ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     /* fall through */
10207ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10208ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10209ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ---------- Doesn't match anything. ---------- */
10210ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return False;
10211ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10212ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  undef INSNA
10213ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  undef INSNT0
10214ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  undef INSNT1
10215ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
10216ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10217ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10218ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
10219ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- LDMxx/STMxx helper (both ARM and Thumb32)            ---*/
10220ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
10221ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10222ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Generate IR for LDMxx and STMxx.  This is complex.  Assumes it's
10223ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   unconditional, so the caller must produce a jump-around before
10224ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   calling this, if the insn is to be conditional.  Caller is
10225ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   responsible for all validation of parameters.  For LDMxx, if PC is
10226ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   amongst the values loaded, caller is also responsible for
10227ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   generating the jump. */
10228ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void mk_ldm_stm ( Bool arm,     /* True: ARM, False: Thumb */
10229ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         UInt rN,      /* base reg */
10230ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         UInt bINC,    /* 1: inc,  0: dec */
10231ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         UInt bBEFORE, /* 1: inc/dec before, 0: after */
10232ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         UInt bW,      /* 1: writeback to Rn */
10233ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         UInt bL,      /* 1: load, 0: store */
10234ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         UInt regList )
10235ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
10236ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int i, r, m, nRegs;
10237b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   IRTemp jk = Ijk_Boring;
10238ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10239ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Get hold of the old Rn value.  We might need to write its value
10240ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      to memory during a store, and if it's also the writeback
10241ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      register then we need to get its value now.  We can't treat it
10242ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      exactly like the other registers we're going to transfer,
10243ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      because for xxMDA and xxMDB writeback forms, the generated IR
10244ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      updates Rn in the guest state before any transfers take place.
10245ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      We have to do this as per comments below, in order that if Rn is
10246ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      the stack pointer then it always has a value is below or equal
10247ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      to any of the transfer addresses.  Ick. */
10248ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp oldRnT = newTemp(Ity_I32);
10249ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign(oldRnT, arm ? getIRegA(rN) : getIRegT(rN));
10250ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10251ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp anchorT = newTemp(Ity_I32);
10252ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* The old (Addison-Wesley) ARM ARM seems to say that LDMxx/STMxx
10253ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ignore the bottom two bits of the address.  However, Cortex-A8
10254ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      doesn't seem to care.  Hence: */
10255ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* No .. don't force alignment .. */
10256ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* assign(anchorT, binop(Iop_And32, mkexpr(oldRnT), mkU32(~3U))); */
10257ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Instead, use the potentially misaligned address directly. */
10258ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign(anchorT, mkexpr(oldRnT));
10259ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10260ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IROp opADDorSUB = bINC ? Iop_Add32 : Iop_Sub32;
10261ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // bINC == 1:  xxMIA, xxMIB
10262ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // bINC == 0:  xxMDA, xxMDB
10263ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10264ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // For xxMDA and xxMDB, update Rn first if necessary.  We have
10265ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // to do this first so that, for the common idiom of the transfers
10266ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // faulting because we're pushing stuff onto a stack and the stack
10267ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // is growing down onto allocate-on-fault pages (as Valgrind simulates),
10268ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // we need to have the SP up-to-date "covering" (pointing below) the
10269ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // transfer area.  For the same reason, if we are doing xxMIA or xxMIB,
10270ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // do the transfer first, and then update rN afterwards.
10271ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   nRegs = 0;
10272ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (i = 0; i < 16; i++) {
10273ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     if ((regList & (1 << i)) != 0)
10274ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         nRegs++;
10275ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10276ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (bW == 1 && !bINC) {
10277ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRExpr* e = binop(opADDorSUB, mkexpr(oldRnT), mkU32(4*nRegs));
10278ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (arm)
10279ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIRegA( rN, e, IRTemp_INVALID, Ijk_Boring );
10280ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      else
10281ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIRegT( rN, e, IRTemp_INVALID );
10282ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10283ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10284ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Make up a list of the registers to transfer, and their offsets
10285ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // in memory relative to the anchor.  If the base reg (Rn) is part
10286ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // of the transfer, then do it last for a load and first for a store.
10287ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt xReg[16], xOff[16];
10288ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int  nX = 0;
10289ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   m = 0;
10290ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (i = 0; i < 16; i++) {
10291ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      r = bINC ? i : (15-i);
10292ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (0 == (regList & (1<<r)))
10293ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         continue;
10294ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (bBEFORE)
10295ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         m++;
10296ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* paranoia: check we aren't transferring the writeback
10297ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         register during a load. Should be assured by decode-point
10298ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         check above. */
10299ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (bW == 1 && bL == 1)
10300ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vassert(r != rN);
10301ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10302ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      xOff[nX] = 4 * m;
10303ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      xReg[nX] = r;
10304ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      nX++;
10305ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10306ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!bBEFORE)
10307ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         m++;
10308ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10309ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(m == nRegs);
10310ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(nX == nRegs);
10311ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(nX <= 16);
10312ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10313ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (bW == 0 && (regList & (1<<rN)) != 0) {
10314ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Non-writeback, and basereg is to be transferred.  Do its
10315ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         transfer last for a load and first for a store.  Requires
10316ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         reordering xOff/xReg. */
10317ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (0) {
10318ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vex_printf("\nREG_LIST_PRE: (rN=%d)\n", rN);
10319ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         for (i = 0; i < nX; i++)
10320ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            vex_printf("reg %d   off %d\n", xReg[i], xOff[i]);
10321ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vex_printf("\n");
10322ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
10323ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10324ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(nX > 0);
10325ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      for (i = 0; i < nX; i++) {
10326ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (xReg[i] == rN)
10327ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             break;
10328ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
10329ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(i < nX); /* else we didn't find it! */
10330ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt tReg = xReg[i];
10331ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt tOff = xOff[i];
10332ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (bL == 1) {
10333ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* load; make this transfer happen last */
10334ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (i < nX-1) {
10335ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            for (m = i+1; m < nX; m++) {
10336ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               xReg[m-1] = xReg[m];
10337ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               xOff[m-1] = xOff[m];
10338ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
10339ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            vassert(m == nX);
10340ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            xReg[m-1] = tReg;
10341ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            xOff[m-1] = tOff;
10342ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
10343ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
10344ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* store; make this transfer happen first */
10345ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (i > 0) {
10346ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            for (m = i-1; m >= 0; m--) {
10347ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               xReg[m+1] = xReg[m];
10348ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               xOff[m+1] = xOff[m];
10349ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
10350ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            vassert(m == -1);
10351ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            xReg[0] = tReg;
10352ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            xOff[0] = tOff;
10353ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
10354ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
10355ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10356ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (0) {
10357ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vex_printf("REG_LIST_POST:\n");
10358ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         for (i = 0; i < nX; i++)
10359ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            vex_printf("reg %d   off %d\n", xReg[i], xOff[i]);
10360ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vex_printf("\n");
10361ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
10362ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10363ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10364b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   /* According to the Cortex A8 TRM Sec. 5.2.1, LDM(1) with r13 as the base
10365b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov       register and PC in the register list is a return for purposes of branch
10366b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov       prediction.
10367b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      The ARM ARM Sec. C9.10.1 further specifies that writeback must be enabled
10368b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov       to be counted in event 0x0E (Procedure return).*/
10369b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   if (rN == 13 && bL == 1 && bINC && !bBEFORE && bW == 1) {
10370b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      jk = Ijk_Ret;
10371b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   }
10372b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
10373ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Actually generate the transfers */
10374ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (i = 0; i < nX; i++) {
10375ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      r = xReg[i];
10376ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (bL == 1) {
10377ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRExpr* e = loadLE(Ity_I32,
10378ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            binop(opADDorSUB, mkexpr(anchorT),
10379ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  mkU32(xOff[i])));
10380ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (arm) {
10381b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            putIRegA( r, e, IRTemp_INVALID, jk );
10382ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
10383ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            // no: putIRegT( r, e, IRTemp_INVALID );
10384ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            // putIRegT refuses to write to R15.  But that might happen.
10385ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            // Since this is uncond, and we need to be able to
10386ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            // write the PC, just use the low level put:
10387ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            llPutIReg( r, e );
10388ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
10389ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
10390ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* if we're storing Rn, make sure we use the correct
10391ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            value, as per extensive comments above */
10392ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         storeLE( binop(opADDorSUB, mkexpr(anchorT), mkU32(xOff[i])),
10393ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  r == rN ? mkexpr(oldRnT)
10394ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          : (arm ? getIRegA(r) : getIRegT(r) ) );
10395ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
10396ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10397ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10398ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // If we are doing xxMIA or xxMIB,
10399ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // do the transfer first, and then update rN afterwards.
10400ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (bW == 1 && bINC) {
10401ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRExpr* e = binop(opADDorSUB, mkexpr(oldRnT), mkU32(4*nRegs));
10402ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (arm)
10403ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIRegA( rN, e, IRTemp_INVALID, Ijk_Boring );
10404ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      else
10405ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIRegT( rN, e, IRTemp_INVALID );
10406ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10407ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
10408ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10409ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10410ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
10411ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- VFP (CP 10 and 11) instructions                      ---*/
10412ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
10413ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10414ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Both ARM and Thumb */
10415ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10416ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Translate a CP10 or CP11 instruction.  If successful, returns
10417ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   True and *dres may or may not be updated.  If failure, returns
10418ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   False and doesn't change *dres nor create any IR.
10419ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10420ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   The ARM and Thumb encodings are identical for the low 28 bits of
10421ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   the insn (yay!) and that's what the caller must supply, iow, imm28
10422ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   has the top 4 bits masked out.  Caller is responsible for
10423ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   determining whether the masked-out bits are valid for a CP10/11
10424ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   insn.  The rules for the top 4 bits are:
10425ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10426ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     ARM: 0000 to 1110 allowed, and this is the gating condition.
10427ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     1111 (NV) is not allowed.
10428ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10429ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     Thumb: must be 1110.  The gating condition is taken from
10430ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     ITSTATE in the normal way.
10431ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10432ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Conditionalisation:
10433ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10434ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Caller must supply an IRTemp 'condT' holding the gating condition,
10435ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   or IRTemp_INVALID indicating the insn is always executed.
10436ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10437ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Caller must also supply an ARMCondcode 'cond'.  This is only used
10438ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for debug printing, no other purpose.  For ARM, this is simply the
10439ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   top 4 bits of the original instruction.  For Thumb, the condition
10440ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   is not (really) known until run time, and so ARMCondAL should be
10441ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   passed, only so that printing of these instructions does not show
10442ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   any condition.
10443ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10444ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Finally, the caller must indicate whether this occurs in ARM or
10445ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Thumb code.
10446ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
10447ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Bool decode_CP10_CP11_instruction (
10448ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /*MOD*/DisResult* dres,
10449ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               UInt              insn28,
10450ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRTemp            condT,
10451ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               ARMCondcode       conq,
10452ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               Bool              isT
10453ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            )
10454ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
10455ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  define INSN(_bMax,_bMin)  SLICE_UInt(insn28, (_bMax), (_bMin))
10456ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10457ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(INSN(31,28) == BITS4(0,0,0,0)); // caller's obligation
10458ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10459ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (isT) {
10460ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(conq == ARMCondAL);
10461ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
10462ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(conq >= ARMCondEQ && conq <= ARMCondAL);
10463ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10464ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10465ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ----------------------------------------------------------- */
10466ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* -- VFP instructions -- double precision (mostly)         -- */
10467ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ----------------------------------------------------------- */
10468ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10469ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* --------------------- fldmx, fstmx --------------------- */
10470ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /*
10471ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 31   27   23   19 15 11   7   0
10472ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                         P U WL
10473ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      C4-100, C5-26  1  FSTMX    cond 1100 1000 Rn Dd 1011 offset
10474ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      C4-100, C5-28  2  FSTMIAX  cond 1100 1010 Rn Dd 1011 offset
10475ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      C4-100, C5-30  3  FSTMDBX  cond 1101 0010 Rn Dd 1011 offset
10476ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10477ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      C4-42, C5-26   1  FLDMX    cond 1100 1001 Rn Dd 1011 offset
10478ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      C4-42, C5-28   2  FLDMIAX  cond 1100 1011 Rn Dd 1011 offset
10479ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      C4-42, C5-30   3  FLDMDBX  cond 1101 0011 Rn Dd 1011 offset
10480ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10481ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Regs transferred: Dd .. D(d + (offset-3)/2)
10482ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      offset must be odd, must not imply a reg > 15
10483ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IA/DB: Rn is changed by (4 + 8 x # regs transferred)
10484ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10485ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case coding:
10486ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         1  at-Rn   (access at Rn)
10487ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         2  ia-Rn   (access at Rn, then Rn += 4+8n)
10488ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         3  db-Rn   (Rn -= 4+8n,   then access at Rn)
10489ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   */
10490ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (BITS8(1,1,0,0,0,0,0,0) == (INSN(27,20) & BITS8(1,1,1,0,0,0,0,0))
10491ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && INSN(11,8) == BITS4(1,0,1,1)) {
10492ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt bP      = (insn28 >> 24) & 1;
10493ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt bU      = (insn28 >> 23) & 1;
10494ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt bW      = (insn28 >> 21) & 1;
10495ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt bL      = (insn28 >> 20) & 1;
10496ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt offset  = (insn28 >> 0) & 0xFF;
10497ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rN      = INSN(19,16);
10498ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt dD      = (INSN(22,22) << 4) | INSN(15,12);
10499ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt nRegs   = (offset - 1) / 2;
10500ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt summary = 0;
10501ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Int  i;
10502ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10503ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /**/ if (bP == 0 && bU == 1 && bW == 0) {
10504ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         summary = 1;
10505ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
10506ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      else if (bP == 0 && bU == 1 && bW == 1) {
10507ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         summary = 2;
10508ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
10509ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      else if (bP == 1 && bU == 0 && bW == 1) {
10510ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         summary = 3;
10511ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
10512ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      else goto after_vfp_fldmx_fstmx;
10513ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10514ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* no writebacks to r15 allowed.  No use of r15 in thumb mode. */
10515ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (rN == 15 && (summary == 2 || summary == 3 || isT))
10516ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto after_vfp_fldmx_fstmx;
10517ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10518ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* offset must be odd, and specify at least one register */
10519ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (0 == (offset & 1) || offset < 3)
10520ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto after_vfp_fldmx_fstmx;
10521ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10522ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* can't transfer regs after D15 */
10523ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (dD + nRegs - 1 >= 32)
10524ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto after_vfp_fldmx_fstmx;
10525ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10526ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Now, we can't do a conditional load or store, since that very
10527ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         likely will generate an exception.  So we have to take a side
10528ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         exit at this point if the condition is false. */
10529ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (condT != IRTemp_INVALID) {
10530ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (isT)
10531ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            mk_skip_over_T32_if_cond_is_false( condT );
10532ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         else
10533ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            mk_skip_over_A32_if_cond_is_false( condT );
10534ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         condT = IRTemp_INVALID;
10535ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
10536ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Ok, now we're unconditional.  Do the load or store. */
10537ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10538ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* get the old Rn value */
10539ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp rnT = newTemp(Ity_I32);
10540ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(rnT, align4if(isT ? getIRegT(rN) : getIRegA(rN),
10541ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           rN == 15));
10542ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10543ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* make a new value for Rn, post-insn */
10544ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp rnTnew = IRTemp_INVALID;
10545ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (summary == 2 || summary == 3) {
10546ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         rnTnew = newTemp(Ity_I32);
10547ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(rnTnew, binop(summary == 2 ? Iop_Add32 : Iop_Sub32,
10548ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              mkexpr(rnT),
10549ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              mkU32(4 + 8 * nRegs)));
10550ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
10551ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10552ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* decide on the base transfer address */
10553ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp taT = newTemp(Ity_I32);
10554ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(taT,  summary == 3 ? mkexpr(rnTnew) : mkexpr(rnT));
10555ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10556ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* update Rn if necessary -- in case 3, we're moving it down, so
10557ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         update before any memory reference, in order to keep Memcheck
10558ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         and V's stack-extending logic (on linux) happy */
10559ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (summary == 3) {
10560ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (isT)
10561ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putIRegT(rN, mkexpr(rnTnew), IRTemp_INVALID);
10562ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         else
10563ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putIRegA(rN, mkexpr(rnTnew), IRTemp_INVALID, Ijk_Boring);
10564ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
10565ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10566ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* generate the transfers */
10567ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      for (i = 0; i < nRegs; i++) {
10568ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRExpr* addr = binop(Iop_Add32, mkexpr(taT), mkU32(8*i));
10569ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (bL) {
10570ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putDReg(dD + i, loadLE(Ity_F64, addr), IRTemp_INVALID);
10571ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
10572ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            storeLE(addr, getDReg(dD + i));
10573ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
10574ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
10575ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10576ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* update Rn if necessary -- in case 2, we're moving it up, so
10577ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         update after any memory reference, in order to keep Memcheck
10578ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         and V's stack-extending logic (on linux) happy */
10579ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (summary == 2) {
10580ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (isT)
10581ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putIRegT(rN, mkexpr(rnTnew), IRTemp_INVALID);
10582ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         else
10583ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putIRegA(rN, mkexpr(rnTnew), IRTemp_INVALID, Ijk_Boring);
10584ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
10585ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10586ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      HChar* nm = bL==1 ? "ld" : "st";
10587ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      switch (summary) {
10588ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 1:  DIP("f%smx%s r%u, {d%u-d%u}\n",
10589ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      nm, nCC(conq), rN, dD, dD + nRegs - 1);
10590ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  break;
10591ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 2:  DIP("f%smiax%s r%u!, {d%u-d%u}\n",
10592ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      nm, nCC(conq), rN, dD, dD + nRegs - 1);
10593ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  break;
10594ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 3:  DIP("f%smdbx%s r%u!, {d%u-d%u}\n",
10595ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      nm, nCC(conq), rN, dD, dD + nRegs - 1);
10596ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  break;
10597ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         default: vassert(0);
10598ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
10599ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10600ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success_vfp;
10601ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* FIXME alignment constraints? */
10602ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10603ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10604ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  after_vfp_fldmx_fstmx:
10605ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10606ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* --------------------- fldmd, fstmd --------------------- */
10607ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /*
10608ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 31   27   23   19 15 11   7   0
10609ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                         P U WL
10610ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      C4-96, C5-26   1  FSTMD    cond 1100 1000 Rn Dd 1011 offset
10611ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      C4-96, C5-28   2  FSTMDIA  cond 1100 1010 Rn Dd 1011 offset
10612ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      C4-96, C5-30   3  FSTMDDB  cond 1101 0010 Rn Dd 1011 offset
10613ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10614ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      C4-38, C5-26   1  FLDMD    cond 1100 1001 Rn Dd 1011 offset
10615ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      C4-38, C5-28   2  FLDMIAD  cond 1100 1011 Rn Dd 1011 offset
10616ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      C4-38, C5-30   3  FLDMDBD  cond 1101 0011 Rn Dd 1011 offset
10617ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10618ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Regs transferred: Dd .. D(d + (offset-2)/2)
10619ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      offset must be even, must not imply a reg > 15
10620ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IA/DB: Rn is changed by (8 x # regs transferred)
10621ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10622ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case coding:
10623ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         1  at-Rn   (access at Rn)
10624ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         2  ia-Rn   (access at Rn, then Rn += 8n)
10625ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         3  db-Rn   (Rn -= 8n,     then access at Rn)
10626ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   */
10627ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (BITS8(1,1,0,0,0,0,0,0) == (INSN(27,20) & BITS8(1,1,1,0,0,0,0,0))
10628ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && INSN(11,8) == BITS4(1,0,1,1)) {
10629ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt bP      = (insn28 >> 24) & 1;
10630ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt bU      = (insn28 >> 23) & 1;
10631ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt bW      = (insn28 >> 21) & 1;
10632ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt bL      = (insn28 >> 20) & 1;
10633ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt offset  = (insn28 >> 0) & 0xFF;
10634ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rN      = INSN(19,16);
10635ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt dD      = (INSN(22,22) << 4) | INSN(15,12);
10636ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt nRegs   = offset / 2;
10637ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt summary = 0;
10638ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Int  i;
10639ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10640ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /**/ if (bP == 0 && bU == 1 && bW == 0) {
10641ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         summary = 1;
10642ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
10643ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      else if (bP == 0 && bU == 1 && bW == 1) {
10644ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         summary = 2;
10645ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
10646ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      else if (bP == 1 && bU == 0 && bW == 1) {
10647ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         summary = 3;
10648ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
10649ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      else goto after_vfp_fldmd_fstmd;
10650ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10651ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* no writebacks to r15 allowed.  No use of r15 in thumb mode. */
10652ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (rN == 15 && (summary == 2 || summary == 3 || isT))
10653ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto after_vfp_fldmd_fstmd;
10654ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10655ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* offset must be even, and specify at least one register */
10656ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (1 == (offset & 1) || offset < 2)
10657ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto after_vfp_fldmd_fstmd;
10658ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10659ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* can't transfer regs after D15 */
10660ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (dD + nRegs - 1 >= 32)
10661ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto after_vfp_fldmd_fstmd;
10662ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10663ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Now, we can't do a conditional load or store, since that very
10664ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         likely will generate an exception.  So we have to take a side
10665ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         exit at this point if the condition is false. */
10666ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (condT != IRTemp_INVALID) {
10667ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (isT)
10668ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            mk_skip_over_T32_if_cond_is_false( condT );
10669ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         else
10670ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            mk_skip_over_A32_if_cond_is_false( condT );
10671ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         condT = IRTemp_INVALID;
10672ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
10673ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Ok, now we're unconditional.  Do the load or store. */
10674ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10675ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* get the old Rn value */
10676ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp rnT = newTemp(Ity_I32);
10677ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(rnT, align4if(isT ? getIRegT(rN) : getIRegA(rN),
10678ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           rN == 15));
10679ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10680ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* make a new value for Rn, post-insn */
10681ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp rnTnew = IRTemp_INVALID;
10682ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (summary == 2 || summary == 3) {
10683ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         rnTnew = newTemp(Ity_I32);
10684ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(rnTnew, binop(summary == 2 ? Iop_Add32 : Iop_Sub32,
10685ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              mkexpr(rnT),
10686ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              mkU32(8 * nRegs)));
10687ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
10688ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10689ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* decide on the base transfer address */
10690ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp taT = newTemp(Ity_I32);
10691ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(taT, summary == 3 ? mkexpr(rnTnew) : mkexpr(rnT));
10692ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10693ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* update Rn if necessary -- in case 3, we're moving it down, so
10694ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         update before any memory reference, in order to keep Memcheck
10695ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         and V's stack-extending logic (on linux) happy */
10696ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (summary == 3) {
10697ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (isT)
10698ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putIRegT(rN, mkexpr(rnTnew), IRTemp_INVALID);
10699ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         else
10700ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putIRegA(rN, mkexpr(rnTnew), IRTemp_INVALID, Ijk_Boring);
10701ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
10702ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10703ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* generate the transfers */
10704ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      for (i = 0; i < nRegs; i++) {
10705ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRExpr* addr = binop(Iop_Add32, mkexpr(taT), mkU32(8*i));
10706ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (bL) {
10707ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putDReg(dD + i, loadLE(Ity_F64, addr), IRTemp_INVALID);
10708ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
10709ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            storeLE(addr, getDReg(dD + i));
10710ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
10711ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
10712ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10713ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* update Rn if necessary -- in case 2, we're moving it up, so
10714ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         update after any memory reference, in order to keep Memcheck
10715ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         and V's stack-extending logic (on linux) happy */
10716ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (summary == 2) {
10717ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (isT)
10718ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putIRegT(rN, mkexpr(rnTnew), IRTemp_INVALID);
10719ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         else
10720ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putIRegA(rN, mkexpr(rnTnew), IRTemp_INVALID, Ijk_Boring);
10721ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
10722ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10723ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      HChar* nm = bL==1 ? "ld" : "st";
10724ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      switch (summary) {
10725ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 1:  DIP("f%smd%s r%u, {d%u-d%u}\n",
10726ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      nm, nCC(conq), rN, dD, dD + nRegs - 1);
10727ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  break;
10728ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 2:  DIP("f%smiad%s r%u!, {d%u-d%u}\n",
10729ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      nm, nCC(conq), rN, dD, dD + nRegs - 1);
10730ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  break;
10731ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 3:  DIP("f%smdbd%s r%u!, {d%u-d%u}\n",
10732ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      nm, nCC(conq), rN, dD, dD + nRegs - 1);
10733ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  break;
10734ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         default: vassert(0);
10735ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
10736ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10737ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success_vfp;
10738ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* FIXME alignment constraints? */
10739ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10740ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10741ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  after_vfp_fldmd_fstmd:
10742ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10743ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ------------------- fmrx, fmxr ------------------- */
10744ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (BITS8(1,1,1,0,1,1,1,1) == INSN(27,20)
10745ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && BITS4(1,0,1,0) == INSN(11,8)
10746ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && BITS8(0,0,0,1,0,0,0,0) == (insn28 & 0xFF)) {
10747ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rD  = INSN(15,12);
10748ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt reg = INSN(19,16);
10749ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (reg == BITS4(0,0,0,1)) {
10750ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (rD == 15) {
10751ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            IRTemp nzcvT = newTemp(Ity_I32);
10752ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* When rD is 15, we are copying the top 4 bits of FPSCR
10753ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               into CPSR.  That is, set the flags thunk to COPY and
10754ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               install FPSCR[31:28] as the value to copy. */
10755ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(nzcvT, binop(Iop_And32,
10756ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                IRExpr_Get(OFFB_FPSCR, Ity_I32),
10757ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                mkU32(0xF0000000)));
10758ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            setFlags_D1(ARMG_CC_OP_COPY, nzcvT, condT);
10759ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("fmstat%s\n", nCC(conq));
10760ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
10761ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* Otherwise, merely transfer FPSCR to r0 .. r14. */
10762ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            IRExpr* e = IRExpr_Get(OFFB_FPSCR, Ity_I32);
10763ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (isT)
10764ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               putIRegT(rD, e, condT);
10765ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            else
10766ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               putIRegA(rD, e, condT, Ijk_Boring);
10767ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("fmrx%s r%u, fpscr\n", nCC(conq), rD);
10768ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
10769ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success_vfp;
10770ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
10771ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* fall through */
10772ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10773ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10774ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (BITS8(1,1,1,0,1,1,1,0) == INSN(27,20)
10775ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && BITS4(1,0,1,0) == INSN(11,8)
10776ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && BITS8(0,0,0,1,0,0,0,0) == (insn28 & 0xFF)) {
10777ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rD  = INSN(15,12);
10778ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt reg = INSN(19,16);
10779ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (reg == BITS4(0,0,0,1)) {
10780ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putMiscReg32(OFFB_FPSCR,
10781ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      isT ? getIRegT(rD) : getIRegA(rD), condT);
10782ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("fmxr%s fpscr, r%u\n", nCC(conq), rD);
10783ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success_vfp;
10784ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
10785ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* fall through */
10786ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10787ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10788ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* --------------------- vmov --------------------- */
10789ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // VMOV dM, rD, rN
10790ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (0x0C400B10 == (insn28 & 0x0FF00FD0)) {
10791ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt dM = INSN(3,0) | (INSN(5,5) << 4);
10792ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rD = INSN(15,12); /* lo32 */
10793ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rN = INSN(19,16); /* hi32 */
10794ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (rD == 15 || rN == 15 || (isT && (rD == 13 || rN == 13))) {
10795ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* fall through */
10796ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
10797ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putDReg(dM,
10798ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 unop(Iop_ReinterpI64asF64,
10799ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      binop(Iop_32HLto64,
10800ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            isT ? getIRegT(rN) : getIRegA(rN),
10801ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            isT ? getIRegT(rD) : getIRegA(rD))),
10802ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 condT);
10803ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("vmov%s d%u, r%u, r%u\n", nCC(conq), dM, rD, rN);
10804ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success_vfp;
10805ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
10806ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* fall through */
10807ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10808ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10809ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // VMOV rD, rN, dM
10810ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (0x0C500B10 == (insn28 & 0x0FF00FD0)) {
10811ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt dM = INSN(3,0) | (INSN(5,5) << 4);
10812ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rD = INSN(15,12); /* lo32 */
10813ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rN = INSN(19,16); /* hi32 */
10814ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (rD == 15 || rN == 15 || (isT && (rD == 13 || rN == 13))
10815ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          || rD == rN) {
10816ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* fall through */
10817ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
10818ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp i64 = newTemp(Ity_I64);
10819ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(i64, unop(Iop_ReinterpF64asI64, getDReg(dM)));
10820ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRExpr* hi32 = unop(Iop_64HIto32, mkexpr(i64));
10821ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRExpr* lo32 = unop(Iop_64to32,   mkexpr(i64));
10822ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (isT) {
10823ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putIRegT(rN, hi32, condT);
10824ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putIRegT(rD, lo32, condT);
10825ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
10826ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putIRegA(rN, hi32, condT, Ijk_Boring);
10827ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putIRegA(rD, lo32, condT, Ijk_Boring);
10828ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
10829ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("vmov%s r%u, r%u, d%u\n", nCC(conq), rD, rN, dM);
10830ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success_vfp;
10831ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
10832ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* fall through */
10833ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10834ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10835ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // VMOV sD, sD+1, rN, rM
10836ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (0x0C400A10 == (insn28 & 0x0FF00FD0)) {
10837ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt sD = (INSN(3,0) << 1) | INSN(5,5);
10838ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rN = INSN(15,12);
10839ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rM = INSN(19,16);
10840ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (rM == 15 || rN == 15 || (isT && (rM == 13 || rN == 13))
10841ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          || sD == 31) {
10842ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* fall through */
10843ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
10844ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putFReg(sD,
10845ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 unop(Iop_ReinterpI32asF32, isT ? getIRegT(rN) : getIRegA(rN)),
10846ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 condT);
10847ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putFReg(sD+1,
10848ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 unop(Iop_ReinterpI32asF32, isT ? getIRegT(rM) : getIRegA(rM)),
10849ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 condT);
10850ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("vmov%s, s%u, s%u, r%u, r%u\n",
10851ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              nCC(conq), sD, sD + 1, rN, rM);
10852ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success_vfp;
10853ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
10854ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10855ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10856ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // VMOV rN, rM, sD, sD+1
10857ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (0x0C500A10 == (insn28 & 0x0FF00FD0)) {
10858ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt sD = (INSN(3,0) << 1) | INSN(5,5);
10859ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rN = INSN(15,12);
10860ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rM = INSN(19,16);
10861ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (rM == 15 || rN == 15 || (isT && (rM == 13 || rN == 13))
10862ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          || sD == 31 || rN == rM) {
10863ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* fall through */
10864ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
10865ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRExpr* res0 = unop(Iop_ReinterpF32asI32, getFReg(sD));
10866ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRExpr* res1 = unop(Iop_ReinterpF32asI32, getFReg(sD+1));
10867ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (isT) {
10868ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putIRegT(rN, res0, condT);
10869ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putIRegT(rM, res1, condT);
10870ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
10871ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putIRegA(rN, res0, condT, Ijk_Boring);
10872ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putIRegA(rM, res1, condT, Ijk_Boring);
10873ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
10874ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("vmov%s, r%u, r%u, s%u, s%u\n",
10875ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             nCC(conq), rN, rM, sD, sD + 1);
10876ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success_vfp;
10877ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
10878ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10879ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10880ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // VMOV rD[x], rT  (ARM core register to scalar)
10881ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (0x0E000B10 == (insn28 & 0x0F900F1F)) {
10882ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rD  = (INSN(7,7) << 4) | INSN(19,16);
10883ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rT  = INSN(15,12);
10884ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt opc = (INSN(22,21) << 2) | INSN(6,5);
10885ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt index;
10886ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (rT == 15 || (isT && rT == 13)) {
10887ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* fall through */
10888ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
10889ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if ((opc & BITS4(1,0,0,0)) == BITS4(1,0,0,0)) {
10890ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            index = opc & 7;
10891ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putDRegI64(rD, triop(Iop_SetElem8x8,
10892ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 getDRegI64(rD),
10893ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 mkU8(index),
10894ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 unop(Iop_32to8,
10895ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                      isT ? getIRegT(rT) : getIRegA(rT))),
10896ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           condT);
10897ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("vmov%s.8 d%u[%u], r%u\n", nCC(conq), rD, index, rT);
10898ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto decode_success_vfp;
10899ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
10900ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         else if ((opc & BITS4(1,0,0,1)) == BITS4(0,0,0,1)) {
10901ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            index = (opc >> 1) & 3;
10902ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putDRegI64(rD, triop(Iop_SetElem16x4,
10903ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 getDRegI64(rD),
10904ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 mkU8(index),
10905ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 unop(Iop_32to16,
10906ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                      isT ? getIRegT(rT) : getIRegA(rT))),
10907ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           condT);
10908ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("vmov%s.16 d%u[%u], r%u\n", nCC(conq), rD, index, rT);
10909ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto decode_success_vfp;
10910ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
10911ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         else if ((opc & BITS4(1,0,1,1)) == BITS4(0,0,0,0)) {
10912ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            index = (opc >> 2) & 1;
10913ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putDRegI64(rD, triop(Iop_SetElem32x2,
10914ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 getDRegI64(rD),
10915ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 mkU8(index),
10916ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 isT ? getIRegT(rT) : getIRegA(rT)),
10917ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           condT);
10918ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("vmov%s.32 d%u[%u], r%u\n", nCC(conq), rD, index, rT);
10919ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto decode_success_vfp;
10920ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
10921ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* fall through */
10922ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
10923ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
10924ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10925ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10926ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // VMOV (scalar to ARM core register)
10927ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // VMOV rT, rD[x]
10928ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (0x0E100B10 == (insn28 & 0x0F100F1F)) {
10929ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rN  = (INSN(7,7) << 4) | INSN(19,16);
10930ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rT  = INSN(15,12);
10931ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt U   = INSN(23,23);
10932ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt opc = (INSN(22,21) << 2) | INSN(6,5);
10933ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt index;
10934ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (rT == 15 || (isT && rT == 13)) {
10935ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* fall through */
10936ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
10937ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if ((opc & BITS4(1,0,0,0)) == BITS4(1,0,0,0)) {
10938ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            index = opc & 7;
10939ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            IRExpr* e = unop(U ? Iop_8Uto32 : Iop_8Sto32,
10940ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             binop(Iop_GetElem8x8,
10941ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   getDRegI64(rN),
10942ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   mkU8(index)));
10943ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (isT)
10944ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               putIRegT(rT, e, condT);
10945ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            else
10946ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               putIRegA(rT, e, condT, Ijk_Boring);
10947ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("vmov%s.%c8 r%u, d%u[%u]\n", nCC(conq), U ? 'u' : 's',
10948ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  rT, rN, index);
10949ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto decode_success_vfp;
10950ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
10951ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         else if ((opc & BITS4(1,0,0,1)) == BITS4(0,0,0,1)) {
10952ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            index = (opc >> 1) & 3;
10953ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            IRExpr* e = unop(U ? Iop_16Uto32 : Iop_16Sto32,
10954ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             binop(Iop_GetElem16x4,
10955ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   getDRegI64(rN),
10956ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   mkU8(index)));
10957ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (isT)
10958ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               putIRegT(rT, e, condT);
10959ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            else
10960ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               putIRegA(rT, e, condT, Ijk_Boring);
10961ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("vmov%s.%c16 r%u, d%u[%u]\n", nCC(conq), U ? 'u' : 's',
10962ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  rT, rN, index);
10963ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto decode_success_vfp;
10964ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
10965ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         else if ((opc & BITS4(1,0,1,1)) == BITS4(0,0,0,0) && U == 0) {
10966ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            index = (opc >> 2) & 1;
10967ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            IRExpr* e = binop(Iop_GetElem32x2, getDRegI64(rN), mkU8(index));
10968ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (isT)
10969ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               putIRegT(rT, e, condT);
10970ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            else
10971ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               putIRegA(rT, e, condT, Ijk_Boring);
10972ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("vmov%s.32 r%u, d%u[%u]\n", nCC(conq), rT, rN, index);
10973ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto decode_success_vfp;
10974ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
10975ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* fall through */
10976ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
10977ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
10978ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10979ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10980ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // VMOV.F32 sD, #imm
10981ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // FCONSTS sD, #imm
10982ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (BITS8(1,1,1,0,1,0,1,1) == (INSN(27,20) & BITS8(1,1,1,1,1,0,1,1))
10983ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && BITS4(0,0,0,0) == INSN(7,4) && INSN(11,8) == BITS4(1,0,1,0)) {
10984ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rD   = (INSN(15,12) << 1) | INSN(22,22);
10985ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt imm8 = (INSN(19,16) << 4) | INSN(3,0);
10986ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt b    = (imm8 >> 6) & 1;
10987ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt imm;
10988ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      imm = (BITS8((imm8 >> 7) & 1,(~b) & 1,b,b,b,b,b,(imm8 >> 5) & 1) << 8)
10989ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             | ((imm8 & 0x1f) << 3);
10990ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      imm <<= 16;
10991ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putFReg(rD, unop(Iop_ReinterpI32asF32, mkU32(imm)), condT);
10992ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("fconsts%s s%u #%u", nCC(conq), rD, imm8);
10993ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success_vfp;
10994ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10995ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10996ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // VMOV.F64 dD, #imm
10997ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // FCONSTD dD, #imm
10998ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (BITS8(1,1,1,0,1,0,1,1) == (INSN(27,20) & BITS8(1,1,1,1,1,0,1,1))
10999ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && BITS4(0,0,0,0) == INSN(7,4) && INSN(11,8) == BITS4(1,0,1,1)) {
11000ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rD   = INSN(15,12) | (INSN(22,22) << 4);
11001ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt imm8 = (INSN(19,16) << 4) | INSN(3,0);
11002ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt b    = (imm8 >> 6) & 1;
11003ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ULong imm;
11004ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      imm = (BITS8((imm8 >> 7) & 1,(~b) & 1,b,b,b,b,b,b) << 8)
11005ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             | BITS8(b,b,0,0,0,0,0,0) | (imm8 & 0x3f);
11006ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      imm <<= 48;
11007ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putDReg(rD, unop(Iop_ReinterpI64asF64, mkU64(imm)), condT);
11008ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("fconstd%s d%u #%u", nCC(conq), rD, imm8);
11009ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success_vfp;
11010ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11011ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11012ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ---------------------- vdup ------------------------- */
11013ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // VDUP dD, rT
11014ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // VDUP qD, rT
11015ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (BITS8(1,1,1,0,1,0,0,0) == (INSN(27,20) & BITS8(1,1,1,1,1,0,0,1))
11016ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && BITS4(1,0,1,1) == INSN(11,8) && INSN(6,6) == 0 && INSN(4,4) == 1) {
11017ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rD   = (INSN(7,7) << 4) | INSN(19,16);
11018ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rT   = INSN(15,12);
11019ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt Q    = INSN(21,21);
11020ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt size = (INSN(22,22) << 1) | INSN(5,5);
11021f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      if (rT == 15 || (isT && rT == 13) || size == 3 || (Q && (rD & 1))) {
11022ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* fall through */
11023ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
11024ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRExpr* e = isT ? getIRegT(rT) : getIRegA(rT);
11025ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (Q) {
11026ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            rD >>= 1;
11027ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            switch (size) {
11028ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               case 0:
11029ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  putQReg(rD, unop(Iop_Dup32x4, e), condT);
11030ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  break;
11031ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               case 1:
11032ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  putQReg(rD, unop(Iop_Dup16x8, unop(Iop_32to16, e)),
11033ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              condT);
11034ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  break;
11035ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               case 2:
11036ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  putQReg(rD, unop(Iop_Dup8x16, unop(Iop_32to8, e)),
11037ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              condT);
11038ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  break;
11039ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               default:
11040ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  vassert(0);
11041ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
11042ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("vdup.%u q%u, r%u\n", 32 / (1<<size), rD, rT);
11043ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
11044ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            switch (size) {
11045ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               case 0:
11046ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  putDRegI64(rD, unop(Iop_Dup32x2, e), condT);
11047ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  break;
11048ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               case 1:
11049ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  putDRegI64(rD, unop(Iop_Dup16x4, unop(Iop_32to16, e)),
11050ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               condT);
11051ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  break;
11052ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               case 2:
11053ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  putDRegI64(rD, unop(Iop_Dup8x8, unop(Iop_32to8, e)),
11054ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               condT);
11055ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  break;
11056ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               default:
11057ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  vassert(0);
11058ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
11059ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("vdup.%u d%u, r%u\n", 32 / (1<<size), rD, rT);
11060ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
11061ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success_vfp;
11062ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
11063ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11064ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11065ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* --------------------- f{ld,st}d --------------------- */
11066ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // FLDD, FSTD
11067ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (BITS8(1,1,0,1,0,0,0,0) == (INSN(27,20) & BITS8(1,1,1,1,0,0,1,0))
11068ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && BITS4(1,0,1,1) == INSN(11,8)) {
11069ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt dD     = INSN(15,12) | (INSN(22,22) << 4);
11070ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rN     = INSN(19,16);
11071ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt offset = (insn28 & 0xFF) << 2;
11072ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt bU     = (insn28 >> 23) & 1; /* 1: +offset  0: -offset */
11073ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt bL     = (insn28 >> 20) & 1; /* 1: load  0: store */
11074ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* make unconditional */
11075ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (condT != IRTemp_INVALID) {
11076ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (isT)
11077ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            mk_skip_over_T32_if_cond_is_false( condT );
11078ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         else
11079ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            mk_skip_over_A32_if_cond_is_false( condT );
11080ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         condT = IRTemp_INVALID;
11081ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
11082ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp ea = newTemp(Ity_I32);
11083ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(ea, binop(bU ? Iop_Add32 : Iop_Sub32,
11084ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       align4if(isT ? getIRegT(rN) : getIRegA(rN),
11085ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                rN == 15),
11086ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       mkU32(offset)));
11087ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (bL) {
11088ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putDReg(dD, loadLE(Ity_F64,mkexpr(ea)), IRTemp_INVALID);
11089ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
11090ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         storeLE(mkexpr(ea), getDReg(dD));
11091ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
11092ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("f%sd%s d%u, [r%u, %c#%u]\n",
11093ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          bL ? "ld" : "st", nCC(conq), dD, rN,
11094ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          bU ? '+' : '-', offset);
11095ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success_vfp;
11096ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11097ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11098ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* --------------------- dp insns (D) --------------------- */
11099ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (BITS8(1,1,1,0,0,0,0,0) == (INSN(27,20) & BITS8(1,1,1,1,0,0,0,0))
11100ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && BITS4(1,0,1,1) == INSN(11,8)
11101ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && BITS4(0,0,0,0) == (INSN(7,4) & BITS4(0,0,0,1))) {
11102ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt    dM  = INSN(3,0)   | (INSN(5,5) << 4);       /* argR */
11103ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt    dD  = INSN(15,12) | (INSN(22,22) << 4);   /* dst/acc */
11104ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt    dN  = INSN(19,16) | (INSN(7,7) << 4);     /* argL */
11105ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt    bP  = (insn28 >> 23) & 1;
11106ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt    bQ  = (insn28 >> 21) & 1;
11107ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt    bR  = (insn28 >> 20) & 1;
11108ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt    bS  = (insn28 >> 6) & 1;
11109ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt    opc = (bP << 3) | (bQ << 2) | (bR << 1) | bS;
11110ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRExpr* rm  = get_FAKE_roundingmode(); /* XXXROUNDINGFIXME */
11111ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      switch (opc) {
11112ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case BITS4(0,0,0,0): /* MAC: d + n * m */
11113ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putDReg(dD, triop(Iop_AddF64, rm,
11114ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              getDReg(dD),
11115ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              triop(Iop_MulF64, rm, getDReg(dN),
11116ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                                    getDReg(dM))),
11117ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        condT);
11118ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("fmacd%s d%u, d%u, d%u\n", nCC(conq), dD, dN, dM);
11119ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto decode_success_vfp;
11120ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case BITS4(0,0,0,1): /* NMAC: d + -(n * m) */
11121ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putDReg(dD, triop(Iop_AddF64, rm,
11122ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              getDReg(dD),
11123ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              unop(Iop_NegF64,
11124ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   triop(Iop_MulF64, rm, getDReg(dN),
11125ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                                         getDReg(dM)))),
11126ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        condT);
11127ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("fnmacd%s d%u, d%u, d%u\n", nCC(conq), dD, dN, dM);
11128ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto decode_success_vfp;
11129ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case BITS4(0,0,1,0): /* MSC: - d + n * m */
11130ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putDReg(dD, triop(Iop_AddF64, rm,
11131ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              unop(Iop_NegF64, getDReg(dD)),
11132ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              triop(Iop_MulF64, rm, getDReg(dN),
11133ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                                    getDReg(dM))),
11134ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        condT);
11135ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("fmscd%s d%u, d%u, d%u\n", nCC(conq), dD, dN, dM);
11136ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto decode_success_vfp;
11137ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case BITS4(0,0,1,1): /* NMSC: - d + -(n * m) */
11138ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putDReg(dD, triop(Iop_AddF64, rm,
11139ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              unop(Iop_NegF64, getDReg(dD)),
11140ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              unop(Iop_NegF64,
11141ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   triop(Iop_MulF64, rm, getDReg(dN),
11142ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                                         getDReg(dM)))),
11143ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        condT);
11144ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("fnmscd%s d%u, d%u, d%u\n", nCC(conq), dD, dN, dM);
11145ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto decode_success_vfp;
11146ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case BITS4(0,1,0,0): /* MUL: n * m */
11147ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putDReg(dD, triop(Iop_MulF64, rm, getDReg(dN), getDReg(dM)),
11148ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        condT);
11149ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("fmuld%s d%u, d%u, d%u\n", nCC(conq), dD, dN, dM);
11150ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto decode_success_vfp;
11151ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case BITS4(0,1,0,1): /* NMUL: - n * m */
11152ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putDReg(dD, unop(Iop_NegF64,
11153ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             triop(Iop_MulF64, rm, getDReg(dN),
11154ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                                   getDReg(dM))),
11155ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    condT);
11156ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("fnmuld%s d%u, d%u, d%u\n", nCC(conq), dD, dN, dM);
11157ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto decode_success_vfp;
11158ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case BITS4(0,1,1,0): /* ADD: n + m */
11159ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putDReg(dD, triop(Iop_AddF64, rm, getDReg(dN), getDReg(dM)),
11160ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        condT);
11161ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("faddd%s d%u, d%u, d%u\n", nCC(conq), dD, dN, dM);
11162ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto decode_success_vfp;
11163ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case BITS4(0,1,1,1): /* SUB: n - m */
11164ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putDReg(dD, triop(Iop_SubF64, rm, getDReg(dN), getDReg(dM)),
11165ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        condT);
11166ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("fsubd%s d%u, d%u, d%u\n", nCC(conq), dD, dN, dM);
11167ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto decode_success_vfp;
11168ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case BITS4(1,0,0,0): /* DIV: n / m */
11169ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putDReg(dD, triop(Iop_DivF64, rm, getDReg(dN), getDReg(dM)),
11170ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        condT);
11171ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("fdivd%s d%u, d%u, d%u\n", nCC(conq), dD, dN, dM);
11172ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto decode_success_vfp;
11173ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         default:
11174ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
11175ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
11176ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11177ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11178ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* --------------------- compares (D) --------------------- */
11179ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /*          31   27   23   19   15 11   7    3
11180ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 28   24   20   16 12    8    4    0
11181ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      FCMPD    cond 1110 1D11 0100 Dd 1011 0100 Dm
11182ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      FCMPED   cond 1110 1D11 0100 Dd 1011 1100 Dm
11183ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      FCMPZD   cond 1110 1D11 0101 Dd 1011 0100 0000
11184ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      FCMPZED  cond 1110 1D11 0101 Dd 1011 1100 0000
11185ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 Z         N
11186ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11187ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Z=0 Compare Dd vs Dm     and set FPSCR 31:28 accordingly
11188ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Z=1 Compare Dd vs zero
11189ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11190ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      N=1 generates Invalid Operation exn if either arg is any kind of NaN
11191ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      N=0 generates Invalid Operation exn if either arg is a signalling NaN
11192ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      (Not that we pay any attention to N here)
11193ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   */
11194ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (BITS8(1,1,1,0,1,0,1,1) == (INSN(27,20) & BITS8(1,1,1,1,1,0,1,1))
11195ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && BITS4(0,1,0,0) == (INSN(19,16) & BITS4(1,1,1,0))
11196ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && BITS4(1,0,1,1) == INSN(11,8)
11197ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && BITS4(0,1,0,0) == (INSN(7,4) & BITS4(0,1,0,1))) {
11198ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt bZ = (insn28 >> 16) & 1;
11199ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt bN = (insn28 >> 7) & 1;
11200ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt dD = INSN(15,12) | (INSN(22,22) << 4);
11201ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt dM = INSN(3,0) | (INSN(5,5) << 4);
11202ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (bZ && INSN(3,0) != 0) {
11203ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* does not decode; fall through */
11204ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
11205ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp argL = newTemp(Ity_F64);
11206ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp argR = newTemp(Ity_F64);
11207ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp irRes = newTemp(Ity_I32);
11208ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(argL, getDReg(dD));
11209ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(argR, bZ ? IRExpr_Const(IRConst_F64i(0)) : getDReg(dM));
11210ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(irRes, binop(Iop_CmpF64, mkexpr(argL), mkexpr(argR)));
11211ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11212ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp nzcv     = IRTemp_INVALID;
11213ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp oldFPSCR = newTemp(Ity_I32);
11214ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp newFPSCR = newTemp(Ity_I32);
11215ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11216ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* This is where the fun starts.  We have to convert 'irRes'
11217ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            from an IR-convention return result (IRCmpF64Result) to an
11218ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            ARM-encoded (N,Z,C,V) group.  The final result is in the
11219ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            bottom 4 bits of 'nzcv'. */
11220ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Map compare result from IR to ARM(nzcv) */
11221ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /*
11222ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            FP cmp result | IR   | ARM(nzcv)
11223ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            --------------------------------
11224ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            UN              0x45   0011
11225ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            LT              0x01   1000
11226ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            GT              0x00   0010
11227ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            EQ              0x40   0110
11228ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         */
11229ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         nzcv = mk_convert_IRCmpF64Result_to_NZCV(irRes);
11230ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11231ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* And update FPSCR accordingly */
11232ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(oldFPSCR, IRExpr_Get(OFFB_FPSCR, Ity_I32));
11233ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(newFPSCR,
11234ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                binop(Iop_Or32,
11235ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      binop(Iop_And32, mkexpr(oldFPSCR), mkU32(0x0FFFFFFF)),
11236ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      binop(Iop_Shl32, mkexpr(nzcv), mkU8(28))));
11237ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11238ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putMiscReg32(OFFB_FPSCR, mkexpr(newFPSCR), condT);
11239ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11240ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (bZ) {
11241ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("fcmpz%sd%s d%u\n", bN ? "e" : "", nCC(conq), dD);
11242ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
11243ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("fcmp%sd%s d%u, d%u\n", bN ? "e" : "", nCC(conq), dD, dM);
11244ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
11245ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success_vfp;
11246ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
11247ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* fall through */
11248ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11249ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11250ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* --------------------- unary (D) --------------------- */
11251ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (BITS8(1,1,1,0,1,0,1,1) == (INSN(27,20) & BITS8(1,1,1,1,1,0,1,1))
11252ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && BITS4(0,0,0,0) == (INSN(19,16) & BITS4(1,1,1,0))
11253ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && BITS4(1,0,1,1) == INSN(11,8)
11254ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && BITS4(0,1,0,0) == (INSN(7,4) & BITS4(0,1,0,1))) {
11255ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt dD  = INSN(15,12) | (INSN(22,22) << 4);
11256ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt dM  = INSN(3,0) | (INSN(5,5) << 4);
11257ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt b16 = (insn28 >> 16) & 1;
11258ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt b7  = (insn28 >> 7) & 1;
11259ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /**/ if (b16 == 0 && b7 == 0) {
11260ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // FCPYD
11261ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putDReg(dD, getDReg(dM), condT);
11262ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("fcpyd%s d%u, d%u\n", nCC(conq), dD, dM);
11263ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success_vfp;
11264ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
11265ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      else if (b16 == 0 && b7 == 1) {
11266ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // FABSD
11267ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putDReg(dD, unop(Iop_AbsF64, getDReg(dM)), condT);
11268ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("fabsd%s d%u, d%u\n", nCC(conq), dD, dM);
11269ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success_vfp;
11270ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
11271ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      else if (b16 == 1 && b7 == 0) {
11272ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // FNEGD
11273ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putDReg(dD, unop(Iop_NegF64, getDReg(dM)), condT);
11274ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("fnegd%s d%u, d%u\n", nCC(conq), dD, dM);
11275ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success_vfp;
11276ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
11277ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      else if (b16 == 1 && b7 == 1) {
11278ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // FSQRTD
11279ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRExpr* rm = get_FAKE_roundingmode(); /* XXXROUNDINGFIXME */
11280ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putDReg(dD, binop(Iop_SqrtF64, rm, getDReg(dM)), condT);
11281ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("fsqrtd%s d%u, d%u\n", nCC(conq), dD, dM);
11282ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success_vfp;
11283ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
11284ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      else
11285ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vassert(0);
11286ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11287ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* fall through */
11288ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11289ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11290ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ----------------- I <-> D conversions ----------------- */
11291ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11292ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // F{S,U}ITOD dD, fM
11293ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (BITS8(1,1,1,0,1,0,1,1) == (INSN(27,20) & BITS8(1,1,1,1,1,0,1,1))
11294ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && BITS4(1,0,0,0) == (INSN(19,16) & BITS4(1,1,1,1))
11295ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && BITS4(1,0,1,1) == INSN(11,8)
11296ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && BITS4(0,1,0,0) == (INSN(7,4) & BITS4(0,1,0,1))) {
11297ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt bM    = (insn28 >> 5) & 1;
11298ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt fM    = (INSN(3,0) << 1) | bM;
11299ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt dD    = INSN(15,12) | (INSN(22,22) << 4);
11300ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt syned = (insn28 >> 7) & 1;
11301ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (syned) {
11302ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // FSITOD
11303ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putDReg(dD, unop(Iop_I32StoF64,
11304ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          unop(Iop_ReinterpF32asI32, getFReg(fM))),
11305ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 condT);
11306ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("fsitod%s d%u, s%u\n", nCC(conq), dD, fM);
11307ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
11308ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // FUITOD
11309ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putDReg(dD, unop(Iop_I32UtoF64,
11310ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          unop(Iop_ReinterpF32asI32, getFReg(fM))),
11311ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 condT);
11312ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("fuitod%s d%u, s%u\n", nCC(conq), dD, fM);
11313ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
11314ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success_vfp;
11315ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11316ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11317ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // FTO{S,U}ID fD, dM
11318ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (BITS8(1,1,1,0,1,0,1,1) == (INSN(27,20) & BITS8(1,1,1,1,1,0,1,1))
11319ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && BITS4(1,1,0,0) == (INSN(19,16) & BITS4(1,1,1,0))
11320ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && BITS4(1,0,1,1) == INSN(11,8)
11321ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && BITS4(0,1,0,0) == (INSN(7,4) & BITS4(0,1,0,1))) {
11322ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt   bD    = (insn28 >> 22) & 1;
11323ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt   fD    = (INSN(15,12) << 1) | bD;
11324ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt   dM    = INSN(3,0) | (INSN(5,5) << 4);
11325ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt   bZ    = (insn28 >> 7) & 1;
11326ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt   syned = (insn28 >> 16) & 1;
11327ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp rmode = newTemp(Ity_I32);
11328ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(rmode, bZ ? mkU32(Irrm_ZERO)
11329ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       : mkexpr(mk_get_IR_rounding_mode()));
11330ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (syned) {
11331ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // FTOSID
11332ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putFReg(fD, unop(Iop_ReinterpI32asF32,
11333ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          binop(Iop_F64toI32S, mkexpr(rmode),
11334ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                getDReg(dM))),
11335ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 condT);
11336ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("ftosi%sd%s s%u, d%u\n", bZ ? "z" : "",
11337ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             nCC(conq), fD, dM);
11338ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
11339ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // FTOUID
11340ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putFReg(fD, unop(Iop_ReinterpI32asF32,
11341ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          binop(Iop_F64toI32U, mkexpr(rmode),
11342ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                getDReg(dM))),
11343ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 condT);
11344ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("ftoui%sd%s s%u, d%u\n", bZ ? "z" : "",
11345ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             nCC(conq), fD, dM);
11346ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
11347ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success_vfp;
11348ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11349ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11350ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ----------------------------------------------------------- */
11351ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* -- VFP instructions -- single precision                  -- */
11352ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ----------------------------------------------------------- */
11353ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11354ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* --------------------- fldms, fstms --------------------- */
11355ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /*
11356ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 31   27   23   19 15 11   7   0
11357ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                         P UDWL
11358ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      C4-98, C5-26   1  FSTMD    cond 1100 1x00 Rn Fd 1010 offset
11359ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      C4-98, C5-28   2  FSTMDIA  cond 1100 1x10 Rn Fd 1010 offset
11360ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      C4-98, C5-30   3  FSTMDDB  cond 1101 0x10 Rn Fd 1010 offset
11361ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11362ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      C4-40, C5-26   1  FLDMD    cond 1100 1x01 Rn Fd 1010 offset
11363ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      C4-40, C5-26   2  FLDMIAD  cond 1100 1x11 Rn Fd 1010 offset
11364ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      C4-40, C5-26   3  FLDMDBD  cond 1101 0x11 Rn Fd 1010 offset
11365ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11366ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Regs transferred: F(Fd:D) .. F(Fd:d + offset)
11367ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      offset must not imply a reg > 15
11368ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IA/DB: Rn is changed by (4 x # regs transferred)
11369ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11370ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case coding:
11371ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         1  at-Rn   (access at Rn)
11372ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         2  ia-Rn   (access at Rn, then Rn += 4n)
11373ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         3  db-Rn   (Rn -= 4n,     then access at Rn)
11374ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   */
11375ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (BITS8(1,1,0,0,0,0,0,0) == (INSN(27,20) & BITS8(1,1,1,0,0,0,0,0))
11376ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && INSN(11,8) == BITS4(1,0,1,0)) {
11377ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt bP      = (insn28 >> 24) & 1;
11378ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt bU      = (insn28 >> 23) & 1;
11379ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt bW      = (insn28 >> 21) & 1;
11380ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt bL      = (insn28 >> 20) & 1;
11381ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt bD      = (insn28 >> 22) & 1;
11382ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt offset  = (insn28 >> 0) & 0xFF;
11383ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rN      = INSN(19,16);
11384ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt fD      = (INSN(15,12) << 1) | bD;
11385ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt nRegs   = offset;
11386ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt summary = 0;
11387ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Int  i;
11388ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11389ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /**/ if (bP == 0 && bU == 1 && bW == 0) {
11390ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         summary = 1;
11391ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
11392ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      else if (bP == 0 && bU == 1 && bW == 1) {
11393ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         summary = 2;
11394ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
11395ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      else if (bP == 1 && bU == 0 && bW == 1) {
11396ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         summary = 3;
11397ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
11398ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      else goto after_vfp_fldms_fstms;
11399ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11400ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* no writebacks to r15 allowed.  No use of r15 in thumb mode. */
11401ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (rN == 15 && (summary == 2 || summary == 3 || isT))
11402ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto after_vfp_fldms_fstms;
11403ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11404ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* offset must specify at least one register */
11405ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (offset < 1)
11406ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto after_vfp_fldms_fstms;
11407ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11408ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* can't transfer regs after S31 */
11409ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (fD + nRegs - 1 >= 32)
11410ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto after_vfp_fldms_fstms;
11411ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11412ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Now, we can't do a conditional load or store, since that very
11413ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         likely will generate an exception.  So we have to take a side
11414ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         exit at this point if the condition is false. */
11415ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (condT != IRTemp_INVALID) {
11416ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (isT)
11417ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            mk_skip_over_T32_if_cond_is_false( condT );
11418ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         else
11419ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            mk_skip_over_A32_if_cond_is_false( condT );
11420ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         condT = IRTemp_INVALID;
11421ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
11422ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Ok, now we're unconditional.  Do the load or store. */
11423ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11424ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* get the old Rn value */
11425ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp rnT = newTemp(Ity_I32);
11426ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(rnT, align4if(isT ? getIRegT(rN) : getIRegA(rN),
11427ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           rN == 15));
11428ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11429ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* make a new value for Rn, post-insn */
11430ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp rnTnew = IRTemp_INVALID;
11431ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (summary == 2 || summary == 3) {
11432ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         rnTnew = newTemp(Ity_I32);
11433ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(rnTnew, binop(summary == 2 ? Iop_Add32 : Iop_Sub32,
11434ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              mkexpr(rnT),
11435ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              mkU32(4 * nRegs)));
11436ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
11437ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11438ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* decide on the base transfer address */
11439ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp taT = newTemp(Ity_I32);
11440ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(taT, summary == 3 ? mkexpr(rnTnew) : mkexpr(rnT));
11441ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11442ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* update Rn if necessary -- in case 3, we're moving it down, so
11443ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         update before any memory reference, in order to keep Memcheck
11444ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         and V's stack-extending logic (on linux) happy */
11445ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (summary == 3) {
11446ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (isT)
11447ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putIRegT(rN, mkexpr(rnTnew), IRTemp_INVALID);
11448ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         else
11449ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putIRegA(rN, mkexpr(rnTnew), IRTemp_INVALID, Ijk_Boring);
11450ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
11451ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11452ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* generate the transfers */
11453ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      for (i = 0; i < nRegs; i++) {
11454ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRExpr* addr = binop(Iop_Add32, mkexpr(taT), mkU32(4*i));
11455ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (bL) {
11456ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putFReg(fD + i, loadLE(Ity_F32, addr), IRTemp_INVALID);
11457ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
11458ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            storeLE(addr, getFReg(fD + i));
11459ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
11460ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
11461ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11462ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* update Rn if necessary -- in case 2, we're moving it up, so
11463ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         update after any memory reference, in order to keep Memcheck
11464ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         and V's stack-extending logic (on linux) happy */
11465ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (summary == 2) {
11466ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (isT)
11467ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putIRegT(rN, mkexpr(rnTnew), IRTemp_INVALID);
11468ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         else
11469ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putIRegA(rN, mkexpr(rnTnew), IRTemp_INVALID, Ijk_Boring);
11470ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
11471ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11472ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      HChar* nm = bL==1 ? "ld" : "st";
11473ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      switch (summary) {
11474ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 1:  DIP("f%sms%s r%u, {s%u-s%u}\n",
11475ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      nm, nCC(conq), rN, fD, fD + nRegs - 1);
11476ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  break;
11477ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 2:  DIP("f%smias%s r%u!, {s%u-s%u}\n",
11478ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      nm, nCC(conq), rN, fD, fD + nRegs - 1);
11479ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  break;
11480ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 3:  DIP("f%smdbs%s r%u!, {s%u-s%u}\n",
11481ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      nm, nCC(conq), rN, fD, fD + nRegs - 1);
11482ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  break;
11483ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         default: vassert(0);
11484ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
11485ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11486ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success_vfp;
11487ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* FIXME alignment constraints? */
11488ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11489ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11490ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  after_vfp_fldms_fstms:
11491ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11492ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* --------------------- fmsr, fmrs --------------------- */
11493ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (BITS8(1,1,1,0,0,0,0,0) == (INSN(27,20) & BITS8(1,1,1,1,1,1,1,0))
11494ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && BITS4(1,0,1,0) == INSN(11,8)
11495ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && BITS4(0,0,0,0) == INSN(3,0)
11496ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && BITS4(0,0,0,1) == (INSN(7,4) & BITS4(0,1,1,1))) {
11497ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rD  = INSN(15,12);
11498ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt b7  = (insn28 >> 7) & 1;
11499ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt fN  = (INSN(19,16) << 1) | b7;
11500ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt b20 = (insn28 >> 20) & 1;
11501ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (rD == 15) {
11502ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* fall through */
11503ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Let's assume that no sane person would want to do
11504ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            floating-point transfers to or from the program counter,
11505ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            and simply decline to decode the instruction.  The ARM ARM
11506ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            doesn't seem to explicitly disallow this case, though. */
11507ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
11508ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (b20) {
11509ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            IRExpr* res = unop(Iop_ReinterpF32asI32, getFReg(fN));
11510ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (isT)
11511ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               putIRegT(rD, res, condT);
11512ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            else
11513ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               putIRegA(rD, res, condT, Ijk_Boring);
11514ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("fmrs%s r%u, s%u\n", nCC(conq), rD, fN);
11515ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
11516ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putFReg(fN, unop(Iop_ReinterpI32asF32,
11517ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             isT ? getIRegT(rD) : getIRegA(rD)),
11518ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        condT);
11519ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("fmsr%s s%u, r%u\n", nCC(conq), fN, rD);
11520ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
11521ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success_vfp;
11522ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
11523ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* fall through */
11524ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11525ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11526ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* --------------------- f{ld,st}s --------------------- */
11527ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // FLDS, FSTS
11528ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (BITS8(1,1,0,1,0,0,0,0) == (INSN(27,20) & BITS8(1,1,1,1,0,0,1,0))
11529ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && BITS4(1,0,1,0) == INSN(11,8)) {
11530ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt bD     = (insn28 >> 22) & 1;
11531ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt fD     = (INSN(15,12) << 1) | bD;
11532ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rN     = INSN(19,16);
11533ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt offset = (insn28 & 0xFF) << 2;
11534ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt bU     = (insn28 >> 23) & 1; /* 1: +offset  0: -offset */
11535ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt bL     = (insn28 >> 20) & 1; /* 1: load  0: store */
11536ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* make unconditional */
11537ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (condT != IRTemp_INVALID) {
11538ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (isT)
11539ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            mk_skip_over_T32_if_cond_is_false( condT );
11540ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         else
11541ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            mk_skip_over_A32_if_cond_is_false( condT );
11542ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         condT = IRTemp_INVALID;
11543ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
11544ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp ea = newTemp(Ity_I32);
11545ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(ea, binop(bU ? Iop_Add32 : Iop_Sub32,
11546ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       align4if(isT ? getIRegT(rN) : getIRegA(rN),
11547ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                rN == 15),
11548ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       mkU32(offset)));
11549ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (bL) {
11550ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putFReg(fD, loadLE(Ity_F32,mkexpr(ea)), IRTemp_INVALID);
11551ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
11552ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         storeLE(mkexpr(ea), getFReg(fD));
11553ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
11554ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("f%ss%s s%u, [r%u, %c#%u]\n",
11555ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          bL ? "ld" : "st", nCC(conq), fD, rN,
11556ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          bU ? '+' : '-', offset);
11557ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success_vfp;
11558ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11559ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11560ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* --------------------- dp insns (F) --------------------- */
11561ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (BITS8(1,1,1,0,0,0,0,0) == (INSN(27,20) & BITS8(1,1,1,1,0,0,0,0))
11562ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && BITS4(1,0,1,0) == (INSN(11,8) & BITS4(1,1,1,0))
11563ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && BITS4(0,0,0,0) == (INSN(7,4) & BITS4(0,0,0,1))) {
11564ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt    bM  = (insn28 >> 5) & 1;
11565ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt    bD  = (insn28 >> 22) & 1;
11566ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt    bN  = (insn28 >> 7) & 1;
11567ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt    fM  = (INSN(3,0) << 1) | bM;   /* argR */
11568ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt    fD  = (INSN(15,12) << 1) | bD; /* dst/acc */
11569ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt    fN  = (INSN(19,16) << 1) | bN; /* argL */
11570ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt    bP  = (insn28 >> 23) & 1;
11571ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt    bQ  = (insn28 >> 21) & 1;
11572ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt    bR  = (insn28 >> 20) & 1;
11573ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt    bS  = (insn28 >> 6) & 1;
11574ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt    opc = (bP << 3) | (bQ << 2) | (bR << 1) | bS;
11575ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRExpr* rm  = get_FAKE_roundingmode(); /* XXXROUNDINGFIXME */
11576ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      switch (opc) {
11577ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case BITS4(0,0,0,0): /* MAC: d + n * m */
11578ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putFReg(fD, triop(Iop_AddF32, rm,
11579ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              getFReg(fD),
11580ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              triop(Iop_MulF32, rm, getFReg(fN), getFReg(fM))),
11581ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        condT);
11582ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("fmacs%s s%u, s%u, s%u\n", nCC(conq), fD, fN, fM);
11583ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto decode_success_vfp;
11584ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case BITS4(0,0,0,1): /* NMAC: d + -(n * m) */
11585ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putFReg(fD, triop(Iop_AddF32, rm,
11586ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              getFReg(fD),
11587ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              unop(Iop_NegF32,
11588ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   triop(Iop_MulF32, rm, getFReg(fN),
11589ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                                         getFReg(fM)))),
11590ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        condT);
11591ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("fnmacs%s s%u, s%u, s%u\n", nCC(conq), fD, fN, fM);
11592ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto decode_success_vfp;
11593ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case BITS4(0,0,1,0): /* MSC: - d + n * m */
11594ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putFReg(fD, triop(Iop_AddF32, rm,
11595ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              unop(Iop_NegF32, getFReg(fD)),
11596ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              triop(Iop_MulF32, rm, getFReg(fN), getFReg(fM))),
11597ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        condT);
11598ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("fmscs%s s%u, s%u, s%u\n", nCC(conq), fD, fN, fM);
11599ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto decode_success_vfp;
11600ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case BITS4(0,0,1,1): /* NMSC: - d + -(n * m) */
11601ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putFReg(fD, triop(Iop_AddF32, rm,
11602ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              unop(Iop_NegF32, getFReg(fD)),
11603ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              unop(Iop_NegF32,
11604ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   triop(Iop_MulF32, rm,
11605ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                                     getFReg(fN),
11606ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                                    getFReg(fM)))),
11607ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        condT);
11608ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("fnmscs%s s%u, s%u, s%u\n", nCC(conq), fD, fN, fM);
11609ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto decode_success_vfp;
11610ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case BITS4(0,1,0,0): /* MUL: n * m */
11611ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putFReg(fD, triop(Iop_MulF32, rm, getFReg(fN), getFReg(fM)),
11612ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        condT);
11613ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("fmuls%s s%u, s%u, s%u\n", nCC(conq), fD, fN, fM);
11614ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto decode_success_vfp;
11615ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case BITS4(0,1,0,1): /* NMUL: - n * m */
11616ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putFReg(fD, unop(Iop_NegF32,
11617ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             triop(Iop_MulF32, rm, getFReg(fN),
11618ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                                   getFReg(fM))),
11619ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    condT);
11620ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("fnmuls%s s%u, s%u, s%u\n", nCC(conq), fD, fN, fM);
11621ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto decode_success_vfp;
11622ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case BITS4(0,1,1,0): /* ADD: n + m */
11623ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putFReg(fD, triop(Iop_AddF32, rm, getFReg(fN), getFReg(fM)),
11624ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        condT);
11625ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("fadds%s s%u, s%u, s%u\n", nCC(conq), fD, fN, fM);
11626ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto decode_success_vfp;
11627ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case BITS4(0,1,1,1): /* SUB: n - m */
11628ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putFReg(fD, triop(Iop_SubF32, rm, getFReg(fN), getFReg(fM)),
11629ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        condT);
11630ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("fsubs%s s%u, s%u, s%u\n", nCC(conq), fD, fN, fM);
11631ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto decode_success_vfp;
11632ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case BITS4(1,0,0,0): /* DIV: n / m */
11633ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putFReg(fD, triop(Iop_DivF32, rm, getFReg(fN), getFReg(fM)),
11634ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        condT);
11635ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("fdivs%s s%u, s%u, s%u\n", nCC(conq), fD, fN, fM);
11636ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto decode_success_vfp;
11637ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         default:
11638ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
11639ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
11640ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11641ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11642ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* --------------------- compares (S) --------------------- */
11643ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /*          31   27   23   19   15 11   7    3
11644ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 28   24   20   16 12    8    4    0
11645ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      FCMPS    cond 1110 1D11 0100 Fd 1010 01M0 Fm
11646ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      FCMPES   cond 1110 1D11 0100 Fd 1010 11M0 Fm
11647ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      FCMPZS   cond 1110 1D11 0101 Fd 1010 0100 0000
11648ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      FCMPZED  cond 1110 1D11 0101 Fd 1010 1100 0000
11649ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 Z         N
11650ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11651ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Z=0 Compare Fd:D vs Fm:M     and set FPSCR 31:28 accordingly
11652ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Z=1 Compare Fd:D vs zero
11653ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11654ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      N=1 generates Invalid Operation exn if either arg is any kind of NaN
11655ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      N=0 generates Invalid Operation exn if either arg is a signalling NaN
11656ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      (Not that we pay any attention to N here)
11657ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   */
11658ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (BITS8(1,1,1,0,1,0,1,1) == (INSN(27,20) & BITS8(1,1,1,1,1,0,1,1))
11659ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && BITS4(0,1,0,0) == (INSN(19,16) & BITS4(1,1,1,0))
11660ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && BITS4(1,0,1,0) == INSN(11,8)
11661ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && BITS4(0,1,0,0) == (INSN(7,4) & BITS4(0,1,0,1))) {
11662ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt bZ = (insn28 >> 16) & 1;
11663ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt bN = (insn28 >> 7) & 1;
11664ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt bD = (insn28 >> 22) & 1;
11665ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt bM = (insn28 >> 5) & 1;
11666ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt fD = (INSN(15,12) << 1) | bD;
11667ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt fM = (INSN(3,0) << 1) | bM;
11668ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (bZ && (INSN(3,0) != 0 || (INSN(7,4) & 3) != 0)) {
11669ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* does not decode; fall through */
11670ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
11671ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp argL = newTemp(Ity_F64);
11672ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp argR = newTemp(Ity_F64);
11673ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp irRes = newTemp(Ity_I32);
11674ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11675ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(argL, unop(Iop_F32toF64, getFReg(fD)));
11676ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(argR, bZ ? IRExpr_Const(IRConst_F64i(0))
11677ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         : unop(Iop_F32toF64, getFReg(fM)));
11678ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(irRes, binop(Iop_CmpF64, mkexpr(argL), mkexpr(argR)));
11679ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11680ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp nzcv     = IRTemp_INVALID;
11681ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp oldFPSCR = newTemp(Ity_I32);
11682ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp newFPSCR = newTemp(Ity_I32);
11683ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11684ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* This is where the fun starts.  We have to convert 'irRes'
11685ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            from an IR-convention return result (IRCmpF64Result) to an
11686ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            ARM-encoded (N,Z,C,V) group.  The final result is in the
11687ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            bottom 4 bits of 'nzcv'. */
11688ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Map compare result from IR to ARM(nzcv) */
11689ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /*
11690ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            FP cmp result | IR   | ARM(nzcv)
11691ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            --------------------------------
11692ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            UN              0x45   0011
11693ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            LT              0x01   1000
11694ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            GT              0x00   0010
11695ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            EQ              0x40   0110
11696ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         */
11697ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         nzcv = mk_convert_IRCmpF64Result_to_NZCV(irRes);
11698ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11699ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* And update FPSCR accordingly */
11700ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(oldFPSCR, IRExpr_Get(OFFB_FPSCR, Ity_I32));
11701ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(newFPSCR,
11702ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                binop(Iop_Or32,
11703ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      binop(Iop_And32, mkexpr(oldFPSCR), mkU32(0x0FFFFFFF)),
11704ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      binop(Iop_Shl32, mkexpr(nzcv), mkU8(28))));
11705ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11706ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putMiscReg32(OFFB_FPSCR, mkexpr(newFPSCR), condT);
11707ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11708ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (bZ) {
11709ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("fcmpz%ss%s s%u\n", bN ? "e" : "", nCC(conq), fD);
11710ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
11711ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("fcmp%ss%s s%u, s%u\n", bN ? "e" : "",
11712ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                nCC(conq), fD, fM);
11713ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
11714ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success_vfp;
11715ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
11716ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* fall through */
11717ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11718ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11719ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* --------------------- unary (S) --------------------- */
11720ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (BITS8(1,1,1,0,1,0,1,1) == (INSN(27,20) & BITS8(1,1,1,1,1,0,1,1))
11721ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && BITS4(0,0,0,0) == (INSN(19,16) & BITS4(1,1,1,0))
11722ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && BITS4(1,0,1,0) == INSN(11,8)
11723ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && BITS4(0,1,0,0) == (INSN(7,4) & BITS4(0,1,0,1))) {
11724ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt bD = (insn28 >> 22) & 1;
11725ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt bM = (insn28 >> 5) & 1;
11726ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt fD  = (INSN(15,12) << 1) | bD;
11727ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt fM  = (INSN(3,0) << 1) | bM;
11728ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt b16 = (insn28 >> 16) & 1;
11729ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt b7  = (insn28 >> 7) & 1;
11730ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /**/ if (b16 == 0 && b7 == 0) {
11731ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // FCPYS
11732ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putFReg(fD, getFReg(fM), condT);
11733ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("fcpys%s s%u, s%u\n", nCC(conq), fD, fM);
11734ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success_vfp;
11735ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
11736ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      else if (b16 == 0 && b7 == 1) {
11737ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // FABSS
11738ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putFReg(fD, unop(Iop_AbsF32, getFReg(fM)), condT);
11739ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("fabss%s s%u, s%u\n", nCC(conq), fD, fM);
11740ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success_vfp;
11741ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
11742ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      else if (b16 == 1 && b7 == 0) {
11743ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // FNEGS
11744ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putFReg(fD, unop(Iop_NegF32, getFReg(fM)), condT);
11745ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("fnegs%s s%u, s%u\n", nCC(conq), fD, fM);
11746ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success_vfp;
11747ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
11748ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      else if (b16 == 1 && b7 == 1) {
11749ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // FSQRTS
11750ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRExpr* rm = get_FAKE_roundingmode(); /* XXXROUNDINGFIXME */
11751ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putFReg(fD, binop(Iop_SqrtF32, rm, getFReg(fM)), condT);
11752ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("fsqrts%s s%u, s%u\n", nCC(conq), fD, fM);
11753ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success_vfp;
11754ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
11755ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      else
11756ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vassert(0);
11757ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11758ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* fall through */
11759ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11760ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11761ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ----------------- I <-> S conversions ----------------- */
11762ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11763ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // F{S,U}ITOS fD, fM
11764ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* These are more complex than FSITOD/FUITOD.  In the D cases, a 32
11765ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      bit int will always fit within the 53 bit mantissa, so there's
11766ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      no possibility of a loss of precision, but that's obviously not
11767ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      the case here.  Hence this case possibly requires rounding, and
11768ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      so it drags in the current rounding mode. */
11769ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (BITS8(1,1,1,0,1,0,1,1) == (INSN(27,20) & BITS8(1,1,1,1,1,0,1,1))
11770ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && BITS4(1,0,0,0) == INSN(19,16)
11771ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && BITS4(1,0,1,0) == (INSN(11,8) & BITS4(1,1,1,0))
11772ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && BITS4(0,1,0,0) == (INSN(7,4) & BITS4(0,1,0,1))) {
11773ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt bM    = (insn28 >> 5) & 1;
11774ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt bD    = (insn28 >> 22) & 1;
11775ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt fM    = (INSN(3,0) << 1) | bM;
11776ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt fD    = (INSN(15,12) << 1) | bD;
11777ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt syned = (insn28 >> 7) & 1;
11778ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp rmode = newTemp(Ity_I32);
11779ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(rmode, mkexpr(mk_get_IR_rounding_mode()));
11780ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (syned) {
11781ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // FSITOS
11782ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putFReg(fD, binop(Iop_F64toF32,
11783ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           mkexpr(rmode),
11784ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           unop(Iop_I32StoF64,
11785ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                unop(Iop_ReinterpF32asI32, getFReg(fM)))),
11786ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 condT);
11787ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("fsitos%s s%u, s%u\n", nCC(conq), fD, fM);
11788ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
11789ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // FUITOS
11790ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putFReg(fD, binop(Iop_F64toF32,
11791ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           mkexpr(rmode),
11792ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           unop(Iop_I32UtoF64,
11793ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                unop(Iop_ReinterpF32asI32, getFReg(fM)))),
11794ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 condT);
11795ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("fuitos%s s%u, s%u\n", nCC(conq), fD, fM);
11796ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
11797ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success_vfp;
11798ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11799ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11800ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // FTO{S,U}IS fD, fM
11801ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (BITS8(1,1,1,0,1,0,1,1) == (INSN(27,20) & BITS8(1,1,1,1,1,0,1,1))
11802ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && BITS4(1,1,0,0) == (INSN(19,16) & BITS4(1,1,1,0))
11803ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && BITS4(1,0,1,0) == INSN(11,8)
11804ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && BITS4(0,1,0,0) == (INSN(7,4) & BITS4(0,1,0,1))) {
11805ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt   bM    = (insn28 >> 5) & 1;
11806ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt   bD    = (insn28 >> 22) & 1;
11807ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt   fD    = (INSN(15,12) << 1) | bD;
11808ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt   fM    = (INSN(3,0) << 1) | bM;
11809ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt   bZ    = (insn28 >> 7) & 1;
11810ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt   syned = (insn28 >> 16) & 1;
11811ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp rmode = newTemp(Ity_I32);
11812ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(rmode, bZ ? mkU32(Irrm_ZERO)
11813ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       : mkexpr(mk_get_IR_rounding_mode()));
11814ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (syned) {
11815ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // FTOSIS
11816ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putFReg(fD, unop(Iop_ReinterpI32asF32,
11817ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          binop(Iop_F64toI32S, mkexpr(rmode),
11818ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                unop(Iop_F32toF64, getFReg(fM)))),
11819ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 condT);
11820ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("ftosi%ss%s s%u, d%u\n", bZ ? "z" : "",
11821ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             nCC(conq), fD, fM);
11822ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success_vfp;
11823ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
11824ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // FTOUIS
11825ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putFReg(fD, unop(Iop_ReinterpI32asF32,
11826ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          binop(Iop_F64toI32U, mkexpr(rmode),
11827ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                unop(Iop_F32toF64, getFReg(fM)))),
11828ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 condT);
11829ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("ftoui%ss%s s%u, d%u\n", bZ ? "z" : "",
11830ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             nCC(conq), fD, fM);
11831ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success_vfp;
11832ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
11833ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11834ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11835ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ----------------- S <-> D conversions ----------------- */
11836ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11837ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // FCVTDS
11838ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (BITS8(1,1,1,0,1,0,1,1) == (INSN(27,20) & BITS8(1,1,1,1,1,0,1,1))
11839ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && BITS4(0,1,1,1) == INSN(19,16)
11840ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && BITS4(1,0,1,0) == INSN(11,8)
11841ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && BITS4(1,1,0,0) == (INSN(7,4) & BITS4(1,1,0,1))) {
11842ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt dD = INSN(15,12) | (INSN(22,22) << 4);
11843ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt bM = (insn28 >> 5) & 1;
11844ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt fM = (INSN(3,0) << 1) | bM;
11845ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putDReg(dD, unop(Iop_F32toF64, getFReg(fM)), condT);
11846ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("fcvtds%s d%u, s%u\n", nCC(conq), dD, fM);
11847ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success_vfp;
11848ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11849ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11850ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // FCVTSD
11851ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (BITS8(1,1,1,0,1,0,1,1) == (INSN(27,20) & BITS8(1,1,1,1,1,0,1,1))
11852ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && BITS4(0,1,1,1) == INSN(19,16)
11853ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && BITS4(1,0,1,1) == INSN(11,8)
11854ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && BITS4(1,1,0,0) == (INSN(7,4) & BITS4(1,1,0,1))) {
11855ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt   bD    = (insn28 >> 22) & 1;
11856ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt   fD    = (INSN(15,12) << 1) | bD;
11857ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt   dM    = INSN(3,0) | (INSN(5,5) << 4);
11858ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp rmode = newTemp(Ity_I32);
11859ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(rmode, mkexpr(mk_get_IR_rounding_mode()));
11860ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putFReg(fD, binop(Iop_F64toF32, mkexpr(rmode), getDReg(dM)),
11861ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  condT);
11862ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("fcvtsd%s s%u, d%u\n", nCC(conq), fD, dM);
11863ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success_vfp;
11864ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11865ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11866ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* FAILURE */
11867ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return False;
11868ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11869ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  decode_success_vfp:
11870ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Check that any accepted insn really is a CP10 or CP11 insn, iow,
11871ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assert that we aren't accepting, in this fn, insns that actually
11872ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      should be handled somewhere else. */
11873ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(INSN(11,9) == BITS3(1,0,1)); // 11:8 = 1010 or 1011
11874ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return True;
11875ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11876ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  undef INSN
11877ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
11878ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11879ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11880ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
11881ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- Instructions in NV (never) space                     ---*/
11882ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
11883ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11884ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* ARM only */
11885ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Translate a NV space instruction.  If successful, returns True and
11886ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   *dres may or may not be updated.  If failure, returns False and
11887ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   doesn't change *dres nor create any IR.
11888ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11889ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Note that all NEON instructions (in ARM mode) are handled through
11890ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   here, since they are all in NV space.
11891ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
11892ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Bool decode_NV_instruction ( /*MOD*/DisResult* dres,
11893ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    VexArchInfo* archinfo,
11894ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    UInt insn )
11895ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
11896ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  define INSN(_bMax,_bMin)  SLICE_UInt(insn, (_bMax), (_bMin))
11897ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  define INSN_COND          SLICE_UInt(insn, 31, 28)
11898ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11899ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HChar dis_buf[128];
11900ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11901ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Should only be called for NV instructions
11902ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(BITS4(1,1,1,1) == INSN_COND);
11903ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11904ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ------------------------ pld ------------------------ */
11905ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (BITS8(0,1,0,1, 0, 1,0,1) == (INSN(27,20) & BITS8(1,1,1,1,0,1,1,1))
11906ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && BITS4(1,1,1,1) == INSN(15,12)) {
11907ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rN    = INSN(19,16);
11908ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt imm12 = INSN(11,0);
11909ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt bU    = INSN(23,23);
11910ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("pld [r%u, #%c%u]\n", rN, bU ? '+' : '-', imm12);
11911ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return True;
11912ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11913ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11914ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (BITS8(0,1,1,1, 0, 1,0,1) == (INSN(27,20) & BITS8(1,1,1,1,0,1,1,1))
11915ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && BITS4(1,1,1,1) == INSN(15,12)
11916ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && 0 == INSN(4,4)) {
11917ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rN   = INSN(19,16);
11918ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rM   = INSN(3,0);
11919ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt imm5 = INSN(11,7);
11920ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt sh2  = INSN(6,5);
11921ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt bU   = INSN(23,23);
11922ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (rM != 15) {
11923ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRExpr* eaE = mk_EA_reg_plusminus_shifted_reg(rN, bU, rM,
11924ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                                       sh2, imm5, dis_buf);
11925ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp eaT = newTemp(Ity_I32);
11926ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Bind eaE to a temp merely for debugging-vex purposes, so we
11927ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            can check it's a plausible decoding.  It will get removed
11928ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            by iropt a little later on. */
11929ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vassert(eaE);
11930ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(eaT, eaE);
11931ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("pld %s\n", dis_buf);
11932ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         return True;
11933ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
11934ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* fall through */
11935ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11936ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11937ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ------------------------ pli ------------------------ */
11938ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (BITS8(0,1,0,0, 0, 1,0,1) == (INSN(27,20) & BITS8(1,1,1,1,0,1,1,1))
11939ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && BITS4(1,1,1,1) == INSN(15,12)) {
11940ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rN    = INSN(19,16);
11941ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt imm12 = INSN(11,0);
11942ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt bU    = INSN(23,23);
11943ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("pli [r%u, #%c%u]\n", rN, bU ? '+' : '-', imm12);
11944ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return True;
11945ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11946ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11947ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* --------------------- Interworking branches --------------------- */
11948ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11949ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // BLX (1), viz, unconditional branch and link to R15+simm24
11950ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // and set CPSR.T = 1, that is, switch to Thumb mode
11951ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (INSN(31,25) == BITS7(1,1,1,1,1,0,1)) {
11952ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt bitH   = INSN(24,24);
11953ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Int  uimm24 = INSN(23,0);
11954ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Int  simm24 = (((uimm24 << 8) >> 8) << 2) + (bitH << 1);
11955ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Now this is a bit tricky.  Since we're decoding an ARM insn,
11956ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         it is implies that CPSR.T == 0.  Hence the current insn's
11957ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         address is guaranteed to be of the form X--(30)--X00.  So, no
11958ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         need to mask any bits off it.  But need to set the lowest bit
11959ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         to 1 to denote we're in Thumb mode after this, since
11960ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         guest_R15T has CPSR.T as the lowest bit.  And we can't chase
11961ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         into the call, so end the block at this point. */
11962ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt dst = guest_R15_curr_instr_notENC + 8 + (simm24 | 1);
11963ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIRegA( 14, mkU32(guest_R15_curr_instr_notENC + 4),
11964ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    IRTemp_INVALID/*because AL*/, Ijk_Boring );
11965ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      irsb->next     = mkU32(dst);
11966ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      irsb->jumpkind = Ijk_Call;
11967ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      dres->whatNext = Dis_StopHere;
11968ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("blx 0x%x (and switch to Thumb mode)\n", dst - 1);
11969ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return True;
11970ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11971ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11972ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ------------------- v7 barrier insns ------------------- */
11973ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (insn) {
11974ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xF57FF06F: /* ISB */
11975ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         stmt( IRStmt_MBE(Imbe_Fence) );
11976ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("ISB\n");
11977ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         return True;
119781b891657a2208341cc71c68ae16eada0bee46d91Jeff Brown      case 0xF57FF04F: /* DSB sy */
119791b891657a2208341cc71c68ae16eada0bee46d91Jeff Brown      case 0xF57FF04E: /* DSB st */
119801b891657a2208341cc71c68ae16eada0bee46d91Jeff Brown      case 0xF57FF04B: /* DSB ish */
119811b891657a2208341cc71c68ae16eada0bee46d91Jeff Brown      case 0xF57FF04A: /* DSB ishst */
119821b891657a2208341cc71c68ae16eada0bee46d91Jeff Brown      case 0xF57FF047: /* DSB nsh */
119831b891657a2208341cc71c68ae16eada0bee46d91Jeff Brown      case 0xF57FF046: /* DSB nshst */
119841b891657a2208341cc71c68ae16eada0bee46d91Jeff Brown      case 0xF57FF043: /* DSB osh */
119851b891657a2208341cc71c68ae16eada0bee46d91Jeff Brown      case 0xF57FF042: /* DSB oshst */
11986ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         stmt( IRStmt_MBE(Imbe_Fence) );
11987ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("DSB\n");
11988ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         return True;
119891b891657a2208341cc71c68ae16eada0bee46d91Jeff Brown      case 0xF57FF05F: /* DMB sy */
119901b891657a2208341cc71c68ae16eada0bee46d91Jeff Brown      case 0xF57FF05E: /* DMB st */
119911b891657a2208341cc71c68ae16eada0bee46d91Jeff Brown      case 0xF57FF05B: /* DMB ish */
119921b891657a2208341cc71c68ae16eada0bee46d91Jeff Brown      case 0xF57FF05A: /* DMB ishst */
119931b891657a2208341cc71c68ae16eada0bee46d91Jeff Brown      case 0xF57FF057: /* DMB nsh */
119941b891657a2208341cc71c68ae16eada0bee46d91Jeff Brown      case 0xF57FF056: /* DMB nshst */
119951b891657a2208341cc71c68ae16eada0bee46d91Jeff Brown      case 0xF57FF053: /* DMB osh */
119961b891657a2208341cc71c68ae16eada0bee46d91Jeff Brown      case 0xF57FF052: /* DMB oshst */
11997ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         stmt( IRStmt_MBE(Imbe_Fence) );
11998ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("DMB\n");
11999ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         return True;
12000ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default:
12001ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
12002ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
12003ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12004b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   /* ------------------- CLREX ------------------ */
12005b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   if (insn == 0xF57FF01F) {
12006b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      /* AFAICS, this simply cancels a (all?) reservations made by a
12007b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         (any?) preceding LDREX(es).  Arrange to hand it through to
12008b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         the back end. */
12009b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      stmt( IRStmt_MBE(Imbe_CancelReservation) );
12010b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      DIP("clrex\n");
12011b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      return True;
12012b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   }
12013b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
12014ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ------------------- NEON ------------------- */
12015ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (archinfo->hwcaps & VEX_HWCAPS_ARM_NEON) {
12016ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Bool ok_neon = decode_NEON_instruction(
12017ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        dres, insn, IRTemp_INVALID/*unconditional*/,
12018ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        False/*!isT*/
12019ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     );
12020ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (ok_neon)
12021ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         return True;
12022ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
12023ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12024ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // unrecognised
12025ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return False;
12026ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12027ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  undef INSN_COND
12028ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  undef INSN
12029ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
12030ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12031ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12032ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
12033ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- Disassemble a single ARM instruction                 ---*/
12034ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
12035ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12036ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Disassemble a single ARM instruction into IR.  The instruction is
12037ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   located in host memory at guest_instr, and has (decoded) guest IP
12038ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   of guest_R15_curr_instr_notENC, which will have been set before the
12039ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   call here. */
12040ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12041ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
12042ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownDisResult disInstr_ARM_WRK (
12043ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             Bool         put_IP,
12044ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             Bool         (*resteerOkFn) ( /*opaque*/void*, Addr64 ),
12045ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             Bool         resteerCisOk,
12046ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             void*        callback_opaque,
12047ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             UChar*       guest_instr,
12048ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             VexArchInfo* archinfo,
12049ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             VexAbiInfo*  abiinfo
12050ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          )
12051ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
12052ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // A macro to fish bits out of 'insn'.
12053ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  define INSN(_bMax,_bMin)  SLICE_UInt(insn, (_bMax), (_bMin))
12054ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  define INSN_COND          SLICE_UInt(insn, 31, 28)
12055ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12056ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DisResult dres;
12057ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt      insn;
12058ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   //Bool      allow_VFP = False;
12059ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   //UInt      hwcaps = archinfo->hwcaps;
12060ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp    condT; /* :: Ity_I32 */
12061ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt      summary;
12062ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HChar     dis_buf[128];  // big enough to hold LDMIA etc text
12063ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12064ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* What insn variants are we supporting today? */
12065ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   //allow_VFP  = (0 != (hwcaps & VEX_HWCAPS_ARM_VFP));
12066ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // etc etc
12067ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12068ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Set result defaults. */
12069ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   dres.whatNext   = Dis_Continue;
12070ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   dres.len        = 4;
12071ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   dres.continueAt = 0;
12072ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12073ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Set default actions for post-insn handling of writes to r15, if
12074ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      required. */
12075ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   r15written = False;
12076ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   r15guard   = IRTemp_INVALID; /* unconditional */
12077ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   r15kind    = Ijk_Boring;
12078ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12079ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* At least this is simple on ARM: insns are all 4 bytes long, and
12080ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      4-aligned.  So just fish the whole thing out of memory right now
12081ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      and have done. */
12082ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   insn = getUIntLittleEndianly( guest_instr );
12083ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12084ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (0) vex_printf("insn: 0x%x\n", insn);
12085ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12086ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DIP("\t(arm) 0x%x:  ", (UInt)guest_R15_curr_instr_notENC);
12087ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12088ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* We may be asked to update the guest R15 before going further. */
12089ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(0 == (guest_R15_curr_instr_notENC & 3));
12090ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (put_IP) {
12091ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      llPutIReg( 15, mkU32(guest_R15_curr_instr_notENC) );
12092ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
12093ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12094ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ----------------------------------------------------------- */
12095ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12096ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Spot "Special" instructions (see comment at top of file). */
12097ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   {
12098ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UChar* code = (UChar*)guest_instr;
12099ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Spot the 16-byte preamble:
12100ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12101ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         e1a0c1ec  mov r12, r12, ROR #3
12102ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         e1a0c6ec  mov r12, r12, ROR #13
12103ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         e1a0ceec  mov r12, r12, ROR #29
12104ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         e1a0c9ec  mov r12, r12, ROR #19
12105ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      */
12106ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt word1 = 0xE1A0C1EC;
12107ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt word2 = 0xE1A0C6EC;
12108ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt word3 = 0xE1A0CEEC;
12109ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt word4 = 0xE1A0C9EC;
12110ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (getUIntLittleEndianly(code+ 0) == word1 &&
12111ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          getUIntLittleEndianly(code+ 4) == word2 &&
12112ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          getUIntLittleEndianly(code+ 8) == word3 &&
12113ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          getUIntLittleEndianly(code+12) == word4) {
12114ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Got a "Special" instruction preamble.  Which one is it? */
12115ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (getUIntLittleEndianly(code+16) == 0xE18AA00A
12116ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                               /* orr r10,r10,r10 */) {
12117ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* R3 = client_request ( R4 ) */
12118ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("r3 = client_request ( %%r4 )\n");
12119ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            irsb->next     = mkU32( guest_R15_curr_instr_notENC + 20 );
12120ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            irsb->jumpkind = Ijk_ClientReq;
12121ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            dres.whatNext  = Dis_StopHere;
12122ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto decode_success;
12123ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
12124ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         else
12125ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (getUIntLittleEndianly(code+16) == 0xE18BB00B
12126ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                               /* orr r11,r11,r11 */) {
12127ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* R3 = guest_NRADDR */
12128ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("r3 = guest_NRADDR\n");
12129ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            dres.len = 20;
12130ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            llPutIReg(3, IRExpr_Get( OFFB_NRADDR, Ity_I32 ));
12131ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto decode_success;
12132ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
12133ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         else
12134ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (getUIntLittleEndianly(code+16) == 0xE18CC00C
12135ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                               /* orr r12,r12,r12 */) {
12136ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /*  branch-and-link-to-noredir R4 */
12137ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("branch-and-link-to-noredir r4\n");
12138ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            llPutIReg(14, mkU32( guest_R15_curr_instr_notENC + 20) );
12139ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            irsb->next     = llGetIReg(4);
12140ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            irsb->jumpkind = Ijk_NoRedir;
12141ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            dres.whatNext  = Dis_StopHere;
12142ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto decode_success;
12143ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
12144ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* We don't know what it is.  Set opc1/opc2 so decode_failure
12145ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            can print the insn following the Special-insn preamble. */
12146ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         insn = getUIntLittleEndianly(code+16);
12147ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_failure;
12148ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /*NOTREACHED*/
12149ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
12150ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12151ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
12152ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12153ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ----------------------------------------------------------- */
12154ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12155ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Main ARM instruction decoder starts here. */
12156ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12157ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Deal with the condition.  Strategy is to merely generate a
12158ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      condition temporary at this point (or IRTemp_INVALID, meaning
12159ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      unconditional).  We leave it to lower-level instruction decoders
12160ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      to decide whether they can generate straight-line code, or
12161ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      whether they must generate a side exit before the instruction.
12162ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      condT :: Ity_I32 and is always either zero or one. */
12163ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   condT = IRTemp_INVALID;
12164ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch ( (ARMCondcode)INSN_COND ) {
12165ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case ARMCondNV: {
12166ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // Illegal instruction prior to v5 (see ARM ARM A3-5), but
12167ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // some cases are acceptable
12168ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Bool ok = decode_NV_instruction(&dres, archinfo, insn);
12169ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (ok)
12170ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto decode_success;
12171ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         else
12172ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto decode_failure;
12173ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
12174ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case ARMCondAL: // Always executed
12175ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
12176ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case ARMCondEQ: case ARMCondNE: case ARMCondHS: case ARMCondLO:
12177ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case ARMCondMI: case ARMCondPL: case ARMCondVS: case ARMCondVC:
12178ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case ARMCondHI: case ARMCondLS: case ARMCondGE: case ARMCondLT:
12179ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case ARMCondGT: case ARMCondLE:
12180ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         condT = newTemp(Ity_I32);
12181ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( condT, mk_armg_calculate_condition( INSN_COND ));
12182ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
12183ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
12184ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12185ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ----------------------------------------------------------- */
12186ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* -- ARMv5 integer instructions                            -- */
12187ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ----------------------------------------------------------- */
12188ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12189ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ---------------- Data processing ops ------------------- */
12190ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12191ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (0 == (INSN(27,20) & BITS8(1,1,0,0,0,0,0,0))
12192ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && !(INSN(25,25) == 0 && INSN(7,7) == 1 && INSN(4,4) == 1)) {
12193ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp  shop = IRTemp_INVALID; /* shifter operand */
12194ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp  shco = IRTemp_INVALID; /* shifter carry out */
12195ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt    rD   = (insn >> 12) & 0xF; /* 15:12 */
12196ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt    rN   = (insn >> 16) & 0xF; /* 19:16 */
12197ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt    bitS = (insn >> 20) & 1; /* 20:20 */
12198ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp  rNt  = IRTemp_INVALID;
12199ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp  res  = IRTemp_INVALID;
12200ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp  oldV = IRTemp_INVALID;
12201ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp  oldC = IRTemp_INVALID;
12202ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      HChar*  name = NULL;
12203ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IROp    op   = Iop_INVALID;
12204ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Bool    ok;
12205ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12206ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      switch (INSN(24,21)) {
12207ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12208ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* --------- ADD, SUB, AND, OR --------- */
12209ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case BITS4(0,1,0,0): /* ADD:  Rd = Rn + shifter_operand */
12210ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            name = "add"; op = Iop_Add32; goto rd_eq_rn_op_SO;
12211ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case BITS4(0,0,1,0): /* SUB:  Rd = Rn - shifter_operand */
12212ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            name = "sub"; op = Iop_Sub32; goto rd_eq_rn_op_SO;
12213ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case BITS4(0,0,1,1): /* RSB:  Rd = shifter_operand - Rn */
12214ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            name = "rsb"; op = Iop_Sub32; goto rd_eq_rn_op_SO;
12215ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case BITS4(0,0,0,0): /* AND:  Rd = Rn & shifter_operand */
12216ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            name = "and"; op = Iop_And32; goto rd_eq_rn_op_SO;
12217ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case BITS4(1,1,0,0): /* OR:   Rd = Rn | shifter_operand */
12218ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            name = "orr"; op = Iop_Or32; goto rd_eq_rn_op_SO;
12219ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case BITS4(0,0,0,1): /* EOR:  Rd = Rn ^ shifter_operand */
12220ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            name = "eor"; op = Iop_Xor32; goto rd_eq_rn_op_SO;
12221ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case BITS4(1,1,1,0): /* BIC:  Rd = Rn & ~shifter_operand */
12222ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            name = "bic"; op = Iop_And32; goto rd_eq_rn_op_SO;
12223ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         rd_eq_rn_op_SO: {
12224ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            Bool isRSB = False;
12225ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            Bool isBIC = False;
12226ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            switch (INSN(24,21)) {
12227ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               case BITS4(0,0,1,1):
12228ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  vassert(op == Iop_Sub32); isRSB = True; break;
12229ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               case BITS4(1,1,1,0):
12230ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  vassert(op == Iop_And32); isBIC = True; break;
12231ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               default:
12232ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  break;
12233ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
12234ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            rNt = newTemp(Ity_I32);
12235ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(rNt, getIRegA(rN));
12236ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            ok = mk_shifter_operand(
12237ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    INSN(25,25), INSN(11,0),
12238ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    &shop, bitS ? &shco : NULL, dis_buf
12239ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 );
12240ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (!ok)
12241ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
12242ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            res = newTemp(Ity_I32);
12243ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            // compute the main result
12244ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (isRSB) {
12245ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               // reverse-subtract: shifter_operand - Rn
12246ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               vassert(op == Iop_Sub32);
12247ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign(res, binop(op, mkexpr(shop), mkexpr(rNt)) );
12248ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            } else if (isBIC) {
12249ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               // andn: shifter_operand & ~Rn
12250ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               vassert(op == Iop_And32);
12251ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign(res, binop(op, mkexpr(rNt),
12252ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                     unop(Iop_Not32, mkexpr(shop))) );
12253ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            } else {
12254ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               // normal: Rn op shifter_operand
12255ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign(res, binop(op, mkexpr(rNt), mkexpr(shop)) );
12256ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
12257ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            // but don't commit it until after we've finished
12258ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            // all necessary reads from the guest state
12259ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (bitS
12260ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                && (op == Iop_And32 || op == Iop_Or32 || op == Iop_Xor32)) {
12261ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               oldV = newTemp(Ity_I32);
12262ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign( oldV, mk_armg_calculate_flag_v() );
12263ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
12264ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            // can't safely read guest state after here
12265ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            // now safe to put the main result
12266ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putIRegA( rD, mkexpr(res), condT, Ijk_Boring );
12267ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            // XXXX!! not safe to read any guest state after
12268ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            // this point (I think the code below doesn't do that).
12269ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (!bitS)
12270ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               vassert(shco == IRTemp_INVALID);
12271ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* Update the flags thunk if necessary */
12272ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (bitS) {
12273ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               vassert(shco != IRTemp_INVALID);
12274ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               switch (op) {
12275ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case Iop_Add32:
12276ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     setFlags_D1_D2( ARMG_CC_OP_ADD, rNt, shop, condT );
12277ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
12278ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case Iop_Sub32:
12279ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     if (isRSB) {
12280ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        setFlags_D1_D2( ARMG_CC_OP_SUB, shop, rNt, condT );
12281ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     } else {
12282ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        setFlags_D1_D2( ARMG_CC_OP_SUB, rNt, shop, condT );
12283ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     }
12284ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
12285ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case Iop_And32: /* BIC and AND set the flags the same */
12286ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case Iop_Or32:
12287ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case Iop_Xor32:
12288ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     // oldV has been read just above
12289ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     setFlags_D1_D2_ND( ARMG_CC_OP_LOGIC,
12290ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                        res, shco, oldV, condT );
12291ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
12292ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  default:
12293ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     vassert(0);
12294ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               }
12295ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
12296ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("%s%s%s r%u, r%u, %s\n",
12297ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                name, nCC(INSN_COND), bitS ? "s" : "", rD, rN, dis_buf );
12298ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto decode_success;
12299ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
12300ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12301ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* --------- MOV, MVN --------- */
12302ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case BITS4(1,1,0,1):   /* MOV: Rd = shifter_operand */
12303ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case BITS4(1,1,1,1): { /* MVN: Rd = not(shifter_operand) */
12304ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            Bool isMVN = INSN(24,21) == BITS4(1,1,1,1);
12305b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            IRTemp jk = Ijk_Boring;
12306ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (rN != 0)
12307ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break; /* rN must be zero */
12308ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            ok = mk_shifter_operand(
12309ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    INSN(25,25), INSN(11,0),
12310ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    &shop, bitS ? &shco : NULL, dis_buf
12311ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 );
12312ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (!ok)
12313ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
12314ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            res = newTemp(Ity_I32);
12315ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign( res, isMVN ? unop(Iop_Not32, mkexpr(shop))
12316ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               : mkexpr(shop) );
12317ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (bitS) {
12318ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               vassert(shco != IRTemp_INVALID);
12319ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               oldV = newTemp(Ity_I32);
12320ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign( oldV, mk_armg_calculate_flag_v() );
12321ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            } else {
12322ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               vassert(shco == IRTemp_INVALID);
12323ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
12324b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            /* According to the Cortex A8 TRM Sec. 5.2.1, MOV PC, r14 is a
12325b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                return for purposes of branch prediction. */
12326b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            if (!isMVN && INSN(11,0) == 14) {
12327b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov              jk = Ijk_Ret;
12328b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            }
12329ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            // can't safely read guest state after here
12330b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            putIRegA( rD, mkexpr(res), condT, jk );
12331ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* Update the flags thunk if necessary */
12332ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (bitS) {
12333ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               setFlags_D1_D2_ND( ARMG_CC_OP_LOGIC,
12334ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  res, shco, oldV, condT );
12335ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
12336ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("%s%s%s r%u, %s\n",
12337ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                isMVN ? "mvn" : "mov",
12338ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                nCC(INSN_COND), bitS ? "s" : "", rD, dis_buf );
12339ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto decode_success;
12340ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
12341ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12342ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* --------- CMP --------- */
12343ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case BITS4(1,0,1,0):   /* CMP:  (void) Rn - shifter_operand */
12344ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case BITS4(1,0,1,1): { /* CMN:  (void) Rn + shifter_operand */
12345ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            Bool isCMN = INSN(24,21) == BITS4(1,0,1,1);
12346ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (rD != 0)
12347ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break; /* rD must be zero */
12348ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (bitS == 0)
12349ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break; /* if S (bit 20) is not set, it's not CMP/CMN */
12350ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            rNt = newTemp(Ity_I32);
12351ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(rNt, getIRegA(rN));
12352ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            ok = mk_shifter_operand(
12353ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    INSN(25,25), INSN(11,0),
12354ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    &shop, NULL, dis_buf
12355ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 );
12356ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (!ok)
12357ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
12358ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            // can't safely read guest state after here
12359ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* Update the flags thunk. */
12360ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            setFlags_D1_D2( isCMN ? ARMG_CC_OP_ADD : ARMG_CC_OP_SUB,
12361ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            rNt, shop, condT );
12362ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("%s%s r%u, %s\n",
12363ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                isCMN ? "cmn" : "cmp",
12364ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                nCC(INSN_COND), rN, dis_buf );
12365ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto decode_success;
12366ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
12367ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12368ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* --------- TST --------- */
12369ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case BITS4(1,0,0,0):   /* TST:  (void) Rn & shifter_operand */
12370ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case BITS4(1,0,0,1): { /* TEQ:  (void) Rn ^ shifter_operand */
12371ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            Bool isTEQ = INSN(24,21) == BITS4(1,0,0,1);
12372ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (rD != 0)
12373ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break; /* rD must be zero */
12374ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (bitS == 0)
12375ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break; /* if S (bit 20) is not set, it's not TST/TEQ */
12376ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            rNt = newTemp(Ity_I32);
12377ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(rNt, getIRegA(rN));
12378ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            ok = mk_shifter_operand(
12379ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    INSN(25,25), INSN(11,0),
12380ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    &shop, &shco, dis_buf
12381ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 );
12382ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (!ok)
12383ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
12384ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* Update the flags thunk. */
12385ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            res = newTemp(Ity_I32);
12386ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign( res, binop(isTEQ ? Iop_Xor32 : Iop_And32,
12387ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               mkexpr(rNt), mkexpr(shop)) );
12388ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            oldV = newTemp(Ity_I32);
12389ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign( oldV, mk_armg_calculate_flag_v() );
12390ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            // can't safely read guest state after here
12391ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            setFlags_D1_D2_ND( ARMG_CC_OP_LOGIC,
12392ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               res, shco, oldV, condT );
12393ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("%s%s r%u, %s\n",
12394ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                isTEQ ? "teq" : "tst",
12395ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                nCC(INSN_COND), rN, dis_buf );
12396ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto decode_success;
12397ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
12398ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12399ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* --------- ADC, SBC, RSC --------- */
12400ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case BITS4(0,1,0,1): /* ADC:  Rd = Rn + shifter_operand + oldC */
12401ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            name = "adc"; goto rd_eq_rn_op_SO_op_oldC;
12402ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case BITS4(0,1,1,0): /* SBC:  Rd = Rn - shifter_operand - (oldC ^ 1) */
12403ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            name = "sbc"; goto rd_eq_rn_op_SO_op_oldC;
12404ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case BITS4(0,1,1,1): /* RSC:  Rd = shifter_operand - Rn - (oldC ^ 1) */
12405ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            name = "rsc"; goto rd_eq_rn_op_SO_op_oldC;
12406ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         rd_eq_rn_op_SO_op_oldC: {
12407ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            // FIXME: shco isn't used for anything.  Get rid of it.
12408ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            rNt = newTemp(Ity_I32);
12409ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(rNt, getIRegA(rN));
12410ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            ok = mk_shifter_operand(
12411ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    INSN(25,25), INSN(11,0),
12412ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    &shop, bitS ? &shco : NULL, dis_buf
12413ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 );
12414ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (!ok)
12415ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
12416ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            oldC = newTemp(Ity_I32);
12417ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign( oldC, mk_armg_calculate_flag_c() );
12418ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            res = newTemp(Ity_I32);
12419ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            // compute the main result
12420ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            switch (INSN(24,21)) {
12421ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               case BITS4(0,1,0,1): /* ADC */
12422ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  assign(res,
12423ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         binop(Iop_Add32,
12424ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               binop(Iop_Add32, mkexpr(rNt), mkexpr(shop)),
12425ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               mkexpr(oldC) ));
12426ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  break;
12427ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               case BITS4(0,1,1,0): /* SBC */
12428ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  assign(res,
12429ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         binop(Iop_Sub32,
12430ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               binop(Iop_Sub32, mkexpr(rNt), mkexpr(shop)),
12431ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               binop(Iop_Xor32, mkexpr(oldC), mkU32(1)) ));
12432ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  break;
12433ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               case BITS4(0,1,1,1): /* RSC */
12434ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  assign(res,
12435ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         binop(Iop_Sub32,
12436ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               binop(Iop_Sub32, mkexpr(shop), mkexpr(rNt)),
12437ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               binop(Iop_Xor32, mkexpr(oldC), mkU32(1)) ));
12438ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  break;
12439ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               default:
12440ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  vassert(0);
12441ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
12442ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            // but don't commit it until after we've finished
12443ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            // all necessary reads from the guest state
12444ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            // now safe to put the main result
12445ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putIRegA( rD, mkexpr(res), condT, Ijk_Boring );
12446ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            // XXXX!! not safe to read any guest state after
12447ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            // this point (I think the code below doesn't do that).
12448ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (!bitS)
12449ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               vassert(shco == IRTemp_INVALID);
12450ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* Update the flags thunk if necessary */
12451ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (bitS) {
12452ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               vassert(shco != IRTemp_INVALID);
12453ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               switch (INSN(24,21)) {
12454ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case BITS4(0,1,0,1): /* ADC */
12455ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     setFlags_D1_D2_ND( ARMG_CC_OP_ADC,
12456ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                        rNt, shop, oldC, condT );
12457ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
12458ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case BITS4(0,1,1,0): /* SBC */
12459ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     setFlags_D1_D2_ND( ARMG_CC_OP_SBB,
12460ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                        rNt, shop, oldC, condT );
12461ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
12462ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case BITS4(0,1,1,1): /* RSC */
12463ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     setFlags_D1_D2_ND( ARMG_CC_OP_SBB,
12464ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                        shop, rNt, oldC, condT );
12465ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
12466ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  default:
12467ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     vassert(0);
12468ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               }
12469ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
12470ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("%s%s%s r%u, r%u, %s\n",
12471ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                name, nCC(INSN_COND), bitS ? "s" : "", rD, rN, dis_buf );
12472ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto decode_success;
12473ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
12474ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12475ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* --------- ??? --------- */
12476ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         default:
12477ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
12478ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
12479ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } /* if (0 == (INSN(27,20) & BITS8(1,1,0,0,0,0,0,0)) */
12480ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12481ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* --------------------- Load/store (ubyte & word) -------- */
12482ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // LDR STR LDRB STRB
12483ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /*                 31   27   23   19 15 11    6   4 3  # highest bit
12484ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        28   24   20 16 12
12485ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      A5-20   1 | 16  cond 0101 UB0L Rn Rd imm12
12486ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      A5-22   1 | 32  cond 0111 UBOL Rn Rd imm5  sh2 0 Rm
12487ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      A5-24   2 | 16  cond 0101 UB1L Rn Rd imm12
12488ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      A5-26   2 | 32  cond 0111 UB1L Rn Rd imm5  sh2 0 Rm
12489ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      A5-28   3 | 16  cond 0100 UB0L Rn Rd imm12
12490ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      A5-32   3 | 32  cond 0110 UB0L Rn Rd imm5  sh2 0 Rm
12491ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   */
12492ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* case coding:
12493ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             1   at-ea               (access at ea)
12494ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             2   at-ea-then-upd      (access at ea, then Rn = ea)
12495ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             3   at-Rn-then-upd      (access at Rn, then Rn = ea)
12496ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ea coding
12497ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             16  Rn +/- imm12
12498ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             32  Rn +/- Rm sh2 imm5
12499ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   */
12500ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Quickly skip over all of this for hopefully most instructions */
12501ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if ((INSN(27,24) & BITS4(1,1,0,0)) != BITS4(0,1,0,0))
12502ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto after_load_store_ubyte_or_word;
12503ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12504ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   summary = 0;
12505ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12506ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /**/ if (INSN(27,24) == BITS4(0,1,0,1) && INSN(21,21) == 0) {
12507ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      summary = 1 | 16;
12508ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
12509ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else if (INSN(27,24) == BITS4(0,1,1,1) && INSN(21,21) == 0
12510ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                          && INSN(4,4) == 0) {
12511ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      summary = 1 | 32;
12512ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
12513ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else if (INSN(27,24) == BITS4(0,1,0,1) && INSN(21,21) == 1) {
12514ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      summary = 2 | 16;
12515ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
12516ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else if (INSN(27,24) == BITS4(0,1,1,1) && INSN(21,21) == 1
12517ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                          && INSN(4,4) == 0) {
12518ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      summary = 2 | 32;
12519ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
12520ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else if (INSN(27,24) == BITS4(0,1,0,0) && INSN(21,21) == 0) {
12521ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      summary = 3 | 16;
12522ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
12523ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else if (INSN(27,24) == BITS4(0,1,1,0) && INSN(21,21) == 0
12524ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                          && INSN(4,4) == 0) {
12525ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      summary = 3 | 32;
12526ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
12527ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else goto after_load_store_ubyte_or_word;
12528ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12529ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   { UInt rN = (insn >> 16) & 0xF; /* 19:16 */
12530ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     UInt rD = (insn >> 12) & 0xF; /* 15:12 */
12531ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     UInt rM = (insn >> 0)  & 0xF; /*  3:0  */
12532ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     UInt bU = (insn >> 23) & 1;      /* 23 */
12533ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     UInt bB = (insn >> 22) & 1;      /* 22 */
12534ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     UInt bL = (insn >> 20) & 1;      /* 20 */
12535ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     UInt imm12 = (insn >> 0) & 0xFFF; /* 11:0 */
12536ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     UInt imm5  = (insn >> 7) & 0x1F;  /* 11:7 */
12537ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     UInt sh2   = (insn >> 5) & 3;     /* 6:5 */
12538ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12539ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     /* Skip some invalid cases, which would lead to two competing
12540ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        updates to the same register, or which are otherwise
12541ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        disallowed by the spec. */
12542ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     switch (summary) {
12543ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        case 1 | 16:
12544ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           break;
12545ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        case 1 | 32:
12546ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           if (rM == 15) goto after_load_store_ubyte_or_word;
12547ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           break;
12548ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        case 2 | 16: case 3 | 16:
12549ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           if (rN == 15) goto after_load_store_ubyte_or_word;
12550ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           if (bL == 1 && rN == rD) goto after_load_store_ubyte_or_word;
12551ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           break;
12552ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        case 2 | 32: case 3 | 32:
12553ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           if (rM == 15) goto after_load_store_ubyte_or_word;
12554ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           if (rN == 15) goto after_load_store_ubyte_or_word;
12555ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           if (rN == rM) goto after_load_store_ubyte_or_word;
12556ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           if (bL == 1 && rN == rD) goto after_load_store_ubyte_or_word;
12557ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           break;
12558ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        default:
12559ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           vassert(0);
12560ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     }
12561ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12562ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     /* Now, we can't do a conditional load or store, since that very
12563ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        likely will generate an exception.  So we have to take a side
12564ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        exit at this point if the condition is false. */
12565ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     if (condT != IRTemp_INVALID) {
12566ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        mk_skip_over_A32_if_cond_is_false( condT );
12567ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        condT = IRTemp_INVALID;
12568ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     }
12569ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     /* Ok, now we're unconditional.  Do the load or store. */
12570ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12571ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     /* compute the effective address.  Bind it to a tmp since we
12572ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        may need to use it twice. */
12573ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     IRExpr* eaE = NULL;
12574ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     switch (summary & 0xF0) {
12575ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        case 16:
12576ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           eaE = mk_EA_reg_plusminus_imm12( rN, bU, imm12, dis_buf );
12577ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           break;
12578ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        case 32:
12579ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           eaE = mk_EA_reg_plusminus_shifted_reg( rN, bU, rM, sh2, imm5,
12580ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                                  dis_buf );
12581ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           break;
12582ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     }
12583ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     vassert(eaE);
12584ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     IRTemp eaT = newTemp(Ity_I32);
12585ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     assign(eaT, eaE);
12586ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12587ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     /* get the old Rn value */
12588ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     IRTemp rnT = newTemp(Ity_I32);
12589ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     assign(rnT, getIRegA(rN));
12590ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12591ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     /* decide on the transfer address */
12592ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     IRTemp taT = IRTemp_INVALID;
12593ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     switch (summary & 0x0F) {
12594ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        case 1: case 2: taT = eaT; break;
12595ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        case 3:         taT = rnT; break;
12596ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     }
12597ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     vassert(taT != IRTemp_INVALID);
12598ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12599ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     if (bL == 0) {
12600ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       /* Store.  If necessary, update the base register before the
12601ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          store itself, so that the common idiom of "str rX, [sp,
12602ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          #-4]!" (store rX at sp-4, then do new sp = sp-4, a.k.a "push
12603ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          rX") doesn't cause Memcheck to complain that the access is
12604ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          below the stack pointer.  Also, not updating sp before the
12605ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          store confuses Valgrind's dynamic stack-extending logic.  So
12606ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          do it before the store.  Hence we need to snarf the store
12607ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          data before doing the basereg update. */
12608ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12609ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        /* get hold of the data to be stored */
12610ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRTemp rDt = newTemp(Ity_I32);
12611ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        assign(rDt, getIRegA(rD));
12612ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12613ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        /* Update Rn if necessary. */
12614ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        switch (summary & 0x0F) {
12615ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           case 2: case 3:
12616ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              putIRegA( rN, mkexpr(eaT), IRTemp_INVALID, Ijk_Boring );
12617ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              break;
12618ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        }
12619ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12620ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        /* generate the transfer */
12621ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        if (bB == 0) { // word store
12622ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           storeLE( mkexpr(taT), mkexpr(rDt) );
12623ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        } else { // byte store
12624ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           vassert(bB == 1);
12625ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           storeLE( mkexpr(taT), unop(Iop_32to8, mkexpr(rDt)) );
12626ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        }
12627ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12628ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     } else {
12629ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        /* Load */
12630ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        vassert(bL == 1);
12631ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12632ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        /* generate the transfer */
12633ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        if (bB == 0) { // word load
12634b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov           IRTemp jk = Ijk_Boring;
12635b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov           /* According to the Cortex A8 TRM Sec. 5.2.1, LDR(1) with r13 as the
12636b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               base register and PC as the destination register is a return for
12637b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               purposes of branch prediction.
12638b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov              The ARM ARM Sec. C9.10.1 further specifies that it must use a
12639b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               post-increment by immediate addressing mode to be counted in
12640b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               event 0x0E (Procedure return).*/
12641b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov           if (rN == 13 && summary == (3 | 16) && bB == 0) {
12642b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov              jk = Ijk_Ret;
12643b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov           }
12644ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           putIRegA( rD, loadLE(Ity_I32, mkexpr(taT)),
12645b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                     IRTemp_INVALID, jk );
12646ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        } else { // byte load
12647ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           vassert(bB == 1);
12648ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           putIRegA( rD, unop(Iop_8Uto32, loadLE(Ity_I8, mkexpr(taT))),
12649ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     IRTemp_INVALID, Ijk_Boring );
12650ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        }
12651ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12652ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        /* Update Rn if necessary. */
12653ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        switch (summary & 0x0F) {
12654ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           case 2: case 3:
12655ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              // should be assured by logic above:
12656ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              if (bL == 1)
12657ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 vassert(rD != rN); /* since we just wrote rD */
12658ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              putIRegA( rN, mkexpr(eaT), IRTemp_INVALID, Ijk_Boring );
12659ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              break;
12660ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        }
12661ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     }
12662ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12663ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     switch (summary & 0x0F) {
12664ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        case 1:  DIP("%sr%s%s r%u, %s\n",
12665ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     bL == 0 ? "st" : "ld",
12666ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     bB == 0 ? "" : "b", nCC(INSN_COND), rD, dis_buf);
12667ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 break;
12668ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        case 2:  DIP("%sr%s%s r%u, %s! (at-EA-then-Rn=EA)\n",
12669ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     bL == 0 ? "st" : "ld",
12670ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     bB == 0 ? "" : "b", nCC(INSN_COND), rD, dis_buf);
12671ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 break;
12672ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        case 3:  DIP("%sr%s%s r%u, %s! (at-Rn-then-Rn=EA)\n",
12673ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     bL == 0 ? "st" : "ld",
12674ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     bB == 0 ? "" : "b", nCC(INSN_COND), rD, dis_buf);
12675ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 break;
12676ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        default: vassert(0);
12677ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     }
12678ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12679ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     /* XXX deal with alignment constraints */
12680ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12681ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     goto decode_success;
12682ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12683ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     /* Complications:
12684ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12685ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        For all loads: if the Amode specifies base register
12686ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        writeback, and the same register is specified for Rd and Rn,
12687ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        the results are UNPREDICTABLE.
12688ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12689ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        For all loads and stores: if R15 is written, branch to
12690ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        that address afterwards.
12691ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12692ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        STRB: straightforward
12693ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        LDRB: loaded data is zero extended
12694ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        STR:  lowest 2 bits of address are ignored
12695ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        LDR:  if the lowest 2 bits of the address are nonzero
12696ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              then the loaded value is rotated right by 8 * the lowest 2 bits
12697ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     */
12698ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
12699ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12700ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  after_load_store_ubyte_or_word:
12701ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12702ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* --------------------- Load/store (sbyte & hword) -------- */
12703ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // LDRH LDRSH STRH LDRSB
12704ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /*                 31   27   23   19 15 11   7    3     # highest bit
12705ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        28   24   20 16 12    8    4    0
12706ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      A5-36   1 | 16  cond 0001 U10L Rn Rd im4h 1SH1 im4l
12707ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      A5-38   1 | 32  cond 0001 U00L Rn Rd 0000 1SH1 Rm
12708ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      A5-40   2 | 16  cond 0001 U11L Rn Rd im4h 1SH1 im4l
12709ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      A5-42   2 | 32  cond 0001 U01L Rn Rd 0000 1SH1 Rm
12710ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      A5-44   3 | 16  cond 0000 U10L Rn Rd im4h 1SH1 im4l
12711ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      A5-46   3 | 32  cond 0000 U00L Rn Rd 0000 1SH1 Rm
12712ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   */
12713ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* case coding:
12714ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             1   at-ea               (access at ea)
12715ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             2   at-ea-then-upd      (access at ea, then Rn = ea)
12716ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             3   at-Rn-then-upd      (access at Rn, then Rn = ea)
12717ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ea coding
12718ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             16  Rn +/- imm8
12719ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             32  Rn +/- Rm
12720ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   */
12721ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Quickly skip over all of this for hopefully most instructions */
12722ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if ((INSN(27,24) & BITS4(1,1,1,0)) != BITS4(0,0,0,0))
12723ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto after_load_store_sbyte_or_hword;
12724ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12725ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Check the "1SH1" thing. */
12726ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if ((INSN(7,4) & BITS4(1,0,0,1)) != BITS4(1,0,0,1))
12727ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto after_load_store_sbyte_or_hword;
12728ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12729ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   summary = 0;
12730ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12731ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /**/ if (INSN(27,24) == BITS4(0,0,0,1) && INSN(22,21) == BITS2(1,0)) {
12732ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      summary = 1 | 16;
12733ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
12734ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else if (INSN(27,24) == BITS4(0,0,0,1) && INSN(22,21) == BITS2(0,0)) {
12735ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      summary = 1 | 32;
12736ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
12737ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else if (INSN(27,24) == BITS4(0,0,0,1) && INSN(22,21) == BITS2(1,1)) {
12738ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      summary = 2 | 16;
12739ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
12740ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else if (INSN(27,24) == BITS4(0,0,0,1) && INSN(22,21) == BITS2(0,1)) {
12741ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      summary = 2 | 32;
12742ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
12743ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else if (INSN(27,24) == BITS4(0,0,0,0) && INSN(22,21) == BITS2(1,0)) {
12744ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      summary = 3 | 16;
12745ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
12746ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else if (INSN(27,24) == BITS4(0,0,0,0) && INSN(22,21) == BITS2(0,0)) {
12747ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      summary = 3 | 32;
12748ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
12749ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else goto after_load_store_sbyte_or_hword;
12750ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12751ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   { UInt rN   = (insn >> 16) & 0xF; /* 19:16 */
12752ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     UInt rD   = (insn >> 12) & 0xF; /* 15:12 */
12753ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     UInt rM   = (insn >> 0)  & 0xF; /*  3:0  */
12754ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     UInt bU   = (insn >> 23) & 1;   /* 23 U=1 offset+, U=0 offset- */
12755ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     UInt bL   = (insn >> 20) & 1;   /* 20 L=1 load, L=0 store */
12756ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     UInt bH   = (insn >> 5) & 1;    /* H=1 halfword, H=0 byte */
12757ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     UInt bS   = (insn >> 6) & 1;    /* S=1 signed, S=0 unsigned */
12758ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     UInt imm8 = ((insn >> 4) & 0xF0) | (insn & 0xF); /* 11:8, 3:0 */
12759ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12760ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     /* Skip combinations that are either meaningless or already
12761ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        handled by main word-or-unsigned-byte load-store
12762ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        instructions. */
12763ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     if (bS == 0 && bH == 0) /* "unsigned byte" */
12764ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        goto after_load_store_sbyte_or_hword;
12765ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     if (bS == 1 && bL == 0) /* "signed store" */
12766ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        goto after_load_store_sbyte_or_hword;
12767ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12768ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     /* Require 11:8 == 0 for Rn +/- Rm cases */
12769ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     if ((summary & 32) != 0 && (imm8 & 0xF0) != 0)
12770ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        goto after_load_store_sbyte_or_hword;
12771ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12772ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     /* Skip some invalid cases, which would lead to two competing
12773ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        updates to the same register, or which are otherwise
12774ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        disallowed by the spec. */
12775ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     switch (summary) {
12776ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        case 1 | 16:
12777ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           break;
12778ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        case 1 | 32:
12779ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           if (rM == 15) goto after_load_store_sbyte_or_hword;
12780ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           break;
12781ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        case 2 | 16: case 3 | 16:
12782ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           if (rN == 15) goto after_load_store_sbyte_or_hword;
12783ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           if (bL == 1 && rN == rD) goto after_load_store_sbyte_or_hword;
12784ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           break;
12785ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        case 2 | 32: case 3 | 32:
12786ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           if (rM == 15) goto after_load_store_sbyte_or_hword;
12787ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           if (rN == 15) goto after_load_store_sbyte_or_hword;
12788ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           if (rN == rM) goto after_load_store_sbyte_or_hword;
12789ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           if (bL == 1 && rN == rD) goto after_load_store_sbyte_or_hword;
12790ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           break;
12791ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        default:
12792ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           vassert(0);
12793ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     }
12794ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12795ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     /* Now, we can't do a conditional load or store, since that very
12796ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        likely will generate an exception.  So we have to take a side
12797ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        exit at this point if the condition is false. */
12798ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     if (condT != IRTemp_INVALID) {
12799ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        mk_skip_over_A32_if_cond_is_false( condT );
12800ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        condT = IRTemp_INVALID;
12801ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     }
12802ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     /* Ok, now we're unconditional.  Do the load or store. */
12803ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12804ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     /* compute the effective address.  Bind it to a tmp since we
12805ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        may need to use it twice. */
12806ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     IRExpr* eaE = NULL;
12807ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     switch (summary & 0xF0) {
12808ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        case 16:
12809ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           eaE = mk_EA_reg_plusminus_imm8( rN, bU, imm8, dis_buf );
12810ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           break;
12811ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        case 32:
12812ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           eaE = mk_EA_reg_plusminus_reg( rN, bU, rM, dis_buf );
12813ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           break;
12814ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     }
12815ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     vassert(eaE);
12816ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     IRTemp eaT = newTemp(Ity_I32);
12817ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     assign(eaT, eaE);
12818ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12819ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     /* get the old Rn value */
12820ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     IRTemp rnT = newTemp(Ity_I32);
12821ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     assign(rnT, getIRegA(rN));
12822ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12823ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     /* decide on the transfer address */
12824ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     IRTemp taT = IRTemp_INVALID;
12825ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     switch (summary & 0x0F) {
12826ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        case 1: case 2: taT = eaT; break;
12827ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        case 3:         taT = rnT; break;
12828ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     }
12829ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     vassert(taT != IRTemp_INVALID);
12830ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12831ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     /* halfword store  H 1  L 0  S 0
12832ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        uhalf load      H 1  L 1  S 0
12833ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        shalf load      H 1  L 1  S 1
12834ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        sbyte load      H 0  L 1  S 1
12835ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     */
12836ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     HChar* name = NULL;
12837ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     /* generate the transfer */
12838ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     /**/ if (bH == 1 && bL == 0 && bS == 0) { // halfword store
12839ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        storeLE( mkexpr(taT), unop(Iop_32to16, getIRegA(rD)) );
12840ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        name = "strh";
12841ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     }
12842ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     else if (bH == 1 && bL == 1 && bS == 0) { // uhalf load
12843ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        putIRegA( rD, unop(Iop_16Uto32, loadLE(Ity_I16, mkexpr(taT))),
12844ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  IRTemp_INVALID, Ijk_Boring );
12845ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        name = "ldrh";
12846ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     }
12847ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     else if (bH == 1 && bL == 1 && bS == 1) { // shalf load
12848ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        putIRegA( rD, unop(Iop_16Sto32, loadLE(Ity_I16, mkexpr(taT))),
12849ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  IRTemp_INVALID, Ijk_Boring );
12850ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        name = "ldrsh";
12851ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     }
12852ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     else if (bH == 0 && bL == 1 && bS == 1) { // sbyte load
12853ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        putIRegA( rD, unop(Iop_8Sto32, loadLE(Ity_I8, mkexpr(taT))),
12854ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  IRTemp_INVALID, Ijk_Boring );
12855ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        name = "ldrsb";
12856ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     }
12857ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     else
12858ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        vassert(0); // should be assured by logic above
12859ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12860ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     /* Update Rn if necessary. */
12861ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     switch (summary & 0x0F) {
12862ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        case 2: case 3:
12863ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           // should be assured by logic above:
12864ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           if (bL == 1)
12865ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              vassert(rD != rN); /* since we just wrote rD */
12866ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           putIRegA( rN, mkexpr(eaT), IRTemp_INVALID, Ijk_Boring );
12867ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           break;
12868ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     }
12869ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12870ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     switch (summary & 0x0F) {
12871ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        case 1:  DIP("%s%s r%u, %s\n", name, nCC(INSN_COND), rD, dis_buf);
12872ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 break;
12873ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        case 2:  DIP("%s%s r%u, %s! (at-EA-then-Rn=EA)\n",
12874ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     name, nCC(INSN_COND), rD, dis_buf);
12875ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 break;
12876ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        case 3:  DIP("%s%s r%u, %s! (at-Rn-then-Rn=EA)\n",
12877ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     name, nCC(INSN_COND), rD, dis_buf);
12878ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 break;
12879ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        default: vassert(0);
12880ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     }
12881ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12882ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     /* XXX deal with alignment constraints */
12883ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12884ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     goto decode_success;
12885ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12886ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     /* Complications:
12887ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12888ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        For all loads: if the Amode specifies base register
12889ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        writeback, and the same register is specified for Rd and Rn,
12890ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        the results are UNPREDICTABLE.
12891ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12892ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        For all loads and stores: if R15 is written, branch to
12893ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        that address afterwards.
12894ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12895ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        Misaligned halfword stores => Unpredictable
12896ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        Misaligned halfword loads  => Unpredictable
12897ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     */
12898ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
12899ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12900ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  after_load_store_sbyte_or_hword:
12901ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12902ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* --------------------- Load/store multiple -------------- */
12903ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // LD/STMIA LD/STMIB LD/STMDA LD/STMDB
12904ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Remarkably complex and difficult to get right
12905ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // match 27:20 as 100XX0WL
12906ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (BITS8(1,0,0,0,0,0,0,0) == (INSN(27,20) & BITS8(1,1,1,0,0,1,0,0))) {
12907ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // A5-50 LD/STMIA  cond 1000 10WL Rn RegList
12908ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // A5-51 LD/STMIB  cond 1001 10WL Rn RegList
12909ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // A5-53 LD/STMDA  cond 1000 00WL Rn RegList
12910ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // A5-53 LD/STMDB  cond 1001 00WL Rn RegList
12911ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      //                   28   24   20 16       0
12912ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12913ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt bINC    = (insn >> 23) & 1;
12914ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt bBEFORE = (insn >> 24) & 1;
12915ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12916ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt bL      = (insn >> 20) & 1;  /* load=1, store=0 */
12917ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt bW      = (insn >> 21) & 1;  /* Rn wback=1, no wback=0 */
12918ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rN      = (insn >> 16) & 0xF;
12919ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt regList = insn & 0xFFFF;
12920ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Skip some invalid cases, which would lead to two competing
12921ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         updates to the same register, or which are otherwise
12922ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         disallowed by the spec.  Note the test above has required
12923ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         that S == 0, since that looks like a kernel-mode only thing.
12924ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Done by forcing the real pattern, viz 100XXSWL to actually be
12925ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         100XX0WL. */
12926ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (rN == 15) goto after_load_store_multiple;
12927ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // reglist can't be empty
12928ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (regList == 0) goto after_load_store_multiple;
12929ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // if requested to writeback Rn, and this is a load instruction,
12930ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // then Rn can't appear in RegList, since we'd have two competing
12931ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // new values for Rn.  We do however accept this case for store
12932ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // instructions.
12933ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (bW == 1 && bL == 1 && ((1 << rN) & regList) > 0)
12934ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto after_load_store_multiple;
12935ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12936ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Now, we can't do a conditional load or store, since that very
12937ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         likely will generate an exception.  So we have to take a side
12938ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         exit at this point if the condition is false. */
12939ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (condT != IRTemp_INVALID) {
12940ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         mk_skip_over_A32_if_cond_is_false( condT );
12941ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         condT = IRTemp_INVALID;
12942ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
12943ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12944ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Ok, now we're unconditional.  Generate the IR. */
12945ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      mk_ldm_stm( True/*arm*/, rN, bINC, bBEFORE, bW, bL, regList );
12946ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12947ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("%sm%c%c%s r%u%s, {0x%04x}\n",
12948ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          bL == 1 ? "ld" : "st", bINC ? 'i' : 'd', bBEFORE ? 'b' : 'a',
12949ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          nCC(INSN_COND),
12950ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          rN, bW ? "!" : "", regList);
12951ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12952ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
12953ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
12954ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12955ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  after_load_store_multiple:
12956ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12957ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* --------------------- Control flow --------------------- */
12958ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // B, BL (Branch, or Branch-and-Link, to immediate offset)
12959ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   //
12960ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (BITS8(1,0,1,0,0,0,0,0) == (INSN(27,20) & BITS8(1,1,1,0,0,0,0,0))) {
12961ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt link   = (insn >> 24) & 1;
12962ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt uimm24 = insn & ((1<<24)-1);
12963ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Int  simm24 = (Int)uimm24;
12964ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt dst    = guest_R15_curr_instr_notENC + 8
12965ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    + (((simm24 << 8) >> 8) << 2);
12966ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRJumpKind jk = link ? Ijk_Call : Ijk_Boring;
12967ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (link) {
12968ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIRegA(14, mkU32(guest_R15_curr_instr_notENC + 4),
12969ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      condT, Ijk_Boring);
12970ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
12971ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (condT == IRTemp_INVALID) {
12972ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* unconditional transfer to 'dst'.  See if we can simply
12973ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            continue tracing at the destination. */
12974ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (resteerOkFn( callback_opaque, (Addr64)dst )) {
12975ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* yes */
12976ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            dres.whatNext   = Dis_ResteerU;
12977ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            dres.continueAt = (Addr64)dst;
12978ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
12979ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* no; terminate the SB at this point. */
12980ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            irsb->next     = mkU32(dst);
12981ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            irsb->jumpkind = jk;
12982ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            dres.whatNext  = Dis_StopHere;
12983ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
12984ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("b%s 0x%x\n", link ? "l" : "", dst);
12985ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
12986ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* conditional transfer to 'dst' */
12987ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         HChar* comment = "";
12988ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12989ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* First see if we can do some speculative chasing into one
12990ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            arm or the other.  Be conservative and only chase if
12991ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            !link, that is, this is a normal conditional branch to a
12992ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            known destination. */
12993ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (!link
12994ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             && resteerCisOk
12995ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             && vex_control.guest_chase_cond
12996ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             && dst < guest_R15_curr_instr_notENC
12997ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             && resteerOkFn( callback_opaque, (Addr64)(Addr32)dst) ) {
12998ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* Speculation: assume this backward branch is taken.  So
12999ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               we need to emit a side-exit to the insn following this
13000ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               one, on the negation of the condition, and continue at
13001ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               the branch target address (dst). */
13002ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            stmt( IRStmt_Exit( unop(Iop_Not1,
13003ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    unop(Iop_32to1, mkexpr(condT))),
13004ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               Ijk_Boring,
13005ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               IRConst_U32(guest_R15_curr_instr_notENC+4) ));
13006ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            dres.whatNext   = Dis_ResteerC;
13007ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            dres.continueAt = (Addr64)(Addr32)dst;
13008ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            comment = "(assumed taken)";
13009ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
13010ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         else
13011ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (!link
13012ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             && resteerCisOk
13013ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             && vex_control.guest_chase_cond
13014ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             && dst >= guest_R15_curr_instr_notENC
13015ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             && resteerOkFn( callback_opaque,
13016ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             (Addr64)(Addr32)
13017ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                     (guest_R15_curr_instr_notENC+4)) ) {
13018ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* Speculation: assume this forward branch is not taken.
13019ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               So we need to emit a side-exit to dst (the dest) and
13020ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               continue disassembling at the insn immediately
13021ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               following this one. */
13022ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            stmt( IRStmt_Exit( unop(Iop_32to1, mkexpr(condT)),
13023ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               Ijk_Boring,
13024ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               IRConst_U32(dst) ));
13025ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            dres.whatNext   = Dis_ResteerC;
13026ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            dres.continueAt = (Addr64)(Addr32)
13027ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                      (guest_R15_curr_instr_notENC+4);
13028ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            comment = "(assumed not taken)";
13029ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
13030ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         else {
13031ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* Conservative default translation - end the block at
13032ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               this point. */
13033ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            stmt( IRStmt_Exit( unop(Iop_32to1, mkexpr(condT)),
13034ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               jk, IRConst_U32(dst) ));
13035ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            irsb->next     = mkU32(guest_R15_curr_instr_notENC + 4);
13036b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            irsb->jumpkind = Ijk_Boring;
13037ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            dres.whatNext  = Dis_StopHere;
13038ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
13039ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("b%s%s 0x%x %s\n", link ? "l" : "", nCC(INSN_COND),
13040ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             dst, comment);
13041ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
13042ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
13043ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
13044ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13045ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // B, BL (Branch, or Branch-and-Link, to a register)
13046ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // NB: interworking branch
13047ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (INSN(27,20) == BITS8(0,0,0,1,0,0,1,0)
13048ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && INSN(19,12) == BITS8(1,1,1,1,1,1,1,1)
13049ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && (INSN(11,4) == BITS8(1,1,1,1,0,0,1,1)
13050ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           || INSN(11,4) == BITS8(1,1,1,1,0,0,0,1))) {
13051b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      IRTemp  dst = newTemp(Ity_I32);
13052ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt    link = (INSN(11,4) >> 1) & 1;
13053ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt    rM   = INSN(3,0);
13054ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // we don't decode the case (link && rM == 15), as that's
13055ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // Unpredictable.
13056ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!(link && rM == 15)) {
13057ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (condT != IRTemp_INVALID) {
13058ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            mk_skip_over_A32_if_cond_is_false( condT );
13059ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
13060ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // rM contains an interworking address exactly as we require
13061ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // (with continuation CPSR.T in bit 0), so we can use it
13062ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // as-is, with no masking.
13063b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         assign( dst, getIRegA(rM) );
13064ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (link) {
13065ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putIRegA( 14, mkU32(guest_R15_curr_instr_notENC + 4),
13066ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      IRTemp_INVALID/*because AL*/, Ijk_Boring );
13067ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
13068b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         irsb->next     = mkexpr(dst);
13069ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         irsb->jumpkind = link ? Ijk_Call
13070ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               : (rM == 14 ? Ijk_Ret : Ijk_Boring);
13071ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         dres.whatNext  = Dis_StopHere;
13072ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (condT == IRTemp_INVALID) {
13073ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("b%sx r%u\n", link ? "l" : "", rM);
13074ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
13075ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("b%sx%s r%u\n", link ? "l" : "", nCC(INSN_COND), rM);
13076ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
13077ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
13078ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
13079ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* else: (link && rM == 15): just fall through */
13080ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
13081ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13082ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* --- NB: ARM interworking branches are in NV space, hence
13083ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      are handled elsewhere by decode_NV_instruction.
13084ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ---
13085ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   */
13086ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13087ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* --------------------- Clz --------------------- */
13088ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // CLZ
13089ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (INSN(27,20) == BITS8(0,0,0,1,0,1,1,0)
13090ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && INSN(19,16) == BITS4(1,1,1,1)
13091ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && INSN(11,4) == BITS8(1,1,1,1,0,0,0,1)) {
13092ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rD = INSN(15,12);
13093ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rM = INSN(3,0);
13094ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp arg = newTemp(Ity_I32);
13095ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp res = newTemp(Ity_I32);
13096ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(arg, getIRegA(rM));
13097ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(res, IRExpr_Mux0X(
13098ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     unop(Iop_1Uto8,binop(Iop_CmpEQ32, mkexpr(arg),
13099ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                                       mkU32(0))),
13100ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     unop(Iop_Clz32, mkexpr(arg)),
13101ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     mkU32(32)
13102ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            ));
13103ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIRegA(rD, mkexpr(res), condT, Ijk_Boring);
13104ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("clz%s r%u, r%u\n", nCC(INSN_COND), rD, rM);
13105ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
13106ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
13107ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13108ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* --------------------- Mul etc --------------------- */
13109ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // MUL
13110ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (BITS8(0,0,0,0,0,0,0,0) == (INSN(27,20) & BITS8(1,1,1,1,1,1,1,0))
13111ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && INSN(15,12) == BITS4(0,0,0,0)
13112ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && INSN(7,4) == BITS4(1,0,0,1)) {
13113ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt bitS = (insn >> 20) & 1; /* 20:20 */
13114ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rD = INSN(19,16);
13115ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rS = INSN(11,8);
13116ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rM = INSN(3,0);
13117ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (rD == 15 || rM == 15 || rS == 15) {
13118ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Unpredictable; don't decode; fall through */
13119ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
13120ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp argL = newTemp(Ity_I32);
13121ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp argR = newTemp(Ity_I32);
13122ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp res  = newTemp(Ity_I32);
13123ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp oldC = IRTemp_INVALID;
13124ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp oldV = IRTemp_INVALID;
13125ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( argL, getIRegA(rM));
13126ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( argR, getIRegA(rS));
13127ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( res, binop(Iop_Mul32, mkexpr(argL), mkexpr(argR)) );
13128ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (bitS) {
13129ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            oldC = newTemp(Ity_I32);
13130ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(oldC, mk_armg_calculate_flag_c());
13131ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            oldV = newTemp(Ity_I32);
13132ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(oldV, mk_armg_calculate_flag_v());
13133ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
13134ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // now update guest state
13135ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIRegA( rD, mkexpr(res), condT, Ijk_Boring );
13136ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (bitS) {
13137ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            IRTemp pair = newTemp(Ity_I32);
13138ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign( pair, binop(Iop_Or32,
13139ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                binop(Iop_Shl32, mkexpr(oldC), mkU8(1)),
13140ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                mkexpr(oldV)) );
13141ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            setFlags_D1_ND( ARMG_CC_OP_MUL, res, pair, condT );
13142ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
13143ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("mul%c%s r%u, r%u, r%u\n",
13144ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             bitS ? 's' : ' ', nCC(INSN_COND), rD, rM, rS);
13145ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
13146ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
13147ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* fall through */
13148ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
13149ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13150ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // MLA, MLS
13151ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (BITS8(0,0,0,0,0,0,1,0) == (INSN(27,20) & BITS8(1,1,1,1,1,0,1,0))
13152ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && INSN(7,4) == BITS4(1,0,0,1)) {
13153ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt bitS  = (insn >> 20) & 1; /* 20:20 */
13154ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt isMLS = (insn >> 22) & 1; /* 22:22 */
13155ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rD = INSN(19,16);
13156ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rN = INSN(15,12);
13157ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rS = INSN(11,8);
13158ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rM = INSN(3,0);
13159ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (bitS == 1 && isMLS == 1) {
13160ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* This isn't allowed (MLS that sets flags).  don't decode;
13161ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            fall through */
13162ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
13163ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      else
13164ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (rD == 15 || rM == 15 || rS == 15 || rN == 15) {
13165ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Unpredictable; don't decode; fall through */
13166ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
13167ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp argL = newTemp(Ity_I32);
13168ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp argR = newTemp(Ity_I32);
13169ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp argP = newTemp(Ity_I32);
13170ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp res  = newTemp(Ity_I32);
13171ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp oldC = IRTemp_INVALID;
13172ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp oldV = IRTemp_INVALID;
13173ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( argL, getIRegA(rM));
13174ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( argR, getIRegA(rS));
13175ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( argP, getIRegA(rN));
13176ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( res, binop(isMLS ? Iop_Sub32 : Iop_Add32,
13177ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            mkexpr(argP),
13178ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            binop(Iop_Mul32, mkexpr(argL), mkexpr(argR)) ));
13179ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (bitS) {
13180ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            vassert(!isMLS); // guaranteed above
13181ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            oldC = newTemp(Ity_I32);
13182ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(oldC, mk_armg_calculate_flag_c());
13183ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            oldV = newTemp(Ity_I32);
13184ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(oldV, mk_armg_calculate_flag_v());
13185ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
13186ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // now update guest state
13187ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIRegA( rD, mkexpr(res), condT, Ijk_Boring );
13188ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (bitS) {
13189ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            IRTemp pair = newTemp(Ity_I32);
13190ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign( pair, binop(Iop_Or32,
13191ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                binop(Iop_Shl32, mkexpr(oldC), mkU8(1)),
13192ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                mkexpr(oldV)) );
13193ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            setFlags_D1_ND( ARMG_CC_OP_MUL, res, pair, condT );
13194ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
13195ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("ml%c%c%s r%u, r%u, r%u, r%u\n",
13196ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             isMLS ? 's' : 'a', bitS ? 's' : ' ',
13197ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             nCC(INSN_COND), rD, rM, rS, rN);
13198ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
13199ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
13200ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* fall through */
13201ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
13202ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13203ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // SMULL, UMULL
13204ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (BITS8(0,0,0,0,1,0,0,0) == (INSN(27,20) & BITS8(1,1,1,1,1,0,1,0))
13205ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && INSN(7,4) == BITS4(1,0,0,1)) {
13206ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt bitS = (insn >> 20) & 1; /* 20:20 */
13207ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rDhi = INSN(19,16);
13208ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rDlo = INSN(15,12);
13209ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rS   = INSN(11,8);
13210ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rM   = INSN(3,0);
13211ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt isS  = (INSN(27,20) >> 2) & 1; /* 22:22 */
13212ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (rDhi == 15 || rDlo == 15 || rM == 15 || rS == 15 || rDhi == rDlo)  {
13213ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Unpredictable; don't decode; fall through */
13214ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
13215ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp argL  = newTemp(Ity_I32);
13216ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp argR  = newTemp(Ity_I32);
13217ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp res   = newTemp(Ity_I64);
13218ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp resHi = newTemp(Ity_I32);
13219ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp resLo = newTemp(Ity_I32);
13220ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp oldC  = IRTemp_INVALID;
13221ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp oldV  = IRTemp_INVALID;
13222ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IROp   mulOp = isS ? Iop_MullS32 : Iop_MullU32;
13223ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( argL, getIRegA(rM));
13224ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( argR, getIRegA(rS));
13225ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( res, binop(mulOp, mkexpr(argL), mkexpr(argR)) );
13226ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( resHi, unop(Iop_64HIto32, mkexpr(res)) );
13227ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( resLo, unop(Iop_64to32, mkexpr(res)) );
13228ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (bitS) {
13229ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            oldC = newTemp(Ity_I32);
13230ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(oldC, mk_armg_calculate_flag_c());
13231ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            oldV = newTemp(Ity_I32);
13232ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(oldV, mk_armg_calculate_flag_v());
13233ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
13234ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // now update guest state
13235ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIRegA( rDhi, mkexpr(resHi), condT, Ijk_Boring );
13236ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIRegA( rDlo, mkexpr(resLo), condT, Ijk_Boring );
13237ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (bitS) {
13238ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            IRTemp pair = newTemp(Ity_I32);
13239ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign( pair, binop(Iop_Or32,
13240ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                binop(Iop_Shl32, mkexpr(oldC), mkU8(1)),
13241ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                mkexpr(oldV)) );
13242ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            setFlags_D1_D2_ND( ARMG_CC_OP_MULL, resLo, resHi, pair, condT );
13243ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
13244ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("%cmull%c%s r%u, r%u, r%u, r%u\n",
13245ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             isS ? 's' : 'u', bitS ? 's' : ' ',
13246ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             nCC(INSN_COND), rDlo, rDhi, rM, rS);
13247ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
13248ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
13249ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* fall through */
13250ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
13251ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13252ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // SMLAL, UMLAL
13253ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (BITS8(0,0,0,0,1,0,1,0) == (INSN(27,20) & BITS8(1,1,1,1,1,0,1,0))
13254ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && INSN(7,4) == BITS4(1,0,0,1)) {
13255ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt bitS = (insn >> 20) & 1; /* 20:20 */
13256ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rDhi = INSN(19,16);
13257ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rDlo = INSN(15,12);
13258ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rS   = INSN(11,8);
13259ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rM   = INSN(3,0);
13260ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt isS  = (INSN(27,20) >> 2) & 1; /* 22:22 */
13261ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (rDhi == 15 || rDlo == 15 || rM == 15 || rS == 15 || rDhi == rDlo)  {
13262ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Unpredictable; don't decode; fall through */
13263ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
13264ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp argL  = newTemp(Ity_I32);
13265ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp argR  = newTemp(Ity_I32);
13266ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp old   = newTemp(Ity_I64);
13267ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp res   = newTemp(Ity_I64);
13268ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp resHi = newTemp(Ity_I32);
13269ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp resLo = newTemp(Ity_I32);
13270ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp oldC  = IRTemp_INVALID;
13271ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp oldV  = IRTemp_INVALID;
13272ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IROp   mulOp = isS ? Iop_MullS32 : Iop_MullU32;
13273ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( argL, getIRegA(rM));
13274ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( argR, getIRegA(rS));
13275ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( old, binop(Iop_32HLto64, getIRegA(rDhi), getIRegA(rDlo)) );
13276ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( res, binop(Iop_Add64,
13277ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            mkexpr(old),
13278ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            binop(mulOp, mkexpr(argL), mkexpr(argR))) );
13279ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( resHi, unop(Iop_64HIto32, mkexpr(res)) );
13280ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( resLo, unop(Iop_64to32, mkexpr(res)) );
13281ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (bitS) {
13282ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            oldC = newTemp(Ity_I32);
13283ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(oldC, mk_armg_calculate_flag_c());
13284ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            oldV = newTemp(Ity_I32);
13285ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(oldV, mk_armg_calculate_flag_v());
13286ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
13287ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // now update guest state
13288ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIRegA( rDhi, mkexpr(resHi), condT, Ijk_Boring );
13289ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIRegA( rDlo, mkexpr(resLo), condT, Ijk_Boring );
13290ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (bitS) {
13291ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            IRTemp pair = newTemp(Ity_I32);
13292ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign( pair, binop(Iop_Or32,
13293ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                binop(Iop_Shl32, mkexpr(oldC), mkU8(1)),
13294ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                mkexpr(oldV)) );
13295ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            setFlags_D1_D2_ND( ARMG_CC_OP_MULL, resLo, resHi, pair, condT );
13296ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
13297ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("%cmlal%c%s r%u, r%u, r%u, r%u\n",
13298ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             isS ? 's' : 'u', bitS ? 's' : ' ', nCC(INSN_COND),
13299ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             rDlo, rDhi, rM, rS);
13300ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
13301ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
13302ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* fall through */
13303ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
13304ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13305ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* --------------------- Msr etc --------------------- */
13306ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13307ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // MSR apsr, #imm
13308ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (INSN(27,20) == BITS8(0,0,1,1,0,0,1,0)
13309ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && INSN(17,12) == BITS6(0,0,1,1,1,1)) {
13310ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt write_ge    = INSN(18,18);
13311ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt write_nzcvq = INSN(19,19);
13312ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (write_nzcvq || write_ge) {
13313ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         UInt   imm = (INSN(11,0) >> 0) & 0xFF;
13314ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         UInt   rot = 2 * ((INSN(11,0) >> 8) & 0xF);
13315ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp immT = newTemp(Ity_I32);
13316ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vassert(rot <= 30);
13317ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         imm = ROR32(imm, rot);
13318ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(immT, mkU32(imm));
13319ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         desynthesise_APSR( write_nzcvq, write_ge, immT, condT );
13320ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("msr%s cpsr%s%sf, #0x%08x\n", nCC(INSN_COND),
13321ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             write_nzcvq ? "f" : "", write_ge ? "g" : "", imm);
13322ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
13323ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
13324ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* fall through */
13325ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
13326ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13327ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // MSR apsr, reg
13328ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (INSN(27,20) == BITS8(0,0,0,1,0,0,1,0)
13329ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && INSN(17,12) == BITS6(0,0,1,1,1,1)
13330ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && INSN(11,4) == BITS8(0,0,0,0,0,0,0,0)) {
13331ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rN          = INSN(3,0);
13332ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt write_ge    = INSN(18,18);
13333ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt write_nzcvq = INSN(19,19);
13334ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (rN != 15 && (write_nzcvq || write_ge)) {
13335ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp rNt = newTemp(Ity_I32);
13336ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(rNt, getIRegA(rN));
13337ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         desynthesise_APSR( write_nzcvq, write_ge, rNt, condT );
13338ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("msr%s cpsr_%s%s, r%u\n", nCC(INSN_COND),
13339ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             write_nzcvq ? "f" : "", write_ge ? "g" : "", rN);
13340ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
13341ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
13342ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* fall through */
13343ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
13344ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13345ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // MRS rD, cpsr
13346ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if ((insn & 0x0FFF0FFF) == 0x010F0000) {
13347ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rD   = INSN(15,12);
13348ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (rD != 15) {
13349ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp apsr = synthesise_APSR();
13350ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIRegA( rD, mkexpr(apsr), condT, Ijk_Boring );
13351ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("mrs%s r%u, cpsr\n", nCC(INSN_COND), rD);
13352ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
13353ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
13354ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* fall through */
13355ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
13356ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13357ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* --------------------- Svc --------------------- */
13358ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (BITS8(1,1,1,1,0,0,0,0) == (INSN(27,20) & BITS8(1,1,1,1,0,0,0,0))) {
13359ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt imm24 = (insn >> 0) & 0xFFFFFF;
13360ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (imm24 == 0) {
13361ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* A syscall.  We can't do this conditionally, hence: */
13362ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (condT != IRTemp_INVALID) {
13363ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            mk_skip_over_A32_if_cond_is_false( condT );
13364ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
13365ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // AL after here
13366ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         irsb->next     = mkU32( guest_R15_curr_instr_notENC + 4 );
13367ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         irsb->jumpkind = Ijk_Sys_syscall;
13368ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         dres.whatNext  = Dis_StopHere;
13369ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("svc%s #0x%08x\n", nCC(INSN_COND), imm24);
13370ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
13371ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
13372ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* fall through */
13373ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
13374ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13375ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ------------------------ swp ------------------------ */
13376ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13377ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // SWP, SWPB
13378ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (BITS8(0,0,0,1,0,0,0,0) == (INSN(27,20) & BITS8(1,1,1,1,1,0,1,1))
13379ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && BITS4(0,0,0,0) == INSN(11,8)
13380ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && BITS4(1,0,0,1) == INSN(7,4)) {
13381ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt   rN   = INSN(19,16);
13382ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt   rD   = INSN(15,12);
13383ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt   rM   = INSN(3,0);
13384ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp tRn  = newTemp(Ity_I32);
13385ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp tNew = newTemp(Ity_I32);
13386ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp tOld = IRTemp_INVALID;
13387ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp tSC1 = newTemp(Ity_I1);
13388ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt   isB  = (insn >> 22) & 1;
13389ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13390ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (rD == 15 || rN == 15 || rM == 15 || rN == rM || rN == rD) {
13391ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* undecodable; fall through */
13392ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
13393ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* make unconditional */
13394ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (condT != IRTemp_INVALID) {
13395ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            mk_skip_over_A32_if_cond_is_false( condT );
13396ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            condT = IRTemp_INVALID;
13397ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
13398ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Ok, now we're unconditional.  Generate a LL-SC loop. */
13399ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(tRn, getIRegA(rN));
13400ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(tNew, getIRegA(rM));
13401ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (isB) {
13402ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* swpb */
13403ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            tOld = newTemp(Ity_I8);
13404ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            stmt( IRStmt_LLSC(Iend_LE, tOld, mkexpr(tRn),
13405ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              NULL/*=>isLL*/) );
13406ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            stmt( IRStmt_LLSC(Iend_LE, tSC1, mkexpr(tRn),
13407ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              unop(Iop_32to8, mkexpr(tNew))) );
13408ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
13409ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* swp */
13410ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            tOld = newTemp(Ity_I32);
13411ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            stmt( IRStmt_LLSC(Iend_LE, tOld, mkexpr(tRn),
13412ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              NULL/*=>isLL*/) );
13413ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            stmt( IRStmt_LLSC(Iend_LE, tSC1, mkexpr(tRn),
13414ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              mkexpr(tNew)) );
13415ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
13416ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         stmt( IRStmt_Exit(unop(Iop_Not1, mkexpr(tSC1)),
13417ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           /*Ijk_NoRedir*/Ijk_Boring,
13418ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           IRConst_U32(guest_R15_curr_instr_notENC)) );
13419ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIRegA(rD, isB ? unop(Iop_8Uto32, mkexpr(tOld)) : mkexpr(tOld),
13420ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      IRTemp_INVALID, Ijk_Boring);
13421ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("swp%s%s r%u, r%u, [r%u]\n",
13422ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             isB ? "b" : "", nCC(INSN_COND), rD, rM, rN);
13423ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
13424ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
13425ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* fall through */
13426ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
13427ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13428ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ----------------------------------------------------------- */
13429ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* -- ARMv6 instructions                                    -- */
13430ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ----------------------------------------------------------- */
13431ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13432b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   /* ------------------- {ldr,str}ex{,b,h,d} ------------------- */
13433b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
13434b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   // LDREXD, LDREX, LDREXH, LDREXB
13435b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   if (0x01900F9F == (insn & 0x0F900FFF)) {
13436b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      UInt   rT    = INSN(15,12);
13437b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      UInt   rN    = INSN(19,16);
13438b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      IRType ty    = Ity_INVALID;
13439b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      IROp   widen = Iop_INVALID;
13440b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      HChar* nm    = NULL;
13441b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      Bool   valid = True;
13442b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      switch (INSN(22,21)) {
13443b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         case 0: nm = "";  ty = Ity_I32; break;
13444b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         case 1: nm = "d"; ty = Ity_I64; break;
13445b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         case 2: nm = "b"; ty = Ity_I8;  widen = Iop_8Uto32; break;
13446b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         case 3: nm = "h"; ty = Ity_I16; widen = Iop_16Uto32; break;
13447b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         default: vassert(0);
13448b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      }
13449b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      if (ty == Ity_I32 || ty == Ity_I16 || ty == Ity_I8) {
13450b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         if (rT == 15 || rN == 15)
13451b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            valid = False;
13452ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
13453b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         vassert(ty == Ity_I64);
13454b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         if ((rT & 1) == 1 || rT == 14 || rN == 15)
13455b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            valid = False;
13456b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      }
13457b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      if (valid) {
13458ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp res;
13459ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* make unconditional */
13460ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (condT != IRTemp_INVALID) {
13461b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov           mk_skip_over_A32_if_cond_is_false( condT );
13462b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov           condT = IRTemp_INVALID;
13463ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
13464ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Ok, now we're unconditional.  Do the load. */
13465b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         res = newTemp(ty);
13466b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         // FIXME: assumes little-endian guest
13467ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         stmt( IRStmt_LLSC(Iend_LE, res, getIRegA(rN),
13468ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           NULL/*this is a load*/) );
13469b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         if (ty == Ity_I64) {
13470b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            // FIXME: assumes little-endian guest
13471b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            putIRegA(rT+0, unop(Iop_64to32, mkexpr(res)),
13472b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                           IRTemp_INVALID, Ijk_Boring);
13473b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            putIRegA(rT+1, unop(Iop_64HIto32, mkexpr(res)),
13474b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                           IRTemp_INVALID, Ijk_Boring);
13475b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            DIP("ldrex%s%s r%u, r%u, [r%u]\n",
13476b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                nm, nCC(INSN_COND), rT+0, rT+1, rN);
13477b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         } else {
13478b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            putIRegA(rT, widen == Iop_INVALID
13479b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                            ? mkexpr(res) : unop(widen, mkexpr(res)),
13480b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                     IRTemp_INVALID, Ijk_Boring);
13481b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            DIP("ldrex%s%s r%u, [r%u]\n", nm, nCC(INSN_COND), rT, rN);
13482b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         }
13483ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
13484ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
13485b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      /* undecodable; fall through */
13486ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
13487ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13488b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   // STREXD, STREX, STREXH, STREXB
13489b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   if (0x01800F90 == (insn & 0x0F900FF0)) {
13490b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      UInt   rT     = INSN(3,0);
13491b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      UInt   rN     = INSN(19,16);
13492b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      UInt   rD     = INSN(15,12);
13493b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      IRType ty     = Ity_INVALID;
13494b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      IROp   narrow = Iop_INVALID;
13495b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      HChar* nm     = NULL;
13496b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      Bool   valid  = True;
13497b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      switch (INSN(22,21)) {
13498b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         case 0: nm = "";  ty = Ity_I32; break;
13499b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         case 1: nm = "d"; ty = Ity_I64; break;
13500b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         case 2: nm = "b"; ty = Ity_I8;  narrow = Iop_32to8; break;
13501b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         case 3: nm = "h"; ty = Ity_I16; narrow = Iop_32to16; break;
13502b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         default: vassert(0);
13503b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      }
13504b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      if (ty == Ity_I32 || ty == Ity_I16 || ty == Ity_I8) {
13505b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         if (rD == 15 || rN == 15 || rT == 15
13506b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov             || rD == rN || rD == rT)
13507b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            valid = False;
13508ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
13509b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         vassert(ty == Ity_I64);
13510b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         if (rD == 15 || (rT & 1) == 1 || rT == 14 || rN == 15
13511b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov             || rD == rN || rD == rT || rD == rT+1)
13512b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            valid = False;
13513b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      }
13514b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      if (valid) {
13515b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         IRTemp resSC1, resSC32, data;
13516ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* make unconditional */
13517ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (condT != IRTemp_INVALID) {
13518ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            mk_skip_over_A32_if_cond_is_false( condT );
13519ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            condT = IRTemp_INVALID;
13520ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
13521ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Ok, now we're unconditional.  Do the store. */
13522b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         data = newTemp(ty);
13523b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         assign(data,
13524b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                ty == Ity_I64
13525b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                   // FIXME: assumes little-endian guest
13526b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                   ? binop(Iop_32HLto64, getIRegA(rT+1), getIRegA(rT+0))
13527b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                   : narrow == Iop_INVALID
13528b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                      ? getIRegA(rT)
13529b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                      : unop(narrow, getIRegA(rT)));
13530ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         resSC1 = newTemp(Ity_I1);
13531b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         // FIXME: assumes little-endian guest
13532b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         stmt( IRStmt_LLSC(Iend_LE, resSC1, getIRegA(rN), mkexpr(data)) );
13533ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13534ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Set rD to 1 on failure, 0 on success.  Currently we have
13535ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            resSC1 == 0 on failure, 1 on success. */
13536ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         resSC32 = newTemp(Ity_I32);
13537ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(resSC32,
13538ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                unop(Iop_1Uto32, unop(Iop_Not1, mkexpr(resSC1))));
13539ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13540ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIRegA(rD, mkexpr(resSC32),
13541ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      IRTemp_INVALID, Ijk_Boring);
13542b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         if (ty == Ity_I64) {
13543b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            DIP("strex%s%s r%u, r%u, r%u, [r%u]\n",
13544b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                nm, nCC(INSN_COND), rD, rT, rT+1, rN);
13545b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         } else {
13546b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            DIP("strex%s%s r%u, r%u, [r%u]\n",
13547b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                nm, nCC(INSN_COND), rD, rT, rN);
13548b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         }
13549ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
13550ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
13551ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* fall through */
13552ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
13553ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13554ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* --------------------- movw, movt --------------------- */
13555ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (0x03000000 == (insn & 0x0FF00000)
13556ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       || 0x03400000 == (insn & 0x0FF00000)) /* pray for CSE */ {
13557ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rD    = INSN(15,12);
13558ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt imm16 = (insn & 0xFFF) | ((insn >> 4) & 0x0000F000);
13559ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt isT   = (insn >> 22) & 1;
13560ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (rD == 15) {
13561ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* forget it */
13562ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
13563ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (isT) {
13564ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putIRegA(rD,
13565ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     binop(Iop_Or32,
13566ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           binop(Iop_And32, getIRegA(rD), mkU32(0xFFFF)),
13567ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           mkU32(imm16 << 16)),
13568ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     condT, Ijk_Boring);
13569ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("movt%s r%u, #0x%04x\n", nCC(INSN_COND), rD, imm16);
13570ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto decode_success;
13571ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
13572ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putIRegA(rD, mkU32(imm16), condT, Ijk_Boring);
13573ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("movw%s r%u, #0x%04x\n", nCC(INSN_COND), rD, imm16);
13574ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto decode_success;
13575ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
13576ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
13577ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* fall through */
13578ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
13579ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13580ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ----------- uxtb, sxtb, uxth, sxth, uxtb16, sxtb16 ----------- */
13581ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* FIXME: this is an exact duplicate of the Thumb version.  They
13582ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      should be commoned up. */
13583ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (BITS8(0,1,1,0,1, 0,0,0) == (INSN(27,20) & BITS8(1,1,1,1,1,0,0,0))
13584ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && BITS4(1,1,1,1) == INSN(19,16)
13585ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && BITS4(0,1,1,1) == INSN(7,4)
13586ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && BITS4(0,0, 0,0) == (INSN(11,8) & BITS4(0,0,1,1))) {
13587ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt subopc = INSN(27,20) & BITS8(0,0,0,0,0, 1,1,1);
13588ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (subopc != BITS4(0,0,0,1) && subopc != BITS4(0,1,0,1)) {
13589ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Int    rot  = (INSN(11,8) >> 2) & 3;
13590ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         UInt   rM   = INSN(3,0);
13591ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         UInt   rD   = INSN(15,12);
13592ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp srcT = newTemp(Ity_I32);
13593ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp rotT = newTemp(Ity_I32);
13594ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp dstT = newTemp(Ity_I32);
13595ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         HChar* nm   = "???";
13596ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(srcT, getIRegA(rM));
13597ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(rotT, genROR32(srcT, 8 * rot)); /* 0, 8, 16 or 24 only */
13598ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         switch (subopc) {
13599ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case BITS4(0,1,1,0): // UXTB
13600ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign(dstT, unop(Iop_8Uto32, unop(Iop_32to8, mkexpr(rotT))));
13601ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               nm = "uxtb";
13602ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
13603ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case BITS4(0,0,1,0): // SXTB
13604ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign(dstT, unop(Iop_8Sto32, unop(Iop_32to8, mkexpr(rotT))));
13605ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               nm = "sxtb";
13606ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
13607ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case BITS4(0,1,1,1): // UXTH
13608ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign(dstT, unop(Iop_16Uto32, unop(Iop_32to16, mkexpr(rotT))));
13609ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               nm = "uxth";
13610ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
13611ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case BITS4(0,0,1,1): // SXTH
13612ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign(dstT, unop(Iop_16Sto32, unop(Iop_32to16, mkexpr(rotT))));
13613ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               nm = "sxth";
13614ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
13615ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case BITS4(0,1,0,0): // UXTB16
13616ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign(dstT, binop(Iop_And32, mkexpr(rotT), mkU32(0x00FF00FF)));
13617ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               nm = "uxtb16";
13618ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
13619ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case BITS4(0,0,0,0): { // SXTB16
13620ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRTemp lo32 = newTemp(Ity_I32);
13621ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRTemp hi32 = newTemp(Ity_I32);
13622ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign(lo32, binop(Iop_And32, mkexpr(rotT), mkU32(0xFF)));
13623ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign(hi32, binop(Iop_Shr32, mkexpr(rotT), mkU8(16)));
13624ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign(
13625ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  dstT,
13626ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  binop(Iop_Or32,
13627ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        binop(Iop_And32,
13628ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              unop(Iop_8Sto32,
13629ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   unop(Iop_32to8, mkexpr(lo32))),
13630ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              mkU32(0xFFFF)),
13631ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        binop(Iop_Shl32,
13632ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              unop(Iop_8Sto32,
13633ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   unop(Iop_32to8, mkexpr(hi32))),
13634ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              mkU8(16))
13635ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               ));
13636ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               nm = "sxtb16";
13637ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
13638ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
13639ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            default:
13640ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               vassert(0); // guarded by "if" above
13641ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
13642ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIRegA(rD, mkexpr(dstT), condT, Ijk_Boring);
13643ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("%s%s r%u, r%u, ROR #%u\n", nm, nCC(INSN_COND), rD, rM, rot);
13644ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
13645ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
13646ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* fall through */
13647ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
13648ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13649ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ------------------- bfi, bfc ------------------- */
13650ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (BITS8(0,1,1,1,1,1,0, 0) == (INSN(27,20) & BITS8(1,1,1,1,1,1,1,0))
13651ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && BITS4(0, 0,0,1) == (INSN(7,4) & BITS4(0,1,1,1))) {
13652ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rD  = INSN(15,12);
13653ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rN  = INSN(3,0);
13654ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt msb = (insn >> 16) & 0x1F; /* 20:16 */
13655ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt lsb = (insn >> 7) & 0x1F;  /* 11:7 */
13656ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (rD == 15 || msb < lsb) {
13657ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* undecodable; fall through */
13658ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
13659ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp src    = newTemp(Ity_I32);
13660ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp olddst = newTemp(Ity_I32);
13661ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp newdst = newTemp(Ity_I32);
13662ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         UInt   mask = 1 << (msb - lsb);
13663ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         mask = (mask - 1) + mask;
13664ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vassert(mask != 0); // guaranteed by "msb < lsb" check above
13665ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         mask <<= lsb;
13666ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13667ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(src, rN == 15 ? mkU32(0) : getIRegA(rN));
13668ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(olddst, getIRegA(rD));
13669ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(newdst,
13670ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                binop(Iop_Or32,
13671ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   binop(Iop_And32,
13672ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         binop(Iop_Shl32, mkexpr(src), mkU8(lsb)),
13673ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         mkU32(mask)),
13674ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   binop(Iop_And32,
13675ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         mkexpr(olddst),
13676ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         mkU32(~mask)))
13677ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               );
13678ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13679ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIRegA(rD, mkexpr(newdst), condT, Ijk_Boring);
13680ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13681ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (rN == 15) {
13682ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("bfc%s r%u, #%u, #%u\n",
13683ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                nCC(INSN_COND), rD, lsb, msb-lsb+1);
13684ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
13685ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("bfi%s r%u, r%u, #%u, #%u\n",
13686ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                nCC(INSN_COND), rD, rN, lsb, msb-lsb+1);
13687ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
13688ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
13689ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
13690ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* fall through */
13691ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
13692ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13693ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ------------------- {u,s}bfx ------------------- */
13694ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (BITS8(0,1,1,1,1,0,1,0) == (INSN(27,20) & BITS8(1,1,1,1,1,0,1,0))
13695ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && BITS4(0,1,0,1) == (INSN(7,4) & BITS4(0,1,1,1))) {
13696ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rD  = INSN(15,12);
13697ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rN  = INSN(3,0);
13698ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt wm1 = (insn >> 16) & 0x1F; /* 20:16 */
13699ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt lsb = (insn >> 7) & 0x1F;  /* 11:7 */
13700ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt msb = lsb + wm1;
13701ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt isU = (insn >> 22) & 1;    /* 22:22 */
13702ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (rD == 15 || rN == 15 || msb >= 32) {
13703ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* undecodable; fall through */
13704ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
13705ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp src  = newTemp(Ity_I32);
13706ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp tmp  = newTemp(Ity_I32);
13707ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp res  = newTemp(Ity_I32);
13708ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         UInt   mask = ((1 << wm1) - 1) + (1 << wm1);
13709ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vassert(msb >= 0 && msb <= 31);
13710ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vassert(mask != 0); // guaranteed by msb being in 0 .. 31 inclusive
13711ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13712ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(src, getIRegA(rN));
13713ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(tmp, binop(Iop_And32,
13714ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           binop(Iop_Shr32, mkexpr(src), mkU8(lsb)),
13715ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           mkU32(mask)));
13716ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(res, binop(isU ? Iop_Shr32 : Iop_Sar32,
13717ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           binop(Iop_Shl32, mkexpr(tmp), mkU8(31-wm1)),
13718ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           mkU8(31-wm1)));
13719ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13720ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIRegA(rD, mkexpr(res), condT, Ijk_Boring);
13721ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13722ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("%s%s r%u, r%u, #%u, #%u\n",
13723ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             isU ? "ubfx" : "sbfx",
13724ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             nCC(INSN_COND), rD, rN, lsb, wm1 + 1);
13725ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
13726ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
13727ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* fall through */
13728ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
13729ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13730ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* --------------------- Load/store doubleword ------------- */
13731ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // LDRD STRD
13732ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /*                 31   27   23   19 15 11   7    3     # highest bit
13733ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        28   24   20 16 12    8    4    0
13734ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      A5-36   1 | 16  cond 0001 U100 Rn Rd im4h 11S1 im4l
13735ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      A5-38   1 | 32  cond 0001 U000 Rn Rd 0000 11S1 Rm
13736ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      A5-40   2 | 16  cond 0001 U110 Rn Rd im4h 11S1 im4l
13737ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      A5-42   2 | 32  cond 0001 U010 Rn Rd 0000 11S1 Rm
13738ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      A5-44   3 | 16  cond 0000 U100 Rn Rd im4h 11S1 im4l
13739ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      A5-46   3 | 32  cond 0000 U000 Rn Rd 0000 11S1 Rm
13740ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   */
13741ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* case coding:
13742ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             1   at-ea               (access at ea)
13743ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             2   at-ea-then-upd      (access at ea, then Rn = ea)
13744ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             3   at-Rn-then-upd      (access at Rn, then Rn = ea)
13745ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ea coding
13746ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             16  Rn +/- imm8
13747ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             32  Rn +/- Rm
13748ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   */
13749ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Quickly skip over all of this for hopefully most instructions */
13750ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if ((INSN(27,24) & BITS4(1,1,1,0)) != BITS4(0,0,0,0))
13751ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto after_load_store_doubleword;
13752ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13753ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Check the "11S1" thing. */
13754ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if ((INSN(7,4) & BITS4(1,1,0,1)) != BITS4(1,1,0,1))
13755ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto after_load_store_doubleword;
13756ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13757ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   summary = 0;
13758ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13759ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /**/ if (INSN(27,24) == BITS4(0,0,0,1) && INSN(22,20) == BITS3(1,0,0)) {
13760ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      summary = 1 | 16;
13761ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
13762ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else if (INSN(27,24) == BITS4(0,0,0,1) && INSN(22,20) == BITS3(0,0,0)) {
13763ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      summary = 1 | 32;
13764ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
13765ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else if (INSN(27,24) == BITS4(0,0,0,1) && INSN(22,20) == BITS3(1,1,0)) {
13766ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      summary = 2 | 16;
13767ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
13768ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else if (INSN(27,24) == BITS4(0,0,0,1) && INSN(22,20) == BITS3(0,1,0)) {
13769ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      summary = 2 | 32;
13770ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
13771ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else if (INSN(27,24) == BITS4(0,0,0,0) && INSN(22,20) == BITS3(1,0,0)) {
13772ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      summary = 3 | 16;
13773ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
13774ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else if (INSN(27,24) == BITS4(0,0,0,0) && INSN(22,20) == BITS3(0,0,0)) {
13775ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      summary = 3 | 32;
13776ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
13777ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else goto after_load_store_doubleword;
13778ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13779ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   { UInt rN   = (insn >> 16) & 0xF; /* 19:16 */
13780ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     UInt rD   = (insn >> 12) & 0xF; /* 15:12 */
13781ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     UInt rM   = (insn >> 0)  & 0xF; /*  3:0  */
13782ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     UInt bU   = (insn >> 23) & 1;   /* 23 U=1 offset+, U=0 offset- */
13783ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     UInt bS   = (insn >> 5) & 1;    /* S=1 store, S=0 load */
13784ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     UInt imm8 = ((insn >> 4) & 0xF0) | (insn & 0xF); /* 11:8, 3:0 */
13785ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13786ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     /* Require rD to be an even numbered register */
13787ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     if ((rD & 1) != 0)
13788ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        goto after_load_store_doubleword;
13789ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13790ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     /* Require 11:8 == 0 for Rn +/- Rm cases */
13791ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     if ((summary & 32) != 0 && (imm8 & 0xF0) != 0)
13792ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        goto after_load_store_doubleword;
13793ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13794ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     /* Skip some invalid cases, which would lead to two competing
13795ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        updates to the same register, or which are otherwise
13796ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        disallowed by the spec. */
13797ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     switch (summary) {
13798ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        case 1 | 16:
13799ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           break;
13800ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        case 1 | 32:
13801ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           if (rM == 15) goto after_load_store_doubleword;
13802ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           break;
13803ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        case 2 | 16: case 3 | 16:
13804ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           if (rN == 15) goto after_load_store_doubleword;
13805ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           if (bS == 0 && (rN == rD || rN == rD+1))
13806ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              goto after_load_store_doubleword;
13807ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           break;
13808ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        case 2 | 32: case 3 | 32:
13809ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           if (rM == 15) goto after_load_store_doubleword;
13810ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           if (rN == 15) goto after_load_store_doubleword;
13811ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           if (rN == rM) goto after_load_store_doubleword;
13812ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           if (bS == 0 && (rN == rD || rN == rD+1))
13813ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              goto after_load_store_doubleword;
13814ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           break;
13815ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        default:
13816ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           vassert(0);
13817ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     }
13818ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13819ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     /* Now, we can't do a conditional load or store, since that very
13820ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        likely will generate an exception.  So we have to take a side
13821ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        exit at this point if the condition is false. */
13822ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     if (condT != IRTemp_INVALID) {
13823ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        mk_skip_over_A32_if_cond_is_false( condT );
13824ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        condT = IRTemp_INVALID;
13825ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     }
13826ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     /* Ok, now we're unconditional.  Do the load or store. */
13827ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13828ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     /* compute the effective address.  Bind it to a tmp since we
13829ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        may need to use it twice. */
13830ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     IRExpr* eaE = NULL;
13831ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     switch (summary & 0xF0) {
13832ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        case 16:
13833ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           eaE = mk_EA_reg_plusminus_imm8( rN, bU, imm8, dis_buf );
13834ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           break;
13835ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        case 32:
13836ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           eaE = mk_EA_reg_plusminus_reg( rN, bU, rM, dis_buf );
13837ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           break;
13838ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     }
13839ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     vassert(eaE);
13840ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     IRTemp eaT = newTemp(Ity_I32);
13841ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     assign(eaT, eaE);
13842ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13843ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     /* get the old Rn value */
13844ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     IRTemp rnT = newTemp(Ity_I32);
13845ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     assign(rnT, getIRegA(rN));
13846ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13847ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     /* decide on the transfer address */
13848ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     IRTemp taT = IRTemp_INVALID;
13849ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     switch (summary & 0x0F) {
13850ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        case 1: case 2: taT = eaT; break;
13851ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        case 3:         taT = rnT; break;
13852ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     }
13853ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     vassert(taT != IRTemp_INVALID);
13854ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13855ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     /* XXX deal with alignment constraints */
13856ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     /* XXX: but the A8 doesn't seem to trap for misaligned loads, so,
13857ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        ignore alignment issues for the time being. */
13858ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13859ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     /* doubleword store  S 1
13860ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        doubleword load   S 0
13861ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     */
13862ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     HChar* name = NULL;
13863ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     /* generate the transfers */
13864ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     if (bS == 1) { // doubleword store
13865ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        storeLE( binop(Iop_Add32, mkexpr(taT), mkU32(0)), getIRegA(rD+0) );
13866ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        storeLE( binop(Iop_Add32, mkexpr(taT), mkU32(4)), getIRegA(rD+1) );
13867ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        name = "strd";
13868ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     } else { // doubleword load
13869ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        putIRegA( rD+0,
13870ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  loadLE(Ity_I32, binop(Iop_Add32, mkexpr(taT), mkU32(0))),
13871ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  IRTemp_INVALID, Ijk_Boring );
13872ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        putIRegA( rD+1,
13873ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  loadLE(Ity_I32, binop(Iop_Add32, mkexpr(taT), mkU32(4))),
13874ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  IRTemp_INVALID, Ijk_Boring );
13875ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        name = "ldrd";
13876ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     }
13877ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13878ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     /* Update Rn if necessary. */
13879ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     switch (summary & 0x0F) {
13880ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        case 2: case 3:
13881ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           // should be assured by logic above:
13882ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           if (bS == 0) {
13883ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              vassert(rD+0 != rN); /* since we just wrote rD+0 */
13884ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              vassert(rD+1 != rN); /* since we just wrote rD+1 */
13885ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           }
13886ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           putIRegA( rN, mkexpr(eaT), IRTemp_INVALID, Ijk_Boring );
13887ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           break;
13888ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     }
13889ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13890ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     switch (summary & 0x0F) {
13891ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        case 1:  DIP("%s%s r%u, %s\n", name, nCC(INSN_COND), rD, dis_buf);
13892ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 break;
13893ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        case 2:  DIP("%s%s r%u, %s! (at-EA-then-Rn=EA)\n",
13894ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     name, nCC(INSN_COND), rD, dis_buf);
13895ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 break;
13896ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        case 3:  DIP("%s%s r%u, %s! (at-Rn-then-Rn=EA)\n",
13897ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     name, nCC(INSN_COND), rD, dis_buf);
13898ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 break;
13899ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        default: vassert(0);
13900ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     }
13901ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13902ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     goto decode_success;
13903ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
13904ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13905ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  after_load_store_doubleword:
13906ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13907ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ------------------- {s,u}xtab ------------- */
13908ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (BITS8(0,1,1,0,1,0,1,0) == (INSN(27,20) & BITS8(1,1,1,1,1,0,1,1))
13909ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && BITS4(0,0,0,0) == (INSN(11,8) & BITS4(0,0,1,1))
13910ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && BITS4(0,1,1,1) == INSN(7,4)) {
13911ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rN  = INSN(19,16);
13912ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rD  = INSN(15,12);
13913ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rM  = INSN(3,0);
13914ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rot = (insn >> 10) & 3;
13915ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt isU = INSN(22,22);
13916ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (rN == 15/*it's {S,U}XTB*/ || rD == 15 || rM == 15) {
13917ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* undecodable; fall through */
13918ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
13919ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp srcL = newTemp(Ity_I32);
13920ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp srcR = newTemp(Ity_I32);
13921ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp res  = newTemp(Ity_I32);
13922ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(srcR, getIRegA(rM));
13923ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(srcL, getIRegA(rN));
13924ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(res,  binop(Iop_Add32,
13925ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            mkexpr(srcL),
13926ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            unop(isU ? Iop_8Uto32 : Iop_8Sto32,
13927ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 unop(Iop_32to8,
13928ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                      genROR32(srcR, 8 * rot)))));
13929ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIRegA(rD, mkexpr(res), condT, Ijk_Boring);
13930ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("%cxtab%s r%u, r%u, r%u, ror #%u\n",
13931ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             isU ? 'u' : 's', nCC(INSN_COND), rD, rN, rM, rot);
13932ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
13933ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
13934ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* fall through */
13935ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
13936ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13937ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ------------------- {s,u}xtah ------------- */
13938ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (BITS8(0,1,1,0,1,0,1,1) == (INSN(27,20) & BITS8(1,1,1,1,1,0,1,1))
13939ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && BITS4(0,0,0,0) == (INSN(11,8) & BITS4(0,0,1,1))
13940ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && BITS4(0,1,1,1) == INSN(7,4)) {
13941ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rN  = INSN(19,16);
13942ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rD  = INSN(15,12);
13943ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rM  = INSN(3,0);
13944ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rot = (insn >> 10) & 3;
13945ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt isU = INSN(22,22);
13946ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (rN == 15/*it's {S,U}XTH*/ || rD == 15 || rM == 15) {
13947ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* undecodable; fall through */
13948ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
13949ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp srcL = newTemp(Ity_I32);
13950ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp srcR = newTemp(Ity_I32);
13951ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp res  = newTemp(Ity_I32);
13952ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(srcR, getIRegA(rM));
13953ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(srcL, getIRegA(rN));
13954ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(res,  binop(Iop_Add32,
13955ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            mkexpr(srcL),
13956ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            unop(isU ? Iop_16Uto32 : Iop_16Sto32,
13957ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 unop(Iop_32to16,
13958ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                      genROR32(srcR, 8 * rot)))));
13959ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIRegA(rD, mkexpr(res), condT, Ijk_Boring);
13960ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13961ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("%cxtah%s r%u, r%u, r%u, ror #%u\n",
13962ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             isU ? 'u' : 's', nCC(INSN_COND), rD, rN, rM, rot);
13963ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
13964ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
13965ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* fall through */
13966ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
13967ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13968ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ------------------- rev16, rev ------------------ */
13969ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (INSN(27,16) == 0x6BF
13970ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && (INSN(11,4) == 0xFB/*rev16*/ || INSN(11,4) == 0xF3/*rev*/)) {
13971ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Bool isREV = INSN(11,4) == 0xF3;
13972ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rM    = INSN(3,0);
13973ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rD    = INSN(15,12);
13974ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (rM != 15 && rD != 15) {
13975ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp rMt = newTemp(Ity_I32);
13976ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(rMt, getIRegA(rM));
13977ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp res = isREV ? gen_REV(rMt) : gen_REV16(rMt);
13978ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIRegA(rD, mkexpr(res), condT, Ijk_Boring);
13979ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("rev%s%s r%u, r%u\n", isREV ? "" : "16",
13980ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             nCC(INSN_COND), rD, rM);
13981ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
13982ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
13983ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
13984ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13985ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ------------------- rbit ------------------ */
13986ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (INSN(27,16) == 0x6FF && INSN(11,4) == 0xF3) {
13987ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rD = INSN(15,12);
13988ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rM = INSN(3,0);
13989ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (rD != 15 && rM != 15) {
13990ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp arg = newTemp(Ity_I32);
13991ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(arg, getIRegA(rM));
13992ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp res = gen_BITREV(arg);
13993ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIRegA(rD, mkexpr(res), condT, Ijk_Boring);
13994ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("rbit r%u, r%u\n", rD, rM);
13995ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
13996ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
13997ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
13998ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13999ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ------------------- smmul ------------------ */
14000ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (INSN(27,20) == BITS8(0,1,1,1,0,1,0,1)
14001ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && INSN(15,12) == BITS4(1,1,1,1)
14002ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && (INSN(7,4) & BITS4(1,1,0,1)) == BITS4(0,0,0,1)) {
14003ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt bitR = INSN(5,5);
14004ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rD = INSN(19,16);
14005ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rM = INSN(11,8);
14006ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rN = INSN(3,0);
14007ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (rD != 15 && rM != 15 && rN != 15) {
14008ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRExpr* res
14009ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         = unop(Iop_64HIto32,
14010ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                binop(Iop_Add64,
14011ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      binop(Iop_MullS32, getIRegA(rN), getIRegA(rM)),
14012ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      mkU64(bitR ? 0x80000000ULL : 0ULL)));
14013ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIRegA(rD, res, condT, Ijk_Boring);
14014ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("smmul%s%s r%u, r%u, r%u\n",
14015ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             nCC(INSN_COND), bitR ? "r" : "", rD, rN, rM);
14016ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
14017ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
14018ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
14019ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14020ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ------------------- NOP ------------------ */
14021ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (0x0320F000 == (insn & 0x0FFFFFFF)) {
14022ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("nop%s\n", nCC(INSN_COND));
14023ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
14024ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
14025ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14026ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ----------------------------------------------------------- */
14027ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* -- ARMv7 instructions                                    -- */
14028ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ----------------------------------------------------------- */
14029ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14030ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* -------------- read CP15 TPIDRURO register ------------- */
14031ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* mrc     p15, 0, r0, c13, c0, 3  up to
14032ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      mrc     p15, 0, r14, c13, c0, 3
14033ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   */
14034ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* I don't know whether this is really v7-only.  But anyway, we
14035ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      have to support it since arm-linux uses TPIDRURO as a thread
14036ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      state register. */
14037ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (0x0E1D0F70 == (insn & 0x0FFF0FFF)) {
14038ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rD = INSN(15,12);
14039ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (rD <= 14) {
14040ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* skip r15, that's too stupid to handle */
14041ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIRegA(rD, IRExpr_Get(OFFB_TPIDRURO, Ity_I32),
14042ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      condT, Ijk_Boring);
14043ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("mrc%s p15,0, r%u, c13, c0, 3\n", nCC(INSN_COND), rD);
14044ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
14045ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
14046ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* fall through */
14047ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
14048ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14049ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Handle various kinds of barriers.  This is rather indiscriminate
14050ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      in the sense that they are all turned into an IR Fence, which
14051ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      means we don't know which they are, so the back end has to
14052ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      re-emit them all when it comes acrosss an IR Fence.
14053ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   */
1405410a4e5850b3ca9d2e88abe08032887cfc8d21515Kenny Root   if (0xEE070F9A == (insn & 0xFFFF0FFF)) { /* v6 */
1405510a4e5850b3ca9d2e88abe08032887cfc8d21515Kenny Root      /* mcr 15, 0, r0, c7, c10, 4 (v6) equiv to DSB (v7).  Data
1405610a4e5850b3ca9d2e88abe08032887cfc8d21515Kenny Root         Synch Barrier -- ensures completion of memory accesses. */
1405710a4e5850b3ca9d2e88abe08032887cfc8d21515Kenny Root      stmt( IRStmt_MBE(Imbe_Fence) );
1405810a4e5850b3ca9d2e88abe08032887cfc8d21515Kenny Root      DIP("mcr 15, 0, rX, c7, c10, 4 (data synch barrier)\n");
1405910a4e5850b3ca9d2e88abe08032887cfc8d21515Kenny Root      goto decode_success;
1406010a4e5850b3ca9d2e88abe08032887cfc8d21515Kenny Root   }
1406110a4e5850b3ca9d2e88abe08032887cfc8d21515Kenny Root   if (0xEE070FBA == (insn & 0xFFFF0FFF)) { /* v6 */
1406210a4e5850b3ca9d2e88abe08032887cfc8d21515Kenny Root      /* mcr 15, 0, r0, c7, c10, 5 (v6) equiv to DMB (v7).  Data
1406310a4e5850b3ca9d2e88abe08032887cfc8d21515Kenny Root         Memory Barrier -- ensures ordering of memory accesses. */
1406410a4e5850b3ca9d2e88abe08032887cfc8d21515Kenny Root      stmt( IRStmt_MBE(Imbe_Fence) );
1406510a4e5850b3ca9d2e88abe08032887cfc8d21515Kenny Root      DIP("mcr 15, 0, rX, c7, c10, 5 (data memory barrier)\n");
1406610a4e5850b3ca9d2e88abe08032887cfc8d21515Kenny Root      goto decode_success;
1406710a4e5850b3ca9d2e88abe08032887cfc8d21515Kenny Root   }
1406810a4e5850b3ca9d2e88abe08032887cfc8d21515Kenny Root   if (0xEE070F95 == (insn & 0xFFFF0FFF)) { /* v6 */
1406910a4e5850b3ca9d2e88abe08032887cfc8d21515Kenny Root      /* mcr 15, 0, r0, c7, c5, 4 (v6) equiv to ISB (v7).
1407010a4e5850b3ca9d2e88abe08032887cfc8d21515Kenny Root         Instruction Synchronisation Barrier (or Flush Prefetch
1407110a4e5850b3ca9d2e88abe08032887cfc8d21515Kenny Root         Buffer) -- a pipe flush, I think.  I suspect we could
1407210a4e5850b3ca9d2e88abe08032887cfc8d21515Kenny Root         ignore those, but to be on the safe side emit a fence
1407310a4e5850b3ca9d2e88abe08032887cfc8d21515Kenny Root         anyway. */
1407410a4e5850b3ca9d2e88abe08032887cfc8d21515Kenny Root      stmt( IRStmt_MBE(Imbe_Fence) );
1407510a4e5850b3ca9d2e88abe08032887cfc8d21515Kenny Root      DIP("mcr 15, 0, rX, c7, c5, 4 (insn synch barrier)\n");
1407610a4e5850b3ca9d2e88abe08032887cfc8d21515Kenny Root      goto decode_success;
14077ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
14078ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14079ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ----------------------------------------------------------- */
14080ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* -- VFP (CP 10, CP 11) instructions (in ARM mode)         -- */
14081ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ----------------------------------------------------------- */
14082ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14083ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (INSN_COND != ARMCondNV) {
14084ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Bool ok_vfp = decode_CP10_CP11_instruction (
14085ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       &dres, INSN(27,0), condT, INSN_COND,
14086ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       False/*!isT*/
14087ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    );
14088ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (ok_vfp)
14089ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
14090ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
14091ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14092ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ----------------------------------------------------------- */
14093ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* -- NEON instructions (in ARM mode)                       -- */
14094ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ----------------------------------------------------------- */
14095ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14096ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* These are all in NV space, and so are taken care of (far) above,
14097ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      by a call from this function to decode_NV_instruction(). */
14098ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14099ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ----------------------------------------------------------- */
14100ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* -- v6 media instructions (in ARM mode)                   -- */
14101ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ----------------------------------------------------------- */
14102ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14103ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   { Bool ok_v6m = decode_V6MEDIA_instruction(
14104ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       &dres, INSN(27,0), condT, INSN_COND,
14105ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       False/*!isT*/
14106ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   );
14107ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     if (ok_v6m)
14108ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        goto decode_success;
14109ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
14110ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14111ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ----------------------------------------------------------- */
14112ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* -- Undecodable                                           -- */
14113ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ----------------------------------------------------------- */
14114ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14115ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   goto decode_failure;
14116ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /*NOTREACHED*/
14117ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14118ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  decode_failure:
14119ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* All decode failures end up here. */
14120ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vex_printf("disInstr(arm): unhandled instruction: "
14121ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              "0x%x\n", insn);
14122ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vex_printf("                 cond=%d(0x%x) 27:20=%u(0x%02x) "
14123ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                "4:4=%d "
14124ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                "3:0=%u(0x%x)\n",
14125ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              (Int)INSN_COND, (UInt)INSN_COND,
14126ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              (Int)INSN(27,20), (UInt)INSN(27,20),
14127ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              (Int)INSN(4,4),
14128ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              (Int)INSN(3,0), (UInt)INSN(3,0) );
14129ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14130ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Tell the dispatcher that this insn cannot be decoded, and so has
14131ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      not been executed, and (is currently) the next to be executed.
14132ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      R15 should be up-to-date since it made so at the start of each
14133ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      insn, but nevertheless be paranoid and update it again right
14134ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      now. */
14135ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(0 == (guest_R15_curr_instr_notENC & 3));
14136ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   llPutIReg( 15, mkU32(guest_R15_curr_instr_notENC) );
14137ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   irsb->next     = mkU32(guest_R15_curr_instr_notENC);
14138ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   irsb->jumpkind = Ijk_NoDecode;
14139ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   dres.whatNext  = Dis_StopHere;
14140ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   dres.len       = 0;
14141ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return dres;
14142ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14143ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  decode_success:
14144ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* All decode successes end up here. */
14145ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DIP("\n");
14146ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14147ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(dres.len == 4 || dres.len == 20);
14148ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14149ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Now then.  Do we have an implicit jump to r15 to deal with? */
14150ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (r15written) {
14151ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* If we get jump to deal with, we assume that there's been no
14152ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         other competing branch stuff previously generated for this
14153ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         insn.  That's reasonable, in the sense that the ARM insn set
14154ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         appears to declare as "Unpredictable" any instruction which
14155ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         generates more than one possible new value for r15.  Hence
14156ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         just assert.  The decoders themselves should check against
14157ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         all such instructions which are thusly Unpredictable, and
14158ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         decline to decode them.  Hence we should never get here if we
14159ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         have competing new values for r15, and hence it is safe to
14160ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assert here. */
14161ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(dres.whatNext == Dis_Continue);
14162ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(irsb->next == NULL);
14163b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      vassert(irsb->jumpkind == Ijk_Boring);
14164ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* If r15 is unconditionally written, terminate the block by
14165ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         jumping to it.  If it's conditionally written, still
14166ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         terminate the block (a shame, but we can't do side exits to
14167ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         arbitrary destinations), but first jump to the next
14168ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         instruction if the condition doesn't hold. */
14169ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* We can't use getIReg(15) to get the destination, since that
14170ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         will produce r15+8, which isn't what we want.  Must use
14171ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         llGetIReg(15) instead. */
14172ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (r15guard == IRTemp_INVALID) {
14173ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* unconditional */
14174ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
14175ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* conditional */
14176ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         stmt( IRStmt_Exit(
14177ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  unop(Iop_32to1,
14178ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       binop(Iop_Xor32,
14179ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             mkexpr(r15guard), mkU32(1))),
14180ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  r15kind,
14181ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  IRConst_U32(guest_R15_curr_instr_notENC + 4)
14182ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         ));
14183ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
14184ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      irsb->next     = llGetIReg(15);
14185ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      irsb->jumpkind = r15kind;
14186ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      dres.whatNext  = Dis_StopHere;
14187ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
14188ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14189ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return dres;
14190ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14191ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  undef INSN_COND
14192ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  undef INSN
14193ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
14194ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14195ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14196ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
14197ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- Disassemble a single Thumb2 instruction              ---*/
14198ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
14199ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14200b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanovstatic const UChar it_length_table[256]; /* fwds */
14201b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
14202ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* NB: in Thumb mode we do fetches of regs with getIRegT, which
14203ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   automagically adds 4 to fetches of r15.  However, writes to regs
14204ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   are done with putIRegT, which disallows writes to r15.  Hence any
14205ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   r15 writes and associated jumps have to be done "by hand". */
14206ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14207ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Disassemble a single Thumb instruction into IR.  The instruction is
14208ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   located in host memory at guest_instr, and has (decoded) guest IP
14209ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   of guest_R15_curr_instr_notENC, which will have been set before the
14210ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   call here. */
14211ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14212ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
14213ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownDisResult disInstr_THUMB_WRK (
14214ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             Bool         put_IP,
14215ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             Bool         (*resteerOkFn) ( /*opaque*/void*, Addr64 ),
14216ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             Bool         resteerCisOk,
14217ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             void*        callback_opaque,
14218ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             UChar*       guest_instr,
14219ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             VexArchInfo* archinfo,
14220ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             VexAbiInfo*  abiinfo
14221ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          )
14222ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
14223ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* A macro to fish bits out of insn0.  There's also INSN1, to fish
14224ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      bits out of insn1, but that's defined only after the end of the
14225ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      16-bit insn decoder, so as to stop it mistakenly being used
14226ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      therein. */
14227ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  define INSN0(_bMax,_bMin)  SLICE_UInt(((UInt)insn0), (_bMax), (_bMin))
14228ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14229ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DisResult dres;
14230ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UShort    insn0; /* first 16 bits of the insn */
14231ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   //Bool      allow_VFP = False;
14232ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   //UInt      hwcaps = archinfo->hwcaps;
14233ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HChar     dis_buf[128];  // big enough to hold LDMIA etc text
14234ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14235ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Summary result of the ITxxx backwards analysis: False == safe
14236ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      but suboptimal. */
14237ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Bool guaranteedUnconditional = False;
14238ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14239ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* What insn variants are we supporting today? */
14240ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   //allow_VFP  = (0 != (hwcaps & VEX_HWCAPS_ARM_VFP));
14241ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // etc etc
14242ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14243ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Set result defaults. */
14244ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   dres.whatNext   = Dis_Continue;
14245ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   dres.len        = 2;
14246ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   dres.continueAt = 0;
14247ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14248ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Set default actions for post-insn handling of writes to r15, if
14249ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      required. */
14250ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   r15written = False;
14251ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   r15guard   = IRTemp_INVALID; /* unconditional */
14252ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   r15kind    = Ijk_Boring;
14253ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14254ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Insns could be 2 or 4 bytes long.  Just get the first 16 bits at
14255ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      this point.  If we need the second 16, get them later.  We can't
14256ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      get them both out immediately because it risks a fault (very
14257ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      unlikely, but ..) if the second 16 bits aren't actually
14258ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      necessary. */
14259ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   insn0 = getUShortLittleEndianly( guest_instr );
14260ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14261ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (0) vex_printf("insn: 0x%x\n", insn0);
14262ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14263ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DIP("\t(thumb) 0x%x:  ", (UInt)guest_R15_curr_instr_notENC);
14264ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14265ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* We may be asked to update the guest R15 before going further. */
14266ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(0 == (guest_R15_curr_instr_notENC & 1));
14267ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (put_IP) {
14268ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      llPutIReg( 15, mkU32(guest_R15_curr_instr_notENC | 1) );
14269ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
14270ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14271ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ----------------------------------------------------------- */
14272ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Spot "Special" instructions (see comment at top of file). */
14273ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   {
14274ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UChar* code = (UChar*)guest_instr;
14275ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Spot the 16-byte preamble:
14276ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14277ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         ea4f 0cfc  mov.w   ip, ip, ror #3
14278ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         ea4f 3c7c  mov.w   ip, ip, ror #13
14279ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         ea4f 7c7c  mov.w   ip, ip, ror #29
14280ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         ea4f 4cfc  mov.w   ip, ip, ror #19
14281ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      */
14282ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt word1 = 0x0CFCEA4F;
14283ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt word2 = 0x3C7CEA4F;
14284ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt word3 = 0x7C7CEA4F;
14285ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt word4 = 0x4CFCEA4F;
14286ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (getUIntLittleEndianly(code+ 0) == word1 &&
14287ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          getUIntLittleEndianly(code+ 4) == word2 &&
14288ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          getUIntLittleEndianly(code+ 8) == word3 &&
14289ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          getUIntLittleEndianly(code+12) == word4) {
14290ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Got a "Special" instruction preamble.  Which one is it? */
14291ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // 0x 0A 0A EA 4A
14292ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (getUIntLittleEndianly(code+16) == 0x0A0AEA4A
14293ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                               /* orr.w r10,r10,r10 */) {
14294ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* R3 = client_request ( R4 ) */
14295ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("r3 = client_request ( %%r4 )\n");
14296ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            irsb->next     = mkU32( (guest_R15_curr_instr_notENC + 20) | 1 );
14297ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            irsb->jumpkind = Ijk_ClientReq;
14298ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            dres.whatNext  = Dis_StopHere;
14299ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto decode_success;
14300ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
14301ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         else
14302ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // 0x 0B 0B EA 4B
14303ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (getUIntLittleEndianly(code+16) == 0x0B0BEA4B
14304ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                               /* orr r11,r11,r11 */) {
14305ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* R3 = guest_NRADDR */
14306ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("r3 = guest_NRADDR\n");
14307ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            dres.len = 20;
14308ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            llPutIReg(3, IRExpr_Get( OFFB_NRADDR, Ity_I32 ));
14309ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto decode_success;
14310ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
14311ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         else
14312ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // 0x 0C 0C EA 4C
14313ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (getUIntLittleEndianly(code+16) == 0x0C0CEA4C
14314ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                               /* orr r12,r12,r12 */) {
14315ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /*  branch-and-link-to-noredir R4 */
14316ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("branch-and-link-to-noredir r4\n");
14317ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            llPutIReg(14, mkU32( (guest_R15_curr_instr_notENC + 20) | 1 ));
14318ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            irsb->next     = getIRegT(4);
14319ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            irsb->jumpkind = Ijk_NoRedir;
14320ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            dres.whatNext  = Dis_StopHere;
14321ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto decode_success;
14322ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
14323ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* We don't know what it is.  Set insn0 so decode_failure
14324ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            can print the insn following the Special-insn preamble. */
14325ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         insn0 = getUShortLittleEndianly(code+16);
14326ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_failure;
14327ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /*NOTREACHED*/
14328ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
14329ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14330ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
14331ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14332ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ----------------------------------------------------------- */
14333ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14334ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Main Thumb instruction decoder starts here.  It's a series of
14335ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      switches which examine ever longer bit sequences at the MSB of
14336ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      the instruction word, first for 16-bit insns, then for 32-bit
14337ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      insns. */
14338ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14339ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* --- BEGIN ITxxx optimisation analysis --- */
14340ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* This is a crucial optimisation for the ITState boilerplate that
14341ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      follows.  Examine the 9 halfwords preceding this instruction,
14342ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      and if we are absolutely sure that none of them constitute an
14343ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      'it' instruction, then we can be sure that this instruction is
14344ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      not under the control of any 'it' instruction, and so
14345ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      guest_ITSTATE must be zero.  So write zero into ITSTATE right
14346ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      now, so that iropt can fold out almost all of the resulting
14347ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      junk.
14348ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14349ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      If we aren't sure, we can always safely skip this step.  So be a
14350ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      bit conservative about it: only poke around in the same page as
14351ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      this instruction, lest we get a fault from the previous page
14352ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      that would not otherwise have happened.  The saving grace is
14353ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      that such skipping is pretty rare -- it only happens,
14354ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      statistically, 18/4096ths of the time, so is judged unlikely to
14355ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      be a performance problems.
14356ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14357ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      FIXME: do better.  Take into account the number of insns covered
14358ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      by any IT insns we find, to rule out cases where an IT clearly
14359ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      cannot cover this instruction.  This would improve behaviour for
14360ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      branch targets immediately following an IT-guarded group that is
14361ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      not of full length.  Eg, (and completely ignoring issues of 16-
14362ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vs 32-bit insn length):
14363ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14364ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             ite cond
14365ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             insn1
14366ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             insn2
14367ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      label: insn3
14368ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             insn4
14369ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14370ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      The 'it' only conditionalises insn1 and insn2.  However, the
14371ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      current analysis is conservative and considers insn3 and insn4
14372ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      also possibly guarded.  Hence if 'label:' is the start of a hot
14373ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      loop we will get a big performance hit.
14374ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   */
14375ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   {
14376ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Summary result of this analysis: False == safe but
14377ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         suboptimal. */
14378ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(guaranteedUnconditional == False);
14379ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14380ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt pc = guest_R15_curr_instr_notENC;
14381ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(0 == (pc & 1));
14382ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14383ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt pageoff = pc & 0xFFF;
14384ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (pageoff >= 18) {
14385ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* It's safe to poke about in the 9 halfwords preceding this
14386ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            insn.  So, have a look at them. */
14387b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         guaranteedUnconditional = True; /* assume no 'it' insn found,
14388b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                                            till we do */
14389ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         UShort* hwp = (UShort*)(HWord)pc;
14390ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Int i;
14391ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         for (i = -1; i >= -9; i--) {
14392ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* We're in the same page.  (True, but commented out due
14393ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               to expense.) */
14394ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /*
14395ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            vassert( ( ((UInt)(&hwp[i])) & 0xFFFFF000 )
14396ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      == ( pc & 0xFFFFF000 ) );
14397ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            */
14398ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* All valid IT instructions must have the form 0xBFxy,
14399b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               where x can be anything, but y must be nonzero.  Find
14400b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               the number of insns covered by it (1 .. 4) and check to
14401b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               see if it can possibly reach up to the instruction in
14402b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               question.  Some (x,y) combinations mean UNPREDICTABLE,
14403b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               and the table is constructed to be conservative by
14404b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               returning 4 for those cases, so the analysis is safe
14405b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               even if the code uses unpredictable IT instructions (in
14406b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               which case its authors are nuts, but hey.)  */
14407b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            UShort hwp_i = hwp[i];
14408b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            if (UNLIKELY((hwp_i & 0xFF00) == 0xBF00 && (hwp_i & 0xF) != 0)) {
14409b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               /* might be an 'it' insn. */
14410b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               /* # guarded insns */
14411b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               Int n_guarded = (Int)it_length_table[hwp_i & 0xFF];
14412b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               vassert(n_guarded >= 1 && n_guarded <= 4);
14413b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               if (n_guarded * 2 /* # guarded HWs, worst case */
14414b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                   > (-(i+1)))   /* -(i+1): # remaining HWs after the IT */
14415b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                   /* -(i+0) also seems to work, even though I think
14416b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                      it's wrong.  I don't understand that. */
14417b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                  guaranteedUnconditional = False;
14418ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
14419ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
14420ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
14421ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
14422ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
14423ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* --- END ITxxx optimisation analysis --- */
14424ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14425ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Generate the guarding condition for this insn, by examining
14426ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ITSTATE.  Assign it to condT.  Also, generate new
14427ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      values for ITSTATE ready for stuffing back into the
14428ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      guest state, but don't actually do the Put yet, since it will
14429ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      need to stuffed back in only after the instruction gets to a
14430ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      point where it is sure to complete.  Mostly we let the code at
14431ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      decode_success handle this, but in cases where the insn contains
14432ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      a side exit, we have to update them before the exit. */
14433ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14434ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* If the ITxxx optimisation analysis above could not prove that
14435ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      this instruction is guaranteed unconditional, we insert a
14436ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      lengthy IR preamble to compute the guarding condition at
14437ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      runtime.  If it can prove it (which obviously we hope is the
14438ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      normal case) then we insert a minimal preamble, which is
14439ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      equivalent to setting guest_ITSTATE to zero and then folding
14440ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      that through the full preamble (which completely disappears). */
14441ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14442ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp condT              = IRTemp_INVALID;
14443ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp old_itstate        = IRTemp_INVALID;
14444ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp new_itstate        = IRTemp_INVALID;
14445ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp cond_AND_notInIT_T = IRTemp_INVALID;
14446ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14447ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (guaranteedUnconditional) {
14448ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* BEGIN "partial eval { ITSTATE = 0; STANDARD_PREAMBLE; }" */
14449ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14450ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // ITSTATE = 0 :: I32
14451ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp z32 = newTemp(Ity_I32);
14452ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(z32, mkU32(0));
14453ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      put_ITSTATE(z32);
14454ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14455ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // old_itstate = 0 :: I32
14456ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      //
14457ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // old_itstate = get_ITSTATE();
14458ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      old_itstate = z32; /* 0 :: I32 */
14459ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14460ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // new_itstate = old_itstate >> 8
14461ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      //             = 0 >> 8
14462ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      //             = 0 :: I32
14463ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      //
14464ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // new_itstate = newTemp(Ity_I32);
14465ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // assign(new_itstate,
14466ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      //        binop(Iop_Shr32, mkexpr(old_itstate), mkU8(8)));
14467ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      new_itstate = z32;
14468ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14469ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // ITSTATE = 0 :: I32(again)
14470ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      //
14471ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // put_ITSTATE(new_itstate);
14472ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14473ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // condT1 = calc_cond_dyn( xor(and(old_istate,0xF0), 0xE0) )
14474ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      //        = calc_cond_dyn( xor(0,0xE0) )
14475ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      //        = calc_cond_dyn ( 0xE0 )
14476ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      //        = 1 :: I32
14477ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // Not that this matters, since the computed value is not used:
14478ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // see condT folding below
14479ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      //
14480ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // IRTemp condT1 = newTemp(Ity_I32);
14481ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // assign(condT1,
14482ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      //        mk_armg_calculate_condition_dyn(
14483ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      //           binop(Iop_Xor32,
14484ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      //                 binop(Iop_And32, mkexpr(old_itstate), mkU32(0xF0)),
14485ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      //                 mkU32(0xE0))
14486ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      //       )
14487ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // );
14488ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14489ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // condT = 32to8(and32(old_itstate,0xF0)) == 0  ? 1  : condT1
14490ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      //       = 32to8(and32(0,0xF0)) == 0  ? 1  : condT1
14491ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      //       = 32to8(0) == 0  ? 1  : condT1
14492ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      //       = 0 == 0  ? 1  : condT1
14493ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      //       = 1
14494ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      //
14495ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // condT = newTemp(Ity_I32);
14496ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // assign(condT, IRExpr_Mux0X(
14497ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      //                  unop(Iop_32to8, binop(Iop_And32,
14498ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      //                                        mkexpr(old_itstate),
14499ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      //                                        mkU32(0xF0))),
14500ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      //                  mkU32(1),
14501ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      //                  mkexpr(condT1)
14502ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      //       ));
14503ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      condT = newTemp(Ity_I32);
14504ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(condT, mkU32(1));
14505ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14506ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // notInITt = xor32(and32(old_itstate, 1), 1)
14507ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      //          = xor32(and32(0, 1), 1)
14508ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      //          = xor32(0, 1)
14509ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      //          = 1 :: I32
14510ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      //
14511ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // IRTemp notInITt = newTemp(Ity_I32);
14512ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // assign(notInITt,
14513ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      //        binop(Iop_Xor32,
14514ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      //              binop(Iop_And32, mkexpr(old_itstate), mkU32(1)),
14515ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      //              mkU32(1)));
14516ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14517ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // cond_AND_notInIT_T = and32(notInITt, condT)
14518ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      //                    = and32(1, 1)
14519ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      //                    = 1
14520ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      //
14521ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // cond_AND_notInIT_T = newTemp(Ity_I32);
14522ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // assign(cond_AND_notInIT_T,
14523ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      //        binop(Iop_And32, mkexpr(notInITt), mkexpr(condT)));
14524ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      cond_AND_notInIT_T = condT; /* 1 :: I32 */
14525ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14526ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* END "partial eval { ITSTATE = 0; STANDARD_PREAMBLE; }" */
14527ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
14528ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* BEGIN { STANDARD PREAMBLE; } */
14529ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14530ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      old_itstate = get_ITSTATE();
14531ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14532ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      new_itstate = newTemp(Ity_I32);
14533ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(new_itstate,
14534ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             binop(Iop_Shr32, mkexpr(old_itstate), mkU8(8)));
14535ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14536ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      put_ITSTATE(new_itstate);
14537ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14538ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Same strategy as for ARM insns: generate a condition
14539ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         temporary at this point (or IRTemp_INVALID, meaning
14540ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         unconditional).  We leave it to lower-level instruction
14541ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         decoders to decide whether they can generate straight-line
14542ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         code, or whether they must generate a side exit before the
14543ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         instruction.  condT :: Ity_I32 and is always either zero or
14544ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         one. */
14545ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp condT1 = newTemp(Ity_I32);
14546ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(condT1,
14547ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             mk_armg_calculate_condition_dyn(
14548ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                binop(Iop_Xor32,
14549ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      binop(Iop_And32, mkexpr(old_itstate), mkU32(0xF0)),
14550ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      mkU32(0xE0))
14551ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            )
14552ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      );
14553ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14554ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* This is a bit complex, but needed to make Memcheck understand
14555ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         that, if the condition in old_itstate[7:4] denotes AL (that
14556ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         is, if this instruction is to be executed unconditionally),
14557ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         then condT does not depend on the results of calling the
14558ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         helper.
14559ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14560ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         We test explicitly for old_itstate[7:4] == AL ^ 0xE, and in
14561ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         that case set condT directly to 1.  Else we use the results
14562ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         of the helper.  Since old_itstate is always defined and
14563ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         because Memcheck does lazy V-bit propagation through Mux0X,
14564ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         this will cause condT to always be a defined 1 if the
14565ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         condition is 'AL'.  From an execution semantics point of view
14566ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         this is irrelevant since we're merely duplicating part of the
14567ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         behaviour of the helper.  But it makes it clear to Memcheck,
14568ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         in this case, that condT does not in fact depend on the
14569ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         contents of the condition code thunk.  Without it, we get
14570ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         quite a lot of false errors.
14571ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14572ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         So, just to clarify: from a straight semantics point of view,
14573ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         we can simply do "assign(condT, mkexpr(condT1))", and the
14574ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         simulator still runs fine.  It's just that we get loads of
14575ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         false errors from Memcheck. */
14576ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      condT = newTemp(Ity_I32);
14577ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(condT, IRExpr_Mux0X(
14578ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       unop(Iop_32to8, binop(Iop_And32,
14579ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                             mkexpr(old_itstate),
14580ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                             mkU32(0xF0))),
14581ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       mkU32(1),
14582ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       mkexpr(condT1)
14583ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            ));
14584ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14585ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Something we don't have in ARM: generate a 0 or 1 value
14586ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         indicating whether or not we are in an IT block (NB: 0 = in
14587ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IT block, 1 = not in IT block).  This is used to gate
14588ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         condition code updates in 16-bit Thumb instructions. */
14589ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp notInITt = newTemp(Ity_I32);
14590ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(notInITt,
14591ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             binop(Iop_Xor32,
14592ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   binop(Iop_And32, mkexpr(old_itstate), mkU32(1)),
14593ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   mkU32(1)));
14594ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14595ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Compute 'condT && notInITt' -- that is, the instruction is
14596ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         going to execute, and we're not in an IT block.  This is the
14597ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         gating condition for updating condition codes in 16-bit Thumb
14598ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         instructions, except for CMP, CMN and TST. */
14599ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      cond_AND_notInIT_T = newTemp(Ity_I32);
14600ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(cond_AND_notInIT_T,
14601ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             binop(Iop_And32, mkexpr(notInITt), mkexpr(condT)));
14602ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* END { STANDARD PREAMBLE; } */
14603ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
14604ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14605ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14606ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* At this point:
14607ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      * ITSTATE has been updated
14608ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      * condT holds the guarding condition for this instruction (0 or 1),
14609ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      * notInITt is 1 if we're in "normal" code, 0 if in an IT block
14610ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      * cond_AND_notInIT_T is the AND of the above two.
14611ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14612ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      If the instruction proper can't trap, then there's nothing else
14613ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      to do w.r.t. ITSTATE -- just go and and generate IR for the
14614ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      insn, taking into account the guarding condition.
14615ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14616ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      If, however, the instruction might trap, then we must back up
14617ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ITSTATE to the old value, and re-update it after the potentially
14618ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      trapping IR section.  A trap can happen either via a memory
14619ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      reference or because we need to throw SIGILL.
14620ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14621ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      If an instruction has a side exit, we need to be sure that any
14622ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ITSTATE backup is re-updated before the side exit.
14623ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   */
14624ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14625ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ----------------------------------------------------------- */
14626ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* --                                                       -- */
14627ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* -- Thumb 16-bit integer instructions                     -- */
14628ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* --                                                       -- */
14629ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* -- IMPORTANT: references to insn1 or INSN1 are           -- */
14630ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* --            not allowed in this section                -- */
14631ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* --                                                       -- */
14632ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ----------------------------------------------------------- */
14633ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14634ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 16-bit instructions inside an IT block, apart from CMP, CMN and
14635ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      TST, do not set the condition codes.  Hence we must dynamically
14636ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      test for this case for every condition code update. */
14637ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14638ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IROp   anOp   = Iop_INVALID;
14639ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HChar* anOpNm = NULL;
14640ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14641ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ================ 16-bit 15:6 cases ================ */
14642ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14643ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (INSN0(15,6)) {
14644ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14645ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x10a:   // CMP
14646ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x10b: { // CMN
14647ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* ---------------- CMP Rn, Rm ---------------- */
14648ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Bool   isCMN = INSN0(15,6) == 0x10b;
14649ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt   rN    = INSN0(2,0);
14650ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt   rM    = INSN0(5,3);
14651ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp argL  = newTemp(Ity_I32);
14652ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp argR  = newTemp(Ity_I32);
14653ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( argL, getIRegT(rN) );
14654ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( argR, getIRegT(rM) );
14655ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Update flags regardless of whether in an IT block or not. */
14656ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      setFlags_D1_D2( isCMN ? ARMG_CC_OP_ADD : ARMG_CC_OP_SUB,
14657ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      argL, argR, condT );
14658ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("%s r%u, r%u\n", isCMN ? "cmn" : "cmp", rN, rM);
14659ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
14660ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
14661ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14662ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x108: {
14663ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* ---------------- TST Rn, Rm ---------------- */
14664ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt   rN   = INSN0(2,0);
14665ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt   rM   = INSN0(5,3);
14666ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp oldC = newTemp(Ity_I32);
14667ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp oldV = newTemp(Ity_I32);
14668ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp res  = newTemp(Ity_I32);
14669ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( oldC, mk_armg_calculate_flag_c() );
14670ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( oldV, mk_armg_calculate_flag_v() );
14671ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( res,  binop(Iop_And32, getIRegT(rN), getIRegT(rM)) );
14672ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Update flags regardless of whether in an IT block or not. */
14673ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      setFlags_D1_D2_ND( ARMG_CC_OP_LOGIC, res, oldC, oldV, condT );
14674ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("tst r%u, r%u\n", rN, rM);
14675ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
14676ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
14677ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14678ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x109: {
14679ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* ---------------- NEGS Rd, Rm ---------------- */
14680ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Rd = -Rm */
14681ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt   rM   = INSN0(5,3);
14682ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt   rD   = INSN0(2,0);
14683ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp arg  = newTemp(Ity_I32);
14684ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp zero = newTemp(Ity_I32);
14685ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(arg, getIRegT(rM));
14686ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(zero, mkU32(0));
14687ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // rD can never be r15
14688ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIRegT(rD, binop(Iop_Sub32, mkexpr(zero), mkexpr(arg)), condT);
14689ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      setFlags_D1_D2( ARMG_CC_OP_SUB, zero, arg, cond_AND_notInIT_T);
14690ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("negs r%u, r%u\n", rD, rM);
14691ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
14692ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
14693ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14694ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x10F: {
14695ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* ---------------- MVNS Rd, Rm ---------------- */
14696ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Rd = ~Rm */
14697ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt   rM   = INSN0(5,3);
14698ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt   rD   = INSN0(2,0);
14699ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp oldV = newTemp(Ity_I32);
14700ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp oldC = newTemp(Ity_I32);
14701ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp res  = newTemp(Ity_I32);
14702ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( oldV, mk_armg_calculate_flag_v() );
14703ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( oldC, mk_armg_calculate_flag_c() );
14704ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(res, unop(Iop_Not32, getIRegT(rM)));
14705ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // rD can never be r15
14706ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIRegT(rD, mkexpr(res), condT);
14707ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      setFlags_D1_D2_ND( ARMG_CC_OP_LOGIC, res, oldC, oldV,
14708ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         cond_AND_notInIT_T );
14709ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("mvns r%u, r%u\n", rD, rM);
14710ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
14711ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
14712ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14713ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x10C:
14714ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* ---------------- ORRS Rd, Rm ---------------- */
14715ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      anOp = Iop_Or32; anOpNm = "orr"; goto and_orr_eor_mul;
14716ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x100:
14717ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* ---------------- ANDS Rd, Rm ---------------- */
14718ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      anOp = Iop_And32; anOpNm = "and"; goto and_orr_eor_mul;
14719ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x101:
14720ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* ---------------- EORS Rd, Rm ---------------- */
14721ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      anOp = Iop_Xor32; anOpNm = "eor"; goto and_orr_eor_mul;
14722ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x10d:
14723ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* ---------------- MULS Rd, Rm ---------------- */
14724ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      anOp = Iop_Mul32; anOpNm = "mul"; goto and_orr_eor_mul;
14725ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   and_orr_eor_mul: {
14726ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Rd = Rd `op` Rm */
14727ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt   rM   = INSN0(5,3);
14728ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt   rD   = INSN0(2,0);
14729ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp res  = newTemp(Ity_I32);
14730ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp oldV = newTemp(Ity_I32);
14731ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp oldC = newTemp(Ity_I32);
14732ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( oldV, mk_armg_calculate_flag_v() );
14733ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( oldC, mk_armg_calculate_flag_c() );
14734ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( res, binop(anOp, getIRegT(rD), getIRegT(rM) ));
14735ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // not safe to read guest state after here
14736ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // rD can never be r15
14737ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIRegT(rD, mkexpr(res), condT);
14738ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      setFlags_D1_D2_ND( ARMG_CC_OP_LOGIC, res, oldC, oldV,
14739ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         cond_AND_notInIT_T );
14740ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("%s r%u, r%u\n", anOpNm, rD, rM);
14741ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
14742ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
14743ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14744ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x10E: {
14745ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* ---------------- BICS Rd, Rm ---------------- */
14746ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Rd = Rd & ~Rm */
14747ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt   rM   = INSN0(5,3);
14748ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt   rD   = INSN0(2,0);
14749ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp res  = newTemp(Ity_I32);
14750ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp oldV = newTemp(Ity_I32);
14751ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp oldC = newTemp(Ity_I32);
14752ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( oldV, mk_armg_calculate_flag_v() );
14753ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( oldC, mk_armg_calculate_flag_c() );
14754ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( res, binop(Iop_And32, getIRegT(rD),
14755ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    unop(Iop_Not32, getIRegT(rM) )));
14756ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // not safe to read guest state after here
14757ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // rD can never be r15
14758ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIRegT(rD, mkexpr(res), condT);
14759ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      setFlags_D1_D2_ND( ARMG_CC_OP_LOGIC, res, oldC, oldV,
14760ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         cond_AND_notInIT_T );
14761ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("bics r%u, r%u\n", rD, rM);
14762ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
14763ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
14764ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14765ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x105: {
14766ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* ---------------- ADCS Rd, Rm ---------------- */
14767ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Rd = Rd + Rm + oldC */
14768ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt   rM   = INSN0(5,3);
14769ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt   rD   = INSN0(2,0);
14770ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp argL = newTemp(Ity_I32);
14771ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp argR = newTemp(Ity_I32);
14772ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp oldC = newTemp(Ity_I32);
14773ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp res  = newTemp(Ity_I32);
14774ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(argL, getIRegT(rD));
14775ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(argR, getIRegT(rM));
14776ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(oldC, mk_armg_calculate_flag_c());
14777ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(res, binop(Iop_Add32,
14778ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        binop(Iop_Add32, mkexpr(argL), mkexpr(argR)),
14779ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        mkexpr(oldC)));
14780ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // rD can never be r15
14781ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIRegT(rD, mkexpr(res), condT);
14782ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      setFlags_D1_D2_ND( ARMG_CC_OP_ADC, argL, argR, oldC,
14783ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         cond_AND_notInIT_T );
14784ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("adcs r%u, r%u\n", rD, rM);
14785ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
14786ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
14787ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14788ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x106: {
14789ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* ---------------- SBCS Rd, Rm ---------------- */
14790ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Rd = Rd - Rm - (oldC ^ 1) */
14791ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt   rM   = INSN0(5,3);
14792ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt   rD   = INSN0(2,0);
14793ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp argL = newTemp(Ity_I32);
14794ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp argR = newTemp(Ity_I32);
14795ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp oldC = newTemp(Ity_I32);
14796ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp res  = newTemp(Ity_I32);
14797ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(argL, getIRegT(rD));
14798ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(argR, getIRegT(rM));
14799ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(oldC, mk_armg_calculate_flag_c());
14800ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(res, binop(Iop_Sub32,
14801ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        binop(Iop_Sub32, mkexpr(argL), mkexpr(argR)),
14802ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        binop(Iop_Xor32, mkexpr(oldC), mkU32(1))));
14803ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // rD can never be r15
14804ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIRegT(rD, mkexpr(res), condT);
14805ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      setFlags_D1_D2_ND( ARMG_CC_OP_SBB, argL, argR, oldC,
14806ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         cond_AND_notInIT_T );
14807ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("sbcs r%u, r%u\n", rD, rM);
14808ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
14809ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
14810ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14811ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x2CB: {
14812ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* ---------------- UXTB Rd, Rm ---------------- */
14813ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Rd = 8Uto32(Rm) */
14814ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rM = INSN0(5,3);
14815ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rD = INSN0(2,0);
14816ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIRegT(rD, binop(Iop_And32, getIRegT(rM), mkU32(0xFF)),
14817ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   condT);
14818ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("uxtb r%u, r%u\n", rD, rM);
14819ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
14820ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
14821ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14822ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x2C9: {
14823ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* ---------------- SXTB Rd, Rm ---------------- */
14824ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Rd = 8Sto32(Rm) */
14825ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rM = INSN0(5,3);
14826ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rD = INSN0(2,0);
14827ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIRegT(rD, binop(Iop_Sar32,
14828ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         binop(Iop_Shl32, getIRegT(rM), mkU8(24)),
14829ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         mkU8(24)),
14830ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   condT);
14831ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("sxtb r%u, r%u\n", rD, rM);
14832ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
14833ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
14834ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14835ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x2CA: {
14836ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* ---------------- UXTH Rd, Rm ---------------- */
14837ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Rd = 16Uto32(Rm) */
14838ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rM = INSN0(5,3);
14839ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rD = INSN0(2,0);
14840ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIRegT(rD, binop(Iop_And32, getIRegT(rM), mkU32(0xFFFF)),
14841ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   condT);
14842ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("uxth r%u, r%u\n", rD, rM);
14843ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
14844ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
14845ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14846ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x2C8: {
14847ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* ---------------- SXTH Rd, Rm ---------------- */
14848ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Rd = 16Sto32(Rm) */
14849ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rM = INSN0(5,3);
14850ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rD = INSN0(2,0);
14851ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIRegT(rD, binop(Iop_Sar32,
14852ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         binop(Iop_Shl32, getIRegT(rM), mkU8(16)),
14853ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         mkU8(16)),
14854ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   condT);
14855ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("sxth r%u, r%u\n", rD, rM);
14856ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
14857ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
14858ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14859ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x102:   // LSLS
14860ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x103:   // LSRS
14861ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x104:   // ASRS
14862ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x107: { // RORS
14863ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* ---------------- LSLS Rs, Rd ---------------- */
14864ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* ---------------- LSRS Rs, Rd ---------------- */
14865ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* ---------------- ASRS Rs, Rd ---------------- */
14866ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* ---------------- RORS Rs, Rd ---------------- */
14867ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Rd = Rd `op` Rs, and set flags */
14868ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt   rS   = INSN0(5,3);
14869ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt   rD   = INSN0(2,0);
14870ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp oldV = newTemp(Ity_I32);
14871ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp rDt  = newTemp(Ity_I32);
14872ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp rSt  = newTemp(Ity_I32);
14873ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp res  = newTemp(Ity_I32);
14874ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp resC = newTemp(Ity_I32);
14875ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      HChar* wot  = "???";
14876ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(rSt, getIRegT(rS));
14877ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(rDt, getIRegT(rD));
14878ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(oldV, mk_armg_calculate_flag_v());
14879ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Does not appear to be the standard 'how' encoding. */
14880ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      switch (INSN0(15,6)) {
14881ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0x102:
14882ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            compute_result_and_C_after_LSL_by_reg(
14883ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               dis_buf, &res, &resC, rDt, rSt, rD, rS
14884ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            );
14885ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            wot = "lsl";
14886ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
14887ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0x103:
14888ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            compute_result_and_C_after_LSR_by_reg(
14889ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               dis_buf, &res, &resC, rDt, rSt, rD, rS
14890ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            );
14891ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            wot = "lsr";
14892ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
14893ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0x104:
14894ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            compute_result_and_C_after_ASR_by_reg(
14895ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               dis_buf, &res, &resC, rDt, rSt, rD, rS
14896ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            );
14897ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            wot = "asr";
14898ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
14899ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0x107:
14900ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            compute_result_and_C_after_ROR_by_reg(
14901ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               dis_buf, &res, &resC, rDt, rSt, rD, rS
14902ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            );
14903ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            wot = "ror";
14904ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
14905ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         default:
14906ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /*NOTREACHED*/vassert(0);
14907ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
14908ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // not safe to read guest state after this point
14909ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIRegT(rD, mkexpr(res), condT);
14910ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      setFlags_D1_D2_ND( ARMG_CC_OP_LOGIC, res, resC, oldV,
14911ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         cond_AND_notInIT_T );
14912ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("%ss r%u, r%u\n", wot, rS, rD);
14913ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
14914ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
14915ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14916ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x2E8:   // REV
14917ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x2E9: { // REV16
14918ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* ---------------- REV   Rd, Rm ---------------- */
14919ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* ---------------- REV16 Rd, Rm ---------------- */
14920ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rM = INSN0(5,3);
14921ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rD = INSN0(2,0);
14922ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Bool isREV = INSN0(15,6) == 0x2E8;
14923ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp arg = newTemp(Ity_I32);
14924ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(arg, getIRegT(rM));
14925ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp res = isREV ? gen_REV(arg) : gen_REV16(arg);
14926ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIRegT(rD, mkexpr(res), condT);
14927ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("rev%s r%u, r%u\n", isREV ? "" : "16", rD, rM);
14928ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
14929ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
14930ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14931ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   default:
14932ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break; /* examine the next shortest prefix */
14933ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14934ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
14935ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14936ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14937ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ================ 16-bit 15:7 cases ================ */
14938ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14939ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (INSN0(15,7)) {
14940ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14941ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case BITS9(1,0,1,1,0,0,0,0,0): {
14942ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* ------------ ADD SP, #imm7 * 4 ------------ */
14943ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt uimm7 = INSN0(6,0);
14944ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIRegT(13, binop(Iop_Add32, getIRegT(13), mkU32(uimm7 * 4)),
14945ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   condT);
14946ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("add sp, #%u\n", uimm7 * 4);
14947ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
14948ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
14949ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14950ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case BITS9(1,0,1,1,0,0,0,0,1): {
14951ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* ------------ SUB SP, #imm7 * 4 ------------ */
14952ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt uimm7 = INSN0(6,0);
14953ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIRegT(13, binop(Iop_Sub32, getIRegT(13), mkU32(uimm7 * 4)),
14954ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   condT);
14955ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("sub sp, #%u\n", uimm7 * 4);
14956ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
14957ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
14958ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14959ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case BITS9(0,1,0,0,0,1,1,1,0): {
14960ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* ---------------- BX rM ---------------- */
14961ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Branch to reg, and optionally switch modes.  Reg contains a
14962ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         suitably encoded address therefore (w CPSR.T at the bottom).
14963ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Have to special-case r15, as usual. */
14964ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rM = (INSN0(6,6) << 3) | INSN0(5,3);
14965ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (BITS3(0,0,0) == INSN0(2,0)) {
14966ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp dst = newTemp(Ity_I32);
14967ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         gen_SIGILL_T_if_in_but_NLI_ITBlock(old_itstate, new_itstate);
14968ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         mk_skip_over_T16_if_cond_is_false(condT);
14969ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         condT = IRTemp_INVALID;
14970ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // now uncond
14971ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (rM <= 14) {
14972ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign( dst, getIRegT(rM) );
14973ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
14974ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            vassert(rM == 15);
14975ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign( dst, mkU32(guest_R15_curr_instr_notENC + 4) );
14976ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
14977ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         irsb->next     = mkexpr(dst);
14978b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         irsb->jumpkind = rM == 14 ? Ijk_Ret : Ijk_Boring;
14979ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         dres.whatNext  = Dis_StopHere;
14980ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("bx r%u (possibly switch to ARM mode)\n", rM);
14981ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
14982ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
14983ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
14984ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
14985ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14986ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ---------------- BLX rM ---------------- */
14987ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Branch and link to interworking address in rM. */
14988ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case BITS9(0,1,0,0,0,1,1,1,1): {
14989ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (BITS3(0,0,0) == INSN0(2,0)) {
14990ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         UInt rM = (INSN0(6,6) << 3) | INSN0(5,3);
14991ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp dst = newTemp(Ity_I32);
14992ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (rM <= 14) {
14993ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            gen_SIGILL_T_if_in_but_NLI_ITBlock(old_itstate, new_itstate);
14994ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            mk_skip_over_T16_if_cond_is_false(condT);
14995ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            condT = IRTemp_INVALID;
14996ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            // now uncond
14997ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* We're returning to Thumb code, hence "| 1" */
14998ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign( dst, getIRegT(rM) );
14999ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putIRegT( 14, mkU32( (guest_R15_curr_instr_notENC + 2) | 1 ),
15000ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          IRTemp_INVALID );
15001ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            irsb->next     = mkexpr(dst);
15002bdd8f267a354bac579372c9bae8773c6a8b14bd7Evgeniy Stepanov            irsb->jumpkind = Ijk_Call;
15003ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            dres.whatNext  = Dis_StopHere;
15004ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("blx r%u (possibly switch to ARM mode)\n", rM);
15005ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto decode_success;
15006ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
15007ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* else unpredictable, fall through */
15008ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
15009ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
15010ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
15011ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15012ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   default:
15013ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break; /* examine the next shortest prefix */
15014ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15015ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
15016ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15017ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15018ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ================ 16-bit 15:8 cases ================ */
15019ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15020ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (INSN0(15,8)) {
15021ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15022ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case BITS8(1,1,0,1,1,1,1,1): {
15023ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* ---------------- SVC ---------------- */
15024ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt imm8 = INSN0(7,0);
15025ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (imm8 == 0) {
15026ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* A syscall.  We can't do this conditionally, hence: */
15027ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         mk_skip_over_T16_if_cond_is_false( condT );
15028ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // FIXME: what if we have to back up and restart this insn?
15029ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // then ITSTATE will be wrong (we'll have it as "used")
15030ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // when it isn't.  Correct is to save ITSTATE in a
15031ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // stash pseudo-reg, and back up from that if we have to
15032ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // restart.
15033ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // uncond after here
15034ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         irsb->next     = mkU32( (guest_R15_curr_instr_notENC + 2) | 1 );
15035ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         irsb->jumpkind = Ijk_Sys_syscall;
15036ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         dres.whatNext  = Dis_StopHere;
15037ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("svc #0x%08x\n", imm8);
15038ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
15039ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
15040ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* else fall through */
15041ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
15042ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
15043ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15044ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case BITS8(0,1,0,0,0,1,0,0): {
15045ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* ---------------- ADD(HI) Rd, Rm ---------------- */
15046ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt h1 = INSN0(7,7);
15047ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt h2 = INSN0(6,6);
15048ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rM = (h2 << 3) | INSN0(5,3);
15049ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rD = (h1 << 3) | INSN0(2,0);
15050ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      //if (h1 == 0 && h2 == 0) { // Original T1 was more restrictive
15051ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (rD == 15 && rM == 15) {
15052ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // then it's invalid
15053ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
15054ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp res = newTemp(Ity_I32);
15055ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( res, binop(Iop_Add32, getIRegT(rD), getIRegT(rM) ));
15056ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (rD != 15) {
15057ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putIRegT( rD, mkexpr(res), condT );
15058ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
15059ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* Only allowed outside or last-in IT block; SIGILL if not so. */
15060ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            gen_SIGILL_T_if_in_but_NLI_ITBlock(old_itstate, new_itstate);
15061ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* jump over insn if not selected */
15062ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            mk_skip_over_T16_if_cond_is_false(condT);
15063ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            condT = IRTemp_INVALID;
15064ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            // now uncond
15065ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* non-interworking branch */
15066ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            irsb->next = binop(Iop_Or32, mkexpr(res), mkU32(1));
15067ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            irsb->jumpkind = Ijk_Boring;
15068ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            dres.whatNext = Dis_StopHere;
15069ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
15070ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("add(hi) r%u, r%u\n", rD, rM);
15071ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
15072ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
15073ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
15074ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
15075ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15076ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case BITS8(0,1,0,0,0,1,0,1): {
15077ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* ---------------- CMP(HI) Rd, Rm ---------------- */
15078ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt h1 = INSN0(7,7);
15079ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt h2 = INSN0(6,6);
15080ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rM = (h2 << 3) | INSN0(5,3);
15081ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rN = (h1 << 3) | INSN0(2,0);
15082ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (h1 != 0 || h2 != 0) {
15083ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp argL  = newTemp(Ity_I32);
15084ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp argR  = newTemp(Ity_I32);
15085ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( argL, getIRegT(rN) );
15086ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( argR, getIRegT(rM) );
15087ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Update flags regardless of whether in an IT block or not. */
15088ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         setFlags_D1_D2( ARMG_CC_OP_SUB, argL, argR, condT );
15089ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("cmphi r%u, r%u\n", rN, rM);
15090ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
15091ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
15092ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
15093ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
15094ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15095ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case BITS8(0,1,0,0,0,1,1,0): {
15096ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* ---------------- MOV(HI) Rd, Rm ---------------- */
15097ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt h1 = INSN0(7,7);
15098ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt h2 = INSN0(6,6);
15099ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rM = (h2 << 3) | INSN0(5,3);
15100ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rD = (h1 << 3) | INSN0(2,0);
15101ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* The old ARM ARM seems to disallow the case where both Rd and
15102ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Rm are "low" registers, but newer versions allow it. */
15103ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (1 /*h1 != 0 || h2 != 0*/) {
15104ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp val = newTemp(Ity_I32);
15105ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( val, getIRegT(rM) );
15106ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (rD != 15) {
15107ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putIRegT( rD, mkexpr(val), condT );
15108ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
15109ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* Only allowed outside or last-in IT block; SIGILL if not so. */
15110ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            gen_SIGILL_T_if_in_but_NLI_ITBlock(old_itstate, new_itstate);
15111ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* jump over insn if not selected */
15112ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            mk_skip_over_T16_if_cond_is_false(condT);
15113ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            condT = IRTemp_INVALID;
15114ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            // now uncond
15115ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* non-interworking branch */
15116ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            irsb->next = binop(Iop_Or32, mkexpr(val), mkU32(1));
15117b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            irsb->jumpkind = rM == 14 ? Ijk_Ret : Ijk_Boring;
15118ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            dres.whatNext = Dis_StopHere;
15119ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
15120ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("mov r%u, r%u\n", rD, rM);
15121ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
15122ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
15123ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
15124ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
15125ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15126ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case BITS8(1,0,1,1,1,1,1,1): {
15127ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* ---------------- IT (if-then) ---------------- */
15128ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt firstcond = INSN0(7,4);
15129ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt mask = INSN0(3,0);
15130ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt newITSTATE = 0;
15131ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* This is the ITSTATE represented as described in
15132ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         libvex_guest_arm.h.  It is not the ARM ARM representation. */
15133ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UChar c1 = '.';
15134ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UChar c2 = '.';
15135ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UChar c3 = '.';
15136ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Bool valid = compute_ITSTATE( &newITSTATE, &c1, &c2, &c3,
15137ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    firstcond, mask );
15138ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (valid && firstcond != 0xF/*NV*/) {
15139ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Not allowed in an IT block; SIGILL if so. */
15140ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         gen_SIGILL_T_if_in_ITBlock(old_itstate, new_itstate);
15141ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15142ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp t = newTemp(Ity_I32);
15143ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(t, mkU32(newITSTATE));
15144ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         put_ITSTATE(t);
15145ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15146ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("it%c%c%c %s\n", c1, c2, c3, nCC(firstcond));
15147ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
15148ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
15149ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
15150ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
15151ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15152ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case BITS8(1,0,1,1,0,0,0,1):
15153ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case BITS8(1,0,1,1,0,0,1,1):
15154ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case BITS8(1,0,1,1,1,0,0,1):
15155ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case BITS8(1,0,1,1,1,0,1,1): {
15156ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* ---------------- CB{N}Z ---------------- */
15157ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rN    = INSN0(2,0);
15158ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt bOP   = INSN0(11,11);
15159ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt imm32 = (INSN0(9,9) << 6) | (INSN0(7,3) << 1);
15160ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      gen_SIGILL_T_if_in_ITBlock(old_itstate, new_itstate);
15161ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* It's a conditional branch forward. */
15162ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp kond = newTemp(Ity_I1);
15163ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( kond, binop(bOP ? Iop_CmpNE32 : Iop_CmpEQ32,
15164ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          getIRegT(rN), mkU32(0)) );
15165ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15166ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(0 == (guest_R15_curr_instr_notENC & 1));
15167ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Looks like the nearest insn we can branch to is the one after
15168ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         next.  That makes sense, as there's no point in being able to
15169ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         encode a conditional branch to the next instruction. */
15170ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt dst = (guest_R15_curr_instr_notENC + 4 + imm32) | 1;
15171ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt(IRStmt_Exit( mkexpr(kond),
15172ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        Ijk_Boring,
15173ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        IRConst_U32(toUInt(dst)) ));
15174ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("cb%s r%u, 0x%x\n", bOP ? "nz" : "z", rN, dst - 1);
15175ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
15176ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
15177ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15178ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   default:
15179ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break; /* examine the next shortest prefix */
15180ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15181ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
15182ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15183ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15184ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ================ 16-bit 15:9 cases ================ */
15185ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15186ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (INSN0(15,9)) {
15187ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15188ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case BITS7(1,0,1,1,0,1,0): {
15189ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* ---------------- PUSH ---------------- */
15190ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* This is a bit like STMxx, but way simpler. Complications we
15191ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         don't have to deal with:
15192ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         * SP being one of the transferred registers
15193ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         * direction (increment vs decrement)
15194ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         * before-vs-after-ness
15195ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      */
15196ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Int  i, nRegs;
15197ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt bitR    = INSN0(8,8);
15198ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt regList = INSN0(7,0);
15199ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (bitR) regList |= (1 << 14);
15200ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15201ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (regList != 0) {
15202ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Since we can't generate a guaranteed non-trapping IR
15203ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            sequence, (1) jump over the insn if it is gated false, and
15204ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            (2) back out the ITSTATE update. */
15205ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         mk_skip_over_T16_if_cond_is_false(condT);
15206ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         condT = IRTemp_INVALID;
15207ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         put_ITSTATE(old_itstate);
15208ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // now uncond
15209ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15210ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         nRegs = 0;
15211ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         for (i = 0; i < 16; i++) {
15212ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if ((regList & (1 << i)) != 0)
15213ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               nRegs++;
15214ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
15215ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vassert(nRegs >= 1 && nRegs <= 8);
15216ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15217ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Move SP down first of all, so we're "covered".  And don't
15218ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            mess with its alignment. */
15219ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp newSP = newTemp(Ity_I32);
15220ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(newSP, binop(Iop_Sub32, getIRegT(13), mkU32(4 * nRegs)));
15221ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIRegT(13, mkexpr(newSP), IRTemp_INVALID);
15222ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15223ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Generate a transfer base address as a forced-aligned
15224ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            version of the final SP value. */
15225ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp base = newTemp(Ity_I32);
15226ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(base, binop(Iop_And32, mkexpr(newSP), mkU32(~3)));
15227ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15228ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Now the transfers */
15229ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         nRegs = 0;
15230ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         for (i = 0; i < 16; i++) {
15231ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if ((regList & (1 << i)) != 0) {
15232ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               storeLE( binop(Iop_Add32, mkexpr(base), mkU32(4 * nRegs)),
15233ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        getIRegT(i) );
15234ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               nRegs++;
15235ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
15236ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
15237ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15238ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Reinstate the ITSTATE update. */
15239ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         put_ITSTATE(new_itstate);
15240ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15241ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("push {%s0x%04x}\n", bitR ? "lr," : "", regList & 0xFF);
15242ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
15243ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
15244ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
15245ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
15246ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15247ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case BITS7(1,0,1,1,1,1,0): {
15248ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* ---------------- POP ---------------- */
15249ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Int  i, nRegs;
15250ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt bitR    = INSN0(8,8);
15251ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt regList = INSN0(7,0);
15252ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15253ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (regList != 0 || bitR) {
15254ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Since we can't generate a guaranteed non-trapping IR
15255ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            sequence, (1) jump over the insn if it is gated false, and
15256ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            (2) back out the ITSTATE update. */
15257ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         mk_skip_over_T16_if_cond_is_false(condT);
15258ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         condT = IRTemp_INVALID;
15259ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         put_ITSTATE(old_itstate);
15260ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // now uncond
15261ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15262ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         nRegs = 0;
15263ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         for (i = 0; i < 8; i++) {
15264ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if ((regList & (1 << i)) != 0)
15265ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               nRegs++;
15266ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
15267ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vassert(nRegs >= 0 && nRegs <= 7);
15268ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vassert(bitR == 0 || bitR == 1);
15269ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15270ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp oldSP = newTemp(Ity_I32);
15271ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(oldSP, getIRegT(13));
15272ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15273ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Generate a transfer base address as a forced-aligned
15274ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            version of the original SP value. */
15275ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp base = newTemp(Ity_I32);
15276ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(base, binop(Iop_And32, mkexpr(oldSP), mkU32(~3)));
15277ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15278ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Compute a new value for SP, but don't install it yet, so
15279ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            that we're "covered" until all the transfers are done.
15280ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            And don't mess with its alignment. */
15281ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp newSP = newTemp(Ity_I32);
15282ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(newSP, binop(Iop_Add32, mkexpr(oldSP),
15283ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                        mkU32(4 * (nRegs + bitR))));
15284ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15285ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Now the transfers, not including PC */
15286ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         nRegs = 0;
15287ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         for (i = 0; i < 8; i++) {
15288ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if ((regList & (1 << i)) != 0) {
15289ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               putIRegT(i, loadLE( Ity_I32,
15290ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   binop(Iop_Add32, mkexpr(base),
15291ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                                    mkU32(4 * nRegs))),
15292ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           IRTemp_INVALID );
15293ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               nRegs++;
15294ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
15295ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
15296ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15297ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp newPC = IRTemp_INVALID;
15298ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (bitR) {
15299ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            newPC = newTemp(Ity_I32);
15300ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign( newPC, loadLE( Ity_I32,
15301ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   binop(Iop_Add32, mkexpr(base),
15302ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                                    mkU32(4 * nRegs))));
15303ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
15304ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15305ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Now we can safely install the new SP value */
15306ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIRegT(13, mkexpr(newSP), IRTemp_INVALID);
15307ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15308ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Reinstate the ITSTATE update. */
15309ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         put_ITSTATE(new_itstate);
15310ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15311ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* now, do we also have to do a branch?  If so, it turns out
15312ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            that the new PC value is encoded exactly as we need it to
15313ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            be -- with CPSR.T in the bottom bit.  So we can simply use
15314ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            it as is, no need to mess with it.  Note, therefore, this
15315ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            is an interworking return. */
15316ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (bitR) {
15317ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            irsb->next     = mkexpr(newPC);
15318ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            irsb->jumpkind = Ijk_Ret;
15319ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            dres.whatNext  = Dis_StopHere;
15320ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
15321ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15322ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("pop {%s0x%04x}\n", bitR ? "pc," : "", regList & 0xFF);
15323ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
15324ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
15325ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
15326ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
15327ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15328ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case BITS7(0,0,0,1,1,1,0):   /* ADDS */
15329ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case BITS7(0,0,0,1,1,1,1): { /* SUBS */
15330ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* ---------------- ADDS Rd, Rn, #uimm3 ---------------- */
15331ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* ---------------- SUBS Rd, Rn, #uimm3 ---------------- */
15332ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt   uimm3 = INSN0(8,6);
15333ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt   rN    = INSN0(5,3);
15334ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt   rD    = INSN0(2,0);
15335ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt   isSub = INSN0(9,9);
15336ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp argL  = newTemp(Ity_I32);
15337ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp argR  = newTemp(Ity_I32);
15338ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( argL, getIRegT(rN) );
15339ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( argR, mkU32(uimm3) );
15340ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIRegT(rD, binop(isSub ? Iop_Sub32 : Iop_Add32,
15341ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         mkexpr(argL), mkexpr(argR)),
15342ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   condT);
15343ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      setFlags_D1_D2( isSub ? ARMG_CC_OP_SUB : ARMG_CC_OP_ADD,
15344ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      argL, argR, cond_AND_notInIT_T );
15345ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("%s r%u, r%u, #%u\n", isSub ? "subs" : "adds", rD, rN, uimm3);
15346ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
15347ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
15348ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15349ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case BITS7(0,0,0,1,1,0,0):   /* ADDS */
15350ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case BITS7(0,0,0,1,1,0,1): { /* SUBS */
15351ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* ---------------- ADDS Rd, Rn, Rm ---------------- */
15352ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* ---------------- SUBS Rd, Rn, Rm ---------------- */
15353ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt   rM    = INSN0(8,6);
15354ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt   rN    = INSN0(5,3);
15355ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt   rD    = INSN0(2,0);
15356ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt   isSub = INSN0(9,9);
15357ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp argL  = newTemp(Ity_I32);
15358ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp argR  = newTemp(Ity_I32);
15359ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( argL, getIRegT(rN) );
15360ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( argR, getIRegT(rM) );
15361ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIRegT( rD, binop(isSub ? Iop_Sub32 : Iop_Add32,
15362ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          mkexpr(argL), mkexpr(argR)),
15363ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    condT );
15364ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      setFlags_D1_D2( isSub ? ARMG_CC_OP_SUB : ARMG_CC_OP_ADD,
15365ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      argL, argR, cond_AND_notInIT_T );
15366ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("%s r%u, r%u, r%u\n", isSub ? "subs" : "adds", rD, rN, rM);
15367ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
15368ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
15369ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15370ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case BITS7(0,1,0,1,0,0,0):   /* STR */
15371ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case BITS7(0,1,0,1,1,0,0): { /* LDR */
15372ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* ------------- LDR Rd, [Rn, Rm] ------------- */
15373ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* ------------- STR Rd, [Rn, Rm] ------------- */
15374ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* LDR/STR Rd, [Rn + Rm] */
15375ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt    rD   = INSN0(2,0);
15376ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt    rN   = INSN0(5,3);
15377ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt    rM   = INSN0(8,6);
15378ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt    isLD = INSN0(11,11);
15379ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15380ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      mk_skip_over_T16_if_cond_is_false(condT);
15381ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      condT = IRTemp_INVALID;
15382ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // now uncond
15383ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15384ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRExpr* ea = binop(Iop_Add32, getIRegT(rN), getIRegT(rM));
15385ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      put_ITSTATE(old_itstate); // backout
15386ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (isLD) {
15387ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIRegT(rD, loadLE(Ity_I32, ea), IRTemp_INVALID);
15388ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
15389ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         storeLE(ea, getIRegT(rD));
15390ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
15391ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      put_ITSTATE(new_itstate); // restore
15392ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15393ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("%s r%u, [r%u, r%u]\n", isLD ? "ldr" : "str", rD, rN, rM);
15394ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
15395ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
15396ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15397ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case BITS7(0,1,0,1,0,0,1):
15398ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case BITS7(0,1,0,1,1,0,1): {
15399ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* ------------- LDRH Rd, [Rn, Rm] ------------- */
15400ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* ------------- STRH Rd, [Rn, Rm] ------------- */
15401ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* LDRH/STRH Rd, [Rn + Rm] */
15402ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt    rD   = INSN0(2,0);
15403ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt    rN   = INSN0(5,3);
15404ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt    rM   = INSN0(8,6);
15405ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt    isLD = INSN0(11,11);
15406ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15407ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      mk_skip_over_T16_if_cond_is_false(condT);
15408ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      condT = IRTemp_INVALID;
15409ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // now uncond
15410ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15411ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRExpr* ea = binop(Iop_Add32, getIRegT(rN), getIRegT(rM));
15412ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      put_ITSTATE(old_itstate); // backout
15413ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (isLD) {
15414ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIRegT(rD, unop(Iop_16Uto32, loadLE(Ity_I16, ea)),
15415ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      IRTemp_INVALID);
15416ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
15417ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         storeLE( ea, unop(Iop_32to16, getIRegT(rD)) );
15418ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
15419ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      put_ITSTATE(new_itstate); // restore
15420ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15421ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("%sh r%u, [r%u, r%u]\n", isLD ? "ldr" : "str", rD, rN, rM);
15422ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
15423ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
15424ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15425ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case BITS7(0,1,0,1,1,1,1): {
15426ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* ------------- LDRSH Rd, [Rn, Rm] ------------- */
15427ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* LDRSH Rd, [Rn + Rm] */
15428ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt    rD = INSN0(2,0);
15429ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt    rN = INSN0(5,3);
15430ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt    rM = INSN0(8,6);
15431ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15432ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      mk_skip_over_T16_if_cond_is_false(condT);
15433ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      condT = IRTemp_INVALID;
15434ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // now uncond
15435ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15436ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRExpr* ea = binop(Iop_Add32, getIRegT(rN), getIRegT(rM));
15437ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      put_ITSTATE(old_itstate); // backout
15438ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIRegT(rD, unop(Iop_16Sto32, loadLE(Ity_I16, ea)),
15439ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   IRTemp_INVALID);
15440ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      put_ITSTATE(new_itstate); // restore
15441ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15442ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("ldrsh r%u, [r%u, r%u]\n", rD, rN, rM);
15443ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
15444ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
15445ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15446ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case BITS7(0,1,0,1,0,1,1): {
15447ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* ------------- LDRSB Rd, [Rn, Rm] ------------- */
15448ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* LDRSB Rd, [Rn + Rm] */
15449ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt    rD = INSN0(2,0);
15450ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt    rN = INSN0(5,3);
15451ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt    rM = INSN0(8,6);
15452ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15453ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      mk_skip_over_T16_if_cond_is_false(condT);
15454ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      condT = IRTemp_INVALID;
15455ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // now uncond
15456ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15457ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRExpr* ea = binop(Iop_Add32, getIRegT(rN), getIRegT(rM));
15458ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      put_ITSTATE(old_itstate); // backout
15459ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIRegT(rD, unop(Iop_8Sto32, loadLE(Ity_I8, ea)),
15460ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   IRTemp_INVALID);
15461ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      put_ITSTATE(new_itstate); // restore
15462ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15463ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("ldrsb r%u, [r%u, r%u]\n", rD, rN, rM);
15464ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
15465ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
15466ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15467ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case BITS7(0,1,0,1,0,1,0):
15468ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case BITS7(0,1,0,1,1,1,0): {
15469ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* ------------- LDRB Rd, [Rn, Rm] ------------- */
15470ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* ------------- STRB Rd, [Rn, Rm] ------------- */
15471ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* LDRB/STRB Rd, [Rn + Rm] */
15472ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt    rD   = INSN0(2,0);
15473ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt    rN   = INSN0(5,3);
15474ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt    rM   = INSN0(8,6);
15475ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt    isLD = INSN0(11,11);
15476ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15477ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      mk_skip_over_T16_if_cond_is_false(condT);
15478ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      condT = IRTemp_INVALID;
15479ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // now uncond
15480ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15481ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRExpr* ea = binop(Iop_Add32, getIRegT(rN), getIRegT(rM));
15482ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      put_ITSTATE(old_itstate); // backout
15483ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (isLD) {
15484ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIRegT(rD, unop(Iop_8Uto32, loadLE(Ity_I8, ea)),
15485ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  IRTemp_INVALID);
15486ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
15487ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         storeLE( ea, unop(Iop_32to8, getIRegT(rD)) );
15488ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
15489ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      put_ITSTATE(new_itstate); // restore
15490ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15491ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("%sb r%u, [r%u, r%u]\n", isLD ? "ldr" : "str", rD, rN, rM);
15492ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
15493ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
15494ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15495ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   default:
15496ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break; /* examine the next shortest prefix */
15497ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15498ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
15499ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15500ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15501ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ================ 16-bit 15:11 cases ================ */
15502ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15503ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (INSN0(15,11)) {
15504ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15505ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case BITS5(0,0,1,1,0):
15506ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case BITS5(0,0,1,1,1): {
15507ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* ---------------- ADDS Rn, #uimm8 ---------------- */
15508ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* ---------------- SUBS Rn, #uimm8 ---------------- */
15509ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt   isSub = INSN0(11,11);
15510ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt   rN    = INSN0(10,8);
15511ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt   uimm8 = INSN0(7,0);
15512ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp argL  = newTemp(Ity_I32);
15513ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp argR  = newTemp(Ity_I32);
15514ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( argL, getIRegT(rN) );
15515ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( argR, mkU32(uimm8) );
15516ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIRegT( rN, binop(isSub ? Iop_Sub32 : Iop_Add32,
15517ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          mkexpr(argL), mkexpr(argR)), condT );
15518ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      setFlags_D1_D2( isSub ? ARMG_CC_OP_SUB : ARMG_CC_OP_ADD,
15519ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      argL, argR, cond_AND_notInIT_T );
15520ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("%s r%u, #%u\n", isSub ? "subs" : "adds", rN, uimm8);
15521ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
15522ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
15523ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15524ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case BITS5(1,0,1,0,0): {
15525ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* ---------------- ADD rD, PC, #imm8 * 4 ---------------- */
15526ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* a.k.a. ADR */
15527ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* rD = align4(PC) + imm8 * 4 */
15528ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rD   = INSN0(10,8);
15529ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt imm8 = INSN0(7,0);
15530ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIRegT(rD, binop(Iop_Add32,
15531ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         binop(Iop_And32, getIRegT(15), mkU32(~3U)),
15532ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         mkU32(imm8 * 4)),
15533ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   condT);
15534ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("add r%u, pc, #%u\n", rD, imm8 * 4);
15535ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
15536ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
15537ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15538ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case BITS5(1,0,1,0,1): {
15539ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* ---------------- ADD rD, SP, #imm8 * 4 ---------------- */
15540ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rD   = INSN0(10,8);
15541ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt imm8 = INSN0(7,0);
15542ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIRegT(rD, binop(Iop_Add32, getIRegT(13), mkU32(imm8 * 4)),
15543ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   condT);
15544ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("add r%u, r13, #%u\n", rD, imm8 * 4);
15545ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
15546ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
15547ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15548ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case BITS5(0,0,1,0,1): {
15549ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* ---------------- CMP Rn, #uimm8 ---------------- */
15550ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt   rN    = INSN0(10,8);
15551ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt   uimm8 = INSN0(7,0);
15552ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp argL  = newTemp(Ity_I32);
15553ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp argR  = newTemp(Ity_I32);
15554ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( argL, getIRegT(rN) );
15555ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( argR, mkU32(uimm8) );
15556ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Update flags regardless of whether in an IT block or not. */
15557ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      setFlags_D1_D2( ARMG_CC_OP_SUB, argL, argR, condT );
15558ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("cmp r%u, #%u\n", rN, uimm8);
15559ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
15560ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
15561ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15562ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case BITS5(0,0,1,0,0): {
15563ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* -------------- (T1) MOVS Rn, #uimm8 -------------- */
15564ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt   rD    = INSN0(10,8);
15565ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt   uimm8 = INSN0(7,0);
15566ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp oldV  = newTemp(Ity_I32);
15567ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp oldC  = newTemp(Ity_I32);
15568ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp res   = newTemp(Ity_I32);
15569ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( oldV, mk_armg_calculate_flag_v() );
15570ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( oldC, mk_armg_calculate_flag_c() );
15571ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( res, mkU32(uimm8) );
15572ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIRegT(rD, mkexpr(res), condT);
15573ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      setFlags_D1_D2_ND( ARMG_CC_OP_LOGIC, res, oldC, oldV,
15574ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         cond_AND_notInIT_T );
15575ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("movs r%u, #%u\n", rD, uimm8);
15576ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
15577ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
15578ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15579ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case BITS5(0,1,0,0,1): {
15580ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* ------------- LDR Rd, [PC, #imm8 * 4] ------------- */
15581ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* LDR Rd, [align4(PC) + imm8 * 4] */
15582ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt   rD   = INSN0(10,8);
15583ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt   imm8 = INSN0(7,0);
15584ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp ea   = newTemp(Ity_I32);
15585ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15586ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      mk_skip_over_T16_if_cond_is_false(condT);
15587ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      condT = IRTemp_INVALID;
15588ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // now uncond
15589ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15590ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(ea, binop(Iop_Add32,
15591ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       binop(Iop_And32, getIRegT(15), mkU32(~3U)),
15592ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       mkU32(imm8 * 4)));
15593ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      put_ITSTATE(old_itstate); // backout
15594ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIRegT(rD, loadLE(Ity_I32, mkexpr(ea)),
15595ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   IRTemp_INVALID);
15596ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      put_ITSTATE(new_itstate); // restore
15597ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15598ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("ldr r%u, [pc, #%u]\n", rD, imm8 * 4);
15599ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
15600ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
15601ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15602ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case BITS5(0,1,1,0,0):   /* STR */
15603ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case BITS5(0,1,1,0,1): { /* LDR */
15604ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* ------------- LDR Rd, [Rn, #imm5 * 4] ------------- */
15605ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* ------------- STR Rd, [Rn, #imm5 * 4] ------------- */
15606ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* LDR/STR Rd, [Rn + imm5 * 4] */
15607ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt    rD   = INSN0(2,0);
15608ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt    rN   = INSN0(5,3);
15609ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt    imm5 = INSN0(10,6);
15610ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt    isLD = INSN0(11,11);
15611ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15612ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      mk_skip_over_T16_if_cond_is_false(condT);
15613ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      condT = IRTemp_INVALID;
15614ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // now uncond
15615ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15616ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRExpr* ea = binop(Iop_Add32, getIRegT(rN), mkU32(imm5 * 4));
15617ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      put_ITSTATE(old_itstate); // backout
15618ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (isLD) {
15619ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIRegT(rD, loadLE(Ity_I32, ea), IRTemp_INVALID);
15620ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
15621ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         storeLE( ea, getIRegT(rD) );
15622ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
15623ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      put_ITSTATE(new_itstate); // restore
15624ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15625ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("%s r%u, [r%u, #%u]\n", isLD ? "ldr" : "str", rD, rN, imm5 * 4);
15626ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
15627ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
15628ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15629ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case BITS5(1,0,0,0,0):   /* STRH */
15630ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case BITS5(1,0,0,0,1): { /* LDRH */
15631ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* ------------- LDRH Rd, [Rn, #imm5 * 2] ------------- */
15632ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* ------------- STRH Rd, [Rn, #imm5 * 2] ------------- */
15633ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* LDRH/STRH Rd, [Rn + imm5 * 2] */
15634ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt    rD   = INSN0(2,0);
15635ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt    rN   = INSN0(5,3);
15636ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt    imm5 = INSN0(10,6);
15637ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt    isLD = INSN0(11,11);
15638ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15639ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      mk_skip_over_T16_if_cond_is_false(condT);
15640ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      condT = IRTemp_INVALID;
15641ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // now uncond
15642ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15643ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRExpr* ea = binop(Iop_Add32, getIRegT(rN), mkU32(imm5 * 2));
15644ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      put_ITSTATE(old_itstate); // backout
15645ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (isLD) {
15646ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIRegT(rD, unop(Iop_16Uto32, loadLE(Ity_I16, ea)),
15647ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  IRTemp_INVALID);
15648ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
15649ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         storeLE( ea, unop(Iop_32to16, getIRegT(rD)) );
15650ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
15651ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      put_ITSTATE(new_itstate); // restore
15652ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15653ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("%sh r%u, [r%u, #%u]\n", isLD ? "ldr" : "str", rD, rN, imm5 * 2);
15654ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
15655ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
15656ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15657ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case BITS5(0,1,1,1,0):   /* STRB */
15658ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case BITS5(0,1,1,1,1): { /* LDRB */
15659ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* ------------- LDRB Rd, [Rn, #imm5] ------------- */
15660ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* ------------- STRB Rd, [Rn, #imm5] ------------- */
15661ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* LDRB/STRB Rd, [Rn + imm5] */
15662ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt    rD   = INSN0(2,0);
15663ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt    rN   = INSN0(5,3);
15664ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt    imm5 = INSN0(10,6);
15665ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt    isLD = INSN0(11,11);
15666ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15667ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      mk_skip_over_T16_if_cond_is_false(condT);
15668ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      condT = IRTemp_INVALID;
15669ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // now uncond
15670ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15671ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRExpr* ea = binop(Iop_Add32, getIRegT(rN), mkU32(imm5));
15672ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      put_ITSTATE(old_itstate); // backout
15673ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (isLD) {
15674ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIRegT(rD, unop(Iop_8Uto32, loadLE(Ity_I8, ea)),
15675ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  IRTemp_INVALID);
15676ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
15677ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         storeLE( ea, unop(Iop_32to8, getIRegT(rD)) );
15678ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
15679ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      put_ITSTATE(new_itstate); // restore
15680ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15681ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("%sb r%u, [r%u, #%u]\n", isLD ? "ldr" : "str", rD, rN, imm5);
15682ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
15683ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
15684ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15685ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case BITS5(1,0,0,1,0):   /* STR */
15686ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case BITS5(1,0,0,1,1): { /* LDR */
15687ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* ------------- LDR Rd, [SP, #imm8 * 4] ------------- */
15688ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* ------------- STR Rd, [SP, #imm8 * 4] ------------- */
15689ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* LDR/STR Rd, [SP + imm8 * 4] */
15690ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rD    = INSN0(10,8);
15691ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt imm8  = INSN0(7,0);
15692ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt isLD  = INSN0(11,11);
15693ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15694ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      mk_skip_over_T16_if_cond_is_false(condT);
15695ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      condT = IRTemp_INVALID;
15696ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // now uncond
15697ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15698ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRExpr* ea = binop(Iop_Add32, getIRegT(13), mkU32(imm8 * 4));
15699ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      put_ITSTATE(old_itstate); // backout
15700ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (isLD) {
15701ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIRegT(rD, loadLE(Ity_I32, ea), IRTemp_INVALID);
15702ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
15703ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         storeLE(ea, getIRegT(rD));
15704ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
15705ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      put_ITSTATE(new_itstate); // restore
15706ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15707ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("%s r%u, [sp, #%u]\n", isLD ? "ldr" : "str", rD, imm8 * 4);
15708ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
15709ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
15710ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15711ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case BITS5(1,1,0,0,1): {
15712ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* ------------- LDMIA Rn!, {reglist} ------------- */
15713ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Int i, nRegs = 0;
15714ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rN   = INSN0(10,8);
15715ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt list = INSN0(7,0);
15716ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Empty lists aren't allowed. */
15717ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (list != 0) {
15718ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         mk_skip_over_T16_if_cond_is_false(condT);
15719ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         condT = IRTemp_INVALID;
15720ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         put_ITSTATE(old_itstate);
15721ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // now uncond
15722ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15723ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp oldRn = newTemp(Ity_I32);
15724ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp base  = newTemp(Ity_I32);
15725ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(oldRn, getIRegT(rN));
15726ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(base, binop(Iop_And32, mkexpr(oldRn), mkU32(~3U)));
15727ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         for (i = 0; i < 8; i++) {
15728ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (0 == (list & (1 << i)))
15729ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               continue;
15730ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            nRegs++;
15731ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putIRegT(
15732ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               i, loadLE(Ity_I32,
15733ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         binop(Iop_Add32, mkexpr(base),
15734ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                          mkU32(nRegs * 4 - 4))),
15735ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRTemp_INVALID
15736ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            );
15737ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
15738ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Only do the writeback for rN if it isn't in the list of
15739ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            registers to be transferred. */
15740ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (0 == (list & (1 << rN))) {
15741ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putIRegT(rN,
15742ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     binop(Iop_Add32, mkexpr(oldRn),
15743ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                      mkU32(nRegs * 4)),
15744ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     IRTemp_INVALID
15745ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            );
15746ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
15747ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15748ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Reinstate the ITSTATE update. */
15749ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         put_ITSTATE(new_itstate);
15750ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15751ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("ldmia r%u!, {0x%04x}\n", rN, list);
15752ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
15753ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
15754ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
15755ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
15756ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15757ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case BITS5(1,1,0,0,0): {
15758ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* ------------- STMIA Rn!, {reglist} ------------- */
15759ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Int i, nRegs = 0;
15760ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rN   = INSN0(10,8);
15761ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt list = INSN0(7,0);
15762ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Empty lists aren't allowed.  Also, if rN is in the list then
15763ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         it must be the lowest numbered register in the list. */
15764ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Bool valid = list != 0;
15765ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (valid && 0 != (list & (1 << rN))) {
15766ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         for (i = 0; i < rN; i++) {
15767ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (0 != (list & (1 << i)))
15768ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               valid = False;
15769ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
15770ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
15771ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (valid) {
15772ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         mk_skip_over_T16_if_cond_is_false(condT);
15773ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         condT = IRTemp_INVALID;
15774ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         put_ITSTATE(old_itstate);
15775ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // now uncond
15776ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15777ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp oldRn = newTemp(Ity_I32);
15778ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp base = newTemp(Ity_I32);
15779ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(oldRn, getIRegT(rN));
15780ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(base, binop(Iop_And32, mkexpr(oldRn), mkU32(~3U)));
15781ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         for (i = 0; i < 8; i++) {
15782ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (0 == (list & (1 << i)))
15783ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               continue;
15784ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            nRegs++;
15785ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            storeLE( binop(Iop_Add32, mkexpr(base), mkU32(nRegs * 4 - 4)),
15786ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     getIRegT(i) );
15787ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
15788ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Always do the writeback. */
15789ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIRegT(rN,
15790ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  binop(Iop_Add32, mkexpr(oldRn),
15791ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   mkU32(nRegs * 4)),
15792ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  IRTemp_INVALID);
15793ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15794ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Reinstate the ITSTATE update. */
15795ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         put_ITSTATE(new_itstate);
15796ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15797ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("stmia r%u!, {0x%04x}\n", rN, list);
15798ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
15799ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
15800ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
15801ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
15802ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15803ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case BITS5(0,0,0,0,0):   /* LSLS */
15804ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case BITS5(0,0,0,0,1):   /* LSRS */
15805ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case BITS5(0,0,0,1,0): { /* ASRS */
15806ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* ---------------- LSLS Rd, Rm, #imm5 ---------------- */
15807ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* ---------------- LSRS Rd, Rm, #imm5 ---------------- */
15808ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* ---------------- ASRS Rd, Rm, #imm5 ---------------- */
15809ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt   rD   = INSN0(2,0);
15810ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt   rM   = INSN0(5,3);
15811ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt   imm5 = INSN0(10,6);
15812ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp res  = newTemp(Ity_I32);
15813ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp resC = newTemp(Ity_I32);
15814ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp rMt  = newTemp(Ity_I32);
15815ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp oldV = newTemp(Ity_I32);
15816ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      HChar* wot  = "???";
15817ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(rMt, getIRegT(rM));
15818ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(oldV, mk_armg_calculate_flag_v());
15819ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Looks like INSN0(12,11) are the standard 'how' encoding.
15820ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Could compactify if the ROR case later appears. */
15821ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      switch (INSN0(15,11)) {
15822ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case BITS5(0,0,0,0,0):
15823ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            compute_result_and_C_after_LSL_by_imm5(
15824ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               dis_buf, &res, &resC, rMt, imm5, rM
15825ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            );
15826ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            wot = "lsl";
15827ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
15828ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case BITS5(0,0,0,0,1):
15829ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            compute_result_and_C_after_LSR_by_imm5(
15830ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               dis_buf, &res, &resC, rMt, imm5, rM
15831ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            );
15832ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            wot = "lsr";
15833ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
15834ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case BITS5(0,0,0,1,0):
15835ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            compute_result_and_C_after_ASR_by_imm5(
15836ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               dis_buf, &res, &resC, rMt, imm5, rM
15837ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            );
15838ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            wot = "asr";
15839ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
15840ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         default:
15841ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /*NOTREACHED*/vassert(0);
15842ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
15843ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // not safe to read guest state after this point
15844ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIRegT(rD, mkexpr(res), condT);
15845ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      setFlags_D1_D2_ND( ARMG_CC_OP_LOGIC, res, resC, oldV,
15846ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         cond_AND_notInIT_T );
15847ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* ignore buf and roll our own output */
15848ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("%ss r%u, r%u, #%u\n", wot, rD, rM, imm5);
15849ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
15850ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
15851ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15852ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case BITS5(1,1,1,0,0): {
15853ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* ---------------- B #simm11 ---------------- */
15854ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Int  simm11 = INSN0(10,0);
15855ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           simm11 = (simm11 << 21) >> 20;
15856ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt dst    = simm11 + guest_R15_curr_instr_notENC + 4;
15857ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Only allowed outside or last-in IT block; SIGILL if not so. */
15858ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      gen_SIGILL_T_if_in_but_NLI_ITBlock(old_itstate, new_itstate);
15859ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // and skip this insn if not selected; being cleverer is too
15860ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // difficult
15861ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      mk_skip_over_T16_if_cond_is_false(condT);
15862ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      condT = IRTemp_INVALID;
15863ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // now uncond
15864ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      irsb->next     = mkU32( dst | 1 /*CPSR.T*/ );
15865ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      irsb->jumpkind = Ijk_Boring;
15866ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      dres.whatNext  = Dis_StopHere;
15867ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("b 0x%x\n", dst);
15868ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
15869ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
15870ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15871ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   default:
15872ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break; /* examine the next shortest prefix */
15873ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15874ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
15875ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15876ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15877ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ================ 16-bit 15:12 cases ================ */
15878ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15879ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (INSN0(15,12)) {
15880ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15881ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case BITS4(1,1,0,1): {
15882ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* ---------------- Bcond #simm8 ---------------- */
15883ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt cond  = INSN0(11,8);
15884ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Int  simm8 = INSN0(7,0);
15885ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           simm8 = (simm8 << 24) >> 23;
15886ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt dst   = simm8 + guest_R15_curr_instr_notENC + 4;
15887ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (cond != ARMCondAL && cond != ARMCondNV) {
15888ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Not allowed in an IT block; SIGILL if so. */
15889ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         gen_SIGILL_T_if_in_ITBlock(old_itstate, new_itstate);
15890ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15891ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp kondT = newTemp(Ity_I32);
15892ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( kondT, mk_armg_calculate_condition(cond) );
15893ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         stmt( IRStmt_Exit( unop(Iop_32to1, mkexpr(kondT)),
15894ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            Ijk_Boring,
15895ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            IRConst_U32(dst | 1/*CPSR.T*/) ));
15896ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         irsb->next = mkU32( (guest_R15_curr_instr_notENC + 2)
15897ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             | 1 /*CPSR.T*/ );
15898ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         irsb->jumpkind = Ijk_Boring;
15899ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         dres.whatNext  = Dis_StopHere;
15900ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("b%s 0x%x\n", nCC(cond), dst);
15901ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
15902ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
15903ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
15904ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
15905ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15906ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   default:
15907ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break; /* hmm, nothing matched */
15908ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15909ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
15910ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15911ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ================ 16-bit misc cases ================ */
15912ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15913ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ------ NOP ------ */
15914ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (INSN0(15,0) == 0xBF00) {
15915ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("nop");
15916ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
15917ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
15918ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15919ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ----------------------------------------------------------- */
15920ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* --                                                       -- */
15921ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* -- Thumb 32-bit integer instructions                     -- */
15922ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* --                                                       -- */
15923ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ----------------------------------------------------------- */
15924ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15925ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  define INSN1(_bMax,_bMin)  SLICE_UInt(((UInt)insn1), (_bMax), (_bMin))
15926ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15927ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* second 16 bits of the instruction, if any */
15928ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UShort insn1 = getUShortLittleEndianly( guest_instr+2 );
15929ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15930ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   anOp   = Iop_INVALID; /* paranoia */
15931ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   anOpNm = NULL;        /* paranoia */
15932ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15933ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Change result defaults to suit 32-bit insns. */
15934ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(dres.whatNext   == Dis_Continue);
15935ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(dres.len        == 2);
15936ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(dres.continueAt == 0);
15937ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   dres.len = 4;
15938ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15939d4deed466a5276f711b3f9bd52003ac70bc91285Evgeniy Stepanov   /* ------------------- (T1) SMMUL{R} ------------------ */
15940d4deed466a5276f711b3f9bd52003ac70bc91285Evgeniy Stepanov   if (INSN0(15,7) == BITS9(1,1,1,1,1,0,1,1,0)
15941d4deed466a5276f711b3f9bd52003ac70bc91285Evgeniy Stepanov       && INSN0(6,4) == BITS3(1,0,1)
15942d4deed466a5276f711b3f9bd52003ac70bc91285Evgeniy Stepanov       && INSN1(15,12) == BITS4(1,1,1,1)
15943d4deed466a5276f711b3f9bd52003ac70bc91285Evgeniy Stepanov       && INSN1(7,5) == BITS3(0,0,0)) {
15944d4deed466a5276f711b3f9bd52003ac70bc91285Evgeniy Stepanov      UInt bitR = INSN1(4,4);
15945d4deed466a5276f711b3f9bd52003ac70bc91285Evgeniy Stepanov      UInt rD = INSN1(11,8);
15946d4deed466a5276f711b3f9bd52003ac70bc91285Evgeniy Stepanov      UInt rM = INSN1(3,0);
15947d4deed466a5276f711b3f9bd52003ac70bc91285Evgeniy Stepanov      UInt rN = INSN0(3,0);
15948d4deed466a5276f711b3f9bd52003ac70bc91285Evgeniy Stepanov      if (!isBadRegT(rD) && !isBadRegT(rN) && !isBadRegT(rM)) {
15949d4deed466a5276f711b3f9bd52003ac70bc91285Evgeniy Stepanov        IRExpr* res = newTemp(Ity_I32);
15950d4deed466a5276f711b3f9bd52003ac70bc91285Evgeniy Stepanov        assign(res, unop(Iop_64HIto32,
15951d4deed466a5276f711b3f9bd52003ac70bc91285Evgeniy Stepanov                binop(Iop_Add64,
15952d4deed466a5276f711b3f9bd52003ac70bc91285Evgeniy Stepanov                      binop(Iop_MullS32, getIRegT(rN), getIRegT(rM)),
15953d4deed466a5276f711b3f9bd52003ac70bc91285Evgeniy Stepanov                    mkU64(bitR ? 0x80000000ULL : 0ULL))));
15954d4deed466a5276f711b3f9bd52003ac70bc91285Evgeniy Stepanov         putIRegT(rD, mkexpr(res), condT);
15955d4deed466a5276f711b3f9bd52003ac70bc91285Evgeniy Stepanov         DIP("smmul%s r%u, r%u, r%u\n",
15956d4deed466a5276f711b3f9bd52003ac70bc91285Evgeniy Stepanov             bitR ? "r" : "", rD, rN, rM);
15957d4deed466a5276f711b3f9bd52003ac70bc91285Evgeniy Stepanov         goto decode_success;
15958d4deed466a5276f711b3f9bd52003ac70bc91285Evgeniy Stepanov      }
15959d4deed466a5276f711b3f9bd52003ac70bc91285Evgeniy Stepanov   }
15960d4deed466a5276f711b3f9bd52003ac70bc91285Evgeniy Stepanov
15961d4deed466a5276f711b3f9bd52003ac70bc91285Evgeniy Stepanov
15962ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ---------------- BL/BLX simm26 ---------------- */
15963ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (BITS5(1,1,1,1,0) == INSN0(15,11) && BITS2(1,1) == INSN1(15,14)) {
15964ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt isBL = INSN1(12,12);
15965ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt bS   = INSN0(10,10);
15966ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt bJ1  = INSN1(13,13);
15967ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt bJ2  = INSN1(11,11);
15968ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt bI1  = 1 ^ (bJ1 ^ bS);
15969ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt bI2  = 1 ^ (bJ2 ^ bS);
15970ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Int simm25
15971ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         =   (bS          << (1 + 1 + 10 + 11 + 1))
15972ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           | (bI1         << (1 + 10 + 11 + 1))
15973ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           | (bI2         << (10 + 11 + 1))
15974ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           | (INSN0(9,0)  << (11 + 1))
15975ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           | (INSN1(10,0) << 1);
15976ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      simm25 = (simm25 << 7) >> 7;
15977ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15978ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(0 == (guest_R15_curr_instr_notENC & 1));
15979ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt dst = simm25 + guest_R15_curr_instr_notENC + 4;
15980ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15981ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* One further validity case to check: in the case of BLX
15982ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         (not-BL), that insn1[0] must be zero. */
15983ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Bool valid = True;
15984ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (isBL == 0 && INSN1(0,0) == 1) valid = False;
15985ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (valid) {
15986ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Only allowed outside or last-in IT block; SIGILL if not so. */
15987ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         gen_SIGILL_T_if_in_but_NLI_ITBlock(old_itstate, new_itstate);
15988ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // and skip this insn if not selected; being cleverer is too
15989ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // difficult
15990ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         mk_skip_over_T32_if_cond_is_false(condT);
15991ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         condT = IRTemp_INVALID;
15992ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // now uncond
15993ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15994ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* We're returning to Thumb code, hence "| 1" */
15995ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIRegT( 14, mkU32( (guest_R15_curr_instr_notENC + 4) | 1 ),
15996ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   IRTemp_INVALID);
15997ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (isBL) {
15998ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* BL: unconditional T -> T call */
15999ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* we're calling Thumb code, hence "| 1" */
16000ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            irsb->next = mkU32( dst | 1 );
16001ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("bl 0x%x (stay in Thumb mode)\n", dst);
16002ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
16003ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* BLX: unconditional T -> A call */
16004ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* we're calling ARM code, hence "& 3" to align to a
16005ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               valid ARM insn address */
16006ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            irsb->next = mkU32( dst & ~3 );
16007ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("blx 0x%x (switch to ARM mode)\n", dst & ~3);
16008ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
16009ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         irsb->jumpkind = Ijk_Call;
16010ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         dres.whatNext = Dis_StopHere;
16011ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
16012ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
16013ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
16014ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16015ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ---------------- {LD,ST}M{IA,DB} ---------------- */
16016ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (0x3a2 == INSN0(15,6) // {LD,ST}MIA
16017ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       || 0x3a4 == INSN0(15,6)) { // {LD,ST}MDB
16018ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt bW      = INSN0(5,5); /* writeback Rn ? */
16019ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt bL      = INSN0(4,4);
16020ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rN      = INSN0(3,0);
16021ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt bP      = INSN1(15,15); /* reglist entry for r15 */
16022ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt bM      = INSN1(14,14); /* reglist entry for r14 */
16023ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rLmost  = INSN1(12,0);  /* reglist entry for r0 .. 12 */
16024ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rL13    = INSN1(13,13); /* must be zero */
16025ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt regList = 0;
16026ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Bool valid   = True;
16027ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16028ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt bINC    = 1;
16029ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt bBEFORE = 0;
16030ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (INSN0(15,6) == 0x3a4) {
16031ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         bINC    = 0;
16032ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         bBEFORE = 1;
16033ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
16034ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16035ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* detect statically invalid cases, and construct the final
16036ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         reglist */
16037ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (rL13 == 1)
16038ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         valid = False;
16039ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16040ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (bL == 1) {
16041ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         regList = (bP << 15) | (bM << 14) | rLmost;
16042ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (rN == 15)                       valid = False;
16043ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (popcount32(regList) < 2)        valid = False;
16044ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (bP == 1 && bM == 1)             valid = False;
16045ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (bW == 1 && (regList & (1<<rN))) valid = False;
16046ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
16047ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         regList = (bM << 14) | rLmost;
16048ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (bP == 1)                        valid = False;
16049ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (rN == 15)                       valid = False;
16050ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (popcount32(regList) < 2)        valid = False;
16051ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (bW == 1 && (regList & (1<<rN))) valid = False;
16052ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (regList & (1<<rN)) {
16053ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            UInt i;
16054ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* if Rn is in the list, then it must be the
16055ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               lowest numbered entry */
16056ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            for (i = 0; i < rN; i++) {
16057ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               if (regList & (1<<i))
16058ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  valid = False;
16059ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
16060ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
16061ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
16062ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16063ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (valid) {
16064ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (bL == 1 && bP == 1) {
16065ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            // We'll be writing the PC.  Hence:
16066ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* Only allowed outside or last-in IT block; SIGILL if not so. */
16067ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            gen_SIGILL_T_if_in_but_NLI_ITBlock(old_itstate, new_itstate);
16068ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
16069ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16070ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Go uncond: */
16071ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         mk_skip_over_T32_if_cond_is_false(condT);
16072ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         condT = IRTemp_INVALID;
16073ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // now uncond
16074ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16075ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Generate the IR.  This might generate a write to R15, */
16076ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         mk_ldm_stm(False/*!arm*/, rN, bINC, bBEFORE, bW, bL, regList);
16077ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16078ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (bL == 1 && (regList & (1<<15))) {
16079ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            // If we wrote to R15, we have an interworking return to
16080ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            // deal with.
16081ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            irsb->next     = llGetIReg(15);
16082ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            irsb->jumpkind = Ijk_Ret;
16083ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            dres.whatNext  = Dis_StopHere;
16084ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
16085ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16086ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("%sm%c%c r%u%s, {0x%04x}\n",
16087ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              bL == 1 ? "ld" : "st", bINC ? 'i' : 'd', bBEFORE ? 'b' : 'a',
16088ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              rN, bW ? "!" : "", regList);
16089ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16090ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
16091ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
16092ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
16093ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16094ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* -------------- (T3) ADD{S}.W Rd, Rn, #constT -------------- */
16095ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (INSN0(15,11) == BITS5(1,1,1,1,0)
16096ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && INSN0(9,5) == BITS5(0,1,0,0,0)
16097ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && INSN1(15,15) == 0) {
16098ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt bS = INSN0(4,4);
16099ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rN = INSN0(3,0);
16100ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rD = INSN1(11,8);
16101ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Bool valid = !isBadRegT(rN) && !isBadRegT(rD);
16102ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* but allow "add.w reg, sp, #constT" */
16103b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      if (!valid && rN == 13 && rD != 15)
16104ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         valid = True;
16105ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (valid) {
16106ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp argL  = newTemp(Ity_I32);
16107ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp argR  = newTemp(Ity_I32);
16108ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp res   = newTemp(Ity_I32);
16109ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         UInt   imm32 = thumbExpandImm_from_I0_I1(NULL, insn0, insn1);
16110ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(argL, getIRegT(rN));
16111ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(argR, mkU32(imm32));
16112ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(res,  binop(Iop_Add32, mkexpr(argL), mkexpr(argR)));
16113ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIRegT(rD, mkexpr(res), condT);
16114ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (bS == 1)
16115ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            setFlags_D1_D2( ARMG_CC_OP_ADD, argL, argR, condT );
16116ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("add%s.w r%u, r%u, #%u\n",
16117ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             bS == 1 ? "s" : "", rD, rN, imm32);
16118ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
16119ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
16120ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
16121ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16122b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   /* ---------------- (T4) ADDW Rd, Rn, #uimm12 -------------- */
1612353309af808693e7481777590bf359702e1c05b17Kenny Root   if (INSN0(15,11) == BITS5(1,1,1,1,0)
1612453309af808693e7481777590bf359702e1c05b17Kenny Root       && INSN0(9,4) == BITS6(1,0,0,0,0,0)
1612553309af808693e7481777590bf359702e1c05b17Kenny Root       && INSN1(15,15) == 0) {
1612653309af808693e7481777590bf359702e1c05b17Kenny Root      UInt rN = INSN0(3,0);
1612753309af808693e7481777590bf359702e1c05b17Kenny Root      UInt rD = INSN1(11,8);
1612853309af808693e7481777590bf359702e1c05b17Kenny Root      Bool valid = !isBadRegT(rN) && !isBadRegT(rD);
16129b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      /* but allow "addw sp, sp, #uimm12" */
16130b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      if (!valid && rD == 13 && rN == 13)
1613153309af808693e7481777590bf359702e1c05b17Kenny Root         valid = True;
1613253309af808693e7481777590bf359702e1c05b17Kenny Root      if (valid) {
1613353309af808693e7481777590bf359702e1c05b17Kenny Root         IRTemp argL = newTemp(Ity_I32);
1613453309af808693e7481777590bf359702e1c05b17Kenny Root         IRTemp argR = newTemp(Ity_I32);
1613553309af808693e7481777590bf359702e1c05b17Kenny Root         IRTemp res  = newTemp(Ity_I32);
16136b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         UInt imm12  = (INSN0(10,10) << 11) | (INSN1(14,12) << 8) | INSN1(7,0);
1613753309af808693e7481777590bf359702e1c05b17Kenny Root         assign(argL, getIRegT(rN));
1613853309af808693e7481777590bf359702e1c05b17Kenny Root         assign(argR, mkU32(imm12));
1613953309af808693e7481777590bf359702e1c05b17Kenny Root         assign(res,  binop(Iop_Add32, mkexpr(argL), mkexpr(argR)));
1614053309af808693e7481777590bf359702e1c05b17Kenny Root         putIRegT(rD, mkexpr(res), condT);
1614153309af808693e7481777590bf359702e1c05b17Kenny Root         DIP("addw r%u, r%u, #%u\n", rD, rN, imm12);
1614253309af808693e7481777590bf359702e1c05b17Kenny Root         goto decode_success;
1614353309af808693e7481777590bf359702e1c05b17Kenny Root      }
1614453309af808693e7481777590bf359702e1c05b17Kenny Root   }
1614553309af808693e7481777590bf359702e1c05b17Kenny Root
16146ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ---------------- (T2) CMP.W Rn, #constT ---------------- */
16147ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ---------------- (T2) CMN.W Rn, #constT ---------------- */
16148ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (INSN0(15,11) == BITS5(1,1,1,1,0)
16149ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && (   INSN0(9,4) == BITS6(0,1,1,0,1,1)  // CMP
16150ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           || INSN0(9,4) == BITS6(0,1,0,0,0,1)) // CMN
16151ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && INSN1(15,15) == 0
16152ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && INSN1(11,8) == BITS4(1,1,1,1)) {
16153ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rN = INSN0(3,0);
16154ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (rN != 15) {
16155ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp argL  = newTemp(Ity_I32);
16156ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp argR  = newTemp(Ity_I32);
16157ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Bool   isCMN = INSN0(9,4) == BITS6(0,1,0,0,0,1);
16158ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         UInt   imm32 = thumbExpandImm_from_I0_I1(NULL, insn0, insn1);
16159ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(argL, getIRegT(rN));
16160ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(argR, mkU32(imm32));
16161ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         setFlags_D1_D2( isCMN ? ARMG_CC_OP_ADD : ARMG_CC_OP_SUB,
16162ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         argL, argR, condT );
16163ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("%s.w r%u, #%u\n", isCMN ? "cmn" : "cmp", rN, imm32);
16164ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
16165ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
16166ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
16167ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16168ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* -------------- (T1) TST.W Rn, #constT -------------- */
16169ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* -------------- (T1) TEQ.W Rn, #constT -------------- */
16170ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (INSN0(15,11) == BITS5(1,1,1,1,0)
16171ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && (   INSN0(9,4) == BITS6(0,0,0,0,0,1)  // TST
16172ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           || INSN0(9,4) == BITS6(0,0,1,0,0,1)) // TEQ
16173ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && INSN1(15,15) == 0
16174ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && INSN1(11,8) == BITS4(1,1,1,1)) {
16175ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rN = INSN0(3,0);
16176ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!isBadRegT(rN)) { // yes, really, it's inconsistent with CMP.W
16177ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Bool  isTST  = INSN0(9,4) == BITS6(0,0,0,0,0,1);
16178ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp argL  = newTemp(Ity_I32);
16179ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp argR  = newTemp(Ity_I32);
16180ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp res   = newTemp(Ity_I32);
16181ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp oldV  = newTemp(Ity_I32);
16182ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp oldC  = newTemp(Ity_I32);
16183ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Bool   updC  = False;
16184ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         UInt   imm32 = thumbExpandImm_from_I0_I1(&updC, insn0, insn1);
16185ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(argL, getIRegT(rN));
16186ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(argR, mkU32(imm32));
16187ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(res,  binop(isTST ? Iop_And32 : Iop_Xor32,
16188ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            mkexpr(argL), mkexpr(argR)));
16189ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( oldV, mk_armg_calculate_flag_v() );
16190ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( oldC, updC
16191ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       ? mkU32((imm32 >> 31) & 1)
16192ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       : mk_armg_calculate_flag_c() );
16193ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         setFlags_D1_D2_ND( ARMG_CC_OP_LOGIC, res, oldC, oldV, condT );
16194ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("%s.w r%u, #%u\n", isTST ? "tst" : "teq", rN, imm32);
16195ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
16196ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
16197ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
16198ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16199ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* -------------- (T3) SUB{S}.W Rd, Rn, #constT -------------- */
16200ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* -------------- (T3) RSB{S}.W Rd, Rn, #constT -------------- */
16201ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (INSN0(15,11) == BITS5(1,1,1,1,0)
16202ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && (INSN0(9,5) == BITS5(0,1,1,0,1) // SUB
16203ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           || INSN0(9,5) == BITS5(0,1,1,1,0)) // RSB
16204ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && INSN1(15,15) == 0) {
16205ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Bool isRSB = INSN0(9,5) == BITS5(0,1,1,1,0);
16206ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt bS    = INSN0(4,4);
16207ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rN    = INSN0(3,0);
16208ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rD    = INSN1(11,8);
16209ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Bool valid = !isBadRegT(rN) && !isBadRegT(rD);
16210b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      /* but allow "sub{s}.w reg, sp, #constT
16211b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         this is (T2) of "SUB (SP minus immediate)" */
16212b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      if (!valid && !isRSB && rN == 13 && rD != 15)
16213ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         valid = True;
16214ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (valid) {
16215ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp argL  = newTemp(Ity_I32);
16216ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp argR  = newTemp(Ity_I32);
16217ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp res   = newTemp(Ity_I32);
16218ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         UInt   imm32 = thumbExpandImm_from_I0_I1(NULL, insn0, insn1);
16219ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(argL, getIRegT(rN));
16220ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(argR, mkU32(imm32));
16221ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(res,  isRSB
16222ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      ? binop(Iop_Sub32, mkexpr(argR), mkexpr(argL))
16223ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      : binop(Iop_Sub32, mkexpr(argL), mkexpr(argR)));
16224ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIRegT(rD, mkexpr(res), condT);
16225ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (bS == 1) {
16226ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (isRSB)
16227ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               setFlags_D1_D2( ARMG_CC_OP_SUB, argR, argL, condT );
16228ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            else
16229ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               setFlags_D1_D2( ARMG_CC_OP_SUB, argL, argR, condT );
16230ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
16231ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("%s%s.w r%u, r%u, #%u\n",
16232ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             isRSB ? "rsb" : "sub", bS == 1 ? "s" : "", rD, rN, imm32);
16233ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
16234ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
16235ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
16236ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16237b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   /* -------------- (T4) SUBW Rd, Rn, #uimm12 ------------------- */
162386116123147b1a0a13a2ead4c0d7374e7af5ce741Kenny Root   if (INSN0(15,11) == BITS5(1,1,1,1,0)
162396116123147b1a0a13a2ead4c0d7374e7af5ce741Kenny Root       && INSN0(9,4) == BITS6(1,0,1,0,1,0)
162406116123147b1a0a13a2ead4c0d7374e7af5ce741Kenny Root       && INSN1(15,15) == 0) {
162416116123147b1a0a13a2ead4c0d7374e7af5ce741Kenny Root      UInt rN = INSN0(3,0);
162426116123147b1a0a13a2ead4c0d7374e7af5ce741Kenny Root      UInt rD = INSN1(11,8);
162436116123147b1a0a13a2ead4c0d7374e7af5ce741Kenny Root      Bool valid = !isBadRegT(rN) && !isBadRegT(rD);
16244b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      /* but allow "subw sp, sp, #uimm12" */
16245b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      if (!valid && rD == 13 && rN == 13)
162466116123147b1a0a13a2ead4c0d7374e7af5ce741Kenny Root         valid = True;
162476116123147b1a0a13a2ead4c0d7374e7af5ce741Kenny Root      if (valid) {
162486116123147b1a0a13a2ead4c0d7374e7af5ce741Kenny Root         IRTemp argL  = newTemp(Ity_I32);
162496116123147b1a0a13a2ead4c0d7374e7af5ce741Kenny Root         IRTemp argR  = newTemp(Ity_I32);
162506116123147b1a0a13a2ead4c0d7374e7af5ce741Kenny Root         IRTemp res   = newTemp(Ity_I32);
162516116123147b1a0a13a2ead4c0d7374e7af5ce741Kenny Root         UInt imm12   = (INSN0(10,10) << 11) | (INSN1(14,12) << 8) | INSN1(7,0);
162526116123147b1a0a13a2ead4c0d7374e7af5ce741Kenny Root         assign(argL, getIRegT(rN));
162536116123147b1a0a13a2ead4c0d7374e7af5ce741Kenny Root         assign(argR, mkU32(imm12));
162546116123147b1a0a13a2ead4c0d7374e7af5ce741Kenny Root         assign(res,  binop(Iop_Sub32, mkexpr(argL), mkexpr(argR)));
162556116123147b1a0a13a2ead4c0d7374e7af5ce741Kenny Root         putIRegT(rD, mkexpr(res), condT);
162566116123147b1a0a13a2ead4c0d7374e7af5ce741Kenny Root         DIP("subw r%u, r%u, #%u\n", rD, rN, imm12);
162576116123147b1a0a13a2ead4c0d7374e7af5ce741Kenny Root         goto decode_success;
162586116123147b1a0a13a2ead4c0d7374e7af5ce741Kenny Root      }
162596116123147b1a0a13a2ead4c0d7374e7af5ce741Kenny Root   }
162606116123147b1a0a13a2ead4c0d7374e7af5ce741Kenny Root
16261ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* -------------- (T1) ADC{S}.W Rd, Rn, #constT -------------- */
16262ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* -------------- (T1) SBC{S}.W Rd, Rn, #constT -------------- */
16263ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (INSN0(15,11) == BITS5(1,1,1,1,0)
16264ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && (   INSN0(9,5) == BITS5(0,1,0,1,0)  // ADC
16265ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           || INSN0(9,5) == BITS5(0,1,0,1,1)) // SBC
16266ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && INSN1(15,15) == 0) {
16267ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* ADC:  Rd = Rn + constT + oldC */
16268ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* SBC:  Rd = Rn - constT - (oldC ^ 1) */
16269ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt bS    = INSN0(4,4);
16270ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rN    = INSN0(3,0);
16271ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rD    = INSN1(11,8);
16272ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!isBadRegT(rN) && !isBadRegT(rD)) {
16273ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp argL  = newTemp(Ity_I32);
16274ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp argR  = newTemp(Ity_I32);
16275ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp res   = newTemp(Ity_I32);
16276ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp oldC  = newTemp(Ity_I32);
16277ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         UInt   imm32 = thumbExpandImm_from_I0_I1(NULL, insn0, insn1);
16278ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(argL, getIRegT(rN));
16279ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(argR, mkU32(imm32));
16280ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(oldC, mk_armg_calculate_flag_c() );
16281ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         HChar* nm  = "???";
16282ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         switch (INSN0(9,5)) {
16283ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case BITS5(0,1,0,1,0): // ADC
16284ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               nm = "adc";
16285ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign(res,
16286ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      binop(Iop_Add32,
16287ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            binop(Iop_Add32, mkexpr(argL), mkexpr(argR)),
16288ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            mkexpr(oldC) ));
16289ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               putIRegT(rD, mkexpr(res), condT);
16290ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               if (bS)
16291ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  setFlags_D1_D2_ND( ARMG_CC_OP_ADC,
16292ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                     argL, argR, oldC, condT );
16293ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
16294ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case BITS5(0,1,0,1,1): // SBC
16295ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               nm = "sbc";
16296ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign(res,
16297ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      binop(Iop_Sub32,
16298ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            binop(Iop_Sub32, mkexpr(argL), mkexpr(argR)),
16299ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            binop(Iop_Xor32, mkexpr(oldC), mkU32(1)) ));
16300ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               putIRegT(rD, mkexpr(res), condT);
16301ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               if (bS)
16302ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  setFlags_D1_D2_ND( ARMG_CC_OP_SBB,
16303ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                     argL, argR, oldC, condT );
16304ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
16305ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            default:
16306ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              vassert(0);
16307ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
16308ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("%s%s.w r%u, r%u, #%u\n",
16309ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             nm, bS == 1 ? "s" : "", rD, rN, imm32);
16310ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
16311ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
16312ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
16313ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16314ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* -------------- (T1) ORR{S}.W Rd, Rn, #constT -------------- */
16315ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* -------------- (T1) AND{S}.W Rd, Rn, #constT -------------- */
16316ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* -------------- (T1) BIC{S}.W Rd, Rn, #constT -------------- */
16317ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* -------------- (T1) EOR{S}.W Rd, Rn, #constT -------------- */
16318ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (INSN0(15,11) == BITS5(1,1,1,1,0)
16319ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && (   INSN0(9,5) == BITS5(0,0,0,1,0)  // ORR
16320ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           || INSN0(9,5) == BITS5(0,0,0,0,0)  // AND
16321ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           || INSN0(9,5) == BITS5(0,0,0,0,1)  // BIC
16322ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           || INSN0(9,5) == BITS5(0,0,1,0,0)  // EOR
16323ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           || INSN0(9,5) == BITS5(0,0,0,1,1)) // ORN
16324ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && INSN1(15,15) == 0) {
16325ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt bS = INSN0(4,4);
16326ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rN = INSN0(3,0);
16327ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rD = INSN1(11,8);
16328ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!isBadRegT(rN) && !isBadRegT(rD)) {
16329ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Bool   notArgR = False;
16330ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IROp   op      = Iop_INVALID;
16331ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         HChar* nm      = "???";
16332ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         switch (INSN0(9,5)) {
16333ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case BITS5(0,0,0,1,0): op = Iop_Or32;  nm = "orr"; break;
16334ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case BITS5(0,0,0,0,0): op = Iop_And32; nm = "and"; break;
16335ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case BITS5(0,0,0,0,1): op = Iop_And32; nm = "bic";
16336ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   notArgR = True; break;
16337ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case BITS5(0,0,1,0,0): op = Iop_Xor32; nm = "eor"; break;
16338ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case BITS5(0,0,0,1,1): op = Iop_Or32;  nm = "orn";
16339ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   notArgR = True; break;
16340ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            default: vassert(0);
16341ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
16342ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp argL  = newTemp(Ity_I32);
16343ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp argR  = newTemp(Ity_I32);
16344ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp res   = newTemp(Ity_I32);
16345ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Bool   updC  = False;
16346ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         UInt   imm32 = thumbExpandImm_from_I0_I1(&updC, insn0, insn1);
16347ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(argL, getIRegT(rN));
16348ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(argR, mkU32(notArgR ? ~imm32 : imm32));
16349ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(res,  binop(op, mkexpr(argL), mkexpr(argR)));
16350ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIRegT(rD, mkexpr(res), condT);
16351ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (bS) {
16352ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            IRTemp oldV = newTemp(Ity_I32);
16353ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            IRTemp oldC = newTemp(Ity_I32);
16354ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign( oldV, mk_armg_calculate_flag_v() );
16355ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign( oldC, updC
16356ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          ? mkU32((imm32 >> 31) & 1)
16357ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          : mk_armg_calculate_flag_c() );
16358ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            setFlags_D1_D2_ND( ARMG_CC_OP_LOGIC, res, oldC, oldV,
16359ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               condT );
16360ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
16361ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("%s%s.w r%u, r%u, #%u\n",
16362ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             nm, bS == 1 ? "s" : "", rD, rN, imm32);
16363ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
16364ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
16365ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
16366ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16367ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ---------- (T3) ADD{S}.W Rd, Rn, Rm, {shift} ---------- */
16368ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ---------- (T3) SUB{S}.W Rd, Rn, Rm, {shift} ---------- */
16369ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ---------- (T3) RSB{S}.W Rd, Rn, Rm, {shift} ---------- */
16370ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (INSN0(15,9) == BITS7(1,1,1,0,1,0,1)
16371ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && (   INSN0(8,5) == BITS4(1,0,0,0)  // add subopc
16372ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           || INSN0(8,5) == BITS4(1,1,0,1)  // sub subopc
16373ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           || INSN0(8,5) == BITS4(1,1,1,0)) // rsb subopc
16374ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && INSN1(15,15) == 0) {
16375ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rN   = INSN0(3,0);
16376ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rD   = INSN1(11,8);
16377ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rM   = INSN1(3,0);
16378ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt bS   = INSN0(4,4);
16379ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt imm5 = (INSN1(14,12) << 2) | INSN1(7,6);
16380ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt how  = INSN1(5,4);
16381ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16382ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Bool valid = !isBadRegT(rD) && !isBadRegT(rN) && !isBadRegT(rM);
16383b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      /* but allow "add.w reg, sp, reg   w/ no shift
16384b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         (T3) "ADD (SP plus register) */
16385ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!valid && INSN0(8,5) == BITS4(1,0,0,0) // add
16386b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov          && rD != 15 && rN == 13 && imm5 == 0 && how == 0) {
16387ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         valid = True;
16388ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
16389b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      /* also allow "sub.w reg, sp, reg   w/ no shift
16390b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         (T1) "SUB (SP minus register) */
16391b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      if (!valid && INSN0(8,5) == BITS4(1,1,0,1) // sub
16392b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov          && rD != 15 && rN == 13 && imm5 == 0 && how == 0) {
16393ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         valid = True;
16394ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
16395ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (valid) {
16396ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Bool   swap = False;
16397ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IROp   op   = Iop_INVALID;
16398ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         HChar* nm   = "???";
16399ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         switch (INSN0(8,5)) {
16400ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case BITS4(1,0,0,0): op = Iop_Add32; nm = "add"; break;
16401ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case BITS4(1,1,0,1): op = Iop_Sub32; nm = "sub"; break;
16402ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case BITS4(1,1,1,0): op = Iop_Sub32; nm = "rsb";
16403ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 swap = True; break;
16404ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            default: vassert(0);
16405ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
16406ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16407ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp argL = newTemp(Ity_I32);
16408ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(argL, getIRegT(rN));
16409ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16410ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp rMt = newTemp(Ity_I32);
16411ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(rMt, getIRegT(rM));
16412ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16413ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp argR = newTemp(Ity_I32);
16414ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         compute_result_and_C_after_shift_by_imm5(
16415ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            dis_buf, &argR, NULL, rMt, how, imm5, rM
16416ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         );
16417ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16418ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp res = newTemp(Ity_I32);
16419ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(res, swap
16420ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     ? binop(op, mkexpr(argR), mkexpr(argL))
16421ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     : binop(op, mkexpr(argL), mkexpr(argR)));
16422ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16423ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIRegT(rD, mkexpr(res), condT);
16424ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (bS) {
16425ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            switch (op) {
16426ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               case Iop_Add32:
16427ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  setFlags_D1_D2( ARMG_CC_OP_ADD, argL, argR, condT );
16428ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  break;
16429ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               case Iop_Sub32:
16430ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  if (swap)
16431ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     setFlags_D1_D2( ARMG_CC_OP_SUB, argR, argL, condT );
16432ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  else
16433ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     setFlags_D1_D2( ARMG_CC_OP_SUB, argL, argR, condT );
16434ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  break;
16435ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               default:
16436ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  vassert(0);
16437ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
16438ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
16439ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16440ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("%s%s.w r%u, r%u, %s\n",
16441ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             nm, bS ? "s" : "", rD, rN, dis_buf);
16442ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
16443ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
16444ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
16445ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16446ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ---------- (T3) ADC{S}.W Rd, Rn, Rm, {shift} ---------- */
16447ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ---------- (T2) SBC{S}.W Rd, Rn, Rm, {shift} ---------- */
16448ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (INSN0(15,9) == BITS7(1,1,1,0,1,0,1)
16449ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && (   INSN0(8,5) == BITS4(1,0,1,0)   // adc subopc
16450ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           || INSN0(8,5) == BITS4(1,0,1,1))  // sbc subopc
16451ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && INSN1(15,15) == 0) {
16452ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* ADC:  Rd = Rn + shifter_operand + oldC */
16453ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* SBC:  Rd = Rn - shifter_operand - (oldC ^ 1) */
16454ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rN = INSN0(3,0);
16455ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rD = INSN1(11,8);
16456ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rM = INSN1(3,0);
16457ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!isBadRegT(rD) && !isBadRegT(rN) && !isBadRegT(rM)) {
16458ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         UInt bS   = INSN0(4,4);
16459ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         UInt imm5 = (INSN1(14,12) << 2) | INSN1(7,6);
16460ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         UInt how  = INSN1(5,4);
16461ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16462ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp argL = newTemp(Ity_I32);
16463ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(argL, getIRegT(rN));
16464ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16465ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp rMt = newTemp(Ity_I32);
16466ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(rMt, getIRegT(rM));
16467ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16468ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp oldC = newTemp(Ity_I32);
16469ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(oldC, mk_armg_calculate_flag_c());
16470ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16471ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp argR = newTemp(Ity_I32);
16472ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         compute_result_and_C_after_shift_by_imm5(
16473ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            dis_buf, &argR, NULL, rMt, how, imm5, rM
16474ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         );
16475ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16476ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         HChar* nm  = "???";
16477ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp res = newTemp(Ity_I32);
16478ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         switch (INSN0(8,5)) {
16479ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case BITS4(1,0,1,0): // ADC
16480ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               nm = "adc";
16481ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign(res,
16482ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      binop(Iop_Add32,
16483ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            binop(Iop_Add32, mkexpr(argL), mkexpr(argR)),
16484ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            mkexpr(oldC) ));
16485ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               putIRegT(rD, mkexpr(res), condT);
16486ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               if (bS)
16487ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  setFlags_D1_D2_ND( ARMG_CC_OP_ADC,
16488ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                     argL, argR, oldC, condT );
16489ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
16490ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case BITS4(1,0,1,1): // SBC
16491ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               nm = "sbc";
16492ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign(res,
16493ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      binop(Iop_Sub32,
16494ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            binop(Iop_Sub32, mkexpr(argL), mkexpr(argR)),
16495ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            binop(Iop_Xor32, mkexpr(oldC), mkU32(1)) ));
16496ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               putIRegT(rD, mkexpr(res), condT);
16497ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               if (bS)
16498ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  setFlags_D1_D2_ND( ARMG_CC_OP_SBB,
16499ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                     argL, argR, oldC, condT );
16500ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
16501ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            default:
16502ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               vassert(0);
16503ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
16504ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16505ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("%s%s.w r%u, r%u, %s\n",
16506ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             nm, bS ? "s" : "", rD, rN, dis_buf);
16507ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
16508ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
16509ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
16510ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16511ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ---------- (T3) AND{S}.W Rd, Rn, Rm, {shift} ---------- */
16512ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ---------- (T3) ORR{S}.W Rd, Rn, Rm, {shift} ---------- */
16513ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ---------- (T3) EOR{S}.W Rd, Rn, Rm, {shift} ---------- */
16514ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ---------- (T3) BIC{S}.W Rd, Rn, Rm, {shift} ---------- */
16515ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ---------- (T1) ORN{S}.W Rd, Rn, Rm, {shift} ---------- */
16516ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (INSN0(15,9) == BITS7(1,1,1,0,1,0,1)
16517ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && (   INSN0(8,5) == BITS4(0,0,0,0)  // and subopc
16518ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           || INSN0(8,5) == BITS4(0,0,1,0)  // orr subopc
16519ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           || INSN0(8,5) == BITS4(0,1,0,0)  // eor subopc
16520ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           || INSN0(8,5) == BITS4(0,0,0,1)  // bic subopc
16521ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           || INSN0(8,5) == BITS4(0,0,1,1)) // orn subopc
16522ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && INSN1(15,15) == 0) {
16523ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rN = INSN0(3,0);
16524ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rD = INSN1(11,8);
16525ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rM = INSN1(3,0);
16526ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!isBadRegT(rD) && !isBadRegT(rN) && !isBadRegT(rM)) {
16527ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Bool notArgR = False;
16528ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IROp op      = Iop_INVALID;
16529ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         HChar* nm  = "???";
16530ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         switch (INSN0(8,5)) {
16531ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case BITS4(0,0,0,0): op = Iop_And32; nm = "and"; break;
16532ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case BITS4(0,0,1,0): op = Iop_Or32;  nm = "orr"; break;
16533ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case BITS4(0,1,0,0): op = Iop_Xor32; nm = "eor"; break;
16534ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case BITS4(0,0,0,1): op = Iop_And32; nm = "bic";
16535ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 notArgR = True; break;
16536ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case BITS4(0,0,1,1): op = Iop_Or32; nm = "orn";
16537ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 notArgR = True; break;
16538ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            default: vassert(0);
16539ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
16540ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         UInt bS   = INSN0(4,4);
16541ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         UInt imm5 = (INSN1(14,12) << 2) | INSN1(7,6);
16542ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         UInt how  = INSN1(5,4);
16543ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16544ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp rNt = newTemp(Ity_I32);
16545ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(rNt, getIRegT(rN));
16546ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16547ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp rMt = newTemp(Ity_I32);
16548ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(rMt, getIRegT(rM));
16549ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16550ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp argR = newTemp(Ity_I32);
16551ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp oldC = bS ? newTemp(Ity_I32) : IRTemp_INVALID;
16552ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16553ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         compute_result_and_C_after_shift_by_imm5(
16554ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            dis_buf, &argR, bS ? &oldC : NULL, rMt, how, imm5, rM
16555ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         );
16556ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16557ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp res = newTemp(Ity_I32);
16558ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (notArgR) {
16559ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            vassert(op == Iop_And32 || op == Iop_Or32);
16560ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(res, binop(op, mkexpr(rNt),
16561ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  unop(Iop_Not32, mkexpr(argR))));
16562ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
16563ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(res, binop(op, mkexpr(rNt), mkexpr(argR)));
16564ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
16565ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16566ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIRegT(rD, mkexpr(res), condT);
16567ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (bS) {
16568ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            IRTemp oldV = newTemp(Ity_I32);
16569ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign( oldV, mk_armg_calculate_flag_v() );
16570ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            setFlags_D1_D2_ND( ARMG_CC_OP_LOGIC, res, oldC, oldV,
16571ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               condT );
16572ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
16573ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16574ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("%s%s.w r%u, r%u, %s\n",
16575ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             nm, bS ? "s" : "", rD, rN, dis_buf);
16576ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
16577ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
16578ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
16579ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16580ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* -------------- (T?) LSL{S}.W Rd, Rn, Rm -------------- */
16581ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* -------------- (T?) LSR{S}.W Rd, Rn, Rm -------------- */
16582ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* -------------- (T?) ASR{S}.W Rd, Rn, Rm -------------- */
16583ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* -------------- (T?) ROR{S}.W Rd, Rn, Rm -------------- */
16584ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (INSN0(15,7) == BITS9(1,1,1,1,1,0,1,0,0)
16585ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && INSN1(15,12) == BITS4(1,1,1,1)
16586ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && INSN1(7,4) == BITS4(0,0,0,0)) {
16587ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt how = INSN0(6,5); // standard encoding
16588ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rN  = INSN0(3,0);
16589ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rD  = INSN1(11,8);
16590ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rM  = INSN1(3,0);
16591ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt bS  = INSN0(4,4);
16592ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Bool valid = !isBadRegT(rN) && !isBadRegT(rM) && !isBadRegT(rD);
16593ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (valid) {
16594ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp rNt    = newTemp(Ity_I32);
16595ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp rMt    = newTemp(Ity_I32);
16596ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp res    = newTemp(Ity_I32);
16597ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp oldC   = bS ? newTemp(Ity_I32) : IRTemp_INVALID;
16598ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp oldV   = bS ? newTemp(Ity_I32) : IRTemp_INVALID;
16599ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         HChar* nms[4] = { "lsl", "lsr", "asr", "ror" };
16600ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         HChar* nm     = nms[how];
16601ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(rNt, getIRegT(rN));
16602ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(rMt, getIRegT(rM));
16603ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         compute_result_and_C_after_shift_by_reg(
16604ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            dis_buf, &res, bS ? &oldC : NULL,
16605ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            rNt, how, rMt, rN, rM
16606ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         );
16607ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (bS)
16608ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(oldV, mk_armg_calculate_flag_v());
16609ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIRegT(rD, mkexpr(res), condT);
16610ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (bS) {
16611ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            setFlags_D1_D2_ND( ARMG_CC_OP_LOGIC, res, oldC, oldV,
16612ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               condT );
16613ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
16614ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("%s%s.w r%u, r%u, r%u\n",
16615ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             nm, bS ? "s" : "", rD, rN, rM);
16616ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
16617ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
16618ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
16619ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16620ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ------------ (T?) MOV{S}.W Rd, Rn, {shift} ------------ */
16621ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ------------ (T?) MVN{S}.W Rd, Rn, {shift} ------------ */
16622ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if ((INSN0(15,0) & 0xFFCF) == 0xEA4F
16623ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && INSN1(15,15) == 0) {
16624ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rD = INSN1(11,8);
16625ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rN = INSN1(3,0);
16626ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!isBadRegT(rD) && !isBadRegT(rN)) {
16627ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         UInt bS    = INSN0(4,4);
16628ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         UInt isMVN = INSN0(5,5);
16629ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         UInt imm5  = (INSN1(14,12) << 2) | INSN1(7,6);
16630ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         UInt how   = INSN1(5,4);
16631ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16632ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp rNt = newTemp(Ity_I32);
16633ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(rNt, getIRegT(rN));
16634ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16635ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp oldRn = newTemp(Ity_I32);
16636ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp oldC  = bS ? newTemp(Ity_I32) : IRTemp_INVALID;
16637ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         compute_result_and_C_after_shift_by_imm5(
16638ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            dis_buf, &oldRn, bS ? &oldC : NULL, rNt, how, imm5, rN
16639ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         );
16640ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16641ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp res = newTemp(Ity_I32);
16642ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(res, isMVN ? unop(Iop_Not32, mkexpr(oldRn))
16643ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           : mkexpr(oldRn));
16644ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16645ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIRegT(rD, mkexpr(res), condT);
16646ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (bS) {
16647ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            IRTemp oldV = newTemp(Ity_I32);
16648ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign( oldV, mk_armg_calculate_flag_v() );
16649ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            setFlags_D1_D2_ND( ARMG_CC_OP_LOGIC, res, oldC, oldV, condT);
16650ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
16651ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("%s%s.w r%u, %s\n",
16652ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             isMVN ? "mvn" : "mov", bS ? "s" : "", rD, dis_buf);
16653ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
16654ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
16655ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
16656ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16657ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* -------------- (T?) TST.W Rn, Rm, {shift} -------------- */
16658ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* -------------- (T?) TEQ.W Rn, Rm, {shift} -------------- */
16659ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (INSN0(15,9) == BITS7(1,1,1,0,1,0,1)
16660ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && (   INSN0(8,4) == BITS5(0,0,0,0,1)  // TST
16661ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           || INSN0(8,4) == BITS5(0,1,0,0,1)) // TEQ
16662ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && INSN1(15,15) == 0
16663ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && INSN1(11,8) == BITS4(1,1,1,1)) {
16664ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rN = INSN0(3,0);
16665ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rM = INSN1(3,0);
16666ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!isBadRegT(rN) && !isBadRegT(rM)) {
16667ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Bool isTST = INSN0(8,4) == BITS5(0,0,0,0,1);
16668ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16669ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         UInt how  = INSN1(5,4);
16670ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         UInt imm5 = (INSN1(14,12) << 2) | INSN1(7,6);
16671ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16672ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp argL = newTemp(Ity_I32);
16673ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(argL, getIRegT(rN));
16674ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16675ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp rMt = newTemp(Ity_I32);
16676ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(rMt, getIRegT(rM));
16677ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16678ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp argR = newTemp(Ity_I32);
16679ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp oldC = newTemp(Ity_I32);
16680ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         compute_result_and_C_after_shift_by_imm5(
16681ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            dis_buf, &argR, &oldC, rMt, how, imm5, rM
16682ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         );
16683ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16684ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp oldV = newTemp(Ity_I32);
16685ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( oldV, mk_armg_calculate_flag_v() );
16686ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16687ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp res = newTemp(Ity_I32);
16688ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(res, binop(isTST ? Iop_And32 : Iop_Xor32,
16689ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           mkexpr(argL), mkexpr(argR)));
16690ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16691ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         setFlags_D1_D2_ND( ARMG_CC_OP_LOGIC, res, oldC, oldV,
16692ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            condT );
16693ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("%s.w r%u, %s\n", isTST ? "tst" : "teq", rN, dis_buf);
16694ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
16695ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
16696ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
16697ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16698ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* -------------- (T3) CMP.W Rn, Rm, {shift} -------------- */
16699ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* -------------- (T2) CMN.W Rn, Rm, {shift} -------------- */
16700ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (INSN0(15,9) == BITS7(1,1,1,0,1,0,1)
16701ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && (   INSN0(8,4) == BITS5(1,1,0,1,1)  // CMP
16702ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           || INSN0(8,4) == BITS5(1,0,0,0,1)) // CMN
16703ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && INSN1(15,15) == 0
16704ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && INSN1(11,8) == BITS4(1,1,1,1)) {
16705ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rN = INSN0(3,0);
16706ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rM = INSN1(3,0);
16707ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!isBadRegT(rN) && !isBadRegT(rM)) {
16708ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Bool isCMN = INSN0(8,4) == BITS5(1,0,0,0,1);
16709ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         UInt how   = INSN1(5,4);
16710ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         UInt imm5  = (INSN1(14,12) << 2) | INSN1(7,6);
16711ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16712ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp argL = newTemp(Ity_I32);
16713ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(argL, getIRegT(rN));
16714ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16715ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp rMt = newTemp(Ity_I32);
16716ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(rMt, getIRegT(rM));
16717ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16718ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp argR = newTemp(Ity_I32);
16719ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         compute_result_and_C_after_shift_by_imm5(
16720ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            dis_buf, &argR, NULL, rMt, how, imm5, rM
16721ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         );
16722ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16723ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         setFlags_D1_D2( isCMN ? ARMG_CC_OP_ADD : ARMG_CC_OP_SUB,
16724ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         argL, argR, condT );
16725ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16726ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("%s.w r%u, %s\n", isCMN ? "cmn" : "cmp", rN, dis_buf);
16727ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
16728ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
16729ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
16730ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16731ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* -------------- (T2) MOV{S}.W Rd, #constT -------------- */
16732ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* -------------- (T2) MVN{S}.W Rd, #constT -------------- */
16733ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (INSN0(15,11) == BITS5(1,1,1,1,0)
16734ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && (   INSN0(9,5) == BITS5(0,0,0,1,0)  // MOV
16735ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           || INSN0(9,5) == BITS5(0,0,0,1,1)) // MVN
16736ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && INSN0(3,0) == BITS4(1,1,1,1)
16737ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && INSN1(15,15) == 0) {
16738ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rD = INSN1(11,8);
16739ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!isBadRegT(rD)) {
16740ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Bool   updC  = False;
16741ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         UInt   bS    = INSN0(4,4);
16742ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Bool   isMVN = INSN0(5,5) == 1;
16743ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         UInt   imm32 = thumbExpandImm_from_I0_I1(&updC, insn0, insn1);
16744ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp res   = newTemp(Ity_I32);
16745ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(res, mkU32(isMVN ? ~imm32 : imm32));
16746ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIRegT(rD, mkexpr(res), condT);
16747ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (bS) {
16748ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            IRTemp oldV = newTemp(Ity_I32);
16749ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            IRTemp oldC = newTemp(Ity_I32);
16750ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign( oldV, mk_armg_calculate_flag_v() );
16751ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign( oldC, updC
16752ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          ? mkU32((imm32 >> 31) & 1)
16753ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          : mk_armg_calculate_flag_c() );
16754ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            setFlags_D1_D2_ND( ARMG_CC_OP_LOGIC, res, oldC, oldV,
16755ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               condT );
16756ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
16757ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("%s%s.w r%u, #%u\n",
16758ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             isMVN ? "mvn" : "mov", bS ? "s" : "", rD, imm32);
16759ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
16760ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
16761ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
16762ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16763ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* -------------- (T3) MOVW Rd, #imm16 -------------- */
16764ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (INSN0(15,11) == BITS5(1,1,1,1,0)
16765ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && INSN0(9,4) == BITS6(1,0,0,1,0,0)
16766ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && INSN1(15,15) == 0) {
16767ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rD = INSN1(11,8);
16768ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!isBadRegT(rD)) {
16769ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         UInt imm16 = (INSN0(3,0) << 12) | (INSN0(10,10) << 11)
16770ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      | (INSN1(14,12) << 8) | INSN1(7,0);
16771ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIRegT(rD, mkU32(imm16), condT);
16772ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("movw r%u, #%u\n", rD, imm16);
16773ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
16774ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
16775ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
16776ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16777ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ---------------- MOVT Rd, #imm16 ---------------- */
16778ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (INSN0(15,11) == BITS5(1,1,1,1,0)
16779ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && INSN0(9,4) == BITS6(1,0,1,1,0,0)
16780ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && INSN1(15,15) == 0) {
16781ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rD = INSN1(11,8);
16782ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!isBadRegT(rD)) {
16783ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         UInt imm16 = (INSN0(3,0) << 12) | (INSN0(10,10) << 11)
16784ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      | (INSN1(14,12) << 8) | INSN1(7,0);
16785ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp res = newTemp(Ity_I32);
16786ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(res,
16787ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                binop(Iop_Or32,
16788ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      binop(Iop_And32, getIRegT(rD), mkU32(0xFFFF)),
16789ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      mkU32(imm16 << 16)));
16790ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIRegT(rD, mkexpr(res), condT);
16791ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("movt r%u, #%u\n", rD, imm16);
16792ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
16793ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
16794ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
16795ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16796ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ---------------- LD/ST reg+/-#imm8 ---------------- */
16797ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Loads and stores of the form:
16798ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         op  Rt, [Rn, #-imm8]      or
16799ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         op  Rt, [Rn], #+/-imm8    or
16800ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         op  Rt, [Rn, #+/-imm8]!
16801ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      where op is one of
16802ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         ldrb ldrh ldr  ldrsb ldrsh
16803ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         strb strh str
16804ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   */
16805ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (INSN0(15,9) == BITS7(1,1,1,1,1,0,0) && INSN1(11,11) == 1) {
16806ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Bool   valid  = True;
16807ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Bool   syned  = False;
16808ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Bool   isST   = False;
16809ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRType ty     = Ity_I8;
16810ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      HChar* nm     = "???";
16811ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16812ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      switch (INSN0(8,4)) {
16813ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case BITS5(0,0,0,0,0):   // strb
16814ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            nm = "strb"; isST = True; break;
16815ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case BITS5(0,0,0,0,1):   // ldrb
16816ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            nm = "ldrb"; break;
16817ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case BITS5(1,0,0,0,1):   // ldrsb
16818ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            nm = "ldrsb"; syned = True; break;
16819ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case BITS5(0,0,0,1,0):   // strh
16820ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            nm = "strh"; ty = Ity_I16; isST = True; break;
16821ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case BITS5(0,0,0,1,1):   // ldrh
16822ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            nm = "ldrh"; ty = Ity_I16; break;
16823ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case BITS5(1,0,0,1,1):   // ldrsh
16824ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            nm = "ldrsh"; ty = Ity_I16; syned = True; break;
16825ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case BITS5(0,0,1,0,0):   // str
16826ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            nm = "str"; ty = Ity_I32; isST = True; break;
16827ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case BITS5(0,0,1,0,1):
16828ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            nm = "ldr"; ty = Ity_I32; break;  // ldr
16829ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         default:
16830ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            valid = False; break;
16831ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
16832ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16833ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rN      = INSN0(3,0);
16834ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rT      = INSN1(15,12);
16835ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt bP      = INSN1(10,10);
16836ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt bU      = INSN1(9,9);
16837ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt bW      = INSN1(8,8);
16838ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt imm8    = INSN1(7,0);
16839ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Bool loadsPC = False;
16840ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16841ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (valid) {
16842ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (bP == 1 && bU == 1 && bW == 0)
16843ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            valid = False;
16844ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (bP == 0 && bW == 0)
16845ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            valid = False;
16846ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (rN == 15)
16847ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            valid = False;
16848ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (bW == 1 && rN == rT)
16849ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            valid = False;
16850ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (ty == Ity_I8 || ty == Ity_I16) {
16851ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (isBadRegT(rT))
16852ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               valid = False;
16853ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
16854ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* ty == Ity_I32 */
16855ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (isST && rT == 15)
16856ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               valid = False;
16857ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (!isST && rT == 15)
16858ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               loadsPC = True;
16859ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
16860ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
16861ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16862ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (valid) {
16863ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // if it's a branch, it can't happen in the middle of an IT block
16864ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (loadsPC)
16865ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            gen_SIGILL_T_if_in_but_NLI_ITBlock(old_itstate, new_itstate);
16866ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // go uncond
16867ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         mk_skip_over_T32_if_cond_is_false(condT);
16868ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         condT = IRTemp_INVALID;
16869ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // now uncond
16870ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16871ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp preAddr = newTemp(Ity_I32);
16872ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(preAddr, getIRegT(rN));
16873ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16874ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp postAddr = newTemp(Ity_I32);
16875ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(postAddr, binop(bU == 1 ? Iop_Add32 : Iop_Sub32,
16876ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                mkexpr(preAddr), mkU32(imm8)));
16877ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16878ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp transAddr = bP == 1 ? postAddr : preAddr;
16879ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16880ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (isST) {
16881ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16882ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             /* Store.  If necessary, update the base register before
16883ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                the store itself, so that the common idiom of "str rX,
16884ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                [sp, #-4]!" (store rX at sp-4, then do new sp = sp-4,
16885ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                a.k.a "push rX") doesn't cause Memcheck to complain
16886ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                that the access is below the stack pointer.  Also, not
16887ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                updating sp before the store confuses Valgrind's
16888ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                dynamic stack-extending logic.  So do it before the
16889ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                store.  Hence we need to snarf the store data before
16890ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                doing the basereg update. */
16891ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16892ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* get hold of the data to be stored */
16893ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            IRTemp oldRt = newTemp(Ity_I32);
16894ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(oldRt, getIRegT(rT));
16895ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16896ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* Update Rn if necessary. */
16897ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (bW == 1) {
16898ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               vassert(rN != rT); // assured by validity check above
16899ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               putIRegT(rN, mkexpr(postAddr), IRTemp_INVALID);
16900ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
16901ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16902ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* generate the transfer */
16903ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            switch (ty) {
16904ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               case Ity_I8:
16905ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  storeLE(mkexpr(transAddr),
16906ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 unop(Iop_32to8, mkexpr(oldRt)));
16907ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  break;
16908ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               case Ity_I16:
16909ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  storeLE(mkexpr(transAddr),
16910ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          unop(Iop_32to16, mkexpr(oldRt)));
16911ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  break;
16912ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              case Ity_I32:
16913ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  storeLE(mkexpr(transAddr), mkexpr(oldRt));
16914ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  break;
16915ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              default:
16916ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 vassert(0);
16917ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
16918ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16919ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
16920ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16921ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* Load. */
16922ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16923ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* generate the transfer */
16924ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            IRTemp newRt = newTemp(Ity_I32);
16925ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            IROp   widen = Iop_INVALID;
16926ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            switch (ty) {
16927ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               case Ity_I8:
16928ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  widen = syned ? Iop_8Sto32 : Iop_8Uto32; break;
16929ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               case Ity_I16:
16930ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  widen = syned ? Iop_16Sto32 : Iop_16Uto32; break;
16931ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               case Ity_I32:
16932ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  break;
16933ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               default:
16934ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  vassert(0);
16935ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
16936ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (widen == Iop_INVALID) {
16937ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign(newRt, loadLE(ty, mkexpr(transAddr)));
16938ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            } else {
16939ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign(newRt, unop(widen, loadLE(ty, mkexpr(transAddr))));
16940ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
16941ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (loadsPC) {
16942ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               vassert(rT == 15);
16943ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               llPutIReg(rT, mkexpr(newRt));
16944ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            } else {
16945ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               putIRegT(rT, mkexpr(newRt), IRTemp_INVALID);
16946ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
16947ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16948ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (loadsPC) {
16949ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* Presumably this is an interworking branch. */
16950ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               irsb->next = mkexpr(newRt);
16951ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               irsb->jumpkind = Ijk_Boring;  /* or _Ret ? */
16952ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               dres.whatNext  = Dis_StopHere;
16953ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
16954ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16955ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* Update Rn if necessary. */
16956ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (bW == 1) {
16957ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               vassert(rN != rT); // assured by validity check above
16958ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               putIRegT(rN, mkexpr(postAddr), IRTemp_INVALID);
16959ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
16960ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
16961ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16962ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (bP == 1 && bW == 0) {
16963ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("%s.w r%u, [r%u, #%c%u]\n",
16964ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                nm, rT, rN, bU ? '+' : '-', imm8);
16965ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
16966ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         else if (bP == 1 && bW == 1) {
16967ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("%s.w r%u, [r%u, #%c%u]!\n",
16968ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                nm, rT, rN, bU ? '+' : '-', imm8);
16969ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
16970ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         else {
16971ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            vassert(bP == 0 && bW == 1);
16972ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("%s.w r%u, [r%u], #%c%u\n",
16973ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                nm, rT, rN, bU ? '+' : '-', imm8);
16974ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
16975ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16976ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
16977ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
16978ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
16979ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16980ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ------------- LD/ST reg+(reg<<imm2) ------------- */
16981ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Loads and stores of the form:
16982ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         op  Rt, [Rn, Rm, LSL #imm8]
16983ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      where op is one of
16984ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         ldrb ldrh ldr  ldrsb ldrsh
16985ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         strb strh str
16986ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   */
16987ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (INSN0(15,9) == BITS7(1,1,1,1,1,0,0)
16988ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && INSN1(11,6) == BITS6(0,0,0,0,0,0)) {
16989ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Bool   valid  = True;
16990ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Bool   syned  = False;
16991ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Bool   isST   = False;
16992ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRType ty     = Ity_I8;
16993ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      HChar* nm     = "???";
16994ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16995ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      switch (INSN0(8,4)) {
16996ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case BITS5(0,0,0,0,0):   // strb
16997ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            nm = "strb"; isST = True; break;
16998ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case BITS5(0,0,0,0,1):   // ldrb
16999ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            nm = "ldrb"; break;
17000ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case BITS5(1,0,0,0,1):   // ldrsb
17001ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            nm = "ldrsb"; syned = True; break;
17002ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case BITS5(0,0,0,1,0):   // strh
17003ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            nm = "strh"; ty = Ity_I16; isST = True; break;
17004ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case BITS5(0,0,0,1,1):   // ldrh
17005ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            nm = "ldrh"; ty = Ity_I16; break;
17006ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case BITS5(1,0,0,1,1):   // ldrsh
17007ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            nm = "ldrsh"; ty = Ity_I16; syned = True; break;
17008ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case BITS5(0,0,1,0,0):   // str
17009ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            nm = "str"; ty = Ity_I32; isST = True; break;
17010ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case BITS5(0,0,1,0,1):
17011ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            nm = "ldr"; ty = Ity_I32; break;  // ldr
17012ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         default:
17013ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            valid = False; break;
17014ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
17015ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17016ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rN      = INSN0(3,0);
17017ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rM      = INSN1(3,0);
17018ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rT      = INSN1(15,12);
17019ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt imm2    = INSN1(5,4);
17020ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Bool loadsPC = False;
17021ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17022ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (ty == Ity_I8 || ty == Ity_I16) {
17023ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* all 8- and 16-bit load and store cases have the
17024ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            same exclusion set. */
17025ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (rN == 15 || isBadRegT(rT) || isBadRegT(rM))
17026ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            valid = False;
17027ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
17028ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vassert(ty == Ity_I32);
17029ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (rN == 15 || isBadRegT(rM))
17030ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            valid = False;
17031ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (isST && rT == 15)
17032ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            valid = False;
17033ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* If it is a load and rT is 15, that's only allowable if we
17034ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            not in an IT block, or are the last in it.  Need to insert
17035ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            a dynamic check for that. */
17036ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (!isST && rT == 15)
17037ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            loadsPC = True;
17038ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
17039ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17040ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (valid) {
17041ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // if it's a branch, it can't happen in the middle of an IT block
17042ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (loadsPC)
17043ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            gen_SIGILL_T_if_in_but_NLI_ITBlock(old_itstate, new_itstate);
17044ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // go uncond
17045ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         mk_skip_over_T32_if_cond_is_false(condT);
17046ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         condT = IRTemp_INVALID;
17047ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // now uncond
17048ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17049ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp transAddr = newTemp(Ity_I32);
17050ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(transAddr,
17051ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                binop( Iop_Add32,
17052ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       getIRegT(rN),
17053ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       binop(Iop_Shl32, getIRegT(rM), mkU8(imm2)) ));
17054ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17055ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (isST) {
17056ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            IRTemp oldRt = newTemp(Ity_I32);
17057ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(oldRt, getIRegT(rT));
17058ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            switch (ty) {
17059ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               case Ity_I8:
17060ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  storeLE(mkexpr(transAddr),
17061ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 unop(Iop_32to8, mkexpr(oldRt)));
17062ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  break;
17063ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               case Ity_I16:
17064ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  storeLE(mkexpr(transAddr),
17065ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          unop(Iop_32to16, mkexpr(oldRt)));
17066ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  break;
17067ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              case Ity_I32:
17068ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  storeLE(mkexpr(transAddr), mkexpr(oldRt));
17069ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  break;
17070ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              default:
17071ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 vassert(0);
17072ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
17073ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
17074ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            IRTemp newRt = newTemp(Ity_I32);
17075ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            IROp   widen = Iop_INVALID;
17076ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            switch (ty) {
17077ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               case Ity_I8:
17078ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  widen = syned ? Iop_8Sto32 : Iop_8Uto32; break;
17079ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               case Ity_I16:
17080ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  widen = syned ? Iop_16Sto32 : Iop_16Uto32; break;
17081ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               case Ity_I32:
17082ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  break;
17083ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               default:
17084ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  vassert(0);
17085ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
17086ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (widen == Iop_INVALID) {
17087ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign(newRt, loadLE(ty, mkexpr(transAddr)));
17088ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            } else {
17089ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign(newRt, unop(widen, loadLE(ty, mkexpr(transAddr))));
17090ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
17091ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17092ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* If we're loading the PC, putIRegT will assert.  So go
17093ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               direct via llPutIReg.  In all other cases use putIRegT
17094ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               as it is safer (although could simply use llPutIReg for
17095ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               _all_ cases here.) */
17096ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (loadsPC) {
17097ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               vassert(rT == 15);
17098ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               llPutIReg(rT, mkexpr(newRt));
17099ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            } else {
17100ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               putIRegT(rT, mkexpr(newRt), IRTemp_INVALID);
17101ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
17102ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17103ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (loadsPC) {
17104ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* Presumably this is an interworking branch. */
17105ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               irsb->next = mkexpr(newRt);
17106ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               irsb->jumpkind = Ijk_Boring;  /* or _Ret ? */
17107ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               dres.whatNext  = Dis_StopHere;
17108ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
17109ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
17110ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17111ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("%s.w r%u, [r%u, r%u, LSL #%u]\n",
17112ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             nm, rT, rN, rM, imm2);
17113ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17114ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
17115ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
17116ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
17117ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17118ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* --------------- LD/ST reg+imm12 --------------- */
17119ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Loads and stores of the form:
17120ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         op  Rt, [Rn, +#imm12]
17121ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      where op is one of
17122ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         ldrb ldrh ldr  ldrsb ldrsh
17123ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         strb strh str
17124ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   */
17125ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (INSN0(15,9) == BITS7(1,1,1,1,1,0,0)) {
17126ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Bool   valid  = True;
17127ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Bool   syned  = False;
17128ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Bool   isST   = False;
17129ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRType ty     = Ity_I8;
17130ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      HChar* nm     = "???";
17131ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17132ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      switch (INSN0(8,4)) {
17133ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case BITS5(0,1,0,0,0):   // strb
17134ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            nm = "strb"; isST = True; break;
17135ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case BITS5(0,1,0,0,1):   // ldrb
17136ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            nm = "ldrb"; break;
17137ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case BITS5(1,1,0,0,1):   // ldrsb
17138ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            nm = "ldrsb"; syned = True; break;
17139ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case BITS5(0,1,0,1,0):   // strh
17140ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            nm = "strh"; ty = Ity_I16; isST = True; break;
17141ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case BITS5(0,1,0,1,1):   // ldrh
17142ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            nm = "ldrh"; ty = Ity_I16; break;
17143ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case BITS5(1,1,0,1,1):   // ldrsh
17144ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            nm = "ldrsh"; ty = Ity_I16; syned = True; break;
17145ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case BITS5(0,1,1,0,0):   // str
17146ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            nm = "str"; ty = Ity_I32; isST = True; break;
17147ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case BITS5(0,1,1,0,1):
17148ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            nm = "ldr"; ty = Ity_I32; break;  // ldr
17149ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         default:
17150ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            valid = False; break;
17151ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
17152ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17153ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rN      = INSN0(3,0);
17154ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rT      = INSN1(15,12);
17155ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt imm12   = INSN1(11,0);
17156ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Bool loadsPC = False;
17157ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17158ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (ty == Ity_I8 || ty == Ity_I16) {
17159ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* all 8- and 16-bit load and store cases have the
17160ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            same exclusion set. */
17161ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (rN == 15 || isBadRegT(rT))
17162ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            valid = False;
17163ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
17164ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vassert(ty == Ity_I32);
17165ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (isST) {
17166ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (rN == 15 || rT == 15)
17167ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               valid = False;
17168ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
17169ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* For a 32-bit load, rT == 15 is only allowable if we not
17170ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               in an IT block, or are the last in it.  Need to insert
17171ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               a dynamic check for that.  Also, in this particular
17172ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               case, rN == 15 is allowable.  In this case however, the
17173ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               value obtained for rN is (apparently)
17174ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               "word-align(address of current insn + 4)". */
17175ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (rT == 15)
17176ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               loadsPC = True;
17177ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
17178ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
17179ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17180ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (valid) {
17181ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // if it's a branch, it can't happen in the middle of an IT block
17182ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (loadsPC)
17183ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            gen_SIGILL_T_if_in_but_NLI_ITBlock(old_itstate, new_itstate);
17184ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // go uncond
17185ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         mk_skip_over_T32_if_cond_is_false(condT);
17186ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         condT = IRTemp_INVALID;
17187ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // now uncond
17188ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17189ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp rNt = newTemp(Ity_I32);
17190ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (rN == 15) {
17191ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            vassert(ty == Ity_I32 && !isST);
17192ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(rNt, binop(Iop_And32, getIRegT(rN), mkU32(~3)));
17193ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
17194ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(rNt, getIRegT(rN));
17195ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
17196ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17197ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp transAddr = newTemp(Ity_I32);
17198ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(transAddr,
17199ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                binop( Iop_Add32, mkexpr(rNt), mkU32(imm12) ));
17200ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17201ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (isST) {
17202ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            IRTemp oldRt = newTemp(Ity_I32);
17203ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(oldRt, getIRegT(rT));
17204ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            switch (ty) {
17205ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               case Ity_I8:
17206ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  storeLE(mkexpr(transAddr),
17207ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 unop(Iop_32to8, mkexpr(oldRt)));
17208ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  break;
17209ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               case Ity_I16:
17210ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  storeLE(mkexpr(transAddr),
17211ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          unop(Iop_32to16, mkexpr(oldRt)));
17212ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  break;
17213ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              case Ity_I32:
17214ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  storeLE(mkexpr(transAddr), mkexpr(oldRt));
17215ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  break;
17216ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              default:
17217ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 vassert(0);
17218ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
17219ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
17220ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            IRTemp newRt = newTemp(Ity_I32);
17221ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            IROp   widen = Iop_INVALID;
17222ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            switch (ty) {
17223ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               case Ity_I8:
17224ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  widen = syned ? Iop_8Sto32 : Iop_8Uto32; break;
17225ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               case Ity_I16:
17226ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  widen = syned ? Iop_16Sto32 : Iop_16Uto32; break;
17227ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               case Ity_I32:
17228ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  break;
17229ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               default:
17230ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  vassert(0);
17231ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
17232ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (widen == Iop_INVALID) {
17233ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign(newRt, loadLE(ty, mkexpr(transAddr)));
17234ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            } else {
17235ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign(newRt, unop(widen, loadLE(ty, mkexpr(transAddr))));
17236ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
17237ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putIRegT(rT, mkexpr(newRt), IRTemp_INVALID);
17238ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17239ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (loadsPC) {
17240ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* Presumably this is an interworking branch. */
17241ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               irsb->next = mkexpr(newRt);
17242ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               irsb->jumpkind = Ijk_Boring;  /* or _Ret ? */
17243ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               dres.whatNext  = Dis_StopHere;
17244ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
17245ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
17246ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17247ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("%s.w r%u, [r%u, +#%u]\n", nm, rT, rN, imm12);
17248ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17249ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
17250ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
17251ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
17252ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17253ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* -------------- LDRD/STRD reg+/-#imm8 -------------- */
17254ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Doubleword loads and stores of the form:
17255ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         ldrd/strd  Rt, Rt2, [Rn, #-imm8]      or
17256ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         ldrd/strd  Rt, Rt2, [Rn], #+/-imm8    or
17257ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         ldrd/strd  Rt, Rt2, [Rn, #+/-imm8]!
17258ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   */
17259ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (INSN0(15,9) == BITS7(1,1,1,0,1,0,0) && INSN0(6,6) == 1) {
17260ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt bP   = INSN0(8,8);
17261ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt bU   = INSN0(7,7);
17262ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt bW   = INSN0(5,5);
17263ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt bL   = INSN0(4,4);  // 1: load  0: store
17264ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rN   = INSN0(3,0);
17265ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rT   = INSN1(15,12);
17266ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rT2  = INSN1(11,8);
17267ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt imm8 = INSN1(7,0);
17268ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17269ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Bool valid = True;
17270ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (bP == 0 && bW == 0)                 valid = False;
17271ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (bW == 1 && (rN == rT || rN == rT2)) valid = False;
17272ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (isBadRegT(rT) || isBadRegT(rT2))    valid = False;
17273ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (rN == 15)                           valid = False;
17274ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (bL == 1 && rT == rT2)               valid = False;
17275ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17276ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (valid) {
17277ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // go uncond
17278ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         mk_skip_over_T32_if_cond_is_false(condT);
17279ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         condT = IRTemp_INVALID;
17280ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // now uncond
17281ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17282ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp preAddr = newTemp(Ity_I32);
17283ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(preAddr, getIRegT(rN));
17284ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17285ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp postAddr = newTemp(Ity_I32);
17286ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(postAddr, binop(bU == 1 ? Iop_Add32 : Iop_Sub32,
17287ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                mkexpr(preAddr), mkU32(imm8 << 2)));
17288ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17289ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp transAddr = bP == 1 ? postAddr : preAddr;
17290ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17291ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (bL == 0) {
17292ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            IRTemp oldRt  = newTemp(Ity_I32);
17293ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            IRTemp oldRt2 = newTemp(Ity_I32);
17294ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(oldRt,  getIRegT(rT));
17295ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(oldRt2, getIRegT(rT2));
17296ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            storeLE(mkexpr(transAddr),
17297ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    mkexpr(oldRt));
17298ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            storeLE(binop(Iop_Add32, mkexpr(transAddr), mkU32(4)),
17299ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    mkexpr(oldRt2));
17300ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
17301ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            IRTemp newRt  = newTemp(Ity_I32);
17302ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            IRTemp newRt2 = newTemp(Ity_I32);
17303ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(newRt,
17304ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   loadLE(Ity_I32,
17305ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          mkexpr(transAddr)));
17306ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(newRt2,
17307ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   loadLE(Ity_I32,
17308ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          binop(Iop_Add32, mkexpr(transAddr), mkU32(4))));
17309ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putIRegT(rT,  mkexpr(newRt), IRTemp_INVALID);
17310ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putIRegT(rT2, mkexpr(newRt2), IRTemp_INVALID);
17311ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
17312ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17313ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (bW == 1) {
17314ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putIRegT(rN, mkexpr(postAddr), IRTemp_INVALID);
17315ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
17316ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17317ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         HChar* nm = bL ? "ldrd" : "strd";
17318ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17319ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (bP == 1 && bW == 0) {
17320ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("%s.w r%u, r%u, [r%u, #%c%u]\n",
17321ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                nm, rT, rT2, rN, bU ? '+' : '-', imm8 << 2);
17322ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
17323ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         else if (bP == 1 && bW == 1) {
17324ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("%s.w r%u, r%u, [r%u, #%c%u]!\n",
17325ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                nm, rT, rT2, rN, bU ? '+' : '-', imm8 << 2);
17326ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
17327ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         else {
17328ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            vassert(bP == 0 && bW == 1);
17329ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("%s.w r%u, r%u, [r%u], #%c%u\n",
17330ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                nm, rT, rT2, rN, bU ? '+' : '-', imm8 << 2);
17331ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
17332ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17333ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
17334ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
17335ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
17336ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17337ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* -------------- (T3) Bcond.W label -------------- */
17338ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* This variant carries its own condition, so can't be part of an
17339ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IT block ... */
17340ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (INSN0(15,11) == BITS5(1,1,1,1,0)
17341ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && INSN1(15,14) == BITS2(1,0)
17342ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && INSN1(12,12) == 0) {
17343ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt cond = INSN0(9,6);
17344ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (cond != ARMCondAL && cond != ARMCondNV) {
17345ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Int simm21
17346ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            =   (INSN0(10,10) << (1 + 1 + 6 + 11 + 1))
17347ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              | (INSN1(11,11) << (1 + 6 + 11 + 1))
17348ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              | (INSN1(13,13) << (6 + 11 + 1))
17349ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              | (INSN0(5,0)   << (11 + 1))
17350ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              | (INSN1(10,0)  << 1);
17351ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         simm21 = (simm21 << 11) >> 11;
17352ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17353ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vassert(0 == (guest_R15_curr_instr_notENC & 1));
17354ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         UInt dst = simm21 + guest_R15_curr_instr_notENC + 4;
17355ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17356ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Not allowed in an IT block; SIGILL if so. */
17357ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         gen_SIGILL_T_if_in_ITBlock(old_itstate, new_itstate);
17358ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17359ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp kondT = newTemp(Ity_I32);
17360ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( kondT, mk_armg_calculate_condition(cond) );
17361ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         stmt( IRStmt_Exit( unop(Iop_32to1, mkexpr(kondT)),
17362ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            Ijk_Boring,
17363ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            IRConst_U32(dst | 1/*CPSR.T*/) ));
17364ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         irsb->next = mkU32( (guest_R15_curr_instr_notENC + 4)
17365ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             | 1 /*CPSR.T*/ );
17366ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         irsb->jumpkind = Ijk_Boring;
17367ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         dres.whatNext  = Dis_StopHere;
17368ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("b%s.w 0x%x\n", nCC(cond), dst);
17369ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
17370ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
17371ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
17372ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17373ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ---------------- (T4) B.W label ---------------- */
17374ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ... whereas this variant doesn't carry its own condition, so it
17375ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      has to be either unconditional or the conditional by virtue of
17376ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      being the last in an IT block.  The upside is that there's 4
17377ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      more bits available for the jump offset, so it has a 16-times
17378ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      greater branch range than the T3 variant. */
17379ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (INSN0(15,11) == BITS5(1,1,1,1,0)
17380ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && INSN1(15,14) == BITS2(1,0)
17381ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && INSN1(12,12) == 1) {
17382ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (1) {
17383ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         UInt bS  = INSN0(10,10);
17384ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         UInt bJ1 = INSN1(13,13);
17385ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         UInt bJ2 = INSN1(11,11);
17386ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         UInt bI1 = 1 ^ (bJ1 ^ bS);
17387ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         UInt bI2 = 1 ^ (bJ2 ^ bS);
17388ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Int simm25
17389ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            =   (bS          << (1 + 1 + 10 + 11 + 1))
17390ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              | (bI1         << (1 + 10 + 11 + 1))
17391ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              | (bI2         << (10 + 11 + 1))
17392ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              | (INSN0(9,0)  << (11 + 1))
17393ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              | (INSN1(10,0) << 1);
17394ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         simm25 = (simm25 << 7) >> 7;
17395ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17396ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vassert(0 == (guest_R15_curr_instr_notENC & 1));
17397ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         UInt dst = simm25 + guest_R15_curr_instr_notENC + 4;
17398ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17399ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* If in an IT block, must be the last insn. */
17400ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         gen_SIGILL_T_if_in_but_NLI_ITBlock(old_itstate, new_itstate);
17401ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17402ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // go uncond
17403ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         mk_skip_over_T32_if_cond_is_false(condT);
17404ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         condT = IRTemp_INVALID;
17405ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // now uncond
17406ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17407ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // branch to dst
17408ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         irsb->next = mkU32( dst | 1 /*CPSR.T*/ );
17409ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         irsb->jumpkind = Ijk_Boring;
17410ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         dres.whatNext  = Dis_StopHere;
17411ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("b.w 0x%x\n", dst);
17412ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
17413ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
17414ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
17415ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17416ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ------------------ TBB, TBH ------------------ */
17417ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (INSN0(15,4) == 0xE8D && INSN1(15,5) == 0x780) {
17418ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rN = INSN0(3,0);
17419ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rM = INSN1(3,0);
17420ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt bH = INSN1(4,4);
17421ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (bH/*ATC*/ || (rN != 13 && !isBadRegT(rM))) {
17422ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Must be last or not-in IT block */
17423ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         gen_SIGILL_T_if_in_but_NLI_ITBlock(old_itstate, new_itstate);
17424ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Go uncond */
17425ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         mk_skip_over_T32_if_cond_is_false(condT);
17426ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         condT = IRTemp_INVALID;
17427ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17428ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRExpr* ea
17429ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             = binop(Iop_Add32,
17430ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     getIRegT(rN),
17431ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     bH ? binop(Iop_Shl32, getIRegT(rM), mkU8(1))
17432ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        : getIRegT(rM));
17433ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17434ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp delta = newTemp(Ity_I32);
17435ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (bH) {
17436ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(delta, unop(Iop_16Uto32, loadLE(Ity_I16, ea)));
17437ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
17438ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(delta, unop(Iop_8Uto32, loadLE(Ity_I8, ea)));
17439ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
17440ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17441ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         irsb->next
17442ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            = binop(Iop_Or32,
17443ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    binop(Iop_Add32,
17444ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          getIRegT(15),
17445ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          binop(Iop_Shl32, mkexpr(delta), mkU8(1))
17446ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    ),
17447ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    mkU32(1)
17448ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              );
17449ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         irsb->jumpkind = Ijk_Boring;
17450ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         dres.whatNext = Dis_StopHere;
17451ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("tb%c [r%u, r%u%s]\n",
17452ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             bH ? 'h' : 'b', rN, rM, bH ? ", LSL #1" : "");
17453ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
17454ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
17455ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
17456ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17457ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ------------------ UBFX ------------------ */
17458ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ------------------ SBFX ------------------ */
17459ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* There's also ARM versions of same, but it doesn't seem worth the
17460ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      hassle to common up the handling (it's only a couple of C
17461ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      statements). */
17462ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if ((INSN0(15,4) == 0xF3C // UBFX
17463ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        || INSN0(15,4) == 0xF34) // SBFX
17464ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && INSN1(15,15) == 0 && INSN1(5,5) == 0) {
17465ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rN  = INSN0(3,0);
17466ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rD  = INSN1(11,8);
17467ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt lsb = (INSN1(14,12) << 2) | INSN1(7,6);
17468ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt wm1 = INSN1(4,0);
17469ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt msb =  lsb + wm1;
17470ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!isBadRegT(rD) && !isBadRegT(rN) && msb <= 31) {
17471ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Bool   isU  = INSN0(15,4) == 0xF3C;
17472ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp src  = newTemp(Ity_I32);
17473ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp tmp  = newTemp(Ity_I32);
17474ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp res  = newTemp(Ity_I32);
17475ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         UInt   mask = ((1 << wm1) - 1) + (1 << wm1);
17476ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vassert(msb >= 0 && msb <= 31);
17477ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vassert(mask != 0); // guaranteed by msb being in 0 .. 31 inclusive
17478ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17479ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(src, getIRegT(rN));
17480ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(tmp, binop(Iop_And32,
17481ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           binop(Iop_Shr32, mkexpr(src), mkU8(lsb)),
17482ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           mkU32(mask)));
17483ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(res, binop(isU ? Iop_Shr32 : Iop_Sar32,
17484ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           binop(Iop_Shl32, mkexpr(tmp), mkU8(31-wm1)),
17485ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           mkU8(31-wm1)));
17486ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17487ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIRegT(rD, mkexpr(res), condT);
17488ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17489ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("%s r%u, r%u, #%u, #%u\n",
17490ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             isU ? "ubfx" : "sbfx", rD, rN, lsb, wm1 + 1);
17491ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
17492ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
17493ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
17494ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17495ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ------------------ UXTB ------------------ */
17496ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ------------------ UXTH ------------------ */
17497ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ------------------ SXTB ------------------ */
17498ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ------------------ SXTH ------------------ */
17499ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ----------------- UXTB16 ----------------- */
17500ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ----------------- SXTB16 ----------------- */
17501ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* FIXME: this is an exact duplicate of the ARM version.  They
17502ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      should be commoned up. */
17503ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if ((INSN0(15,0) == 0xFA5F     // UXTB
17504ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        || INSN0(15,0) == 0xFA1F  // UXTH
17505ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        || INSN0(15,0) == 0xFA4F  // SXTB
17506ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        || INSN0(15,0) == 0xFA0F  // SXTH
17507ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        || INSN0(15,0) == 0xFA3F  // UXTB16
17508ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        || INSN0(15,0) == 0xFA2F) // SXTB16
17509ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && INSN1(15,12) == BITS4(1,1,1,1)
17510ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && INSN1(7,6) == BITS2(1,0)) {
17511ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rD = INSN1(11,8);
17512ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rM = INSN1(3,0);
17513ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rot = INSN1(5,4);
17514ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!isBadRegT(rD) && !isBadRegT(rM)) {
17515ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         HChar* nm = "???";
17516ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp srcT = newTemp(Ity_I32);
17517ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp rotT = newTemp(Ity_I32);
17518ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp dstT = newTemp(Ity_I32);
17519ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(srcT, getIRegT(rM));
17520ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(rotT, genROR32(srcT, 8 * rot));
17521ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         switch (INSN0(15,0)) {
17522ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xFA5F: // UXTB
17523ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               nm = "uxtb";
17524ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign(dstT, unop(Iop_8Uto32,
17525ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 unop(Iop_32to8, mkexpr(rotT))));
17526ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
17527ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xFA1F: // UXTH
17528ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               nm = "uxth";
17529ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign(dstT, unop(Iop_16Uto32,
17530ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 unop(Iop_32to16, mkexpr(rotT))));
17531ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
17532ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xFA4F: // SXTB
17533ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               nm = "sxtb";
17534ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign(dstT, unop(Iop_8Sto32,
17535ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 unop(Iop_32to8, mkexpr(rotT))));
17536ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
17537ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xFA0F: // SXTH
17538ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               nm = "sxth";
17539ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign(dstT, unop(Iop_16Sto32,
17540ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 unop(Iop_32to16, mkexpr(rotT))));
17541ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
17542ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xFA3F: // UXTB16
17543ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               nm = "uxtb16";
17544ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign(dstT, binop(Iop_And32, mkexpr(rotT),
17545ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                             mkU32(0x00FF00FF)));
17546ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
17547ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xFA2F: { // SXTB16
17548ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               nm = "sxtb16";
17549ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRTemp lo32 = newTemp(Ity_I32);
17550ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRTemp hi32 = newTemp(Ity_I32);
17551ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign(lo32, binop(Iop_And32, mkexpr(rotT), mkU32(0xFF)));
17552ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign(hi32, binop(Iop_Shr32, mkexpr(rotT), mkU8(16)));
17553ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign(
17554ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  dstT,
17555ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  binop(Iop_Or32,
17556ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        binop(Iop_And32,
17557ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              unop(Iop_8Sto32,
17558ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   unop(Iop_32to8, mkexpr(lo32))),
17559ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              mkU32(0xFFFF)),
17560ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        binop(Iop_Shl32,
17561ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              unop(Iop_8Sto32,
17562ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   unop(Iop_32to8, mkexpr(hi32))),
17563ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              mkU8(16))
17564ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               ));
17565ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
17566ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
17567ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            default:
17568ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               vassert(0);
17569ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
17570ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIRegT(rD, mkexpr(dstT), condT);
17571ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("%s r%u, r%u, ror #%u\n", nm, rD, rM, 8 * rot);
17572ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
17573ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
17574ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
17575ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17576ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* -------------- MUL.W Rd, Rn, Rm -------------- */
17577ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (INSN0(15,4) == 0xFB0
17578ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && (INSN1(15,0) & 0xF0F0) == 0xF000) {
17579ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rN = INSN0(3,0);
17580ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rD = INSN1(11,8);
17581ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rM = INSN1(3,0);
17582ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!isBadRegT(rD) && !isBadRegT(rN) && !isBadRegT(rM)) {
17583ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp res = newTemp(Ity_I32);
17584ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(res, binop(Iop_Mul32, getIRegT(rN), getIRegT(rM)));
17585ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIRegT(rD, mkexpr(res), condT);
17586ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("mul.w r%u, r%u, r%u\n", rD, rN, rM);
17587ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
17588ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
17589ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
17590ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17591ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ------------------ {U,S}MULL ------------------ */
17592ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if ((INSN0(15,4) == 0xFB8 || INSN0(15,4) == 0xFBA)
17593ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && INSN1(7,4) == BITS4(0,0,0,0)) {
17594ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt isU  = INSN0(5,5);
17595ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rN   = INSN0(3,0);
17596ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rDlo = INSN1(15,12);
17597ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rDhi = INSN1(11,8);
17598ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rM   = INSN1(3,0);
17599ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!isBadRegT(rDhi) && !isBadRegT(rDlo)
17600ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          && !isBadRegT(rN) && !isBadRegT(rM) && rDlo != rDhi) {
17601ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp res   = newTemp(Ity_I64);
17602ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(res, binop(isU ? Iop_MullU32 : Iop_MullS32,
17603ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           getIRegT(rN), getIRegT(rM)));
17604ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIRegT( rDhi, unop(Iop_64HIto32, mkexpr(res)), condT );
17605ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIRegT( rDlo, unop(Iop_64to32, mkexpr(res)), condT );
17606ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("%cmull r%u, r%u, r%u, r%u\n",
17607ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             isU ? 'u' : 's', rDlo, rDhi, rN, rM);
17608ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
17609ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
17610ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
17611ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17612ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ------------------ ML{A,S} ------------------ */
17613ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (INSN0(15,4) == 0xFB0
17614ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && (   INSN1(7,4) == BITS4(0,0,0,0)    // MLA
17615ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           || INSN1(7,4) == BITS4(0,0,0,1))) { // MLS
17616ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rN = INSN0(3,0);
17617ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rA = INSN1(15,12);
17618ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rD = INSN1(11,8);
17619ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rM = INSN1(3,0);
17620ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!isBadRegT(rD) && !isBadRegT(rN)
17621ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          && !isBadRegT(rM) && !isBadRegT(rA)) {
17622ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Bool   isMLA = INSN1(7,4) == BITS4(0,0,0,0);
17623ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp res   = newTemp(Ity_I32);
17624ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(res,
17625ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                binop(isMLA ? Iop_Add32 : Iop_Sub32,
17626ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      getIRegT(rA),
17627ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      binop(Iop_Mul32, getIRegT(rN), getIRegT(rM))));
17628ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIRegT(rD, mkexpr(res), condT);
17629ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("%s r%u, r%u, r%u, r%u\n",
17630ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             isMLA ? "mla" : "mls", rD, rN, rM, rA);
17631ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
17632ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
17633ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
17634ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17635ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ------------------ (T3) ADR ------------------ */
17636ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if ((INSN0(15,0) == 0xF20F || INSN0(15,0) == 0xF60F)
17637ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && INSN1(15,15) == 0) {
17638ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* rD = align4(PC) + imm32 */
17639ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rD = INSN1(11,8);
17640ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!isBadRegT(rD)) {
17641ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         UInt imm32 = (INSN0(10,10) << 11)
17642ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      | (INSN1(14,12) << 8) | INSN1(7,0);
17643ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIRegT(rD, binop(Iop_Add32,
17644ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            binop(Iop_And32, getIRegT(15), mkU32(~3U)),
17645ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            mkU32(imm32)),
17646ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      condT);
17647ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("add r%u, pc, #%u\n", rD, imm32);
17648ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
17649ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
17650ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
17651ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17652ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ----------------- (T1) UMLAL ----------------- */
17653ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ----------------- (T1) SMLAL ----------------- */
17654ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if ((INSN0(15,4) == 0xFBE // UMLAL
17655ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        || INSN0(15,4) == 0xFBC) // SMLAL
17656ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && INSN1(7,4) == BITS4(0,0,0,0)) {
17657ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rN   = INSN0(3,0);
17658ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rDlo = INSN1(15,12);
17659ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rDhi = INSN1(11,8);
17660ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rM   = INSN1(3,0);
17661ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!isBadRegT(rDlo) && !isBadRegT(rDhi) && !isBadRegT(rN)
17662ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          && !isBadRegT(rM) && rDhi != rDlo) {
17663ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Bool   isS   = INSN0(15,4) == 0xFBC;
17664ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp argL  = newTemp(Ity_I32);
17665ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp argR  = newTemp(Ity_I32);
17666ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp old   = newTemp(Ity_I64);
17667ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp res   = newTemp(Ity_I64);
17668ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp resHi = newTemp(Ity_I32);
17669ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp resLo = newTemp(Ity_I32);
17670ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IROp   mulOp = isS ? Iop_MullS32 : Iop_MullU32;
17671ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( argL, getIRegT(rM));
17672ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( argR, getIRegT(rN));
17673ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( old, binop(Iop_32HLto64, getIRegT(rDhi), getIRegT(rDlo)) );
17674ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( res, binop(Iop_Add64,
17675ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            mkexpr(old),
17676ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            binop(mulOp, mkexpr(argL), mkexpr(argR))) );
17677ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( resHi, unop(Iop_64HIto32, mkexpr(res)) );
17678ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( resLo, unop(Iop_64to32, mkexpr(res)) );
17679ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIRegT( rDhi, mkexpr(resHi), condT );
17680ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIRegT( rDlo, mkexpr(resLo), condT );
17681ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("%cmlal r%u, r%u, r%u, r%u\n",
17682ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             isS ? 's' : 'u', rDlo, rDhi, rN, rM);
17683ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
17684ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
17685ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
17686ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17687ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ------------------ (T2) ADR ------------------ */
17688ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if ((INSN0(15,0) == 0xF2AF || INSN0(15,0) == 0xF6AF)
17689ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && INSN1(15,15) == 0) {
17690ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* rD = align4(PC) - imm32 */
17691ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rD = INSN1(11,8);
17692ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!isBadRegT(rD)) {
17693ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         UInt imm32 = (INSN0(10,10) << 11)
17694ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      | (INSN1(14,12) << 8) | INSN1(7,0);
17695ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIRegT(rD, binop(Iop_Sub32,
17696ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            binop(Iop_And32, getIRegT(15), mkU32(~3U)),
17697ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            mkU32(imm32)),
17698ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      condT);
17699ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("sub r%u, pc, #%u\n", rD, imm32);
17700ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
17701ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
17702ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
17703ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17704ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ------------------- (T1) BFI ------------------- */
17705ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ------------------- (T1) BFC ------------------- */
17706ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (INSN0(15,4) == 0xF36 && INSN1(15,15) == 0 && INSN1(5,5) == 0) {
17707ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rD  = INSN1(11,8);
17708ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rN  = INSN0(3,0);
17709ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt msb = INSN1(4,0);
17710ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt lsb = (INSN1(14,12) << 2) | INSN1(7,6);
17711ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (isBadRegT(rD) || rN == 13 || msb < lsb) {
17712ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* undecodable; fall through */
17713ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
17714ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp src    = newTemp(Ity_I32);
17715ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp olddst = newTemp(Ity_I32);
17716ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp newdst = newTemp(Ity_I32);
17717ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         UInt   mask = 1 << (msb - lsb);
17718ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         mask = (mask - 1) + mask;
17719ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vassert(mask != 0); // guaranteed by "msb < lsb" check above
17720ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         mask <<= lsb;
17721ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17722ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(src, rN == 15 ? mkU32(0) : getIRegT(rN));
17723ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(olddst, getIRegT(rD));
17724ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(newdst,
17725ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                binop(Iop_Or32,
17726ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   binop(Iop_And32,
17727ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         binop(Iop_Shl32, mkexpr(src), mkU8(lsb)),
17728ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         mkU32(mask)),
17729ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   binop(Iop_And32,
17730ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         mkexpr(olddst),
17731ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         mkU32(~mask)))
17732ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               );
17733ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17734ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIRegT(rD, mkexpr(newdst), condT);
17735ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17736ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (rN == 15) {
17737ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("bfc r%u, #%u, #%u\n",
17738ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                rD, lsb, msb-lsb+1);
17739ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
17740ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("bfi r%u, r%u, #%u, #%u\n",
17741ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                rD, rN, lsb, msb-lsb+1);
17742ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
17743ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
17744ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
17745ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
17746ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17747ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ------------------- (T1) SXTAH ------------------- */
17748ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ------------------- (T1) UXTAH ------------------- */
17749ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if ((INSN0(15,4) == 0xFA1      // UXTAH
17750ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        || INSN0(15,4) == 0xFA0)  // SXTAH
17751ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && INSN1(15,12) == BITS4(1,1,1,1)
17752ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && INSN1(7,6) == BITS2(1,0)) {
17753ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Bool isU = INSN0(15,4) == 0xFA1;
17754ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rN  = INSN0(3,0);
17755ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rD  = INSN1(11,8);
17756ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rM  = INSN1(3,0);
17757ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rot = INSN1(5,4);
17758ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!isBadRegT(rD) && !isBadRegT(rN) && !isBadRegT(rM)) {
17759ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp srcL = newTemp(Ity_I32);
17760ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp srcR = newTemp(Ity_I32);
17761ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp res  = newTemp(Ity_I32);
17762ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(srcR, getIRegT(rM));
17763ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(srcL, getIRegT(rN));
17764ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(res,  binop(Iop_Add32,
17765ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            mkexpr(srcL),
17766ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            unop(isU ? Iop_16Uto32 : Iop_16Sto32,
17767ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 unop(Iop_32to16,
17768ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                      genROR32(srcR, 8 * rot)))));
17769ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIRegT(rD, mkexpr(res), condT);
17770ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("%cxtah r%u, r%u, r%u, ror #%u\n",
17771ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             isU ? 'u' : 's', rD, rN, rM, rot);
17772ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
17773ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
17774ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
17775ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17776ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ------------------- (T1) SXTAB ------------------- */
17777ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ------------------- (T1) UXTAB ------------------- */
17778ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if ((INSN0(15,4) == 0xFA5      // UXTAB
17779ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        || INSN0(15,4) == 0xFA4)  // SXTAB
17780ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && INSN1(15,12) == BITS4(1,1,1,1)
17781ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && INSN1(7,6) == BITS2(1,0)) {
17782ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Bool isU = INSN0(15,4) == 0xFA5;
17783ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rN  = INSN0(3,0);
17784ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rD  = INSN1(11,8);
17785ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rM  = INSN1(3,0);
17786ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rot = INSN1(5,4);
17787ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!isBadRegT(rD) && !isBadRegT(rN) && !isBadRegT(rM)) {
17788ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp srcL = newTemp(Ity_I32);
17789ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp srcR = newTemp(Ity_I32);
17790ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp res  = newTemp(Ity_I32);
17791ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(srcR, getIRegT(rM));
17792ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(srcL, getIRegT(rN));
17793ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(res,  binop(Iop_Add32,
17794ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            mkexpr(srcL),
17795ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            unop(isU ? Iop_8Uto32 : Iop_8Sto32,
17796ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 unop(Iop_32to8,
17797ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                      genROR32(srcR, 8 * rot)))));
17798ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIRegT(rD, mkexpr(res), condT);
17799ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("%cxtab r%u, r%u, r%u, ror #%u\n",
17800ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             isU ? 'u' : 's', rD, rN, rM, rot);
17801ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
17802ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
17803ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
17804ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17805ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ------------------- (T1) CLZ ------------------- */
17806ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (INSN0(15,4) == 0xFAB
17807ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && INSN1(15,12) == BITS4(1,1,1,1)
17808ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && INSN1(7,4) == BITS4(1,0,0,0)) {
17809ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rM1 = INSN0(3,0);
17810ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rD  = INSN1(11,8);
17811ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rM2 = INSN1(3,0);
17812ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!isBadRegT(rD) && !isBadRegT(rM1) && rM1 == rM2) {
17813ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp arg = newTemp(Ity_I32);
17814ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp res = newTemp(Ity_I32);
17815ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(arg, getIRegT(rM1));
17816ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(res, IRExpr_Mux0X(
17817ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        unop(Iop_1Uto8,binop(Iop_CmpEQ32,
17818ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                             mkexpr(arg),
17819ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                             mkU32(0))),
17820ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        unop(Iop_Clz32, mkexpr(arg)),
17821ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        mkU32(32)
17822ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         ));
17823ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIRegT(rD, mkexpr(res), condT);
17824ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("clz r%u, r%u\n", rD, rM1);
17825ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
17826ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
17827ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
17828ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17829ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ------------------- (T1) RBIT ------------------- */
17830ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (INSN0(15,4) == 0xFA9
17831ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && INSN1(15,12) == BITS4(1,1,1,1)
17832ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && INSN1(7,4) == BITS4(1,0,1,0)) {
17833ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rM1 = INSN0(3,0);
17834ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rD  = INSN1(11,8);
17835ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rM2 = INSN1(3,0);
17836ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!isBadRegT(rD) && !isBadRegT(rM1) && rM1 == rM2) {
17837ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp arg = newTemp(Ity_I32);
17838ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(arg, getIRegT(rM1));
17839ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp res = gen_BITREV(arg);
17840ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIRegT(rD, mkexpr(res), condT);
17841ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("rbit r%u, r%u\n", rD, rM1);
17842ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
17843ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
17844ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
17845ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17846ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ------------------- (T2) REV   ------------------- */
17847ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ------------------- (T2) REV16 ------------------- */
17848ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (INSN0(15,4) == 0xFA9
17849ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && INSN1(15,12) == BITS4(1,1,1,1)
17850ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && (   INSN1(7,4) == BITS4(1,0,0,0)     // REV
17851ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           || INSN1(7,4) == BITS4(1,0,0,1))) { // REV16
17852ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rM1   = INSN0(3,0);
17853ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rD    = INSN1(11,8);
17854ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rM2   = INSN1(3,0);
17855ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Bool isREV = INSN1(7,4) == BITS4(1,0,0,0);
17856ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!isBadRegT(rD) && !isBadRegT(rM1) && rM1 == rM2) {
17857ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp arg = newTemp(Ity_I32);
17858ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(arg, getIRegT(rM1));
17859ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp res = isREV ? gen_REV(arg) : gen_REV16(arg);
17860ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIRegT(rD, mkexpr(res), condT);
17861ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("rev%s r%u, r%u\n", isREV ? "" : "16", rD, rM1);
17862ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
17863ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
17864ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
17865ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17866ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* -------------- (T1) MSR apsr, reg -------------- */
17867ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (INSN0(15,4) == 0xF38
17868ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && INSN1(15,12) == BITS4(1,0,0,0) && INSN1(9,0) == 0x000) {
17869ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rN          = INSN0(3,0);
17870ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt write_ge    = INSN1(10,10);
17871ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt write_nzcvq = INSN1(11,11);
17872ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!isBadRegT(rN) && (write_nzcvq || write_ge)) {
17873ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp rNt = newTemp(Ity_I32);
17874ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(rNt, getIRegT(rN));
17875ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         desynthesise_APSR( write_nzcvq, write_ge, rNt, condT );
17876ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("msr cpsr_%s%s, r%u\n",
17877ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             write_nzcvq ? "f" : "", write_ge ? "g" : "", rN);
17878ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
17879ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
17880ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
17881ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17882ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* -------------- (T1) MRS reg, apsr -------------- */
17883ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (INSN0(15,0) == 0xF3EF
17884ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && INSN1(15,12) == BITS4(1,0,0,0) && INSN1(7,0) == 0x00) {
17885ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rD = INSN1(11,8);
17886ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!isBadRegT(rD)) {
17887ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp apsr = synthesise_APSR();
17888ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIRegT( rD, mkexpr(apsr), condT );
17889ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("mrs r%u, cpsr\n", rD);
17890ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
17891ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
17892ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
17893ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17894ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ----------------- (T1) LDREX ----------------- */
17895ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (INSN0(15,4) == 0xE85 && INSN1(11,8) == BITS4(1,1,1,1)) {
17896ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rN   = INSN0(3,0);
17897ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rT   = INSN1(15,12);
17898ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt imm8 = INSN1(7,0);
17899ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!isBadRegT(rT) && rN != 15) {
17900ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp res;
17901ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // go uncond
17902ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         mk_skip_over_T32_if_cond_is_false( condT );
17903ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // now uncond
17904ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         res = newTemp(Ity_I32);
17905ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         stmt( IRStmt_LLSC(Iend_LE,
17906ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           res,
17907ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           binop(Iop_Add32, getIRegT(rN), mkU32(imm8 * 4)),
17908ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           NULL/*this is a load*/ ));
17909ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIRegT(rT, mkexpr(res), IRTemp_INVALID);
17910ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("ldrex r%u, [r%u, #+%u]\n", rT, rN, imm8 * 4);
17911ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
17912ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
17913ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
17914ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17915b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   /* --------------- (T1) LDREX{B,H} --------------- */
17916b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   if (INSN0(15,4) == 0xE8D
17917b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov       && (INSN1(11,0) == 0xF4F || INSN1(11,0) == 0xF5F)) {
17918b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      UInt rN  = INSN0(3,0);
17919b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      UInt rT  = INSN1(15,12);
17920b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      Bool isH = INSN1(11,0) == 0xF5F;
17921b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      if (!isBadRegT(rT) && rN != 15) {
17922b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         IRTemp res;
17923b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         // go uncond
17924b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         mk_skip_over_T32_if_cond_is_false( condT );
17925b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         // now uncond
17926b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         res = newTemp(isH ? Ity_I16 : Ity_I8);
17927b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         stmt( IRStmt_LLSC(Iend_LE, res, getIRegT(rN),
17928b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                           NULL/*this is a load*/ ));
17929b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         putIRegT(rT, unop(isH ? Iop_16Uto32 : Iop_8Uto32, mkexpr(res)),
17930b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                      IRTemp_INVALID);
17931b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         DIP("ldrex%c r%u, [r%u]\n", isH ? 'h' : 'b', rT, rN);
17932b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         goto decode_success;
17933b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      }
17934b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   }
17935b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
17936b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   /* --------------- (T1) LDREXD --------------- */
17937b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   if (INSN0(15,4) == 0xE8D && INSN1(7,0) == 0x7F) {
17938b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      UInt rN  = INSN0(3,0);
17939b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      UInt rT  = INSN1(15,12);
17940b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      UInt rT2 = INSN1(11,8);
17941b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      if (!isBadRegT(rT) && !isBadRegT(rT2) && rT != rT2 && rN != 15) {
17942b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         IRTemp res;
17943b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         // go uncond
17944b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         mk_skip_over_T32_if_cond_is_false( condT );
17945b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         // now uncond
17946b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         res = newTemp(Ity_I64);
17947b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         // FIXME: assumes little-endian guest
17948b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         stmt( IRStmt_LLSC(Iend_LE, res, getIRegT(rN),
17949b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                           NULL/*this is a load*/ ));
17950b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         // FIXME: assumes little-endian guest
17951b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         putIRegT(rT,  unop(Iop_64to32,   mkexpr(res)), IRTemp_INVALID);
17952b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         putIRegT(rT2, unop(Iop_64HIto32, mkexpr(res)), IRTemp_INVALID);
17953b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         DIP("ldrexd r%u, r%u, [r%u]\n", rT, rT2, rN);
17954b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         goto decode_success;
17955b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      }
17956b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   }
17957b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
17958ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ----------------- (T1) STREX ----------------- */
17959ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (INSN0(15,4) == 0xE84) {
17960ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rN   = INSN0(3,0);
17961ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rT   = INSN1(15,12);
17962ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt rD   = INSN1(11,8);
17963ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt imm8 = INSN1(7,0);
17964ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!isBadRegT(rD) && !isBadRegT(rT) && rN != 15
17965ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          && rD != rN && rD != rT) {
17966ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp resSC1, resSC32;
17967ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // go uncond
17968ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         mk_skip_over_T32_if_cond_is_false( condT );
17969ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // now uncond
17970ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Ok, now we're unconditional.  Do the store. */
17971ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         resSC1 = newTemp(Ity_I1);
17972ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         stmt( IRStmt_LLSC(Iend_LE,
17973ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           resSC1,
17974ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           binop(Iop_Add32, getIRegT(rN), mkU32(imm8 * 4)),
17975ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           getIRegT(rT)) );
17976ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Set rD to 1 on failure, 0 on success.  Currently we have
17977ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            resSC1 == 0 on failure, 1 on success. */
17978ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         resSC32 = newTemp(Ity_I32);
17979ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(resSC32,
17980ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                unop(Iop_1Uto32, unop(Iop_Not1, mkexpr(resSC1))));
17981ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIRegT(rD, mkexpr(resSC32), IRTemp_INVALID);
17982ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("strex r%u, r%u, [r%u, #+%u]\n", rD, rT, rN, imm8 * 4);
17983ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
17984ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
17985ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
17986ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17987b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   /* --------------- (T1) STREX{B,H} --------------- */
17988b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   if (INSN0(15,4) == 0xE8C
17989b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov       && (INSN1(11,4) == 0xF4 || INSN1(11,4) == 0xF5)) {
17990b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      UInt rN  = INSN0(3,0);
17991b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      UInt rT  = INSN1(15,12);
17992b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      UInt rD  = INSN1(3,0);
17993b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      Bool isH = INSN1(11,4) == 0xF5;
17994b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      if (!isBadRegT(rD) && !isBadRegT(rT) && rN != 15
17995b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov          && rD != rN && rD != rT) {
17996b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         IRTemp resSC1, resSC32;
17997b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         // go uncond
17998b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         mk_skip_over_T32_if_cond_is_false( condT );
17999b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         // now uncond
18000b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         /* Ok, now we're unconditional.  Do the store. */
18001b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         resSC1 = newTemp(Ity_I1);
18002b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         stmt( IRStmt_LLSC(Iend_LE, resSC1, getIRegT(rN),
18003b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                           unop(isH ? Iop_32to16 : Iop_32to8,
18004b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                                getIRegT(rT))) );
18005b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         /* Set rD to 1 on failure, 0 on success.  Currently we have
18006b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            resSC1 == 0 on failure, 1 on success. */
18007b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         resSC32 = newTemp(Ity_I32);
18008b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         assign(resSC32,
18009b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                unop(Iop_1Uto32, unop(Iop_Not1, mkexpr(resSC1))));
18010b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         putIRegT(rD, mkexpr(resSC32), IRTemp_INVALID);
18011b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         DIP("strex%c r%u, r%u, [r%u]\n", isH ? 'h' : 'b', rD, rT, rN);
180121b891657a2208341cc71c68ae16eada0bee46d91Jeff Brown         goto decode_success;
180131b891657a2208341cc71c68ae16eada0bee46d91Jeff Brown      }
180141b891657a2208341cc71c68ae16eada0bee46d91Jeff Brown   }
180151b891657a2208341cc71c68ae16eada0bee46d91Jeff Brown
18016b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   /* ---------------- (T1) STREXD ---------------- */
18017b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   if (INSN0(15,4) == 0xE8C && INSN1(7,4) == BITS4(0,1,1,1)) {
18018b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      UInt rN  = INSN0(3,0);
18019b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      UInt rT  = INSN1(15,12);
18020b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      UInt rT2 = INSN1(11,8);
18021b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      UInt rD  = INSN1(3,0);
18022b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      if (!isBadRegT(rD) && !isBadRegT(rT) && !isBadRegT(rT2)
18023b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov          && rN != 15 && rD != rN && rD != rT && rD != rT) {
18024b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         IRTemp resSC1, resSC32, data;
18025b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         // go uncond
18026b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         mk_skip_over_T32_if_cond_is_false( condT );
18027b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         // now uncond
18028b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         /* Ok, now we're unconditional.  Do the store. */
18029b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         resSC1 = newTemp(Ity_I1);
18030b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         data = newTemp(Ity_I64);
18031b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         // FIXME: assumes little-endian guest
18032b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         assign(data, binop(Iop_32HLto64, getIRegT(rT2), getIRegT(rT)));
18033b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         // FIXME: assumes little-endian guest
18034b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         stmt( IRStmt_LLSC(Iend_LE, resSC1, getIRegT(rN), mkexpr(data)));
18035b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         /* Set rD to 1 on failure, 0 on success.  Currently we have
18036b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            resSC1 == 0 on failure, 1 on success. */
18037b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         resSC32 = newTemp(Ity_I32);
18038b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         assign(resSC32,
18039b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                unop(Iop_1Uto32, unop(Iop_Not1, mkexpr(resSC1))));
18040b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         putIRegT(rD, mkexpr(resSC32), IRTemp_INVALID);
18041b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         DIP("strexd r%u, r%u, r%u, [r%u]\n", rD, rT, rT2, rN);
18042b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         goto decode_success;
18043b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      }
18044b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   }
18045ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* -------------- v7 barrier insns -------------- */
18046545813738cad7083ce736912c82ad4587cbce489Jeff Brown   if (INSN0(15,0) == 0xF3BF && (INSN1(15,0) & 0xFF00) == 0x8F00) {
18047b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      /* FIXME: should this be unconditional? */
18048ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* XXX this isn't really right, is it?  The generated IR does
18049ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         them unconditionally.  I guess it doesn't matter since it
18050ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         doesn't do any harm to do them even when the guarding
18051ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         condition is false -- it's just a performance loss. */
18052545813738cad7083ce736912c82ad4587cbce489Jeff Brown      switch (INSN1(7,0)) {
18053545813738cad7083ce736912c82ad4587cbce489Jeff Brown         case 0x4F: /* DSB sy */
18054545813738cad7083ce736912c82ad4587cbce489Jeff Brown         case 0x4E: /* DSB st */
18055545813738cad7083ce736912c82ad4587cbce489Jeff Brown         case 0x4B: /* DSB ish */
18056545813738cad7083ce736912c82ad4587cbce489Jeff Brown         case 0x4A: /* DSB ishst */
18057545813738cad7083ce736912c82ad4587cbce489Jeff Brown         case 0x47: /* DSB nsh */
18058545813738cad7083ce736912c82ad4587cbce489Jeff Brown         case 0x46: /* DSB nshst */
18059545813738cad7083ce736912c82ad4587cbce489Jeff Brown         case 0x43: /* DSB osh */
18060545813738cad7083ce736912c82ad4587cbce489Jeff Brown         case 0x42: /* DSB oshst */
18061ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            stmt( IRStmt_MBE(Imbe_Fence) );
18062ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("DSB\n");
18063ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto decode_success;
18064545813738cad7083ce736912c82ad4587cbce489Jeff Brown         case 0x5F: /* DMB sy */
18065545813738cad7083ce736912c82ad4587cbce489Jeff Brown         case 0x5E: /* DMB st */
18066545813738cad7083ce736912c82ad4587cbce489Jeff Brown         case 0x5B: /* DMB ish */
18067545813738cad7083ce736912c82ad4587cbce489Jeff Brown         case 0x5A: /* DMB ishst */
18068545813738cad7083ce736912c82ad4587cbce489Jeff Brown         case 0x57: /* DMB nsh */
18069545813738cad7083ce736912c82ad4587cbce489Jeff Brown         case 0x56: /* DMB nshst */
18070545813738cad7083ce736912c82ad4587cbce489Jeff Brown         case 0x53: /* DMB osh */
18071545813738cad7083ce736912c82ad4587cbce489Jeff Brown         case 0x52: /* DMB oshst */
18072ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            stmt( IRStmt_MBE(Imbe_Fence) );
18073ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("DMB\n");
18074ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto decode_success;
18075545813738cad7083ce736912c82ad4587cbce489Jeff Brown         case 0x6F: /* ISB */
18076ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            stmt( IRStmt_MBE(Imbe_Fence) );
18077ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("ISB\n");
18078ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto decode_success;
18079ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         default:
18080ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
18081ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
18082ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
18083ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
18084b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   /* ---------------------- PLD{,W} ---------------------- */
18085b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   if ((INSN0(15,4) & 0xFFD) == 0xF89 && INSN1(15,12) == 0xF) {
18086b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      /* FIXME: should this be unconditional? */
18087b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      /* PLD/PLDW immediate, encoding T1 */
18088b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      UInt rN    = INSN0(3,0);
18089b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      UInt bW    = INSN0(5,5);
18090b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      UInt imm12 = INSN1(11,0);
18091b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      DIP("pld%s [r%u, #%u]\n", bW ? "w" : "",  rN, imm12);
18092b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      goto decode_success;
18093b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   }
18094b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
18095b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   if ((INSN0(15,4) & 0xFFD) == 0xF81 && INSN1(15,8) == 0xFC) {
18096b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      /* FIXME: should this be unconditional? */
18097b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      /* PLD/PLDW immediate, encoding T2 */
18098b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      UInt rN    = INSN0(3,0);
18099b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      UInt bW    = INSN0(5,5);
18100b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      UInt imm8  = INSN1(7,0);
18101b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      DIP("pld%s [r%u, #-%u]\n", bW ? "w" : "",  rN, imm8);
18102b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      goto decode_success;
18103b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   }
18104b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
18105b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   if ((INSN0(15,4) & 0xFFD) == 0xF81 && INSN1(15,6) == 0x3C0) {
18106b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      /* FIXME: should this be unconditional? */
18107b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      /* PLD/PLDW register, encoding T1 */
18108b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      UInt rN   = INSN0(3,0);
18109b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      UInt rM   = INSN1(3,0);
18110b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      UInt bW   = INSN0(5,5);
18111b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      UInt imm2 = INSN1(5,4);
18112b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      if (!isBadRegT(rM)) {
18113b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         DIP("pld%s [r%u, r%u, lsl %d]\n", bW ? "w" : "", rN, rM, imm2);
18114b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         goto decode_success;
18115b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      }
18116b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      /* fall through */
18117b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   }
18118b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
18119f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root   /* -------------- read CP15 TPIDRURO register ------------- */
18120f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root   /* mrc     p15, 0,  r0, c13, c0, 3  up to
18121f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      mrc     p15, 0, r14, c13, c0, 3
18122f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root   */
18123f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root   /* I don't know whether this is really v7-only.  But anyway, we
18124f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      have to support it since arm-linux uses TPIDRURO as a thread
18125f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      state register. */
18126f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root   if ((INSN0(15,0) == 0xEE1D) && (INSN1(11,0) == 0x0F70)) {
18127b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      /* FIXME: should this be unconditional? */
18128f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      UInt rD = INSN1(15,12);
18129f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      if (!isBadRegT(rD)) {
18130f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root         putIRegT(rD, IRExpr_Get(OFFB_TPIDRURO, Ity_I32), IRTemp_INVALID);
18131f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root         DIP("mrc p15,0, r%u, c13, c0, 3\n", rD);
18132f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root         goto decode_success;
18133f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      }
18134f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      /* fall through */
18135f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root   }
18136f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root
18137b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   /* ------------------- CLREX ------------------ */
18138b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   if (INSN0(15,0) == 0xF3BF && INSN1(15,0) == 0x8F2F) {
18139b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      /* AFAICS, this simply cancels a (all?) reservations made by a
18140b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         (any?) preceding LDREX(es).  Arrange to hand it through to
18141b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         the back end. */
18142b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      mk_skip_over_T32_if_cond_is_false( condT );
18143b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      stmt( IRStmt_MBE(Imbe_CancelReservation) );
18144b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      DIP("clrex\n");
18145b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      goto decode_success;
18146b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   }
18147b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
18148ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ------------------- NOP ------------------ */
18149ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (INSN0(15,0) == 0xF3AF && INSN1(15,0) == 0x8000) {
18150ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("nop\n");
18151ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
18152ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
18153ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
18154ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ----------------------------------------------------------- */
18155ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* -- VFP (CP 10, CP 11) instructions (in Thumb mode)       -- */
18156ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ----------------------------------------------------------- */
18157ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
18158ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (INSN0(15,12) == BITS4(1,1,1,0)) {
18159ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt insn28 = (INSN0(11,0) << 16) | INSN1(15,0);
18160ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Bool ok_vfp = decode_CP10_CP11_instruction (
18161ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       &dres, insn28, condT, ARMCondAL/*bogus*/,
18162ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       True/*isT*/
18163ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    );
18164ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (ok_vfp)
18165ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
18166ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
18167ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
18168ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ----------------------------------------------------------- */
18169ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* -- NEON instructions (in Thumb mode)                     -- */
18170ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ----------------------------------------------------------- */
18171ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
18172ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (archinfo->hwcaps & VEX_HWCAPS_ARM_NEON) {
18173ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt insn32 = (INSN0(15,0) << 16) | INSN1(15,0);
18174ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Bool ok_neon = decode_NEON_instruction(
18175ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        &dres, insn32, condT, True/*isT*/
18176ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     );
18177ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (ok_neon)
18178ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
18179ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
18180ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
18181ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ----------------------------------------------------------- */
18182ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* -- v6 media instructions (in Thumb mode)                 -- */
18183ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ----------------------------------------------------------- */
18184ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
18185ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   { UInt insn32 = (INSN0(15,0) << 16) | INSN1(15,0);
18186ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     Bool ok_v6m = decode_V6MEDIA_instruction(
18187ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      &dres, insn32, condT, ARMCondAL/*bogus*/,
18188ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      True/*isT*/
18189ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   );
18190ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     if (ok_v6m)
18191ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        goto decode_success;
18192ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
18193ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
18194ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ----------------------------------------------------------- */
18195ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* -- Undecodable                                           -- */
18196ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ----------------------------------------------------------- */
18197ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
18198ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   goto decode_failure;
18199ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /*NOTREACHED*/
18200ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
18201ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  decode_failure:
18202ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* All decode failures end up here. */
18203ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vex_printf("disInstr(thumb): unhandled instruction: "
18204ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              "0x%04x 0x%04x\n", (UInt)insn0, (UInt)insn1);
18205ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
18206ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Back up ITSTATE to the initial value for this instruction.
18207ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      If we don't do that, any subsequent restart of the instruction
18208ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      will restart with the wrong value. */
18209ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   put_ITSTATE(old_itstate);
18210ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Tell the dispatcher that this insn cannot be decoded, and so has
18211ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      not been executed, and (is currently) the next to be executed.
18212ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      R15 should be up-to-date since it made so at the start of each
18213ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      insn, but nevertheless be paranoid and update it again right
18214ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      now. */
18215ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(0 == (guest_R15_curr_instr_notENC & 1));
18216ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   llPutIReg( 15, mkU32(guest_R15_curr_instr_notENC | 1) );
18217ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   irsb->next     = mkU32(guest_R15_curr_instr_notENC | 1 /* CPSR.T */);
18218ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   irsb->jumpkind = Ijk_NoDecode;
18219ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   dres.whatNext  = Dis_StopHere;
18220ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   dres.len       = 0;
18221ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return dres;
18222ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
18223ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  decode_success:
18224ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* All decode successes end up here. */
18225ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DIP("\n");
18226ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
18227ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(dres.len == 2 || dres.len == 4 || dres.len == 20);
18228ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
18229ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#if 0
18230ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // XXX is this necessary on Thumb?
18231ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Now then.  Do we have an implicit jump to r15 to deal with? */
18232ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (r15written) {
18233ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* If we get jump to deal with, we assume that there's been no
18234ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         other competing branch stuff previously generated for this
18235ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         insn.  That's reasonable, in the sense that the ARM insn set
18236ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         appears to declare as "Unpredictable" any instruction which
18237ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         generates more than one possible new value for r15.  Hence
18238ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         just assert.  The decoders themselves should check against
18239ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         all such instructions which are thusly Unpredictable, and
18240ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         decline to decode them.  Hence we should never get here if we
18241ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         have competing new values for r15, and hence it is safe to
18242ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assert here. */
18243ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(dres.whatNext == Dis_Continue);
18244ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(irsb->next == NULL);
18245b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      vassert(irsb->jumpkind == Ijk_Boring);
18246ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* If r15 is unconditionally written, terminate the block by
18247ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         jumping to it.  If it's conditionally written, still
18248ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         terminate the block (a shame, but we can't do side exits to
18249ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         arbitrary destinations), but first jump to the next
18250ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         instruction if the condition doesn't hold. */
18251ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* We can't use getIRegT(15) to get the destination, since that
18252ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         will produce r15+4, which isn't what we want.  Must use
18253ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         llGetIReg(15) instead. */
18254ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (r15guard == IRTemp_INVALID) {
18255ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* unconditional */
18256ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
18257ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* conditional */
18258ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         stmt( IRStmt_Exit(
18259ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  unop(Iop_32to1,
18260ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       binop(Iop_Xor32,
18261ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             mkexpr(r15guard), mkU32(1))),
18262ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  r15kind,
18263ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  IRConst_U32(guest_R15_curr_instr_notENC + 4)
18264ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         ));
18265ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
18266ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      irsb->next     = llGetIReg(15);
18267ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      irsb->jumpkind = r15kind;
18268ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      dres.whatNext  = Dis_StopHere;
18269ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
18270ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#endif
18271ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
18272ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return dres;
18273ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
18274ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  undef INSN0
18275ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  undef INSN1
18276ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
18277ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
18278ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#undef DIP
18279ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#undef DIS
18280ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
18281ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
18282b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov/* Helper table for figuring out how many insns an IT insn
18283b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   conditionalises.
18284b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
18285b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   An ITxyz instruction of the format "1011 1111 firstcond mask"
18286b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   conditionalises some number of instructions, as indicated by the
18287b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   following table.  A value of zero indicates the instruction is
18288b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   invalid in some way.
18289b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
18290b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   mask = 0 means this isn't an IT instruction
18291b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   fc = 15 (NV) means unpredictable
18292b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
18293b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   The line fc = 14 (AL) is different from the others; there are
18294b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   additional constraints in this case.
18295b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
18296b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov          mask(0 ..                   15)
18297b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov        +--------------------------------
18298b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   fc(0 | 0 4 3 4 2 4 3 4 1 4 3 4 2 4 3 4
18299b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   ..   | 0 4 3 4 2 4 3 4 1 4 3 4 2 4 3 4
18300b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov        | 0 4 3 4 2 4 3 4 1 4 3 4 2 4 3 4
18301b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov        | 0 4 3 4 2 4 3 4 1 4 3 4 2 4 3 4
18302b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov        | 0 4 3 4 2 4 3 4 1 4 3 4 2 4 3 4
18303b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov        | 0 4 3 4 2 4 3 4 1 4 3 4 2 4 3 4
18304b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov        | 0 4 3 4 2 4 3 4 1 4 3 4 2 4 3 4
18305b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov        | 0 4 3 4 2 4 3 4 1 4 3 4 2 4 3 4
18306b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov        | 0 4 3 4 2 4 3 4 1 4 3 4 2 4 3 4
18307b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov        | 0 4 3 4 2 4 3 4 1 4 3 4 2 4 3 4
18308b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov        | 0 4 3 4 2 4 3 4 1 4 3 4 2 4 3 4
18309b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov        | 0 4 3 4 2 4 3 4 1 4 3 4 2 4 3 4
18310b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov        | 0 4 3 4 2 4 3 4 1 4 3 4 2 4 3 4
18311b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov        | 0 4 3 4 2 4 3 4 1 4 3 4 2 4 3 4
18312b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov        | 0 4 3 0 2 0 0 0 1 0 0 0 0 0 0 0
18313b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   15)  | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
18314b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
18315b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   To be conservative with the analysis, let's rule out the mask = 0
18316b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   case, since that isn't an IT insn at all.  But for all the other
18317b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   cases where the table contains zero, that means unpredictable, so
18318b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   let's say 4 to be conservative.  Hence we have a safe value for any
18319b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   IT (mask,fc) pair that the CPU would actually identify as an IT
18320b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   instruction.  The final table is
18321b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
18322b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov          mask(0 ..                   15)
18323b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov        +--------------------------------
18324b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   fc(0 | 0 4 3 4 2 4 3 4 1 4 3 4 2 4 3 4
18325b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   ..   | 0 4 3 4 2 4 3 4 1 4 3 4 2 4 3 4
18326b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov        | 0 4 3 4 2 4 3 4 1 4 3 4 2 4 3 4
18327b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov        | 0 4 3 4 2 4 3 4 1 4 3 4 2 4 3 4
18328b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov        | 0 4 3 4 2 4 3 4 1 4 3 4 2 4 3 4
18329b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov        | 0 4 3 4 2 4 3 4 1 4 3 4 2 4 3 4
18330b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov        | 0 4 3 4 2 4 3 4 1 4 3 4 2 4 3 4
18331b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov        | 0 4 3 4 2 4 3 4 1 4 3 4 2 4 3 4
18332b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov        | 0 4 3 4 2 4 3 4 1 4 3 4 2 4 3 4
18333b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov        | 0 4 3 4 2 4 3 4 1 4 3 4 2 4 3 4
18334b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov        | 0 4 3 4 2 4 3 4 1 4 3 4 2 4 3 4
18335b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov        | 0 4 3 4 2 4 3 4 1 4 3 4 2 4 3 4
18336b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov        | 0 4 3 4 2 4 3 4 1 4 3 4 2 4 3 4
18337b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov        | 0 4 3 4 2 4 3 4 1 4 3 4 2 4 3 4
18338b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov        | 0 4 3 4 2 4 4 4 1 4 4 4 4 4 4 4
18339b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   15)  | 0 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4
18340b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov*/
18341b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanovstatic const UChar it_length_table[256]
18342b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   = { 0, 4, 3, 4, 2, 4, 3, 4, 1, 4, 3, 4, 2, 4, 3, 4,
18343b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov       0, 4, 3, 4, 2, 4, 3, 4, 1, 4, 3, 4, 2, 4, 3, 4,
18344b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov       0, 4, 3, 4, 2, 4, 3, 4, 1, 4, 3, 4, 2, 4, 3, 4,
18345b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov       0, 4, 3, 4, 2, 4, 3, 4, 1, 4, 3, 4, 2, 4, 3, 4,
18346b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov       0, 4, 3, 4, 2, 4, 3, 4, 1, 4, 3, 4, 2, 4, 3, 4,
18347b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov       0, 4, 3, 4, 2, 4, 3, 4, 1, 4, 3, 4, 2, 4, 3, 4,
18348b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov       0, 4, 3, 4, 2, 4, 3, 4, 1, 4, 3, 4, 2, 4, 3, 4,
18349b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov       0, 4, 3, 4, 2, 4, 3, 4, 1, 4, 3, 4, 2, 4, 3, 4,
18350b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov       0, 4, 3, 4, 2, 4, 3, 4, 1, 4, 3, 4, 2, 4, 3, 4,
18351b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov       0, 4, 3, 4, 2, 4, 3, 4, 1, 4, 3, 4, 2, 4, 3, 4,
18352b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov       0, 4, 3, 4, 2, 4, 3, 4, 1, 4, 3, 4, 2, 4, 3, 4,
18353b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov       0, 4, 3, 4, 2, 4, 3, 4, 1, 4, 3, 4, 2, 4, 3, 4,
18354b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov       0, 4, 3, 4, 2, 4, 3, 4, 1, 4, 3, 4, 2, 4, 3, 4,
18355b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov       0, 4, 3, 4, 2, 4, 3, 4, 1, 4, 3, 4, 2, 4, 3, 4,
18356b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov       0, 4, 3, 4, 2, 4, 4, 4, 1, 4, 4, 4, 4, 4, 4, 4,
18357b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov       0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4
18358b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov     };
18359b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
18360b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
18361ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
18362ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- Top-level fn                                         ---*/
18363ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
18364ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
18365ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Disassemble a single instruction into IR.  The instruction
18366ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   is located in host memory at &guest_code[delta]. */
18367ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
18368ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownDisResult disInstr_ARM ( IRSB*        irsb_IN,
18369ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         Bool         put_IP,
18370ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         Bool         (*resteerOkFn) ( void*, Addr64 ),
18371ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         Bool         resteerCisOk,
18372ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         void*        callback_opaque,
18373ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         UChar*       guest_code_IN,
18374ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         Long         delta_ENCODED,
18375ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         Addr64       guest_IP_ENCODED,
18376ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         VexArch      guest_arch,
18377ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         VexArchInfo* archinfo,
18378ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         VexAbiInfo*  abiinfo,
18379ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         Bool         host_bigendian_IN )
18380ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
18381ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DisResult dres;
18382ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Bool isThumb = (Bool)(guest_IP_ENCODED & 1);
18383ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
18384ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Set globals (see top of this file) */
18385ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(guest_arch == VexArchARM);
18386ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
18387ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   irsb              = irsb_IN;
18388ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   host_is_bigendian = host_bigendian_IN;
18389ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   __curr_is_Thumb   = isThumb;
18390ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
18391ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (isThumb) {
18392ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      guest_R15_curr_instr_notENC = (Addr32)guest_IP_ENCODED - 1;
18393ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
18394ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      guest_R15_curr_instr_notENC = (Addr32)guest_IP_ENCODED;
18395ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
18396ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
18397ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (isThumb) {
18398ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      dres = disInstr_THUMB_WRK ( put_IP, resteerOkFn,
18399ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  resteerCisOk, callback_opaque,
18400ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  &guest_code_IN[delta_ENCODED - 1],
18401ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  archinfo, abiinfo );
18402ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
18403ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      dres = disInstr_ARM_WRK ( put_IP, resteerOkFn,
18404ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                resteerCisOk, callback_opaque,
18405ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                &guest_code_IN[delta_ENCODED],
18406ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                archinfo, abiinfo );
18407ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
18408ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
18409ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return dres;
18410ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
18411ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
18412ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Test program for the conversion of IRCmpF64Result values to VFP
18413ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   nzcv values.  See handling of FCMPD et al above. */
18414ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*
18415ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownUInt foo ( UInt x )
18416ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
18417ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt ix    = ((x >> 5) & 3) | (x & 1);
18418ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt termL = (((((ix ^ 1) << 30) - 1) >> 29) + 1);
18419ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt termR = (ix & (ix >> 1) & 1);
18420ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return termL  -  termR;
18421ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
18422ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
18423ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid try ( char* s, UInt ir, UInt req )
18424ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
18425ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt act = foo(ir);
18426ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   printf("%s 0x%02x -> req %d%d%d%d act %d%d%d%d (0x%x)\n",
18427ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          s, ir, (req >> 3) & 1, (req >> 2) & 1,
18428ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 (req >> 1) & 1, (req >> 0) & 1,
18429ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 (act >> 3) & 1, (act >> 2) & 1,
18430ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 (act >> 1) & 1, (act >> 0) & 1, act);
18431ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
18432ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
18433ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
18434ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownint main ( void )
18435ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
18436ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   printf("\n");
18437ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   try("UN", 0x45, 0b0011);
18438ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   try("LT", 0x01, 0b1000);
18439ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   try("GT", 0x00, 0b0010);
18440ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   try("EQ", 0x40, 0b0110);
18441ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   printf("\n");
18442ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return 0;
18443ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
18444ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
18445ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
18446ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--------------------------------------------------------------------*/
18447ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- end                                         guest_arm_toIR.c ---*/
18448ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--------------------------------------------------------------------*/
18449