blob: f19c1f1e2920a5ebac45ffc018cded1cdddfabb5 [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"
buzbeee3acd072012-02-25 17:03:10 -080021
22namespace art {
23
24#define MAX_ASSEMBLER_RETRIES 50
25
26/*
27 * opcode: MipsOpCode enum
28 * skeleton: pre-designated bit-pattern for this opcode
29 * k0: key to applying ds/de
30 * ds: dest start bit position
31 * de: dest end bit position
32 * k1: key to applying s1s/s1e
33 * s1s: src1 start bit position
34 * s1e: src1 end bit position
35 * k2: key to applying s2s/s2e
36 * s2s: src2 start bit position
37 * s2e: src2 end bit position
38 * operands: number of operands (for sanity check purposes)
39 * name: mnemonic name
40 * fmt: for pretty-printing
41 */
42#define ENCODING_MAP(opcode, skeleton, k0, ds, de, k1, s1s, s1e, k2, s2s, s2e, \
43 k3, k3s, k3e, flags, name, fmt, size) \
44 {skeleton, {{k0, ds, de}, {k1, s1s, s1e}, {k2, s2s, s2e}, \
45 {k3, k3s, k3e}}, opcode, flags, name, fmt, size}
46
47/* Instruction dump string format keys: !pf, where "!" is the start
48 * of the key, "p" is which numeric operand to use and "f" is the
49 * print format.
50 *
51 * [p]ositions:
52 * 0 -> operands[0] (dest)
53 * 1 -> operands[1] (src1)
54 * 2 -> operands[2] (src2)
55 * 3 -> operands[3] (extra)
56 *
57 * [f]ormats:
58 * h -> 4-digit hex
59 * d -> decimal
60 * E -> decimal*4
61 * F -> decimal*2
62 * c -> branch condition (beq, bne, etc.)
63 * t -> pc-relative target
64 * T -> pc-region target
65 * u -> 1st half of bl[x] target
66 * v -> 2nd half ob bl[x] target
67 * R -> register list
68 * s -> single precision floating point register
69 * S -> double precision floating point register
70 * m -> Thumb2 modified immediate
71 * n -> complimented Thumb2 modified immediate
72 * M -> Thumb2 16-bit zero-extended immediate
73 * b -> 4-digit binary
buzbee82488f52012-03-02 08:20:26 -080074 * N -> append a NOP
buzbeee3acd072012-02-25 17:03:10 -080075 *
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 */
buzbee82488f52012-03-02 08:20:26 -080079/*
80 * TUNING: We're currently punting on the branch delay slots. All branch
81 * instructions in this map are given a size of 8, which during assembly
82 * is expanded to include a nop. This scheme should be replaced with
83 * an assembler pass to fill those slots when possible.
84 */
buzbeee3acd072012-02-25 17:03:10 -080085MipsEncodingMap EncodingMap[kMipsLast] = {
86 ENCODING_MAP(kMips32BitData, 0x00000000,
87 kFmtBitBlt, 31, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
88 kFmtUnused, -1, -1, IS_UNARY_OP,
buzbee71ac9942012-03-01 17:23:10 -080089 "data", "0x!0h(!0d)", 4),
buzbeee3acd072012-02-25 17:03:10 -080090 ENCODING_MAP(kMipsAddiu, 0x24000000,
91 kFmtBitBlt, 20, 16, kFmtBitBlt, 25, 21, kFmtBitBlt, 15, 0,
92 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
buzbee71ac9942012-03-01 17:23:10 -080093 "addiu", "!0r,!1r,0x!2h(!2d)", 4),
buzbeee3acd072012-02-25 17:03:10 -080094 ENCODING_MAP(kMipsAddu, 0x00000021,
95 kFmtBitBlt, 15, 11, kFmtBitBlt, 25, 21, kFmtBitBlt, 20, 16,
96 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
buzbee71ac9942012-03-01 17:23:10 -080097 "addu", "!0r,!1r,!2r", 4),
buzbeee3acd072012-02-25 17:03:10 -080098 ENCODING_MAP(kMipsAnd, 0x00000024,
99 kFmtBitBlt, 15, 11, kFmtBitBlt, 25, 21, kFmtBitBlt, 20, 16,
100 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
buzbee71ac9942012-03-01 17:23:10 -0800101 "and", "!0r,!1r,!2r", 4),
buzbeee3acd072012-02-25 17:03:10 -0800102 ENCODING_MAP(kMipsAndi, 0x30000000,
103 kFmtBitBlt, 20, 16, kFmtBitBlt, 25, 21, kFmtBitBlt, 15, 0,
104 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
buzbee71ac9942012-03-01 17:23:10 -0800105 "andi", "!0r,!1r,0x!2h(!2d)", 4),
buzbeee3acd072012-02-25 17:03:10 -0800106 ENCODING_MAP(kMipsB, 0x10000000,
107 kFmtBitBlt, 15, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
Ian Rogers680b1bd2012-03-07 20:18:49 -0800108 kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH | NEEDS_FIXUP,
buzbee82488f52012-03-02 08:20:26 -0800109 "b", "!0t!0N", 8),
buzbeee3acd072012-02-25 17:03:10 -0800110 ENCODING_MAP(kMipsBal, 0x04110000,
111 kFmtBitBlt, 15, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
Ian Rogers680b1bd2012-03-07 20:18:49 -0800112 kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH | REG_DEF_LR |
buzbeea2ebdd72012-03-04 14:57:06 -0800113 NEEDS_FIXUP, "bal", "!0t!0N", 8),
buzbeee3acd072012-02-25 17:03:10 -0800114 ENCODING_MAP(kMipsBeq, 0x10000000,
115 kFmtBitBlt, 25, 21, kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0,
buzbeea2ebdd72012-03-04 14:57:06 -0800116 kFmtUnused, -1, -1, IS_BINARY_OP | IS_BRANCH | REG_USE01 |
117 NEEDS_FIXUP, "beq", "!0r,!1r,!2t!0N", 8),
buzbeee3acd072012-02-25 17:03:10 -0800118 ENCODING_MAP(kMipsBeqz, 0x10000000, /* same as beq above with t = $zero */
119 kFmtBitBlt, 25, 21, kFmtBitBlt, 15, 0, kFmtUnused, -1, -1,
buzbeea2ebdd72012-03-04 14:57:06 -0800120 kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH | REG_USE0 |
121 NEEDS_FIXUP, "beqz", "!0r,!1t!0N", 8),
buzbeee3acd072012-02-25 17:03:10 -0800122 ENCODING_MAP(kMipsBgez, 0x04010000,
123 kFmtBitBlt, 25, 21, kFmtBitBlt, 15, 0, kFmtUnused, -1, -1,
buzbeea2ebdd72012-03-04 14:57:06 -0800124 kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH | REG_USE0 |
125 NEEDS_FIXUP, "bgez", "!0r,!1t!0N", 8),
buzbeee3acd072012-02-25 17:03:10 -0800126 ENCODING_MAP(kMipsBgtz, 0x1C000000,
127 kFmtBitBlt, 25, 21, kFmtBitBlt, 15, 0, kFmtUnused, -1, -1,
buzbeea2ebdd72012-03-04 14:57:06 -0800128 kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH | REG_USE0 |
129 NEEDS_FIXUP, "bgtz", "!0r,!1t!0N", 8),
buzbeee3acd072012-02-25 17:03:10 -0800130 ENCODING_MAP(kMipsBlez, 0x18000000,
131 kFmtBitBlt, 25, 21, kFmtBitBlt, 15, 0, kFmtUnused, -1, -1,
buzbeea2ebdd72012-03-04 14:57:06 -0800132 kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH | REG_USE0 |
133 NEEDS_FIXUP, "blez", "!0r,!1t!0N", 8),
buzbeee3acd072012-02-25 17:03:10 -0800134 ENCODING_MAP(kMipsBltz, 0x04000000,
135 kFmtBitBlt, 25, 21, kFmtBitBlt, 15, 0, kFmtUnused, -1, -1,
buzbeea2ebdd72012-03-04 14:57:06 -0800136 kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH | REG_USE0 |
137 NEEDS_FIXUP, "bltz", "!0r,!1t!0N", 8),
buzbeee3acd072012-02-25 17:03:10 -0800138 ENCODING_MAP(kMipsBnez, 0x14000000, /* same as bne below with t = $zero */
139 kFmtBitBlt, 25, 21, kFmtBitBlt, 15, 0, kFmtUnused, -1, -1,
buzbeea2ebdd72012-03-04 14:57:06 -0800140 kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH | REG_USE0 |
141 NEEDS_FIXUP, "bnez", "!0r,!1t!0N", 8),
buzbeee3acd072012-02-25 17:03:10 -0800142 ENCODING_MAP(kMipsBne, 0x14000000,
143 kFmtBitBlt, 25, 21, kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0,
buzbeea2ebdd72012-03-04 14:57:06 -0800144 kFmtUnused, -1, -1, IS_BINARY_OP | IS_BRANCH | REG_USE01 |
145 NEEDS_FIXUP, "bne", "!0r,!1r,!2t!0N", 8),
buzbeee3acd072012-02-25 17:03:10 -0800146 ENCODING_MAP(kMipsDiv, 0x0000001a,
147 kFmtUnused, -1, -1, kFmtUnused, -1, -1, kFmtBitBlt, 25, 21,
148 kFmtBitBlt, 20, 16, IS_QUAD_OP | REG_DEF01 | REG_USE23,
buzbee71ac9942012-03-01 17:23:10 -0800149 "div", "!2r,!3r", 4),
buzbeee3acd072012-02-25 17:03:10 -0800150#if __mips_isa_rev>=2
151 ENCODING_MAP(kMipsExt, 0x7c000000,
152 kFmtBitBlt, 20, 16, kFmtBitBlt, 25, 21, kFmtBitBlt, 10, 6,
153 kFmtBitBlt, 15, 11, IS_QUAD_OP | REG_DEF0 | REG_USE1,
buzbee71ac9942012-03-01 17:23:10 -0800154 "ext", "!0r,!1r,!2d,!3D", 4),
buzbeee3acd072012-02-25 17:03:10 -0800155#endif
156 ENCODING_MAP(kMipsJal, 0x0c000000,
157 kFmtBitBlt, 25, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
158 kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH | REG_DEF_LR,
buzbee82488f52012-03-02 08:20:26 -0800159 "jal", "!0T(!0E)!0N", 8),
buzbeee3acd072012-02-25 17:03:10 -0800160 ENCODING_MAP(kMipsJalr, 0x00000009,
161 kFmtBitBlt, 15, 11, kFmtBitBlt, 25, 21, kFmtUnused, -1, -1,
162 kFmtUnused, -1, -1, IS_BINARY_OP | IS_BRANCH | REG_DEF0_USE1,
buzbee82488f52012-03-02 08:20:26 -0800163 "jalr", "!0r,!1r!0N", 8),
buzbeee3acd072012-02-25 17:03:10 -0800164 ENCODING_MAP(kMipsJr, 0x00000008,
165 kFmtBitBlt, 25, 21, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
buzbeea2ebdd72012-03-04 14:57:06 -0800166 kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH | REG_USE0 |
167 NEEDS_FIXUP, "jr", "!0r!0N", 8),
buzbeee3acd072012-02-25 17:03:10 -0800168 ENCODING_MAP(kMipsLahi, 0x3C000000,
169 kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0, kFmtUnused, -1, -1,
170 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0,
buzbee71ac9942012-03-01 17:23:10 -0800171 "lahi/lui", "!0r,0x!1h(!1d)", 4),
buzbeee3acd072012-02-25 17:03:10 -0800172 ENCODING_MAP(kMipsLalo, 0x34000000,
173 kFmtBitBlt, 20, 16, kFmtBitBlt, 25, 21, kFmtBitBlt, 15, 0,
174 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
buzbee71ac9942012-03-01 17:23:10 -0800175 "lalo/ori", "!0r,!1r,0x!2h(!2d)", 4),
buzbeee3acd072012-02-25 17:03:10 -0800176 ENCODING_MAP(kMipsLui, 0x3C000000,
177 kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0, kFmtUnused, -1, -1,
178 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0,
buzbee71ac9942012-03-01 17:23:10 -0800179 "lui", "!0r,0x!1h(!1d)", 4),
buzbeee3acd072012-02-25 17:03:10 -0800180 ENCODING_MAP(kMipsLb, 0x80000000,
181 kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0, kFmtBitBlt, 25, 21,
182 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE2 | IS_LOAD,
buzbee71ac9942012-03-01 17:23:10 -0800183 "lb", "!0r,!1d(!2r)", 4),
buzbeee3acd072012-02-25 17:03:10 -0800184 ENCODING_MAP(kMipsLbu, 0x90000000,
185 kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0, kFmtBitBlt, 25, 21,
186 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE2 | IS_LOAD,
buzbee71ac9942012-03-01 17:23:10 -0800187 "lbu", "!0r,!1d(!2r)", 4),
buzbeee3acd072012-02-25 17:03:10 -0800188 ENCODING_MAP(kMipsLh, 0x84000000,
189 kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0, kFmtBitBlt, 25, 21,
190 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE2 | IS_LOAD,
buzbee71ac9942012-03-01 17:23:10 -0800191 "lh", "!0r,!1d(!2r)", 4),
buzbeee3acd072012-02-25 17:03:10 -0800192 ENCODING_MAP(kMipsLhu, 0x94000000,
193 kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0, kFmtBitBlt, 25, 21,
194 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE2 | IS_LOAD,
buzbee71ac9942012-03-01 17:23:10 -0800195 "lhu", "!0r,!1d(!2r)", 4),
buzbeee3acd072012-02-25 17:03:10 -0800196 ENCODING_MAP(kMipsLw, 0x8C000000,
197 kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0, kFmtBitBlt, 25, 21,
198 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE2 | IS_LOAD,
buzbee71ac9942012-03-01 17:23:10 -0800199 "lw", "!0r,!1d(!2r)", 4),
buzbeee3acd072012-02-25 17:03:10 -0800200 ENCODING_MAP(kMipsMfhi, 0x00000010,
201 kFmtBitBlt, 15, 11, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
202 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
buzbee71ac9942012-03-01 17:23:10 -0800203 "mfhi", "!0r", 4),
buzbeee3acd072012-02-25 17:03:10 -0800204 ENCODING_MAP(kMipsMflo, 0x00000012,
205 kFmtBitBlt, 15, 11, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
206 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
buzbee71ac9942012-03-01 17:23:10 -0800207 "mflo", "!0r", 4),
buzbeee3acd072012-02-25 17:03:10 -0800208 ENCODING_MAP(kMipsMove, 0x00000025, /* or using zero reg */
209 kFmtBitBlt, 15, 11, kFmtBitBlt, 25, 21, kFmtUnused, -1, -1,
210 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
buzbee71ac9942012-03-01 17:23:10 -0800211 "move", "!0r,!1r", 4),
buzbeee3acd072012-02-25 17:03:10 -0800212 ENCODING_MAP(kMipsMovz, 0x0000000a,
213 kFmtBitBlt, 15, 11, kFmtBitBlt, 25, 21, kFmtBitBlt, 20, 16,
214 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
buzbee71ac9942012-03-01 17:23:10 -0800215 "movz", "!0r,!1r,!2r", 4),
buzbeee3acd072012-02-25 17:03:10 -0800216 ENCODING_MAP(kMipsMul, 0x70000002,
217 kFmtBitBlt, 15, 11, kFmtBitBlt, 25, 21, kFmtBitBlt, 20, 16,
218 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
buzbee71ac9942012-03-01 17:23:10 -0800219 "mul", "!0r,!1r,!2r", 4),
buzbeee3acd072012-02-25 17:03:10 -0800220 ENCODING_MAP(kMipsNop, 0x00000000,
221 kFmtUnused, -1, -1, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
222 kFmtUnused, -1, -1, NO_OPERAND,
buzbeec5159d52012-03-03 11:48:39 -0800223 "nop", ";", 4),
buzbeee3acd072012-02-25 17:03:10 -0800224 ENCODING_MAP(kMipsNor, 0x00000027, /* used for "not" too */
225 kFmtBitBlt, 15, 11, kFmtBitBlt, 25, 21, kFmtBitBlt, 20, 16,
226 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
buzbee71ac9942012-03-01 17:23:10 -0800227 "nor", "!0r,!1r,!2r", 4),
buzbeee3acd072012-02-25 17:03:10 -0800228 ENCODING_MAP(kMipsOr, 0x00000025,
229 kFmtBitBlt, 15, 11, kFmtBitBlt, 25, 21, kFmtBitBlt, 20, 16,
230 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
buzbee71ac9942012-03-01 17:23:10 -0800231 "or", "!0r,!1r,!2r", 4),
buzbeee3acd072012-02-25 17:03:10 -0800232 ENCODING_MAP(kMipsOri, 0x34000000,
233 kFmtBitBlt, 20, 16, kFmtBitBlt, 25, 21, kFmtBitBlt, 15, 0,
234 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
buzbee71ac9942012-03-01 17:23:10 -0800235 "ori", "!0r,!1r,0x!2h(!2d)", 4),
buzbeee3acd072012-02-25 17:03:10 -0800236 ENCODING_MAP(kMipsPref, 0xCC000000,
237 kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0, kFmtBitBlt, 25, 21,
238 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE2,
buzbee71ac9942012-03-01 17:23:10 -0800239 "pref", "!0d,!1d(!2r)", 4),
buzbeee3acd072012-02-25 17:03:10 -0800240 ENCODING_MAP(kMipsSb, 0xA0000000,
241 kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0, kFmtBitBlt, 25, 21,
242 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE02 | IS_STORE,
buzbee71ac9942012-03-01 17:23:10 -0800243 "sb", "!0r,!1d(!2r)", 4),
buzbeee3acd072012-02-25 17:03:10 -0800244#if __mips_isa_rev>=2
245 ENCODING_MAP(kMipsSeb, 0x7c000420,
246 kFmtBitBlt, 15, 11, kFmtBitBlt, 20, 16, kFmtUnused, -1, -1,
247 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
buzbee71ac9942012-03-01 17:23:10 -0800248 "seb", "!0r,!1r", 4),
buzbeee3acd072012-02-25 17:03:10 -0800249 ENCODING_MAP(kMipsSeh, 0x7c000620,
250 kFmtBitBlt, 15, 11, kFmtBitBlt, 20, 16, kFmtUnused, -1, -1,
251 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
buzbee71ac9942012-03-01 17:23:10 -0800252 "seh", "!0r,!1r", 4),
buzbeee3acd072012-02-25 17:03:10 -0800253#endif
254 ENCODING_MAP(kMipsSh, 0xA4000000,
255 kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0, kFmtBitBlt, 25, 21,
256 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE02 | IS_STORE,
buzbee71ac9942012-03-01 17:23:10 -0800257 "sh", "!0r,!1d(!2r)", 4),
buzbeee3acd072012-02-25 17:03:10 -0800258 ENCODING_MAP(kMipsSll, 0x00000000,
259 kFmtBitBlt, 15, 11, kFmtBitBlt, 20, 16, kFmtBitBlt, 10, 6,
260 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
buzbee71ac9942012-03-01 17:23:10 -0800261 "sll", "!0r,!1r,0x!2h(!2d)", 4),
buzbeee3acd072012-02-25 17:03:10 -0800262 ENCODING_MAP(kMipsSllv, 0x00000004,
263 kFmtBitBlt, 15, 11, kFmtBitBlt, 20, 16, kFmtBitBlt, 25, 21,
264 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
buzbee71ac9942012-03-01 17:23:10 -0800265 "sllv", "!0r,!1r,!2r", 4),
buzbeee3acd072012-02-25 17:03:10 -0800266 ENCODING_MAP(kMipsSlt, 0x0000002a,
267 kFmtBitBlt, 15, 11, kFmtBitBlt, 25, 21, kFmtBitBlt, 20, 16,
268 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
buzbee71ac9942012-03-01 17:23:10 -0800269 "slt", "!0r,!1r,!2r", 4),
buzbeee3acd072012-02-25 17:03:10 -0800270 ENCODING_MAP(kMipsSlti, 0x28000000,
271 kFmtBitBlt, 20, 16, kFmtBitBlt, 25, 21, kFmtBitBlt, 15, 0,
272 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
buzbee71ac9942012-03-01 17:23:10 -0800273 "slti", "!0r,!1r,0x!2h(!2d)", 4),
buzbeee3acd072012-02-25 17:03:10 -0800274 ENCODING_MAP(kMipsSltu, 0x0000002b,
275 kFmtBitBlt, 15, 11, kFmtBitBlt, 25, 21, kFmtBitBlt, 20, 16,
276 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
buzbee71ac9942012-03-01 17:23:10 -0800277 "sltu", "!0r,!1r,!2r", 4),
buzbeee3acd072012-02-25 17:03:10 -0800278 ENCODING_MAP(kMipsSra, 0x00000003,
279 kFmtBitBlt, 15, 11, kFmtBitBlt, 20, 16, kFmtBitBlt, 10, 6,
280 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
buzbee71ac9942012-03-01 17:23:10 -0800281 "sra", "!0r,!1r,0x!2h(!2d)", 4),
buzbeee3acd072012-02-25 17:03:10 -0800282 ENCODING_MAP(kMipsSrav, 0x00000007,
283 kFmtBitBlt, 15, 11, kFmtBitBlt, 20, 16, kFmtBitBlt, 25, 21,
284 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
buzbee71ac9942012-03-01 17:23:10 -0800285 "srav", "!0r,!1r,!2r", 4),
buzbeee3acd072012-02-25 17:03:10 -0800286 ENCODING_MAP(kMipsSrl, 0x00000002,
287 kFmtBitBlt, 15, 11, kFmtBitBlt, 20, 16, kFmtBitBlt, 10, 6,
288 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
buzbee71ac9942012-03-01 17:23:10 -0800289 "srl", "!0r,!1r,0x!2h(!2d)", 4),
buzbeee3acd072012-02-25 17:03:10 -0800290 ENCODING_MAP(kMipsSrlv, 0x00000006,
291 kFmtBitBlt, 15, 11, kFmtBitBlt, 20, 16, kFmtBitBlt, 25, 21,
292 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
buzbee71ac9942012-03-01 17:23:10 -0800293 "srlv", "!0r,!1r,!2r", 4),
buzbeee3acd072012-02-25 17:03:10 -0800294 ENCODING_MAP(kMipsSubu, 0x00000023, /* used for "neg" too */
295 kFmtBitBlt, 15, 11, kFmtBitBlt, 25, 21, kFmtBitBlt, 20, 16,
296 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
buzbee71ac9942012-03-01 17:23:10 -0800297 "subu", "!0r,!1r,!2r", 4),
buzbeee3acd072012-02-25 17:03:10 -0800298 ENCODING_MAP(kMipsSw, 0xAC000000,
299 kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0, kFmtBitBlt, 25, 21,
300 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE02 | IS_STORE,
buzbee71ac9942012-03-01 17:23:10 -0800301 "sw", "!0r,!1d(!2r)", 4),
buzbeee3acd072012-02-25 17:03:10 -0800302 ENCODING_MAP(kMipsXor, 0x00000026,
303 kFmtBitBlt, 15, 11, kFmtBitBlt, 25, 21, kFmtBitBlt, 20, 16,
304 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
buzbee71ac9942012-03-01 17:23:10 -0800305 "xor", "!0r,!1r,!2r", 4),
buzbeee3acd072012-02-25 17:03:10 -0800306 ENCODING_MAP(kMipsXori, 0x38000000,
307 kFmtBitBlt, 20, 16, kFmtBitBlt, 25, 21, kFmtBitBlt, 15, 0,
308 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
buzbee71ac9942012-03-01 17:23:10 -0800309 "xori", "!0r,!1r,0x!2h(!2d)", 4),
buzbeee3acd072012-02-25 17:03:10 -0800310#ifdef __mips_hard_float
311 ENCODING_MAP(kMipsFadds, 0x46000000,
312 kFmtSfp, 10, 6, kFmtSfp, 15, 11, kFmtSfp, 20, 16,
313 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
buzbee71ac9942012-03-01 17:23:10 -0800314 "add.s", "!0s,!1s,!2s", 4),
buzbeee3acd072012-02-25 17:03:10 -0800315 ENCODING_MAP(kMipsFsubs, 0x46000001,
316 kFmtSfp, 10, 6, kFmtSfp, 15, 11, kFmtSfp, 20, 16,
317 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
buzbee71ac9942012-03-01 17:23:10 -0800318 "sub.s", "!0s,!1s,!2s", 4),
buzbeee3acd072012-02-25 17:03:10 -0800319 ENCODING_MAP(kMipsFmuls, 0x46000002,
320 kFmtSfp, 10, 6, kFmtSfp, 15, 11, kFmtSfp, 20, 16,
321 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
buzbee71ac9942012-03-01 17:23:10 -0800322 "mul.s", "!0s,!1s,!2s", 4),
buzbeee3acd072012-02-25 17:03:10 -0800323 ENCODING_MAP(kMipsFdivs, 0x46000003,
324 kFmtSfp, 10, 6, kFmtSfp, 15, 11, kFmtSfp, 20, 16,
325 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
buzbee71ac9942012-03-01 17:23:10 -0800326 "div.s", "!0s,!1s,!2s", 4),
buzbeee3acd072012-02-25 17:03:10 -0800327 ENCODING_MAP(kMipsFaddd, 0x46200000,
328 kFmtDfp, 10, 6, kFmtDfp, 15, 11, kFmtDfp, 20, 16,
329 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
buzbee71ac9942012-03-01 17:23:10 -0800330 "add.d", "!0S,!1S,!2S", 4),
buzbeee3acd072012-02-25 17:03:10 -0800331 ENCODING_MAP(kMipsFsubd, 0x46200001,
332 kFmtDfp, 10, 6, kFmtDfp, 15, 11, kFmtDfp, 20, 16,
333 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
buzbee71ac9942012-03-01 17:23:10 -0800334 "sub.d", "!0S,!1S,!2S", 4),
buzbeee3acd072012-02-25 17:03:10 -0800335 ENCODING_MAP(kMipsFmuld, 0x46200002,
336 kFmtDfp, 10, 6, kFmtDfp, 15, 11, kFmtDfp, 20, 16,
337 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
buzbee71ac9942012-03-01 17:23:10 -0800338 "mul.d", "!0S,!1S,!2S", 4),
buzbeee3acd072012-02-25 17:03:10 -0800339 ENCODING_MAP(kMipsFdivd, 0x46200003,
340 kFmtDfp, 10, 6, kFmtDfp, 15, 11, kFmtDfp, 20, 16,
341 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
buzbee71ac9942012-03-01 17:23:10 -0800342 "div.d", "!0S,!1S,!2S", 4),
buzbeee3acd072012-02-25 17:03:10 -0800343 ENCODING_MAP(kMipsFcvtsd, 0x46200020,
344 kFmtSfp, 10, 6, kFmtDfp, 15, 11, kFmtUnused, -1, -1,
345 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
buzbee71ac9942012-03-01 17:23:10 -0800346 "cvt.s.d", "!0s,!1S", 4),
buzbeee3acd072012-02-25 17:03:10 -0800347 ENCODING_MAP(kMipsFcvtsw, 0x46800020,
348 kFmtSfp, 10, 6, kFmtSfp, 15, 11, kFmtUnused, -1, -1,
349 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
buzbee71ac9942012-03-01 17:23:10 -0800350 "cvt.s.w", "!0s,!1s", 4),
buzbeee3acd072012-02-25 17:03:10 -0800351 ENCODING_MAP(kMipsFcvtds, 0x46000021,
352 kFmtDfp, 10, 6, kFmtSfp, 15, 11, kFmtUnused, -1, -1,
353 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
buzbee71ac9942012-03-01 17:23:10 -0800354 "cvt.d.s", "!0S,!1s", 4),
buzbeee3acd072012-02-25 17:03:10 -0800355 ENCODING_MAP(kMipsFcvtdw, 0x46800021,
356 kFmtDfp, 10, 6, kFmtSfp, 15, 11, kFmtUnused, -1, -1,
357 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
buzbee71ac9942012-03-01 17:23:10 -0800358 "cvt.d.w", "!0S,!1s", 4),
buzbeee3acd072012-02-25 17:03:10 -0800359 ENCODING_MAP(kMipsFcvtws, 0x46000024,
360 kFmtSfp, 10, 6, kFmtSfp, 15, 11, kFmtUnused, -1, -1,
361 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
buzbee71ac9942012-03-01 17:23:10 -0800362 "cvt.w.s", "!0s,!1s", 4),
buzbeee3acd072012-02-25 17:03:10 -0800363 ENCODING_MAP(kMipsFcvtwd, 0x46200024,
364 kFmtSfp, 10, 6, kFmtDfp, 15, 11, kFmtUnused, -1, -1,
365 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
buzbee71ac9942012-03-01 17:23:10 -0800366 "cvt.w.d", "!0s,!1S", 4),
buzbeee3acd072012-02-25 17:03:10 -0800367 ENCODING_MAP(kMipsFmovs, 0x46000006,
368 kFmtSfp, 10, 6, kFmtSfp, 15, 11, kFmtUnused, -1, -1,
369 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
buzbee71ac9942012-03-01 17:23:10 -0800370 "mov.s", "!0s,!1s", 4),
buzbeee3acd072012-02-25 17:03:10 -0800371 ENCODING_MAP(kMipsFmovd, 0x46200006,
372 kFmtDfp, 10, 6, kFmtDfp, 15, 11, kFmtUnused, -1, -1,
373 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
buzbee71ac9942012-03-01 17:23:10 -0800374 "mov.d", "!0S,!1S", 4),
buzbeee3acd072012-02-25 17:03:10 -0800375 ENCODING_MAP(kMipsFlwc1, 0xC4000000,
376 kFmtSfp, 20, 16, kFmtBitBlt, 15, 0, kFmtBitBlt, 25, 21,
377 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE2 | IS_LOAD,
buzbee71ac9942012-03-01 17:23:10 -0800378 "lwc1", "!0s,!1d(!2r)", 4),
buzbeee3acd072012-02-25 17:03:10 -0800379 ENCODING_MAP(kMipsFldc1, 0xD4000000,
380 kFmtDfp, 20, 16, kFmtBitBlt, 15, 0, kFmtBitBlt, 25, 21,
381 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE2 | IS_LOAD,
buzbee71ac9942012-03-01 17:23:10 -0800382 "ldc1", "!0S,!1d(!2r)", 4),
buzbeee3acd072012-02-25 17:03:10 -0800383 ENCODING_MAP(kMipsFswc1, 0xE4000000,
384 kFmtSfp, 20, 16, kFmtBitBlt, 15, 0, kFmtBitBlt, 25, 21,
385 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE02 | IS_STORE,
buzbee71ac9942012-03-01 17:23:10 -0800386 "swc1", "!0s,!1d(!2r)", 4),
buzbeee3acd072012-02-25 17:03:10 -0800387 ENCODING_MAP(kMipsFsdc1, 0xF4000000,
388 kFmtDfp, 20, 16, kFmtBitBlt, 15, 0, kFmtBitBlt, 25, 21,
389 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE02 | IS_STORE,
buzbee71ac9942012-03-01 17:23:10 -0800390 "sdc1", "!0S,!1d(!2r)", 4),
buzbeee3acd072012-02-25 17:03:10 -0800391 ENCODING_MAP(kMipsMfc1, 0x44000000,
392 kFmtBitBlt, 20, 16, kFmtSfp, 15, 11, kFmtUnused, -1, -1,
393 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
buzbee71ac9942012-03-01 17:23:10 -0800394 "mfc1", "!0r,!1s", 4),
buzbeee3acd072012-02-25 17:03:10 -0800395 ENCODING_MAP(kMipsMtc1, 0x44800000,
396 kFmtBitBlt, 20, 16, kFmtSfp, 15, 11, kFmtUnused, -1, -1,
397 kFmtUnused, -1, -1, IS_BINARY_OP | REG_USE0 | REG_DEF1,
buzbee71ac9942012-03-01 17:23:10 -0800398 "mtc1", "!0r,!1s", 4),
buzbeee3acd072012-02-25 17:03:10 -0800399#endif
buzbeec5159d52012-03-03 11:48:39 -0800400 ENCODING_MAP(kMipsDelta, 0x27e00000,
401 kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0, kFmtUnused, 15, 0,
buzbeea2ebdd72012-03-04 14:57:06 -0800402 kFmtUnused, -1, -1, IS_QUAD_OP | REG_DEF0 | REG_USE_LR |
jeffhaofa147e22012-10-12 17:03:32 -0700403 NEEDS_FIXUP, "addiu", "!0r,ra,0x!1h(!1d)", 4),
buzbeec5159d52012-03-03 11:48:39 -0800404 ENCODING_MAP(kMipsDeltaHi, 0x3C000000,
405 kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0, kFmtUnused, -1, -1,
buzbeea2ebdd72012-03-04 14:57:06 -0800406 kFmtUnused, -1, -1, IS_QUAD_OP | REG_DEF0 | NEEDS_FIXUP,
buzbeec5159d52012-03-03 11:48:39 -0800407 "lui", "!0r,0x!1h(!1d)", 4),
408 ENCODING_MAP(kMipsDeltaLo, 0x34000000,
409 kFmtBlt5_2, 16, 21, kFmtBitBlt, 15, 0, kFmtUnused, -1, -1,
buzbeea2ebdd72012-03-04 14:57:06 -0800410 kFmtUnused, -1, -1, IS_QUAD_OP | REG_DEF0_USE0 | NEEDS_FIXUP,
buzbeec5159d52012-03-03 11:48:39 -0800411 "ori", "!0r,!0r,0x!1h(!1d)", 4),
jeffhaofa147e22012-10-12 17:03:32 -0700412 ENCODING_MAP(kMipsCurrPC, 0x04110001,
buzbeec5159d52012-03-03 11:48:39 -0800413 kFmtUnused, -1, -1, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
414 kFmtUnused, -1, -1, NO_OPERAND | IS_BRANCH | REG_DEF_LR,
jeffhaofa147e22012-10-12 17:03:32 -0700415 "addiu", "ra,pc,8", 4),
buzbeea2ebdd72012-03-04 14:57:06 -0800416 ENCODING_MAP(kMipsSync, 0x0000000f,
417 kFmtBitBlt, 10, 6, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
418 kFmtUnused, -1, -1, IS_UNARY_OP,
419 "sync", ";", 4),
buzbeee3acd072012-02-25 17:03:10 -0800420 ENCODING_MAP(kMipsUndefined, 0x64000000,
421 kFmtUnused, -1, -1, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
422 kFmtUnused, -1, -1, NO_OPERAND,
buzbee71ac9942012-03-01 17:23:10 -0800423 "undefined", "", 4),
buzbeee3acd072012-02-25 17:03:10 -0800424};
425
buzbeea2ebdd72012-03-04 14:57:06 -0800426
427/*
428 * Convert a short-form branch to long form. Hopefully, this won't happen
429 * very often because the PIC sequence is especially unfortunate.
430 *
431 * Orig conditional branch
432 * -----------------------
433 * beq rs,rt,target
434 *
435 * Long conditional branch
436 * -----------------------
437 * bne rs,rt,hop
438 * bal .+8 ; r_RA <- anchor
439 * lui r_AT, ((target-anchor) >> 16)
440 * anchor:
441 * ori r_AT, r_AT, ((target-anchor) & 0xffff)
442 * addu r_AT, r_AT, r_RA
443 * jr r_AT
444 * hop:
445 *
446 * Orig unconditional branch
447 * -------------------------
448 * b target
449 *
450 * Long unconditional branch
451 * -----------------------
452 * bal .+8 ; r_RA <- anchor
453 * lui r_AT, ((target-anchor) >> 16)
454 * anchor:
455 * ori r_AT, r_AT, ((target-anchor) & 0xffff)
456 * addu r_AT, r_AT, r_RA
457 * jr r_AT
458 *
459 *
460 * NOTE: An out-of-range bal isn't supported because it should
461 * never happen with the current PIC model.
462 */
463void convertShortToLongBranch(CompilationUnit* cUnit, LIR* lir)
464{
Bill Buzbeea114add2012-05-03 15:00:40 -0700465 // For conditional branches we'll need to reverse the sense
466 bool unconditional = false;
467 int opcode = lir->opcode;
468 int dalvikOffset = lir->dalvikOffset;
469 switch (opcode) {
470 case kMipsBal:
471 LOG(FATAL) << "long branch and link unsupported";
472 case kMipsB:
473 unconditional = true;
474 break;
475 case kMipsBeq: opcode = kMipsBne; break;
476 case kMipsBne: opcode = kMipsBeq; break;
477 case kMipsBeqz: opcode = kMipsBnez; break;
478 case kMipsBgez: opcode = kMipsBltz; break;
479 case kMipsBgtz: opcode = kMipsBlez; break;
480 case kMipsBlez: opcode = kMipsBgtz; break;
481 case kMipsBltz: opcode = kMipsBgez; break;
482 case kMipsBnez: opcode = kMipsBeqz; break;
483 default:
484 LOG(FATAL) << "Unexpected branch kind " << (int)opcode;
485 }
486 LIR* hopTarget = NULL;
487 if (!unconditional) {
488 hopTarget = rawLIR(cUnit, dalvikOffset, kPseudoTargetLabel);
489 LIR* hopBranch = rawLIR(cUnit, dalvikOffset, opcode, lir->operands[0],
490 lir->operands[1], 0, 0, 0, hopTarget);
491 oatInsertLIRBefore(lir, hopBranch);
492 }
493 LIR* currPC = rawLIR(cUnit, dalvikOffset, kMipsCurrPC);
494 oatInsertLIRBefore(lir, currPC);
495 LIR* anchor = rawLIR(cUnit, dalvikOffset, kPseudoTargetLabel);
496 LIR* deltaHi = rawLIR(cUnit, dalvikOffset, kMipsDeltaHi, r_AT, 0,
497 (uintptr_t)anchor, 0, 0, lir->target);
498 oatInsertLIRBefore(lir, deltaHi);
499 oatInsertLIRBefore(lir, anchor);
500 LIR* deltaLo = rawLIR(cUnit, dalvikOffset, kMipsDeltaLo, r_AT, 0,
501 (uintptr_t)anchor, 0, 0, lir->target);
502 oatInsertLIRBefore(lir, deltaLo);
503 LIR* addu = rawLIR(cUnit, dalvikOffset, kMipsAddu, r_AT, r_AT, r_RA);
504 oatInsertLIRBefore(lir, addu);
505 LIR* jr = rawLIR(cUnit, dalvikOffset, kMipsJr, r_AT);
506 oatInsertLIRBefore(lir, jr);
507 if (!unconditional) {
508 oatInsertLIRBefore(lir, hopTarget);
509 }
510 lir->flags.isNop = true;
buzbeea2ebdd72012-03-04 14:57:06 -0800511}
512
buzbeee3acd072012-02-25 17:03:10 -0800513/*
514 * Assemble the LIR into binary instruction format. Note that we may
515 * discover that pc-relative displacements may not fit the selected
516 * instruction. In those cases we will try to substitute a new code
517 * sequence or request that the trace be shortened and retried.
518 */
519AssemblerStatus oatAssembleInstructions(CompilationUnit *cUnit,
Bill Buzbeea114add2012-05-03 15:00:40 -0700520 intptr_t startAddr)
buzbeee3acd072012-02-25 17:03:10 -0800521{
Bill Buzbeea114add2012-05-03 15:00:40 -0700522 LIR *lir;
523 AssemblerStatus res = kSuccess; // Assume success
buzbeee3acd072012-02-25 17:03:10 -0800524
Bill Buzbeea114add2012-05-03 15:00:40 -0700525 for (lir = (LIR *) cUnit->firstLIRInsn; lir; lir = NEXT_LIR(lir)) {
526 if (lir->opcode < 0) {
527 continue;
buzbeee3acd072012-02-25 17:03:10 -0800528 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700529
530
531 if (lir->flags.isNop) {
532 continue;
533 }
534
535 if (lir->flags.pcRelFixup) {
536 if (lir->opcode == kMipsDelta) {
537 /*
538 * The "Delta" pseudo-ops load the difference between
539 * two pc-relative locations into a the target register
540 * found in operands[0]. The delta is determined by
541 * (label2 - label1), where label1 is a standard
542 * kPseudoTargetLabel and is stored in operands[2].
543 * If operands[3] is null, then label2 is a kPseudoTargetLabel
544 * and is found in lir->target. If operands[3] is non-NULL,
545 * then it is a Switch/Data table.
546 */
547 int offset1 = ((LIR*)lir->operands[2])->offset;
548 SwitchTable *tabRec = (SwitchTable*)lir->operands[3];
549 int offset2 = tabRec ? tabRec->offset : lir->target->offset;
550 int delta = offset2 - offset1;
551 if ((delta & 0xffff) == delta) {
552 // Fits
553 lir->operands[1] = delta;
554 } else {
555 // Doesn't fit - must expand to kMipsDelta[Hi|Lo] pair
556 LIR *newDeltaHi =
557 rawLIR(cUnit, lir->dalvikOffset, kMipsDeltaHi,
558 lir->operands[0], 0, lir->operands[2],
559 lir->operands[3], 0, lir->target);
560 oatInsertLIRBefore((LIR*)lir, (LIR*)newDeltaHi);
561 LIR *newDeltaLo =
562 rawLIR(cUnit, lir->dalvikOffset, kMipsDeltaLo,
563 lir->operands[0], 0, lir->operands[2],
564 lir->operands[3], 0, lir->target);
565 oatInsertLIRBefore((LIR*)lir, (LIR*)newDeltaLo);
566 lir->flags.isNop = true;
567 res = kRetryAll;
568 }
569 } else if (lir->opcode == kMipsDeltaLo) {
570 int offset1 = ((LIR*)lir->operands[2])->offset;
571 SwitchTable *tabRec = (SwitchTable*)lir->operands[3];
572 int offset2 = tabRec ? tabRec->offset : lir->target->offset;
573 int delta = offset2 - offset1;
574 lir->operands[1] = delta & 0xffff;
575 } else if (lir->opcode == kMipsDeltaHi) {
576 int offset1 = ((LIR*)lir->operands[2])->offset;
577 SwitchTable *tabRec = (SwitchTable*)lir->operands[3];
578 int offset2 = tabRec ? tabRec->offset : lir->target->offset;
579 int delta = offset2 - offset1;
580 lir->operands[1] = (delta >> 16) & 0xffff;
581 } else if (lir->opcode == kMipsB || lir->opcode == kMipsBal) {
582 LIR *targetLIR = (LIR *) lir->target;
583 intptr_t pc = lir->offset + 4;
584 intptr_t target = targetLIR->offset;
585 int delta = target - pc;
586 if (delta & 0x3) {
587 LOG(FATAL) << "PC-rel offset not multiple of 4: " << delta;
588 }
589 if (delta > 131068 || delta < -131069) {
590 res = kRetryAll;
591 convertShortToLongBranch(cUnit, lir);
592 } else {
593 lir->operands[0] = delta >> 2;
594 }
595 } else if (lir->opcode >= kMipsBeqz && lir->opcode <= kMipsBnez) {
596 LIR *targetLIR = (LIR *) lir->target;
597 intptr_t pc = lir->offset + 4;
598 intptr_t target = targetLIR->offset;
599 int delta = target - pc;
600 if (delta & 0x3) {
601 LOG(FATAL) << "PC-rel offset not multiple of 4: " << delta;
602 }
603 if (delta > 131068 || delta < -131069) {
604 res = kRetryAll;
605 convertShortToLongBranch(cUnit, lir);
606 } else {
607 lir->operands[1] = delta >> 2;
608 }
609 } else if (lir->opcode == kMipsBeq || lir->opcode == kMipsBne) {
610 LIR *targetLIR = (LIR *) lir->target;
611 intptr_t pc = lir->offset + 4;
612 intptr_t target = targetLIR->offset;
613 int delta = target - pc;
614 if (delta & 0x3) {
615 LOG(FATAL) << "PC-rel offset not multiple of 4: " << delta;
616 }
617 if (delta > 131068 || delta < -131069) {
618 res = kRetryAll;
619 convertShortToLongBranch(cUnit, lir);
620 } else {
621 lir->operands[2] = delta >> 2;
622 }
623 } else if (lir->opcode == kMipsJal) {
624 intptr_t curPC = (startAddr + lir->offset + 4) & ~3;
625 intptr_t target = lir->operands[0];
626 /* ensure PC-region branch can be used */
627 DCHECK_EQ((curPC & 0xF0000000), (target & 0xF0000000));
628 if (target & 0x3) {
629 LOG(FATAL) << "Jump target not multiple of 4: " << target;
630 }
631 lir->operands[0] = target >> 2;
632 } else if (lir->opcode == kMipsLahi) { /* ld address hi (via lui) */
633 LIR *targetLIR = (LIR *) lir->target;
634 intptr_t target = startAddr + targetLIR->offset;
635 lir->operands[1] = target >> 16;
636 } else if (lir->opcode == kMipsLalo) { /* ld address lo (via ori) */
637 LIR *targetLIR = (LIR *) lir->target;
638 intptr_t target = startAddr + targetLIR->offset;
639 lir->operands[2] = lir->operands[2] + target;
640 }
641 }
642
643 /*
644 * If one of the pc-relative instructions expanded we'll have
645 * to make another pass. Don't bother to fully assemble the
646 * instruction.
647 */
648 if (res != kSuccess) {
649 continue;
650 }
651 const MipsEncodingMap *encoder = &EncodingMap[lir->opcode];
652 u4 bits = encoder->skeleton;
653 int i;
654 for (i = 0; i < 4; i++) {
655 u4 operand;
656 u4 value;
657 operand = lir->operands[i];
658 switch (encoder->fieldLoc[i].kind) {
659 case kFmtUnused:
660 break;
661 case kFmtBitBlt:
662 if (encoder->fieldLoc[i].start == 0 && encoder->fieldLoc[i].end == 31) {
663 value = operand;
664 } else {
665 value = (operand << encoder->fieldLoc[i].start) &
666 ((1 << (encoder->fieldLoc[i].end + 1)) - 1);
667 }
668 bits |= value;
669 break;
670 case kFmtBlt5_2:
671 value = (operand & 0x1f);
672 bits |= (value << encoder->fieldLoc[i].start);
673 bits |= (value << encoder->fieldLoc[i].end);
674 break;
675 case kFmtDfp: {
676 DCHECK(DOUBLEREG(operand));
Elliott Hughes74847412012-06-20 18:10:21 -0700677 DCHECK_EQ((operand & 0x1), 0U);
Bill Buzbeea114add2012-05-03 15:00:40 -0700678 value = ((operand & FP_REG_MASK) << encoder->fieldLoc[i].start) &
679 ((1 << (encoder->fieldLoc[i].end + 1)) - 1);
680 bits |= value;
681 break;
682 }
683 case kFmtSfp:
684 DCHECK(SINGLEREG(operand));
685 value = ((operand & FP_REG_MASK) << encoder->fieldLoc[i].start) &
686 ((1 << (encoder->fieldLoc[i].end + 1)) - 1);
687 bits |= value;
688 break;
689 default:
690 LOG(FATAL) << "Bad encoder format: "
691 << (int)encoder->fieldLoc[i].kind;
692 }
693 }
jeffhao4f8f04a2012-10-02 18:10:35 -0700694 // We only support little-endian MIPS.
Bill Buzbeea114add2012-05-03 15:00:40 -0700695 cUnit->codeBuffer.push_back(bits & 0xff);
jeffhao4f8f04a2012-10-02 18:10:35 -0700696 cUnit->codeBuffer.push_back((bits >> 8) & 0xff);
697 cUnit->codeBuffer.push_back((bits >> 16) & 0xff);
698 cUnit->codeBuffer.push_back((bits >> 24) & 0xff);
Bill Buzbeea114add2012-05-03 15:00:40 -0700699 // TUNING: replace with proper delay slot handling
700 if (encoder->size == 8) {
701 const MipsEncodingMap *encoder = &EncodingMap[kMipsNop];
702 u4 bits = encoder->skeleton;
Bill Buzbeea114add2012-05-03 15:00:40 -0700703 cUnit->codeBuffer.push_back(bits & 0xff);
jeffhao4f8f04a2012-10-02 18:10:35 -0700704 cUnit->codeBuffer.push_back((bits >> 8) & 0xff);
705 cUnit->codeBuffer.push_back((bits >> 16) & 0xff);
706 cUnit->codeBuffer.push_back((bits >> 24) & 0xff);
Bill Buzbeea114add2012-05-03 15:00:40 -0700707 }
708 }
709 return res;
buzbeee3acd072012-02-25 17:03:10 -0800710}
711
buzbeee88dfbf2012-03-05 11:19:57 -0800712int oatGetInsnSize(LIR* lir)
713{
Bill Buzbeea114add2012-05-03 15:00:40 -0700714 return EncodingMap[lir->opcode].size;
buzbeee88dfbf2012-03-05 11:19:57 -0800715}
buzbeee3acd072012-02-25 17:03:10 -0800716/*
717 * Target-dependent offset assignment.
buzbeee3acd072012-02-25 17:03:10 -0800718 * independent.
719 */
720int oatAssignInsnOffsets(CompilationUnit* cUnit)
721{
Bill Buzbeea114add2012-05-03 15:00:40 -0700722 LIR* mipsLIR;
723 int offset = 0;
buzbeee3acd072012-02-25 17:03:10 -0800724
Bill Buzbeea114add2012-05-03 15:00:40 -0700725 for (mipsLIR = (LIR *) cUnit->firstLIRInsn;
726 mipsLIR;
727 mipsLIR = NEXT_LIR(mipsLIR)) {
728 mipsLIR->offset = offset;
729 if (mipsLIR->opcode >= 0) {
730 if (!mipsLIR->flags.isNop) {
731 offset += mipsLIR->flags.size;
732 }
733 } else if (mipsLIR->opcode == kPseudoPseudoAlign4) {
734 if (offset & 0x2) {
735 offset += 2;
736 mipsLIR->operands[0] = 1;
737 } else {
738 mipsLIR->operands[0] = 0;
739 }
buzbeee3acd072012-02-25 17:03:10 -0800740 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700741 /* Pseudo opcodes don't consume space */
742 }
buzbeee3acd072012-02-25 17:03:10 -0800743
Bill Buzbeea114add2012-05-03 15:00:40 -0700744 return offset;
buzbeee3acd072012-02-25 17:03:10 -0800745}
746
747} // namespace art