1 /*
2 * Copyright (C) 2012 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 "codegen_mips.h"
18
19 #include "base/logging.h"
20 #include "dex/compiler_ir.h"
21 #include "dex/quick/mir_to_lir-inl.h"
22 #include "mips_lir.h"
23
24 namespace art {
25
26 #define MAX_ASSEMBLER_RETRIES 50
27
28 /*
29 * opcode: MipsOpCode enum
30 * skeleton: pre-designated bit-pattern for this opcode
31 * k0: key to applying ds/de
32 * ds: dest start bit position
33 * de: dest end bit position
34 * k1: key to applying s1s/s1e
35 * s1s: src1 start bit position
36 * s1e: src1 end bit position
37 * k2: key to applying s2s/s2e
38 * s2s: src2 start bit position
39 * s2e: src2 end bit position
40 * operands: number of operands (for sanity check purposes)
41 * name: mnemonic name
42 * fmt: for pretty-printing
43 */
44 #define ENCODING_MAP(opcode, skeleton, k0, ds, de, k1, s1s, s1e, k2, s2s, s2e, \
45 k3, k3s, k3e, flags, name, fmt, size) \
46 {skeleton, {{k0, ds, de}, {k1, s1s, s1e}, {k2, s2s, s2e}, \
47 {k3, k3s, k3e}}, opcode, flags, name, fmt, size}
48
49 /* Instruction dump string format keys: !pf, where "!" is the start
50 * of the key, "p" is which numeric operand to use and "f" is the
51 * print format.
52 *
53 * [p]ositions:
54 * 0 -> operands[0] (dest)
55 * 1 -> operands[1] (src1)
56 * 2 -> operands[2] (src2)
57 * 3 -> operands[3] (extra)
58 *
59 * [f]ormats:
60 * h -> 4-digit hex
61 * d -> decimal
62 * E -> decimal*4
63 * F -> decimal*2
64 * c -> branch condition (beq, bne, etc.)
65 * t -> pc-relative target
66 * T -> pc-region target
67 * u -> 1st half of bl[x] target
68 * v -> 2nd half ob bl[x] target
69 * R -> register list
70 * s -> single precision floating point register
71 * S -> double precision floating point register
72 * m -> Thumb2 modified immediate
73 * n -> complimented Thumb2 modified immediate
74 * M -> Thumb2 16-bit zero-extended immediate
75 * b -> 4-digit binary
76 * N -> append a NOP
77 *
78 * [!] escape. To insert "!", use "!!"
79 */
80 /* NOTE: must be kept in sync with enum MipsOpcode from mips_lir.h */
81 /*
82 * TUNING: We're currently punting on the branch delay slots. All branch
83 * instructions in this map are given a size of 8, which during assembly
84 * is expanded to include a nop. This scheme should be replaced with
85 * an assembler pass to fill those slots when possible.
86 */
87 const MipsEncodingMap MipsMir2Lir::EncodingMap[kMipsLast] = {
88 // The following are common mips32r2, mips32r6 and mips64r6 instructions.
89 ENCODING_MAP(kMips32BitData, 0x00000000,
90 kFmtBitBlt, 31, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
91 kFmtUnused, -1, -1, IS_UNARY_OP,
92 "data", "0x!0h(!0d)", 4),
93 ENCODING_MAP(kMipsAddiu, 0x24000000,
94 kFmtBitBlt, 20, 16, kFmtBitBlt, 25, 21, kFmtBitBlt, 15, 0,
95 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
96 "addiu", "!0r,!1r,0x!2h(!2d)", 4),
97 ENCODING_MAP(kMipsAddu, 0x00000021,
98 kFmtBitBlt, 15, 11, kFmtBitBlt, 25, 21, kFmtBitBlt, 20, 16,
99 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
100 "addu", "!0r,!1r,!2r", 4),
101 ENCODING_MAP(kMipsAnd, 0x00000024,
102 kFmtBitBlt, 15, 11, kFmtBitBlt, 25, 21, kFmtBitBlt, 20, 16,
103 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
104 "and", "!0r,!1r,!2r", 4),
105 ENCODING_MAP(kMipsAndi, 0x30000000,
106 kFmtBitBlt, 20, 16, kFmtBitBlt, 25, 21, kFmtBitBlt, 15, 0,
107 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
108 "andi", "!0r,!1r,0x!2h(!2d)", 4),
109 ENCODING_MAP(kMipsB, 0x10000000,
110 kFmtBitBlt, 15, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
111 kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH | NEEDS_FIXUP,
112 "b", "!0t!0N", 8),
113 ENCODING_MAP(kMipsBal, 0x04110000,
114 kFmtBitBlt, 15, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
115 kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH | REG_DEF_LR |
116 NEEDS_FIXUP, "bal", "!0t!0N", 8),
117 ENCODING_MAP(kMipsBeq, 0x10000000,
118 kFmtBitBlt, 25, 21, kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0,
119 kFmtUnused, -1, -1, IS_BINARY_OP | IS_BRANCH | REG_USE01 |
120 NEEDS_FIXUP, "beq", "!0r,!1r,!2t!0N", 8),
121 ENCODING_MAP(kMipsBeqz, 0x10000000, // Same as beq above with t = $zero.
122 kFmtBitBlt, 25, 21, kFmtBitBlt, 15, 0, kFmtUnused, -1, -1,
123 kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH | REG_USE0 |
124 NEEDS_FIXUP, "beqz", "!0r,!1t!0N", 8),
125 ENCODING_MAP(kMipsBgez, 0x04010000,
126 kFmtBitBlt, 25, 21, kFmtBitBlt, 15, 0, kFmtUnused, -1, -1,
127 kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH | REG_USE0 |
128 NEEDS_FIXUP, "bgez", "!0r,!1t!0N", 8),
129 ENCODING_MAP(kMipsBgtz, 0x1C000000,
130 kFmtBitBlt, 25, 21, kFmtBitBlt, 15, 0, kFmtUnused, -1, -1,
131 kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH | REG_USE0 |
132 NEEDS_FIXUP, "bgtz", "!0r,!1t!0N", 8),
133 ENCODING_MAP(kMipsBlez, 0x18000000,
134 kFmtBitBlt, 25, 21, kFmtBitBlt, 15, 0, kFmtUnused, -1, -1,
135 kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH | REG_USE0 |
136 NEEDS_FIXUP, "blez", "!0r,!1t!0N", 8),
137 ENCODING_MAP(kMipsBltz, 0x04000000,
138 kFmtBitBlt, 25, 21, kFmtBitBlt, 15, 0, kFmtUnused, -1, -1,
139 kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH | REG_USE0 |
140 NEEDS_FIXUP, "bltz", "!0r,!1t!0N", 8),
141 ENCODING_MAP(kMipsBnez, 0x14000000, // Same as bne below with t = $zero.
142 kFmtBitBlt, 25, 21, kFmtBitBlt, 15, 0, kFmtUnused, -1, -1,
143 kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH | REG_USE0 |
144 NEEDS_FIXUP, "bnez", "!0r,!1t!0N", 8),
145 ENCODING_MAP(kMipsBne, 0x14000000,
146 kFmtBitBlt, 25, 21, kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0,
147 kFmtUnused, -1, -1, IS_BINARY_OP | IS_BRANCH | REG_USE01 |
148 NEEDS_FIXUP, "bne", "!0r,!1r,!2t!0N", 8),
149 ENCODING_MAP(kMipsExt, 0x7c000000,
150 kFmtBitBlt, 20, 16, kFmtBitBlt, 25, 21, kFmtBitBlt, 10, 6,
151 kFmtBitBlt, 15, 11, IS_QUAD_OP | REG_DEF0 | REG_USE1,
152 "ext", "!0r,!1r,!2d,!3D", 4),
153 ENCODING_MAP(kMipsFaddd, 0x46200000,
154 kFmtDfp, 10, 6, kFmtDfp, 15, 11, kFmtDfp, 20, 16,
155 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
156 "add.d", "!0S,!1S,!2S", 4),
157 ENCODING_MAP(kMipsFadds, 0x46000000,
158 kFmtSfp, 10, 6, kFmtSfp, 15, 11, kFmtSfp, 20, 16,
159 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
160 "add.s", "!0s,!1s,!2s", 4),
161 ENCODING_MAP(kMipsFsubd, 0x46200001,
162 kFmtDfp, 10, 6, kFmtDfp, 15, 11, kFmtDfp, 20, 16,
163 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
164 "sub.d", "!0S,!1S,!2S", 4),
165 ENCODING_MAP(kMipsFsubs, 0x46000001,
166 kFmtSfp, 10, 6, kFmtSfp, 15, 11, kFmtSfp, 20, 16,
167 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
168 "sub.s", "!0s,!1s,!2s", 4),
169 ENCODING_MAP(kMipsFdivd, 0x46200003,
170 kFmtDfp, 10, 6, kFmtDfp, 15, 11, kFmtDfp, 20, 16,
171 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
172 "div.d", "!0S,!1S,!2S", 4),
173 ENCODING_MAP(kMipsFdivs, 0x46000003,
174 kFmtSfp, 10, 6, kFmtSfp, 15, 11, kFmtSfp, 20, 16,
175 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
176 "div.s", "!0s,!1s,!2s", 4),
177 ENCODING_MAP(kMipsFmuld, 0x46200002,
178 kFmtDfp, 10, 6, kFmtDfp, 15, 11, kFmtDfp, 20, 16,
179 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
180 "mul.d", "!0S,!1S,!2S", 4),
181 ENCODING_MAP(kMipsFmuls, 0x46000002,
182 kFmtSfp, 10, 6, kFmtSfp, 15, 11, kFmtSfp, 20, 16,
183 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
184 "mul.s", "!0s,!1s,!2s", 4),
185 ENCODING_MAP(kMipsFcvtsd, 0x46200020,
186 kFmtSfp, 10, 6, kFmtDfp, 15, 11, kFmtUnused, -1, -1,
187 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
188 "cvt.s.d", "!0s,!1S", 4),
189 ENCODING_MAP(kMipsFcvtsw, 0x46800020,
190 kFmtSfp, 10, 6, kFmtSfp, 15, 11, kFmtUnused, -1, -1,
191 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
192 "cvt.s.w", "!0s,!1s", 4),
193 ENCODING_MAP(kMipsFcvtds, 0x46000021,
194 kFmtDfp, 10, 6, kFmtSfp, 15, 11, kFmtUnused, -1, -1,
195 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
196 "cvt.d.s", "!0S,!1s", 4),
197 ENCODING_MAP(kMipsFcvtdw, 0x46800021,
198 kFmtDfp, 10, 6, kFmtSfp, 15, 11, kFmtUnused, -1, -1,
199 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
200 "cvt.d.w", "!0S,!1s", 4),
201 ENCODING_MAP(kMipsFcvtwd, 0x46200024,
202 kFmtSfp, 10, 6, kFmtDfp, 15, 11, kFmtUnused, -1, -1,
203 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
204 "cvt.w.d", "!0s,!1S", 4),
205 ENCODING_MAP(kMipsFcvtws, 0x46000024,
206 kFmtSfp, 10, 6, kFmtSfp, 15, 11, kFmtUnused, -1, -1,
207 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
208 "cvt.w.s", "!0s,!1s", 4),
209 ENCODING_MAP(kMipsFmovd, 0x46200006,
210 kFmtDfp, 10, 6, kFmtDfp, 15, 11, kFmtUnused, -1, -1,
211 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
212 "mov.d", "!0S,!1S", 4),
213 ENCODING_MAP(kMipsFmovs, 0x46000006,
214 kFmtSfp, 10, 6, kFmtSfp, 15, 11, kFmtUnused, -1, -1,
215 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
216 "mov.s", "!0s,!1s", 4),
217 ENCODING_MAP(kMipsFnegd, 0x46200007,
218 kFmtDfp, 10, 6, kFmtDfp, 15, 11, kFmtUnused, -1, -1,
219 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
220 "neg.d", "!0S,!1S", 4),
221 ENCODING_MAP(kMipsFnegs, 0x46000007,
222 kFmtSfp, 10, 6, kFmtSfp, 15, 11, kFmtUnused, -1, -1,
223 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
224 "neg.s", "!0s,!1s", 4),
225 ENCODING_MAP(kMipsFldc1, 0xd4000000,
226 kFmtDfp, 20, 16, kFmtBitBlt, 15, 0, kFmtBitBlt, 25, 21,
227 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE2 | IS_LOAD,
228 "ldc1", "!0S,!1d(!2r)", 4),
229 ENCODING_MAP(kMipsFlwc1, 0xc4000000,
230 kFmtSfp, 20, 16, kFmtBitBlt, 15, 0, kFmtBitBlt, 25, 21,
231 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE2 | IS_LOAD,
232 "lwc1", "!0s,!1d(!2r)", 4),
233 ENCODING_MAP(kMipsFsdc1, 0xf4000000,
234 kFmtDfp, 20, 16, kFmtBitBlt, 15, 0, kFmtBitBlt, 25, 21,
235 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE02 | IS_STORE,
236 "sdc1", "!0S,!1d(!2r)", 4),
237 ENCODING_MAP(kMipsFswc1, 0xe4000000,
238 kFmtSfp, 20, 16, kFmtBitBlt, 15, 0, kFmtBitBlt, 25, 21,
239 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE02 | IS_STORE,
240 "swc1", "!0s,!1d(!2r)", 4),
241 ENCODING_MAP(kMipsJal, 0x0c000000,
242 kFmtBitBlt, 25, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
243 kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH | REG_DEF_LR,
244 "jal", "!0T(!0E)!0N", 8),
245 ENCODING_MAP(kMipsJalr, 0x00000009,
246 kFmtBitBlt, 15, 11, kFmtBitBlt, 25, 21, kFmtUnused, -1, -1,
247 kFmtUnused, -1, -1, IS_BINARY_OP | IS_BRANCH | REG_DEF0_USE1,
248 "jalr", "!0r,!1r!0N", 8),
249 ENCODING_MAP(kMipsJr, 0x00000008,
250 kFmtBitBlt, 25, 21, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
251 kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH | REG_USE0 |
252 NEEDS_FIXUP, "jr", "!0r!0N", 8),
253 ENCODING_MAP(kMipsLahi, 0x3C000000,
254 kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0, kFmtUnused, -1, -1,
255 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0,
256 "lahi/lui", "!0r,0x!1h(!1d)", 4),
257 ENCODING_MAP(kMipsLalo, 0x34000000,
258 kFmtBitBlt, 20, 16, kFmtBitBlt, 25, 21, kFmtBitBlt, 15, 0,
259 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
260 "lalo/ori", "!0r,!1r,0x!2h(!2d)", 4),
261 ENCODING_MAP(kMipsLui, 0x3C000000,
262 kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0, kFmtUnused, -1, -1,
263 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0,
264 "lui", "!0r,0x!1h(!1d)", 4),
265 ENCODING_MAP(kMipsLb, 0x80000000,
266 kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0, kFmtBitBlt, 25, 21,
267 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE2 | IS_LOAD,
268 "lb", "!0r,!1d(!2r)", 4),
269 ENCODING_MAP(kMipsLbu, 0x90000000,
270 kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0, kFmtBitBlt, 25, 21,
271 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE2 | IS_LOAD,
272 "lbu", "!0r,!1d(!2r)", 4),
273 ENCODING_MAP(kMipsLh, 0x84000000,
274 kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0, kFmtBitBlt, 25, 21,
275 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE2 | IS_LOAD,
276 "lh", "!0r,!1d(!2r)", 4),
277 ENCODING_MAP(kMipsLhu, 0x94000000,
278 kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0, kFmtBitBlt, 25, 21,
279 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE2 | IS_LOAD,
280 "lhu", "!0r,!1d(!2r)", 4),
281 ENCODING_MAP(kMipsLw, 0x8C000000,
282 kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0, kFmtBitBlt, 25, 21,
283 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE2 | IS_LOAD,
284 "lw", "!0r,!1d(!2r)", 4),
285 ENCODING_MAP(kMipsMove, 0x00000025, // Or using zero reg.
286 kFmtBitBlt, 15, 11, kFmtBitBlt, 25, 21, kFmtUnused, -1, -1,
287 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
288 "move", "!0r,!1r", 4),
289 ENCODING_MAP(kMipsMfc1, 0x44000000,
290 kFmtBitBlt, 20, 16, kFmtSfp, 15, 11, kFmtUnused, -1, -1,
291 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
292 "mfc1", "!0r,!1s", 4),
293 ENCODING_MAP(kMipsMtc1, 0x44800000,
294 kFmtBitBlt, 20, 16, kFmtSfp, 15, 11, kFmtUnused, -1, -1,
295 kFmtUnused, -1, -1, IS_BINARY_OP | REG_USE0 | REG_DEF1,
296 "mtc1", "!0r,!1s", 4),
297 ENCODING_MAP(kMipsMfhc1, 0x44600000,
298 kFmtBitBlt, 20, 16, kFmtSfp, 15, 11, kFmtUnused, -1, -1,
299 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
300 "mfhc1", "!0r,!1s", 4),
301 ENCODING_MAP(kMipsMthc1, 0x44e00000,
302 kFmtBitBlt, 20, 16, kFmtSfp, 15, 11, kFmtUnused, -1, -1,
303 kFmtUnused, -1, -1, IS_BINARY_OP | REG_USE0 | REG_DEF1,
304 "mthc1", "!0r,!1s", 4),
305 ENCODING_MAP(kMipsNop, 0x00000000,
306 kFmtUnused, -1, -1, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
307 kFmtUnused, -1, -1, NO_OPERAND,
308 "nop", ";", 4),
309 ENCODING_MAP(kMipsNor, 0x00000027, // Used for "not" too.
310 kFmtBitBlt, 15, 11, kFmtBitBlt, 25, 21, kFmtBitBlt, 20, 16,
311 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
312 "nor", "!0r,!1r,!2r", 4),
313 ENCODING_MAP(kMipsOr, 0x00000025,
314 kFmtBitBlt, 15, 11, kFmtBitBlt, 25, 21, kFmtBitBlt, 20, 16,
315 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
316 "or", "!0r,!1r,!2r", 4),
317 ENCODING_MAP(kMipsOri, 0x34000000,
318 kFmtBitBlt, 20, 16, kFmtBitBlt, 25, 21, kFmtBitBlt, 15, 0,
319 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
320 "ori", "!0r,!1r,0x!2h(!2d)", 4),
321 ENCODING_MAP(kMipsPref, 0xCC000000,
322 kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0, kFmtBitBlt, 25, 21,
323 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE2,
324 "pref", "!0d,!1d(!2r)", 4),
325 ENCODING_MAP(kMipsSb, 0xA0000000,
326 kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0, kFmtBitBlt, 25, 21,
327 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE02 | IS_STORE,
328 "sb", "!0r,!1d(!2r)", 4),
329 ENCODING_MAP(kMipsSeb, 0x7c000420,
330 kFmtBitBlt, 15, 11, kFmtBitBlt, 20, 16, kFmtUnused, -1, -1,
331 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
332 "seb", "!0r,!1r", 4),
333 ENCODING_MAP(kMipsSeh, 0x7c000620,
334 kFmtBitBlt, 15, 11, kFmtBitBlt, 20, 16, kFmtUnused, -1, -1,
335 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
336 "seh", "!0r,!1r", 4),
337 ENCODING_MAP(kMipsSh, 0xA4000000,
338 kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0, kFmtBitBlt, 25, 21,
339 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE02 | IS_STORE,
340 "sh", "!0r,!1d(!2r)", 4),
341 ENCODING_MAP(kMipsSll, 0x00000000,
342 kFmtBitBlt, 15, 11, kFmtBitBlt, 20, 16, kFmtBitBlt, 10, 6,
343 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
344 "sll", "!0r,!1r,0x!2h(!2d)", 4),
345 ENCODING_MAP(kMipsSllv, 0x00000004,
346 kFmtBitBlt, 15, 11, kFmtBitBlt, 20, 16, kFmtBitBlt, 25, 21,
347 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
348 "sllv", "!0r,!1r,!2r", 4),
349 ENCODING_MAP(kMipsSlt, 0x0000002a,
350 kFmtBitBlt, 15, 11, kFmtBitBlt, 25, 21, kFmtBitBlt, 20, 16,
351 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
352 "slt", "!0r,!1r,!2r", 4),
353 ENCODING_MAP(kMipsSlti, 0x28000000,
354 kFmtBitBlt, 20, 16, kFmtBitBlt, 25, 21, kFmtBitBlt, 15, 0,
355 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
356 "slti", "!0r,!1r,0x!2h(!2d)", 4),
357 ENCODING_MAP(kMipsSltu, 0x0000002b,
358 kFmtBitBlt, 15, 11, kFmtBitBlt, 25, 21, kFmtBitBlt, 20, 16,
359 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
360 "sltu", "!0r,!1r,!2r", 4),
361 ENCODING_MAP(kMipsSra, 0x00000003,
362 kFmtBitBlt, 15, 11, kFmtBitBlt, 20, 16, kFmtBitBlt, 10, 6,
363 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
364 "sra", "!0r,!1r,0x!2h(!2d)", 4),
365 ENCODING_MAP(kMipsSrav, 0x00000007,
366 kFmtBitBlt, 15, 11, kFmtBitBlt, 20, 16, kFmtBitBlt, 25, 21,
367 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
368 "srav", "!0r,!1r,!2r", 4),
369 ENCODING_MAP(kMipsSrl, 0x00000002,
370 kFmtBitBlt, 15, 11, kFmtBitBlt, 20, 16, kFmtBitBlt, 10, 6,
371 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
372 "srl", "!0r,!1r,0x!2h(!2d)", 4),
373 ENCODING_MAP(kMipsSrlv, 0x00000006,
374 kFmtBitBlt, 15, 11, kFmtBitBlt, 20, 16, kFmtBitBlt, 25, 21,
375 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
376 "srlv", "!0r,!1r,!2r", 4),
377 ENCODING_MAP(kMipsSubu, 0x00000023, // Used for "neg" too.
378 kFmtBitBlt, 15, 11, kFmtBitBlt, 25, 21, kFmtBitBlt, 20, 16,
379 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
380 "subu", "!0r,!1r,!2r", 4),
381 ENCODING_MAP(kMipsSw, 0xAC000000,
382 kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0, kFmtBitBlt, 25, 21,
383 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE02 | IS_STORE,
384 "sw", "!0r,!1d(!2r)", 4),
385 ENCODING_MAP(kMipsSync, 0x0000000f,
386 kFmtBitBlt, 10, 6, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
387 kFmtUnused, -1, -1, IS_UNARY_OP,
388 "sync", ";", 4),
389 ENCODING_MAP(kMipsXor, 0x00000026,
390 kFmtBitBlt, 15, 11, kFmtBitBlt, 25, 21, kFmtBitBlt, 20, 16,
391 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
392 "xor", "!0r,!1r,!2r", 4),
393 ENCODING_MAP(kMipsXori, 0x38000000,
394 kFmtBitBlt, 20, 16, kFmtBitBlt, 25, 21, kFmtBitBlt, 15, 0,
395 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
396 "xori", "!0r,!1r,0x!2h(!2d)", 4),
397
398 // The following are mips32r2 instructions.
399 ENCODING_MAP(kMipsR2Div, 0x0000001a,
400 kFmtBitBlt, 25, 21, kFmtBitBlt, 20, 16, kFmtUnused, -1, -1,
401 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF_HI | REG_DEF_LO | REG_USE01,
402 "div", "!0r,!1r", 4),
403 ENCODING_MAP(kMipsR2Mul, 0x70000002,
404 kFmtBitBlt, 15, 11, kFmtBitBlt, 25, 21, kFmtBitBlt, 20, 16,
405 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
406 "mul", "!0r,!1r,!2r", 4),
407 ENCODING_MAP(kMipsR2Mfhi, 0x00000010,
408 kFmtBitBlt, 15, 11, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
409 kFmtUnused, -1, -1, IS_UNARY_OP | REG_DEF0 | REG_USE_HI,
410 "mfhi", "!0r", 4),
411 ENCODING_MAP(kMipsR2Mflo, 0x00000012,
412 kFmtBitBlt, 15, 11, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
413 kFmtUnused, -1, -1, IS_UNARY_OP | REG_DEF0 | REG_USE_LO,
414 "mflo", "!0r", 4),
415 ENCODING_MAP(kMipsR2Movz, 0x0000000a,
416 kFmtBitBlt, 15, 11, kFmtBitBlt, 25, 21, kFmtBitBlt, 20, 16,
417 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
418 "movz", "!0r,!1r,!2r", 4),
419
420 // The following are mips32r6 and mips64r6 instructions.
421 ENCODING_MAP(kMipsR6Div, 0x0000009a,
422 kFmtBitBlt, 15, 11, kFmtBitBlt, 25, 21, kFmtBitBlt, 20, 16,
423 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
424 "div", "!0r,!1r,!2r", 4),
425 ENCODING_MAP(kMipsR6Mod, 0x000000da,
426 kFmtBitBlt, 15, 11, kFmtBitBlt, 25, 21, kFmtBitBlt, 20, 16,
427 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
428 "mod", "!0r,!1r,!2r", 4),
429 ENCODING_MAP(kMipsR6Mul, 0x00000098,
430 kFmtBitBlt, 15, 11, kFmtBitBlt, 25, 21, kFmtBitBlt, 20, 16,
431 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
432 "mul", "!0r,!1r,!2r", 4),
433
434 // The following are mips64r6 instructions.
435 ENCODING_MAP(kMips64Daddiu, 0x64000000,
436 kFmtBitBlt, 20, 16, kFmtBitBlt, 25, 21, kFmtBitBlt, 15, 0,
437 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
438 "daddiu", "!0r,!1r,0x!2h(!2d)", 4),
439 ENCODING_MAP(kMips64Daddu, 0x0000002d,
440 kFmtBitBlt, 15, 11, kFmtBitBlt, 25, 21, kFmtBitBlt, 20, 16,
441 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
442 "daddu", "!0r,!1r,!2r", 4),
443 ENCODING_MAP(kMips64Dahi, 0x04060000,
444 kFmtBitBlt, 25, 21, kFmtBitBlt, 15, 0, kFmtUnused, -1, -1,
445 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE0,
446 "dahi", "!0r,0x!1h(!1d)", 4),
447 ENCODING_MAP(kMips64Dati, 0x041E0000,
448 kFmtBitBlt, 25, 21, kFmtBitBlt, 15, 0, kFmtUnused, -1, -1,
449 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE0,
450 "dati", "!0r,0x!1h(!1d)", 4),
451 ENCODING_MAP(kMips64Daui, 0x74000000,
452 kFmtBitBlt, 20, 16, kFmtBitBlt, 25, 21, kFmtBitBlt, 15, 0,
453 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
454 "daui", "!0r,!1r,0x!2h(!2d)", 4),
455 ENCODING_MAP(kMips64Ddiv, 0x0000009e,
456 kFmtBitBlt, 15, 11, kFmtBitBlt, 25, 21, kFmtBitBlt, 20, 16,
457 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
458 "ddiv", "!0r,!1r,!2r", 4),
459 ENCODING_MAP(kMips64Dmod, 0x000000de,
460 kFmtBitBlt, 15, 11, kFmtBitBlt, 25, 21, kFmtBitBlt, 20, 16,
461 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
462 "dmod", "!0r,!1r,!2r", 4),
463 ENCODING_MAP(kMips64Dmul, 0x0000009c,
464 kFmtBitBlt, 15, 11, kFmtBitBlt, 25, 21, kFmtBitBlt, 20, 16,
465 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
466 "dmul", "!0r,!1r,!2r", 4),
467 ENCODING_MAP(kMips64Dmfc1, 0x44200000,
468 kFmtBitBlt, 20, 16, kFmtDfp, 15, 11, kFmtUnused, -1, -1,
469 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
470 "dmfc1", "!0r,!1s", 4),
471 ENCODING_MAP(kMips64Dmtc1, 0x44a00000,
472 kFmtBitBlt, 20, 16, kFmtDfp, 15, 11, kFmtUnused, -1, -1,
473 kFmtUnused, -1, -1, IS_BINARY_OP | REG_USE0 | REG_DEF1,
474 "dmtc1", "!0r,!1s", 4),
475 ENCODING_MAP(kMips64Drotr32, 0x0000003e | (1 << 21),
476 kFmtBitBlt, 15, 11, kFmtBitBlt, 20, 16, kFmtBitBlt, 10, 6,
477 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
478 "drotr32", "!0r,!1r,0x!2h(!2d)", 4),
479 ENCODING_MAP(kMips64Dsll, 0x00000038,
480 kFmtBitBlt, 15, 11, kFmtBitBlt, 20, 16, kFmtBitBlt, 10, 6,
481 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
482 "dsll", "!0r,!1r,0x!2h(!2d)", 4),
483 ENCODING_MAP(kMips64Dsll32, 0x0000003c,
484 kFmtBitBlt, 15, 11, kFmtBitBlt, 20, 16, kFmtBitBlt, 10, 6,
485 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
486 "dsll32", "!0r,!1r,0x!2h(!2d)", 4),
487 ENCODING_MAP(kMips64Dsrl, 0x0000003a,
488 kFmtBitBlt, 15, 11, kFmtBitBlt, 20, 16, kFmtBitBlt, 10, 6,
489 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
490 "dsrl", "!0r,!1r,0x!2h(!2d)", 4),
491 ENCODING_MAP(kMips64Dsrl32, 0x0000003e,
492 kFmtBitBlt, 15, 11, kFmtBitBlt, 20, 16, kFmtBitBlt, 10, 6,
493 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
494 "dsrl32", "!0r,!1r,0x!2h(!2d)", 4),
495 ENCODING_MAP(kMips64Dsra, 0x0000003b,
496 kFmtBitBlt, 15, 11, kFmtBitBlt, 20, 16, kFmtBitBlt, 10, 6,
497 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
498 "dsra", "!0r,!1r,0x!2h(!2d)", 4),
499 ENCODING_MAP(kMips64Dsra32, 0x0000003f,
500 kFmtBitBlt, 15, 11, kFmtBitBlt, 20, 16, kFmtBitBlt, 10, 6,
501 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
502 "dsra32", "!0r,!1r,0x!2h(!2d)", 4),
503 ENCODING_MAP(kMips64Dsllv, 0x00000014,
504 kFmtBitBlt, 15, 11, kFmtBitBlt, 20, 16, kFmtBitBlt, 25, 21,
505 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
506 "dsllv", "!0r,!1r,!2r", 4),
507 ENCODING_MAP(kMips64Dsrlv, 0x00000016,
508 kFmtBitBlt, 15, 11, kFmtBitBlt, 20, 16, kFmtBitBlt, 25, 21,
509 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
510 "dsrlv", "!0r,!1r,!2r", 4),
511 ENCODING_MAP(kMips64Dsrav, 0x00000017,
512 kFmtBitBlt, 15, 11, kFmtBitBlt, 20, 16, kFmtBitBlt, 25, 21,
513 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
514 "dsrav", "!0r,!1r,!2r", 4),
515 ENCODING_MAP(kMips64Dsubu, 0x0000002f,
516 kFmtBitBlt, 15, 11, kFmtBitBlt, 25, 21, kFmtBitBlt, 20, 16,
517 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
518 "dsubu", "!0r,!1r,!2r", 4),
519 ENCODING_MAP(kMips64Ld, 0xdc000000,
520 kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0, kFmtBitBlt, 25, 21,
521 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE2 | IS_LOAD,
522 "ld", "!0r,!1d(!2r)", 4),
523 ENCODING_MAP(kMips64Lwu, 0x9c000000,
524 kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0, kFmtBitBlt, 25, 21,
525 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE2 | IS_LOAD,
526 "lwu", "!0r,!1d(!2r)", 4),
527 ENCODING_MAP(kMips64Sd, 0xfc000000,
528 kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0, kFmtBitBlt, 25, 21,
529 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE02 | IS_STORE,
530 "sd", "!0r,!1d(!2r)", 4),
531
532 // The following are pseudoinstructions.
533 ENCODING_MAP(kMipsDelta, 0x27e00000, // It is implemented as daddiu for mips64.
534 kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0, kFmtUnused, 15, 0,
535 kFmtUnused, -1, -1, IS_QUAD_OP | REG_DEF0 | REG_USE_LR |
536 NEEDS_FIXUP, "addiu", "!0r,ra,0x!1h(!1d)", 4),
537 ENCODING_MAP(kMipsDeltaHi, 0x3C000000,
538 kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0, kFmtUnused, -1, -1,
539 kFmtUnused, -1, -1, IS_QUAD_OP | REG_DEF0 | NEEDS_FIXUP,
540 "lui", "!0r,0x!1h(!1d)", 4),
541 ENCODING_MAP(kMipsDeltaLo, 0x34000000,
542 kFmtBlt5_2, 16, 21, kFmtBitBlt, 15, 0, kFmtUnused, -1, -1,
543 kFmtUnused, -1, -1, IS_QUAD_OP | REG_DEF0_USE0 | NEEDS_FIXUP,
544 "ori", "!0r,!0r,0x!1h(!1d)", 4),
545 ENCODING_MAP(kMipsCurrPC, 0x04110001,
546 kFmtUnused, -1, -1, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
547 kFmtUnused, -1, -1, NO_OPERAND | IS_BRANCH | REG_DEF_LR,
548 "addiu", "ra,pc,8", 4),
549 ENCODING_MAP(kMipsUndefined, 0x64000000,
550 kFmtUnused, -1, -1, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
551 kFmtUnused, -1, -1, NO_OPERAND,
552 "undefined", "", 4),
553 };
554
555
556 /*
557 * Convert a short-form branch to long form. Hopefully, this won't happen
558 * very often because the PIC sequence is especially unfortunate.
559 *
560 * Orig conditional branch
561 * -----------------------
562 * beq rs,rt,target
563 *
564 * Long conditional branch
565 * -----------------------
566 * bne rs,rt,hop
567 * bal .+8 ; rRA <- anchor
568 * lui rAT, ((target-anchor) >> 16)
569 * anchor:
570 * ori rAT, rAT, ((target-anchor) & 0xffff)
571 * addu rAT, rAT, rRA
572 * jalr rZERO, rAT
573 * hop:
574 *
575 * Orig unconditional branch
576 * -------------------------
577 * b target
578 *
579 * Long unconditional branch
580 * -----------------------
581 * bal .+8 ; rRA <- anchor
582 * lui rAT, ((target-anchor) >> 16)
583 * anchor:
584 * ori rAT, rAT, ((target-anchor) & 0xffff)
585 * addu rAT, rAT, rRA
586 * jalr rZERO, rAT
587 *
588 *
589 * NOTE: An out-of-range bal isn't supported because it should
590 * never happen with the current PIC model.
591 */
ConvertShortToLongBranch(LIR * lir)592 void MipsMir2Lir::ConvertShortToLongBranch(LIR* lir) {
593 // For conditional branches we'll need to reverse the sense
594 bool unconditional = false;
595 int opcode = lir->opcode;
596 int dalvik_offset = lir->dalvik_offset;
597 switch (opcode) {
598 case kMipsBal:
599 LOG(FATAL) << "long branch and link unsupported";
600 UNREACHABLE();
601 case kMipsB:
602 unconditional = true;
603 break;
604 case kMipsBeq: opcode = kMipsBne; break;
605 case kMipsBne: opcode = kMipsBeq; break;
606 case kMipsBeqz: opcode = kMipsBnez; break;
607 case kMipsBgez: opcode = kMipsBltz; break;
608 case kMipsBgtz: opcode = kMipsBlez; break;
609 case kMipsBlez: opcode = kMipsBgtz; break;
610 case kMipsBltz: opcode = kMipsBgez; break;
611 case kMipsBnez: opcode = kMipsBeqz; break;
612 default:
613 LOG(FATAL) << "Unexpected branch kind " << opcode;
614 UNREACHABLE();
615 }
616 LIR* hop_target = nullptr;
617 if (!unconditional) {
618 hop_target = RawLIR(dalvik_offset, kPseudoTargetLabel);
619 LIR* hop_branch = RawLIR(dalvik_offset, opcode, lir->operands[0],
620 lir->operands[1], 0, 0, 0, hop_target);
621 InsertLIRBefore(lir, hop_branch);
622 }
623 LIR* curr_pc = RawLIR(dalvik_offset, kMipsCurrPC);
624 InsertLIRBefore(lir, curr_pc);
625 LIR* anchor = RawLIR(dalvik_offset, kPseudoTargetLabel);
626 LIR* delta_hi = RawLIR(dalvik_offset, kMipsDeltaHi, rAT, 0, WrapPointer(anchor), 0, 0,
627 lir->target);
628 InsertLIRBefore(lir, delta_hi);
629 InsertLIRBefore(lir, anchor);
630 LIR* delta_lo = RawLIR(dalvik_offset, kMipsDeltaLo, rAT, 0, WrapPointer(anchor), 0, 0,
631 lir->target);
632 InsertLIRBefore(lir, delta_lo);
633 LIR* addu = RawLIR(dalvik_offset, kMipsAddu, rAT, rAT, rRA);
634 InsertLIRBefore(lir, addu);
635 LIR* jalr = RawLIR(dalvik_offset, kMipsJalr, rZERO, rAT);
636 InsertLIRBefore(lir, jalr);
637 if (!unconditional) {
638 InsertLIRBefore(lir, hop_target);
639 }
640 NopLIR(lir);
641 }
642
643 /*
644 * Assemble the LIR into binary instruction format. Note that we may
645 * discover that pc-relative displacements may not fit the selected
646 * instruction. In those cases we will try to substitute a new code
647 * sequence or request that the trace be shortened and retried.
648 */
AssembleInstructions(CodeOffset start_addr)649 AssemblerStatus MipsMir2Lir::AssembleInstructions(CodeOffset start_addr) {
650 LIR *lir;
651 AssemblerStatus res = kSuccess; // Assume success.
652
653 for (lir = first_lir_insn_; lir != nullptr; lir = NEXT_LIR(lir)) {
654 if (lir->opcode < 0) {
655 continue;
656 }
657
658 if (lir->flags.is_nop) {
659 continue;
660 }
661
662 if (lir->flags.fixup != kFixupNone) {
663 if (lir->opcode == kMipsDelta) {
664 /*
665 * The "Delta" pseudo-ops load the difference between
666 * two pc-relative locations into a the target register
667 * found in operands[0]. The delta is determined by
668 * (label2 - label1), where label1 is a standard
669 * kPseudoTargetLabel and is stored in operands[2].
670 * If operands[3] is null, then label2 is a kPseudoTargetLabel
671 * and is found in lir->target. If operands[3] is non-nullptr,
672 * then it is a Switch/Data table.
673 */
674 int offset1 = UnwrapPointer<LIR>(lir->operands[2])->offset;
675 const EmbeddedData* tab_rec = UnwrapPointer<EmbeddedData>(lir->operands[3]);
676 int offset2 = tab_rec ? tab_rec->offset : lir->target->offset;
677 int delta = offset2 - offset1;
678 if ((delta & 0xffff) == delta && ((delta & 0x8000) == 0)) {
679 // Fits.
680 lir->operands[1] = delta;
681 if (cu_->target64) {
682 LIR *new_addiu = RawLIR(lir->dalvik_offset, kMips64Daddiu, lir->operands[0], rRAd,
683 delta);
684 InsertLIRBefore(lir, new_addiu);
685 NopLIR(lir);
686 res = kRetryAll;
687 }
688 } else {
689 // Doesn't fit - must expand to kMipsDelta[Hi|Lo] pair.
690 LIR *new_delta_hi = RawLIR(lir->dalvik_offset, kMipsDeltaHi, lir->operands[0], 0,
691 lir->operands[2], lir->operands[3], 0, lir->target);
692 InsertLIRBefore(lir, new_delta_hi);
693 LIR *new_delta_lo = RawLIR(lir->dalvik_offset, kMipsDeltaLo, lir->operands[0], 0,
694 lir->operands[2], lir->operands[3], 0, lir->target);
695 InsertLIRBefore(lir, new_delta_lo);
696 LIR *new_addu;
697 if (cu_->target64) {
698 new_addu = RawLIR(lir->dalvik_offset, kMips64Daddu, lir->operands[0], lir->operands[0],
699 rRAd);
700 } else {
701 new_addu = RawLIR(lir->dalvik_offset, kMipsAddu, lir->operands[0], lir->operands[0],
702 rRA);
703 }
704 InsertLIRBefore(lir, new_addu);
705 NopLIR(lir);
706 res = kRetryAll;
707 }
708 } else if (lir->opcode == kMipsDeltaLo) {
709 int offset1 = UnwrapPointer<LIR>(lir->operands[2])->offset;
710 const EmbeddedData* tab_rec = UnwrapPointer<EmbeddedData>(lir->operands[3]);
711 int offset2 = tab_rec ? tab_rec->offset : lir->target->offset;
712 int delta = offset2 - offset1;
713 lir->operands[1] = delta & 0xffff;
714 } else if (lir->opcode == kMipsDeltaHi) {
715 int offset1 = UnwrapPointer<LIR>(lir->operands[2])->offset;
716 const EmbeddedData* tab_rec = UnwrapPointer<EmbeddedData>(lir->operands[3]);
717 int offset2 = tab_rec ? tab_rec->offset : lir->target->offset;
718 int delta = offset2 - offset1;
719 lir->operands[1] = (delta >> 16) & 0xffff;
720 } else if (lir->opcode == kMipsB || lir->opcode == kMipsBal) {
721 LIR *target_lir = lir->target;
722 CodeOffset pc = lir->offset + 4;
723 CodeOffset target = target_lir->offset;
724 int delta = target - pc;
725 if (delta & 0x3) {
726 LOG(FATAL) << "PC-rel offset not multiple of 4: " << delta;
727 }
728 if (delta > 131068 || delta < -131069) {
729 res = kRetryAll;
730 ConvertShortToLongBranch(lir);
731 } else {
732 lir->operands[0] = delta >> 2;
733 }
734 } else if (lir->opcode >= kMipsBeqz && lir->opcode <= kMipsBnez) {
735 LIR *target_lir = lir->target;
736 CodeOffset pc = lir->offset + 4;
737 CodeOffset target = target_lir->offset;
738 int delta = target - pc;
739 if (delta & 0x3) {
740 LOG(FATAL) << "PC-rel offset not multiple of 4: " << delta;
741 }
742 if (delta > 131068 || delta < -131069) {
743 res = kRetryAll;
744 ConvertShortToLongBranch(lir);
745 } else {
746 lir->operands[1] = delta >> 2;
747 }
748 } else if (lir->opcode == kMipsBeq || lir->opcode == kMipsBne) {
749 LIR *target_lir = lir->target;
750 CodeOffset pc = lir->offset + 4;
751 CodeOffset target = target_lir->offset;
752 int delta = target - pc;
753 if (delta & 0x3) {
754 LOG(FATAL) << "PC-rel offset not multiple of 4: " << delta;
755 }
756 if (delta > 131068 || delta < -131069) {
757 res = kRetryAll;
758 ConvertShortToLongBranch(lir);
759 } else {
760 lir->operands[2] = delta >> 2;
761 }
762 } else if (lir->opcode == kMipsJal) {
763 CodeOffset cur_pc = (start_addr + lir->offset + 4) & ~3;
764 CodeOffset target = lir->operands[0];
765 /* ensure PC-region branch can be used */
766 DCHECK_EQ((cur_pc & 0xF0000000), (target & 0xF0000000));
767 if (target & 0x3) {
768 LOG(FATAL) << "Jump target not multiple of 4: " << target;
769 }
770 lir->operands[0] = target >> 2;
771 } else if (lir->opcode == kMipsLahi) { /* ld address hi (via lui) */
772 LIR *target_lir = lir->target;
773 CodeOffset target = start_addr + target_lir->offset;
774 lir->operands[1] = target >> 16;
775 } else if (lir->opcode == kMipsLalo) { /* ld address lo (via ori) */
776 LIR *target_lir = lir->target;
777 CodeOffset target = start_addr + target_lir->offset;
778 lir->operands[2] = lir->operands[2] + target;
779 }
780 }
781
782 /*
783 * If one of the pc-relative instructions expanded we'll have
784 * to make another pass. Don't bother to fully assemble the
785 * instruction.
786 */
787 if (res != kSuccess) {
788 continue;
789 }
790 DCHECK(!IsPseudoLirOp(lir->opcode));
791 const MipsEncodingMap *encoder = &EncodingMap[lir->opcode];
792 uint32_t bits = encoder->skeleton;
793 int i;
794 for (i = 0; i < 4; i++) {
795 uint32_t operand;
796 uint32_t value;
797 operand = lir->operands[i];
798 switch (encoder->field_loc[i].kind) {
799 case kFmtUnused:
800 break;
801 case kFmtBitBlt:
802 if (encoder->field_loc[i].start == 0 && encoder->field_loc[i].end == 31) {
803 value = operand;
804 } else {
805 value = (operand << encoder->field_loc[i].start) &
806 ((1 << (encoder->field_loc[i].end + 1)) - 1);
807 }
808 bits |= value;
809 break;
810 case kFmtBlt5_2:
811 value = (operand & 0x1f);
812 bits |= (value << encoder->field_loc[i].start);
813 bits |= (value << encoder->field_loc[i].end);
814 break;
815 case kFmtDfp: {
816 // TODO: do we need to adjust now that we're using 64BitSolo?
817 DCHECK(RegStorage::IsDouble(operand)) << ", Operand = 0x" << std::hex << operand;
818 if (!cu_->target64) {
819 DCHECK_EQ((operand & 0x1), 0U); // May only use even numbered registers for mips32.
820 }
821 value = (RegStorage::RegNum(operand) << encoder->field_loc[i].start) &
822 ((1 << (encoder->field_loc[i].end + 1)) - 1);
823 bits |= value;
824 break;
825 }
826 case kFmtSfp:
827 DCHECK(RegStorage::IsSingle(operand)) << ", Operand = 0x" << std::hex << operand;
828 value = (RegStorage::RegNum(operand) << encoder->field_loc[i].start) &
829 ((1 << (encoder->field_loc[i].end + 1)) - 1);
830 bits |= value;
831 break;
832 default:
833 LOG(FATAL) << "Bad encoder format: " << encoder->field_loc[i].kind;
834 }
835 }
836 // We only support little-endian MIPS.
837 code_buffer_.push_back(bits & 0xff);
838 code_buffer_.push_back((bits >> 8) & 0xff);
839 code_buffer_.push_back((bits >> 16) & 0xff);
840 code_buffer_.push_back((bits >> 24) & 0xff);
841 // TUNING: replace with proper delay slot handling.
842 if (encoder->size == 8) {
843 DCHECK(!IsPseudoLirOp(lir->opcode));
844 const MipsEncodingMap *encoder2 = &EncodingMap[kMipsNop];
845 uint32_t bits2 = encoder2->skeleton;
846 code_buffer_.push_back(bits2 & 0xff);
847 code_buffer_.push_back((bits2 >> 8) & 0xff);
848 code_buffer_.push_back((bits2 >> 16) & 0xff);
849 code_buffer_.push_back((bits2 >> 24) & 0xff);
850 }
851 }
852 return res;
853 }
854
GetInsnSize(LIR * lir)855 size_t MipsMir2Lir::GetInsnSize(LIR* lir) {
856 DCHECK(!IsPseudoLirOp(lir->opcode));
857 return EncodingMap[lir->opcode].size;
858 }
859
860 // LIR offset assignment.
861 // TODO: consolidate w/ Arm assembly mechanism.
AssignInsnOffsets()862 int MipsMir2Lir::AssignInsnOffsets() {
863 LIR* lir;
864 int offset = 0;
865
866 for (lir = first_lir_insn_; lir != nullptr; lir = NEXT_LIR(lir)) {
867 lir->offset = offset;
868 if (LIKELY(lir->opcode >= 0)) {
869 if (!lir->flags.is_nop) {
870 offset += lir->flags.size;
871 }
872 } else if (UNLIKELY(lir->opcode == kPseudoPseudoAlign4)) {
873 if (offset & 0x2) {
874 offset += 2;
875 lir->operands[0] = 1;
876 } else {
877 lir->operands[0] = 0;
878 }
879 }
880 // Pseudo opcodes don't consume space.
881 }
882 return offset;
883 }
884
885 /*
886 * Walk the compilation unit and assign offsets to instructions
887 * and literals and compute the total size of the compiled unit.
888 * TODO: consolidate w/ Arm assembly mechanism.
889 */
AssignOffsets()890 void MipsMir2Lir::AssignOffsets() {
891 int offset = AssignInsnOffsets();
892
893 // Const values have to be word aligned.
894 offset = RoundUp(offset, 4);
895
896 // Set up offsets for literals.
897 data_offset_ = offset;
898
899 offset = AssignLiteralOffset(offset);
900
901 offset = AssignSwitchTablesOffset(offset);
902
903 offset = AssignFillArrayDataOffset(offset);
904
905 total_size_ = offset;
906 }
907
908 /*
909 * Go over each instruction in the list and calculate the offset from the top
910 * before sending them off to the assembler. If out-of-range branch distance is
911 * seen rearrange the instructions a bit to correct it.
912 * TODO: consolidate w/ Arm assembly mechanism.
913 */
AssembleLIR()914 void MipsMir2Lir::AssembleLIR() {
915 cu_->NewTimingSplit("Assemble");
916 AssignOffsets();
917 int assembler_retries = 0;
918 /*
919 * Assemble here. Note that we generate code with optimistic assumptions
920 * and if found now to work, we'll have to redo the sequence and retry.
921 */
922
923 while (true) {
924 AssemblerStatus res = AssembleInstructions(0);
925 if (res == kSuccess) {
926 break;
927 } else {
928 assembler_retries++;
929 if (assembler_retries > MAX_ASSEMBLER_RETRIES) {
930 CodegenDump();
931 LOG(FATAL) << "Assembler error - too many retries";
932 }
933 // Redo offsets and try again.
934 AssignOffsets();
935 code_buffer_.clear();
936 }
937 }
938
939 // Install literals.
940 InstallLiteralPools();
941
942 // Install switch tables.
943 InstallSwitchTables();
944
945 // Install fill array data.
946 InstallFillArrayData();
947
948 // Create the mapping table and native offset to reference map.
949 cu_->NewTimingSplit("PcMappingTable");
950 CreateMappingTables();
951
952 cu_->NewTimingSplit("GcMap");
953 CreateNativeGcMap();
954 }
955
956 } // namespace art
957