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