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