blob: d9dd8c4d49e6fb4fc176c2d3e9c0974f548f65a2 [file] [log] [blame]
buzbee67bf8852011-08-17 17:51:35 -07001/*
2 * Copyright (C) 2011 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 "../../CompilerInternals.h"
19#include "ArmLIR.h"
20#include "Codegen.h"
21#include <sys/mman.h> /* for protection change */
22
23//#define TESTMODE
24#ifdef TESTMODE
25#include <cutils/ashmem.h> /* for oat testing */
26#include <unistd.h>
27#endif
28
29#define MAX_ASSEMBLER_RETRIES 50
30
31/*
32 * opcode: ArmOpcode enum
33 * skeleton: pre-designated bit-pattern for this opcode
34 * k0: key to applying ds/de
35 * ds: dest start bit position
36 * de: dest end bit position
37 * k1: key to applying s1s/s1e
38 * s1s: src1 start bit position
39 * s1e: src1 end bit position
40 * k2: key to applying s2s/s2e
41 * s2s: src2 start bit position
42 * s2e: src2 end bit position
43 * operands: number of operands (for sanity check purposes)
44 * name: mnemonic name
45 * fmt: for pretty-printing
46 */
47#define ENCODING_MAP(opcode, skeleton, k0, ds, de, k1, s1s, s1e, k2, s2s, s2e, \
48 k3, k3s, k3e, flags, name, fmt, size) \
49 {skeleton, {{k0, ds, de}, {k1, s1s, s1e}, {k2, s2s, s2e}, \
50 {k3, k3s, k3e}}, opcode, flags, name, fmt, size}
51
52/* Instruction dump string format keys: !pf, where "!" is the start
53 * of the key, "p" is which numeric operand to use and "f" is the
54 * print format.
55 *
56 * [p]ositions:
57 * 0 -> operands[0] (dest)
58 * 1 -> operands[1] (src1)
59 * 2 -> operands[2] (src2)
60 * 3 -> operands[3] (extra)
61 *
62 * [f]ormats:
63 * h -> 4-digit hex
64 * d -> decimal
65 * E -> decimal*4
66 * F -> decimal*2
67 * c -> branch condition (beq, bne, etc.)
68 * t -> pc-relative target
69 * u -> 1st half of bl[x] target
70 * v -> 2nd half ob bl[x] target
71 * R -> register list
72 * s -> single precision floating point register
73 * S -> double precision floating point register
74 * m -> Thumb2 modified immediate
75 * n -> complimented Thumb2 modified immediate
76 * M -> Thumb2 16-bit zero-extended immediate
77 * b -> 4-digit binary
78 * B -> dmb option string (sy, st, ish, ishst, nsh, hshst)
79 * H -> operand shift
80 * C -> core register name
81 * P -> fp cs register list (base of s16)
82 * Q -> fp cs register list (base of s0)
83 *
84 * [!] escape. To insert "!", use "!!"
85 */
86/* NOTE: must be kept in sync with enum ArmOpcode from ArmLIR.h */
87ArmEncodingMap EncodingMap[kArmLast] = {
88 ENCODING_MAP(kArm16BitData, 0x0000,
89 kFmtBitBlt, 15, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
90 kFmtUnused, -1, -1, IS_UNARY_OP, "data", "0x!0h(!0d)", 1),
91 ENCODING_MAP(kThumbAdcRR, 0x4140,
92 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1,
93 kFmtUnused, -1, -1,
94 IS_BINARY_OP | REG_DEF0_USE01 | SETS_CCODES | USES_CCODES,
95 "adcs", "!0C, !1C", 1),
96 ENCODING_MAP(kThumbAddRRI3, 0x1c00,
97 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtBitBlt, 8, 6,
98 kFmtUnused, -1, -1,
99 IS_TERTIARY_OP | REG_DEF0_USE1 | SETS_CCODES,
100 "adds", "!0C, !1C, #!2d", 1),
101 ENCODING_MAP(kThumbAddRI8, 0x3000,
102 kFmtBitBlt, 10, 8, kFmtBitBlt, 7, 0, kFmtUnused, -1, -1,
103 kFmtUnused, -1, -1,
104 IS_BINARY_OP | REG_DEF0_USE0 | SETS_CCODES,
105 "adds", "!0C, !0C, #!1d", 1),
106 ENCODING_MAP(kThumbAddRRR, 0x1800,
107 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtBitBlt, 8, 6,
108 kFmtUnused, -1, -1,
109 IS_TERTIARY_OP | REG_DEF0_USE12 | SETS_CCODES,
110 "adds", "!0C, !1C, !2C", 1),
111 ENCODING_MAP(kThumbAddRRLH, 0x4440,
112 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1,
113 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE01,
114 "add", "!0C, !1C", 1),
115 ENCODING_MAP(kThumbAddRRHL, 0x4480,
116 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1,
117 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE01,
118 "add", "!0C, !1C", 1),
119 ENCODING_MAP(kThumbAddRRHH, 0x44c0,
120 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1,
121 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE01,
122 "add", "!0C, !1C", 1),
123 ENCODING_MAP(kThumbAddPcRel, 0xa000,
124 kFmtBitBlt, 10, 8, kFmtBitBlt, 7, 0, kFmtUnused, -1, -1,
125 kFmtUnused, -1, -1, IS_TERTIARY_OP | IS_BRANCH,
126 "add", "!0C, pc, #!1E", 1),
127 ENCODING_MAP(kThumbAddSpRel, 0xa800,
128 kFmtBitBlt, 10, 8, kFmtUnused, -1, -1, kFmtBitBlt, 7, 0,
129 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF_SP | REG_USE_SP,
130 "add", "!0C, sp, #!2E", 1),
131 ENCODING_MAP(kThumbAddSpI7, 0xb000,
132 kFmtBitBlt, 6, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
133 kFmtUnused, -1, -1, IS_UNARY_OP | REG_DEF_SP | REG_USE_SP,
134 "add", "sp, #!0d*4", 1),
135 ENCODING_MAP(kThumbAndRR, 0x4000,
136 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1,
137 kFmtUnused, -1, -1,
138 IS_BINARY_OP | REG_DEF0_USE01 | SETS_CCODES,
139 "ands", "!0C, !1C", 1),
140 ENCODING_MAP(kThumbAsrRRI5, 0x1000,
141 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtBitBlt, 10, 6,
142 kFmtUnused, -1, -1,
143 IS_TERTIARY_OP | REG_DEF0_USE1 | SETS_CCODES,
144 "asrs", "!0C, !1C, #!2d", 1),
145 ENCODING_MAP(kThumbAsrRR, 0x4100,
146 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1,
147 kFmtUnused, -1, -1,
148 IS_BINARY_OP | REG_DEF0_USE01 | SETS_CCODES,
149 "asrs", "!0C, !1C", 1),
150 ENCODING_MAP(kThumbBCond, 0xd000,
151 kFmtBitBlt, 7, 0, kFmtBitBlt, 11, 8, kFmtUnused, -1, -1,
152 kFmtUnused, -1, -1, IS_BINARY_OP | IS_BRANCH | USES_CCODES,
153 "b!1c", "!0t", 1),
154 ENCODING_MAP(kThumbBUncond, 0xe000,
155 kFmtBitBlt, 10, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
156 kFmtUnused, -1, -1, NO_OPERAND | IS_BRANCH,
157 "b", "!0t", 1),
158 ENCODING_MAP(kThumbBicRR, 0x4380,
159 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1,
160 kFmtUnused, -1, -1,
161 IS_BINARY_OP | REG_DEF0_USE01 | SETS_CCODES,
162 "bics", "!0C, !1C", 1),
163 ENCODING_MAP(kThumbBkpt, 0xbe00,
164 kFmtBitBlt, 7, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
165 kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH,
166 "bkpt", "!0d", 1),
167 ENCODING_MAP(kThumbBlx1, 0xf000,
168 kFmtBitBlt, 10, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
169 kFmtUnused, -1, -1, IS_BINARY_OP | IS_BRANCH | REG_DEF_LR,
170 "blx_1", "!0u", 1),
171 ENCODING_MAP(kThumbBlx2, 0xe800,
172 kFmtBitBlt, 10, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
173 kFmtUnused, -1, -1, IS_BINARY_OP | IS_BRANCH | REG_DEF_LR,
174 "blx_2", "!0v", 1),
175 ENCODING_MAP(kThumbBl1, 0xf000,
176 kFmtBitBlt, 10, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
177 kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH | REG_DEF_LR,
178 "bl_1", "!0u", 1),
179 ENCODING_MAP(kThumbBl2, 0xf800,
180 kFmtBitBlt, 10, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
181 kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH | REG_DEF_LR,
182 "bl_2", "!0v", 1),
183 ENCODING_MAP(kThumbBlxR, 0x4780,
184 kFmtBitBlt, 6, 3, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
185 kFmtUnused, -1, -1,
186 IS_UNARY_OP | REG_USE0 | IS_BRANCH | REG_DEF_LR,
187 "blx", "!0C", 1),
188 ENCODING_MAP(kThumbBx, 0x4700,
189 kFmtBitBlt, 6, 3, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
190 kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH,
191 "bx", "!0C", 1),
192 ENCODING_MAP(kThumbCmnRR, 0x42c0,
193 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1,
194 kFmtUnused, -1, -1, IS_BINARY_OP | REG_USE01 | SETS_CCODES,
195 "cmn", "!0C, !1C", 1),
196 ENCODING_MAP(kThumbCmpRI8, 0x2800,
197 kFmtBitBlt, 10, 8, kFmtBitBlt, 7, 0, kFmtUnused, -1, -1,
198 kFmtUnused, -1, -1, IS_BINARY_OP | REG_USE0 | SETS_CCODES,
199 "cmp", "!0C, #!1d", 1),
200 ENCODING_MAP(kThumbCmpRR, 0x4280,
201 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1,
202 kFmtUnused, -1, -1, IS_BINARY_OP | REG_USE01 | SETS_CCODES,
203 "cmp", "!0C, !1C", 1),
204 ENCODING_MAP(kThumbCmpLH, 0x4540,
205 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1,
206 kFmtUnused, -1, -1, IS_BINARY_OP | REG_USE01 | SETS_CCODES,
207 "cmp", "!0C, !1C", 1),
208 ENCODING_MAP(kThumbCmpHL, 0x4580,
209 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1,
210 kFmtUnused, -1, -1, IS_BINARY_OP | REG_USE01 | SETS_CCODES,
211 "cmp", "!0C, !1C", 1),
212 ENCODING_MAP(kThumbCmpHH, 0x45c0,
213 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1,
214 kFmtUnused, -1, -1, IS_BINARY_OP | REG_USE01 | SETS_CCODES,
215 "cmp", "!0C, !1C", 1),
216 ENCODING_MAP(kThumbEorRR, 0x4040,
217 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1,
218 kFmtUnused, -1, -1,
219 IS_BINARY_OP | REG_DEF0_USE01 | SETS_CCODES,
220 "eors", "!0C, !1C", 1),
221 ENCODING_MAP(kThumbLdmia, 0xc800,
222 kFmtBitBlt, 10, 8, kFmtBitBlt, 7, 0, kFmtUnused, -1, -1,
223 kFmtUnused, -1, -1,
224 IS_BINARY_OP | REG_DEF0_USE0 | REG_DEF_LIST1 | IS_LOAD,
225 "ldmia", "!0C!!, <!1R>", 1),
226 ENCODING_MAP(kThumbLdrRRI5, 0x6800,
227 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtBitBlt, 10, 6,
228 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1 | IS_LOAD,
229 "ldr", "!0C, [!1C, #!2E]", 1),
230 ENCODING_MAP(kThumbLdrRRR, 0x5800,
231 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtBitBlt, 8, 6,
232 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12 | IS_LOAD,
233 "ldr", "!0C, [!1C, !2C]", 1),
234 ENCODING_MAP(kThumbLdrPcRel, 0x4800,
235 kFmtBitBlt, 10, 8, kFmtBitBlt, 7, 0, kFmtUnused, -1, -1,
236 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0 | REG_USE_PC
237 | IS_LOAD, "ldr", "!0C, [pc, #!1E]", 1),
238 ENCODING_MAP(kThumbLdrSpRel, 0x9800,
239 kFmtBitBlt, 10, 8, kFmtUnused, -1, -1, kFmtBitBlt, 7, 0,
240 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0 | REG_USE_SP
241 | IS_LOAD, "ldr", "!0C, [sp, #!2E]", 1),
242 ENCODING_MAP(kThumbLdrbRRI5, 0x7800,
243 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtBitBlt, 10, 6,
244 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1 | IS_LOAD,
245 "ldrb", "!0C, [!1C, #2d]", 1),
246 ENCODING_MAP(kThumbLdrbRRR, 0x5c00,
247 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtBitBlt, 8, 6,
248 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12 | IS_LOAD,
249 "ldrb", "!0C, [!1C, !2C]", 1),
250 ENCODING_MAP(kThumbLdrhRRI5, 0x8800,
251 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtBitBlt, 10, 6,
252 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1 | IS_LOAD,
253 "ldrh", "!0C, [!1C, #!2F]", 1),
254 ENCODING_MAP(kThumbLdrhRRR, 0x5a00,
255 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtBitBlt, 8, 6,
256 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12 | IS_LOAD,
257 "ldrh", "!0C, [!1C, !2C]", 1),
258 ENCODING_MAP(kThumbLdrsbRRR, 0x5600,
259 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtBitBlt, 8, 6,
260 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12 | IS_LOAD,
261 "ldrsb", "!0C, [!1C, !2C]", 1),
262 ENCODING_MAP(kThumbLdrshRRR, 0x5e00,
263 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtBitBlt, 8, 6,
264 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12 | IS_LOAD,
265 "ldrsh", "!0C, [!1C, !2C]", 1),
266 ENCODING_MAP(kThumbLslRRI5, 0x0000,
267 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtBitBlt, 10, 6,
268 kFmtUnused, -1, -1,
269 IS_TERTIARY_OP | REG_DEF0_USE1 | SETS_CCODES,
270 "lsls", "!0C, !1C, #!2d", 1),
271 ENCODING_MAP(kThumbLslRR, 0x4080,
272 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1,
273 kFmtUnused, -1, -1,
274 IS_BINARY_OP | REG_DEF0_USE01 | SETS_CCODES,
275 "lsls", "!0C, !1C", 1),
276 ENCODING_MAP(kThumbLsrRRI5, 0x0800,
277 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtBitBlt, 10, 6,
278 kFmtUnused, -1, -1,
279 IS_TERTIARY_OP | REG_DEF0_USE1 | SETS_CCODES,
280 "lsrs", "!0C, !1C, #!2d", 1),
281 ENCODING_MAP(kThumbLsrRR, 0x40c0,
282 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1,
283 kFmtUnused, -1, -1,
284 IS_BINARY_OP | REG_DEF0_USE01 | SETS_CCODES,
285 "lsrs", "!0C, !1C", 1),
286 ENCODING_MAP(kThumbMovImm, 0x2000,
287 kFmtBitBlt, 10, 8, kFmtBitBlt, 7, 0, kFmtUnused, -1, -1,
288 kFmtUnused, -1, -1,
289 IS_BINARY_OP | REG_DEF0 | SETS_CCODES,
290 "movs", "!0C, #!1d", 1),
291 ENCODING_MAP(kThumbMovRR, 0x1c00,
292 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1,
293 kFmtUnused, -1, -1,
294 IS_BINARY_OP | REG_DEF0_USE1 | SETS_CCODES,
295 "movs", "!0C, !1C", 1),
296 ENCODING_MAP(kThumbMovRR_H2H, 0x46c0,
297 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1,
298 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
299 "mov", "!0C, !1C", 1),
300 ENCODING_MAP(kThumbMovRR_H2L, 0x4640,
301 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1,
302 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
303 "mov", "!0C, !1C", 1),
304 ENCODING_MAP(kThumbMovRR_L2H, 0x4680,
305 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1,
306 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
307 "mov", "!0C, !1C", 1),
308 ENCODING_MAP(kThumbMul, 0x4340,
309 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1,
310 kFmtUnused, -1, -1,
311 IS_BINARY_OP | REG_DEF0_USE01 | SETS_CCODES,
312 "muls", "!0C, !1C", 1),
313 ENCODING_MAP(kThumbMvn, 0x43c0,
314 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1,
315 kFmtUnused, -1, -1,
316 IS_BINARY_OP | REG_DEF0_USE1 | SETS_CCODES,
317 "mvns", "!0C, !1C", 1),
318 ENCODING_MAP(kThumbNeg, 0x4240,
319 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1,
320 kFmtUnused, -1, -1,
321 IS_BINARY_OP | REG_DEF0_USE1 | SETS_CCODES,
322 "negs", "!0C, !1C", 1),
323 ENCODING_MAP(kThumbOrr, 0x4300,
324 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1,
325 kFmtUnused, -1, -1,
326 IS_BINARY_OP | REG_DEF0_USE01 | SETS_CCODES,
327 "orrs", "!0C, !1C", 1),
328 ENCODING_MAP(kThumbPop, 0xbc00,
329 kFmtBitBlt, 8, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
330 kFmtUnused, -1, -1,
331 IS_UNARY_OP | REG_DEF_SP | REG_USE_SP | REG_DEF_LIST0
332 | IS_LOAD, "pop", "<!0R>", 1),
333 ENCODING_MAP(kThumbPush, 0xb400,
334 kFmtBitBlt, 8, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
335 kFmtUnused, -1, -1,
336 IS_UNARY_OP | REG_DEF_SP | REG_USE_SP | REG_USE_LIST0
337 | IS_STORE, "push", "<!0R>", 1),
338 ENCODING_MAP(kThumbRorRR, 0x41c0,
339 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1,
340 kFmtUnused, -1, -1,
341 IS_BINARY_OP | REG_DEF0_USE01 | SETS_CCODES,
342 "rors", "!0C, !1C", 1),
343 ENCODING_MAP(kThumbSbc, 0x4180,
344 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1,
345 kFmtUnused, -1, -1,
346 IS_BINARY_OP | REG_DEF0_USE01 | USES_CCODES | SETS_CCODES,
347 "sbcs", "!0C, !1C", 1),
348 ENCODING_MAP(kThumbStmia, 0xc000,
349 kFmtBitBlt, 10, 8, kFmtBitBlt, 7, 0, kFmtUnused, -1, -1,
350 kFmtUnused, -1, -1,
351 IS_BINARY_OP | REG_DEF0 | REG_USE0 | REG_USE_LIST1 | IS_STORE,
352 "stmia", "!0C!!, <!1R>", 1),
353 ENCODING_MAP(kThumbStrRRI5, 0x6000,
354 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtBitBlt, 10, 6,
355 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE01 | IS_STORE,
356 "str", "!0C, [!1C, #!2E]", 1),
357 ENCODING_MAP(kThumbStrRRR, 0x5000,
358 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtBitBlt, 8, 6,
359 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE012 | IS_STORE,
360 "str", "!0C, [!1C, !2C]", 1),
361 ENCODING_MAP(kThumbStrSpRel, 0x9000,
362 kFmtBitBlt, 10, 8, kFmtUnused, -1, -1, kFmtBitBlt, 7, 0,
363 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE0 | REG_USE_SP
364 | IS_STORE, "str", "!0C, [sp, #!2E]", 1),
365 ENCODING_MAP(kThumbStrbRRI5, 0x7000,
366 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtBitBlt, 10, 6,
367 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE01 | IS_STORE,
368 "strb", "!0C, [!1C, #!2d]", 1),
369 ENCODING_MAP(kThumbStrbRRR, 0x5400,
370 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtBitBlt, 8, 6,
371 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE012 | IS_STORE,
372 "strb", "!0C, [!1C, !2C]", 1),
373 ENCODING_MAP(kThumbStrhRRI5, 0x8000,
374 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtBitBlt, 10, 6,
375 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE01 | IS_STORE,
376 "strh", "!0C, [!1C, #!2F]", 1),
377 ENCODING_MAP(kThumbStrhRRR, 0x5200,
378 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtBitBlt, 8, 6,
379 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE012 | IS_STORE,
380 "strh", "!0C, [!1C, !2C]", 1),
381 ENCODING_MAP(kThumbSubRRI3, 0x1e00,
382 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtBitBlt, 8, 6,
383 kFmtUnused, -1, -1,
384 IS_TERTIARY_OP | REG_DEF0_USE1 | SETS_CCODES,
385 "subs", "!0C, !1C, #!2d", 1),
386 ENCODING_MAP(kThumbSubRI8, 0x3800,
387 kFmtBitBlt, 10, 8, kFmtBitBlt, 7, 0, kFmtUnused, -1, -1,
388 kFmtUnused, -1, -1,
389 IS_BINARY_OP | REG_DEF0_USE0 | SETS_CCODES,
390 "subs", "!0C, #!1d", 1),
391 ENCODING_MAP(kThumbSubRRR, 0x1a00,
392 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtBitBlt, 8, 6,
393 kFmtUnused, -1, -1,
394 IS_TERTIARY_OP | REG_DEF0_USE12 | SETS_CCODES,
395 "subs", "!0C, !1C, !2C", 1),
396 ENCODING_MAP(kThumbSubSpI7, 0xb080,
397 kFmtBitBlt, 6, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
398 kFmtUnused, -1, -1,
399 IS_UNARY_OP | REG_DEF_SP | REG_USE_SP,
400 "sub", "sp, #!0d*4", 1),
401 ENCODING_MAP(kThumbSwi, 0xdf00,
Ian Rogers408f79a2011-08-23 18:22:33 -0700402 kFmtBitBlt, 7, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
403 kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH,
buzbee67bf8852011-08-17 17:51:35 -0700404 "swi", "!0d", 1),
405 ENCODING_MAP(kThumbTst, 0x4200,
406 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1,
407 kFmtUnused, -1, -1, IS_UNARY_OP | REG_USE01 | SETS_CCODES,
408 "tst", "!0C, !1C", 1),
409 ENCODING_MAP(kThumb2Vldrs, 0xed900a00,
410 kFmtSfp, 22, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 7, 0,
411 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1 | IS_LOAD,
412 "vldr", "!0s, [!1C, #!2E]", 2),
413 ENCODING_MAP(kThumb2Vldrd, 0xed900b00,
414 kFmtDfp, 22, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 7, 0,
415 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1 | IS_LOAD,
416 "vldr", "!0S, [!1C, #!2E]", 2),
417 ENCODING_MAP(kThumb2Vmuls, 0xee200a00,
418 kFmtSfp, 22, 12, kFmtSfp, 7, 16, kFmtSfp, 5, 0,
419 kFmtUnused, -1, -1,
420 IS_TERTIARY_OP | REG_DEF0_USE12,
421 "vmuls", "!0s, !1s, !2s", 2),
422 ENCODING_MAP(kThumb2Vmuld, 0xee200b00,
423 kFmtDfp, 22, 12, kFmtDfp, 7, 16, kFmtDfp, 5, 0,
424 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
425 "vmuld", "!0S, !1S, !2S", 2),
426 ENCODING_MAP(kThumb2Vstrs, 0xed800a00,
427 kFmtSfp, 22, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 7, 0,
428 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE01 | IS_STORE,
429 "vstr", "!0s, [!1C, #!2E]", 2),
430 ENCODING_MAP(kThumb2Vstrd, 0xed800b00,
431 kFmtDfp, 22, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 7, 0,
432 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE01 | IS_STORE,
433 "vstr", "!0S, [!1C, #!2E]", 2),
434 ENCODING_MAP(kThumb2Vsubs, 0xee300a40,
435 kFmtSfp, 22, 12, kFmtSfp, 7, 16, kFmtSfp, 5, 0,
436 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
437 "vsub", "!0s, !1s, !2s", 2),
438 ENCODING_MAP(kThumb2Vsubd, 0xee300b40,
439 kFmtDfp, 22, 12, kFmtDfp, 7, 16, kFmtDfp, 5, 0,
440 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
441 "vsub", "!0S, !1S, !2S", 2),
442 ENCODING_MAP(kThumb2Vadds, 0xee300a00,
443 kFmtSfp, 22, 12, kFmtSfp, 7, 16, kFmtSfp, 5, 0,
444 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
445 "vadd", "!0s, !1s, !2s", 2),
446 ENCODING_MAP(kThumb2Vaddd, 0xee300b00,
447 kFmtDfp, 22, 12, kFmtDfp, 7, 16, kFmtDfp, 5, 0,
448 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
449 "vadd", "!0S, !1S, !2S", 2),
450 ENCODING_MAP(kThumb2Vdivs, 0xee800a00,
451 kFmtSfp, 22, 12, kFmtSfp, 7, 16, kFmtSfp, 5, 0,
452 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
453 "vdivs", "!0s, !1s, !2s", 2),
454 ENCODING_MAP(kThumb2Vdivd, 0xee800b00,
455 kFmtDfp, 22, 12, kFmtDfp, 7, 16, kFmtDfp, 5, 0,
456 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
457 "vdivd", "!0S, !1S, !2S", 2),
458 ENCODING_MAP(kThumb2VcvtIF, 0xeeb80ac0,
459 kFmtSfp, 22, 12, kFmtSfp, 5, 0, kFmtUnused, -1, -1,
460 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
461 "vcvt.f32", "!0s, !1s", 2),
462 ENCODING_MAP(kThumb2VcvtID, 0xeeb80bc0,
463 kFmtDfp, 22, 12, kFmtSfp, 5, 0, kFmtUnused, -1, -1,
464 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
465 "vcvt.f64", "!0S, !1s", 2),
466 ENCODING_MAP(kThumb2VcvtFI, 0xeebd0ac0,
467 kFmtSfp, 22, 12, kFmtSfp, 5, 0, kFmtUnused, -1, -1,
468 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
469 "vcvt.s32.f32 ", "!0s, !1s", 2),
470 ENCODING_MAP(kThumb2VcvtDI, 0xeebd0bc0,
471 kFmtSfp, 22, 12, kFmtDfp, 5, 0, kFmtUnused, -1, -1,
472 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
473 "vcvt.s32.f64 ", "!0s, !1S", 2),
474 ENCODING_MAP(kThumb2VcvtFd, 0xeeb70ac0,
475 kFmtDfp, 22, 12, kFmtSfp, 5, 0, kFmtUnused, -1, -1,
476 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
477 "vcvt.f64.f32 ", "!0S, !1s", 2),
478 ENCODING_MAP(kThumb2VcvtDF, 0xeeb70bc0,
479 kFmtSfp, 22, 12, kFmtDfp, 5, 0, kFmtUnused, -1, -1,
480 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
481 "vcvt.f32.f64 ", "!0s, !1S", 2),
482 ENCODING_MAP(kThumb2Vsqrts, 0xeeb10ac0,
483 kFmtSfp, 22, 12, kFmtSfp, 5, 0, kFmtUnused, -1, -1,
484 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
485 "vsqrt.f32 ", "!0s, !1s", 2),
486 ENCODING_MAP(kThumb2Vsqrtd, 0xeeb10bc0,
487 kFmtDfp, 22, 12, kFmtDfp, 5, 0, kFmtUnused, -1, -1,
488 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
489 "vsqrt.f64 ", "!0S, !1S", 2),
490 ENCODING_MAP(kThumb2MovImmShift, 0xf04f0000, /* no setflags encoding */
491 kFmtBitBlt, 11, 8, kFmtModImm, -1, -1, kFmtUnused, -1, -1,
492 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0,
493 "mov", "!0C, #!1m", 2),
494 ENCODING_MAP(kThumb2MovImm16, 0xf2400000,
495 kFmtBitBlt, 11, 8, kFmtImm16, -1, -1, kFmtUnused, -1, -1,
496 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0,
497 "mov", "!0C, #!1M", 2),
498 ENCODING_MAP(kThumb2StrRRI12, 0xf8c00000,
499 kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 11, 0,
500 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE01 | IS_STORE,
501 "str", "!0C, [!1C, #!2d]", 2),
502 ENCODING_MAP(kThumb2LdrRRI12, 0xf8d00000,
503 kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 11, 0,
504 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1 | IS_LOAD,
505 "ldr", "!0C, [!1C, #!2d]", 2),
506 ENCODING_MAP(kThumb2StrRRI8Predec, 0xf8400c00,
507 kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 8, 0,
508 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE01 | IS_STORE,
509 "str", "!0C, [!1C, #-!2d]", 2),
510 ENCODING_MAP(kThumb2LdrRRI8Predec, 0xf8500c00,
511 kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 8, 0,
512 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1 | IS_LOAD,
513 "ldr", "!0C, [!1C, #-!2d]", 2),
514 ENCODING_MAP(kThumb2Cbnz, 0xb900, /* Note: does not affect flags */
515 kFmtBitBlt, 2, 0, kFmtImm6, -1, -1, kFmtUnused, -1, -1,
516 kFmtUnused, -1, -1, IS_BINARY_OP | REG_USE0 | IS_BRANCH,
517 "cbnz", "!0C,!1t", 1),
518 ENCODING_MAP(kThumb2Cbz, 0xb100, /* Note: does not affect flags */
519 kFmtBitBlt, 2, 0, kFmtImm6, -1, -1, kFmtUnused, -1, -1,
520 kFmtUnused, -1, -1, IS_BINARY_OP | REG_USE0 | IS_BRANCH,
521 "cbz", "!0C,!1t", 1),
522 ENCODING_MAP(kThumb2AddRRI12, 0xf2000000,
523 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtImm12, -1, -1,
524 kFmtUnused, -1, -1,
525 IS_TERTIARY_OP | REG_DEF0_USE1,/* Note: doesn't affect flags */
526 "add", "!0C,!1C,#!2d", 2),
527 ENCODING_MAP(kThumb2MovRR, 0xea4f0000, /* no setflags encoding */
528 kFmtBitBlt, 11, 8, kFmtBitBlt, 3, 0, kFmtUnused, -1, -1,
529 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
530 "mov", "!0C, !1C", 2),
531 ENCODING_MAP(kThumb2Vmovs, 0xeeb00a40,
532 kFmtSfp, 22, 12, kFmtSfp, 5, 0, kFmtUnused, -1, -1,
533 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
534 "vmov.f32 ", " !0s, !1s", 2),
535 ENCODING_MAP(kThumb2Vmovd, 0xeeb00b40,
536 kFmtDfp, 22, 12, kFmtDfp, 5, 0, kFmtUnused, -1, -1,
537 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
538 "vmov.f64 ", " !0S, !1S", 2),
539 ENCODING_MAP(kThumb2Ldmia, 0xe8900000,
540 kFmtBitBlt, 19, 16, kFmtBitBlt, 15, 0, kFmtUnused, -1, -1,
541 kFmtUnused, -1, -1,
542 IS_BINARY_OP | REG_DEF0_USE0 | REG_DEF_LIST1 | IS_LOAD,
543 "ldmia", "!0C!!, <!1R>", 2),
544 ENCODING_MAP(kThumb2Stmia, 0xe8800000,
545 kFmtBitBlt, 19, 16, kFmtBitBlt, 15, 0, kFmtUnused, -1, -1,
546 kFmtUnused, -1, -1,
547 IS_BINARY_OP | REG_DEF0_USE0 | REG_USE_LIST1 | IS_STORE,
548 "stmia", "!0C!!, <!1R>", 2),
549 ENCODING_MAP(kThumb2AddRRR, 0xeb100000, /* setflags encoding */
550 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0,
551 kFmtShift, -1, -1,
552 IS_QUAD_OP | REG_DEF0_USE12 | SETS_CCODES,
553 "adds", "!0C, !1C, !2C!3H", 2),
554 ENCODING_MAP(kThumb2SubRRR, 0xebb00000, /* setflags enconding */
555 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0,
556 kFmtShift, -1, -1,
557 IS_QUAD_OP | REG_DEF0_USE12 | SETS_CCODES,
558 "subs", "!0C, !1C, !2C!3H", 2),
559 ENCODING_MAP(kThumb2SbcRRR, 0xeb700000, /* setflags encoding */
560 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0,
561 kFmtShift, -1, -1,
562 IS_QUAD_OP | REG_DEF0_USE12 | USES_CCODES | SETS_CCODES,
563 "sbcs", "!0C, !1C, !2C!3H", 2),
564 ENCODING_MAP(kThumb2CmpRR, 0xebb00f00,
565 kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0, kFmtShift, -1, -1,
566 kFmtUnused, -1, -1,
567 IS_TERTIARY_OP | REG_USE01 | SETS_CCODES,
568 "cmp", "!0C, !1C", 2),
569 ENCODING_MAP(kThumb2SubRRI12, 0xf2a00000,
570 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtImm12, -1, -1,
571 kFmtUnused, -1, -1,
572 IS_TERTIARY_OP | REG_DEF0_USE1,/* Note: doesn't affect flags */
573 "sub", "!0C,!1C,#!2d", 2),
574 ENCODING_MAP(kThumb2MvnImmShift, 0xf06f0000, /* no setflags encoding */
575 kFmtBitBlt, 11, 8, kFmtModImm, -1, -1, kFmtUnused, -1, -1,
576 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0,
577 "mvn", "!0C, #!1n", 2),
578 ENCODING_MAP(kThumb2Sel, 0xfaa0f080,
579 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0,
580 kFmtUnused, -1, -1,
581 IS_TERTIARY_OP | REG_DEF0_USE12 | USES_CCODES,
582 "sel", "!0C, !1C, !2C", 2),
583 ENCODING_MAP(kThumb2Ubfx, 0xf3c00000,
584 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtLsb, -1, -1,
585 kFmtBWidth, 4, 0, IS_QUAD_OP | REG_DEF0_USE1,
586 "ubfx", "!0C, !1C, #!2d, #!3d", 2),
587 ENCODING_MAP(kThumb2Sbfx, 0xf3400000,
588 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtLsb, -1, -1,
589 kFmtBWidth, 4, 0, IS_QUAD_OP | REG_DEF0_USE1,
590 "sbfx", "!0C, !1C, #!2d, #!3d", 2),
591 ENCODING_MAP(kThumb2LdrRRR, 0xf8500000,
592 kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0,
593 kFmtBitBlt, 5, 4, IS_QUAD_OP | REG_DEF0_USE12 | IS_LOAD,
594 "ldr", "!0C, [!1C, !2C, LSL #!3d]", 2),
595 ENCODING_MAP(kThumb2LdrhRRR, 0xf8300000,
596 kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0,
597 kFmtBitBlt, 5, 4, IS_QUAD_OP | REG_DEF0_USE12 | IS_LOAD,
598 "ldrh", "!0C, [!1C, !2C, LSL #!3d]", 2),
599 ENCODING_MAP(kThumb2LdrshRRR, 0xf9300000,
600 kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0,
601 kFmtBitBlt, 5, 4, IS_QUAD_OP | REG_DEF0_USE12 | IS_LOAD,
602 "ldrsh", "!0C, [!1C, !2C, LSL #!3d]", 2),
603 ENCODING_MAP(kThumb2LdrbRRR, 0xf8100000,
604 kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0,
605 kFmtBitBlt, 5, 4, IS_QUAD_OP | REG_DEF0_USE12 | IS_LOAD,
606 "ldrb", "!0C, [!1C, !2C, LSL #!3d]", 2),
607 ENCODING_MAP(kThumb2LdrsbRRR, 0xf9100000,
608 kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0,
609 kFmtBitBlt, 5, 4, IS_QUAD_OP | REG_DEF0_USE12 | IS_LOAD,
610 "ldrsb", "!0C, [!1C, !2C, LSL #!3d]", 2),
611 ENCODING_MAP(kThumb2StrRRR, 0xf8400000,
612 kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0,
613 kFmtBitBlt, 5, 4, IS_QUAD_OP | REG_USE012 | IS_STORE,
614 "str", "!0C, [!1C, !2C, LSL #!3d]", 2),
615 ENCODING_MAP(kThumb2StrhRRR, 0xf8200000,
616 kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0,
617 kFmtBitBlt, 5, 4, IS_QUAD_OP | REG_USE012 | IS_STORE,
618 "strh", "!0C, [!1C, !2C, LSL #!3d]", 2),
619 ENCODING_MAP(kThumb2StrbRRR, 0xf8000000,
620 kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0,
621 kFmtBitBlt, 5, 4, IS_QUAD_OP | REG_USE012 | IS_STORE,
622 "strb", "!0C, [!1C, !2C, LSL #!3d]", 2),
623 ENCODING_MAP(kThumb2LdrhRRI12, 0xf8b00000,
624 kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 11, 0,
625 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1 | IS_LOAD,
626 "ldrh", "!0C, [!1C, #!2d]", 2),
627 ENCODING_MAP(kThumb2LdrshRRI12, 0xf9b00000,
628 kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 11, 0,
629 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1 | IS_LOAD,
630 "ldrsh", "!0C, [!1C, #!2d]", 2),
631 ENCODING_MAP(kThumb2LdrbRRI12, 0xf8900000,
632 kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 11, 0,
633 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1 | IS_LOAD,
634 "ldrb", "!0C, [!1C, #!2d]", 2),
635 ENCODING_MAP(kThumb2LdrsbRRI12, 0xf9900000,
636 kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 11, 0,
637 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1 | IS_LOAD,
638 "ldrsb", "!0C, [!1C, #!2d]", 2),
639 ENCODING_MAP(kThumb2StrhRRI12, 0xf8a00000,
640 kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 11, 0,
641 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE01 | IS_STORE,
642 "strh", "!0C, [!1C, #!2d]", 2),
643 ENCODING_MAP(kThumb2StrbRRI12, 0xf8800000,
644 kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 11, 0,
645 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE01 | IS_STORE,
646 "strb", "!0C, [!1C, #!2d]", 2),
647 ENCODING_MAP(kThumb2Pop, 0xe8bd0000,
648 kFmtBitBlt, 15, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
649 kFmtUnused, -1, -1,
650 IS_UNARY_OP | REG_DEF_SP | REG_USE_SP | REG_DEF_LIST0
651 | IS_LOAD, "pop", "<!0R>", 2),
652 ENCODING_MAP(kThumb2Push, 0xe92d0000,
653 kFmtBitBlt, 15, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
654 kFmtUnused, -1, -1,
655 IS_UNARY_OP | REG_DEF_SP | REG_USE_SP | REG_USE_LIST0
656 | IS_STORE, "push", "<!0R>", 2),
657 ENCODING_MAP(kThumb2CmpRI8, 0xf1b00f00,
658 kFmtBitBlt, 19, 16, kFmtModImm, -1, -1, kFmtUnused, -1, -1,
659 kFmtUnused, -1, -1,
660 IS_BINARY_OP | REG_USE0 | SETS_CCODES,
661 "cmp", "!0C, #!1m", 2),
662 ENCODING_MAP(kThumb2AdcRRR, 0xeb500000, /* setflags encoding */
663 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0,
664 kFmtShift, -1, -1,
665 IS_QUAD_OP | REG_DEF0_USE12 | SETS_CCODES,
666 "adcs", "!0C, !1C, !2C!3H", 2),
667 ENCODING_MAP(kThumb2AndRRR, 0xea000000,
668 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0,
669 kFmtShift, -1, -1, IS_QUAD_OP | REG_DEF0_USE12,
670 "and", "!0C, !1C, !2C!3H", 2),
671 ENCODING_MAP(kThumb2BicRRR, 0xea200000,
672 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0,
673 kFmtShift, -1, -1, IS_QUAD_OP | REG_DEF0_USE12,
674 "bic", "!0C, !1C, !2C!3H", 2),
675 ENCODING_MAP(kThumb2CmnRR, 0xeb000000,
676 kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0, kFmtShift, -1, -1,
677 kFmtUnused, -1, -1,
678 IS_TERTIARY_OP | REG_DEF0_USE1 | SETS_CCODES,
679 "cmn", "!0C, !1C, shift !2d", 2),
680 ENCODING_MAP(kThumb2EorRRR, 0xea800000,
681 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0,
682 kFmtShift, -1, -1, IS_QUAD_OP | REG_DEF0_USE12,
683 "eor", "!0C, !1C, !2C!3H", 2),
684 ENCODING_MAP(kThumb2MulRRR, 0xfb00f000,
685 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0,
686 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
687 "mul", "!0C, !1C, !2C", 2),
688 ENCODING_MAP(kThumb2MnvRR, 0xea6f0000,
689 kFmtBitBlt, 11, 8, kFmtBitBlt, 3, 0, kFmtShift, -1, -1,
690 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
691 "mvn", "!0C, !1C, shift !2d", 2),
692 ENCODING_MAP(kThumb2RsubRRI8, 0xf1d00000,
693 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtModImm, -1, -1,
694 kFmtUnused, -1, -1,
695 IS_TERTIARY_OP | REG_DEF0_USE1 | SETS_CCODES,
696 "rsb", "!0C,!1C,#!2m", 2),
697 ENCODING_MAP(kThumb2NegRR, 0xf1d00000, /* instance of rsub */
698 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtUnused, -1, -1,
699 kFmtUnused, -1, -1,
700 IS_BINARY_OP | REG_DEF0_USE1 | SETS_CCODES,
701 "neg", "!0C,!1C", 2),
702 ENCODING_MAP(kThumb2OrrRRR, 0xea400000,
703 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0,
704 kFmtShift, -1, -1, IS_QUAD_OP | REG_DEF0_USE12,
705 "orr", "!0C, !1C, !2C!3H", 2),
706 ENCODING_MAP(kThumb2TstRR, 0xea100f00,
707 kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0, kFmtShift, -1, -1,
708 kFmtUnused, -1, -1,
709 IS_TERTIARY_OP | REG_USE01 | SETS_CCODES,
710 "tst", "!0C, !1C, shift !2d", 2),
711 ENCODING_MAP(kThumb2LslRRR, 0xfa00f000,
712 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0,
713 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
714 "lsl", "!0C, !1C, !2C", 2),
715 ENCODING_MAP(kThumb2LsrRRR, 0xfa20f000,
716 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0,
717 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
718 "lsr", "!0C, !1C, !2C", 2),
719 ENCODING_MAP(kThumb2AsrRRR, 0xfa40f000,
720 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0,
721 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
722 "asr", "!0C, !1C, !2C", 2),
723 ENCODING_MAP(kThumb2RorRRR, 0xfa60f000,
724 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0,
725 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
726 "ror", "!0C, !1C, !2C", 2),
727 ENCODING_MAP(kThumb2LslRRI5, 0xea4f0000,
728 kFmtBitBlt, 11, 8, kFmtBitBlt, 3, 0, kFmtShift5, -1, -1,
729 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
730 "lsl", "!0C, !1C, #!2d", 2),
731 ENCODING_MAP(kThumb2LsrRRI5, 0xea4f0010,
732 kFmtBitBlt, 11, 8, kFmtBitBlt, 3, 0, kFmtShift5, -1, -1,
733 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
734 "lsr", "!0C, !1C, #!2d", 2),
735 ENCODING_MAP(kThumb2AsrRRI5, 0xea4f0020,
736 kFmtBitBlt, 11, 8, kFmtBitBlt, 3, 0, kFmtShift5, -1, -1,
737 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
738 "asr", "!0C, !1C, #!2d", 2),
739 ENCODING_MAP(kThumb2RorRRI5, 0xea4f0030,
740 kFmtBitBlt, 11, 8, kFmtBitBlt, 3, 0, kFmtShift5, -1, -1,
741 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
742 "ror", "!0C, !1C, #!2d", 2),
743 ENCODING_MAP(kThumb2BicRRI8, 0xf0200000,
744 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtModImm, -1, -1,
745 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
746 "bic", "!0C, !1C, #!2m", 2),
747 ENCODING_MAP(kThumb2AndRRI8, 0xf0000000,
748 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtModImm, -1, -1,
749 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
750 "and", "!0C, !1C, #!2m", 2),
751 ENCODING_MAP(kThumb2OrrRRI8, 0xf0400000,
752 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtModImm, -1, -1,
753 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
754 "orr", "!0C, !1C, #!2m", 2),
755 ENCODING_MAP(kThumb2EorRRI8, 0xf0800000,
756 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtModImm, -1, -1,
757 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
758 "eor", "!0C, !1C, #!2m", 2),
759 ENCODING_MAP(kThumb2AddRRI8, 0xf1100000,
760 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtModImm, -1, -1,
761 kFmtUnused, -1, -1,
762 IS_TERTIARY_OP | REG_DEF0_USE1 | SETS_CCODES,
763 "adds", "!0C, !1C, #!2m", 2),
764 ENCODING_MAP(kThumb2AdcRRI8, 0xf1500000,
765 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtModImm, -1, -1,
766 kFmtUnused, -1, -1,
767 IS_TERTIARY_OP | REG_DEF0_USE1 | SETS_CCODES | USES_CCODES,
768 "adcs", "!0C, !1C, #!2m", 2),
769 ENCODING_MAP(kThumb2SubRRI8, 0xf1b00000,
770 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtModImm, -1, -1,
771 kFmtUnused, -1, -1,
772 IS_TERTIARY_OP | REG_DEF0_USE1 | SETS_CCODES,
773 "subs", "!0C, !1C, #!2m", 2),
774 ENCODING_MAP(kThumb2SbcRRI8, 0xf1700000,
775 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtModImm, -1, -1,
776 kFmtUnused, -1, -1,
777 IS_TERTIARY_OP | REG_DEF0_USE1 | SETS_CCODES | USES_CCODES,
778 "sbcs", "!0C, !1C, #!2m", 2),
779 ENCODING_MAP(kThumb2It, 0xbf00,
780 kFmtBitBlt, 7, 4, kFmtBitBlt, 3, 0, kFmtModImm, -1, -1,
781 kFmtUnused, -1, -1, IS_BINARY_OP | IS_IT | USES_CCODES,
782 "it:!1b", "!0c", 1),
783 ENCODING_MAP(kThumb2Fmstat, 0xeef1fa10,
784 kFmtUnused, -1, -1, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
785 kFmtUnused, -1, -1, NO_OPERAND | SETS_CCODES,
786 "fmstat", "", 2),
787 ENCODING_MAP(kThumb2Vcmpd, 0xeeb40b40,
788 kFmtDfp, 22, 12, kFmtDfp, 5, 0, kFmtUnused, -1, -1,
789 kFmtUnused, -1, -1, IS_BINARY_OP | REG_USE01,
790 "vcmp.f64", "!0S, !1S", 2),
791 ENCODING_MAP(kThumb2Vcmps, 0xeeb40a40,
792 kFmtSfp, 22, 12, kFmtSfp, 5, 0, kFmtUnused, -1, -1,
793 kFmtUnused, -1, -1, IS_BINARY_OP | REG_USE01,
794 "vcmp.f32", "!0s, !1s", 2),
795 ENCODING_MAP(kThumb2LdrPcRel12, 0xf8df0000,
796 kFmtBitBlt, 15, 12, kFmtBitBlt, 11, 0, kFmtUnused, -1, -1,
797 kFmtUnused, -1, -1,
798 IS_TERTIARY_OP | REG_DEF0 | REG_USE_PC | IS_LOAD,
799 "ldr", "!0C, [r15pc, #!1d]", 2),
800 ENCODING_MAP(kThumb2BCond, 0xf0008000,
801 kFmtBrOffset, -1, -1, kFmtBitBlt, 25, 22, kFmtUnused, -1, -1,
802 kFmtUnused, -1, -1,
803 IS_BINARY_OP | IS_BRANCH | USES_CCODES,
804 "b!1c", "!0t", 2),
805 ENCODING_MAP(kThumb2Vmovd_RR, 0xeeb00b40,
806 kFmtDfp, 22, 12, kFmtDfp, 5, 0, kFmtUnused, -1, -1,
807 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
808 "vmov.f64", "!0S, !1S", 2),
809 ENCODING_MAP(kThumb2Vmovs_RR, 0xeeb00a40,
810 kFmtSfp, 22, 12, kFmtSfp, 5, 0, kFmtUnused, -1, -1,
811 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
812 "vmov.f32", "!0s, !1s", 2),
813 ENCODING_MAP(kThumb2Fmrs, 0xee100a10,
814 kFmtBitBlt, 15, 12, kFmtSfp, 7, 16, kFmtUnused, -1, -1,
815 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
816 "fmrs", "!0C, !1s", 2),
817 ENCODING_MAP(kThumb2Fmsr, 0xee000a10,
818 kFmtSfp, 7, 16, kFmtBitBlt, 15, 12, kFmtUnused, -1, -1,
819 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
820 "fmsr", "!0s, !1C", 2),
821 ENCODING_MAP(kThumb2Fmrrd, 0xec500b10,
822 kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtDfp, 5, 0,
823 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF01_USE2,
824 "fmrrd", "!0C, !1C, !2S", 2),
825 ENCODING_MAP(kThumb2Fmdrr, 0xec400b10,
826 kFmtDfp, 5, 0, kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16,
827 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
828 "fmdrr", "!0S, !1C, !2C", 2),
829 ENCODING_MAP(kThumb2Vabsd, 0xeeb00bc0,
830 kFmtDfp, 22, 12, kFmtDfp, 5, 0, kFmtUnused, -1, -1,
831 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
832 "vabs.f64", "!0S, !1S", 2),
833 ENCODING_MAP(kThumb2Vabss, 0xeeb00ac0,
834 kFmtSfp, 22, 12, kFmtSfp, 5, 0, kFmtUnused, -1, -1,
835 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
836 "vabs.f32", "!0s, !1s", 2),
837 ENCODING_MAP(kThumb2Vnegd, 0xeeb10b40,
838 kFmtDfp, 22, 12, kFmtDfp, 5, 0, kFmtUnused, -1, -1,
839 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
840 "vneg.f64", "!0S, !1S", 2),
841 ENCODING_MAP(kThumb2Vnegs, 0xeeb10a40,
842 kFmtSfp, 22, 12, kFmtSfp, 5, 0, kFmtUnused, -1, -1,
843 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
844 "vneg.f32", "!0s, !1s", 2),
845 ENCODING_MAP(kThumb2Vmovs_IMM8, 0xeeb00a00,
846 kFmtSfp, 22, 12, kFmtFPImm, 16, 0, kFmtUnused, -1, -1,
847 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0,
848 "vmov.f32", "!0s, #0x!1h", 2),
849 ENCODING_MAP(kThumb2Vmovd_IMM8, 0xeeb00b00,
850 kFmtDfp, 22, 12, kFmtFPImm, 16, 0, kFmtUnused, -1, -1,
851 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0,
852 "vmov.f64", "!0S, #0x!1h", 2),
853 ENCODING_MAP(kThumb2Mla, 0xfb000000,
854 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0,
855 kFmtBitBlt, 15, 12,
856 IS_QUAD_OP | REG_DEF0 | REG_USE1 | REG_USE2 | REG_USE3,
857 "mla", "!0C, !1C, !2C, !3C", 2),
858 ENCODING_MAP(kThumb2Umull, 0xfba00000,
859 kFmtBitBlt, 15, 12, kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16,
860 kFmtBitBlt, 3, 0,
861 IS_QUAD_OP | REG_DEF0 | REG_DEF1 | REG_USE2 | REG_USE3,
862 "umull", "!0C, !1C, !2C, !3C", 2),
863 ENCODING_MAP(kThumb2Ldrex, 0xe8500f00,
864 kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 7, 0,
865 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1 | IS_LOAD,
866 "ldrex", "!0C, [!1C, #!2E]", 2),
867 ENCODING_MAP(kThumb2Strex, 0xe8400000,
868 kFmtBitBlt, 11, 8, kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16,
869 kFmtBitBlt, 7, 0, IS_QUAD_OP | REG_DEF0_USE12 | IS_STORE,
870 "strex", "!0C,!1C, [!2C, #!2E]", 2),
871 ENCODING_MAP(kThumb2Clrex, 0xf3bf8f2f,
872 kFmtUnused, -1, -1, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
873 kFmtUnused, -1, -1, NO_OPERAND,
874 "clrex", "", 2),
875 ENCODING_MAP(kThumb2Bfi, 0xf3600000,
876 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtShift5, -1, -1,
877 kFmtBitBlt, 4, 0, IS_QUAD_OP | REG_DEF0_USE1,
878 "bfi", "!0C,!1C,#!2d,#!3d", 2),
879 ENCODING_MAP(kThumb2Bfc, 0xf36f0000,
880 kFmtBitBlt, 11, 8, kFmtShift5, -1, -1, kFmtBitBlt, 4, 0,
881 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0,
882 "bfc", "!0C,#!1d,#!2d", 2),
883 ENCODING_MAP(kThumb2Dmb, 0xf3bf8f50,
884 kFmtBitBlt, 3, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
885 kFmtUnused, -1, -1, IS_UNARY_OP,
886 "dmb","#!0B",2),
887 ENCODING_MAP(kThumb2LdrPcReln12, 0xf85f0000,
888 kFmtBitBlt, 15, 12, kFmtBitBlt, 11, 0, kFmtUnused, -1, -1,
889 kFmtUnused, -1, -1,
890 IS_BINARY_OP | REG_DEF0 | REG_USE_PC | IS_LOAD,
891 "ldr", "!0C, [r15pc, -#!1d]", 2),
892 ENCODING_MAP(kThumb2Stm, 0xe9000000,
893 kFmtBitBlt, 19, 16, kFmtBitBlt, 12, 0, kFmtUnused, -1, -1,
894 kFmtUnused, -1, -1,
895 IS_BINARY_OP | REG_USE0 | REG_USE_LIST1 | IS_STORE,
896 "stm", "!0C, <!1R>", 2),
897 ENCODING_MAP(kThumbUndefined, 0xde00,
898 kFmtUnused, -1, -1, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
899 kFmtUnused, -1, -1, NO_OPERAND,
900 "undefined", "", 1),
901 // NOTE: vpop, vpush hard-encoded for s16+ reg list
902 ENCODING_MAP(kThumb2VPopCS, 0xecbd8a00,
903 kFmtBitBlt, 7, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
904 kFmtUnused, -1, -1,
905 IS_UNARY_OP | REG_DEF_SP | REG_USE_SP | REG_DEF_FPCS_LIST0
906 | IS_LOAD, "vpop", "<!0P>", 2),
907 ENCODING_MAP(kThumb2VPushCS, 0xed2d8a00,
908 kFmtBitBlt, 7, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
909 kFmtUnused, -1, -1,
910 IS_UNARY_OP | REG_DEF_SP | REG_USE_SP | REG_USE_FPCS_LIST0
911 | IS_STORE, "vpush", "<!0P>", 2),
912 ENCODING_MAP(kThumb2Vldms, 0xec900a00,
913 kFmtBitBlt, 19, 16, kFmtSfp, 22, 12, kFmtBitBlt, 7, 0,
914 kFmtUnused, -1, -1,
915 IS_TERTIARY_OP | REG_USE0 | REG_DEF_FPCS_LIST2
916 | IS_LOAD, "vldms", "!0C, <!2Q>", 2),
917 ENCODING_MAP(kThumb2Vstms, 0xec800a00,
918 kFmtBitBlt, 19, 16, kFmtSfp, 22, 12, kFmtBitBlt, 7, 0,
919 kFmtUnused, -1, -1,
920 IS_TERTIARY_OP | REG_USE0 | REG_USE_FPCS_LIST2
921 | IS_STORE, "vstms", "!0C, <!2Q>", 2),
922 ENCODING_MAP(kThumb2BUncond, 0xf0009000,
923 kFmtOff24, -1, -1, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
924 kFmtUnused, -1, -1, NO_OPERAND | IS_BRANCH,
925 "b", "!0t", 2),
926 ENCODING_MAP(kThumb2MovImm16H, 0xf2c00000,
927 kFmtBitBlt, 11, 8, kFmtImm16, -1, -1, kFmtUnused, -1, -1,
928 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0,
929 "movh", "!0C, #!1M", 2),
930 ENCODING_MAP(kThumb2AddPCR, 0x4487,
931 kFmtBitBlt, 6, 3, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
932 kFmtUnused, -1, -1,
933 IS_UNARY_OP | REG_USE0 | IS_BRANCH,
934 "add", "rPC, !0C", 1),
935 ENCODING_MAP(kThumb2AdrST, 0xf20f0000,
936 kFmtBitBlt, 11, 8, kFmtImm12, -1, -1, kFmtUnused, -1, -1,
937 kFmtUnused, -1, -1,
938 IS_TERTIARY_OP | REG_DEF0,/* Note: doesn't affect flags */
939 "adr", "!0C,#!1d", 2),
940 ENCODING_MAP(kThumb2MovImm16LST, 0xf2400000,
941 kFmtBitBlt, 11, 8, kFmtImm16, -1, -1, kFmtUnused, -1, -1,
942 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0,
943 "mov", "!0C, #!1M", 2),
944 ENCODING_MAP(kThumb2MovImm16HST, 0xf2c00000,
945 kFmtBitBlt, 11, 8, kFmtImm16, -1, -1, kFmtUnused, -1, -1,
946 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0,
947 "movh", "!0C, #!1M", 2),
948 ENCODING_MAP(kThumb2LdmiaWB, 0xe8b00000,
949 kFmtBitBlt, 19, 16, kFmtBitBlt, 15, 0, kFmtUnused, -1, -1,
950 kFmtUnused, -1, -1,
951 IS_BINARY_OP | REG_DEF0_USE0 | REG_DEF_LIST1 | IS_LOAD,
952 "ldmia", "!0C!!, <!1R>", 2),
953 ENCODING_MAP(kThumb2SubsRRI12, 0xf1b00000,
954 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtImm12, -1, -1,
955 kFmtUnused, -1, -1,
956 IS_TERTIARY_OP | REG_DEF0_USE1 | SETS_CCODES,
957 "subs", "!0C,!1C,#!2d", 2),
958
959};
960
961/*
962 * The fake NOP of moving r0 to r0 actually will incur data stalls if r0 is
963 * not ready. Since r5FP is not updated often, it is less likely to
964 * generate unnecessary stall cycles.
965 * TUNING: No longer true - find new NOP pattern.
966 */
967#define PADDING_MOV_R5_R5 0x1C2D
968
buzbeec143c552011-08-20 17:38:58 -0700969static void pushWord(std::vector<short>&buf, int data) {
buzbeec143c552011-08-20 17:38:58 -0700970 buf.push_back( data & 0xffff);
buzbee9e0f9b02011-08-24 15:32:46 -0700971 buf.push_back( (data >> 16) & 0xffff);
buzbeec143c552011-08-20 17:38:58 -0700972}
973
974void alignBuffer(std::vector<short>&buf, size_t offset) {
975 while (buf.size() < (offset/2))
976 buf.push_back(0);
977}
978
buzbee67bf8852011-08-17 17:51:35 -0700979/* Write the numbers in the constant to the output stream */
980static void installLiteralPools(CompilationUnit* cUnit)
981{
buzbeec143c552011-08-20 17:38:58 -0700982 alignBuffer(cUnit->codeBuffer, cUnit->dataOffset);
buzbee67bf8852011-08-17 17:51:35 -0700983 ArmLIR* dataLIR = (ArmLIR*) cUnit->literalList;
984 while (dataLIR) {
buzbeec143c552011-08-20 17:38:58 -0700985 pushWord(cUnit->codeBuffer, dataLIR->operands[0]);
buzbee67bf8852011-08-17 17:51:35 -0700986 dataLIR = NEXT_LIR(dataLIR);
987 }
988}
989
990/* Write the switch tables to the output stream */
991static void installSwitchTables(CompilationUnit* cUnit)
992{
993 GrowableListIterator iterator;
994 oatGrowableListIteratorInit(&cUnit->switchTables, &iterator);
995 while (true) {
996 SwitchTable* tabRec = (SwitchTable *) oatGrowableListIteratorNext(
997 &iterator);
998 if (tabRec == NULL) break;
buzbeec143c552011-08-20 17:38:58 -0700999 alignBuffer(cUnit->codeBuffer, tabRec->offset);
buzbee67bf8852011-08-17 17:51:35 -07001000 int bxOffset = tabRec->bxInst->generic.offset + 4;
1001 if (cUnit->printMe) {
buzbee9e0f9b02011-08-24 15:32:46 -07001002 LOG(INFO) << "Switch table for offset 0x" << std::hex << bxOffset;
buzbee67bf8852011-08-17 17:51:35 -07001003 }
1004 if (tabRec->table[0] == kSparseSwitchSignature) {
1005 int* keys = (int*)&(tabRec->table[2]);
1006 for (int elems = 0; elems < tabRec->table[1]; elems++) {
1007 int disp = tabRec->targets[elems]->generic.offset - bxOffset;
1008 if (cUnit->printMe) {
1009 LOG(INFO) << " Case[" << elems << "] key: 0x" <<
1010 std::hex << keys[elems] << ", disp: 0x" <<
1011 std::hex << disp;
1012 }
buzbeec143c552011-08-20 17:38:58 -07001013 pushWord(cUnit->codeBuffer, keys[elems]);
1014 pushWord(cUnit->codeBuffer,
1015 tabRec->targets[elems]->generic.offset - bxOffset);
buzbee67bf8852011-08-17 17:51:35 -07001016 }
1017 } else {
1018 assert(tabRec->table[0] == kPackedSwitchSignature);
1019 for (int elems = 0; elems < tabRec->table[1]; elems++) {
1020 int disp = tabRec->targets[elems]->generic.offset - bxOffset;
1021 if (cUnit->printMe) {
1022 LOG(INFO) << " Case[" << elems << "] disp: 0x" <<
1023 std::hex << disp;
1024 }
buzbeec143c552011-08-20 17:38:58 -07001025 pushWord(cUnit->codeBuffer,
1026 tabRec->targets[elems]->generic.offset - bxOffset);
buzbee67bf8852011-08-17 17:51:35 -07001027 }
1028 }
1029 }
1030}
1031
1032/* Write the fill array dta to the output stream */
1033static void installFillArrayData(CompilationUnit* cUnit)
1034{
1035 GrowableListIterator iterator;
1036 oatGrowableListIteratorInit(&cUnit->fillArrayData, &iterator);
1037 while (true) {
1038 FillArrayData *tabRec = (FillArrayData *) oatGrowableListIteratorNext(
1039 &iterator);
1040 if (tabRec == NULL) break;
buzbeec143c552011-08-20 17:38:58 -07001041 alignBuffer(cUnit->codeBuffer, tabRec->offset);
1042 cUnit->codeBuffer.reserve(cUnit->codeBuffer.size() + (tabRec->size/2));
1043 memcpy(&cUnit->codeBuffer[tabRec->offset/2],
1044 (char*)tabRec->table, tabRec->size);
buzbee67bf8852011-08-17 17:51:35 -07001045 }
1046}
1047
1048/*
1049 * Assemble the LIR into binary instruction format. Note that we may
1050 * discover that pc-relative displacements may not fit the selected
1051 * instruction.
1052 */
1053static AssemblerStatus assembleInstructions(CompilationUnit* cUnit,
1054 intptr_t startAddr)
1055{
buzbee67bf8852011-08-17 17:51:35 -07001056 ArmLIR* lir;
1057 AssemblerStatus res = kSuccess; // Assume success
1058
1059 for (lir = (ArmLIR *) cUnit->firstLIRInsn; lir; lir = NEXT_LIR(lir)) {
1060 if (lir->opcode < 0) {
1061 if ((lir->opcode == kArmPseudoPseudoAlign4) &&
1062 /* 1 means padding is needed */
1063 (lir->operands[0] == 1)) {
buzbeec143c552011-08-20 17:38:58 -07001064 cUnit->codeBuffer.push_back(PADDING_MOV_R5_R5);
buzbee67bf8852011-08-17 17:51:35 -07001065 }
1066 continue;
1067 }
1068
1069 if (lir->flags.isNop) {
1070 continue;
1071 }
1072
1073 /*
1074 * For PC-relative displacements we won't know if the
1075 * selected instruction will work until late (i.e. - now).
1076 * If something doesn't fit, we must replace the short-form
1077 * operation with a longer-form one. Note, though, that this
1078 * can change code we've already processed, so we'll need to
1079 * re-calculate offsets and restart. To limit the number of
1080 * restarts, the entire list will be scanned and patched.
1081 * Of course, the patching itself may cause new overflows so this
1082 * is an iterative process.
1083 */
1084
1085 if (lir->opcode == kThumbLdrPcRel ||
1086 lir->opcode == kThumb2LdrPcRel12 ||
1087 lir->opcode == kThumbAddPcRel ||
1088 ((lir->opcode == kThumb2Vldrs) && (lir->operands[1] == r15pc))) {
1089 /*
1090 * PC-relative loads are mostly used to load immediates
1091 * that are too large to materialize directly in one shot.
1092 * However, if the load displacement exceeds the limit,
1093 * we revert to a 2-instruction materialization sequence.
1094 */
1095 ArmLIR *lirTarget = (ArmLIR *) lir->generic.target;
1096 intptr_t pc = (lir->generic.offset + 4) & ~3;
1097 intptr_t target = lirTarget->generic.offset;
1098 int delta = target - pc;
1099 if (delta & 0x3) {
1100 LOG(FATAL) << "PC-rel offset not multiple of 4: " << delta;
1101 }
1102 // First, a sanity check for cases we shouldn't see now
1103 if (((lir->opcode == kThumbAddPcRel) && (delta > 1020)) ||
1104 ((lir->opcode == kThumbLdrPcRel) && (delta > 1020))) {
1105 // Shouldn't happen in current codegen.
1106 LOG(FATAL) << "Unexpected pc-rel offset " << delta;
1107 }
1108 // Now, check for the two difficult cases
1109 if (1 || ((lir->opcode == kThumb2LdrPcRel12) && (delta > 4091)) ||
1110 ((lir->opcode == kThumb2Vldrs) && (delta > 1020))) {
1111 /*
1112 * OK - the load doesn't work. We'll just materialize
1113 * the immediate directly using mov16l and mov16h.
1114 * It's a little ugly for float immediates as we don't have
1115 * float ops like the core mov imm16H/L. In this case
1116 * we'll materialize in a core register (rLR) and then copy.
1117 * NOTE/WARNING: This is a *very* fragile workaround that will
1118 * be addressed in a later release when we have a late spill
1119 * capability. We can get away with it for now because rLR
1120 * is currently only used during call setups, and our convention
1121 * requires all arguments to be passed in core register & the
1122 * frame (and thus, we won't see any vlrds in the sequence).
1123 * The normal resource mask mechanism will prevent any damaging
1124 * code motion.
1125 */
1126 int tgtReg = (lir->opcode == kThumb2Vldrs) ? rLR :
1127 lir->operands[0];
1128 int immVal = lirTarget->operands[0];
1129 // The standard utilities won't work here - build manually
1130 ArmLIR *newMov16L =
1131 (ArmLIR *)oatNew(sizeof(ArmLIR), true);
1132 newMov16L->generic.dalvikOffset = lir->generic.dalvikOffset;
1133 newMov16L->opcode = kThumb2MovImm16;
1134 newMov16L->operands[0] = tgtReg;
1135 newMov16L->operands[1] = immVal & 0xffff;
1136 oatSetupResourceMasks(newMov16L);
1137 oatInsertLIRBefore((LIR*)lir, (LIR*)newMov16L);
1138 ArmLIR *newMov16H =
1139 (ArmLIR *)oatNew(sizeof(ArmLIR), true);
1140 newMov16H->generic.dalvikOffset = lir->generic.dalvikOffset;
1141 newMov16H->opcode = kThumb2MovImm16H;
1142 newMov16H->operands[0] = tgtReg;
1143 newMov16H->operands[1] = (immVal >> 16) & 0xffff;
1144 oatSetupResourceMasks(newMov16H);
1145 oatInsertLIRBefore((LIR*)lir, (LIR*)newMov16H);
1146 if (lir->opcode == kThumb2Vldrs) {
1147 // Convert the vldrs to a kThumb2Fmsr
1148 lir->opcode = kThumb2Fmsr;
1149 lir->operands[1] = rLR;
1150 lir->generic.target = NULL;
1151 lir->operands[2] = 0;
1152 oatSetupResourceMasks(lir);
1153 } else {
1154 // Nullify the original load
1155 lir->flags.isNop = true;
1156 }
1157 res = kRetryAll;
1158 } else {
1159 if (lir->opcode == kThumb2Vldrs) {
1160 lir->operands[2] = delta >> 2;
1161 } else {
1162 lir->operands[1] = (lir->opcode == kThumb2LdrPcRel12) ?
1163 delta : delta >> 2;
1164 }
1165 }
1166 } else if (lir->opcode == kThumb2Cbnz || lir->opcode == kThumb2Cbz) {
1167 ArmLIR *targetLIR = (ArmLIR *) lir->generic.target;
1168 intptr_t pc = lir->generic.offset + 4;
1169 intptr_t target = targetLIR->generic.offset;
1170 int delta = target - pc;
1171 if (delta > 126 || delta < 0) {
1172 /* Convert to cmp rx,#0 / b[eq/ne] tgt pair */
1173 ArmLIR *newInst =
1174 (ArmLIR *)oatNew(sizeof(ArmLIR), true);
1175 /* Make new branch instruction and insert after */
1176 newInst->generic.dalvikOffset = lir->generic.dalvikOffset;
1177 newInst->opcode = kThumbBCond;
1178 newInst->operands[0] = 0;
1179 newInst->operands[1] = (lir->opcode == kThumb2Cbz) ?
1180 kArmCondEq : kArmCondNe;
1181 newInst->generic.target = lir->generic.target;
1182 oatSetupResourceMasks(newInst);
1183 oatInsertLIRAfter((LIR *)lir, (LIR *)newInst);
1184 /* Convert the cb[n]z to a cmp rx, #0 ] */
1185 lir->opcode = kThumbCmpRI8;
1186 /* operand[0] is src1 in both cb[n]z & CmpRI8 */
1187 lir->operands[1] = 0;
1188 lir->generic.target = 0;
1189 oatSetupResourceMasks(lir);
1190 res = kRetryAll;
1191 } else {
1192 lir->operands[1] = delta >> 1;
1193 }
1194 } else if (lir->opcode == kThumbBCond ||
1195 lir->opcode == kThumb2BCond) {
1196 ArmLIR *targetLIR = (ArmLIR *) lir->generic.target;
buzbee7b1b86d2011-08-26 18:59:10 -07001197 int delta = 0;
1198 if (targetLIR == NULL) {
1199 UNIMPLEMENTED(WARNING) << "Throw targets unimplemented";
1200 } else {
1201 intptr_t pc = lir->generic.offset + 4;
1202 intptr_t target = targetLIR->generic.offset;
1203 delta = target - pc;
1204 if ((lir->opcode == kThumbBCond) && (delta > 254 || delta < -256)) {
1205 lir->opcode = kThumb2BCond;
1206 oatSetupResourceMasks(lir);
1207 res = kRetryAll;
1208 }
buzbee67bf8852011-08-17 17:51:35 -07001209 }
1210 lir->operands[0] = delta >> 1;
1211 } else if (lir->opcode == kThumb2BUncond) {
1212 ArmLIR *targetLIR = (ArmLIR *) lir->generic.target;
1213 intptr_t pc = lir->generic.offset + 4;
1214 intptr_t target = targetLIR->generic.offset;
1215 int delta = target - pc;
1216 lir->operands[0] = delta >> 1;
1217 if (lir->operands[0] == 0) { // Useless branch?
1218 lir->flags.isNop = true;
1219 res = kRetryAll;
1220 }
1221 } else if (lir->opcode == kThumbBUncond) {
1222 ArmLIR *targetLIR = (ArmLIR *) lir->generic.target;
1223 intptr_t pc = lir->generic.offset + 4;
1224 intptr_t target = targetLIR->generic.offset;
1225 int delta = target - pc;
1226 if (delta > 2046 || delta < -2048) {
1227 // Convert to Thumb2BCond w/ kArmCondAl
1228 lir->opcode = kThumb2BUncond;
1229 lir->operands[0] = 0;
1230 oatSetupResourceMasks(lir);
1231 res = kRetryAll;
1232 }
1233 lir->operands[0] = delta >> 1;
1234 if ((lir->operands[0] == 0) ||
1235 (lir->operands[0] == -1)) { // Useless branch?
1236 lir->flags.isNop = true;
1237 res = kRetryAll;
1238 }
1239 } else if (lir->opcode == kThumbBlx1) {
1240 assert(NEXT_LIR(lir)->opcode == kThumbBlx2);
1241 /* curPC is Thumb */
1242 intptr_t curPC = (startAddr + lir->generic.offset + 4) & ~3;
1243 intptr_t target = lir->operands[1];
1244
1245 /* Match bit[1] in target with base */
1246 if (curPC & 0x2) {
1247 target |= 0x2;
1248 }
1249 int delta = target - curPC;
1250 assert((delta >= -(1<<22)) && (delta <= ((1<<22)-2)));
1251
1252 lir->operands[0] = (delta >> 12) & 0x7ff;
1253 NEXT_LIR(lir)->operands[0] = (delta>> 1) & 0x7ff;
1254 } else if (lir->opcode == kThumbBl1) {
1255 assert(NEXT_LIR(lir)->opcode == kThumbBl2);
1256 /* Both curPC and target are Thumb */
1257 intptr_t curPC = startAddr + lir->generic.offset + 4;
1258 intptr_t target = lir->operands[1];
1259
1260 int delta = target - curPC;
1261 assert((delta >= -(1<<22)) && (delta <= ((1<<22)-2)));
1262
1263 lir->operands[0] = (delta >> 12) & 0x7ff;
1264 NEXT_LIR(lir)->operands[0] = (delta>> 1) & 0x7ff;
1265 } else if (lir->opcode == kThumb2AdrST) {
1266 SwitchTable *tabRec = (SwitchTable*)lir->operands[2];
1267 int disp = tabRec->offset - ((lir->generic.offset + 4) & ~3);
1268 if (disp < 4096) {
1269 lir->operands[1] = disp;
1270 } else {
1271 // convert to ldimm16l, ldimm16h, add tgt, pc, r12
1272 ArmLIR *newMov16L =
1273 (ArmLIR *)oatNew(sizeof(ArmLIR), true);
1274 newMov16L->generic.dalvikOffset = lir->generic.dalvikOffset;
1275 newMov16L->opcode = kThumb2MovImm16LST;
1276 newMov16L->operands[0] = lir->operands[0];
1277 newMov16L->operands[2] = (intptr_t)lir;
1278 newMov16L->operands[3] = (intptr_t)tabRec;
1279 oatSetupResourceMasks(newMov16L);
1280 oatInsertLIRBefore((LIR*)lir, (LIR*)newMov16L);
1281 ArmLIR *newMov16H =
1282 (ArmLIR *)oatNew(sizeof(ArmLIR), true);
1283 newMov16H->generic.dalvikOffset = lir->generic.dalvikOffset;
1284 newMov16H->opcode = kThumb2MovImm16HST;
1285 newMov16H->operands[0] = lir->operands[0];
1286 newMov16H->operands[2] = (intptr_t)lir;
1287 newMov16H->operands[3] = (intptr_t)tabRec;
1288 oatSetupResourceMasks(newMov16H);
1289 oatInsertLIRBefore((LIR*)lir, (LIR*)newMov16H);
1290 lir->opcode = kThumb2AddRRR;
1291 lir->operands[1] = rPC;
1292 lir->operands[2] = lir->operands[0];
1293 oatSetupResourceMasks(lir);
1294 res = kRetryAll;
1295 }
1296 } else if (lir->opcode == kThumb2MovImm16LST) {
1297 // operands[1] should hold disp, [2] has add, [3] has tabRec
1298 ArmLIR *addPCInst = (ArmLIR*)lir->operands[2];
1299 SwitchTable *tabRec = (SwitchTable*)lir->operands[3];
1300 lir->operands[1] = (tabRec->offset -
1301 ((addPCInst->generic.offset + 4) & ~3)) & 0xffff;
1302 } else if (lir->opcode == kThumb2MovImm16HST) {
1303 // operands[1] should hold disp, [2] has add, [3] has tabRec
1304 ArmLIR *addPCInst = (ArmLIR*)lir->operands[2];
1305 SwitchTable *tabRec = (SwitchTable*)lir->operands[3];
1306 lir->operands[1] = ((tabRec->offset -
1307 ((addPCInst->generic.offset + 4) & ~3)) >> 16) & 0xffff;
1308 }
1309 ArmEncodingMap *encoder = &EncodingMap[lir->opcode];
1310 u4 bits = encoder->skeleton;
1311 int i;
1312 for (i = 0; i < 4; i++) {
1313 u4 operand;
1314 u4 value;
1315 operand = lir->operands[i];
1316 switch(encoder->fieldLoc[i].kind) {
1317 case kFmtUnused:
1318 break;
1319 case kFmtFPImm:
1320 value = ((operand & 0xF0) >> 4) << encoder->fieldLoc[i].end;
1321 value |= (operand & 0x0F) << encoder->fieldLoc[i].start;
1322 bits |= value;
1323 break;
1324 case kFmtBrOffset:
1325 value = ((operand & 0x80000) >> 19) << 26;
1326 value |= ((operand & 0x40000) >> 18) << 11;
1327 value |= ((operand & 0x20000) >> 17) << 13;
1328 value |= ((operand & 0x1f800) >> 11) << 16;
1329 value |= (operand & 0x007ff);
1330 bits |= value;
1331 break;
1332 case kFmtShift5:
1333 value = ((operand & 0x1c) >> 2) << 12;
1334 value |= (operand & 0x03) << 6;
1335 bits |= value;
1336 break;
1337 case kFmtShift:
1338 value = ((operand & 0x70) >> 4) << 12;
1339 value |= (operand & 0x0f) << 4;
1340 bits |= value;
1341 break;
1342 case kFmtBWidth:
1343 value = operand - 1;
1344 bits |= value;
1345 break;
1346 case kFmtLsb:
1347 value = ((operand & 0x1c) >> 2) << 12;
1348 value |= (operand & 0x03) << 6;
1349 bits |= value;
1350 break;
1351 case kFmtImm6:
1352 value = ((operand & 0x20) >> 5) << 9;
1353 value |= (operand & 0x1f) << 3;
1354 bits |= value;
1355 break;
1356 case kFmtBitBlt:
1357 value = (operand << encoder->fieldLoc[i].start) &
1358 ((1 << (encoder->fieldLoc[i].end + 1)) - 1);
1359 bits |= value;
1360 break;
1361 case kFmtDfp: {
1362 assert(DOUBLEREG(operand));
1363 assert((operand & 0x1) == 0);
1364 int regName = (operand & FP_REG_MASK) >> 1;
1365 /* Snag the 1-bit slice and position it */
1366 value = ((regName & 0x10) >> 4) <<
1367 encoder->fieldLoc[i].end;
1368 /* Extract and position the 4-bit slice */
1369 value |= (regName & 0x0f) <<
1370 encoder->fieldLoc[i].start;
1371 bits |= value;
1372 break;
1373 }
1374 case kFmtSfp:
1375 assert(SINGLEREG(operand));
1376 /* Snag the 1-bit slice and position it */
1377 value = (operand & 0x1) <<
1378 encoder->fieldLoc[i].end;
1379 /* Extract and position the 4-bit slice */
1380 value |= ((operand & 0x1e) >> 1) <<
1381 encoder->fieldLoc[i].start;
1382 bits |= value;
1383 break;
1384 case kFmtImm12:
1385 case kFmtModImm:
1386 value = ((operand & 0x800) >> 11) << 26;
1387 value |= ((operand & 0x700) >> 8) << 12;
1388 value |= operand & 0x0ff;
1389 bits |= value;
1390 break;
1391 case kFmtImm16:
1392 value = ((operand & 0x0800) >> 11) << 26;
1393 value |= ((operand & 0xf000) >> 12) << 16;
1394 value |= ((operand & 0x0700) >> 8) << 12;
1395 value |= operand & 0x0ff;
1396 bits |= value;
1397 break;
1398 case kFmtOff24: {
1399 u4 signbit = (operand >> 31) & 0x1;
1400 u4 i1 = (operand >> 22) & 0x1;
1401 u4 i2 = (operand >> 21) & 0x1;
1402 u4 imm10 = (operand >> 11) & 0x03ff;
1403 u4 imm11 = operand & 0x07ff;
1404 u4 j1 = (i1 ^ signbit) ? 0 : 1;
1405 u4 j2 = (i2 ^ signbit) ? 0 : 1;
1406 value = (signbit << 26) | (j1 << 13) | (j2 << 11) |
1407 (imm10 << 16) | imm11;
1408 bits |= value;
1409 }
1410 break;
1411 default:
1412 assert(0);
1413 }
1414 }
1415 if (encoder->size == 2) {
buzbeec143c552011-08-20 17:38:58 -07001416 cUnit->codeBuffer.push_back((bits >> 16) & 0xffff);
buzbee67bf8852011-08-17 17:51:35 -07001417 }
buzbeec143c552011-08-20 17:38:58 -07001418 cUnit->codeBuffer.push_back(bits & 0xffff);
buzbee67bf8852011-08-17 17:51:35 -07001419 }
1420 return res;
1421}
1422
1423static int assignLiteralOffsetCommon(LIR* lir, int offset)
1424{
1425 for (;lir != NULL; lir = lir->next) {
1426 lir->offset = offset;
1427 offset += 4;
1428 }
1429 return offset;
1430}
1431
1432static int createMappingTable(CompilationUnit* cUnit, MappingTable** pTable)
1433{
1434 ArmLIR* armLIR;
1435 int currentDalvikOffset = -1;
1436 int count = 0;
1437
1438 for (armLIR = (ArmLIR *) cUnit->firstLIRInsn;
1439 armLIR;
1440 armLIR = NEXT_LIR(armLIR)) {
1441 if ((armLIR->opcode >= 0) && !armLIR->flags.isNop &&
1442 (currentDalvikOffset != armLIR->generic.dalvikOffset)) {
1443 // Changed - need to emit a record
1444 if (pTable) {
1445 MappingTable *table = *pTable;
1446 assert(table);
1447 table[count].targetOffset = armLIR->generic.offset;
1448 table[count].dalvikOffset = armLIR->generic.dalvikOffset;
1449 }
1450 count++;
1451 currentDalvikOffset = armLIR->generic.dalvikOffset;
1452 }
1453 }
1454 return count;
1455}
1456
1457/* Determine the offset of each literal field */
1458static int assignLiteralOffset(CompilationUnit* cUnit, int offset)
1459{
1460 offset = assignLiteralOffsetCommon(cUnit->literalList, offset);
1461 return offset;
1462}
1463
1464static int assignSwitchTablesOffset(CompilationUnit* cUnit, int offset)
1465{
1466 GrowableListIterator iterator;
1467 oatGrowableListIteratorInit(&cUnit->switchTables, &iterator);
1468 while (true) {
1469 SwitchTable *tabRec = (SwitchTable *) oatGrowableListIteratorNext(
1470 &iterator);
1471 if (tabRec == NULL) break;
1472 tabRec->offset = offset;
1473 if (tabRec->table[0] == kSparseSwitchSignature) {
1474 offset += tabRec->table[1] * (sizeof(int) * 2);
1475 } else {
1476 assert(tabRec->table[0] == kPackedSwitchSignature);
1477 offset += tabRec->table[1] * sizeof(int);
1478 }
1479 }
1480 return offset;
1481}
1482
1483static int assignFillArrayDataOffset(CompilationUnit* cUnit, int offset)
1484{
1485 GrowableListIterator iterator;
1486 oatGrowableListIteratorInit(&cUnit->fillArrayData, &iterator);
1487 while (true) {
1488 FillArrayData *tabRec = (FillArrayData *) oatGrowableListIteratorNext(
1489 &iterator);
1490 if (tabRec == NULL) break;
1491 tabRec->offset = offset;
1492 offset += tabRec->size;
1493 // word align
1494 offset = (offset + 3) & ~3;
1495 }
1496 return offset;
1497}
1498
1499/*
1500 * Walk the compilation unit and assign offsets to instructions
1501 * and literals and compute the total size of the compiled unit.
1502 */
1503void assignOffsets(CompilationUnit* cUnit)
1504{
1505 ArmLIR* armLIR;
1506 int offset = 0;
1507
1508 for (armLIR = (ArmLIR *) cUnit->firstLIRInsn;
1509 armLIR;
1510 armLIR = NEXT_LIR(armLIR)) {
1511 armLIR->generic.offset = offset;
1512 if (armLIR->opcode >= 0 && !armLIR->flags.isNop) {
1513 armLIR->flags.size = EncodingMap[armLIR->opcode].size * 2;
1514 offset += armLIR->flags.size;
1515 } else if (armLIR->opcode == kArmPseudoPseudoAlign4) {
1516 if (offset & 0x2) {
1517 offset += 2;
1518 armLIR->operands[0] = 1;
1519 } else {
1520 armLIR->operands[0] = 0;
1521 }
1522 }
1523 /* Pseudo opcodes don't consume space */
1524 }
1525
1526 /* Const values have to be word aligned */
1527 offset = (offset + 3) & ~3;
1528
1529 /* Set up offsets for literals */
1530 cUnit->dataOffset = offset;
1531
1532 offset = assignLiteralOffset(cUnit, offset);
1533
1534 offset = assignSwitchTablesOffset(cUnit, offset);
1535
1536 offset = assignFillArrayDataOffset(cUnit, offset);
1537
1538 cUnit->totalSize = offset;
1539}
1540/*
1541 * Go over each instruction in the list and calculate the offset from the top
1542 * before sending them off to the assembler. If out-of-range branch distance is
1543 * seen rearrange the instructions a bit to correct it.
1544 */
1545void oatAssembleLIR(CompilationUnit* cUnit)
1546{
1547 assignOffsets(cUnit);
buzbee67bf8852011-08-17 17:51:35 -07001548 /*
1549 * Assemble here. Note that we generate code with optimistic assumptions
1550 * and if found now to work, we'll have to redo the sequence and retry.
1551 */
1552
1553 while (true) {
1554 AssemblerStatus res = assembleInstructions(cUnit, NULL);
1555 if (res == kSuccess) {
1556 break;
1557 } else {
1558 cUnit->assemblerRetries++;
1559 if (cUnit->assemblerRetries > MAX_ASSEMBLER_RETRIES) {
1560 LOG(FATAL) << "Assembler error - too many retries";
1561 }
1562 // Redo offsets and try again
1563 assignOffsets(cUnit);
buzbeec143c552011-08-20 17:38:58 -07001564 cUnit->codeBuffer.clear();
buzbee67bf8852011-08-17 17:51:35 -07001565 }
1566 }
1567
1568 // Install literals
1569 installLiteralPools(cUnit);
1570
1571 // Install switch tables
1572 installSwitchTables(cUnit);
1573
1574 // Install fill array data
1575 installFillArrayData(cUnit);
1576
1577 /*
1578 * Create the mapping table
1579 */
1580 cUnit->mappingTableSize = createMappingTable(cUnit, NULL /* just count */);
1581 cUnit->mappingTable = (MappingTable*)oatNew(
1582 cUnit->mappingTableSize * sizeof(*cUnit->mappingTable), true);
1583 createMappingTable(cUnit, &cUnit->mappingTable);
1584}