blob: cb355c0b317b4e818a36018c2115f10ab8d7b247 [file] [log] [blame]
buzbeee3acd072012-02-25 17:03:10 -08001/*
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 "../../Dalvik.h"
18#include "../../CompilerInternals.h"
19#include "MipsLIR.h"
20#include "Codegen.h"
21#include <sys/mman.h> /* for protection change */
22
23namespace art {
24
25#define MAX_ASSEMBLER_RETRIES 50
26
27/*
28 * opcode: MipsOpCode enum
29 * skeleton: pre-designated bit-pattern for this opcode
30 * k0: key to applying ds/de
31 * ds: dest start bit position
32 * de: dest end bit position
33 * k1: key to applying s1s/s1e
34 * s1s: src1 start bit position
35 * s1e: src1 end bit position
36 * k2: key to applying s2s/s2e
37 * s2s: src2 start bit position
38 * s2e: src2 end bit position
39 * operands: number of operands (for sanity check purposes)
40 * name: mnemonic name
41 * fmt: for pretty-printing
42 */
43#define ENCODING_MAP(opcode, skeleton, k0, ds, de, k1, s1s, s1e, k2, s2s, s2e, \
44 k3, k3s, k3e, flags, name, fmt, size) \
45 {skeleton, {{k0, ds, de}, {k1, s1s, s1e}, {k2, s2s, s2e}, \
46 {k3, k3s, k3e}}, opcode, flags, name, fmt, size}
47
48/* Instruction dump string format keys: !pf, where "!" is the start
49 * of the key, "p" is which numeric operand to use and "f" is the
50 * print format.
51 *
52 * [p]ositions:
53 * 0 -> operands[0] (dest)
54 * 1 -> operands[1] (src1)
55 * 2 -> operands[2] (src2)
56 * 3 -> operands[3] (extra)
57 *
58 * [f]ormats:
59 * h -> 4-digit hex
60 * d -> decimal
61 * E -> decimal*4
62 * F -> decimal*2
63 * c -> branch condition (beq, bne, etc.)
64 * t -> pc-relative target
65 * T -> pc-region target
66 * u -> 1st half of bl[x] target
67 * v -> 2nd half ob bl[x] target
68 * R -> register list
69 * s -> single precision floating point register
70 * S -> double precision floating point register
71 * m -> Thumb2 modified immediate
72 * n -> complimented Thumb2 modified immediate
73 * M -> Thumb2 16-bit zero-extended immediate
74 * b -> 4-digit binary
75 *
76 * [!] escape. To insert "!", use "!!"
77 */
buzbee5de34942012-03-01 14:51:57 -080078/* NOTE: must be kept in sync with enum MipsOpcode from LIR.h */
buzbeee3acd072012-02-25 17:03:10 -080079MipsEncodingMap EncodingMap[kMipsLast] = {
80 ENCODING_MAP(kMips32BitData, 0x00000000,
81 kFmtBitBlt, 31, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
82 kFmtUnused, -1, -1, IS_UNARY_OP,
83 "data", "0x!0h(!0d)", 2),
84 ENCODING_MAP(kMipsAddiu, 0x24000000,
85 kFmtBitBlt, 20, 16, kFmtBitBlt, 25, 21, kFmtBitBlt, 15, 0,
86 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
87 "addiu", "!0r,!1r,0x!2h(!2d)", 2),
88 ENCODING_MAP(kMipsAddu, 0x00000021,
89 kFmtBitBlt, 15, 11, kFmtBitBlt, 25, 21, kFmtBitBlt, 20, 16,
90 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
91 "addu", "!0r,!1r,!2r", 2),
92 ENCODING_MAP(kMipsAnd, 0x00000024,
93 kFmtBitBlt, 15, 11, kFmtBitBlt, 25, 21, kFmtBitBlt, 20, 16,
94 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
95 "and", "!0r,!1r,!2r", 2),
96 ENCODING_MAP(kMipsAndi, 0x30000000,
97 kFmtBitBlt, 20, 16, kFmtBitBlt, 25, 21, kFmtBitBlt, 15, 0,
98 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
99 "andi", "!0r,!1r,0x!2h(!2d)", 2),
100 ENCODING_MAP(kMipsB, 0x10000000,
101 kFmtBitBlt, 15, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
102 kFmtUnused, -1, -1, NO_OPERAND | IS_BRANCH,
103 "b", "!0t", 2),
104 ENCODING_MAP(kMipsBal, 0x04110000,
105 kFmtBitBlt, 15, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
106 kFmtUnused, -1, -1, NO_OPERAND | IS_BRANCH | REG_DEF_LR,
107 "bal", "!0t", 2),
108 ENCODING_MAP(kMipsBeq, 0x10000000,
109 kFmtBitBlt, 25, 21, kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0,
110 kFmtUnused, -1, -1, IS_BINARY_OP | IS_BRANCH | REG_USE01,
111 "beq", "!0r,!1r,!2t", 2),
112 ENCODING_MAP(kMipsBeqz, 0x10000000, /* same as beq above with t = $zero */
113 kFmtBitBlt, 25, 21, kFmtBitBlt, 15, 0, kFmtUnused, -1, -1,
114 kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH | REG_USE0,
115 "beqz", "!0r,!1t", 2),
116 ENCODING_MAP(kMipsBgez, 0x04010000,
117 kFmtBitBlt, 25, 21, kFmtBitBlt, 15, 0, kFmtUnused, -1, -1,
118 kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH | REG_USE0,
119 "bgez", "!0r,!1t", 2),
120 ENCODING_MAP(kMipsBgtz, 0x1C000000,
121 kFmtBitBlt, 25, 21, kFmtBitBlt, 15, 0, kFmtUnused, -1, -1,
122 kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH | REG_USE0,
123 "bgtz", "!0r,!1t", 2),
124 ENCODING_MAP(kMipsBlez, 0x18000000,
125 kFmtBitBlt, 25, 21, kFmtBitBlt, 15, 0, kFmtUnused, -1, -1,
126 kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH | REG_USE0,
127 "blez", "!0r,!1t", 2),
128 ENCODING_MAP(kMipsBltz, 0x04000000,
129 kFmtBitBlt, 25, 21, kFmtBitBlt, 15, 0, kFmtUnused, -1, -1,
130 kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH | REG_USE0,
131 "bltz", "!0r,!1t", 2),
132 ENCODING_MAP(kMipsBnez, 0x14000000, /* same as bne below with t = $zero */
133 kFmtBitBlt, 25, 21, kFmtBitBlt, 15, 0, kFmtUnused, -1, -1,
134 kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH | REG_USE0,
135 "bnez", "!0r,!1t", 2),
136 ENCODING_MAP(kMipsBne, 0x14000000,
137 kFmtBitBlt, 25, 21, kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0,
138 kFmtUnused, -1, -1, IS_BINARY_OP | IS_BRANCH | REG_USE01,
139 "bne", "!0r,!1r,!2t", 2),
140 ENCODING_MAP(kMipsDiv, 0x0000001a,
141 kFmtUnused, -1, -1, kFmtUnused, -1, -1, kFmtBitBlt, 25, 21,
142 kFmtBitBlt, 20, 16, IS_QUAD_OP | REG_DEF01 | REG_USE23,
143 "div", "!2r,!3r", 2),
144#if __mips_isa_rev>=2
145 ENCODING_MAP(kMipsExt, 0x7c000000,
146 kFmtBitBlt, 20, 16, kFmtBitBlt, 25, 21, kFmtBitBlt, 10, 6,
147 kFmtBitBlt, 15, 11, IS_QUAD_OP | REG_DEF0 | REG_USE1,
148 "ext", "!0r,!1r,!2d,!3D", 2),
149#endif
150 ENCODING_MAP(kMipsJal, 0x0c000000,
151 kFmtBitBlt, 25, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
152 kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH | REG_DEF_LR,
153 "jal", "!0T(!0E)", 2),
154 ENCODING_MAP(kMipsJalr, 0x00000009,
155 kFmtBitBlt, 15, 11, kFmtBitBlt, 25, 21, kFmtUnused, -1, -1,
156 kFmtUnused, -1, -1, IS_BINARY_OP | IS_BRANCH | REG_DEF0_USE1,
157 "jalr", "!0r,!1r", 2),
158 ENCODING_MAP(kMipsJr, 0x00000008,
159 kFmtBitBlt, 25, 21, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
160 kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH | REG_USE0,
161 "jr", "!0r", 2),
162 ENCODING_MAP(kMipsLahi, 0x3C000000,
163 kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0, kFmtUnused, -1, -1,
164 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0,
165 "lahi/lui", "!0r,0x!1h(!1d)", 2),
166 ENCODING_MAP(kMipsLalo, 0x34000000,
167 kFmtBitBlt, 20, 16, kFmtBitBlt, 25, 21, kFmtBitBlt, 15, 0,
168 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
169 "lalo/ori", "!0r,!1r,0x!2h(!2d)", 2),
170 ENCODING_MAP(kMipsLui, 0x3C000000,
171 kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0, kFmtUnused, -1, -1,
172 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0,
173 "lui", "!0r,0x!1h(!1d)", 2),
174 ENCODING_MAP(kMipsLb, 0x80000000,
175 kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0, kFmtBitBlt, 25, 21,
176 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE2 | IS_LOAD,
177 "lb", "!0r,!1d(!2r)", 2),
178 ENCODING_MAP(kMipsLbu, 0x90000000,
179 kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0, kFmtBitBlt, 25, 21,
180 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE2 | IS_LOAD,
181 "lbu", "!0r,!1d(!2r)", 2),
182 ENCODING_MAP(kMipsLh, 0x84000000,
183 kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0, kFmtBitBlt, 25, 21,
184 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE2 | IS_LOAD,
185 "lh", "!0r,!1d(!2r)", 2),
186 ENCODING_MAP(kMipsLhu, 0x94000000,
187 kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0, kFmtBitBlt, 25, 21,
188 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE2 | IS_LOAD,
189 "lhu", "!0r,!1d(!2r)", 2),
190 ENCODING_MAP(kMipsLw, 0x8C000000,
191 kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0, kFmtBitBlt, 25, 21,
192 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE2 | IS_LOAD,
193 "lw", "!0r,!1d(!2r)", 2),
194 ENCODING_MAP(kMipsMfhi, 0x00000010,
195 kFmtBitBlt, 15, 11, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
196 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
197 "mfhi", "!0r", 2),
198 ENCODING_MAP(kMipsMflo, 0x00000012,
199 kFmtBitBlt, 15, 11, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
200 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
201 "mflo", "!0r", 2),
202 ENCODING_MAP(kMipsMove, 0x00000025, /* or using zero reg */
203 kFmtBitBlt, 15, 11, kFmtBitBlt, 25, 21, kFmtUnused, -1, -1,
204 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
205 "move", "!0r,!1r", 2),
206 ENCODING_MAP(kMipsMovz, 0x0000000a,
207 kFmtBitBlt, 15, 11, kFmtBitBlt, 25, 21, kFmtBitBlt, 20, 16,
208 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
209 "movz", "!0r,!1r,!2r", 2),
210 ENCODING_MAP(kMipsMul, 0x70000002,
211 kFmtBitBlt, 15, 11, kFmtBitBlt, 25, 21, kFmtBitBlt, 20, 16,
212 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
213 "mul", "!0r,!1r,!2r", 2),
214 ENCODING_MAP(kMipsNop, 0x00000000,
215 kFmtUnused, -1, -1, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
216 kFmtUnused, -1, -1, NO_OPERAND,
217 "nop", "", 2),
218 ENCODING_MAP(kMipsNor, 0x00000027, /* used for "not" too */
219 kFmtBitBlt, 15, 11, kFmtBitBlt, 25, 21, kFmtBitBlt, 20, 16,
220 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
221 "nor", "!0r,!1r,!2r", 2),
222 ENCODING_MAP(kMipsOr, 0x00000025,
223 kFmtBitBlt, 15, 11, kFmtBitBlt, 25, 21, kFmtBitBlt, 20, 16,
224 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
225 "or", "!0r,!1r,!2r", 2),
226 ENCODING_MAP(kMipsOri, 0x34000000,
227 kFmtBitBlt, 20, 16, kFmtBitBlt, 25, 21, kFmtBitBlt, 15, 0,
228 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
229 "ori", "!0r,!1r,0x!2h(!2d)", 2),
230 ENCODING_MAP(kMipsPref, 0xCC000000,
231 kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0, kFmtBitBlt, 25, 21,
232 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE2,
233 "pref", "!0d,!1d(!2r)", 2),
234 ENCODING_MAP(kMipsSb, 0xA0000000,
235 kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0, kFmtBitBlt, 25, 21,
236 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE02 | IS_STORE,
237 "sb", "!0r,!1d(!2r)", 2),
238#if __mips_isa_rev>=2
239 ENCODING_MAP(kMipsSeb, 0x7c000420,
240 kFmtBitBlt, 15, 11, kFmtBitBlt, 20, 16, kFmtUnused, -1, -1,
241 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
242 "seb", "!0r,!1r", 2),
243 ENCODING_MAP(kMipsSeh, 0x7c000620,
244 kFmtBitBlt, 15, 11, kFmtBitBlt, 20, 16, kFmtUnused, -1, -1,
245 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
246 "seh", "!0r,!1r", 2),
247#endif
248 ENCODING_MAP(kMipsSh, 0xA4000000,
249 kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0, kFmtBitBlt, 25, 21,
250 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE02 | IS_STORE,
251 "sh", "!0r,!1d(!2r)", 2),
252 ENCODING_MAP(kMipsSll, 0x00000000,
253 kFmtBitBlt, 15, 11, kFmtBitBlt, 20, 16, kFmtBitBlt, 10, 6,
254 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
255 "sll", "!0r,!1r,0x!2h(!2d)", 2),
256 ENCODING_MAP(kMipsSllv, 0x00000004,
257 kFmtBitBlt, 15, 11, kFmtBitBlt, 20, 16, kFmtBitBlt, 25, 21,
258 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
259 "sllv", "!0r,!1r,!2r", 2),
260 ENCODING_MAP(kMipsSlt, 0x0000002a,
261 kFmtBitBlt, 15, 11, kFmtBitBlt, 25, 21, kFmtBitBlt, 20, 16,
262 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
263 "slt", "!0r,!1r,!2r", 2),
264 ENCODING_MAP(kMipsSlti, 0x28000000,
265 kFmtBitBlt, 20, 16, kFmtBitBlt, 25, 21, kFmtBitBlt, 15, 0,
266 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
267 "slti", "!0r,!1r,0x!2h(!2d)", 2),
268 ENCODING_MAP(kMipsSltu, 0x0000002b,
269 kFmtBitBlt, 15, 11, kFmtBitBlt, 25, 21, kFmtBitBlt, 20, 16,
270 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
271 "sltu", "!0r,!1r,!2r", 2),
272 ENCODING_MAP(kMipsSra, 0x00000003,
273 kFmtBitBlt, 15, 11, kFmtBitBlt, 20, 16, kFmtBitBlt, 10, 6,
274 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
275 "sra", "!0r,!1r,0x!2h(!2d)", 2),
276 ENCODING_MAP(kMipsSrav, 0x00000007,
277 kFmtBitBlt, 15, 11, kFmtBitBlt, 20, 16, kFmtBitBlt, 25, 21,
278 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
279 "srav", "!0r,!1r,!2r", 2),
280 ENCODING_MAP(kMipsSrl, 0x00000002,
281 kFmtBitBlt, 15, 11, kFmtBitBlt, 20, 16, kFmtBitBlt, 10, 6,
282 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
283 "srl", "!0r,!1r,0x!2h(!2d)", 2),
284 ENCODING_MAP(kMipsSrlv, 0x00000006,
285 kFmtBitBlt, 15, 11, kFmtBitBlt, 20, 16, kFmtBitBlt, 25, 21,
286 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
287 "srlv", "!0r,!1r,!2r", 2),
288 ENCODING_MAP(kMipsSubu, 0x00000023, /* used for "neg" too */
289 kFmtBitBlt, 15, 11, kFmtBitBlt, 25, 21, kFmtBitBlt, 20, 16,
290 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
291 "subu", "!0r,!1r,!2r", 2),
292 ENCODING_MAP(kMipsSw, 0xAC000000,
293 kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0, kFmtBitBlt, 25, 21,
294 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE02 | IS_STORE,
295 "sw", "!0r,!1d(!2r)", 2),
296 ENCODING_MAP(kMipsXor, 0x00000026,
297 kFmtBitBlt, 15, 11, kFmtBitBlt, 25, 21, kFmtBitBlt, 20, 16,
298 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
299 "xor", "!0r,!1r,!2r", 2),
300 ENCODING_MAP(kMipsXori, 0x38000000,
301 kFmtBitBlt, 20, 16, kFmtBitBlt, 25, 21, kFmtBitBlt, 15, 0,
302 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
303 "xori", "!0r,!1r,0x!2h(!2d)", 2),
304#ifdef __mips_hard_float
305 ENCODING_MAP(kMipsFadds, 0x46000000,
306 kFmtSfp, 10, 6, kFmtSfp, 15, 11, kFmtSfp, 20, 16,
307 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
308 "add.s", "!0s,!1s,!2s", 2),
309 ENCODING_MAP(kMipsFsubs, 0x46000001,
310 kFmtSfp, 10, 6, kFmtSfp, 15, 11, kFmtSfp, 20, 16,
311 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
312 "sub.s", "!0s,!1s,!2s", 2),
313 ENCODING_MAP(kMipsFmuls, 0x46000002,
314 kFmtSfp, 10, 6, kFmtSfp, 15, 11, kFmtSfp, 20, 16,
315 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
316 "mul.s", "!0s,!1s,!2s", 2),
317 ENCODING_MAP(kMipsFdivs, 0x46000003,
318 kFmtSfp, 10, 6, kFmtSfp, 15, 11, kFmtSfp, 20, 16,
319 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
320 "div.s", "!0s,!1s,!2s", 2),
321 ENCODING_MAP(kMipsFaddd, 0x46200000,
322 kFmtDfp, 10, 6, kFmtDfp, 15, 11, kFmtDfp, 20, 16,
323 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
324 "add.d", "!0S,!1S,!2S", 2),
325 ENCODING_MAP(kMipsFsubd, 0x46200001,
326 kFmtDfp, 10, 6, kFmtDfp, 15, 11, kFmtDfp, 20, 16,
327 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
328 "sub.d", "!0S,!1S,!2S", 2),
329 ENCODING_MAP(kMipsFmuld, 0x46200002,
330 kFmtDfp, 10, 6, kFmtDfp, 15, 11, kFmtDfp, 20, 16,
331 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
332 "mul.d", "!0S,!1S,!2S", 2),
333 ENCODING_MAP(kMipsFdivd, 0x46200003,
334 kFmtDfp, 10, 6, kFmtDfp, 15, 11, kFmtDfp, 20, 16,
335 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
336 "div.d", "!0S,!1S,!2S", 2),
337 ENCODING_MAP(kMipsFcvtsd, 0x46200020,
338 kFmtSfp, 10, 6, kFmtDfp, 15, 11, kFmtUnused, -1, -1,
339 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
340 "cvt.s.d", "!0s,!1S", 2),
341 ENCODING_MAP(kMipsFcvtsw, 0x46800020,
342 kFmtSfp, 10, 6, kFmtSfp, 15, 11, kFmtUnused, -1, -1,
343 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
344 "cvt.s.w", "!0s,!1s", 2),
345 ENCODING_MAP(kMipsFcvtds, 0x46000021,
346 kFmtDfp, 10, 6, kFmtSfp, 15, 11, kFmtUnused, -1, -1,
347 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
348 "cvt.d.s", "!0S,!1s", 2),
349 ENCODING_MAP(kMipsFcvtdw, 0x46800021,
350 kFmtDfp, 10, 6, kFmtSfp, 15, 11, kFmtUnused, -1, -1,
351 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
352 "cvt.d.w", "!0S,!1s", 2),
353 ENCODING_MAP(kMipsFcvtws, 0x46000024,
354 kFmtSfp, 10, 6, kFmtSfp, 15, 11, kFmtUnused, -1, -1,
355 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
356 "cvt.w.s", "!0s,!1s", 2),
357 ENCODING_MAP(kMipsFcvtwd, 0x46200024,
358 kFmtSfp, 10, 6, kFmtDfp, 15, 11, kFmtUnused, -1, -1,
359 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
360 "cvt.w.d", "!0s,!1S", 2),
361 ENCODING_MAP(kMipsFmovs, 0x46000006,
362 kFmtSfp, 10, 6, kFmtSfp, 15, 11, kFmtUnused, -1, -1,
363 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
364 "mov.s", "!0s,!1s", 2),
365 ENCODING_MAP(kMipsFmovd, 0x46200006,
366 kFmtDfp, 10, 6, kFmtDfp, 15, 11, kFmtUnused, -1, -1,
367 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
368 "mov.d", "!0S,!1S", 2),
369 ENCODING_MAP(kMipsFlwc1, 0xC4000000,
370 kFmtSfp, 20, 16, kFmtBitBlt, 15, 0, kFmtBitBlt, 25, 21,
371 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE2 | IS_LOAD,
372 "lwc1", "!0s,!1d(!2r)", 2),
373 ENCODING_MAP(kMipsFldc1, 0xD4000000,
374 kFmtDfp, 20, 16, kFmtBitBlt, 15, 0, kFmtBitBlt, 25, 21,
375 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE2 | IS_LOAD,
376 "ldc1", "!0S,!1d(!2r)", 2),
377 ENCODING_MAP(kMipsFswc1, 0xE4000000,
378 kFmtSfp, 20, 16, kFmtBitBlt, 15, 0, kFmtBitBlt, 25, 21,
379 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE02 | IS_STORE,
380 "swc1", "!0s,!1d(!2r)", 2),
381 ENCODING_MAP(kMipsFsdc1, 0xF4000000,
382 kFmtDfp, 20, 16, kFmtBitBlt, 15, 0, kFmtBitBlt, 25, 21,
383 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE02 | IS_STORE,
384 "sdc1", "!0S,!1d(!2r)", 2),
385 ENCODING_MAP(kMipsMfc1, 0x44000000,
386 kFmtBitBlt, 20, 16, kFmtSfp, 15, 11, kFmtUnused, -1, -1,
387 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
388 "mfc1", "!0r,!1s", 2),
389 ENCODING_MAP(kMipsMtc1, 0x44800000,
390 kFmtBitBlt, 20, 16, kFmtSfp, 15, 11, kFmtUnused, -1, -1,
391 kFmtUnused, -1, -1, IS_BINARY_OP | REG_USE0 | REG_DEF1,
392 "mtc1", "!0r,!1s", 2),
393#endif
394 ENCODING_MAP(kMipsUndefined, 0x64000000,
395 kFmtUnused, -1, -1, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
396 kFmtUnused, -1, -1, NO_OPERAND,
397 "undefined", "", 2),
398};
399
400/*
401 * Assemble the LIR into binary instruction format. Note that we may
402 * discover that pc-relative displacements may not fit the selected
403 * instruction. In those cases we will try to substitute a new code
404 * sequence or request that the trace be shortened and retried.
405 */
406AssemblerStatus oatAssembleInstructions(CompilationUnit *cUnit,
407 intptr_t startAddr)
408{
buzbee5de34942012-03-01 14:51:57 -0800409 LIR *lir;
410 AssemblerStatus res = kSuccess; // Assume success
buzbeee3acd072012-02-25 17:03:10 -0800411
buzbee5de34942012-03-01 14:51:57 -0800412 for (lir = (LIR *) cUnit->firstLIRInsn; lir; lir = NEXT_LIR(lir)) {
buzbeee3acd072012-02-25 17:03:10 -0800413 if (lir->opcode < 0) {
414 continue;
415 }
416
417
418 if (lir->flags.isNop) {
419 continue;
420 }
421
422 if (lir->opcode == kMipsB || lir->opcode == kMipsBal) {
buzbee5de34942012-03-01 14:51:57 -0800423 LIR *targetLIR = (LIR *) lir->target;
424 intptr_t pc = lir->offset + 4;
425 intptr_t target = targetLIR->offset;
buzbeee3acd072012-02-25 17:03:10 -0800426 int delta = target - pc;
427 if (delta & 0x3) {
428 LOG(FATAL) << "PC-rel offset not multiple of 4: " << delta;
429 }
430 if (delta > 131068 || delta < -131069) {
buzbee5de34942012-03-01 14:51:57 -0800431 UNIMPLEMENTED(FATAL) << "B out of range, need long sequence: " << delta;
buzbeee3acd072012-02-25 17:03:10 -0800432 }
433 lir->operands[0] = delta >> 2;
434 } else if (lir->opcode >= kMipsBeqz && lir->opcode <= kMipsBnez) {
buzbee5de34942012-03-01 14:51:57 -0800435 LIR *targetLIR = (LIR *) lir->target;
436 intptr_t pc = lir->offset + 4;
437 intptr_t target = targetLIR->offset;
buzbeee3acd072012-02-25 17:03:10 -0800438 int delta = target - pc;
439 if (delta & 0x3) {
440 LOG(FATAL) << "PC-rel offset not multiple of 4: " << delta;
441 }
442 if (delta > 131068 || delta < -131069) {
buzbee5de34942012-03-01 14:51:57 -0800443 UNIMPLEMENTED(FATAL) << "B[eq|ne]z needs long sequence: " << delta;
buzbeee3acd072012-02-25 17:03:10 -0800444 }
445 lir->operands[1] = delta >> 2;
446 } else if (lir->opcode == kMipsBeq || lir->opcode == kMipsBne) {
buzbee5de34942012-03-01 14:51:57 -0800447 LIR *targetLIR = (LIR *) lir->target;
448 intptr_t pc = lir->offset + 4;
449 intptr_t target = targetLIR->offset;
buzbeee3acd072012-02-25 17:03:10 -0800450 int delta = target - pc;
451 if (delta & 0x3) {
452 LOG(FATAL) << "PC-rel offset not multiple of 4: " << delta;
453 }
454 if (delta > 131068 || delta < -131069) {
buzbee5de34942012-03-01 14:51:57 -0800455 UNIMPLEMENTED(FATAL) << "B[eq|ne] needs long sequence: " << delta;
buzbeee3acd072012-02-25 17:03:10 -0800456 }
457 lir->operands[2] = delta >> 2;
458 } else if (lir->opcode == kMipsJal) {
buzbee5de34942012-03-01 14:51:57 -0800459 intptr_t curPC = (startAddr + lir->offset + 4) & ~3;
buzbeee3acd072012-02-25 17:03:10 -0800460 intptr_t target = lir->operands[0];
461 /* ensure PC-region branch can be used */
462 DCHECK_EQ((curPC & 0xF0000000), (target & 0xF0000000));
463 if (target & 0x3) {
464 LOG(FATAL) << "Jump target not multiple of 4: " << target;
465 }
466 lir->operands[0] = target >> 2;
467 } else if (lir->opcode == kMipsLahi) { /* load address hi (via lui) */
buzbee5de34942012-03-01 14:51:57 -0800468 LIR *targetLIR = (LIR *) lir->target;
469 intptr_t target = startAddr + targetLIR->offset;
buzbeee3acd072012-02-25 17:03:10 -0800470 lir->operands[1] = target >> 16;
471 } else if (lir->opcode == kMipsLalo) { /* load address lo (via ori) */
buzbee5de34942012-03-01 14:51:57 -0800472 LIR *targetLIR = (LIR *) lir->target;
473 intptr_t target = startAddr + targetLIR->offset;
buzbeee3acd072012-02-25 17:03:10 -0800474 lir->operands[2] = lir->operands[2] + target;
475 }
476
buzbee5de34942012-03-01 14:51:57 -0800477 /*
478 * If one of the pc-relative instructions expanded we'll have
479 * to make another pass. Don't bother to fully assemble the
480 * instruction.
481 */
482 if (res != kSuccess) {
483 continue;
484 }
485 const MipsEncodingMap *encoder = &EncodingMap[lir->opcode];
buzbeee3acd072012-02-25 17:03:10 -0800486 u4 bits = encoder->skeleton;
487 int i;
488 for (i = 0; i < 4; i++) {
489 u4 operand;
490 u4 value;
491 operand = lir->operands[i];
492 switch(encoder->fieldLoc[i].kind) {
493 case kFmtUnused:
494 break;
495 case kFmtBitBlt:
496 if (encoder->fieldLoc[i].start == 0 && encoder->fieldLoc[i].end == 31) {
497 value = operand;
498 } else {
499 value = (operand << encoder->fieldLoc[i].start) &
500 ((1 << (encoder->fieldLoc[i].end + 1)) - 1);
501 }
502 bits |= value;
503 break;
504 case kFmtDfp: {
505 DCHECK(DOUBLEREG(operand));
buzbee5de34942012-03-01 14:51:57 -0800506 DCHECK((operand & 0x1) == 0);
buzbeee3acd072012-02-25 17:03:10 -0800507 value = ((operand & FP_REG_MASK) << encoder->fieldLoc[i].start) &
508 ((1 << (encoder->fieldLoc[i].end + 1)) - 1);
509 bits |= value;
510 break;
511 }
512 case kFmtSfp:
513 DCHECK(SINGLEREG(operand));
514 value = ((operand & FP_REG_MASK) << encoder->fieldLoc[i].start) &
515 ((1 << (encoder->fieldLoc[i].end + 1)) - 1);
516 bits |= value;
517 break;
518 default:
519 LOG(FATAL) << "Bad encoder format: "
buzbee5de34942012-03-01 14:51:57 -0800520 << (int)encoder->fieldLoc[i].kind;
buzbeee3acd072012-02-25 17:03:10 -0800521 }
522 }
523 DCHECK_EQ(encoder->size, 2);
buzbee5de34942012-03-01 14:51:57 -0800524 // FIXME: need multi-endian handling here
525 cUnit->codeBuffer.push_back((bits >> 16) & 0xffff);
526 cUnit->codeBuffer.push_back(bits & 0xffff);
buzbeee3acd072012-02-25 17:03:10 -0800527 }
buzbee5de34942012-03-01 14:51:57 -0800528 return res;
buzbeee3acd072012-02-25 17:03:10 -0800529}
530
531/*
532 * Target-dependent offset assignment.
533 * TODO: normalize usage of flags.size and make this target
534 * independent.
535 */
536int oatAssignInsnOffsets(CompilationUnit* cUnit)
537{
buzbee5de34942012-03-01 14:51:57 -0800538 LIR* mipsLIR;
buzbeee3acd072012-02-25 17:03:10 -0800539 int offset = 0;
540
buzbee5de34942012-03-01 14:51:57 -0800541 for (mipsLIR = (LIR *) cUnit->firstLIRInsn;
542 mipsLIR;
543 mipsLIR = NEXT_LIR(mipsLIR)) {
544 mipsLIR->offset = offset;
buzbeee3acd072012-02-25 17:03:10 -0800545 if (mipsLIR->opcode >= 0) {
546 if (!mipsLIR->flags.isNop) {
547 mipsLIR->flags.size = EncodingMap[mipsLIR->opcode].size * 2;
548 offset += mipsLIR->flags.size;
549 }
buzbee31a4a6f2012-02-28 15:36:15 -0800550 } else if (mipsLIR->opcode == kPseudoPseudoAlign4) {
buzbeee3acd072012-02-25 17:03:10 -0800551 if (offset & 0x2) {
552 offset += 2;
553 mipsLIR->operands[0] = 1;
554 } else {
555 mipsLIR->operands[0] = 0;
556 }
557 }
558 /* Pseudo opcodes don't consume space */
559 }
560
561 return offset;
562}
563
564} // namespace art