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