1/*
2 * Copyright (C) 2009 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "Dalvik.h"
18#include "libdex/DexOpcodes.h"
19
20#include "../../CompilerInternals.h"
21#include "ArmLIR.h"
22#include "Codegen.h"
23#include <sys/mman.h>           /* for protection change */
24
25#define MAX_ASSEMBLER_RETRIES 10
26
27/*
28 * opcode: ArmOpcode enum
29 * skeleton: pre-designated bit-pattern for this opcode
30 * k0: key to applying ds/de
31 * ds: dest start bit position
32 * de: dest end bit position
33 * k1: key to applying s1s/s1e
34 * s1s: src1 start bit position
35 * s1e: src1 end bit position
36 * k2: key to applying s2s/s2e
37 * s2s: src2 start bit position
38 * s2e: src2 end bit position
39 * operands: number of operands (for sanity check purposes)
40 * name: mnemonic name
41 * fmt: for pretty-printing
42 */
43#define ENCODING_MAP(opcode, skeleton, k0, ds, de, k1, s1s, s1e, k2, s2s, s2e, \
44                     k3, k3s, k3e, flags, name, fmt, size) \
45        {skeleton, {{k0, ds, de}, {k1, s1s, s1e}, {k2, s2s, s2e}, \
46                    {k3, k3s, k3e}}, opcode, flags, name, fmt, size}
47
48/* Instruction dump string format keys: !pf, where "!" is the start
49 * of the key, "p" is which numeric operand to use and "f" is the
50 * print format.
51 *
52 * [p]ositions:
53 *     0 -> operands[0] (dest)
54 *     1 -> operands[1] (src1)
55 *     2 -> operands[2] (src2)
56 *     3 -> operands[3] (extra)
57 *
58 * [f]ormats:
59 *     h -> 4-digit hex
60 *     d -> decimal
61 *     E -> decimal*4
62 *     F -> decimal*2
63 *     c -> branch condition (beq, bne, etc.)
64 *     t -> pc-relative target
65 *     u -> 1st half of bl[x] target
66 *     v -> 2nd half ob bl[x] target
67 *     R -> register list
68 *     s -> single precision floating point register
69 *     S -> double precision floating point register
70 *     m -> Thumb2 modified immediate
71 *     n -> complimented Thumb2 modified immediate
72 *     M -> Thumb2 16-bit zero-extended immediate
73 *     b -> 4-digit binary
74 *     B -> dmb option string (sy, st, ish, ishst, nsh, hshst)
75 *     H -> operand shift
76 *
77 *  [!] escape.  To insert "!", use "!!"
78 */
79/* NOTE: must be kept in sync with enum ArmOpcode from ArmLIR.h */
80ArmEncodingMap EncodingMap[kArmLast] = {
81    ENCODING_MAP(kArm16BitData,    0x0000,
82                 kFmtBitBlt, 15, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
83                 kFmtUnused, -1, -1, IS_UNARY_OP, "data", "0x!0h(!0d)", 1),
84    ENCODING_MAP(kThumbAdcRR,        0x4140,
85                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1,
86                 kFmtUnused, -1, -1,
87                 IS_BINARY_OP | REG_DEF0_USE01 | SETS_CCODES | USES_CCODES,
88                 "adcs", "r!0d, r!1d", 1),
89    ENCODING_MAP(kThumbAddRRI3,      0x1c00,
90                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtBitBlt, 8, 6,
91                 kFmtUnused, -1, -1,
92                 IS_TERTIARY_OP | REG_DEF0_USE1 | SETS_CCODES,
93                 "adds", "r!0d, r!1d, #!2d", 1),
94    ENCODING_MAP(kThumbAddRI8,       0x3000,
95                 kFmtBitBlt, 10, 8, kFmtBitBlt, 7, 0, kFmtUnused, -1, -1,
96                 kFmtUnused, -1, -1,
97                 IS_BINARY_OP | REG_DEF0_USE0 | SETS_CCODES,
98                 "adds", "r!0d, r!0d, #!1d", 1),
99    ENCODING_MAP(kThumbAddRRR,       0x1800,
100                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtBitBlt, 8, 6,
101                 kFmtUnused, -1, -1,
102                 IS_TERTIARY_OP | REG_DEF0_USE12 | SETS_CCODES,
103                 "adds", "r!0d, r!1d, r!2d", 1),
104    ENCODING_MAP(kThumbAddRRLH,     0x4440,
105                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1,
106                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE01,
107                 "add", "r!0d, r!1d", 1),
108    ENCODING_MAP(kThumbAddRRHL,     0x4480,
109                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1,
110                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE01,
111                 "add", "r!0d, r!1d", 1),
112    ENCODING_MAP(kThumbAddRRHH,     0x44c0,
113                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1,
114                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE01,
115                 "add", "r!0d, r!1d", 1),
116    ENCODING_MAP(kThumbAddPcRel,    0xa000,
117                 kFmtBitBlt, 10, 8, kFmtBitBlt, 7, 0, kFmtUnused, -1, -1,
118                 kFmtUnused, -1, -1, IS_TERTIARY_OP | IS_BRANCH,
119                 "add", "r!0d, pc, #!1E", 1),
120    ENCODING_MAP(kThumbAddSpRel,    0xa800,
121                 kFmtBitBlt, 10, 8, kFmtUnused, -1, -1, kFmtBitBlt, 7, 0,
122                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF_SP | REG_USE_SP,
123                 "add", "r!0d, sp, #!2E", 1),
124    ENCODING_MAP(kThumbAddSpI7,      0xb000,
125                 kFmtBitBlt, 6, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
126                 kFmtUnused, -1, -1, IS_UNARY_OP | REG_DEF_SP | REG_USE_SP,
127                 "add", "sp, #!0d*4", 1),
128    ENCODING_MAP(kThumbAndRR,        0x4000,
129                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1,
130                 kFmtUnused, -1, -1,
131                 IS_BINARY_OP | REG_DEF0_USE01 | SETS_CCODES,
132                 "ands", "r!0d, r!1d", 1),
133    ENCODING_MAP(kThumbAsrRRI5,      0x1000,
134                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtBitBlt, 10, 6,
135                 kFmtUnused, -1, -1,
136                 IS_TERTIARY_OP | REG_DEF0_USE1 | SETS_CCODES,
137                 "asrs", "r!0d, r!1d, #!2d", 1),
138    ENCODING_MAP(kThumbAsrRR,        0x4100,
139                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1,
140                 kFmtUnused, -1, -1,
141                 IS_BINARY_OP | REG_DEF0_USE01 | SETS_CCODES,
142                 "asrs", "r!0d, r!1d", 1),
143    ENCODING_MAP(kThumbBCond,        0xd000,
144                 kFmtBitBlt, 7, 0, kFmtBitBlt, 11, 8, kFmtUnused, -1, -1,
145                 kFmtUnused, -1, -1, IS_BINARY_OP | IS_BRANCH | USES_CCODES,
146                 "b!1c", "!0t", 1),
147    ENCODING_MAP(kThumbBUncond,      0xe000,
148                 kFmtBitBlt, 10, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
149                 kFmtUnused, -1, -1, NO_OPERAND | IS_BRANCH,
150                 "b", "!0t", 1),
151    ENCODING_MAP(kThumbBicRR,        0x4380,
152                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1,
153                 kFmtUnused, -1, -1,
154                 IS_BINARY_OP | REG_DEF0_USE01 | SETS_CCODES,
155                 "bics", "r!0d, r!1d", 1),
156    ENCODING_MAP(kThumbBkpt,          0xbe00,
157                 kFmtBitBlt, 7, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
158                 kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH,
159                 "bkpt", "!0d", 1),
160    ENCODING_MAP(kThumbBlx1,         0xf000,
161                 kFmtBitBlt, 10, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
162                 kFmtUnused, -1, -1, IS_BINARY_OP | IS_BRANCH | REG_DEF_LR,
163                 "blx_1", "!0u", 1),
164    ENCODING_MAP(kThumbBlx2,         0xe800,
165                 kFmtBitBlt, 10, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
166                 kFmtUnused, -1, -1, IS_BINARY_OP | IS_BRANCH | REG_DEF_LR,
167                 "blx_2", "!0v", 1),
168    ENCODING_MAP(kThumbBl1,          0xf000,
169                 kFmtBitBlt, 10, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
170                 kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH | REG_DEF_LR,
171                 "bl_1", "!0u", 1),
172    ENCODING_MAP(kThumbBl2,          0xf800,
173                 kFmtBitBlt, 10, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
174                 kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH | REG_DEF_LR,
175                 "bl_2", "!0v", 1),
176    ENCODING_MAP(kThumbBlxR,         0x4780,
177                 kFmtBitBlt, 6, 3, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
178                 kFmtUnused, -1, -1,
179                 IS_UNARY_OP | REG_USE0 | IS_BRANCH | REG_DEF_LR,
180                 "blx", "r!0d", 1),
181    ENCODING_MAP(kThumbBx,            0x4700,
182                 kFmtBitBlt, 6, 3, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
183                 kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH,
184                 "bx", "r!0d", 1),
185    ENCODING_MAP(kThumbCmnRR,        0x42c0,
186                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1,
187                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_USE01 | SETS_CCODES,
188                 "cmn", "r!0d, r!1d", 1),
189    ENCODING_MAP(kThumbCmpRI8,       0x2800,
190                 kFmtBitBlt, 10, 8, kFmtBitBlt, 7, 0, kFmtUnused, -1, -1,
191                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_USE0 | SETS_CCODES,
192                 "cmp", "r!0d, #!1d", 1),
193    ENCODING_MAP(kThumbCmpRR,        0x4280,
194                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1,
195                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_USE01 | SETS_CCODES,
196                 "cmp", "r!0d, r!1d", 1),
197    ENCODING_MAP(kThumbCmpLH,        0x4540,
198                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1,
199                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_USE01 | SETS_CCODES,
200                 "cmp", "r!0d, r!1d", 1),
201    ENCODING_MAP(kThumbCmpHL,        0x4580,
202                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1,
203                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_USE01 | SETS_CCODES,
204                 "cmp", "r!0d, r!1d", 1),
205    ENCODING_MAP(kThumbCmpHH,        0x45c0,
206                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1,
207                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_USE01 | SETS_CCODES,
208                 "cmp", "r!0d, r!1d", 1),
209    ENCODING_MAP(kThumbEorRR,        0x4040,
210                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1,
211                 kFmtUnused, -1, -1,
212                 IS_BINARY_OP | REG_DEF0_USE01 | SETS_CCODES,
213                 "eors", "r!0d, r!1d", 1),
214    ENCODING_MAP(kThumbLdmia,         0xc800,
215                 kFmtBitBlt, 10, 8, kFmtBitBlt, 7, 0, kFmtUnused, -1, -1,
216                 kFmtUnused, -1, -1,
217                 IS_BINARY_OP | REG_DEF0_USE0 | REG_DEF_LIST1 | IS_LOAD,
218                 "ldmia", "r!0d!!, <!1R>", 1),
219    ENCODING_MAP(kThumbLdrRRI5,      0x6800,
220                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtBitBlt, 10, 6,
221                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1 | IS_LOAD,
222                 "ldr", "r!0d, [r!1d, #!2E]", 1),
223    ENCODING_MAP(kThumbLdrRRR,       0x5800,
224                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtBitBlt, 8, 6,
225                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12 | IS_LOAD,
226                 "ldr", "r!0d, [r!1d, r!2d]", 1),
227    ENCODING_MAP(kThumbLdrPcRel,    0x4800,
228                 kFmtBitBlt, 10, 8, kFmtBitBlt, 7, 0, kFmtUnused, -1, -1,
229                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0 | REG_USE_PC
230                 | IS_LOAD, "ldr", "r!0d, [pc, #!1E]", 1),
231    ENCODING_MAP(kThumbLdrSpRel,    0x9800,
232                 kFmtBitBlt, 10, 8, kFmtUnused, -1, -1, kFmtBitBlt, 7, 0,
233                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0 | REG_USE_SP
234                 | IS_LOAD, "ldr", "r!0d, [sp, #!2E]", 1),
235    ENCODING_MAP(kThumbLdrbRRI5,     0x7800,
236                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtBitBlt, 10, 6,
237                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1 | IS_LOAD,
238                 "ldrb", "r!0d, [r!1d, #2d]", 1),
239    ENCODING_MAP(kThumbLdrbRRR,      0x5c00,
240                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtBitBlt, 8, 6,
241                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12 | IS_LOAD,
242                 "ldrb", "r!0d, [r!1d, r!2d]", 1),
243    ENCODING_MAP(kThumbLdrhRRI5,     0x8800,
244                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtBitBlt, 10, 6,
245                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1 | IS_LOAD,
246                 "ldrh", "r!0d, [r!1d, #!2F]", 1),
247    ENCODING_MAP(kThumbLdrhRRR,      0x5a00,
248                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtBitBlt, 8, 6,
249                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12 | IS_LOAD,
250                 "ldrh", "r!0d, [r!1d, r!2d]", 1),
251    ENCODING_MAP(kThumbLdrsbRRR,     0x5600,
252                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtBitBlt, 8, 6,
253                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12 | IS_LOAD,
254                 "ldrsb", "r!0d, [r!1d, r!2d]", 1),
255    ENCODING_MAP(kThumbLdrshRRR,     0x5e00,
256                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtBitBlt, 8, 6,
257                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12 | IS_LOAD,
258                 "ldrsh", "r!0d, [r!1d, r!2d]", 1),
259    ENCODING_MAP(kThumbLslRRI5,      0x0000,
260                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtBitBlt, 10, 6,
261                 kFmtUnused, -1, -1,
262                 IS_TERTIARY_OP | REG_DEF0_USE1 | SETS_CCODES,
263                 "lsls", "r!0d, r!1d, #!2d", 1),
264    ENCODING_MAP(kThumbLslRR,        0x4080,
265                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1,
266                 kFmtUnused, -1, -1,
267                 IS_BINARY_OP | REG_DEF0_USE01 | SETS_CCODES,
268                 "lsls", "r!0d, r!1d", 1),
269    ENCODING_MAP(kThumbLsrRRI5,      0x0800,
270                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtBitBlt, 10, 6,
271                 kFmtUnused, -1, -1,
272                 IS_TERTIARY_OP | REG_DEF0_USE1 | SETS_CCODES,
273                 "lsrs", "r!0d, r!1d, #!2d", 1),
274    ENCODING_MAP(kThumbLsrRR,        0x40c0,
275                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1,
276                 kFmtUnused, -1, -1,
277                 IS_BINARY_OP | REG_DEF0_USE01 | SETS_CCODES,
278                 "lsrs", "r!0d, r!1d", 1),
279    ENCODING_MAP(kThumbMovImm,       0x2000,
280                 kFmtBitBlt, 10, 8, kFmtBitBlt, 7, 0, kFmtUnused, -1, -1,
281                 kFmtUnused, -1, -1,
282                 IS_BINARY_OP | REG_DEF0 | SETS_CCODES,
283                 "movs", "r!0d, #!1d", 1),
284    ENCODING_MAP(kThumbMovRR,        0x1c00,
285                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1,
286                 kFmtUnused, -1, -1,
287                 IS_BINARY_OP | REG_DEF0_USE1 | SETS_CCODES,
288                 "movs", "r!0d, r!1d", 1),
289    ENCODING_MAP(kThumbMovRR_H2H,    0x46c0,
290                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1,
291                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
292                 "mov", "r!0d, r!1d", 1),
293    ENCODING_MAP(kThumbMovRR_H2L,    0x4640,
294                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1,
295                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
296                 "mov", "r!0d, r!1d", 1),
297    ENCODING_MAP(kThumbMovRR_L2H,    0x4680,
298                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1,
299                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
300                 "mov", "r!0d, r!1d", 1),
301    ENCODING_MAP(kThumbMul,           0x4340,
302                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1,
303                 kFmtUnused, -1, -1,
304                 IS_BINARY_OP | REG_DEF0_USE01 | SETS_CCODES,
305                 "muls", "r!0d, r!1d", 1),
306    ENCODING_MAP(kThumbMvn,           0x43c0,
307                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1,
308                 kFmtUnused, -1, -1,
309                 IS_BINARY_OP | REG_DEF0_USE1 | SETS_CCODES,
310                 "mvns", "r!0d, r!1d", 1),
311    ENCODING_MAP(kThumbNeg,           0x4240,
312                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1,
313                 kFmtUnused, -1, -1,
314                 IS_BINARY_OP | REG_DEF0_USE1 | SETS_CCODES,
315                 "negs", "r!0d, r!1d", 1),
316    ENCODING_MAP(kThumbOrr,           0x4300,
317                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1,
318                 kFmtUnused, -1, -1,
319                 IS_BINARY_OP | REG_DEF0_USE01 | SETS_CCODES,
320                 "orrs", "r!0d, r!1d", 1),
321    ENCODING_MAP(kThumbPop,           0xbc00,
322                 kFmtBitBlt, 8, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
323                 kFmtUnused, -1, -1,
324                 IS_UNARY_OP | REG_DEF_SP | REG_USE_SP | REG_DEF_LIST0
325                 | IS_LOAD, "pop", "<!0R>", 1),
326    ENCODING_MAP(kThumbPush,          0xb400,
327                 kFmtBitBlt, 8, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
328                 kFmtUnused, -1, -1,
329                 IS_UNARY_OP | REG_DEF_SP | REG_USE_SP | REG_USE_LIST0
330                 | IS_STORE, "push", "<!0R>", 1),
331    ENCODING_MAP(kThumbRorRR,        0x41c0,
332                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1,
333                 kFmtUnused, -1, -1,
334                 IS_BINARY_OP | REG_DEF0_USE01 | SETS_CCODES,
335                 "rors", "r!0d, r!1d", 1),
336    ENCODING_MAP(kThumbSbc,           0x4180,
337                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1,
338                 kFmtUnused, -1, -1,
339                 IS_BINARY_OP | REG_DEF0_USE01 | USES_CCODES | SETS_CCODES,
340                 "sbcs", "r!0d, r!1d", 1),
341    ENCODING_MAP(kThumbStmia,         0xc000,
342                 kFmtBitBlt, 10, 8, kFmtBitBlt, 7, 0, kFmtUnused, -1, -1,
343                 kFmtUnused, -1, -1,
344                 IS_BINARY_OP | REG_DEF0 | REG_USE0 | REG_USE_LIST1 | IS_STORE,
345                 "stmia", "r!0d!!, <!1R>", 1),
346    ENCODING_MAP(kThumbStrRRI5,      0x6000,
347                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtBitBlt, 10, 6,
348                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE01 | IS_STORE,
349                 "str", "r!0d, [r!1d, #!2E]", 1),
350    ENCODING_MAP(kThumbStrRRR,       0x5000,
351                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtBitBlt, 8, 6,
352                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE012 | IS_STORE,
353                 "str", "r!0d, [r!1d, r!2d]", 1),
354    ENCODING_MAP(kThumbStrSpRel,    0x9000,
355                 kFmtBitBlt, 10, 8, kFmtUnused, -1, -1, kFmtBitBlt, 7, 0,
356                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE0 | REG_USE_SP
357                 | IS_STORE, "str", "r!0d, [sp, #!2E]", 1),
358    ENCODING_MAP(kThumbStrbRRI5,     0x7000,
359                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtBitBlt, 10, 6,
360                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE01 | IS_STORE,
361                 "strb", "r!0d, [r!1d, #!2d]", 1),
362    ENCODING_MAP(kThumbStrbRRR,      0x5400,
363                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtBitBlt, 8, 6,
364                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE012 | IS_STORE,
365                 "strb", "r!0d, [r!1d, r!2d]", 1),
366    ENCODING_MAP(kThumbStrhRRI5,     0x8000,
367                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtBitBlt, 10, 6,
368                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE01 | IS_STORE,
369                 "strh", "r!0d, [r!1d, #!2F]", 1),
370    ENCODING_MAP(kThumbStrhRRR,      0x5200,
371                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtBitBlt, 8, 6,
372                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE012 | IS_STORE,
373                 "strh", "r!0d, [r!1d, r!2d]", 1),
374    ENCODING_MAP(kThumbSubRRI3,      0x1e00,
375                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtBitBlt, 8, 6,
376                 kFmtUnused, -1, -1,
377                 IS_TERTIARY_OP | REG_DEF0_USE1 | SETS_CCODES,
378                 "subs", "r!0d, r!1d, #!2d]", 1),
379    ENCODING_MAP(kThumbSubRI8,       0x3800,
380                 kFmtBitBlt, 10, 8, kFmtBitBlt, 7, 0, kFmtUnused, -1, -1,
381                 kFmtUnused, -1, -1,
382                 IS_BINARY_OP | REG_DEF0_USE0 | SETS_CCODES,
383                 "subs", "r!0d, #!1d", 1),
384    ENCODING_MAP(kThumbSubRRR,       0x1a00,
385                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtBitBlt, 8, 6,
386                 kFmtUnused, -1, -1,
387                 IS_TERTIARY_OP | REG_DEF0_USE12 | SETS_CCODES,
388                 "subs", "r!0d, r!1d, r!2d", 1),
389    ENCODING_MAP(kThumbSubSpI7,      0xb080,
390                 kFmtBitBlt, 6, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
391                 kFmtUnused, -1, -1,
392                 IS_UNARY_OP | REG_DEF_SP | REG_USE_SP,
393                 "sub", "sp, #!0d", 1),
394    ENCODING_MAP(kThumbSwi,           0xdf00,
395                 kFmtBitBlt, 7, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1,                       kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH,
396                 "swi", "!0d", 1),
397    ENCODING_MAP(kThumbTst,           0x4200,
398                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1,
399                 kFmtUnused, -1, -1, IS_UNARY_OP | REG_USE01 | SETS_CCODES,
400                 "tst", "r!0d, r!1d", 1),
401    ENCODING_MAP(kThumb2Vldrs,       0xed900a00,
402                 kFmtSfp, 22, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 7, 0,
403                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1 | IS_LOAD,
404                 "vldr", "!0s, [r!1d, #!2E]", 2),
405    ENCODING_MAP(kThumb2Vldrd,       0xed900b00,
406                 kFmtDfp, 22, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 7, 0,
407                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1 | IS_LOAD,
408                 "vldr", "!0S, [r!1d, #!2E]", 2),
409    ENCODING_MAP(kThumb2Vmuls,        0xee200a00,
410                 kFmtSfp, 22, 12, kFmtSfp, 7, 16, kFmtSfp, 5, 0,
411                 kFmtUnused, -1, -1,
412                 IS_TERTIARY_OP | REG_DEF0_USE12,
413                 "vmuls", "!0s, !1s, !2s", 2),
414    ENCODING_MAP(kThumb2Vmuld,        0xee200b00,
415                 kFmtDfp, 22, 12, kFmtDfp, 7, 16, kFmtDfp, 5, 0,
416                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
417                 "vmuld", "!0S, !1S, !2S", 2),
418    ENCODING_MAP(kThumb2Vstrs,       0xed800a00,
419                 kFmtSfp, 22, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 7, 0,
420                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE01 | IS_STORE,
421                 "vstr", "!0s, [r!1d, #!2E]", 2),
422    ENCODING_MAP(kThumb2Vstrd,       0xed800b00,
423                 kFmtDfp, 22, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 7, 0,
424                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE01 | IS_STORE,
425                 "vstr", "!0S, [r!1d, #!2E]", 2),
426    ENCODING_MAP(kThumb2Vsubs,        0xee300a40,
427                 kFmtSfp, 22, 12, kFmtSfp, 7, 16, kFmtSfp, 5, 0,
428                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
429                 "vsub", "!0s, !1s, !2s", 2),
430    ENCODING_MAP(kThumb2Vsubd,        0xee300b40,
431                 kFmtDfp, 22, 12, kFmtDfp, 7, 16, kFmtDfp, 5, 0,
432                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
433                 "vsub", "!0S, !1S, !2S", 2),
434    ENCODING_MAP(kThumb2Vadds,        0xee300a00,
435                 kFmtSfp, 22, 12, kFmtSfp, 7, 16, kFmtSfp, 5, 0,
436                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
437                 "vadd", "!0s, !1s, !2s", 2),
438    ENCODING_MAP(kThumb2Vaddd,        0xee300b00,
439                 kFmtDfp, 22, 12, kFmtDfp, 7, 16, kFmtDfp, 5, 0,
440                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
441                 "vadd", "!0S, !1S, !2S", 2),
442    ENCODING_MAP(kThumb2Vdivs,        0xee800a00,
443                 kFmtSfp, 22, 12, kFmtSfp, 7, 16, kFmtSfp, 5, 0,
444                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
445                 "vdivs", "!0s, !1s, !2s", 2),
446    ENCODING_MAP(kThumb2Vdivd,        0xee800b00,
447                 kFmtDfp, 22, 12, kFmtDfp, 7, 16, kFmtDfp, 5, 0,
448                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
449                 "vdivd", "!0S, !1S, !2S", 2),
450    ENCODING_MAP(kThumb2VcvtIF,       0xeeb80ac0,
451                 kFmtSfp, 22, 12, kFmtSfp, 5, 0, kFmtUnused, -1, -1,
452                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
453                 "vcvt.f32", "!0s, !1s", 2),
454    ENCODING_MAP(kThumb2VcvtID,       0xeeb80bc0,
455                 kFmtDfp, 22, 12, kFmtSfp, 5, 0, kFmtUnused, -1, -1,
456                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
457                 "vcvt.f64", "!0S, !1s", 2),
458    ENCODING_MAP(kThumb2VcvtFI,       0xeebd0ac0,
459                 kFmtSfp, 22, 12, kFmtSfp, 5, 0, kFmtUnused, -1, -1,
460                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
461                 "vcvt.s32.f32 ", "!0s, !1s", 2),
462    ENCODING_MAP(kThumb2VcvtDI,       0xeebd0bc0,
463                 kFmtSfp, 22, 12, kFmtDfp, 5, 0, kFmtUnused, -1, -1,
464                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
465                 "vcvt.s32.f64 ", "!0s, !1S", 2),
466    ENCODING_MAP(kThumb2VcvtFd,       0xeeb70ac0,
467                 kFmtDfp, 22, 12, kFmtSfp, 5, 0, kFmtUnused, -1, -1,
468                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
469                 "vcvt.f64.f32 ", "!0S, !1s", 2),
470    ENCODING_MAP(kThumb2VcvtDF,       0xeeb70bc0,
471                 kFmtSfp, 22, 12, kFmtDfp, 5, 0, kFmtUnused, -1, -1,
472                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
473                 "vcvt.f32.f64 ", "!0s, !1S", 2),
474    ENCODING_MAP(kThumb2Vsqrts,       0xeeb10ac0,
475                 kFmtSfp, 22, 12, kFmtSfp, 5, 0, kFmtUnused, -1, -1,
476                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
477                 "vsqrt.f32 ", "!0s, !1s", 2),
478    ENCODING_MAP(kThumb2Vsqrtd,       0xeeb10bc0,
479                 kFmtDfp, 22, 12, kFmtDfp, 5, 0, kFmtUnused, -1, -1,
480                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
481                 "vsqrt.f64 ", "!0S, !1S", 2),
482    ENCODING_MAP(kThumb2MovImmShift, 0xf04f0000, /* no setflags encoding */
483                 kFmtBitBlt, 11, 8, kFmtModImm, -1, -1, kFmtUnused, -1, -1,
484                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0,
485                 "mov", "r!0d, #!1m", 2),
486    ENCODING_MAP(kThumb2MovImm16,       0xf2400000,
487                 kFmtBitBlt, 11, 8, kFmtImm16, -1, -1, kFmtUnused, -1, -1,
488                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0,
489                 "mov", "r!0d, #!1M", 2),
490    ENCODING_MAP(kThumb2StrRRI12,       0xf8c00000,
491                 kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 11, 0,
492                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE01 | IS_STORE,
493                 "str", "r!0d, [r!1d, #!2d]", 2),
494    ENCODING_MAP(kThumb2LdrRRI12,       0xf8d00000,
495                 kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 11, 0,
496                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1 | IS_LOAD,
497                 "ldr", "r!0d, [r!1d, #!2d]", 2),
498    ENCODING_MAP(kThumb2StrRRI8Predec,       0xf8400c00,
499                 kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 8, 0,
500                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE01 | IS_STORE,
501                 "str", "r!0d, [r!1d, #-!2d]", 2),
502    ENCODING_MAP(kThumb2LdrRRI8Predec,       0xf8500c00,
503                 kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 8, 0,
504                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1 | IS_LOAD,
505                 "ldr", "r!0d, [r!1d, #-!2d]", 2),
506    ENCODING_MAP(kThumb2Cbnz,       0xb900, /* Note: does not affect flags */
507                 kFmtBitBlt, 2, 0, kFmtImm6, -1, -1, kFmtUnused, -1, -1,
508                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_USE0 | IS_BRANCH,
509                 "cbnz", "r!0d,!1t", 1),
510    ENCODING_MAP(kThumb2Cbz,       0xb100, /* Note: does not affect flags */
511                 kFmtBitBlt, 2, 0, kFmtImm6, -1, -1, kFmtUnused, -1, -1,
512                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_USE0 | IS_BRANCH,
513                 "cbz", "r!0d,!1t", 1),
514    ENCODING_MAP(kThumb2AddRRI12,       0xf2000000,
515                 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtImm12, -1, -1,
516                 kFmtUnused, -1, -1,
517                 IS_TERTIARY_OP | REG_DEF0_USE1,/* Note: doesn't affect flags */
518                 "add", "r!0d,r!1d,#!2d", 2),
519    ENCODING_MAP(kThumb2MovRR,       0xea4f0000, /* no setflags encoding */
520                 kFmtBitBlt, 11, 8, kFmtBitBlt, 3, 0, kFmtUnused, -1, -1,
521                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
522                 "mov", "r!0d, r!1d", 2),
523    ENCODING_MAP(kThumb2Vmovs,       0xeeb00a40,
524                 kFmtSfp, 22, 12, kFmtSfp, 5, 0, kFmtUnused, -1, -1,
525                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
526                 "vmov.f32 ", " !0s, !1s", 2),
527    ENCODING_MAP(kThumb2Vmovd,       0xeeb00b40,
528                 kFmtDfp, 22, 12, kFmtDfp, 5, 0, kFmtUnused, -1, -1,
529                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
530                 "vmov.f64 ", " !0S, !1S", 2),
531    ENCODING_MAP(kThumb2Ldmia,         0xe8900000,
532                 kFmtBitBlt, 19, 16, kFmtBitBlt, 15, 0, kFmtUnused, -1, -1,
533                 kFmtUnused, -1, -1,
534                 IS_BINARY_OP | REG_DEF0_USE0 | REG_DEF_LIST1 | IS_LOAD,
535                 "ldmia", "r!0d!!, <!1R>", 2),
536    ENCODING_MAP(kThumb2Stmia,         0xe8800000,
537                 kFmtBitBlt, 19, 16, kFmtBitBlt, 15, 0, kFmtUnused, -1, -1,
538                 kFmtUnused, -1, -1,
539                 IS_BINARY_OP | REG_DEF0_USE0 | REG_USE_LIST1 | IS_STORE,
540                 "stmia", "r!0d!!, <!1R>", 2),
541    ENCODING_MAP(kThumb2AddRRR,  0xeb100000, /* setflags encoding */
542                 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0,
543                 kFmtShift, -1, -1,
544                 IS_QUAD_OP | REG_DEF0_USE12 | SETS_CCODES,
545                 "adds", "r!0d, r!1d, r!2d!3H", 2),
546    ENCODING_MAP(kThumb2SubRRR,       0xebb00000, /* setflags enconding */
547                 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0,
548                 kFmtShift, -1, -1,
549                 IS_QUAD_OP | REG_DEF0_USE12 | SETS_CCODES,
550                 "subs", "r!0d, r!1d, r!2d!3H", 2),
551    ENCODING_MAP(kThumb2SbcRRR,       0xeb700000, /* setflags encoding */
552                 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0,
553                 kFmtShift, -1, -1,
554                 IS_QUAD_OP | REG_DEF0_USE12 | USES_CCODES | SETS_CCODES,
555                 "sbcs", "r!0d, r!1d, r!2d!3H", 2),
556    ENCODING_MAP(kThumb2CmpRR,       0xebb00f00,
557                 kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0, kFmtShift, -1, -1,
558                 kFmtUnused, -1, -1,
559                 IS_TERTIARY_OP | REG_USE01 | SETS_CCODES,
560                 "cmp", "r!0d, r!1d", 2),
561    ENCODING_MAP(kThumb2SubRRI12,       0xf2a00000,
562                 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtImm12, -1, -1,
563                 kFmtUnused, -1, -1,
564                 IS_TERTIARY_OP | REG_DEF0_USE1,/* Note: doesn't affect flags */
565                 "sub", "r!0d,r!1d,#!2d", 2),
566    ENCODING_MAP(kThumb2MvnImmShift,  0xf06f0000, /* no setflags encoding */
567                 kFmtBitBlt, 11, 8, kFmtModImm, -1, -1, kFmtUnused, -1, -1,
568                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0,
569                 "mvn", "r!0d, #!1n", 2),
570    ENCODING_MAP(kThumb2Sel,       0xfaa0f080,
571                 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0,
572                 kFmtUnused, -1, -1,
573                 IS_TERTIARY_OP | REG_DEF0_USE12 | USES_CCODES,
574                 "sel", "r!0d, r!1d, r!2d", 2),
575    ENCODING_MAP(kThumb2Ubfx,       0xf3c00000,
576                 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtLsb, -1, -1,
577                 kFmtBWidth, 4, 0, IS_QUAD_OP | REG_DEF0_USE1,
578                 "ubfx", "r!0d, r!1d, #!2d, #!3d", 2),
579    ENCODING_MAP(kThumb2Sbfx,       0xf3400000,
580                 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtLsb, -1, -1,
581                 kFmtBWidth, 4, 0, IS_QUAD_OP | REG_DEF0_USE1,
582                 "sbfx", "r!0d, r!1d, #!2d, #!3d", 2),
583    ENCODING_MAP(kThumb2LdrRRR,    0xf8500000,
584                 kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0,
585                 kFmtBitBlt, 5, 4, IS_QUAD_OP | REG_DEF0_USE12 | IS_LOAD,
586                 "ldr", "r!0d, [r!1d, r!2d, LSL #!3d]", 2),
587    ENCODING_MAP(kThumb2LdrhRRR,    0xf8300000,
588                 kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0,
589                 kFmtBitBlt, 5, 4, IS_QUAD_OP | REG_DEF0_USE12 | IS_LOAD,
590                 "ldrh", "r!0d, [r!1d, r!2d, LSL #!3d]", 2),
591    ENCODING_MAP(kThumb2LdrshRRR,    0xf9300000,
592                 kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0,
593                 kFmtBitBlt, 5, 4, IS_QUAD_OP | REG_DEF0_USE12 | IS_LOAD,
594                 "ldrsh", "r!0d, [r!1d, r!2d, LSL #!3d]", 2),
595    ENCODING_MAP(kThumb2LdrbRRR,    0xf8100000,
596                 kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0,
597                 kFmtBitBlt, 5, 4, IS_QUAD_OP | REG_DEF0_USE12 | IS_LOAD,
598                 "ldrb", "r!0d, [r!1d, r!2d, LSL #!3d]", 2),
599    ENCODING_MAP(kThumb2LdrsbRRR,    0xf9100000,
600                 kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0,
601                 kFmtBitBlt, 5, 4, IS_QUAD_OP | REG_DEF0_USE12 | IS_LOAD,
602                 "ldrsb", "r!0d, [r!1d, r!2d, LSL #!3d]", 2),
603    ENCODING_MAP(kThumb2StrRRR,    0xf8400000,
604                 kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0,
605                 kFmtBitBlt, 5, 4, IS_QUAD_OP | REG_USE012 | IS_STORE,
606                 "str", "r!0d, [r!1d, r!2d, LSL #!3d]", 2),
607    ENCODING_MAP(kThumb2StrhRRR,    0xf8200000,
608                 kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0,
609                 kFmtBitBlt, 5, 4, IS_QUAD_OP | REG_USE012 | IS_STORE,
610                 "strh", "r!0d, [r!1d, r!2d, LSL #!3d]", 2),
611    ENCODING_MAP(kThumb2StrbRRR,    0xf8000000,
612                 kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0,
613                 kFmtBitBlt, 5, 4, IS_QUAD_OP | REG_USE012 | IS_STORE,
614                 "strb", "r!0d, [r!1d, r!2d, LSL #!3d]", 2),
615    ENCODING_MAP(kThumb2LdrhRRI12,       0xf8b00000,
616                 kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 11, 0,
617                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1 | IS_LOAD,
618                 "ldrh", "r!0d, [r!1d, #!2d]", 2),
619    ENCODING_MAP(kThumb2LdrshRRI12,       0xf9b00000,
620                 kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 11, 0,
621                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1 | IS_LOAD,
622                 "ldrsh", "r!0d, [r!1d, #!2d]", 2),
623    ENCODING_MAP(kThumb2LdrbRRI12,       0xf8900000,
624                 kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 11, 0,
625                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1 | IS_LOAD,
626                 "ldrb", "r!0d, [r!1d, #!2d]", 2),
627    ENCODING_MAP(kThumb2LdrsbRRI12,       0xf9900000,
628                 kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 11, 0,
629                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1 | IS_LOAD,
630                 "ldrsb", "r!0d, [r!1d, #!2d]", 2),
631    ENCODING_MAP(kThumb2StrhRRI12,       0xf8a00000,
632                 kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 11, 0,
633                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE01 | IS_STORE,
634                 "strh", "r!0d, [r!1d, #!2d]", 2),
635    ENCODING_MAP(kThumb2StrbRRI12,       0xf8800000,
636                 kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 11, 0,
637                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE01 | IS_STORE,
638                 "strb", "r!0d, [r!1d, #!2d]", 2),
639    ENCODING_MAP(kThumb2Pop,           0xe8bd0000,
640                 kFmtBitBlt, 15, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
641                 kFmtUnused, -1, -1,
642                 IS_UNARY_OP | REG_DEF_SP | REG_USE_SP | REG_DEF_LIST0
643                 | IS_LOAD, "pop", "<!0R>", 2),
644    ENCODING_MAP(kThumb2Push,          0xe92d0000,
645                 kFmtBitBlt, 15, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
646                 kFmtUnused, -1, -1,
647                 IS_UNARY_OP | REG_DEF_SP | REG_USE_SP | REG_USE_LIST0
648                 | IS_STORE, "push", "<!0R>", 2),
649    ENCODING_MAP(kThumb2CmpRI8, 0xf1b00f00,
650                 kFmtBitBlt, 19, 16, kFmtModImm, -1, -1, kFmtUnused, -1, -1,
651                 kFmtUnused, -1, -1,
652                 IS_BINARY_OP | REG_USE0 | SETS_CCODES,
653                 "cmp", "r!0d, #!1m", 2),
654    ENCODING_MAP(kThumb2AdcRRR,  0xeb500000, /* setflags encoding */
655                 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0,
656                 kFmtShift, -1, -1,
657                 IS_QUAD_OP | REG_DEF0_USE12 | SETS_CCODES,
658                 "adcs", "r!0d, r!1d, r!2d!3H", 2),
659    ENCODING_MAP(kThumb2AndRRR,  0xea000000,
660                 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0,
661                 kFmtShift, -1, -1, IS_QUAD_OP | REG_DEF0_USE12,
662                 "and", "r!0d, r!1d, r!2d!3H", 2),
663    ENCODING_MAP(kThumb2BicRRR,  0xea200000,
664                 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0,
665                 kFmtShift, -1, -1, IS_QUAD_OP | REG_DEF0_USE12,
666                 "bic", "r!0d, r!1d, r!2d!3H", 2),
667    ENCODING_MAP(kThumb2CmnRR,  0xeb000000,
668                 kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0, kFmtShift, -1, -1,
669                 kFmtUnused, -1, -1,
670                 IS_TERTIARY_OP | REG_DEF0_USE1 | SETS_CCODES,
671                 "cmn", "r!0d, r!1d, shift !2d", 2),
672    ENCODING_MAP(kThumb2EorRRR,  0xea800000,
673                 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0,
674                 kFmtShift, -1, -1, IS_QUAD_OP | REG_DEF0_USE12,
675                 "eor", "r!0d, r!1d, r!2d!3H", 2),
676    ENCODING_MAP(kThumb2MulRRR,  0xfb00f000,
677                 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0,
678                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
679                 "mul", "r!0d, r!1d, r!2d", 2),
680    ENCODING_MAP(kThumb2MnvRR,  0xea6f0000,
681                 kFmtBitBlt, 11, 8, kFmtBitBlt, 3, 0, kFmtShift, -1, -1,
682                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
683                 "mvn", "r!0d, r!1d, shift !2d", 2),
684    ENCODING_MAP(kThumb2RsubRRI8,       0xf1d00000,
685                 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtModImm, -1, -1,
686                 kFmtUnused, -1, -1,
687                 IS_TERTIARY_OP | REG_DEF0_USE1 | SETS_CCODES,
688                 "rsb", "r!0d,r!1d,#!2m", 2),
689    ENCODING_MAP(kThumb2NegRR,       0xf1d00000, /* instance of rsub */
690                 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtUnused, -1, -1,
691                 kFmtUnused, -1, -1,
692                 IS_BINARY_OP | REG_DEF0_USE1 | SETS_CCODES,
693                 "neg", "r!0d,r!1d", 2),
694    ENCODING_MAP(kThumb2OrrRRR,  0xea400000,
695                 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0,
696                 kFmtShift, -1, -1, IS_QUAD_OP | REG_DEF0_USE12,
697                 "orr", "r!0d, r!1d, r!2d!3H", 2),
698    ENCODING_MAP(kThumb2TstRR,       0xea100f00,
699                 kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0, kFmtShift, -1, -1,
700                 kFmtUnused, -1, -1,
701                 IS_TERTIARY_OP | REG_USE01 | SETS_CCODES,
702                 "tst", "r!0d, r!1d, shift !2d", 2),
703    ENCODING_MAP(kThumb2LslRRR,  0xfa00f000,
704                 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0,
705                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
706                 "lsl", "r!0d, r!1d, r!2d", 2),
707    ENCODING_MAP(kThumb2LsrRRR,  0xfa20f000,
708                 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0,
709                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
710                 "lsr", "r!0d, r!1d, r!2d", 2),
711    ENCODING_MAP(kThumb2AsrRRR,  0xfa40f000,
712                 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0,
713                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
714                 "asr", "r!0d, r!1d, r!2d", 2),
715    ENCODING_MAP(kThumb2RorRRR,  0xfa60f000,
716                 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0,
717                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
718                 "ror", "r!0d, r!1d, r!2d", 2),
719    ENCODING_MAP(kThumb2LslRRI5,  0xea4f0000,
720                 kFmtBitBlt, 11, 8, kFmtBitBlt, 3, 0, kFmtShift5, -1, -1,
721                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
722                 "lsl", "r!0d, r!1d, #!2d", 2),
723    ENCODING_MAP(kThumb2LsrRRI5,  0xea4f0010,
724                 kFmtBitBlt, 11, 8, kFmtBitBlt, 3, 0, kFmtShift5, -1, -1,
725                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
726                 "lsr", "r!0d, r!1d, #!2d", 2),
727    ENCODING_MAP(kThumb2AsrRRI5,  0xea4f0020,
728                 kFmtBitBlt, 11, 8, kFmtBitBlt, 3, 0, kFmtShift5, -1, -1,
729                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
730                 "asr", "r!0d, r!1d, #!2d", 2),
731    ENCODING_MAP(kThumb2RorRRI5,  0xea4f0030,
732                 kFmtBitBlt, 11, 8, kFmtBitBlt, 3, 0, kFmtShift5, -1, -1,
733                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
734                 "ror", "r!0d, r!1d, #!2d", 2),
735    ENCODING_MAP(kThumb2BicRRI8,  0xf0200000,
736                 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtModImm, -1, -1,
737                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
738                 "bic", "r!0d, r!1d, #!2m", 2),
739    ENCODING_MAP(kThumb2AndRRI8,  0xf0000000,
740                 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtModImm, -1, -1,
741                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
742                 "and", "r!0d, r!1d, #!2m", 2),
743    ENCODING_MAP(kThumb2OrrRRI8,  0xf0400000,
744                 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtModImm, -1, -1,
745                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
746                 "orr", "r!0d, r!1d, #!2m", 2),
747    ENCODING_MAP(kThumb2EorRRI8,  0xf0800000,
748                 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtModImm, -1, -1,
749                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
750                 "eor", "r!0d, r!1d, #!2m", 2),
751    ENCODING_MAP(kThumb2AddRRI8,  0xf1100000,
752                 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtModImm, -1, -1,
753                 kFmtUnused, -1, -1,
754                 IS_TERTIARY_OP | REG_DEF0_USE1 | SETS_CCODES,
755                 "adds", "r!0d, r!1d, #!2m", 2),
756    ENCODING_MAP(kThumb2AdcRRI8,  0xf1500000,
757                 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtModImm, -1, -1,
758                 kFmtUnused, -1, -1,
759                 IS_TERTIARY_OP | REG_DEF0_USE1 | SETS_CCODES | USES_CCODES,
760                 "adcs", "r!0d, r!1d, #!2m", 2),
761    ENCODING_MAP(kThumb2SubRRI8,  0xf1b00000,
762                 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtModImm, -1, -1,
763                 kFmtUnused, -1, -1,
764                 IS_TERTIARY_OP | REG_DEF0_USE1 | SETS_CCODES,
765                 "subs", "r!0d, r!1d, #!2m", 2),
766    ENCODING_MAP(kThumb2SbcRRI8,  0xf1700000,
767                 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtModImm, -1, -1,
768                 kFmtUnused, -1, -1,
769                 IS_TERTIARY_OP | REG_DEF0_USE1 | SETS_CCODES | USES_CCODES,
770                 "sbcs", "r!0d, r!1d, #!2m", 2),
771    ENCODING_MAP(kThumb2It,  0xbf00,
772                 kFmtBitBlt, 7, 4, kFmtBitBlt, 3, 0, kFmtModImm, -1, -1,
773                 kFmtUnused, -1, -1, IS_BINARY_OP | IS_IT | USES_CCODES,
774                 "it:!1b", "!0c", 1),
775    ENCODING_MAP(kThumb2Fmstat,  0xeef1fa10,
776                 kFmtUnused, -1, -1, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
777                 kFmtUnused, -1, -1, NO_OPERAND | SETS_CCODES,
778                 "fmstat", "", 2),
779    ENCODING_MAP(kThumb2Vcmpd,        0xeeb40b40,
780                 kFmtDfp, 22, 12, kFmtDfp, 5, 0, kFmtUnused, -1, -1,
781                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_USE01,
782                 "vcmp.f64", "!0S, !1S", 2),
783    ENCODING_MAP(kThumb2Vcmps,        0xeeb40a40,
784                 kFmtSfp, 22, 12, kFmtSfp, 5, 0, kFmtUnused, -1, -1,
785                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_USE01,
786                 "vcmp.f32", "!0s, !1s", 2),
787    ENCODING_MAP(kThumb2LdrPcRel12,       0xf8df0000,
788                 kFmtBitBlt, 15, 12, kFmtBitBlt, 11, 0, kFmtUnused, -1, -1,
789                 kFmtUnused, -1, -1,
790                 IS_TERTIARY_OP | REG_DEF0 | REG_USE_PC | IS_LOAD,
791                 "ldr", "r!0d, [r15pc, #!1d]", 2),
792    ENCODING_MAP(kThumb2BCond,        0xf0008000,
793                 kFmtBrOffset, -1, -1, kFmtBitBlt, 25, 22, kFmtUnused, -1, -1,
794                 kFmtUnused, -1, -1,
795                 IS_BINARY_OP | IS_BRANCH | USES_CCODES,
796                 "b!1c", "!0t", 2),
797    ENCODING_MAP(kThumb2Vmovd_RR,       0xeeb00b40,
798                 kFmtDfp, 22, 12, kFmtDfp, 5, 0, kFmtUnused, -1, -1,
799                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
800                 "vmov.f64", "!0S, !1S", 2),
801    ENCODING_MAP(kThumb2Vmovs_RR,       0xeeb00a40,
802                 kFmtSfp, 22, 12, kFmtSfp, 5, 0, kFmtUnused, -1, -1,
803                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
804                 "vmov.f32", "!0s, !1s", 2),
805    ENCODING_MAP(kThumb2Fmrs,       0xee100a10,
806                 kFmtBitBlt, 15, 12, kFmtSfp, 7, 16, kFmtUnused, -1, -1,
807                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
808                 "fmrs", "r!0d, !1s", 2),
809    ENCODING_MAP(kThumb2Fmsr,       0xee000a10,
810                 kFmtSfp, 7, 16, kFmtBitBlt, 15, 12, kFmtUnused, -1, -1,
811                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
812                 "fmsr", "!0s, r!1d", 2),
813    ENCODING_MAP(kThumb2Fmrrd,       0xec500b10,
814                 kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtDfp, 5, 0,
815                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF01_USE2,
816                 "fmrrd", "r!0d, r!1d, !2S", 2),
817    ENCODING_MAP(kThumb2Fmdrr,       0xec400b10,
818                 kFmtDfp, 5, 0, kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16,
819                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
820                 "fmdrr", "!0S, r!1d, r!2d", 2),
821    ENCODING_MAP(kThumb2Vabsd,       0xeeb00bc0,
822                 kFmtDfp, 22, 12, kFmtDfp, 5, 0, kFmtUnused, -1, -1,
823                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
824                 "vabs.f64", "!0S, !1S", 2),
825    ENCODING_MAP(kThumb2Vabss,       0xeeb00ac0,
826                 kFmtSfp, 22, 12, kFmtSfp, 5, 0, kFmtUnused, -1, -1,
827                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
828                 "vabs.f32", "!0s, !1s", 2),
829    ENCODING_MAP(kThumb2Vnegd,       0xeeb10b40,
830                 kFmtDfp, 22, 12, kFmtDfp, 5, 0, kFmtUnused, -1, -1,
831                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
832                 "vneg.f64", "!0S, !1S", 2),
833    ENCODING_MAP(kThumb2Vnegs,       0xeeb10a40,
834                 kFmtSfp, 22, 12, kFmtSfp, 5, 0, kFmtUnused, -1, -1,
835                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
836                 "vneg.f32", "!0s, !1s", 2),
837    ENCODING_MAP(kThumb2Vmovs_IMM8,       0xeeb00a00,
838                 kFmtSfp, 22, 12, kFmtFPImm, 16, 0, kFmtUnused, -1, -1,
839                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0,
840                 "vmov.f32", "!0s, #0x!1h", 2),
841    ENCODING_MAP(kThumb2Vmovd_IMM8,       0xeeb00b00,
842                 kFmtDfp, 22, 12, kFmtFPImm, 16, 0, kFmtUnused, -1, -1,
843                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0,
844                 "vmov.f64", "!0S, #0x!1h", 2),
845    ENCODING_MAP(kThumb2Mla,  0xfb000000,
846                 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0,
847                 kFmtBitBlt, 15, 12,
848                 IS_QUAD_OP | REG_DEF0 | REG_USE1 | REG_USE2 | REG_USE3,
849                 "mla", "r!0d, r!1d, r!2d, r!3d", 2),
850    ENCODING_MAP(kThumb2Umull,  0xfba00000,
851                 kFmtBitBlt, 15, 12, kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16,
852                 kFmtBitBlt, 3, 0,
853                 IS_QUAD_OP | REG_DEF0 | REG_DEF1 | REG_USE2 | REG_USE3,
854                 "umull", "r!0d, r!1d, r!2d, r!3d", 2),
855    ENCODING_MAP(kThumb2Ldrex,       0xe8500f00,
856                 kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 7, 0,
857                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1 | IS_LOAD,
858                 "ldrex", "r!0d, [r!1d, #!2E]", 2),
859    ENCODING_MAP(kThumb2Strex,       0xe8400000,
860                 kFmtBitBlt, 11, 8, kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16,
861                 kFmtBitBlt, 7, 0, IS_QUAD_OP | REG_DEF0_USE12 | IS_STORE,
862                 "strex", "r!0d,r!1d, [r!2d, #!2E]", 2),
863    ENCODING_MAP(kThumb2Clrex,       0xf3bf8f2f,
864                 kFmtUnused, -1, -1, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
865                 kFmtUnused, -1, -1, NO_OPERAND,
866                 "clrex", "", 2),
867    ENCODING_MAP(kThumb2Bfi,         0xf3600000,
868                 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtShift5, -1, -1,
869                 kFmtBitBlt, 4, 0, IS_QUAD_OP | REG_DEF0_USE1,
870                 "bfi", "r!0d,r!1d,#!2d,#!3d", 2),
871    ENCODING_MAP(kThumb2Bfc,         0xf36f0000,
872                 kFmtBitBlt, 11, 8, kFmtShift5, -1, -1, kFmtBitBlt, 4, 0,
873                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0,
874                 "bfc", "r!0d,#!1d,#!2d", 2),
875    ENCODING_MAP(kThumb2Dmb,         0xf3bf8f50,
876                 kFmtBitBlt, 3, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
877                 kFmtUnused, -1, -1, IS_UNARY_OP,
878                 "dmb","#!0B",2),
879    ENCODING_MAP(kThumb2LdrPcReln12,       0xf85f0000,
880                 kFmtBitBlt, 15, 12, kFmtBitBlt, 11, 0, kFmtUnused, -1, -1,
881                 kFmtUnused, -1, -1,
882                 IS_BINARY_OP | REG_DEF0 | REG_USE_PC | IS_LOAD,
883                 "ldr", "r!0d, [r15pc, -#!1d]", 2),
884    ENCODING_MAP(kThumb2RsbRRR,  0xebd00000, /* setflags encoding */
885                 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0,
886                 kFmtShift, -1, -1,
887                 IS_QUAD_OP | REG_DEF0_USE12 | SETS_CCODES,
888                 "rsb", "r!0d, r!1d, r!2d!3H", 2),
889    ENCODING_MAP(kThumbUndefined,       0xde00,
890                 kFmtUnused, -1, -1, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
891                 kFmtUnused, -1, -1, NO_OPERAND,
892                 "undefined", "", 1),
893};
894
895/*
896 * The fake NOP of moving r0 to r0 actually will incur data stalls if r0 is
897 * not ready. Since r5FP is not updated often, it is less likely to
898 * generate unnecessary stall cycles.
899 */
900#define PADDING_MOV_R5_R5               0x1C2D
901
902/* Track the number of times that the code cache is patched */
903#if defined(WITH_JIT_TUNING)
904#define UPDATE_CODE_CACHE_PATCHES()    (gDvmJit.codeCachePatches++)
905#else
906#define UPDATE_CODE_CACHE_PATCHES()
907#endif
908
909/* Write the numbers in the constant and class pool to the output stream */
910static void installLiteralPools(CompilationUnit *cUnit)
911{
912    int *dataPtr = (int *) ((char *) cUnit->baseAddr + cUnit->dataOffset);
913    /* Install number of class pointer literals */
914    *dataPtr++ = cUnit->numClassPointers;
915    ArmLIR *dataLIR = (ArmLIR *) cUnit->classPointerList;
916    while (dataLIR) {
917        /*
918         * Install the callsiteinfo pointers into the cells for now. They will
919         * be converted into real pointers in dvmJitInstallClassObjectPointers.
920         */
921        *dataPtr++ = dataLIR->operands[0];
922        dataLIR = NEXT_LIR(dataLIR);
923    }
924    dataLIR = (ArmLIR *) cUnit->literalList;
925    while (dataLIR) {
926        *dataPtr++ = dataLIR->operands[0];
927        dataLIR = NEXT_LIR(dataLIR);
928    }
929}
930
931/*
932 * Assemble the LIR into binary instruction format.  Note that we may
933 * discover that pc-relative displacements may not fit the selected
934 * instruction.  In those cases we will try to substitute a new code
935 * sequence or request that the trace be shortened and retried.
936 */
937static AssemblerStatus assembleInstructions(CompilationUnit *cUnit,
938                                            intptr_t startAddr)
939{
940    short *bufferAddr = (short *) cUnit->codeBuffer;
941    ArmLIR *lir;
942
943    for (lir = (ArmLIR *) cUnit->firstLIRInsn; lir; lir = NEXT_LIR(lir)) {
944        if (lir->opcode < 0) {
945            if ((lir->opcode == kArmPseudoPseudoAlign4) &&
946                /* 1 means padding is needed */
947                (lir->operands[0] == 1)) {
948                *bufferAddr++ = PADDING_MOV_R5_R5;
949            }
950            continue;
951        }
952
953        if (lir->flags.isNop) {
954            continue;
955        }
956
957        if (lir->opcode == kThumbLdrPcRel ||
958            lir->opcode == kThumb2LdrPcRel12 ||
959            lir->opcode == kThumbAddPcRel ||
960            ((lir->opcode == kThumb2Vldrd) && (lir->operands[1] == r15pc)) ||
961            ((lir->opcode == kThumb2Vldrs) && (lir->operands[1] == r15pc))) {
962            ArmLIR *lirTarget = (ArmLIR *) lir->generic.target;
963            intptr_t pc = (lir->generic.offset + 4) & ~3;
964            intptr_t target = lirTarget->generic.offset;
965            int delta = target - pc;
966            if (delta & 0x3) {
967                ALOGE("PC-rel distance is not multiples of 4: %d", delta);
968                dvmCompilerAbort(cUnit);
969            }
970            if ((lir->opcode == kThumb2LdrPcRel12) && (delta > 4091)) {
971                if (cUnit->printMe) {
972                    ALOGD("kThumb2LdrPcRel12@%x: delta=%d", lir->generic.offset,
973                         delta);
974                    dvmCompilerCodegenDump(cUnit);
975                }
976                return kRetryHalve;
977            } else if (delta > 1020) {
978                if (cUnit->printMe) {
979                    ALOGD("kThumbLdrPcRel@%x: delta=%d", lir->generic.offset,
980                         delta);
981                    dvmCompilerCodegenDump(cUnit);
982                }
983                return kRetryHalve;
984            }
985            if ((lir->opcode == kThumb2Vldrs) || (lir->opcode == kThumb2Vldrd)) {
986                lir->operands[2] = delta >> 2;
987            } else {
988                lir->operands[1] = (lir->opcode == kThumb2LdrPcRel12) ?
989                                    delta : delta >> 2;
990            }
991        } else if (lir->opcode == kThumb2Cbnz || lir->opcode == kThumb2Cbz) {
992            ArmLIR *targetLIR = (ArmLIR *) lir->generic.target;
993            intptr_t pc = lir->generic.offset + 4;
994            intptr_t target = targetLIR->generic.offset;
995            int delta = target - pc;
996            if (delta > 126 || delta < 0) {
997                /* Convert to cmp rx,#0 / b[eq/ne] tgt pair */
998                ArmLIR *newInst =
999                    (ArmLIR *)dvmCompilerNew(sizeof(ArmLIR), true);
1000                /* Make new branch instruction and insert after */
1001                newInst->opcode = kThumbBCond;
1002                newInst->operands[0] = 0;
1003                newInst->operands[1] = (lir->opcode == kThumb2Cbz) ?
1004                                        kArmCondEq : kArmCondNe;
1005                newInst->generic.target = lir->generic.target;
1006                dvmCompilerSetupResourceMasks(newInst);
1007                dvmCompilerInsertLIRAfter((LIR *)lir, (LIR *)newInst);
1008                /* Convert the cb[n]z to a cmp rx, #0 ] */
1009                lir->opcode = kThumbCmpRI8;
1010                /* operand[0] is src1 in both cb[n]z & CmpRI8 */
1011                lir->operands[1] = 0;
1012                lir->generic.target = 0;
1013                dvmCompilerSetupResourceMasks(lir);
1014                if (cUnit->printMe) {
1015                    ALOGD("kThumb2Cbnz/kThumb2Cbz@%x: delta=%d",
1016                         lir->generic.offset, delta);
1017                    dvmCompilerCodegenDump(cUnit);
1018                }
1019                return kRetryAll;
1020            } else {
1021                lir->operands[1] = delta >> 1;
1022            }
1023        } else if (lir->opcode == kThumbBCond ||
1024                   lir->opcode == kThumb2BCond) {
1025            ArmLIR *targetLIR = (ArmLIR *) lir->generic.target;
1026            intptr_t pc = lir->generic.offset + 4;
1027            intptr_t target = targetLIR->generic.offset;
1028            int delta = target - pc;
1029            if ((lir->opcode == kThumbBCond) && (delta > 254 || delta < -256)) {
1030                if (cUnit->printMe) {
1031                    ALOGD("kThumbBCond@%x: delta=%d", lir->generic.offset,
1032                         delta);
1033                    dvmCompilerCodegenDump(cUnit);
1034                }
1035                return kRetryHalve;
1036            }
1037            lir->operands[0] = delta >> 1;
1038        } else if (lir->opcode == kThumbBUncond) {
1039            ArmLIR *targetLIR = (ArmLIR *) lir->generic.target;
1040            intptr_t pc = lir->generic.offset + 4;
1041            intptr_t target = targetLIR->generic.offset;
1042            int delta = target - pc;
1043            if (delta > 2046 || delta < -2048) {
1044                ALOGE("Unconditional branch distance out of range: %d", delta);
1045                dvmCompilerAbort(cUnit);
1046            }
1047            lir->operands[0] = delta >> 1;
1048        } else if (lir->opcode == kThumbBlx1) {
1049            assert(NEXT_LIR(lir)->opcode == kThumbBlx2);
1050            /* curPC is Thumb */
1051            intptr_t curPC = (startAddr + lir->generic.offset + 4) & ~3;
1052            intptr_t target = lir->operands[1];
1053
1054            /* Match bit[1] in target with base */
1055            if (curPC & 0x2) {
1056                target |= 0x2;
1057            }
1058            int delta = target - curPC;
1059            assert((delta >= -(1<<22)) && (delta <= ((1<<22)-2)));
1060
1061            lir->operands[0] = (delta >> 12) & 0x7ff;
1062            NEXT_LIR(lir)->operands[0] = (delta>> 1) & 0x7ff;
1063        } else if (lir->opcode == kThumbBl1) {
1064            assert(NEXT_LIR(lir)->opcode == kThumbBl2);
1065            /* Both curPC and target are Thumb */
1066            intptr_t curPC = startAddr + lir->generic.offset + 4;
1067            intptr_t target = lir->operands[1];
1068
1069            int delta = target - curPC;
1070            assert((delta >= -(1<<22)) && (delta <= ((1<<22)-2)));
1071
1072            lir->operands[0] = (delta >> 12) & 0x7ff;
1073            NEXT_LIR(lir)->operands[0] = (delta>> 1) & 0x7ff;
1074        }
1075
1076        ArmEncodingMap *encoder = &EncodingMap[lir->opcode];
1077        u4 bits = encoder->skeleton;
1078        int i;
1079        for (i = 0; i < 4; i++) {
1080            u4 operand;
1081            u4 value;
1082            operand = lir->operands[i];
1083            switch(encoder->fieldLoc[i].kind) {
1084                case kFmtUnused:
1085                    break;
1086                case kFmtFPImm:
1087                    value = ((operand & 0xF0) >> 4) << encoder->fieldLoc[i].end;
1088                    value |= (operand & 0x0F) << encoder->fieldLoc[i].start;
1089                    bits |= value;
1090                    break;
1091                case kFmtBrOffset:
1092                    value = ((operand  & 0x80000) >> 19) << 26;
1093                    value |= ((operand & 0x40000) >> 18) << 11;
1094                    value |= ((operand & 0x20000) >> 17) << 13;
1095                    value |= ((operand & 0x1f800) >> 11) << 16;
1096                    value |= (operand  & 0x007ff);
1097                    bits |= value;
1098                    break;
1099                case kFmtShift5:
1100                    value = ((operand & 0x1c) >> 2) << 12;
1101                    value |= (operand & 0x03) << 6;
1102                    bits |= value;
1103                    break;
1104                case kFmtShift:
1105                    value = ((operand & 0x70) >> 4) << 12;
1106                    value |= (operand & 0x0f) << 4;
1107                    bits |= value;
1108                    break;
1109                case kFmtBWidth:
1110                    value = operand - 1;
1111                    bits |= value;
1112                    break;
1113                case kFmtLsb:
1114                    value = ((operand & 0x1c) >> 2) << 12;
1115                    value |= (operand & 0x03) << 6;
1116                    bits |= value;
1117                    break;
1118                case kFmtImm6:
1119                    value = ((operand & 0x20) >> 5) << 9;
1120                    value |= (operand & 0x1f) << 3;
1121                    bits |= value;
1122                    break;
1123                case kFmtBitBlt:
1124                    value = (operand << encoder->fieldLoc[i].start) &
1125                            ((1 << (encoder->fieldLoc[i].end + 1)) - 1);
1126                    bits |= value;
1127                    break;
1128                case kFmtDfp: {
1129                    assert(DOUBLEREG(operand));
1130                    assert((operand & 0x1) == 0);
1131                    int regName = (operand & FP_REG_MASK) >> 1;
1132                    /* Snag the 1-bit slice and position it */
1133                    value = ((regName & 0x10) >> 4) <<
1134                            encoder->fieldLoc[i].end;
1135                    /* Extract and position the 4-bit slice */
1136                    value |= (regName & 0x0f) <<
1137                            encoder->fieldLoc[i].start;
1138                    bits |= value;
1139                    break;
1140                }
1141                case kFmtSfp:
1142                    assert(SINGLEREG(operand));
1143                    /* Snag the 1-bit slice and position it */
1144                    value = (operand & 0x1) <<
1145                            encoder->fieldLoc[i].end;
1146                    /* Extract and position the 4-bit slice */
1147                    value |= ((operand & 0x1e) >> 1) <<
1148                            encoder->fieldLoc[i].start;
1149                    bits |= value;
1150                    break;
1151                case kFmtImm12:
1152                case kFmtModImm:
1153                    value = ((operand & 0x800) >> 11) << 26;
1154                    value |= ((operand & 0x700) >> 8) << 12;
1155                    value |= operand & 0x0ff;
1156                    bits |= value;
1157                    break;
1158                case kFmtImm16:
1159                    value = ((operand & 0x0800) >> 11) << 26;
1160                    value |= ((operand & 0xf000) >> 12) << 16;
1161                    value |= ((operand & 0x0700) >> 8) << 12;
1162                    value |= operand & 0x0ff;
1163                    bits |= value;
1164                    break;
1165                default:
1166                    assert(0);
1167            }
1168        }
1169        if (encoder->size == 2) {
1170            *bufferAddr++ = (bits >> 16) & 0xffff;
1171        }
1172        *bufferAddr++ = bits & 0xffff;
1173    }
1174    return kSuccess;
1175}
1176
1177static int assignLiteralOffsetCommon(LIR *lir, int offset)
1178{
1179    for (;lir != NULL; lir = lir->next) {
1180        lir->offset = offset;
1181        offset += 4;
1182    }
1183    return offset;
1184}
1185
1186/* Determine the offset of each literal field */
1187static int assignLiteralOffset(CompilationUnit *cUnit, int offset)
1188{
1189    /* Reserved for the size field of class pointer pool */
1190    offset += 4;
1191    offset = assignLiteralOffsetCommon(cUnit->classPointerList, offset);
1192    offset = assignLiteralOffsetCommon(cUnit->literalList, offset);
1193    return offset;
1194}
1195
1196/*
1197 * Translation layout in the code cache.  Note that the codeAddress pointer
1198 * in JitTable will point directly to the code body (field codeAddress).  The
1199 * chain cell offset codeAddress - 2, and the address of the trace profile
1200 * counter is at codeAddress - 6.
1201 *
1202 *      +----------------------------+
1203 *      | Trace Profile Counter addr |  -> 4 bytes (PROF_COUNTER_ADDR_SIZE)
1204 *      +----------------------------+
1205 *   +--| Offset to chain cell counts|  -> 2 bytes (CHAIN_CELL_OFFSET_SIZE)
1206 *   |  +----------------------------+
1207 *   |  | Trace profile code         |  <- entry point when profiling
1208 *   |  .  -   -   -   -   -   -   - .
1209 *   |  | Code body                  |  <- entry point when not profiling
1210 *   |  .                            .
1211 *   |  |                            |
1212 *   |  +----------------------------+
1213 *   |  | Chaining Cells             |  -> 12/16 bytes, 4 byte aligned
1214 *   |  .                            .
1215 *   |  .                            .
1216 *   |  |                            |
1217 *   |  +----------------------------+
1218 *   |  | Gap for large switch stmt  |  -> # cases >= MAX_CHAINED_SWITCH_CASES
1219 *   |  +----------------------------+
1220 *   +->| Chaining cell counts       |  -> 8 bytes, chain cell counts by type
1221 *      +----------------------------+
1222 *      | Trace description          |  -> variable sized
1223 *      .                            .
1224 *      |                            |
1225 *      +----------------------------+
1226 *      | # Class pointer pool size  |  -> 4 bytes
1227 *      +----------------------------+
1228 *      | Class pointer pool         |  -> 4-byte aligned, variable size
1229 *      .                            .
1230 *      .                            .
1231 *      |                            |
1232 *      +----------------------------+
1233 *      | Literal pool               |  -> 4-byte aligned, variable size
1234 *      .                            .
1235 *      .                            .
1236 *      |                            |
1237 *      +----------------------------+
1238 *
1239 */
1240
1241#define PROF_COUNTER_ADDR_SIZE 4
1242#define CHAIN_CELL_OFFSET_SIZE 2
1243
1244/*
1245 * Utility functions to navigate various parts in a trace. If we change the
1246 * layout/offset in the future, we just modify these functions and we don't need
1247 * to propagate the changes to all the use cases.
1248 */
1249static inline char *getTraceBase(const JitEntry *p)
1250{
1251    return (char*)p->codeAddress -
1252        (PROF_COUNTER_ADDR_SIZE + CHAIN_CELL_OFFSET_SIZE +
1253         (p->u.info.instructionSet == DALVIK_JIT_ARM ? 0 : 1));
1254}
1255
1256/* Handy function to retrieve the profile count */
1257static inline JitTraceCounter_t getProfileCount(const JitEntry *entry)
1258{
1259    if (entry->dPC == 0 || entry->codeAddress == 0 ||
1260        entry->codeAddress == dvmCompilerGetInterpretTemplate())
1261        return 0;
1262
1263    JitTraceCounter_t **p = (JitTraceCounter_t **) getTraceBase(entry);
1264
1265    return **p;
1266}
1267
1268/* Handy function to reset the profile count */
1269static inline void resetProfileCount(const JitEntry *entry)
1270{
1271    if (entry->dPC == 0 || entry->codeAddress == 0 ||
1272        entry->codeAddress == dvmCompilerGetInterpretTemplate())
1273        return;
1274
1275    JitTraceCounter_t **p = (JitTraceCounter_t **) getTraceBase(entry);
1276
1277    **p = 0;
1278}
1279
1280/* Get the pointer of the chain cell count */
1281static inline ChainCellCounts* getChainCellCountsPointer(const char *base)
1282{
1283    /* 4 is the size of the profile count */
1284    u2 *chainCellOffsetP = (u2 *) (base + PROF_COUNTER_ADDR_SIZE);
1285    u2 chainCellOffset = *chainCellOffsetP;
1286    return (ChainCellCounts *) ((char *) chainCellOffsetP + chainCellOffset);
1287}
1288
1289/* Get the size of all chaining cells */
1290static inline u4 getChainCellSize(const ChainCellCounts* pChainCellCounts)
1291{
1292    int cellSize = 0;
1293    int i;
1294
1295    /* Get total count of chain cells */
1296    for (i = 0; i < kChainingCellGap; i++) {
1297        if (i != kChainingCellInvokePredicted) {
1298            cellSize += pChainCellCounts->u.count[i] *
1299                        (CHAIN_CELL_NORMAL_SIZE >> 2);
1300        } else {
1301            cellSize += pChainCellCounts->u.count[i] *
1302                (CHAIN_CELL_PREDICTED_SIZE >> 2);
1303        }
1304    }
1305    return cellSize;
1306}
1307
1308/* Get the starting pointer of the trace description section */
1309static JitTraceDescription* getTraceDescriptionPointer(const char *base)
1310{
1311    ChainCellCounts* pCellCounts = getChainCellCountsPointer(base);
1312    return (JitTraceDescription*) ((char*)pCellCounts + sizeof(*pCellCounts));
1313}
1314
1315/* Get the size of a trace description */
1316static int getTraceDescriptionSize(const JitTraceDescription *desc)
1317{
1318    int runCount;
1319    /* Trace end is always of non-meta type (ie isCode == true) */
1320    for (runCount = 0; ; runCount++) {
1321        if (desc->trace[runCount].isCode &&
1322            desc->trace[runCount].info.frag.runEnd)
1323           break;
1324    }
1325    return sizeof(JitTraceDescription) + ((runCount+1) * sizeof(JitTraceRun));
1326}
1327
1328#if defined(SIGNATURE_BREAKPOINT)
1329/* Inspect the assembled instruction stream to find potential matches */
1330static void matchSignatureBreakpoint(const CompilationUnit *cUnit,
1331                                     unsigned int size)
1332{
1333    unsigned int i, j;
1334    u4 *ptr = (u4 *) cUnit->codeBuffer;
1335
1336    for (i = 0; i < size - gDvmJit.signatureBreakpointSize + 1; i++) {
1337        if (ptr[i] == gDvmJit.signatureBreakpoint[0]) {
1338            for (j = 1; j < gDvmJit.signatureBreakpointSize; j++) {
1339                if (ptr[i+j] != gDvmJit.signatureBreakpoint[j]) {
1340                    break;
1341                }
1342            }
1343            if (j == gDvmJit.signatureBreakpointSize) {
1344                ALOGD("Signature match starting from offset %#x (%d words)",
1345                     i*4, gDvmJit.signatureBreakpointSize);
1346                int descSize = getTraceDescriptionSize(cUnit->traceDesc);
1347                JitTraceDescription *newCopy =
1348                    (JitTraceDescription *) malloc(descSize);
1349                memcpy(newCopy, cUnit->traceDesc, descSize);
1350                dvmCompilerWorkEnqueue(NULL, kWorkOrderTraceDebug, newCopy);
1351                break;
1352            }
1353        }
1354    }
1355}
1356#endif
1357
1358/*
1359 * Go over each instruction in the list and calculate the offset from the top
1360 * before sending them off to the assembler. If out-of-range branch distance is
1361 * seen rearrange the instructions a bit to correct it.
1362 */
1363void dvmCompilerAssembleLIR(CompilationUnit *cUnit, JitTranslationInfo *info)
1364{
1365    ArmLIR *armLIR;
1366    int offset = 0;
1367    int i;
1368    ChainCellCounts chainCellCounts;
1369    int descSize = (cUnit->jitMode == kJitMethod) ?
1370        0 : getTraceDescriptionSize(cUnit->traceDesc);
1371    int chainingCellGap = 0;
1372
1373    info->instructionSet = cUnit->instructionSet;
1374
1375    /* Beginning offset needs to allow space for chain cell offset */
1376    for (armLIR = (ArmLIR *) cUnit->firstLIRInsn;
1377         armLIR;
1378         armLIR = NEXT_LIR(armLIR)) {
1379        armLIR->generic.offset = offset;
1380        if (armLIR->opcode >= 0 && !armLIR->flags.isNop) {
1381            armLIR->flags.size = EncodingMap[armLIR->opcode].size * 2;
1382            offset += armLIR->flags.size;
1383        } else if (armLIR->opcode == kArmPseudoPseudoAlign4) {
1384            if (offset & 0x2) {
1385                offset += 2;
1386                armLIR->operands[0] = 1;
1387            } else {
1388                armLIR->operands[0] = 0;
1389            }
1390        }
1391        /* Pseudo opcodes don't consume space */
1392    }
1393
1394    /* Const values have to be word aligned */
1395    offset = (offset + 3) & ~3;
1396
1397    u4 chainCellOffset = offset;
1398    ArmLIR *chainCellOffsetLIR = NULL;
1399
1400    if (cUnit->jitMode != kJitMethod) {
1401        /*
1402         * Get the gap (# of u4) between the offset of chaining cell count and
1403         * the bottom of real chaining cells. If the translation has chaining
1404         * cells, the gap is guaranteed to be multiples of 4.
1405         */
1406        chainingCellGap = (offset - cUnit->chainingCellBottom->offset) >> 2;
1407
1408        /* Add space for chain cell counts & trace description */
1409        chainCellOffsetLIR = (ArmLIR *) cUnit->chainCellOffsetLIR;
1410        assert(chainCellOffsetLIR);
1411        assert(chainCellOffset < 0x10000);
1412        assert(chainCellOffsetLIR->opcode == kArm16BitData &&
1413               chainCellOffsetLIR->operands[0] == CHAIN_CELL_OFFSET_TAG);
1414
1415        /*
1416         * Adjust the CHAIN_CELL_OFFSET_TAG LIR's offset to remove the
1417         * space occupied by the pointer to the trace profiling counter.
1418         */
1419        chainCellOffsetLIR->operands[0] = chainCellOffset - 4;
1420
1421        offset += sizeof(chainCellCounts) + descSize;
1422
1423        assert((offset & 0x3) == 0);  /* Should still be word aligned */
1424    }
1425
1426    /* Set up offsets for literals */
1427    cUnit->dataOffset = offset;
1428
1429    /*
1430     * Assign each class pointer/constant an offset from the beginning of the
1431     * compilation unit.
1432     */
1433    offset = assignLiteralOffset(cUnit, offset);
1434
1435    cUnit->totalSize = offset;
1436
1437    if (gDvmJit.codeCacheByteUsed + cUnit->totalSize > gDvmJit.codeCacheSize) {
1438        gDvmJit.codeCacheFull = true;
1439        info->discardResult = true;
1440        return;
1441    }
1442
1443    /* Allocate enough space for the code block */
1444    cUnit->codeBuffer = (unsigned char *)dvmCompilerNew(chainCellOffset, true);
1445    if (cUnit->codeBuffer == NULL) {
1446        ALOGE("Code buffer allocation failure");
1447        info->discardResult = true;
1448        return;
1449    }
1450
1451    /*
1452     * Attempt to assemble the trace.  Note that assembleInstructions
1453     * may rewrite the code sequence and request a retry.
1454     */
1455    cUnit->assemblerStatus = assembleInstructions(cUnit,
1456          (intptr_t) gDvmJit.codeCache + gDvmJit.codeCacheByteUsed);
1457
1458    switch(cUnit->assemblerStatus) {
1459        case kSuccess:
1460            break;
1461        case kRetryAll:
1462            if (cUnit->assemblerRetries < MAX_ASSEMBLER_RETRIES) {
1463                if (cUnit->jitMode != kJitMethod) {
1464                    /* Restore pristine chain cell marker on retry */
1465                    chainCellOffsetLIR->operands[0] = CHAIN_CELL_OFFSET_TAG;
1466                }
1467                return;
1468            }
1469            /* Too many retries - reset and try cutting the trace in half */
1470            cUnit->assemblerRetries = 0;
1471            cUnit->assemblerStatus = kRetryHalve;
1472            return;
1473        case kRetryHalve:
1474            return;
1475        default:
1476             ALOGE("Unexpected assembler status: %d", cUnit->assemblerStatus);
1477             dvmAbort();
1478    }
1479
1480#if defined(SIGNATURE_BREAKPOINT)
1481    if (info->discardResult == false && gDvmJit.signatureBreakpoint != NULL &&
1482        chainCellOffset/4 >= gDvmJit.signatureBreakpointSize) {
1483        matchSignatureBreakpoint(cUnit, chainCellOffset/4);
1484    }
1485#endif
1486
1487    /* Don't go all the way if the goal is just to get the verbose output */
1488    if (info->discardResult) return;
1489
1490    /*
1491     * The cache might disappear - acquire lock and check version
1492     * Continue holding lock until translation cache update is complete.
1493     * These actions are required here in the compiler thread because
1494     * it is unaffected by suspend requests and doesn't know if a
1495     * translation cache flush is in progress.
1496     */
1497    dvmLockMutex(&gDvmJit.compilerLock);
1498    if (info->cacheVersion != gDvmJit.cacheVersion) {
1499        /* Cache changed - discard current translation */
1500        info->discardResult = true;
1501        info->codeAddress = NULL;
1502        dvmUnlockMutex(&gDvmJit.compilerLock);
1503        return;
1504    }
1505
1506    cUnit->baseAddr = (char *) gDvmJit.codeCache + gDvmJit.codeCacheByteUsed;
1507    gDvmJit.codeCacheByteUsed += offset;
1508
1509    UNPROTECT_CODE_CACHE(cUnit->baseAddr, offset);
1510
1511    /* Install the code block */
1512    memcpy((char*)cUnit->baseAddr, cUnit->codeBuffer, chainCellOffset);
1513    gDvmJit.numCompilations++;
1514
1515    if (cUnit->jitMode != kJitMethod) {
1516        /* Install the chaining cell counts */
1517        for (i=0; i< kChainingCellGap; i++) {
1518            chainCellCounts.u.count[i] = cUnit->numChainingCells[i];
1519        }
1520
1521        /* Set the gap number in the chaining cell count structure */
1522        chainCellCounts.u.count[kChainingCellGap] = chainingCellGap;
1523
1524        memcpy((char*)cUnit->baseAddr + chainCellOffset, &chainCellCounts,
1525               sizeof(chainCellCounts));
1526
1527        /* Install the trace description */
1528        memcpy((char*) cUnit->baseAddr + chainCellOffset +
1529                       sizeof(chainCellCounts),
1530               cUnit->traceDesc, descSize);
1531    }
1532
1533    /* Write the literals directly into the code cache */
1534    installLiteralPools(cUnit);
1535
1536    /* Flush dcache and invalidate the icache to maintain coherence */
1537    dvmCompilerCacheFlush((long)cUnit->baseAddr,
1538                          (long)((char *) cUnit->baseAddr + offset), 0);
1539    UPDATE_CODE_CACHE_PATCHES();
1540
1541    PROTECT_CODE_CACHE(cUnit->baseAddr, offset);
1542
1543    /* Translation cache update complete - release lock */
1544    dvmUnlockMutex(&gDvmJit.compilerLock);
1545
1546    /* Record code entry point and instruction set */
1547    info->codeAddress = (char*)cUnit->baseAddr + cUnit->headerSize;
1548    /* If applicable, mark low bit to denote thumb */
1549    if (info->instructionSet != DALVIK_JIT_ARM)
1550        info->codeAddress = (char*)info->codeAddress + 1;
1551    /* transfer the size of the profiling code */
1552    info->profileCodeSize = cUnit->profileCodeSize;
1553}
1554
1555/*
1556 * Returns the skeleton bit pattern associated with an opcode.  All
1557 * variable fields are zeroed.
1558 */
1559static u4 getSkeleton(ArmOpcode op)
1560{
1561    return EncodingMap[op].skeleton;
1562}
1563
1564static u4 assembleChainingBranch(int branchOffset, bool thumbTarget)
1565{
1566    u4 thumb1, thumb2;
1567
1568    if (!thumbTarget) {
1569        thumb1 =  (getSkeleton(kThumbBlx1) | ((branchOffset>>12) & 0x7ff));
1570        thumb2 =  (getSkeleton(kThumbBlx2) | ((branchOffset>> 1) & 0x7ff));
1571    } else if ((branchOffset < -2048) | (branchOffset > 2046)) {
1572        thumb1 =  (getSkeleton(kThumbBl1) | ((branchOffset>>12) & 0x7ff));
1573        thumb2 =  (getSkeleton(kThumbBl2) | ((branchOffset>> 1) & 0x7ff));
1574    } else {
1575        thumb1 =  (getSkeleton(kThumbBUncond) | ((branchOffset>> 1) & 0x7ff));
1576        thumb2 =  getSkeleton(kThumbOrr);  /* nop -> or r0, r0 */
1577    }
1578
1579    return thumb2<<16 | thumb1;
1580}
1581
1582/*
1583 * Perform translation chain operation.
1584 * For ARM, we'll use a pair of thumb instructions to generate
1585 * an unconditional chaining branch of up to 4MB in distance.
1586 * Use a BL, because the generic "interpret" translation needs
1587 * the link register to find the dalvik pc of teh target.
1588 *     111HHooooooooooo
1589 * Where HH is 10 for the 1st inst, and 11 for the second and
1590 * the "o" field is each instruction's 11-bit contribution to the
1591 * 22-bit branch offset.
1592 * If the target is nearby, use a single-instruction bl.
1593 * If one or more threads is suspended, don't chain.
1594 */
1595void* dvmJitChain(void* tgtAddr, u4* branchAddr)
1596{
1597    int baseAddr = (u4) branchAddr + 4;
1598    int branchOffset = (int) tgtAddr - baseAddr;
1599    u4 newInst;
1600    bool thumbTarget;
1601
1602    /*
1603     * Only chain translations when there is no urge to ask all threads to
1604     * suspend themselves via the interpreter.
1605     */
1606    if ((gDvmJit.pProfTable != NULL) && (gDvm.sumThreadSuspendCount == 0) &&
1607        (gDvmJit.codeCacheFull == false)) {
1608        assert((branchOffset >= -(1<<22)) && (branchOffset <= ((1<<22)-2)));
1609
1610        gDvmJit.translationChains++;
1611
1612        COMPILER_TRACE_CHAINING(
1613            ALOGD("Jit Runtime: chaining %#x to %#x",
1614                 (int) branchAddr, (int) tgtAddr & -2));
1615
1616        /*
1617         * NOTE: normally, all translations are Thumb[2] mode, with
1618         * a single exception: the default TEMPLATE_INTERPRET
1619         * pseudo-translation.  If the need ever arises to
1620         * mix Arm & Thumb[2] translations, the following code should be
1621         * generalized.
1622         */
1623        thumbTarget = (tgtAddr != dvmCompilerGetInterpretTemplate());
1624
1625        newInst = assembleChainingBranch(branchOffset, thumbTarget);
1626
1627        /*
1628         * The second half-word instruction of the chaining cell must
1629         * either be a nop (which represents initial state), or is the
1630         * same exact branch halfword that we are trying to install.
1631         */
1632        assert( ((*branchAddr >> 16) == getSkeleton(kThumbOrr)) ||
1633                ((*branchAddr >> 16) == (newInst >> 16)));
1634
1635        UNPROTECT_CODE_CACHE(branchAddr, sizeof(*branchAddr));
1636
1637        *branchAddr = newInst;
1638        dvmCompilerCacheFlush((long)branchAddr, (long)branchAddr + 4, 0);
1639        UPDATE_CODE_CACHE_PATCHES();
1640
1641        PROTECT_CODE_CACHE(branchAddr, sizeof(*branchAddr));
1642
1643        gDvmJit.hasNewChain = true;
1644    }
1645
1646    return tgtAddr;
1647}
1648
1649#if !defined(WITH_SELF_VERIFICATION)
1650/*
1651 * Attempt to enqueue a work order to patch an inline cache for a predicted
1652 * chaining cell for virtual/interface calls.
1653 */
1654static void inlineCachePatchEnqueue(PredictedChainingCell *cellAddr,
1655                                    PredictedChainingCell *newContent)
1656{
1657    /*
1658     * Make sure only one thread gets here since updating the cell (ie fast
1659     * path and queueing the request (ie the queued path) have to be done
1660     * in an atomic fashion.
1661     */
1662    dvmLockMutex(&gDvmJit.compilerICPatchLock);
1663
1664    /* Fast path for uninitialized chaining cell */
1665    if (cellAddr->clazz == NULL &&
1666        cellAddr->branch == PREDICTED_CHAIN_BX_PAIR_INIT) {
1667
1668        UNPROTECT_CODE_CACHE(cellAddr, sizeof(*cellAddr));
1669
1670        cellAddr->method = newContent->method;
1671        cellAddr->branch = newContent->branch;
1672        /*
1673         * The update order matters - make sure clazz is updated last since it
1674         * will bring the uninitialized chaining cell to life.
1675         */
1676        android_atomic_release_store((int32_t)newContent->clazz,
1677            (volatile int32_t *)(void *)&cellAddr->clazz);
1678        dvmCompilerCacheFlush((intptr_t) cellAddr, (intptr_t) (cellAddr+1), 0);
1679        UPDATE_CODE_CACHE_PATCHES();
1680
1681        PROTECT_CODE_CACHE(cellAddr, sizeof(*cellAddr));
1682
1683#if defined(WITH_JIT_TUNING)
1684        gDvmJit.icPatchInit++;
1685#endif
1686    /* Check if this is a frequently missed clazz */
1687    } else if (cellAddr->stagedClazz != newContent->clazz) {
1688        /* Not proven to be frequent yet - build up the filter cache */
1689        UNPROTECT_CODE_CACHE(cellAddr, sizeof(*cellAddr));
1690
1691        cellAddr->stagedClazz = newContent->clazz;
1692
1693        UPDATE_CODE_CACHE_PATCHES();
1694        PROTECT_CODE_CACHE(cellAddr, sizeof(*cellAddr));
1695
1696#if defined(WITH_JIT_TUNING)
1697        gDvmJit.icPatchRejected++;
1698#endif
1699    /*
1700     * Different classes but same method implementation - it is safe to just
1701     * patch the class value without the need to stop the world.
1702     */
1703    } else if (cellAddr->method == newContent->method) {
1704        UNPROTECT_CODE_CACHE(cellAddr, sizeof(*cellAddr));
1705
1706        cellAddr->clazz = newContent->clazz;
1707        /* No need to flush the cache here since the branch is not patched */
1708        UPDATE_CODE_CACHE_PATCHES();
1709
1710        PROTECT_CODE_CACHE(cellAddr, sizeof(*cellAddr));
1711
1712#if defined(WITH_JIT_TUNING)
1713        gDvmJit.icPatchLockFree++;
1714#endif
1715    /*
1716     * Cannot patch the chaining cell inline - queue it until the next safe
1717     * point.
1718     */
1719    } else if (gDvmJit.compilerICPatchIndex < COMPILER_IC_PATCH_QUEUE_SIZE) {
1720        int index = gDvmJit.compilerICPatchIndex++;
1721        const ClassObject *clazz = newContent->clazz;
1722
1723        gDvmJit.compilerICPatchQueue[index].cellAddr = cellAddr;
1724        gDvmJit.compilerICPatchQueue[index].cellContent = *newContent;
1725        gDvmJit.compilerICPatchQueue[index].classDescriptor = clazz->descriptor;
1726        gDvmJit.compilerICPatchQueue[index].classLoader = clazz->classLoader;
1727        /* For verification purpose only */
1728        gDvmJit.compilerICPatchQueue[index].serialNumber = clazz->serialNumber;
1729#if defined(WITH_JIT_TUNING)
1730        gDvmJit.icPatchQueued++;
1731#endif
1732    } else {
1733    /* Queue is full - just drop this patch request */
1734#if defined(WITH_JIT_TUNING)
1735        gDvmJit.icPatchDropped++;
1736#endif
1737    }
1738
1739    dvmUnlockMutex(&gDvmJit.compilerICPatchLock);
1740}
1741#endif
1742
1743/*
1744 * This method is called from the invoke templates for virtual and interface
1745 * methods to speculatively setup a chain to the callee. The templates are
1746 * written in assembly and have setup method, cell, and clazz at r0, r2, and
1747 * r3 respectively, so there is a unused argument in the list. Upon return one
1748 * of the following three results may happen:
1749 *   1) Chain is not setup because the callee is native. Reset the rechain
1750 *      count to a big number so that it will take a long time before the next
1751 *      rechain attempt to happen.
1752 *   2) Chain is not setup because the callee has not been created yet. Reset
1753 *      the rechain count to a small number and retry in the near future.
1754 *   3) Enqueue the new content for the chaining cell which will be appled in
1755 *      next safe point.
1756 */
1757const Method *dvmJitToPatchPredictedChain(const Method *method,
1758                                          Thread *self,
1759                                          PredictedChainingCell *cell,
1760                                          const ClassObject *clazz)
1761{
1762    int newRechainCount = PREDICTED_CHAIN_COUNTER_RECHAIN;
1763#if defined(WITH_SELF_VERIFICATION)
1764    newRechainCount = PREDICTED_CHAIN_COUNTER_AVOID;
1765    goto done;
1766#else
1767    PredictedChainingCell newCell;
1768    int baseAddr, branchOffset, tgtAddr;
1769    if (dvmIsNativeMethod(method)) {
1770        UNPROTECT_CODE_CACHE(cell, sizeof(*cell));
1771
1772        /*
1773         * Put a non-zero/bogus value in the clazz field so that it won't
1774         * trigger immediate patching and will continue to fail to match with
1775         * a real clazz pointer.
1776         */
1777        cell->clazz = (ClassObject *) PREDICTED_CHAIN_FAKE_CLAZZ;
1778
1779        UPDATE_CODE_CACHE_PATCHES();
1780        PROTECT_CODE_CACHE(cell, sizeof(*cell));
1781        goto done;
1782    }
1783    tgtAddr = (int) dvmJitGetTraceAddr(method->insns);
1784
1785    /*
1786     * Compilation not made yet for the callee. Reset the counter to a small
1787     * value and come back to check soon.
1788     */
1789    if ((tgtAddr == 0) ||
1790        ((void*)tgtAddr == dvmCompilerGetInterpretTemplate())) {
1791        COMPILER_TRACE_CHAINING(
1792            ALOGD("Jit Runtime: predicted chain %p to method %s%s delayed",
1793                 cell, method->clazz->descriptor, method->name));
1794        goto done;
1795    }
1796
1797    if (cell->clazz == NULL) {
1798        newRechainCount = self->icRechainCount;
1799    }
1800
1801    baseAddr = (int) cell + 4;   // PC is cur_addr + 4
1802    branchOffset = tgtAddr - baseAddr;
1803
1804    newCell.branch = assembleChainingBranch(branchOffset, true);
1805    newCell.clazz = clazz;
1806    newCell.method = method;
1807    newCell.stagedClazz = NULL;
1808
1809    /*
1810     * Enter the work order to the queue and the chaining cell will be patched
1811     * the next time a safe point is entered.
1812     *
1813     * If the enqueuing fails reset the rechain count to a normal value so that
1814     * it won't get indefinitely delayed.
1815     */
1816    inlineCachePatchEnqueue(cell, &newCell);
1817#endif
1818done:
1819    self->icRechainCount = newRechainCount;
1820    return method;
1821}
1822
1823/*
1824 * Patch the inline cache content based on the content passed from the work
1825 * order.
1826 */
1827void dvmCompilerPatchInlineCache(void)
1828{
1829    int i;
1830    PredictedChainingCell *minAddr, *maxAddr;
1831
1832    /* Nothing to be done */
1833    if (gDvmJit.compilerICPatchIndex == 0) return;
1834
1835    /*
1836     * Since all threads are already stopped we don't really need to acquire
1837     * the lock. But race condition can be easily introduced in the future w/o
1838     * paying attention so we still acquire the lock here.
1839     */
1840    dvmLockMutex(&gDvmJit.compilerICPatchLock);
1841
1842    UNPROTECT_CODE_CACHE(gDvmJit.codeCache, gDvmJit.codeCacheByteUsed);
1843
1844    //ALOGD("Number of IC patch work orders: %d", gDvmJit.compilerICPatchIndex);
1845
1846    /* Initialize the min/max address range */
1847    minAddr = (PredictedChainingCell *)
1848        ((char *) gDvmJit.codeCache + gDvmJit.codeCacheSize);
1849    maxAddr = (PredictedChainingCell *) gDvmJit.codeCache;
1850
1851    for (i = 0; i < gDvmJit.compilerICPatchIndex; i++) {
1852        ICPatchWorkOrder *workOrder = &gDvmJit.compilerICPatchQueue[i];
1853        PredictedChainingCell *cellAddr = workOrder->cellAddr;
1854        PredictedChainingCell *cellContent = &workOrder->cellContent;
1855        ClassObject *clazz = dvmFindClassNoInit(workOrder->classDescriptor,
1856                                                workOrder->classLoader);
1857
1858        assert(clazz->serialNumber == workOrder->serialNumber);
1859
1860        /* Use the newly resolved clazz pointer */
1861        cellContent->clazz = clazz;
1862
1863        COMPILER_TRACE_CHAINING(
1864            ALOGD("Jit Runtime: predicted chain %p from %s to %s (%s) "
1865                 "patched",
1866                 cellAddr,
1867                 cellAddr->clazz->descriptor,
1868                 cellContent->clazz->descriptor,
1869                 cellContent->method->name));
1870
1871        /* Patch the chaining cell */
1872        *cellAddr = *cellContent;
1873        minAddr = (cellAddr < minAddr) ? cellAddr : minAddr;
1874        maxAddr = (cellAddr > maxAddr) ? cellAddr : maxAddr;
1875    }
1876
1877    /* Then synchronize the I/D cache */
1878    dvmCompilerCacheFlush((long) minAddr, (long) (maxAddr+1), 0);
1879    UPDATE_CODE_CACHE_PATCHES();
1880
1881    PROTECT_CODE_CACHE(gDvmJit.codeCache, gDvmJit.codeCacheByteUsed);
1882
1883    gDvmJit.compilerICPatchIndex = 0;
1884    dvmUnlockMutex(&gDvmJit.compilerICPatchLock);
1885}
1886
1887/*
1888 * Unchain a trace given the starting address of the translation
1889 * in the code cache.  Refer to the diagram in dvmCompilerAssembleLIR.
1890 * Returns the address following the last cell unchained.  Note that
1891 * the incoming codeAddr is a thumb code address, and therefore has
1892 * the low bit set.
1893 */
1894static u4* unchainSingle(JitEntry *trace)
1895{
1896    const char *base = getTraceBase(trace);
1897    ChainCellCounts *pChainCellCounts = getChainCellCountsPointer(base);
1898    int cellSize = getChainCellSize(pChainCellCounts);
1899    u4* pChainCells;
1900    u4 newInst;
1901    int i,j;
1902    PredictedChainingCell *predChainCell;
1903
1904    if (cellSize == 0)
1905        return (u4 *) pChainCellCounts;
1906
1907    /* Locate the beginning of the chain cell region */
1908    pChainCells = ((u4 *) pChainCellCounts) - cellSize -
1909                  pChainCellCounts->u.count[kChainingCellGap];
1910
1911    /* The cells are sorted in order - walk through them and reset */
1912    for (i = 0; i < kChainingCellGap; i++) {
1913        int elemSize = CHAIN_CELL_NORMAL_SIZE >> 2;  /* In 32-bit words */
1914        if (i == kChainingCellInvokePredicted) {
1915            elemSize = CHAIN_CELL_PREDICTED_SIZE >> 2;
1916        }
1917
1918        for (j = 0; j < pChainCellCounts->u.count[i]; j++) {
1919            switch(i) {
1920                case kChainingCellNormal:
1921                case kChainingCellHot:
1922                case kChainingCellInvokeSingleton:
1923                case kChainingCellBackwardBranch:
1924                    /*
1925                     * Replace the 1st half-word of the cell with an
1926                     * unconditional branch, leaving the 2nd half-word
1927                     * untouched.  This avoids problems with a thread
1928                     * that is suspended between the two halves when
1929                     * this unchaining takes place.
1930                     */
1931                    newInst = *pChainCells;
1932                    newInst &= 0xFFFF0000;
1933                    newInst |= getSkeleton(kThumbBUncond); /* b offset is 0 */
1934                    *pChainCells = newInst;
1935                    break;
1936                case kChainingCellInvokePredicted:
1937                    predChainCell = (PredictedChainingCell *) pChainCells;
1938                    /*
1939                     * There could be a race on another mutator thread to use
1940                     * this particular predicted cell and the check has passed
1941                     * the clazz comparison. So we cannot safely wipe the
1942                     * method and branch but it is safe to clear the clazz,
1943                     * which serves as the key.
1944                     */
1945                    predChainCell->clazz = PREDICTED_CHAIN_CLAZZ_INIT;
1946                    break;
1947                default:
1948                    ALOGE("Unexpected chaining type: %d", i);
1949                    dvmAbort();  // dvmAbort OK here - can't safely recover
1950            }
1951            COMPILER_TRACE_CHAINING(
1952                ALOGD("Jit Runtime: unchaining %#x", (int)pChainCells));
1953            pChainCells += elemSize;  /* Advance by a fixed number of words */
1954        }
1955    }
1956    return pChainCells;
1957}
1958
1959/* Unchain all translation in the cache. */
1960void dvmJitUnchainAll()
1961{
1962    u4* lowAddress = NULL;
1963    u4* highAddress = NULL;
1964    if (gDvmJit.pJitEntryTable != NULL) {
1965        COMPILER_TRACE_CHAINING(LOGD("Jit Runtime: unchaining all"));
1966        dvmLockMutex(&gDvmJit.tableLock);
1967
1968        UNPROTECT_CODE_CACHE(gDvmJit.codeCache, gDvmJit.codeCacheByteUsed);
1969
1970        for (size_t i = 0; i < gDvmJit.jitTableSize; i++) {
1971            if (gDvmJit.pJitEntryTable[i].dPC &&
1972                !gDvmJit.pJitEntryTable[i].u.info.isMethodEntry &&
1973                gDvmJit.pJitEntryTable[i].codeAddress &&
1974                (gDvmJit.pJitEntryTable[i].codeAddress !=
1975                 dvmCompilerGetInterpretTemplate())) {
1976                u4* lastAddress;
1977                lastAddress = unchainSingle(&gDvmJit.pJitEntryTable[i]);
1978                if (lowAddress == NULL ||
1979                      (u4*)gDvmJit.pJitEntryTable[i].codeAddress <
1980                      lowAddress)
1981                    lowAddress = lastAddress;
1982                if (lastAddress > highAddress)
1983                    highAddress = lastAddress;
1984            }
1985        }
1986        dvmCompilerCacheFlush((long)lowAddress, (long)highAddress, 0);
1987        UPDATE_CODE_CACHE_PATCHES();
1988
1989        PROTECT_CODE_CACHE(gDvmJit.codeCache, gDvmJit.codeCacheByteUsed);
1990
1991        dvmUnlockMutex(&gDvmJit.tableLock);
1992        gDvmJit.translationChains = 0;
1993    }
1994    gDvmJit.hasNewChain = false;
1995}
1996
1997typedef struct jitProfileAddrToLine {
1998    u4 lineNum;
1999    u4 bytecodeOffset;
2000} jitProfileAddrToLine;
2001
2002
2003/* Callback function to track the bytecode offset/line number relationiship */
2004static int addrToLineCb (void *cnxt, u4 bytecodeOffset, u4 lineNum)
2005{
2006    jitProfileAddrToLine *addrToLine = (jitProfileAddrToLine *) cnxt;
2007
2008    /* Best match so far for this offset */
2009    if (addrToLine->bytecodeOffset >= bytecodeOffset) {
2010        addrToLine->lineNum = lineNum;
2011    }
2012    return 0;
2013}
2014
2015/* Dumps profile info for a single trace */
2016static int dumpTraceProfile(JitEntry *p, bool silent, bool reset,
2017                            unsigned long sum)
2018{
2019    int idx;
2020
2021    if (p->codeAddress == NULL) {
2022        if (!silent)
2023            ALOGD("TRACEPROFILE NULL");
2024        return 0;
2025    }
2026    if (p->codeAddress == dvmCompilerGetInterpretTemplate()) {
2027        if (!silent)
2028            ALOGD("TRACEPROFILE INTERPRET_ONLY");
2029        return 0;
2030    }
2031    JitTraceCounter_t count = getProfileCount(p);
2032    if (reset) {
2033        resetProfileCount(p);
2034    }
2035    if (silent) {
2036        return count;
2037    }
2038    JitTraceDescription *desc = getTraceDescriptionPointer(getTraceBase(p));
2039    const Method *method = desc->method;
2040    char *methodDesc = dexProtoCopyMethodDescriptor(&method->prototype);
2041    jitProfileAddrToLine addrToLine = {0, desc->trace[0].info.frag.startOffset};
2042
2043    /*
2044     * We may end up decoding the debug information for the same method
2045     * multiple times, but the tradeoff is we don't need to allocate extra
2046     * space to store the addr/line mapping. Since this is a debugging feature
2047     * and done infrequently so the slower but simpler mechanism should work
2048     * just fine.
2049     */
2050    dexDecodeDebugInfo(method->clazz->pDvmDex->pDexFile,
2051                       dvmGetMethodCode(method),
2052                       method->clazz->descriptor,
2053                       method->prototype.protoIdx,
2054                       method->accessFlags,
2055                       addrToLineCb, NULL, &addrToLine);
2056
2057    ALOGD("TRACEPROFILE 0x%08x % 10d %5.2f%% [%#x(+%d), %d] %s%s;%s",
2058         (int) getTraceBase(p),
2059         count,
2060         ((float ) count) / sum * 100.0,
2061         desc->trace[0].info.frag.startOffset,
2062         desc->trace[0].info.frag.numInsts,
2063         addrToLine.lineNum,
2064         method->clazz->descriptor, method->name, methodDesc);
2065    free(methodDesc);
2066
2067    /* Find the last fragment (ie runEnd is set) */
2068    for (idx = 0;
2069         desc->trace[idx].isCode && !desc->trace[idx].info.frag.runEnd;
2070         idx++) {
2071    }
2072
2073    /*
2074     * runEnd must comes with a JitCodeDesc frag. If isCode is false it must
2075     * be a meta info field (only used by callsite info for now).
2076     */
2077    if (!desc->trace[idx].isCode) {
2078        const Method *method = (const Method *)
2079            desc->trace[idx+JIT_TRACE_CUR_METHOD-1].info.meta;
2080        char *methodDesc = dexProtoCopyMethodDescriptor(&method->prototype);
2081        /* Print the callee info in the trace */
2082        ALOGD("    -> %s%s;%s", method->clazz->descriptor, method->name,
2083             methodDesc);
2084    }
2085
2086    return count;
2087}
2088
2089/* Create a copy of the trace descriptor of an existing compilation */
2090JitTraceDescription *dvmCopyTraceDescriptor(const u2 *pc,
2091                                            const JitEntry *knownEntry)
2092{
2093    const JitEntry *jitEntry = knownEntry ? knownEntry
2094                                          : dvmJitFindEntry(pc, false);
2095    if ((jitEntry == NULL) || (jitEntry->codeAddress == 0))
2096        return NULL;
2097
2098    JitTraceDescription *desc =
2099        getTraceDescriptionPointer(getTraceBase(jitEntry));
2100
2101    /* Now make a copy and return */
2102    int descSize = getTraceDescriptionSize(desc);
2103    JitTraceDescription *newCopy = (JitTraceDescription *) malloc(descSize);
2104    memcpy(newCopy, desc, descSize);
2105    return newCopy;
2106}
2107
2108/* qsort callback function */
2109static int sortTraceProfileCount(const void *entry1, const void *entry2)
2110{
2111    const JitEntry *jitEntry1 = (const JitEntry *)entry1;
2112    const JitEntry *jitEntry2 = (const JitEntry *)entry2;
2113
2114    JitTraceCounter_t count1 = getProfileCount(jitEntry1);
2115    JitTraceCounter_t count2 = getProfileCount(jitEntry2);
2116    return (count1 == count2) ? 0 : ((count1 > count2) ? -1 : 1);
2117}
2118
2119/* Sort the trace profile counts and dump them */
2120void dvmCompilerSortAndPrintTraceProfiles()
2121{
2122    JitEntry *sortedEntries;
2123    int numTraces = 0;
2124    unsigned long sum = 0;
2125    unsigned int i;
2126
2127    /* Make sure that the table is not changing */
2128    dvmLockMutex(&gDvmJit.tableLock);
2129
2130    /* Sort the entries by descending order */
2131    sortedEntries = (JitEntry *)malloc(sizeof(JitEntry) * gDvmJit.jitTableSize);
2132    if (sortedEntries == NULL)
2133        goto done;
2134    memcpy(sortedEntries, gDvmJit.pJitEntryTable,
2135           sizeof(JitEntry) * gDvmJit.jitTableSize);
2136    qsort(sortedEntries, gDvmJit.jitTableSize, sizeof(JitEntry),
2137          sortTraceProfileCount);
2138
2139    /* Analyze the sorted entries */
2140    for (i=0; i < gDvmJit.jitTableSize; i++) {
2141        if (sortedEntries[i].dPC != 0) {
2142            sum += dumpTraceProfile(&sortedEntries[i],
2143                                       true /* silent */,
2144                                       false /* reset */,
2145                                       0);
2146            numTraces++;
2147        }
2148    }
2149    if (numTraces == 0)
2150        numTraces = 1;
2151    if (sum == 0) {
2152        sum = 1;
2153    }
2154
2155    ALOGD("JIT: Average execution count -> %d",(int)(sum / numTraces));
2156    // How efficiently are we using code cache memory?  Bigger is better.
2157    ALOGD("JIT: CodeCache efficiency -> %.2f",(float)sum / (float)gDvmJit.codeCacheByteUsed);
2158
2159    /* Dump the sorted entries. The count of each trace will be reset to 0. */
2160    for (i=0; i < gDvmJit.jitTableSize; i++) {
2161        if (sortedEntries[i].dPC != 0) {
2162            dumpTraceProfile(&sortedEntries[i],
2163                             false /* silent */,
2164                             true /* reset */,
2165                             sum);
2166        }
2167    }
2168
2169    for (i=0; i < gDvmJit.jitTableSize && i < 10; i++) {
2170        /* Stip interpreter stubs */
2171        if (sortedEntries[i].codeAddress == dvmCompilerGetInterpretTemplate()) {
2172            continue;
2173        }
2174        JitTraceDescription* desc =
2175            dvmCopyTraceDescriptor(NULL, &sortedEntries[i]);
2176        if (desc) {
2177            dvmCompilerWorkEnqueue(sortedEntries[i].dPC,
2178                                   kWorkOrderTraceDebug, desc);
2179        }
2180    }
2181
2182    free(sortedEntries);
2183done:
2184    dvmUnlockMutex(&gDvmJit.tableLock);
2185    return;
2186}
2187
2188static void findClassPointersSingleTrace(char *base, void (*callback)(void *))
2189{
2190    unsigned int chainTypeIdx, chainIdx;
2191    ChainCellCounts *pChainCellCounts = getChainCellCountsPointer(base);
2192    int cellSize = getChainCellSize(pChainCellCounts);
2193    /* Scan the chaining cells */
2194    if (cellSize) {
2195        /* Locate the beginning of the chain cell region */
2196        u4 *pChainCells = ((u4 *) pChainCellCounts) - cellSize -
2197            pChainCellCounts->u.count[kChainingCellGap];
2198        /* The cells are sorted in order - walk through them */
2199        for (chainTypeIdx = 0; chainTypeIdx < kChainingCellGap;
2200             chainTypeIdx++) {
2201            if (chainTypeIdx != kChainingCellInvokePredicted) {
2202                /* In 32-bit words */
2203                pChainCells += (CHAIN_CELL_NORMAL_SIZE >> 2) *
2204                    pChainCellCounts->u.count[chainTypeIdx];
2205                continue;
2206            }
2207            for (chainIdx = 0;
2208                 chainIdx < pChainCellCounts->u.count[chainTypeIdx];
2209                 chainIdx++) {
2210                PredictedChainingCell *cell =
2211                    (PredictedChainingCell *) pChainCells;
2212                /*
2213                 * Report the cell if it contains a sane class
2214                 * pointer.
2215                 */
2216                if (cell->clazz != NULL &&
2217                    cell->clazz !=
2218                      (ClassObject *) PREDICTED_CHAIN_FAKE_CLAZZ) {
2219                    callback(&cell->clazz);
2220                }
2221                pChainCells += CHAIN_CELL_PREDICTED_SIZE >> 2;
2222            }
2223        }
2224    }
2225
2226    /* Scan the class pointer pool */
2227    JitTraceDescription *desc = getTraceDescriptionPointer(base);
2228    int descSize = getTraceDescriptionSize(desc);
2229    int *classPointerP = (int *) ((char *) desc + descSize);
2230    int numClassPointers = *classPointerP++;
2231    for (; numClassPointers; numClassPointers--, classPointerP++) {
2232        callback(classPointerP);
2233    }
2234}
2235
2236/*
2237 * Scan class pointers in each translation and pass its address to the callback
2238 * function. Currently such a pointers can be found in the pointer pool and the
2239 * clazz field in the predicted chaining cells.
2240 */
2241void dvmJitScanAllClassPointers(void (*callback)(void *))
2242{
2243    UNPROTECT_CODE_CACHE(gDvmJit.codeCache, gDvmJit.codeCacheByteUsed);
2244
2245    /* Handle the inflight compilation first */
2246    if (gDvmJit.inflightBaseAddr)
2247        findClassPointersSingleTrace((char *) gDvmJit.inflightBaseAddr,
2248                                     callback);
2249
2250    if (gDvmJit.pJitEntryTable != NULL) {
2251        unsigned int traceIdx;
2252        dvmLockMutex(&gDvmJit.tableLock);
2253        for (traceIdx = 0; traceIdx < gDvmJit.jitTableSize; traceIdx++) {
2254            const JitEntry *entry = &gDvmJit.pJitEntryTable[traceIdx];
2255            if (entry->dPC &&
2256                !entry->u.info.isMethodEntry &&
2257                entry->codeAddress &&
2258                (entry->codeAddress != dvmCompilerGetInterpretTemplate())) {
2259                char *base = getTraceBase(entry);
2260                findClassPointersSingleTrace(base, callback);
2261            }
2262        }
2263        dvmUnlockMutex(&gDvmJit.tableLock);
2264    }
2265    UPDATE_CODE_CACHE_PATCHES();
2266
2267    PROTECT_CODE_CACHE(gDvmJit.codeCache, gDvmJit.codeCacheByteUsed);
2268}
2269
2270/*
2271 * Provide the final touch on the class object pointer pool to install the
2272 * actual pointers. The thread has to be in the running state.
2273 */
2274void dvmJitInstallClassObjectPointers(CompilationUnit *cUnit, char *codeAddress)
2275{
2276    char *base = codeAddress - cUnit->headerSize -
2277                 (cUnit->instructionSet == DALVIK_JIT_ARM ? 0 : 1);
2278
2279    /* Scan the class pointer pool */
2280    JitTraceDescription *desc = getTraceDescriptionPointer(base);
2281    int descSize = getTraceDescriptionSize(desc);
2282    intptr_t *classPointerP = (int *) ((char *) desc + descSize);
2283    int numClassPointers = *(int *)classPointerP++;
2284    intptr_t *startClassPointerP = classPointerP;
2285
2286    /*
2287     * Change the thread state to VM_RUNNING so that GC won't be happening
2288     * when the assembler looks up the class pointers. May suspend the current
2289     * thread if there is a pending request before the state is actually
2290     * changed to RUNNING.
2291     */
2292    dvmChangeStatus(gDvmJit.compilerThread, THREAD_RUNNING);
2293
2294    /*
2295     * Unprotecting the code cache will need to acquire the code cache
2296     * protection lock first. Doing so after the state change may increase the
2297     * time spent in the RUNNING state (which may delay the next GC request
2298     * should there be contention on codeCacheProtectionLock). In practice
2299     * this is probably not going to happen often since a GC is just served.
2300     * More importantly, acquiring the lock before the state change will
2301     * cause deadlock (b/4192964).
2302     */
2303    UNPROTECT_CODE_CACHE(startClassPointerP,
2304                         numClassPointers * sizeof(intptr_t));
2305#if defined(WITH_JIT_TUNING)
2306    u8 startTime = dvmGetRelativeTimeUsec();
2307#endif
2308    for (;numClassPointers; numClassPointers--) {
2309        CallsiteInfo *callsiteInfo = (CallsiteInfo *) *classPointerP;
2310        ClassObject *clazz = dvmFindClassNoInit(
2311            callsiteInfo->classDescriptor, callsiteInfo->classLoader);
2312        assert(!strcmp(clazz->descriptor, callsiteInfo->classDescriptor));
2313        *classPointerP++ = (intptr_t) clazz;
2314    }
2315
2316    /*
2317     * Register the base address so that if GC kicks in after the thread state
2318     * has been changed to VMWAIT and before the compiled code is registered
2319     * in the JIT table, its content can be patched if class objects are
2320     * moved.
2321     */
2322    gDvmJit.inflightBaseAddr = base;
2323
2324#if defined(WITH_JIT_TUNING)
2325    u8 blockTime = dvmGetRelativeTimeUsec() - startTime;
2326    gDvmJit.compilerThreadBlockGCTime += blockTime;
2327    if (blockTime > gDvmJit.maxCompilerThreadBlockGCTime)
2328        gDvmJit.maxCompilerThreadBlockGCTime = blockTime;
2329    gDvmJit.numCompilerThreadBlockGC++;
2330#endif
2331    UPDATE_CODE_CACHE_PATCHES();
2332
2333    PROTECT_CODE_CACHE(startClassPointerP, numClassPointers * sizeof(intptr_t));
2334
2335    /* Change the thread state back to VMWAIT */
2336    dvmChangeStatus(gDvmJit.compilerThread, THREAD_VMWAIT);
2337}
2338
2339#if defined(WITH_SELF_VERIFICATION)
2340/*
2341 * The following are used to keep compiled loads and stores from modifying
2342 * memory during self verification mode.
2343 *
2344 * Stores do not modify memory. Instead, the address and value pair are stored
2345 * into heapSpace. Addresses within heapSpace are unique. For accesses smaller
2346 * than a word, the word containing the address is loaded first before being
2347 * updated.
2348 *
2349 * Loads check heapSpace first and return data from there if an entry exists.
2350 * Otherwise, data is loaded from memory as usual.
2351 */
2352
2353/* Used to specify sizes of memory operations */
2354enum {
2355    kSVByte,
2356    kSVSignedByte,
2357    kSVHalfword,
2358    kSVSignedHalfword,
2359    kSVWord,
2360    kSVDoubleword,
2361    kSVVariable,
2362};
2363
2364/* Load the value of a decoded register from the stack */
2365static int selfVerificationMemRegLoad(int* sp, int reg)
2366{
2367    return *(sp + reg);
2368}
2369
2370/* Load the value of a decoded doubleword register from the stack */
2371static s8 selfVerificationMemRegLoadDouble(int* sp, int reg)
2372{
2373    return *((s8*)(sp + reg));
2374}
2375
2376/* Store the value of a decoded register out to the stack */
2377static void selfVerificationMemRegStore(int* sp, int data, int reg)
2378{
2379    *(sp + reg) = data;
2380}
2381
2382/* Store the value of a decoded doubleword register out to the stack */
2383static void selfVerificationMemRegStoreDouble(int* sp, s8 data, int reg)
2384{
2385    *((s8*)(sp + reg)) = data;
2386}
2387
2388/*
2389 * Load the specified size of data from the specified address, checking
2390 * heapSpace first if Self Verification mode wrote to it previously, and
2391 * falling back to actual memory otherwise.
2392 */
2393static int selfVerificationLoad(int addr, int size)
2394{
2395    Thread *self = dvmThreadSelf();
2396    ShadowSpace *shadowSpace = self->shadowSpace;
2397    ShadowHeap *heapSpacePtr;
2398
2399    int data;
2400    int maskedAddr = addr & 0xFFFFFFFC;
2401    int alignment = addr & 0x3;
2402
2403    for (heapSpacePtr = shadowSpace->heapSpace;
2404         heapSpacePtr != shadowSpace->heapSpaceTail; heapSpacePtr++) {
2405        if (heapSpacePtr->addr == maskedAddr) {
2406            addr = ((unsigned int) &(heapSpacePtr->data)) | alignment;
2407            break;
2408        }
2409    }
2410
2411    switch (size) {
2412        case kSVByte:
2413            data = *((u1*) addr);
2414            break;
2415        case kSVSignedByte:
2416            data = *((s1*) addr);
2417            break;
2418        case kSVHalfword:
2419            data = *((u2*) addr);
2420            break;
2421        case kSVSignedHalfword:
2422            data = *((s2*) addr);
2423            break;
2424        case kSVWord:
2425            data = *((u4*) addr);
2426            break;
2427        default:
2428            ALOGE("*** ERROR: BAD SIZE IN selfVerificationLoad: %d", size);
2429            data = 0;
2430            dvmAbort();
2431    }
2432
2433    //ALOGD("*** HEAP LOAD: Addr: %#x Data: %#x Size: %d", addr, data, size);
2434    return data;
2435}
2436
2437/* Like selfVerificationLoad, but specifically for doublewords */
2438static s8 selfVerificationLoadDoubleword(int addr)
2439{
2440    Thread *self = dvmThreadSelf();
2441    ShadowSpace* shadowSpace = self->shadowSpace;
2442    ShadowHeap* heapSpacePtr;
2443
2444    int addr2 = addr+4;
2445    unsigned int data = *((unsigned int*) addr);
2446    unsigned int data2 = *((unsigned int*) addr2);
2447
2448    for (heapSpacePtr = shadowSpace->heapSpace;
2449         heapSpacePtr != shadowSpace->heapSpaceTail; heapSpacePtr++) {
2450        if (heapSpacePtr->addr == addr) {
2451            data = heapSpacePtr->data;
2452        } else if (heapSpacePtr->addr == addr2) {
2453            data2 = heapSpacePtr->data;
2454        }
2455    }
2456
2457    //ALOGD("*** HEAP LOAD DOUBLEWORD: Addr: %#x Data: %#x Data2: %#x",
2458    //    addr, data, data2);
2459    return (((s8) data2) << 32) | data;
2460}
2461
2462/*
2463 * Handles a store of a specified size of data to a specified address.
2464 * This gets logged as an addr/data pair in heapSpace instead of modifying
2465 * memory.  Addresses in heapSpace are unique, and accesses smaller than a
2466 * word pull the entire word from memory first before updating.
2467 */
2468static void selfVerificationStore(int addr, int data, int size)
2469{
2470    Thread *self = dvmThreadSelf();
2471    ShadowSpace *shadowSpace = self->shadowSpace;
2472    ShadowHeap *heapSpacePtr;
2473
2474    int maskedAddr = addr & 0xFFFFFFFC;
2475    int alignment = addr & 0x3;
2476
2477    //ALOGD("*** HEAP STORE: Addr: %#x Data: %#x Size: %d", addr, data, size);
2478
2479    for (heapSpacePtr = shadowSpace->heapSpace;
2480         heapSpacePtr != shadowSpace->heapSpaceTail; heapSpacePtr++) {
2481        if (heapSpacePtr->addr == maskedAddr) break;
2482    }
2483
2484    if (heapSpacePtr == shadowSpace->heapSpaceTail) {
2485        heapSpacePtr->addr = maskedAddr;
2486        heapSpacePtr->data = *((unsigned int*) maskedAddr);
2487        shadowSpace->heapSpaceTail++;
2488    }
2489
2490    addr = ((unsigned int) &(heapSpacePtr->data)) | alignment;
2491    switch (size) {
2492        case kSVByte:
2493            *((u1*) addr) = data;
2494            break;
2495        case kSVSignedByte:
2496            *((s1*) addr) = data;
2497            break;
2498        case kSVHalfword:
2499            *((u2*) addr) = data;
2500            break;
2501        case kSVSignedHalfword:
2502            *((s2*) addr) = data;
2503            break;
2504        case kSVWord:
2505            *((u4*) addr) = data;
2506            break;
2507        default:
2508            ALOGE("*** ERROR: BAD SIZE IN selfVerificationSave: %d", size);
2509            dvmAbort();
2510    }
2511}
2512
2513/* Like selfVerificationStore, but specifically for doublewords */
2514static void selfVerificationStoreDoubleword(int addr, s8 double_data)
2515{
2516    Thread *self = dvmThreadSelf();
2517    ShadowSpace *shadowSpace = self->shadowSpace;
2518    ShadowHeap *heapSpacePtr;
2519
2520    int addr2 = addr+4;
2521    int data = double_data;
2522    int data2 = double_data >> 32;
2523    bool store1 = false, store2 = false;
2524
2525    //ALOGD("*** HEAP STORE DOUBLEWORD: Addr: %#x Data: %#x, Data2: %#x",
2526    //    addr, data, data2);
2527
2528    for (heapSpacePtr = shadowSpace->heapSpace;
2529         heapSpacePtr != shadowSpace->heapSpaceTail; heapSpacePtr++) {
2530        if (heapSpacePtr->addr == addr) {
2531            heapSpacePtr->data = data;
2532            store1 = true;
2533        } else if (heapSpacePtr->addr == addr2) {
2534            heapSpacePtr->data = data2;
2535            store2 = true;
2536        }
2537    }
2538
2539    if (!store1) {
2540        shadowSpace->heapSpaceTail->addr = addr;
2541        shadowSpace->heapSpaceTail->data = data;
2542        shadowSpace->heapSpaceTail++;
2543    }
2544    if (!store2) {
2545        shadowSpace->heapSpaceTail->addr = addr2;
2546        shadowSpace->heapSpaceTail->data = data2;
2547        shadowSpace->heapSpaceTail++;
2548    }
2549}
2550
2551/*
2552 * Decodes the memory instruction at the address specified in the link
2553 * register. All registers (r0-r12,lr) and fp registers (d0-d15) are stored
2554 * consecutively on the stack beginning at the specified stack pointer.
2555 * Calls the proper Self Verification handler for the memory instruction and
2556 * updates the link register to point past the decoded memory instruction.
2557 */
2558void dvmSelfVerificationMemOpDecode(int lr, int* sp)
2559{
2560    enum {
2561        kMemOpLdrPcRel = 0x09, // ldr(3)  [01001] rd[10..8] imm_8[7..0]
2562        kMemOpRRR      = 0x0A, // Full opcode is 7 bits
2563        kMemOp2Single  = 0x0A, // Used for Vstrs and Vldrs
2564        kMemOpRRR2     = 0x0B, // Full opcode is 7 bits
2565        kMemOp2Double  = 0x0B, // Used for Vstrd and Vldrd
2566        kMemOpStrRRI5  = 0x0C, // str(1)  [01100] imm_5[10..6] rn[5..3] rd[2..0]
2567        kMemOpLdrRRI5  = 0x0D, // ldr(1)  [01101] imm_5[10..6] rn[5..3] rd[2..0]
2568        kMemOpStrbRRI5 = 0x0E, // strb(1) [01110] imm_5[10..6] rn[5..3] rd[2..0]
2569        kMemOpLdrbRRI5 = 0x0F, // ldrb(1) [01111] imm_5[10..6] rn[5..3] rd[2..0]
2570        kMemOpStrhRRI5 = 0x10, // strh(1) [10000] imm_5[10..6] rn[5..3] rd[2..0]
2571        kMemOpLdrhRRI5 = 0x11, // ldrh(1) [10001] imm_5[10..6] rn[5..3] rd[2..0]
2572        kMemOpLdrSpRel = 0x13, // ldr(4)  [10011] rd[10..8] imm_8[7..0]
2573        kMemOpStmia    = 0x18, // stmia   [11000] rn[10..8] reglist [7..0]
2574        kMemOpLdmia    = 0x19, // ldmia   [11001] rn[10..8] reglist [7..0]
2575        kMemOpStrRRR   = 0x28, // str(2)  [0101000] rm[8..6] rn[5..3] rd[2..0]
2576        kMemOpStrhRRR  = 0x29, // strh(2) [0101001] rm[8..6] rn[5..3] rd[2..0]
2577        kMemOpStrbRRR  = 0x2A, // strb(2) [0101010] rm[8..6] rn[5..3] rd[2..0]
2578        kMemOpLdrsbRRR = 0x2B, // ldrsb   [0101011] rm[8..6] rn[5..3] rd[2..0]
2579        kMemOpLdrRRR   = 0x2C, // ldr(2)  [0101100] rm[8..6] rn[5..3] rd[2..0]
2580        kMemOpLdrhRRR  = 0x2D, // ldrh(2) [0101101] rm[8..6] rn[5..3] rd[2..0]
2581        kMemOpLdrbRRR  = 0x2E, // ldrb(2) [0101110] rm[8..6] rn[5..3] rd[2..0]
2582        kMemOpLdrshRRR = 0x2F, // ldrsh   [0101111] rm[8..6] rn[5..3] rd[2..0]
2583        kMemOp2Stmia   = 0xE88, // stmia  [111010001000[ rn[19..16] mask[15..0]
2584        kMemOp2Ldmia   = 0xE89, // ldmia  [111010001001[ rn[19..16] mask[15..0]
2585        kMemOp2Stmia2  = 0xE8A, // stmia  [111010001010[ rn[19..16] mask[15..0]
2586        kMemOp2Ldmia2  = 0xE8B, // ldmia  [111010001011[ rn[19..16] mask[15..0]
2587        kMemOp2Vstr    = 0xED8, // Used for Vstrs and Vstrd
2588        kMemOp2Vldr    = 0xED9, // Used for Vldrs and Vldrd
2589        kMemOp2Vstr2   = 0xEDC, // Used for Vstrs and Vstrd
2590        kMemOp2Vldr2   = 0xEDD, // Used for Vstrs and Vstrd
2591        kMemOp2StrbRRR = 0xF80, /* str rt,[rn,rm,LSL #imm] [111110000000]
2592                                rn[19-16] rt[15-12] [000000] imm[5-4] rm[3-0] */
2593        kMemOp2LdrbRRR = 0xF81, /* ldrb rt,[rn,rm,LSL #imm] [111110000001]
2594                                rn[19-16] rt[15-12] [000000] imm[5-4] rm[3-0] */
2595        kMemOp2StrhRRR = 0xF82, /* str rt,[rn,rm,LSL #imm] [111110000010]
2596                                rn[19-16] rt[15-12] [000000] imm[5-4] rm[3-0] */
2597        kMemOp2LdrhRRR = 0xF83, /* ldrh rt,[rn,rm,LSL #imm] [111110000011]
2598                                rn[19-16] rt[15-12] [000000] imm[5-4] rm[3-0] */
2599        kMemOp2StrRRR  = 0xF84, /* str rt,[rn,rm,LSL #imm] [111110000100]
2600                                rn[19-16] rt[15-12] [000000] imm[5-4] rm[3-0] */
2601        kMemOp2LdrRRR  = 0xF85, /* ldr rt,[rn,rm,LSL #imm] [111110000101]
2602                                rn[19-16] rt[15-12] [000000] imm[5-4] rm[3-0] */
2603        kMemOp2StrbRRI12 = 0xF88, /* strb rt,[rn,#imm12] [111110001000]
2604                                       rt[15..12] rn[19..16] imm12[11..0] */
2605        kMemOp2LdrbRRI12 = 0xF89, /* ldrb rt,[rn,#imm12] [111110001001]
2606                                       rt[15..12] rn[19..16] imm12[11..0] */
2607        kMemOp2StrhRRI12 = 0xF8A, /* strh rt,[rn,#imm12] [111110001010]
2608                                       rt[15..12] rn[19..16] imm12[11..0] */
2609        kMemOp2LdrhRRI12 = 0xF8B, /* ldrh rt,[rn,#imm12] [111110001011]
2610                                       rt[15..12] rn[19..16] imm12[11..0] */
2611        kMemOp2StrRRI12 = 0xF8C, /* str(Imm,T3) rd,[rn,#imm12] [111110001100]
2612                                       rn[19..16] rt[15..12] imm12[11..0] */
2613        kMemOp2LdrRRI12 = 0xF8D, /* ldr(Imm,T3) rd,[rn,#imm12] [111110001101]
2614                                       rn[19..16] rt[15..12] imm12[11..0] */
2615        kMemOp2LdrsbRRR = 0xF91, /* ldrsb rt,[rn,rm,LSL #imm] [111110010001]
2616                                rn[19-16] rt[15-12] [000000] imm[5-4] rm[3-0] */
2617        kMemOp2LdrshRRR = 0xF93, /* ldrsh rt,[rn,rm,LSL #imm] [111110010011]
2618                                rn[19-16] rt[15-12] [000000] imm[5-4] rm[3-0] */
2619        kMemOp2LdrsbRRI12 = 0xF99, /* ldrsb rt,[rn,#imm12] [111110011001]
2620                                       rt[15..12] rn[19..16] imm12[11..0] */
2621        kMemOp2LdrshRRI12 = 0xF9B, /* ldrsh rt,[rn,#imm12] [111110011011]
2622                                       rt[15..12] rn[19..16] imm12[11..0] */
2623        kMemOp2        = 0xE000, // top 3 bits set indicates Thumb2
2624    };
2625
2626    int addr, offset, data;
2627    long long double_data;
2628    int size = kSVWord;
2629    bool store = false;
2630    unsigned int *lr_masked = (unsigned int *) (lr & 0xFFFFFFFE);
2631    unsigned int insn = *lr_masked;
2632
2633    int old_lr;
2634    old_lr = selfVerificationMemRegLoad(sp, 13);
2635
2636    if ((insn & kMemOp2) == kMemOp2) {
2637        insn = (insn << 16) | (insn >> 16);
2638        //ALOGD("*** THUMB2 - Addr: %#x Insn: %#x", lr, insn);
2639
2640        int opcode12 = (insn >> 20) & 0xFFF;
2641        int opcode4 = (insn >> 8) & 0xF;
2642        int imm2 = (insn >> 4) & 0x3;
2643        int imm8 = insn & 0xFF;
2644        int imm12 = insn & 0xFFF;
2645        int rd = (insn >> 12) & 0xF;
2646        int rm = insn & 0xF;
2647        int rn = (insn >> 16) & 0xF;
2648        int rt = (insn >> 12) & 0xF;
2649        bool wBack = true;
2650
2651        // Update the link register
2652        selfVerificationMemRegStore(sp, old_lr+4, 13);
2653
2654        // Determine whether the mem op is a store or load
2655        switch (opcode12) {
2656            case kMemOp2Stmia:
2657            case kMemOp2Stmia2:
2658            case kMemOp2Vstr:
2659            case kMemOp2Vstr2:
2660            case kMemOp2StrbRRR:
2661            case kMemOp2StrhRRR:
2662            case kMemOp2StrRRR:
2663            case kMemOp2StrbRRI12:
2664            case kMemOp2StrhRRI12:
2665            case kMemOp2StrRRI12:
2666                store = true;
2667        }
2668
2669        // Determine the size of the mem access
2670        switch (opcode12) {
2671            case kMemOp2StrbRRR:
2672            case kMemOp2LdrbRRR:
2673            case kMemOp2StrbRRI12:
2674            case kMemOp2LdrbRRI12:
2675                size = kSVByte;
2676                break;
2677            case kMemOp2LdrsbRRR:
2678            case kMemOp2LdrsbRRI12:
2679                size = kSVSignedByte;
2680                break;
2681            case kMemOp2StrhRRR:
2682            case kMemOp2LdrhRRR:
2683            case kMemOp2StrhRRI12:
2684            case kMemOp2LdrhRRI12:
2685                size = kSVHalfword;
2686                break;
2687            case kMemOp2LdrshRRR:
2688            case kMemOp2LdrshRRI12:
2689                size = kSVSignedHalfword;
2690                break;
2691            case kMemOp2Vstr:
2692            case kMemOp2Vstr2:
2693            case kMemOp2Vldr:
2694            case kMemOp2Vldr2:
2695                if (opcode4 == kMemOp2Double) size = kSVDoubleword;
2696                break;
2697            case kMemOp2Stmia:
2698            case kMemOp2Ldmia:
2699            case kMemOp2Stmia2:
2700            case kMemOp2Ldmia2:
2701                size = kSVVariable;
2702                break;
2703        }
2704
2705        // Load the value of the address
2706        addr = selfVerificationMemRegLoad(sp, rn);
2707
2708        // Figure out the offset
2709        switch (opcode12) {
2710            case kMemOp2Vstr:
2711            case kMemOp2Vstr2:
2712            case kMemOp2Vldr:
2713            case kMemOp2Vldr2:
2714                offset = imm8 << 2;
2715                if (opcode4 == kMemOp2Single) {
2716                    rt = rd << 1;
2717                    if (insn & 0x400000) rt |= 0x1;
2718                } else if (opcode4 == kMemOp2Double) {
2719                    if (insn & 0x400000) rt |= 0x10;
2720                    rt = rt << 1;
2721                } else {
2722                    ALOGE("*** ERROR: UNRECOGNIZED VECTOR MEM OP: %x", opcode4);
2723                    dvmAbort();
2724                }
2725                rt += 14;
2726                break;
2727            case kMemOp2StrbRRR:
2728            case kMemOp2LdrbRRR:
2729            case kMemOp2StrhRRR:
2730            case kMemOp2LdrhRRR:
2731            case kMemOp2StrRRR:
2732            case kMemOp2LdrRRR:
2733            case kMemOp2LdrsbRRR:
2734            case kMemOp2LdrshRRR:
2735                offset = selfVerificationMemRegLoad(sp, rm) << imm2;
2736                break;
2737            case kMemOp2StrbRRI12:
2738            case kMemOp2LdrbRRI12:
2739            case kMemOp2StrhRRI12:
2740            case kMemOp2LdrhRRI12:
2741            case kMemOp2StrRRI12:
2742            case kMemOp2LdrRRI12:
2743            case kMemOp2LdrsbRRI12:
2744            case kMemOp2LdrshRRI12:
2745                offset = imm12;
2746                break;
2747            case kMemOp2Stmia:
2748            case kMemOp2Ldmia:
2749                wBack = false;
2750            case kMemOp2Stmia2:
2751            case kMemOp2Ldmia2:
2752                offset = 0;
2753                break;
2754            default:
2755                ALOGE("*** ERROR: UNRECOGNIZED THUMB2 MEM OP: %x", opcode12);
2756                offset = 0;
2757                dvmAbort();
2758        }
2759
2760        // Handle the decoded mem op accordingly
2761        if (store) {
2762            if (size == kSVVariable) {
2763                ALOGD("*** THUMB2 STMIA CURRENTLY UNUSED (AND UNTESTED)");
2764                int i;
2765                int regList = insn & 0xFFFF;
2766                for (i = 0; i < 16; i++) {
2767                    if (regList & 0x1) {
2768                        data = selfVerificationMemRegLoad(sp, i);
2769                        selfVerificationStore(addr, data, kSVWord);
2770                        addr += 4;
2771                    }
2772                    regList = regList >> 1;
2773                }
2774                if (wBack) selfVerificationMemRegStore(sp, addr, rn);
2775            } else if (size == kSVDoubleword) {
2776                double_data = selfVerificationMemRegLoadDouble(sp, rt);
2777                selfVerificationStoreDoubleword(addr+offset, double_data);
2778            } else {
2779                data = selfVerificationMemRegLoad(sp, rt);
2780                selfVerificationStore(addr+offset, data, size);
2781            }
2782        } else {
2783            if (size == kSVVariable) {
2784                ALOGD("*** THUMB2 LDMIA CURRENTLY UNUSED (AND UNTESTED)");
2785                int i;
2786                int regList = insn & 0xFFFF;
2787                for (i = 0; i < 16; i++) {
2788                    if (regList & 0x1) {
2789                        data = selfVerificationLoad(addr, kSVWord);
2790                        selfVerificationMemRegStore(sp, data, i);
2791                        addr += 4;
2792                    }
2793                    regList = regList >> 1;
2794                }
2795                if (wBack) selfVerificationMemRegStore(sp, addr, rn);
2796            } else if (size == kSVDoubleword) {
2797                double_data = selfVerificationLoadDoubleword(addr+offset);
2798                selfVerificationMemRegStoreDouble(sp, double_data, rt);
2799            } else {
2800                data = selfVerificationLoad(addr+offset, size);
2801                selfVerificationMemRegStore(sp, data, rt);
2802            }
2803        }
2804    } else {
2805        //ALOGD("*** THUMB - Addr: %#x Insn: %#x", lr, insn);
2806
2807        // Update the link register
2808        selfVerificationMemRegStore(sp, old_lr+2, 13);
2809
2810        int opcode5 = (insn >> 11) & 0x1F;
2811        int opcode7 = (insn >> 9) & 0x7F;
2812        int imm = (insn >> 6) & 0x1F;
2813        int rd = (insn >> 8) & 0x7;
2814        int rm = (insn >> 6) & 0x7;
2815        int rn = (insn >> 3) & 0x7;
2816        int rt = insn & 0x7;
2817
2818        // Determine whether the mem op is a store or load
2819        switch (opcode5) {
2820            case kMemOpRRR:
2821                switch (opcode7) {
2822                    case kMemOpStrRRR:
2823                    case kMemOpStrhRRR:
2824                    case kMemOpStrbRRR:
2825                        store = true;
2826                }
2827                break;
2828            case kMemOpStrRRI5:
2829            case kMemOpStrbRRI5:
2830            case kMemOpStrhRRI5:
2831            case kMemOpStmia:
2832                store = true;
2833        }
2834
2835        // Determine the size of the mem access
2836        switch (opcode5) {
2837            case kMemOpRRR:
2838            case kMemOpRRR2:
2839                switch (opcode7) {
2840                    case kMemOpStrbRRR:
2841                    case kMemOpLdrbRRR:
2842                        size = kSVByte;
2843                        break;
2844                    case kMemOpLdrsbRRR:
2845                        size = kSVSignedByte;
2846                        break;
2847                    case kMemOpStrhRRR:
2848                    case kMemOpLdrhRRR:
2849                        size = kSVHalfword;
2850                        break;
2851                    case kMemOpLdrshRRR:
2852                        size = kSVSignedHalfword;
2853                        break;
2854                }
2855                break;
2856            case kMemOpStrbRRI5:
2857            case kMemOpLdrbRRI5:
2858                size = kSVByte;
2859                break;
2860            case kMemOpStrhRRI5:
2861            case kMemOpLdrhRRI5:
2862                size = kSVHalfword;
2863                break;
2864            case kMemOpStmia:
2865            case kMemOpLdmia:
2866                size = kSVVariable;
2867                break;
2868        }
2869
2870        // Load the value of the address
2871        if (opcode5 == kMemOpLdrPcRel)
2872            addr = selfVerificationMemRegLoad(sp, 4);
2873        else if (opcode5 == kMemOpStmia || opcode5 == kMemOpLdmia)
2874            addr = selfVerificationMemRegLoad(sp, rd);
2875        else
2876            addr = selfVerificationMemRegLoad(sp, rn);
2877
2878        // Figure out the offset
2879        switch (opcode5) {
2880            case kMemOpLdrPcRel:
2881                offset = (insn & 0xFF) << 2;
2882                rt = rd;
2883                break;
2884            case kMemOpRRR:
2885            case kMemOpRRR2:
2886                offset = selfVerificationMemRegLoad(sp, rm);
2887                break;
2888            case kMemOpStrRRI5:
2889            case kMemOpLdrRRI5:
2890                offset = imm << 2;
2891                break;
2892            case kMemOpStrhRRI5:
2893            case kMemOpLdrhRRI5:
2894                offset = imm << 1;
2895                break;
2896            case kMemOpStrbRRI5:
2897            case kMemOpLdrbRRI5:
2898                offset = imm;
2899                break;
2900            case kMemOpStmia:
2901            case kMemOpLdmia:
2902                offset = 0;
2903                break;
2904            default:
2905                ALOGE("*** ERROR: UNRECOGNIZED THUMB MEM OP: %x", opcode5);
2906                offset = 0;
2907                dvmAbort();
2908        }
2909
2910        // Handle the decoded mem op accordingly
2911        if (store) {
2912            if (size == kSVVariable) {
2913                int i;
2914                int regList = insn & 0xFF;
2915                for (i = 0; i < 8; i++) {
2916                    if (regList & 0x1) {
2917                        data = selfVerificationMemRegLoad(sp, i);
2918                        selfVerificationStore(addr, data, kSVWord);
2919                        addr += 4;
2920                    }
2921                    regList = regList >> 1;
2922                }
2923                selfVerificationMemRegStore(sp, addr, rd);
2924            } else {
2925                data = selfVerificationMemRegLoad(sp, rt);
2926                selfVerificationStore(addr+offset, data, size);
2927            }
2928        } else {
2929            if (size == kSVVariable) {
2930                bool wBack = true;
2931                int i;
2932                int regList = insn & 0xFF;
2933                for (i = 0; i < 8; i++) {
2934                    if (regList & 0x1) {
2935                        if (i == rd) wBack = false;
2936                        data = selfVerificationLoad(addr, kSVWord);
2937                        selfVerificationMemRegStore(sp, data, i);
2938                        addr += 4;
2939                    }
2940                    regList = regList >> 1;
2941                }
2942                if (wBack) selfVerificationMemRegStore(sp, addr, rd);
2943            } else {
2944                data = selfVerificationLoad(addr+offset, size);
2945                selfVerificationMemRegStore(sp, data, rt);
2946            }
2947        }
2948    }
2949}
2950#endif
2951