blob: 79259fbe28a93393de9ed59a534fd66022345f2d [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
buzbeeefc63692012-11-14 16:31:52 -080017#include "mips_lir.h"
buzbeeeaf09bc2012-11-15 14:51:41 -080018#include "../codegen_util.h"
buzbeee3acd072012-02-25 17:03:10 -080019
20namespace art {
21
22#define MAX_ASSEMBLER_RETRIES 50
23
24/*
25 * opcode: MipsOpCode enum
26 * skeleton: pre-designated bit-pattern for this opcode
27 * k0: key to applying ds/de
28 * ds: dest start bit position
29 * de: dest end bit position
30 * k1: key to applying s1s/s1e
31 * s1s: src1 start bit position
32 * s1e: src1 end bit position
33 * k2: key to applying s2s/s2e
34 * s2s: src2 start bit position
35 * s2e: src2 end bit position
36 * operands: number of operands (for sanity check purposes)
37 * name: mnemonic name
38 * fmt: for pretty-printing
39 */
40#define ENCODING_MAP(opcode, skeleton, k0, ds, de, k1, s1s, s1e, k2, s2s, s2e, \
41 k3, k3s, k3e, flags, name, fmt, size) \
42 {skeleton, {{k0, ds, de}, {k1, s1s, s1e}, {k2, s2s, s2e}, \
43 {k3, k3s, k3e}}, opcode, flags, name, fmt, size}
44
45/* Instruction dump string format keys: !pf, where "!" is the start
46 * of the key, "p" is which numeric operand to use and "f" is the
47 * print format.
48 *
49 * [p]ositions:
50 * 0 -> operands[0] (dest)
51 * 1 -> operands[1] (src1)
52 * 2 -> operands[2] (src2)
53 * 3 -> operands[3] (extra)
54 *
55 * [f]ormats:
56 * h -> 4-digit hex
57 * d -> decimal
58 * E -> decimal*4
59 * F -> decimal*2
60 * c -> branch condition (beq, bne, etc.)
61 * t -> pc-relative target
62 * T -> pc-region target
63 * u -> 1st half of bl[x] target
64 * v -> 2nd half ob bl[x] target
65 * R -> register list
66 * s -> single precision floating point register
67 * S -> double precision floating point register
68 * m -> Thumb2 modified immediate
69 * n -> complimented Thumb2 modified immediate
70 * M -> Thumb2 16-bit zero-extended immediate
71 * b -> 4-digit binary
buzbee82488f52012-03-02 08:20:26 -080072 * N -> append a NOP
buzbeee3acd072012-02-25 17:03:10 -080073 *
74 * [!] escape. To insert "!", use "!!"
75 */
buzbee5de34942012-03-01 14:51:57 -080076/* NOTE: must be kept in sync with enum MipsOpcode from LIR.h */
buzbee82488f52012-03-02 08:20:26 -080077/*
78 * TUNING: We're currently punting on the branch delay slots. All branch
79 * instructions in this map are given a size of 8, which during assembly
80 * is expanded to include a nop. This scheme should be replaced with
81 * an assembler pass to fill those slots when possible.
82 */
buzbeee3acd072012-02-25 17:03:10 -080083MipsEncodingMap EncodingMap[kMipsLast] = {
84 ENCODING_MAP(kMips32BitData, 0x00000000,
85 kFmtBitBlt, 31, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
86 kFmtUnused, -1, -1, IS_UNARY_OP,
buzbee71ac9942012-03-01 17:23:10 -080087 "data", "0x!0h(!0d)", 4),
buzbeee3acd072012-02-25 17:03:10 -080088 ENCODING_MAP(kMipsAddiu, 0x24000000,
89 kFmtBitBlt, 20, 16, kFmtBitBlt, 25, 21, kFmtBitBlt, 15, 0,
90 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
buzbee71ac9942012-03-01 17:23:10 -080091 "addiu", "!0r,!1r,0x!2h(!2d)", 4),
buzbeee3acd072012-02-25 17:03:10 -080092 ENCODING_MAP(kMipsAddu, 0x00000021,
93 kFmtBitBlt, 15, 11, kFmtBitBlt, 25, 21, kFmtBitBlt, 20, 16,
94 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
buzbee71ac9942012-03-01 17:23:10 -080095 "addu", "!0r,!1r,!2r", 4),
buzbeee3acd072012-02-25 17:03:10 -080096 ENCODING_MAP(kMipsAnd, 0x00000024,
97 kFmtBitBlt, 15, 11, kFmtBitBlt, 25, 21, kFmtBitBlt, 20, 16,
98 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
buzbee71ac9942012-03-01 17:23:10 -080099 "and", "!0r,!1r,!2r", 4),
buzbeee3acd072012-02-25 17:03:10 -0800100 ENCODING_MAP(kMipsAndi, 0x30000000,
101 kFmtBitBlt, 20, 16, kFmtBitBlt, 25, 21, kFmtBitBlt, 15, 0,
102 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
buzbee71ac9942012-03-01 17:23:10 -0800103 "andi", "!0r,!1r,0x!2h(!2d)", 4),
buzbeee3acd072012-02-25 17:03:10 -0800104 ENCODING_MAP(kMipsB, 0x10000000,
105 kFmtBitBlt, 15, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
Ian Rogers680b1bd2012-03-07 20:18:49 -0800106 kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH | NEEDS_FIXUP,
buzbee82488f52012-03-02 08:20:26 -0800107 "b", "!0t!0N", 8),
buzbeee3acd072012-02-25 17:03:10 -0800108 ENCODING_MAP(kMipsBal, 0x04110000,
109 kFmtBitBlt, 15, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
Ian Rogers680b1bd2012-03-07 20:18:49 -0800110 kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH | REG_DEF_LR |
buzbeea2ebdd72012-03-04 14:57:06 -0800111 NEEDS_FIXUP, "bal", "!0t!0N", 8),
buzbeee3acd072012-02-25 17:03:10 -0800112 ENCODING_MAP(kMipsBeq, 0x10000000,
113 kFmtBitBlt, 25, 21, kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0,
buzbeea2ebdd72012-03-04 14:57:06 -0800114 kFmtUnused, -1, -1, IS_BINARY_OP | IS_BRANCH | REG_USE01 |
115 NEEDS_FIXUP, "beq", "!0r,!1r,!2t!0N", 8),
buzbeee3acd072012-02-25 17:03:10 -0800116 ENCODING_MAP(kMipsBeqz, 0x10000000, /* same as beq above with t = $zero */
117 kFmtBitBlt, 25, 21, kFmtBitBlt, 15, 0, kFmtUnused, -1, -1,
buzbeea2ebdd72012-03-04 14:57:06 -0800118 kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH | REG_USE0 |
119 NEEDS_FIXUP, "beqz", "!0r,!1t!0N", 8),
buzbeee3acd072012-02-25 17:03:10 -0800120 ENCODING_MAP(kMipsBgez, 0x04010000,
121 kFmtBitBlt, 25, 21, kFmtBitBlt, 15, 0, kFmtUnused, -1, -1,
buzbeea2ebdd72012-03-04 14:57:06 -0800122 kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH | REG_USE0 |
123 NEEDS_FIXUP, "bgez", "!0r,!1t!0N", 8),
buzbeee3acd072012-02-25 17:03:10 -0800124 ENCODING_MAP(kMipsBgtz, 0x1C000000,
125 kFmtBitBlt, 25, 21, kFmtBitBlt, 15, 0, kFmtUnused, -1, -1,
buzbeea2ebdd72012-03-04 14:57:06 -0800126 kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH | REG_USE0 |
127 NEEDS_FIXUP, "bgtz", "!0r,!1t!0N", 8),
buzbeee3acd072012-02-25 17:03:10 -0800128 ENCODING_MAP(kMipsBlez, 0x18000000,
129 kFmtBitBlt, 25, 21, kFmtBitBlt, 15, 0, kFmtUnused, -1, -1,
buzbeea2ebdd72012-03-04 14:57:06 -0800130 kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH | REG_USE0 |
131 NEEDS_FIXUP, "blez", "!0r,!1t!0N", 8),
buzbeee3acd072012-02-25 17:03:10 -0800132 ENCODING_MAP(kMipsBltz, 0x04000000,
133 kFmtBitBlt, 25, 21, kFmtBitBlt, 15, 0, kFmtUnused, -1, -1,
buzbeea2ebdd72012-03-04 14:57:06 -0800134 kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH | REG_USE0 |
135 NEEDS_FIXUP, "bltz", "!0r,!1t!0N", 8),
buzbeee3acd072012-02-25 17:03:10 -0800136 ENCODING_MAP(kMipsBnez, 0x14000000, /* same as bne below with t = $zero */
137 kFmtBitBlt, 25, 21, kFmtBitBlt, 15, 0, kFmtUnused, -1, -1,
buzbeea2ebdd72012-03-04 14:57:06 -0800138 kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH | REG_USE0 |
139 NEEDS_FIXUP, "bnez", "!0r,!1t!0N", 8),
buzbeee3acd072012-02-25 17:03:10 -0800140 ENCODING_MAP(kMipsBne, 0x14000000,
141 kFmtBitBlt, 25, 21, kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0,
buzbeea2ebdd72012-03-04 14:57:06 -0800142 kFmtUnused, -1, -1, IS_BINARY_OP | IS_BRANCH | REG_USE01 |
143 NEEDS_FIXUP, "bne", "!0r,!1r,!2t!0N", 8),
buzbeee3acd072012-02-25 17:03:10 -0800144 ENCODING_MAP(kMipsDiv, 0x0000001a,
145 kFmtUnused, -1, -1, kFmtUnused, -1, -1, kFmtBitBlt, 25, 21,
146 kFmtBitBlt, 20, 16, IS_QUAD_OP | REG_DEF01 | REG_USE23,
buzbee71ac9942012-03-01 17:23:10 -0800147 "div", "!2r,!3r", 4),
buzbeee3acd072012-02-25 17:03:10 -0800148#if __mips_isa_rev>=2
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,
buzbee71ac9942012-03-01 17:23:10 -0800152 "ext", "!0r,!1r,!2d,!3D", 4),
buzbeee3acd072012-02-25 17:03:10 -0800153#endif
154 ENCODING_MAP(kMipsJal, 0x0c000000,
155 kFmtBitBlt, 25, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
156 kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH | REG_DEF_LR,
buzbee82488f52012-03-02 08:20:26 -0800157 "jal", "!0T(!0E)!0N", 8),
buzbeee3acd072012-02-25 17:03:10 -0800158 ENCODING_MAP(kMipsJalr, 0x00000009,
159 kFmtBitBlt, 15, 11, kFmtBitBlt, 25, 21, kFmtUnused, -1, -1,
160 kFmtUnused, -1, -1, IS_BINARY_OP | IS_BRANCH | REG_DEF0_USE1,
buzbee82488f52012-03-02 08:20:26 -0800161 "jalr", "!0r,!1r!0N", 8),
buzbeee3acd072012-02-25 17:03:10 -0800162 ENCODING_MAP(kMipsJr, 0x00000008,
163 kFmtBitBlt, 25, 21, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
buzbeea2ebdd72012-03-04 14:57:06 -0800164 kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH | REG_USE0 |
165 NEEDS_FIXUP, "jr", "!0r!0N", 8),
buzbeee3acd072012-02-25 17:03:10 -0800166 ENCODING_MAP(kMipsLahi, 0x3C000000,
167 kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0, kFmtUnused, -1, -1,
168 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0,
buzbee71ac9942012-03-01 17:23:10 -0800169 "lahi/lui", "!0r,0x!1h(!1d)", 4),
buzbeee3acd072012-02-25 17:03:10 -0800170 ENCODING_MAP(kMipsLalo, 0x34000000,
171 kFmtBitBlt, 20, 16, kFmtBitBlt, 25, 21, kFmtBitBlt, 15, 0,
172 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
buzbee71ac9942012-03-01 17:23:10 -0800173 "lalo/ori", "!0r,!1r,0x!2h(!2d)", 4),
buzbeee3acd072012-02-25 17:03:10 -0800174 ENCODING_MAP(kMipsLui, 0x3C000000,
175 kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0, kFmtUnused, -1, -1,
176 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0,
buzbee71ac9942012-03-01 17:23:10 -0800177 "lui", "!0r,0x!1h(!1d)", 4),
buzbeee3acd072012-02-25 17:03:10 -0800178 ENCODING_MAP(kMipsLb, 0x80000000,
179 kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0, kFmtBitBlt, 25, 21,
180 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE2 | IS_LOAD,
buzbee71ac9942012-03-01 17:23:10 -0800181 "lb", "!0r,!1d(!2r)", 4),
buzbeee3acd072012-02-25 17:03:10 -0800182 ENCODING_MAP(kMipsLbu, 0x90000000,
183 kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0, kFmtBitBlt, 25, 21,
184 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE2 | IS_LOAD,
buzbee71ac9942012-03-01 17:23:10 -0800185 "lbu", "!0r,!1d(!2r)", 4),
buzbeee3acd072012-02-25 17:03:10 -0800186 ENCODING_MAP(kMipsLh, 0x84000000,
187 kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0, kFmtBitBlt, 25, 21,
188 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE2 | IS_LOAD,
buzbee71ac9942012-03-01 17:23:10 -0800189 "lh", "!0r,!1d(!2r)", 4),
buzbeee3acd072012-02-25 17:03:10 -0800190 ENCODING_MAP(kMipsLhu, 0x94000000,
191 kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0, kFmtBitBlt, 25, 21,
192 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE2 | IS_LOAD,
buzbee71ac9942012-03-01 17:23:10 -0800193 "lhu", "!0r,!1d(!2r)", 4),
buzbeee3acd072012-02-25 17:03:10 -0800194 ENCODING_MAP(kMipsLw, 0x8C000000,
195 kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0, kFmtBitBlt, 25, 21,
196 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE2 | IS_LOAD,
buzbee71ac9942012-03-01 17:23:10 -0800197 "lw", "!0r,!1d(!2r)", 4),
buzbeee3acd072012-02-25 17:03:10 -0800198 ENCODING_MAP(kMipsMfhi, 0x00000010,
199 kFmtBitBlt, 15, 11, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
200 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
buzbee71ac9942012-03-01 17:23:10 -0800201 "mfhi", "!0r", 4),
buzbeee3acd072012-02-25 17:03:10 -0800202 ENCODING_MAP(kMipsMflo, 0x00000012,
203 kFmtBitBlt, 15, 11, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
204 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
buzbee71ac9942012-03-01 17:23:10 -0800205 "mflo", "!0r", 4),
buzbeee3acd072012-02-25 17:03:10 -0800206 ENCODING_MAP(kMipsMove, 0x00000025, /* or using zero reg */
207 kFmtBitBlt, 15, 11, kFmtBitBlt, 25, 21, kFmtUnused, -1, -1,
208 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
buzbee71ac9942012-03-01 17:23:10 -0800209 "move", "!0r,!1r", 4),
buzbeee3acd072012-02-25 17:03:10 -0800210 ENCODING_MAP(kMipsMovz, 0x0000000a,
211 kFmtBitBlt, 15, 11, kFmtBitBlt, 25, 21, kFmtBitBlt, 20, 16,
212 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
buzbee71ac9942012-03-01 17:23:10 -0800213 "movz", "!0r,!1r,!2r", 4),
buzbeee3acd072012-02-25 17:03:10 -0800214 ENCODING_MAP(kMipsMul, 0x70000002,
215 kFmtBitBlt, 15, 11, kFmtBitBlt, 25, 21, kFmtBitBlt, 20, 16,
216 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
buzbee71ac9942012-03-01 17:23:10 -0800217 "mul", "!0r,!1r,!2r", 4),
buzbeee3acd072012-02-25 17:03:10 -0800218 ENCODING_MAP(kMipsNop, 0x00000000,
219 kFmtUnused, -1, -1, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
220 kFmtUnused, -1, -1, NO_OPERAND,
buzbeec5159d52012-03-03 11:48:39 -0800221 "nop", ";", 4),
buzbeee3acd072012-02-25 17:03:10 -0800222 ENCODING_MAP(kMipsNor, 0x00000027, /* used for "not" too */
223 kFmtBitBlt, 15, 11, kFmtBitBlt, 25, 21, kFmtBitBlt, 20, 16,
224 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
buzbee71ac9942012-03-01 17:23:10 -0800225 "nor", "!0r,!1r,!2r", 4),
buzbeee3acd072012-02-25 17:03:10 -0800226 ENCODING_MAP(kMipsOr, 0x00000025,
227 kFmtBitBlt, 15, 11, kFmtBitBlt, 25, 21, kFmtBitBlt, 20, 16,
228 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
buzbee71ac9942012-03-01 17:23:10 -0800229 "or", "!0r,!1r,!2r", 4),
buzbeee3acd072012-02-25 17:03:10 -0800230 ENCODING_MAP(kMipsOri, 0x34000000,
231 kFmtBitBlt, 20, 16, kFmtBitBlt, 25, 21, kFmtBitBlt, 15, 0,
232 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
buzbee71ac9942012-03-01 17:23:10 -0800233 "ori", "!0r,!1r,0x!2h(!2d)", 4),
buzbeee3acd072012-02-25 17:03:10 -0800234 ENCODING_MAP(kMipsPref, 0xCC000000,
235 kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0, kFmtBitBlt, 25, 21,
236 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE2,
buzbee71ac9942012-03-01 17:23:10 -0800237 "pref", "!0d,!1d(!2r)", 4),
buzbeee3acd072012-02-25 17:03:10 -0800238 ENCODING_MAP(kMipsSb, 0xA0000000,
239 kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0, kFmtBitBlt, 25, 21,
240 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE02 | IS_STORE,
buzbee71ac9942012-03-01 17:23:10 -0800241 "sb", "!0r,!1d(!2r)", 4),
buzbeee3acd072012-02-25 17:03:10 -0800242#if __mips_isa_rev>=2
243 ENCODING_MAP(kMipsSeb, 0x7c000420,
244 kFmtBitBlt, 15, 11, kFmtBitBlt, 20, 16, kFmtUnused, -1, -1,
245 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
buzbee71ac9942012-03-01 17:23:10 -0800246 "seb", "!0r,!1r", 4),
buzbeee3acd072012-02-25 17:03:10 -0800247 ENCODING_MAP(kMipsSeh, 0x7c000620,
248 kFmtBitBlt, 15, 11, kFmtBitBlt, 20, 16, kFmtUnused, -1, -1,
249 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
buzbee71ac9942012-03-01 17:23:10 -0800250 "seh", "!0r,!1r", 4),
buzbeee3acd072012-02-25 17:03:10 -0800251#endif
252 ENCODING_MAP(kMipsSh, 0xA4000000,
253 kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0, kFmtBitBlt, 25, 21,
254 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE02 | IS_STORE,
buzbee71ac9942012-03-01 17:23:10 -0800255 "sh", "!0r,!1d(!2r)", 4),
buzbeee3acd072012-02-25 17:03:10 -0800256 ENCODING_MAP(kMipsSll, 0x00000000,
257 kFmtBitBlt, 15, 11, kFmtBitBlt, 20, 16, kFmtBitBlt, 10, 6,
258 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
buzbee71ac9942012-03-01 17:23:10 -0800259 "sll", "!0r,!1r,0x!2h(!2d)", 4),
buzbeee3acd072012-02-25 17:03:10 -0800260 ENCODING_MAP(kMipsSllv, 0x00000004,
261 kFmtBitBlt, 15, 11, kFmtBitBlt, 20, 16, kFmtBitBlt, 25, 21,
262 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
buzbee71ac9942012-03-01 17:23:10 -0800263 "sllv", "!0r,!1r,!2r", 4),
buzbeee3acd072012-02-25 17:03:10 -0800264 ENCODING_MAP(kMipsSlt, 0x0000002a,
265 kFmtBitBlt, 15, 11, kFmtBitBlt, 25, 21, kFmtBitBlt, 20, 16,
266 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
buzbee71ac9942012-03-01 17:23:10 -0800267 "slt", "!0r,!1r,!2r", 4),
buzbeee3acd072012-02-25 17:03:10 -0800268 ENCODING_MAP(kMipsSlti, 0x28000000,
269 kFmtBitBlt, 20, 16, kFmtBitBlt, 25, 21, kFmtBitBlt, 15, 0,
270 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
buzbee71ac9942012-03-01 17:23:10 -0800271 "slti", "!0r,!1r,0x!2h(!2d)", 4),
buzbeee3acd072012-02-25 17:03:10 -0800272 ENCODING_MAP(kMipsSltu, 0x0000002b,
273 kFmtBitBlt, 15, 11, kFmtBitBlt, 25, 21, kFmtBitBlt, 20, 16,
274 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
buzbee71ac9942012-03-01 17:23:10 -0800275 "sltu", "!0r,!1r,!2r", 4),
buzbeee3acd072012-02-25 17:03:10 -0800276 ENCODING_MAP(kMipsSra, 0x00000003,
277 kFmtBitBlt, 15, 11, kFmtBitBlt, 20, 16, kFmtBitBlt, 10, 6,
278 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
buzbee71ac9942012-03-01 17:23:10 -0800279 "sra", "!0r,!1r,0x!2h(!2d)", 4),
buzbeee3acd072012-02-25 17:03:10 -0800280 ENCODING_MAP(kMipsSrav, 0x00000007,
281 kFmtBitBlt, 15, 11, kFmtBitBlt, 20, 16, kFmtBitBlt, 25, 21,
282 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
buzbee71ac9942012-03-01 17:23:10 -0800283 "srav", "!0r,!1r,!2r", 4),
buzbeee3acd072012-02-25 17:03:10 -0800284 ENCODING_MAP(kMipsSrl, 0x00000002,
285 kFmtBitBlt, 15, 11, kFmtBitBlt, 20, 16, kFmtBitBlt, 10, 6,
286 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
buzbee71ac9942012-03-01 17:23:10 -0800287 "srl", "!0r,!1r,0x!2h(!2d)", 4),
buzbeee3acd072012-02-25 17:03:10 -0800288 ENCODING_MAP(kMipsSrlv, 0x00000006,
289 kFmtBitBlt, 15, 11, kFmtBitBlt, 20, 16, kFmtBitBlt, 25, 21,
290 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
buzbee71ac9942012-03-01 17:23:10 -0800291 "srlv", "!0r,!1r,!2r", 4),
buzbeee3acd072012-02-25 17:03:10 -0800292 ENCODING_MAP(kMipsSubu, 0x00000023, /* used for "neg" too */
293 kFmtBitBlt, 15, 11, kFmtBitBlt, 25, 21, kFmtBitBlt, 20, 16,
294 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
buzbee71ac9942012-03-01 17:23:10 -0800295 "subu", "!0r,!1r,!2r", 4),
buzbeee3acd072012-02-25 17:03:10 -0800296 ENCODING_MAP(kMipsSw, 0xAC000000,
297 kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0, kFmtBitBlt, 25, 21,
298 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE02 | IS_STORE,
buzbee71ac9942012-03-01 17:23:10 -0800299 "sw", "!0r,!1d(!2r)", 4),
buzbeee3acd072012-02-25 17:03:10 -0800300 ENCODING_MAP(kMipsXor, 0x00000026,
301 kFmtBitBlt, 15, 11, kFmtBitBlt, 25, 21, kFmtBitBlt, 20, 16,
302 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
buzbee71ac9942012-03-01 17:23:10 -0800303 "xor", "!0r,!1r,!2r", 4),
buzbeee3acd072012-02-25 17:03:10 -0800304 ENCODING_MAP(kMipsXori, 0x38000000,
305 kFmtBitBlt, 20, 16, kFmtBitBlt, 25, 21, kFmtBitBlt, 15, 0,
306 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
buzbee71ac9942012-03-01 17:23:10 -0800307 "xori", "!0r,!1r,0x!2h(!2d)", 4),
buzbeee3acd072012-02-25 17:03:10 -0800308#ifdef __mips_hard_float
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,
buzbee71ac9942012-03-01 17:23:10 -0800312 "add.s", "!0s,!1s,!2s", 4),
buzbeee3acd072012-02-25 17:03:10 -0800313 ENCODING_MAP(kMipsFsubs, 0x46000001,
314 kFmtSfp, 10, 6, kFmtSfp, 15, 11, kFmtSfp, 20, 16,
315 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
buzbee71ac9942012-03-01 17:23:10 -0800316 "sub.s", "!0s,!1s,!2s", 4),
buzbeee3acd072012-02-25 17:03:10 -0800317 ENCODING_MAP(kMipsFmuls, 0x46000002,
318 kFmtSfp, 10, 6, kFmtSfp, 15, 11, kFmtSfp, 20, 16,
319 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
buzbee71ac9942012-03-01 17:23:10 -0800320 "mul.s", "!0s,!1s,!2s", 4),
buzbeee3acd072012-02-25 17:03:10 -0800321 ENCODING_MAP(kMipsFdivs, 0x46000003,
322 kFmtSfp, 10, 6, kFmtSfp, 15, 11, kFmtSfp, 20, 16,
323 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
buzbee71ac9942012-03-01 17:23:10 -0800324 "div.s", "!0s,!1s,!2s", 4),
buzbeee3acd072012-02-25 17:03:10 -0800325 ENCODING_MAP(kMipsFaddd, 0x46200000,
326 kFmtDfp, 10, 6, kFmtDfp, 15, 11, kFmtDfp, 20, 16,
327 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
buzbee71ac9942012-03-01 17:23:10 -0800328 "add.d", "!0S,!1S,!2S", 4),
buzbeee3acd072012-02-25 17:03:10 -0800329 ENCODING_MAP(kMipsFsubd, 0x46200001,
330 kFmtDfp, 10, 6, kFmtDfp, 15, 11, kFmtDfp, 20, 16,
331 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
buzbee71ac9942012-03-01 17:23:10 -0800332 "sub.d", "!0S,!1S,!2S", 4),
buzbeee3acd072012-02-25 17:03:10 -0800333 ENCODING_MAP(kMipsFmuld, 0x46200002,
334 kFmtDfp, 10, 6, kFmtDfp, 15, 11, kFmtDfp, 20, 16,
335 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
buzbee71ac9942012-03-01 17:23:10 -0800336 "mul.d", "!0S,!1S,!2S", 4),
buzbeee3acd072012-02-25 17:03:10 -0800337 ENCODING_MAP(kMipsFdivd, 0x46200003,
338 kFmtDfp, 10, 6, kFmtDfp, 15, 11, kFmtDfp, 20, 16,
339 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
buzbee71ac9942012-03-01 17:23:10 -0800340 "div.d", "!0S,!1S,!2S", 4),
buzbeee3acd072012-02-25 17:03:10 -0800341 ENCODING_MAP(kMipsFcvtsd, 0x46200020,
342 kFmtSfp, 10, 6, kFmtDfp, 15, 11, kFmtUnused, -1, -1,
343 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
buzbee71ac9942012-03-01 17:23:10 -0800344 "cvt.s.d", "!0s,!1S", 4),
buzbeee3acd072012-02-25 17:03:10 -0800345 ENCODING_MAP(kMipsFcvtsw, 0x46800020,
346 kFmtSfp, 10, 6, kFmtSfp, 15, 11, kFmtUnused, -1, -1,
347 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
buzbee71ac9942012-03-01 17:23:10 -0800348 "cvt.s.w", "!0s,!1s", 4),
buzbeee3acd072012-02-25 17:03:10 -0800349 ENCODING_MAP(kMipsFcvtds, 0x46000021,
350 kFmtDfp, 10, 6, kFmtSfp, 15, 11, kFmtUnused, -1, -1,
351 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
buzbee71ac9942012-03-01 17:23:10 -0800352 "cvt.d.s", "!0S,!1s", 4),
buzbeee3acd072012-02-25 17:03:10 -0800353 ENCODING_MAP(kMipsFcvtdw, 0x46800021,
354 kFmtDfp, 10, 6, kFmtSfp, 15, 11, kFmtUnused, -1, -1,
355 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
buzbee71ac9942012-03-01 17:23:10 -0800356 "cvt.d.w", "!0S,!1s", 4),
buzbeee3acd072012-02-25 17:03:10 -0800357 ENCODING_MAP(kMipsFcvtws, 0x46000024,
358 kFmtSfp, 10, 6, kFmtSfp, 15, 11, kFmtUnused, -1, -1,
359 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
buzbee71ac9942012-03-01 17:23:10 -0800360 "cvt.w.s", "!0s,!1s", 4),
buzbeee3acd072012-02-25 17:03:10 -0800361 ENCODING_MAP(kMipsFcvtwd, 0x46200024,
362 kFmtSfp, 10, 6, kFmtDfp, 15, 11, kFmtUnused, -1, -1,
363 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
buzbee71ac9942012-03-01 17:23:10 -0800364 "cvt.w.d", "!0s,!1S", 4),
buzbeee3acd072012-02-25 17:03:10 -0800365 ENCODING_MAP(kMipsFmovs, 0x46000006,
366 kFmtSfp, 10, 6, kFmtSfp, 15, 11, kFmtUnused, -1, -1,
367 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
buzbee71ac9942012-03-01 17:23:10 -0800368 "mov.s", "!0s,!1s", 4),
buzbeee3acd072012-02-25 17:03:10 -0800369 ENCODING_MAP(kMipsFmovd, 0x46200006,
370 kFmtDfp, 10, 6, kFmtDfp, 15, 11, kFmtUnused, -1, -1,
371 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
buzbee71ac9942012-03-01 17:23:10 -0800372 "mov.d", "!0S,!1S", 4),
buzbeee3acd072012-02-25 17:03:10 -0800373 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,
buzbee71ac9942012-03-01 17:23:10 -0800376 "lwc1", "!0s,!1d(!2r)", 4),
buzbeee3acd072012-02-25 17:03:10 -0800377 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,
buzbee71ac9942012-03-01 17:23:10 -0800380 "ldc1", "!0S,!1d(!2r)", 4),
buzbeee3acd072012-02-25 17:03:10 -0800381 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,
buzbee71ac9942012-03-01 17:23:10 -0800384 "swc1", "!0s,!1d(!2r)", 4),
buzbeee3acd072012-02-25 17:03:10 -0800385 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,
buzbee71ac9942012-03-01 17:23:10 -0800388 "sdc1", "!0S,!1d(!2r)", 4),
buzbeee3acd072012-02-25 17:03:10 -0800389 ENCODING_MAP(kMipsMfc1, 0x44000000,
390 kFmtBitBlt, 20, 16, kFmtSfp, 15, 11, kFmtUnused, -1, -1,
391 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
buzbee71ac9942012-03-01 17:23:10 -0800392 "mfc1", "!0r,!1s", 4),
buzbeee3acd072012-02-25 17:03:10 -0800393 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,
buzbee71ac9942012-03-01 17:23:10 -0800396 "mtc1", "!0r,!1s", 4),
buzbeee3acd072012-02-25 17:03:10 -0800397#endif
buzbeec5159d52012-03-03 11:48:39 -0800398 ENCODING_MAP(kMipsDelta, 0x27e00000,
399 kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0, kFmtUnused, 15, 0,
buzbeea2ebdd72012-03-04 14:57:06 -0800400 kFmtUnused, -1, -1, IS_QUAD_OP | REG_DEF0 | REG_USE_LR |
jeffhaofa147e22012-10-12 17:03:32 -0700401 NEEDS_FIXUP, "addiu", "!0r,ra,0x!1h(!1d)", 4),
buzbeec5159d52012-03-03 11:48:39 -0800402 ENCODING_MAP(kMipsDeltaHi, 0x3C000000,
403 kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0, kFmtUnused, -1, -1,
buzbeea2ebdd72012-03-04 14:57:06 -0800404 kFmtUnused, -1, -1, IS_QUAD_OP | REG_DEF0 | NEEDS_FIXUP,
buzbeec5159d52012-03-03 11:48:39 -0800405 "lui", "!0r,0x!1h(!1d)", 4),
406 ENCODING_MAP(kMipsDeltaLo, 0x34000000,
407 kFmtBlt5_2, 16, 21, kFmtBitBlt, 15, 0, kFmtUnused, -1, -1,
buzbeea2ebdd72012-03-04 14:57:06 -0800408 kFmtUnused, -1, -1, IS_QUAD_OP | REG_DEF0_USE0 | NEEDS_FIXUP,
buzbeec5159d52012-03-03 11:48:39 -0800409 "ori", "!0r,!0r,0x!1h(!1d)", 4),
jeffhaofa147e22012-10-12 17:03:32 -0700410 ENCODING_MAP(kMipsCurrPC, 0x04110001,
buzbeec5159d52012-03-03 11:48:39 -0800411 kFmtUnused, -1, -1, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
412 kFmtUnused, -1, -1, NO_OPERAND | IS_BRANCH | REG_DEF_LR,
jeffhaofa147e22012-10-12 17:03:32 -0700413 "addiu", "ra,pc,8", 4),
buzbeea2ebdd72012-03-04 14:57:06 -0800414 ENCODING_MAP(kMipsSync, 0x0000000f,
415 kFmtBitBlt, 10, 6, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
416 kFmtUnused, -1, -1, IS_UNARY_OP,
417 "sync", ";", 4),
buzbeee3acd072012-02-25 17:03:10 -0800418 ENCODING_MAP(kMipsUndefined, 0x64000000,
419 kFmtUnused, -1, -1, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
420 kFmtUnused, -1, -1, NO_OPERAND,
buzbee71ac9942012-03-01 17:23:10 -0800421 "undefined", "", 4),
buzbeee3acd072012-02-25 17:03:10 -0800422};
423
buzbeea2ebdd72012-03-04 14:57:06 -0800424
425/*
426 * Convert a short-form branch to long form. Hopefully, this won't happen
427 * very often because the PIC sequence is especially unfortunate.
428 *
429 * Orig conditional branch
430 * -----------------------
431 * beq rs,rt,target
432 *
433 * Long conditional branch
434 * -----------------------
435 * bne rs,rt,hop
436 * bal .+8 ; r_RA <- anchor
437 * lui r_AT, ((target-anchor) >> 16)
438 * anchor:
439 * ori r_AT, r_AT, ((target-anchor) & 0xffff)
440 * addu r_AT, r_AT, r_RA
441 * jr r_AT
442 * hop:
443 *
444 * Orig unconditional branch
445 * -------------------------
446 * b target
447 *
448 * Long unconditional branch
449 * -----------------------
450 * bal .+8 ; r_RA <- anchor
451 * lui r_AT, ((target-anchor) >> 16)
452 * anchor:
453 * ori r_AT, r_AT, ((target-anchor) & 0xffff)
454 * addu r_AT, r_AT, r_RA
455 * jr r_AT
456 *
457 *
458 * NOTE: An out-of-range bal isn't supported because it should
459 * never happen with the current PIC model.
460 */
461void convertShortToLongBranch(CompilationUnit* cUnit, LIR* lir)
462{
Bill Buzbeea114add2012-05-03 15:00:40 -0700463 // For conditional branches we'll need to reverse the sense
464 bool unconditional = false;
465 int opcode = lir->opcode;
466 int dalvikOffset = lir->dalvikOffset;
467 switch (opcode) {
468 case kMipsBal:
469 LOG(FATAL) << "long branch and link unsupported";
470 case kMipsB:
471 unconditional = true;
472 break;
473 case kMipsBeq: opcode = kMipsBne; break;
474 case kMipsBne: opcode = kMipsBeq; break;
475 case kMipsBeqz: opcode = kMipsBnez; break;
476 case kMipsBgez: opcode = kMipsBltz; break;
477 case kMipsBgtz: opcode = kMipsBlez; break;
478 case kMipsBlez: opcode = kMipsBgtz; break;
479 case kMipsBltz: opcode = kMipsBgez; break;
480 case kMipsBnez: opcode = kMipsBeqz; break;
481 default:
buzbeecbd6d442012-11-17 14:11:25 -0800482 LOG(FATAL) << "Unexpected branch kind " << opcode;
Bill Buzbeea114add2012-05-03 15:00:40 -0700483 }
484 LIR* hopTarget = NULL;
485 if (!unconditional) {
486 hopTarget = rawLIR(cUnit, dalvikOffset, kPseudoTargetLabel);
487 LIR* hopBranch = rawLIR(cUnit, dalvikOffset, opcode, lir->operands[0],
488 lir->operands[1], 0, 0, 0, hopTarget);
489 oatInsertLIRBefore(lir, hopBranch);
490 }
491 LIR* currPC = rawLIR(cUnit, dalvikOffset, kMipsCurrPC);
492 oatInsertLIRBefore(lir, currPC);
493 LIR* anchor = rawLIR(cUnit, dalvikOffset, kPseudoTargetLabel);
494 LIR* deltaHi = rawLIR(cUnit, dalvikOffset, kMipsDeltaHi, r_AT, 0,
buzbeecbd6d442012-11-17 14:11:25 -0800495 reinterpret_cast<uintptr_t>(anchor), 0, 0, lir->target);
Bill Buzbeea114add2012-05-03 15:00:40 -0700496 oatInsertLIRBefore(lir, deltaHi);
497 oatInsertLIRBefore(lir, anchor);
498 LIR* deltaLo = rawLIR(cUnit, dalvikOffset, kMipsDeltaLo, r_AT, 0,
buzbeecbd6d442012-11-17 14:11:25 -0800499 reinterpret_cast<uintptr_t>(anchor), 0, 0, lir->target);
Bill Buzbeea114add2012-05-03 15:00:40 -0700500 oatInsertLIRBefore(lir, deltaLo);
501 LIR* addu = rawLIR(cUnit, dalvikOffset, kMipsAddu, r_AT, r_AT, r_RA);
502 oatInsertLIRBefore(lir, addu);
503 LIR* jr = rawLIR(cUnit, dalvikOffset, kMipsJr, r_AT);
504 oatInsertLIRBefore(lir, jr);
505 if (!unconditional) {
506 oatInsertLIRBefore(lir, hopTarget);
507 }
508 lir->flags.isNop = true;
buzbeea2ebdd72012-03-04 14:57:06 -0800509}
510
buzbeee3acd072012-02-25 17:03:10 -0800511/*
512 * Assemble the LIR into binary instruction format. Note that we may
513 * discover that pc-relative displacements may not fit the selected
514 * instruction. In those cases we will try to substitute a new code
515 * sequence or request that the trace be shortened and retried.
516 */
517AssemblerStatus oatAssembleInstructions(CompilationUnit *cUnit,
buzbeecbd6d442012-11-17 14:11:25 -0800518 uintptr_t startAddr)
buzbeee3acd072012-02-25 17:03:10 -0800519{
Bill Buzbeea114add2012-05-03 15:00:40 -0700520 LIR *lir;
521 AssemblerStatus res = kSuccess; // Assume success
buzbeee3acd072012-02-25 17:03:10 -0800522
buzbeecbd6d442012-11-17 14:11:25 -0800523 for (lir = cUnit->firstLIRInsn; lir; lir = NEXT_LIR(lir)) {
Bill Buzbeea114add2012-05-03 15:00:40 -0700524 if (lir->opcode < 0) {
525 continue;
buzbeee3acd072012-02-25 17:03:10 -0800526 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700527
528
529 if (lir->flags.isNop) {
530 continue;
531 }
532
533 if (lir->flags.pcRelFixup) {
534 if (lir->opcode == kMipsDelta) {
535 /*
536 * The "Delta" pseudo-ops load the difference between
537 * two pc-relative locations into a the target register
538 * found in operands[0]. The delta is determined by
539 * (label2 - label1), where label1 is a standard
540 * kPseudoTargetLabel and is stored in operands[2].
541 * If operands[3] is null, then label2 is a kPseudoTargetLabel
542 * and is found in lir->target. If operands[3] is non-NULL,
543 * then it is a Switch/Data table.
544 */
buzbeecbd6d442012-11-17 14:11:25 -0800545 int offset1 = (reinterpret_cast<LIR*>(lir->operands[2]))->offset;
546 SwitchTable *tabRec = reinterpret_cast<SwitchTable*>(lir->operands[3]);
Bill Buzbeea114add2012-05-03 15:00:40 -0700547 int offset2 = tabRec ? tabRec->offset : lir->target->offset;
548 int delta = offset2 - offset1;
jeffhao61f916c2012-10-25 17:48:51 -0700549 if ((delta & 0xffff) == delta && ((delta & 0x8000) == 0)) {
Bill Buzbeea114add2012-05-03 15:00:40 -0700550 // Fits
551 lir->operands[1] = delta;
552 } else {
553 // Doesn't fit - must expand to kMipsDelta[Hi|Lo] pair
554 LIR *newDeltaHi =
555 rawLIR(cUnit, lir->dalvikOffset, kMipsDeltaHi,
556 lir->operands[0], 0, lir->operands[2],
557 lir->operands[3], 0, lir->target);
buzbeecbd6d442012-11-17 14:11:25 -0800558 oatInsertLIRBefore(lir, newDeltaHi);
Bill Buzbeea114add2012-05-03 15:00:40 -0700559 LIR *newDeltaLo =
560 rawLIR(cUnit, lir->dalvikOffset, kMipsDeltaLo,
561 lir->operands[0], 0, lir->operands[2],
562 lir->operands[3], 0, lir->target);
buzbeecbd6d442012-11-17 14:11:25 -0800563 oatInsertLIRBefore(lir, newDeltaLo);
jeffhao61f916c2012-10-25 17:48:51 -0700564 LIR *newAddu =
565 rawLIR(cUnit, lir->dalvikOffset, kMipsAddu,
566 lir->operands[0], lir->operands[0], r_RA);
buzbeecbd6d442012-11-17 14:11:25 -0800567 oatInsertLIRBefore(lir, newAddu);
Bill Buzbeea114add2012-05-03 15:00:40 -0700568 lir->flags.isNop = true;
569 res = kRetryAll;
570 }
571 } else if (lir->opcode == kMipsDeltaLo) {
buzbeecbd6d442012-11-17 14:11:25 -0800572 int offset1 = (reinterpret_cast<LIR*>(lir->operands[2]))->offset;
573 SwitchTable *tabRec = reinterpret_cast<SwitchTable*>(lir->operands[3]);
Bill Buzbeea114add2012-05-03 15:00:40 -0700574 int offset2 = tabRec ? tabRec->offset : lir->target->offset;
575 int delta = offset2 - offset1;
576 lir->operands[1] = delta & 0xffff;
577 } else if (lir->opcode == kMipsDeltaHi) {
buzbeecbd6d442012-11-17 14:11:25 -0800578 int offset1 = (reinterpret_cast<LIR*>(lir->operands[2]))->offset;
579 SwitchTable *tabRec = reinterpret_cast<SwitchTable*>(lir->operands[3]);
Bill Buzbeea114add2012-05-03 15:00:40 -0700580 int offset2 = tabRec ? tabRec->offset : lir->target->offset;
581 int delta = offset2 - offset1;
582 lir->operands[1] = (delta >> 16) & 0xffff;
583 } else if (lir->opcode == kMipsB || lir->opcode == kMipsBal) {
buzbeecbd6d442012-11-17 14:11:25 -0800584 LIR *targetLIR = lir->target;
585 uintptr_t pc = lir->offset + 4;
586 uintptr_t target = targetLIR->offset;
Bill Buzbeea114add2012-05-03 15:00:40 -0700587 int delta = target - pc;
588 if (delta & 0x3) {
589 LOG(FATAL) << "PC-rel offset not multiple of 4: " << delta;
590 }
591 if (delta > 131068 || delta < -131069) {
592 res = kRetryAll;
593 convertShortToLongBranch(cUnit, lir);
594 } else {
595 lir->operands[0] = delta >> 2;
596 }
597 } else if (lir->opcode >= kMipsBeqz && lir->opcode <= kMipsBnez) {
buzbeecbd6d442012-11-17 14:11:25 -0800598 LIR *targetLIR = lir->target;
599 uintptr_t pc = lir->offset + 4;
600 uintptr_t target = targetLIR->offset;
Bill Buzbeea114add2012-05-03 15:00:40 -0700601 int delta = target - pc;
602 if (delta & 0x3) {
603 LOG(FATAL) << "PC-rel offset not multiple of 4: " << delta;
604 }
605 if (delta > 131068 || delta < -131069) {
606 res = kRetryAll;
607 convertShortToLongBranch(cUnit, lir);
608 } else {
609 lir->operands[1] = delta >> 2;
610 }
611 } else if (lir->opcode == kMipsBeq || lir->opcode == kMipsBne) {
buzbeecbd6d442012-11-17 14:11:25 -0800612 LIR *targetLIR = lir->target;
613 uintptr_t pc = lir->offset + 4;
614 uintptr_t target = targetLIR->offset;
Bill Buzbeea114add2012-05-03 15:00:40 -0700615 int delta = target - pc;
616 if (delta & 0x3) {
617 LOG(FATAL) << "PC-rel offset not multiple of 4: " << delta;
618 }
619 if (delta > 131068 || delta < -131069) {
620 res = kRetryAll;
621 convertShortToLongBranch(cUnit, lir);
622 } else {
623 lir->operands[2] = delta >> 2;
624 }
625 } else if (lir->opcode == kMipsJal) {
buzbeecbd6d442012-11-17 14:11:25 -0800626 uintptr_t curPC = (startAddr + lir->offset + 4) & ~3;
627 uintptr_t target = lir->operands[0];
Bill Buzbeea114add2012-05-03 15:00:40 -0700628 /* ensure PC-region branch can be used */
629 DCHECK_EQ((curPC & 0xF0000000), (target & 0xF0000000));
630 if (target & 0x3) {
631 LOG(FATAL) << "Jump target not multiple of 4: " << target;
632 }
633 lir->operands[0] = target >> 2;
634 } else if (lir->opcode == kMipsLahi) { /* ld address hi (via lui) */
buzbeecbd6d442012-11-17 14:11:25 -0800635 LIR *targetLIR = lir->target;
636 uintptr_t target = startAddr + targetLIR->offset;
Bill Buzbeea114add2012-05-03 15:00:40 -0700637 lir->operands[1] = target >> 16;
638 } else if (lir->opcode == kMipsLalo) { /* ld address lo (via ori) */
buzbeecbd6d442012-11-17 14:11:25 -0800639 LIR *targetLIR = lir->target;
640 uintptr_t target = startAddr + targetLIR->offset;
Bill Buzbeea114add2012-05-03 15:00:40 -0700641 lir->operands[2] = lir->operands[2] + target;
642 }
643 }
644
645 /*
646 * If one of the pc-relative instructions expanded we'll have
647 * to make another pass. Don't bother to fully assemble the
648 * instruction.
649 */
650 if (res != kSuccess) {
651 continue;
652 }
653 const MipsEncodingMap *encoder = &EncodingMap[lir->opcode];
buzbeeeaf09bc2012-11-15 14:51:41 -0800654 uint32_t bits = encoder->skeleton;
Bill Buzbeea114add2012-05-03 15:00:40 -0700655 int i;
656 for (i = 0; i < 4; i++) {
buzbeeeaf09bc2012-11-15 14:51:41 -0800657 uint32_t operand;
658 uint32_t value;
Bill Buzbeea114add2012-05-03 15:00:40 -0700659 operand = lir->operands[i];
660 switch (encoder->fieldLoc[i].kind) {
661 case kFmtUnused:
662 break;
663 case kFmtBitBlt:
664 if (encoder->fieldLoc[i].start == 0 && encoder->fieldLoc[i].end == 31) {
665 value = operand;
666 } else {
667 value = (operand << encoder->fieldLoc[i].start) &
668 ((1 << (encoder->fieldLoc[i].end + 1)) - 1);
669 }
670 bits |= value;
671 break;
672 case kFmtBlt5_2:
673 value = (operand & 0x1f);
674 bits |= (value << encoder->fieldLoc[i].start);
675 bits |= (value << encoder->fieldLoc[i].end);
676 break;
677 case kFmtDfp: {
buzbeef0504cd2012-11-13 16:31:10 -0800678 DCHECK(MIPS_DOUBLEREG(operand));
Elliott Hughes74847412012-06-20 18:10:21 -0700679 DCHECK_EQ((operand & 0x1), 0U);
buzbeef0504cd2012-11-13 16:31:10 -0800680 value = ((operand & MIPS_FP_REG_MASK) << encoder->fieldLoc[i].start) &
Bill Buzbeea114add2012-05-03 15:00:40 -0700681 ((1 << (encoder->fieldLoc[i].end + 1)) - 1);
682 bits |= value;
683 break;
684 }
685 case kFmtSfp:
buzbeef0504cd2012-11-13 16:31:10 -0800686 DCHECK(MIPS_SINGLEREG(operand));
687 value = ((operand & MIPS_FP_REG_MASK) << encoder->fieldLoc[i].start) &
Bill Buzbeea114add2012-05-03 15:00:40 -0700688 ((1 << (encoder->fieldLoc[i].end + 1)) - 1);
689 bits |= value;
690 break;
691 default:
buzbeecbd6d442012-11-17 14:11:25 -0800692 LOG(FATAL) << "Bad encoder format: " << encoder->fieldLoc[i].kind;
Bill Buzbeea114add2012-05-03 15:00:40 -0700693 }
694 }
jeffhao4f8f04a2012-10-02 18:10:35 -0700695 // We only support little-endian MIPS.
Bill Buzbeea114add2012-05-03 15:00:40 -0700696 cUnit->codeBuffer.push_back(bits & 0xff);
jeffhao4f8f04a2012-10-02 18:10:35 -0700697 cUnit->codeBuffer.push_back((bits >> 8) & 0xff);
698 cUnit->codeBuffer.push_back((bits >> 16) & 0xff);
699 cUnit->codeBuffer.push_back((bits >> 24) & 0xff);
Bill Buzbeea114add2012-05-03 15:00:40 -0700700 // TUNING: replace with proper delay slot handling
701 if (encoder->size == 8) {
702 const MipsEncodingMap *encoder = &EncodingMap[kMipsNop];
buzbeeeaf09bc2012-11-15 14:51:41 -0800703 uint32_t bits = encoder->skeleton;
Bill Buzbeea114add2012-05-03 15:00:40 -0700704 cUnit->codeBuffer.push_back(bits & 0xff);
jeffhao4f8f04a2012-10-02 18:10:35 -0700705 cUnit->codeBuffer.push_back((bits >> 8) & 0xff);
706 cUnit->codeBuffer.push_back((bits >> 16) & 0xff);
707 cUnit->codeBuffer.push_back((bits >> 24) & 0xff);
Bill Buzbeea114add2012-05-03 15:00:40 -0700708 }
709 }
710 return res;
buzbeee3acd072012-02-25 17:03:10 -0800711}
712
buzbeee88dfbf2012-03-05 11:19:57 -0800713int oatGetInsnSize(LIR* lir)
714{
Bill Buzbeea114add2012-05-03 15:00:40 -0700715 return EncodingMap[lir->opcode].size;
buzbeee88dfbf2012-03-05 11:19:57 -0800716}
buzbeee3acd072012-02-25 17:03:10 -0800717/*
718 * Target-dependent offset assignment.
buzbeee3acd072012-02-25 17:03:10 -0800719 * independent.
720 */
721int oatAssignInsnOffsets(CompilationUnit* cUnit)
722{
Bill Buzbeea114add2012-05-03 15:00:40 -0700723 LIR* mipsLIR;
724 int offset = 0;
buzbeee3acd072012-02-25 17:03:10 -0800725
buzbeecbd6d442012-11-17 14:11:25 -0800726 for (mipsLIR = cUnit->firstLIRInsn; mipsLIR; mipsLIR = NEXT_LIR(mipsLIR)) {
Bill Buzbeea114add2012-05-03 15:00:40 -0700727 mipsLIR->offset = offset;
728 if (mipsLIR->opcode >= 0) {
729 if (!mipsLIR->flags.isNop) {
730 offset += mipsLIR->flags.size;
731 }
732 } else if (mipsLIR->opcode == kPseudoPseudoAlign4) {
733 if (offset & 0x2) {
734 offset += 2;
735 mipsLIR->operands[0] = 1;
736 } else {
737 mipsLIR->operands[0] = 0;
738 }
buzbeee3acd072012-02-25 17:03:10 -0800739 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700740 /* Pseudo opcodes don't consume space */
741 }
buzbeee3acd072012-02-25 17:03:10 -0800742
Bill Buzbeea114add2012-05-03 15:00:40 -0700743 return offset;
buzbeee3acd072012-02-25 17:03:10 -0800744}
745
746} // namespace art