blob: c0ed3b68bafcb50d677758e2651c2efd1562da54 [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"
buzbee02031b12012-11-23 09:41:35 -080018#include "codegen_mips.h"
buzbeeeaf09bc2012-11-15 14:51:41 -080019#include "../codegen_util.h"
buzbeee3acd072012-02-25 17:03:10 -080020
21namespace art {
22
23#define MAX_ASSEMBLER_RETRIES 50
24
25/*
26 * opcode: MipsOpCode enum
27 * skeleton: pre-designated bit-pattern for this opcode
28 * k0: key to applying ds/de
29 * ds: dest start bit position
30 * de: dest end bit position
31 * k1: key to applying s1s/s1e
32 * s1s: src1 start bit position
33 * s1e: src1 end bit position
34 * k2: key to applying s2s/s2e
35 * s2s: src2 start bit position
36 * s2e: src2 end bit position
37 * operands: number of operands (for sanity check purposes)
38 * name: mnemonic name
39 * fmt: for pretty-printing
40 */
41#define ENCODING_MAP(opcode, skeleton, k0, ds, de, k1, s1s, s1e, k2, s2s, s2e, \
42 k3, k3s, k3e, flags, name, fmt, size) \
43 {skeleton, {{k0, ds, de}, {k1, s1s, s1e}, {k2, s2s, s2e}, \
44 {k3, k3s, k3e}}, opcode, flags, name, fmt, size}
45
46/* Instruction dump string format keys: !pf, where "!" is the start
47 * of the key, "p" is which numeric operand to use and "f" is the
48 * print format.
49 *
50 * [p]ositions:
51 * 0 -> operands[0] (dest)
52 * 1 -> operands[1] (src1)
53 * 2 -> operands[2] (src2)
54 * 3 -> operands[3] (extra)
55 *
56 * [f]ormats:
57 * h -> 4-digit hex
58 * d -> decimal
59 * E -> decimal*4
60 * F -> decimal*2
61 * c -> branch condition (beq, bne, etc.)
62 * t -> pc-relative target
63 * T -> pc-region target
64 * u -> 1st half of bl[x] target
65 * v -> 2nd half ob bl[x] target
66 * R -> register list
67 * s -> single precision floating point register
68 * S -> double precision floating point register
69 * m -> Thumb2 modified immediate
70 * n -> complimented Thumb2 modified immediate
71 * M -> Thumb2 16-bit zero-extended immediate
72 * b -> 4-digit binary
buzbee82488f52012-03-02 08:20:26 -080073 * N -> append a NOP
buzbeee3acd072012-02-25 17:03:10 -080074 *
75 * [!] escape. To insert "!", use "!!"
76 */
buzbee5de34942012-03-01 14:51:57 -080077/* NOTE: must be kept in sync with enum MipsOpcode from LIR.h */
buzbee82488f52012-03-02 08:20:26 -080078/*
79 * TUNING: We're currently punting on the branch delay slots. All branch
80 * instructions in this map are given a size of 8, which during assembly
81 * is expanded to include a nop. This scheme should be replaced with
82 * an assembler pass to fill those slots when possible.
83 */
buzbee02031b12012-11-23 09:41:35 -080084const MipsEncodingMap MipsCodegen::EncodingMap[kMipsLast] = {
buzbeee3acd072012-02-25 17:03:10 -080085 ENCODING_MAP(kMips32BitData, 0x00000000,
86 kFmtBitBlt, 31, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
87 kFmtUnused, -1, -1, IS_UNARY_OP,
buzbee71ac9942012-03-01 17:23:10 -080088 "data", "0x!0h(!0d)", 4),
buzbeee3acd072012-02-25 17:03:10 -080089 ENCODING_MAP(kMipsAddiu, 0x24000000,
90 kFmtBitBlt, 20, 16, kFmtBitBlt, 25, 21, kFmtBitBlt, 15, 0,
91 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
buzbee71ac9942012-03-01 17:23:10 -080092 "addiu", "!0r,!1r,0x!2h(!2d)", 4),
buzbeee3acd072012-02-25 17:03:10 -080093 ENCODING_MAP(kMipsAddu, 0x00000021,
94 kFmtBitBlt, 15, 11, kFmtBitBlt, 25, 21, kFmtBitBlt, 20, 16,
95 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
buzbee71ac9942012-03-01 17:23:10 -080096 "addu", "!0r,!1r,!2r", 4),
buzbeee3acd072012-02-25 17:03:10 -080097 ENCODING_MAP(kMipsAnd, 0x00000024,
98 kFmtBitBlt, 15, 11, kFmtBitBlt, 25, 21, kFmtBitBlt, 20, 16,
99 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
buzbee71ac9942012-03-01 17:23:10 -0800100 "and", "!0r,!1r,!2r", 4),
buzbeee3acd072012-02-25 17:03:10 -0800101 ENCODING_MAP(kMipsAndi, 0x30000000,
102 kFmtBitBlt, 20, 16, kFmtBitBlt, 25, 21, kFmtBitBlt, 15, 0,
103 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
buzbee71ac9942012-03-01 17:23:10 -0800104 "andi", "!0r,!1r,0x!2h(!2d)", 4),
buzbeee3acd072012-02-25 17:03:10 -0800105 ENCODING_MAP(kMipsB, 0x10000000,
106 kFmtBitBlt, 15, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
Ian Rogers680b1bd2012-03-07 20:18:49 -0800107 kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH | NEEDS_FIXUP,
buzbee82488f52012-03-02 08:20:26 -0800108 "b", "!0t!0N", 8),
buzbeee3acd072012-02-25 17:03:10 -0800109 ENCODING_MAP(kMipsBal, 0x04110000,
110 kFmtBitBlt, 15, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
Ian Rogers680b1bd2012-03-07 20:18:49 -0800111 kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH | REG_DEF_LR |
buzbeea2ebdd72012-03-04 14:57:06 -0800112 NEEDS_FIXUP, "bal", "!0t!0N", 8),
buzbeee3acd072012-02-25 17:03:10 -0800113 ENCODING_MAP(kMipsBeq, 0x10000000,
114 kFmtBitBlt, 25, 21, kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0,
buzbeea2ebdd72012-03-04 14:57:06 -0800115 kFmtUnused, -1, -1, IS_BINARY_OP | IS_BRANCH | REG_USE01 |
116 NEEDS_FIXUP, "beq", "!0r,!1r,!2t!0N", 8),
buzbeee3acd072012-02-25 17:03:10 -0800117 ENCODING_MAP(kMipsBeqz, 0x10000000, /* same as beq above with t = $zero */
118 kFmtBitBlt, 25, 21, kFmtBitBlt, 15, 0, kFmtUnused, -1, -1,
buzbeea2ebdd72012-03-04 14:57:06 -0800119 kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH | REG_USE0 |
120 NEEDS_FIXUP, "beqz", "!0r,!1t!0N", 8),
buzbeee3acd072012-02-25 17:03:10 -0800121 ENCODING_MAP(kMipsBgez, 0x04010000,
122 kFmtBitBlt, 25, 21, kFmtBitBlt, 15, 0, kFmtUnused, -1, -1,
buzbeea2ebdd72012-03-04 14:57:06 -0800123 kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH | REG_USE0 |
124 NEEDS_FIXUP, "bgez", "!0r,!1t!0N", 8),
buzbeee3acd072012-02-25 17:03:10 -0800125 ENCODING_MAP(kMipsBgtz, 0x1C000000,
126 kFmtBitBlt, 25, 21, kFmtBitBlt, 15, 0, kFmtUnused, -1, -1,
buzbeea2ebdd72012-03-04 14:57:06 -0800127 kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH | REG_USE0 |
128 NEEDS_FIXUP, "bgtz", "!0r,!1t!0N", 8),
buzbeee3acd072012-02-25 17:03:10 -0800129 ENCODING_MAP(kMipsBlez, 0x18000000,
130 kFmtBitBlt, 25, 21, kFmtBitBlt, 15, 0, kFmtUnused, -1, -1,
buzbeea2ebdd72012-03-04 14:57:06 -0800131 kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH | REG_USE0 |
132 NEEDS_FIXUP, "blez", "!0r,!1t!0N", 8),
buzbeee3acd072012-02-25 17:03:10 -0800133 ENCODING_MAP(kMipsBltz, 0x04000000,
134 kFmtBitBlt, 25, 21, kFmtBitBlt, 15, 0, kFmtUnused, -1, -1,
buzbeea2ebdd72012-03-04 14:57:06 -0800135 kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH | REG_USE0 |
136 NEEDS_FIXUP, "bltz", "!0r,!1t!0N", 8),
buzbeee3acd072012-02-25 17:03:10 -0800137 ENCODING_MAP(kMipsBnez, 0x14000000, /* same as bne below with t = $zero */
138 kFmtBitBlt, 25, 21, kFmtBitBlt, 15, 0, kFmtUnused, -1, -1,
buzbeea2ebdd72012-03-04 14:57:06 -0800139 kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH | REG_USE0 |
140 NEEDS_FIXUP, "bnez", "!0r,!1t!0N", 8),
buzbeee3acd072012-02-25 17:03:10 -0800141 ENCODING_MAP(kMipsBne, 0x14000000,
142 kFmtBitBlt, 25, 21, kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0,
buzbeea2ebdd72012-03-04 14:57:06 -0800143 kFmtUnused, -1, -1, IS_BINARY_OP | IS_BRANCH | REG_USE01 |
144 NEEDS_FIXUP, "bne", "!0r,!1r,!2t!0N", 8),
buzbeee3acd072012-02-25 17:03:10 -0800145 ENCODING_MAP(kMipsDiv, 0x0000001a,
146 kFmtUnused, -1, -1, kFmtUnused, -1, -1, kFmtBitBlt, 25, 21,
147 kFmtBitBlt, 20, 16, IS_QUAD_OP | REG_DEF01 | REG_USE23,
buzbee71ac9942012-03-01 17:23:10 -0800148 "div", "!2r,!3r", 4),
buzbeee3acd072012-02-25 17:03:10 -0800149#if __mips_isa_rev>=2
150 ENCODING_MAP(kMipsExt, 0x7c000000,
151 kFmtBitBlt, 20, 16, kFmtBitBlt, 25, 21, kFmtBitBlt, 10, 6,
152 kFmtBitBlt, 15, 11, IS_QUAD_OP | REG_DEF0 | REG_USE1,
buzbee71ac9942012-03-01 17:23:10 -0800153 "ext", "!0r,!1r,!2d,!3D", 4),
buzbeee3acd072012-02-25 17:03:10 -0800154#endif
155 ENCODING_MAP(kMipsJal, 0x0c000000,
156 kFmtBitBlt, 25, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
157 kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH | REG_DEF_LR,
buzbee82488f52012-03-02 08:20:26 -0800158 "jal", "!0T(!0E)!0N", 8),
buzbeee3acd072012-02-25 17:03:10 -0800159 ENCODING_MAP(kMipsJalr, 0x00000009,
160 kFmtBitBlt, 15, 11, kFmtBitBlt, 25, 21, kFmtUnused, -1, -1,
161 kFmtUnused, -1, -1, IS_BINARY_OP | IS_BRANCH | REG_DEF0_USE1,
buzbee82488f52012-03-02 08:20:26 -0800162 "jalr", "!0r,!1r!0N", 8),
buzbeee3acd072012-02-25 17:03:10 -0800163 ENCODING_MAP(kMipsJr, 0x00000008,
164 kFmtBitBlt, 25, 21, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
buzbeea2ebdd72012-03-04 14:57:06 -0800165 kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH | REG_USE0 |
166 NEEDS_FIXUP, "jr", "!0r!0N", 8),
buzbeee3acd072012-02-25 17:03:10 -0800167 ENCODING_MAP(kMipsLahi, 0x3C000000,
168 kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0, kFmtUnused, -1, -1,
169 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0,
buzbee71ac9942012-03-01 17:23:10 -0800170 "lahi/lui", "!0r,0x!1h(!1d)", 4),
buzbeee3acd072012-02-25 17:03:10 -0800171 ENCODING_MAP(kMipsLalo, 0x34000000,
172 kFmtBitBlt, 20, 16, kFmtBitBlt, 25, 21, kFmtBitBlt, 15, 0,
173 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
buzbee71ac9942012-03-01 17:23:10 -0800174 "lalo/ori", "!0r,!1r,0x!2h(!2d)", 4),
buzbeee3acd072012-02-25 17:03:10 -0800175 ENCODING_MAP(kMipsLui, 0x3C000000,
176 kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0, kFmtUnused, -1, -1,
177 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0,
buzbee71ac9942012-03-01 17:23:10 -0800178 "lui", "!0r,0x!1h(!1d)", 4),
buzbeee3acd072012-02-25 17:03:10 -0800179 ENCODING_MAP(kMipsLb, 0x80000000,
180 kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0, kFmtBitBlt, 25, 21,
181 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE2 | IS_LOAD,
buzbee71ac9942012-03-01 17:23:10 -0800182 "lb", "!0r,!1d(!2r)", 4),
buzbeee3acd072012-02-25 17:03:10 -0800183 ENCODING_MAP(kMipsLbu, 0x90000000,
184 kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0, kFmtBitBlt, 25, 21,
185 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE2 | IS_LOAD,
buzbee71ac9942012-03-01 17:23:10 -0800186 "lbu", "!0r,!1d(!2r)", 4),
buzbeee3acd072012-02-25 17:03:10 -0800187 ENCODING_MAP(kMipsLh, 0x84000000,
188 kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0, kFmtBitBlt, 25, 21,
189 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE2 | IS_LOAD,
buzbee71ac9942012-03-01 17:23:10 -0800190 "lh", "!0r,!1d(!2r)", 4),
buzbeee3acd072012-02-25 17:03:10 -0800191 ENCODING_MAP(kMipsLhu, 0x94000000,
192 kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0, kFmtBitBlt, 25, 21,
193 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE2 | IS_LOAD,
buzbee71ac9942012-03-01 17:23:10 -0800194 "lhu", "!0r,!1d(!2r)", 4),
buzbeee3acd072012-02-25 17:03:10 -0800195 ENCODING_MAP(kMipsLw, 0x8C000000,
196 kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0, kFmtBitBlt, 25, 21,
197 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE2 | IS_LOAD,
buzbee71ac9942012-03-01 17:23:10 -0800198 "lw", "!0r,!1d(!2r)", 4),
buzbeee3acd072012-02-25 17:03:10 -0800199 ENCODING_MAP(kMipsMfhi, 0x00000010,
200 kFmtBitBlt, 15, 11, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
201 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
buzbee71ac9942012-03-01 17:23:10 -0800202 "mfhi", "!0r", 4),
buzbeee3acd072012-02-25 17:03:10 -0800203 ENCODING_MAP(kMipsMflo, 0x00000012,
204 kFmtBitBlt, 15, 11, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
205 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
buzbee71ac9942012-03-01 17:23:10 -0800206 "mflo", "!0r", 4),
buzbeee3acd072012-02-25 17:03:10 -0800207 ENCODING_MAP(kMipsMove, 0x00000025, /* or using zero reg */
208 kFmtBitBlt, 15, 11, kFmtBitBlt, 25, 21, kFmtUnused, -1, -1,
209 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
buzbee71ac9942012-03-01 17:23:10 -0800210 "move", "!0r,!1r", 4),
buzbeee3acd072012-02-25 17:03:10 -0800211 ENCODING_MAP(kMipsMovz, 0x0000000a,
212 kFmtBitBlt, 15, 11, kFmtBitBlt, 25, 21, kFmtBitBlt, 20, 16,
213 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
buzbee71ac9942012-03-01 17:23:10 -0800214 "movz", "!0r,!1r,!2r", 4),
buzbeee3acd072012-02-25 17:03:10 -0800215 ENCODING_MAP(kMipsMul, 0x70000002,
216 kFmtBitBlt, 15, 11, kFmtBitBlt, 25, 21, kFmtBitBlt, 20, 16,
217 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
buzbee71ac9942012-03-01 17:23:10 -0800218 "mul", "!0r,!1r,!2r", 4),
buzbeee3acd072012-02-25 17:03:10 -0800219 ENCODING_MAP(kMipsNop, 0x00000000,
220 kFmtUnused, -1, -1, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
221 kFmtUnused, -1, -1, NO_OPERAND,
buzbeec5159d52012-03-03 11:48:39 -0800222 "nop", ";", 4),
buzbeee3acd072012-02-25 17:03:10 -0800223 ENCODING_MAP(kMipsNor, 0x00000027, /* used for "not" too */
224 kFmtBitBlt, 15, 11, kFmtBitBlt, 25, 21, kFmtBitBlt, 20, 16,
225 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
buzbee71ac9942012-03-01 17:23:10 -0800226 "nor", "!0r,!1r,!2r", 4),
buzbeee3acd072012-02-25 17:03:10 -0800227 ENCODING_MAP(kMipsOr, 0x00000025,
228 kFmtBitBlt, 15, 11, kFmtBitBlt, 25, 21, kFmtBitBlt, 20, 16,
229 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
buzbee71ac9942012-03-01 17:23:10 -0800230 "or", "!0r,!1r,!2r", 4),
buzbeee3acd072012-02-25 17:03:10 -0800231 ENCODING_MAP(kMipsOri, 0x34000000,
232 kFmtBitBlt, 20, 16, kFmtBitBlt, 25, 21, kFmtBitBlt, 15, 0,
233 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
buzbee71ac9942012-03-01 17:23:10 -0800234 "ori", "!0r,!1r,0x!2h(!2d)", 4),
buzbeee3acd072012-02-25 17:03:10 -0800235 ENCODING_MAP(kMipsPref, 0xCC000000,
236 kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0, kFmtBitBlt, 25, 21,
237 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE2,
buzbee71ac9942012-03-01 17:23:10 -0800238 "pref", "!0d,!1d(!2r)", 4),
buzbeee3acd072012-02-25 17:03:10 -0800239 ENCODING_MAP(kMipsSb, 0xA0000000,
240 kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0, kFmtBitBlt, 25, 21,
241 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE02 | IS_STORE,
buzbee71ac9942012-03-01 17:23:10 -0800242 "sb", "!0r,!1d(!2r)", 4),
buzbeee3acd072012-02-25 17:03:10 -0800243#if __mips_isa_rev>=2
244 ENCODING_MAP(kMipsSeb, 0x7c000420,
245 kFmtBitBlt, 15, 11, kFmtBitBlt, 20, 16, kFmtUnused, -1, -1,
246 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
buzbee71ac9942012-03-01 17:23:10 -0800247 "seb", "!0r,!1r", 4),
buzbeee3acd072012-02-25 17:03:10 -0800248 ENCODING_MAP(kMipsSeh, 0x7c000620,
249 kFmtBitBlt, 15, 11, kFmtBitBlt, 20, 16, kFmtUnused, -1, -1,
250 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
buzbee71ac9942012-03-01 17:23:10 -0800251 "seh", "!0r,!1r", 4),
buzbeee3acd072012-02-25 17:03:10 -0800252#endif
253 ENCODING_MAP(kMipsSh, 0xA4000000,
254 kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0, kFmtBitBlt, 25, 21,
255 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE02 | IS_STORE,
buzbee71ac9942012-03-01 17:23:10 -0800256 "sh", "!0r,!1d(!2r)", 4),
buzbeee3acd072012-02-25 17:03:10 -0800257 ENCODING_MAP(kMipsSll, 0x00000000,
258 kFmtBitBlt, 15, 11, kFmtBitBlt, 20, 16, kFmtBitBlt, 10, 6,
259 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
buzbee71ac9942012-03-01 17:23:10 -0800260 "sll", "!0r,!1r,0x!2h(!2d)", 4),
buzbeee3acd072012-02-25 17:03:10 -0800261 ENCODING_MAP(kMipsSllv, 0x00000004,
262 kFmtBitBlt, 15, 11, kFmtBitBlt, 20, 16, kFmtBitBlt, 25, 21,
263 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
buzbee71ac9942012-03-01 17:23:10 -0800264 "sllv", "!0r,!1r,!2r", 4),
buzbeee3acd072012-02-25 17:03:10 -0800265 ENCODING_MAP(kMipsSlt, 0x0000002a,
266 kFmtBitBlt, 15, 11, kFmtBitBlt, 25, 21, kFmtBitBlt, 20, 16,
267 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
buzbee71ac9942012-03-01 17:23:10 -0800268 "slt", "!0r,!1r,!2r", 4),
buzbeee3acd072012-02-25 17:03:10 -0800269 ENCODING_MAP(kMipsSlti, 0x28000000,
270 kFmtBitBlt, 20, 16, kFmtBitBlt, 25, 21, kFmtBitBlt, 15, 0,
271 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
buzbee71ac9942012-03-01 17:23:10 -0800272 "slti", "!0r,!1r,0x!2h(!2d)", 4),
buzbeee3acd072012-02-25 17:03:10 -0800273 ENCODING_MAP(kMipsSltu, 0x0000002b,
274 kFmtBitBlt, 15, 11, kFmtBitBlt, 25, 21, kFmtBitBlt, 20, 16,
275 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
buzbee71ac9942012-03-01 17:23:10 -0800276 "sltu", "!0r,!1r,!2r", 4),
buzbeee3acd072012-02-25 17:03:10 -0800277 ENCODING_MAP(kMipsSra, 0x00000003,
278 kFmtBitBlt, 15, 11, kFmtBitBlt, 20, 16, kFmtBitBlt, 10, 6,
279 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
buzbee71ac9942012-03-01 17:23:10 -0800280 "sra", "!0r,!1r,0x!2h(!2d)", 4),
buzbeee3acd072012-02-25 17:03:10 -0800281 ENCODING_MAP(kMipsSrav, 0x00000007,
282 kFmtBitBlt, 15, 11, kFmtBitBlt, 20, 16, kFmtBitBlt, 25, 21,
283 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
buzbee71ac9942012-03-01 17:23:10 -0800284 "srav", "!0r,!1r,!2r", 4),
buzbeee3acd072012-02-25 17:03:10 -0800285 ENCODING_MAP(kMipsSrl, 0x00000002,
286 kFmtBitBlt, 15, 11, kFmtBitBlt, 20, 16, kFmtBitBlt, 10, 6,
287 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
buzbee71ac9942012-03-01 17:23:10 -0800288 "srl", "!0r,!1r,0x!2h(!2d)", 4),
buzbeee3acd072012-02-25 17:03:10 -0800289 ENCODING_MAP(kMipsSrlv, 0x00000006,
290 kFmtBitBlt, 15, 11, kFmtBitBlt, 20, 16, kFmtBitBlt, 25, 21,
291 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
buzbee71ac9942012-03-01 17:23:10 -0800292 "srlv", "!0r,!1r,!2r", 4),
buzbeee3acd072012-02-25 17:03:10 -0800293 ENCODING_MAP(kMipsSubu, 0x00000023, /* used for "neg" too */
294 kFmtBitBlt, 15, 11, kFmtBitBlt, 25, 21, kFmtBitBlt, 20, 16,
295 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
buzbee71ac9942012-03-01 17:23:10 -0800296 "subu", "!0r,!1r,!2r", 4),
buzbeee3acd072012-02-25 17:03:10 -0800297 ENCODING_MAP(kMipsSw, 0xAC000000,
298 kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0, kFmtBitBlt, 25, 21,
299 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE02 | IS_STORE,
buzbee71ac9942012-03-01 17:23:10 -0800300 "sw", "!0r,!1d(!2r)", 4),
buzbeee3acd072012-02-25 17:03:10 -0800301 ENCODING_MAP(kMipsXor, 0x00000026,
302 kFmtBitBlt, 15, 11, kFmtBitBlt, 25, 21, kFmtBitBlt, 20, 16,
303 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
buzbee71ac9942012-03-01 17:23:10 -0800304 "xor", "!0r,!1r,!2r", 4),
buzbeee3acd072012-02-25 17:03:10 -0800305 ENCODING_MAP(kMipsXori, 0x38000000,
306 kFmtBitBlt, 20, 16, kFmtBitBlt, 25, 21, kFmtBitBlt, 15, 0,
307 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
buzbee71ac9942012-03-01 17:23:10 -0800308 "xori", "!0r,!1r,0x!2h(!2d)", 4),
buzbeee3acd072012-02-25 17:03:10 -0800309 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),
buzbeec5159d52012-03-03 11:48:39 -0800397 ENCODING_MAP(kMipsDelta, 0x27e00000,
398 kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0, kFmtUnused, 15, 0,
buzbeea2ebdd72012-03-04 14:57:06 -0800399 kFmtUnused, -1, -1, IS_QUAD_OP | REG_DEF0 | REG_USE_LR |
jeffhaofa147e22012-10-12 17:03:32 -0700400 NEEDS_FIXUP, "addiu", "!0r,ra,0x!1h(!1d)", 4),
buzbeec5159d52012-03-03 11:48:39 -0800401 ENCODING_MAP(kMipsDeltaHi, 0x3C000000,
402 kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0, kFmtUnused, -1, -1,
buzbeea2ebdd72012-03-04 14:57:06 -0800403 kFmtUnused, -1, -1, IS_QUAD_OP | REG_DEF0 | NEEDS_FIXUP,
buzbeec5159d52012-03-03 11:48:39 -0800404 "lui", "!0r,0x!1h(!1d)", 4),
405 ENCODING_MAP(kMipsDeltaLo, 0x34000000,
406 kFmtBlt5_2, 16, 21, kFmtBitBlt, 15, 0, kFmtUnused, -1, -1,
buzbeea2ebdd72012-03-04 14:57:06 -0800407 kFmtUnused, -1, -1, IS_QUAD_OP | REG_DEF0_USE0 | NEEDS_FIXUP,
buzbeec5159d52012-03-03 11:48:39 -0800408 "ori", "!0r,!0r,0x!1h(!1d)", 4),
jeffhaofa147e22012-10-12 17:03:32 -0700409 ENCODING_MAP(kMipsCurrPC, 0x04110001,
buzbeec5159d52012-03-03 11:48:39 -0800410 kFmtUnused, -1, -1, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
411 kFmtUnused, -1, -1, NO_OPERAND | IS_BRANCH | REG_DEF_LR,
jeffhaofa147e22012-10-12 17:03:32 -0700412 "addiu", "ra,pc,8", 4),
buzbeea2ebdd72012-03-04 14:57:06 -0800413 ENCODING_MAP(kMipsSync, 0x0000000f,
414 kFmtBitBlt, 10, 6, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
415 kFmtUnused, -1, -1, IS_UNARY_OP,
416 "sync", ";", 4),
buzbeee3acd072012-02-25 17:03:10 -0800417 ENCODING_MAP(kMipsUndefined, 0x64000000,
418 kFmtUnused, -1, -1, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
419 kFmtUnused, -1, -1, NO_OPERAND,
buzbee71ac9942012-03-01 17:23:10 -0800420 "undefined", "", 4),
buzbeee3acd072012-02-25 17:03:10 -0800421};
422
buzbeea2ebdd72012-03-04 14:57:06 -0800423
424/*
425 * Convert a short-form branch to long form. Hopefully, this won't happen
426 * very often because the PIC sequence is especially unfortunate.
427 *
428 * Orig conditional branch
429 * -----------------------
430 * beq rs,rt,target
431 *
432 * Long conditional branch
433 * -----------------------
434 * bne rs,rt,hop
435 * bal .+8 ; r_RA <- anchor
436 * lui r_AT, ((target-anchor) >> 16)
437 * anchor:
438 * ori r_AT, r_AT, ((target-anchor) & 0xffff)
439 * addu r_AT, r_AT, r_RA
440 * jr r_AT
441 * hop:
442 *
443 * Orig unconditional branch
444 * -------------------------
445 * b target
446 *
447 * Long unconditional branch
448 * -----------------------
449 * bal .+8 ; r_RA <- anchor
450 * lui r_AT, ((target-anchor) >> 16)
451 * anchor:
452 * ori r_AT, r_AT, ((target-anchor) & 0xffff)
453 * addu r_AT, r_AT, r_RA
454 * jr r_AT
455 *
456 *
457 * NOTE: An out-of-range bal isn't supported because it should
458 * never happen with the current PIC model.
459 */
buzbeefa57c472012-11-21 12:06:18 -0800460static void ConvertShortToLongBranch(CompilationUnit* cu, LIR* lir)
buzbeea2ebdd72012-03-04 14:57:06 -0800461{
Bill Buzbeea114add2012-05-03 15:00:40 -0700462 // For conditional branches we'll need to reverse the sense
463 bool unconditional = false;
464 int opcode = lir->opcode;
buzbeefa57c472012-11-21 12:06:18 -0800465 int dalvik_offset = lir->dalvik_offset;
Bill Buzbeea114add2012-05-03 15:00:40 -0700466 switch (opcode) {
467 case kMipsBal:
468 LOG(FATAL) << "long branch and link unsupported";
469 case kMipsB:
470 unconditional = true;
471 break;
472 case kMipsBeq: opcode = kMipsBne; break;
473 case kMipsBne: opcode = kMipsBeq; break;
474 case kMipsBeqz: opcode = kMipsBnez; break;
475 case kMipsBgez: opcode = kMipsBltz; break;
476 case kMipsBgtz: opcode = kMipsBlez; break;
477 case kMipsBlez: opcode = kMipsBgtz; break;
478 case kMipsBltz: opcode = kMipsBgez; break;
479 case kMipsBnez: opcode = kMipsBeqz; break;
480 default:
buzbeecbd6d442012-11-17 14:11:25 -0800481 LOG(FATAL) << "Unexpected branch kind " << opcode;
Bill Buzbeea114add2012-05-03 15:00:40 -0700482 }
buzbeefa57c472012-11-21 12:06:18 -0800483 LIR* hop_target = NULL;
Bill Buzbeea114add2012-05-03 15:00:40 -0700484 if (!unconditional) {
buzbeefa57c472012-11-21 12:06:18 -0800485 hop_target = RawLIR(cu, dalvik_offset, kPseudoTargetLabel);
486 LIR* hop_branch = RawLIR(cu, dalvik_offset, opcode, lir->operands[0],
487 lir->operands[1], 0, 0, 0, hop_target);
488 InsertLIRBefore(lir, hop_branch);
Bill Buzbeea114add2012-05-03 15:00:40 -0700489 }
buzbeefa57c472012-11-21 12:06:18 -0800490 LIR* curr_pc = RawLIR(cu, dalvik_offset, kMipsCurrPC);
491 InsertLIRBefore(lir, curr_pc);
492 LIR* anchor = RawLIR(cu, dalvik_offset, kPseudoTargetLabel);
493 LIR* delta_hi = RawLIR(cu, dalvik_offset, kMipsDeltaHi, r_AT, 0,
buzbeecbd6d442012-11-17 14:11:25 -0800494 reinterpret_cast<uintptr_t>(anchor), 0, 0, lir->target);
buzbeefa57c472012-11-21 12:06:18 -0800495 InsertLIRBefore(lir, delta_hi);
buzbee52a77fc2012-11-20 19:50:46 -0800496 InsertLIRBefore(lir, anchor);
buzbeefa57c472012-11-21 12:06:18 -0800497 LIR* delta_lo = RawLIR(cu, dalvik_offset, kMipsDeltaLo, r_AT, 0,
buzbeecbd6d442012-11-17 14:11:25 -0800498 reinterpret_cast<uintptr_t>(anchor), 0, 0, lir->target);
buzbeefa57c472012-11-21 12:06:18 -0800499 InsertLIRBefore(lir, delta_lo);
500 LIR* addu = RawLIR(cu, dalvik_offset, kMipsAddu, r_AT, r_AT, r_RA);
buzbee52a77fc2012-11-20 19:50:46 -0800501 InsertLIRBefore(lir, addu);
buzbeefa57c472012-11-21 12:06:18 -0800502 LIR* jr = RawLIR(cu, dalvik_offset, kMipsJr, r_AT);
buzbee52a77fc2012-11-20 19:50:46 -0800503 InsertLIRBefore(lir, jr);
Bill Buzbeea114add2012-05-03 15:00:40 -0700504 if (!unconditional) {
buzbeefa57c472012-11-21 12:06:18 -0800505 InsertLIRBefore(lir, hop_target);
Bill Buzbeea114add2012-05-03 15:00:40 -0700506 }
buzbeefa57c472012-11-21 12:06:18 -0800507 lir->flags.is_nop = true;
buzbeea2ebdd72012-03-04 14:57:06 -0800508}
509
buzbeee3acd072012-02-25 17:03:10 -0800510/*
511 * Assemble the LIR into binary instruction format. Note that we may
512 * discover that pc-relative displacements may not fit the selected
513 * instruction. In those cases we will try to substitute a new code
514 * sequence or request that the trace be shortened and retried.
515 */
buzbee02031b12012-11-23 09:41:35 -0800516AssemblerStatus MipsCodegen::AssembleInstructions(CompilationUnit *cu, uintptr_t start_addr)
buzbeee3acd072012-02-25 17:03:10 -0800517{
Bill Buzbeea114add2012-05-03 15:00:40 -0700518 LIR *lir;
519 AssemblerStatus res = kSuccess; // Assume success
buzbeee3acd072012-02-25 17:03:10 -0800520
buzbee28c9a832012-11-21 15:39:13 -0800521 for (lir = cu->first_lir_insn; lir != NULL; lir = NEXT_LIR(lir)) {
Bill Buzbeea114add2012-05-03 15:00:40 -0700522 if (lir->opcode < 0) {
523 continue;
buzbeee3acd072012-02-25 17:03:10 -0800524 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700525
526
buzbeefa57c472012-11-21 12:06:18 -0800527 if (lir->flags.is_nop) {
Bill Buzbeea114add2012-05-03 15:00:40 -0700528 continue;
529 }
530
531 if (lir->flags.pcRelFixup) {
532 if (lir->opcode == kMipsDelta) {
533 /*
534 * The "Delta" pseudo-ops load the difference between
535 * two pc-relative locations into a the target register
536 * found in operands[0]. The delta is determined by
537 * (label2 - label1), where label1 is a standard
538 * kPseudoTargetLabel and is stored in operands[2].
539 * If operands[3] is null, then label2 is a kPseudoTargetLabel
540 * and is found in lir->target. If operands[3] is non-NULL,
541 * then it is a Switch/Data table.
542 */
buzbeecbd6d442012-11-17 14:11:25 -0800543 int offset1 = (reinterpret_cast<LIR*>(lir->operands[2]))->offset;
buzbeefa57c472012-11-21 12:06:18 -0800544 SwitchTable *tab_rec = reinterpret_cast<SwitchTable*>(lir->operands[3]);
545 int offset2 = tab_rec ? tab_rec->offset : lir->target->offset;
Bill Buzbeea114add2012-05-03 15:00:40 -0700546 int delta = offset2 - offset1;
jeffhao61f916c2012-10-25 17:48:51 -0700547 if ((delta & 0xffff) == delta && ((delta & 0x8000) == 0)) {
Bill Buzbeea114add2012-05-03 15:00:40 -0700548 // Fits
549 lir->operands[1] = delta;
550 } else {
551 // Doesn't fit - must expand to kMipsDelta[Hi|Lo] pair
buzbeefa57c472012-11-21 12:06:18 -0800552 LIR *new_delta_hi =
553 RawLIR(cu, lir->dalvik_offset, kMipsDeltaHi,
Bill Buzbeea114add2012-05-03 15:00:40 -0700554 lir->operands[0], 0, lir->operands[2],
555 lir->operands[3], 0, lir->target);
buzbeefa57c472012-11-21 12:06:18 -0800556 InsertLIRBefore(lir, new_delta_hi);
557 LIR *new_delta_lo =
558 RawLIR(cu, lir->dalvik_offset, kMipsDeltaLo,
Bill Buzbeea114add2012-05-03 15:00:40 -0700559 lir->operands[0], 0, lir->operands[2],
560 lir->operands[3], 0, lir->target);
buzbeefa57c472012-11-21 12:06:18 -0800561 InsertLIRBefore(lir, new_delta_lo);
562 LIR *new_addu =
563 RawLIR(cu, lir->dalvik_offset, kMipsAddu,
jeffhao61f916c2012-10-25 17:48:51 -0700564 lir->operands[0], lir->operands[0], r_RA);
buzbeefa57c472012-11-21 12:06:18 -0800565 InsertLIRBefore(lir, new_addu);
566 lir->flags.is_nop = true;
Bill Buzbeea114add2012-05-03 15:00:40 -0700567 res = kRetryAll;
568 }
569 } else if (lir->opcode == kMipsDeltaLo) {
buzbeecbd6d442012-11-17 14:11:25 -0800570 int offset1 = (reinterpret_cast<LIR*>(lir->operands[2]))->offset;
buzbeefa57c472012-11-21 12:06:18 -0800571 SwitchTable *tab_rec = reinterpret_cast<SwitchTable*>(lir->operands[3]);
572 int offset2 = tab_rec ? tab_rec->offset : lir->target->offset;
Bill Buzbeea114add2012-05-03 15:00:40 -0700573 int delta = offset2 - offset1;
574 lir->operands[1] = delta & 0xffff;
575 } else if (lir->opcode == kMipsDeltaHi) {
buzbeecbd6d442012-11-17 14:11:25 -0800576 int offset1 = (reinterpret_cast<LIR*>(lir->operands[2]))->offset;
buzbeefa57c472012-11-21 12:06:18 -0800577 SwitchTable *tab_rec = reinterpret_cast<SwitchTable*>(lir->operands[3]);
578 int offset2 = tab_rec ? tab_rec->offset : lir->target->offset;
Bill Buzbeea114add2012-05-03 15:00:40 -0700579 int delta = offset2 - offset1;
580 lir->operands[1] = (delta >> 16) & 0xffff;
581 } else if (lir->opcode == kMipsB || lir->opcode == kMipsBal) {
buzbeefa57c472012-11-21 12:06:18 -0800582 LIR *target_lir = lir->target;
buzbeecbd6d442012-11-17 14:11:25 -0800583 uintptr_t pc = lir->offset + 4;
buzbeefa57c472012-11-21 12:06:18 -0800584 uintptr_t target = target_lir->offset;
Bill Buzbeea114add2012-05-03 15:00:40 -0700585 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;
buzbeefa57c472012-11-21 12:06:18 -0800591 ConvertShortToLongBranch(cu, lir);
Bill Buzbeea114add2012-05-03 15:00:40 -0700592 } else {
593 lir->operands[0] = delta >> 2;
594 }
595 } else if (lir->opcode >= kMipsBeqz && lir->opcode <= kMipsBnez) {
buzbeefa57c472012-11-21 12:06:18 -0800596 LIR *target_lir = lir->target;
buzbeecbd6d442012-11-17 14:11:25 -0800597 uintptr_t pc = lir->offset + 4;
buzbeefa57c472012-11-21 12:06:18 -0800598 uintptr_t target = target_lir->offset;
Bill Buzbeea114add2012-05-03 15:00:40 -0700599 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;
buzbeefa57c472012-11-21 12:06:18 -0800605 ConvertShortToLongBranch(cu, lir);
Bill Buzbeea114add2012-05-03 15:00:40 -0700606 } else {
607 lir->operands[1] = delta >> 2;
608 }
609 } else if (lir->opcode == kMipsBeq || lir->opcode == kMipsBne) {
buzbeefa57c472012-11-21 12:06:18 -0800610 LIR *target_lir = lir->target;
buzbeecbd6d442012-11-17 14:11:25 -0800611 uintptr_t pc = lir->offset + 4;
buzbeefa57c472012-11-21 12:06:18 -0800612 uintptr_t target = target_lir->offset;
Bill Buzbeea114add2012-05-03 15:00:40 -0700613 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;
buzbeefa57c472012-11-21 12:06:18 -0800619 ConvertShortToLongBranch(cu, lir);
Bill Buzbeea114add2012-05-03 15:00:40 -0700620 } else {
621 lir->operands[2] = delta >> 2;
622 }
623 } else if (lir->opcode == kMipsJal) {
buzbeefa57c472012-11-21 12:06:18 -0800624 uintptr_t cur_pc = (start_addr + lir->offset + 4) & ~3;
buzbeecbd6d442012-11-17 14:11:25 -0800625 uintptr_t target = lir->operands[0];
Bill Buzbeea114add2012-05-03 15:00:40 -0700626 /* ensure PC-region branch can be used */
buzbeefa57c472012-11-21 12:06:18 -0800627 DCHECK_EQ((cur_pc & 0xF0000000), (target & 0xF0000000));
Bill Buzbeea114add2012-05-03 15:00:40 -0700628 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) */
buzbeefa57c472012-11-21 12:06:18 -0800633 LIR *target_lir = lir->target;
634 uintptr_t target = start_addr + target_lir->offset;
Bill Buzbeea114add2012-05-03 15:00:40 -0700635 lir->operands[1] = target >> 16;
636 } else if (lir->opcode == kMipsLalo) { /* ld address lo (via ori) */
buzbeefa57c472012-11-21 12:06:18 -0800637 LIR *target_lir = lir->target;
638 uintptr_t target = start_addr + target_lir->offset;
Bill Buzbeea114add2012-05-03 15:00:40 -0700639 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];
buzbeeeaf09bc2012-11-15 14:51:41 -0800652 uint32_t bits = encoder->skeleton;
Bill Buzbeea114add2012-05-03 15:00:40 -0700653 int i;
654 for (i = 0; i < 4; i++) {
buzbeeeaf09bc2012-11-15 14:51:41 -0800655 uint32_t operand;
656 uint32_t value;
Bill Buzbeea114add2012-05-03 15:00:40 -0700657 operand = lir->operands[i];
buzbeefa57c472012-11-21 12:06:18 -0800658 switch (encoder->field_loc[i].kind) {
Bill Buzbeea114add2012-05-03 15:00:40 -0700659 case kFmtUnused:
660 break;
661 case kFmtBitBlt:
buzbeefa57c472012-11-21 12:06:18 -0800662 if (encoder->field_loc[i].start == 0 && encoder->field_loc[i].end == 31) {
Bill Buzbeea114add2012-05-03 15:00:40 -0700663 value = operand;
664 } else {
buzbeefa57c472012-11-21 12:06:18 -0800665 value = (operand << encoder->field_loc[i].start) &
666 ((1 << (encoder->field_loc[i].end + 1)) - 1);
Bill Buzbeea114add2012-05-03 15:00:40 -0700667 }
668 bits |= value;
669 break;
670 case kFmtBlt5_2:
671 value = (operand & 0x1f);
buzbeefa57c472012-11-21 12:06:18 -0800672 bits |= (value << encoder->field_loc[i].start);
673 bits |= (value << encoder->field_loc[i].end);
Bill Buzbeea114add2012-05-03 15:00:40 -0700674 break;
675 case kFmtDfp: {
buzbeef0504cd2012-11-13 16:31:10 -0800676 DCHECK(MIPS_DOUBLEREG(operand));
Elliott Hughes74847412012-06-20 18:10:21 -0700677 DCHECK_EQ((operand & 0x1), 0U);
buzbeefa57c472012-11-21 12:06:18 -0800678 value = ((operand & MIPS_FP_REG_MASK) << encoder->field_loc[i].start) &
679 ((1 << (encoder->field_loc[i].end + 1)) - 1);
Bill Buzbeea114add2012-05-03 15:00:40 -0700680 bits |= value;
681 break;
682 }
683 case kFmtSfp:
buzbeef0504cd2012-11-13 16:31:10 -0800684 DCHECK(MIPS_SINGLEREG(operand));
buzbeefa57c472012-11-21 12:06:18 -0800685 value = ((operand & MIPS_FP_REG_MASK) << encoder->field_loc[i].start) &
686 ((1 << (encoder->field_loc[i].end + 1)) - 1);
Bill Buzbeea114add2012-05-03 15:00:40 -0700687 bits |= value;
688 break;
689 default:
buzbeefa57c472012-11-21 12:06:18 -0800690 LOG(FATAL) << "Bad encoder format: " << encoder->field_loc[i].kind;
Bill Buzbeea114add2012-05-03 15:00:40 -0700691 }
692 }
jeffhao4f8f04a2012-10-02 18:10:35 -0700693 // We only support little-endian MIPS.
buzbeefa57c472012-11-21 12:06:18 -0800694 cu->code_buffer.push_back(bits & 0xff);
695 cu->code_buffer.push_back((bits >> 8) & 0xff);
696 cu->code_buffer.push_back((bits >> 16) & 0xff);
697 cu->code_buffer.push_back((bits >> 24) & 0xff);
Bill Buzbeea114add2012-05-03 15:00:40 -0700698 // TUNING: replace with proper delay slot handling
699 if (encoder->size == 8) {
700 const MipsEncodingMap *encoder = &EncodingMap[kMipsNop];
buzbeeeaf09bc2012-11-15 14:51:41 -0800701 uint32_t bits = encoder->skeleton;
buzbeefa57c472012-11-21 12:06:18 -0800702 cu->code_buffer.push_back(bits & 0xff);
703 cu->code_buffer.push_back((bits >> 8) & 0xff);
704 cu->code_buffer.push_back((bits >> 16) & 0xff);
705 cu->code_buffer.push_back((bits >> 24) & 0xff);
Bill Buzbeea114add2012-05-03 15:00:40 -0700706 }
707 }
708 return res;
buzbeee3acd072012-02-25 17:03:10 -0800709}
710
buzbee02031b12012-11-23 09:41:35 -0800711int MipsCodegen::GetInsnSize(LIR* lir)
buzbeee88dfbf2012-03-05 11:19:57 -0800712{
Bill Buzbeea114add2012-05-03 15:00:40 -0700713 return EncodingMap[lir->opcode].size;
buzbeee88dfbf2012-03-05 11:19:57 -0800714}
buzbeee3acd072012-02-25 17:03:10 -0800715
716} // namespace art