blob: 9e8af2a7f3a0042baf5d534a2b2ee0e593574f70 [file] [log] [blame]
/*
* Copyright (C) 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "../../Dalvik.h"
#include "../../CompilerInternals.h"
#include "MipsLIR.h"
#include "Codegen.h"
#include <sys/mman.h> /* for protection change */
namespace art {
#define MAX_ASSEMBLER_RETRIES 50
/*
* opcode: MipsOpCode enum
* skeleton: pre-designated bit-pattern for this opcode
* k0: key to applying ds/de
* ds: dest start bit position
* de: dest end bit position
* k1: key to applying s1s/s1e
* s1s: src1 start bit position
* s1e: src1 end bit position
* k2: key to applying s2s/s2e
* s2s: src2 start bit position
* s2e: src2 end bit position
* operands: number of operands (for sanity check purposes)
* name: mnemonic name
* fmt: for pretty-printing
*/
#define ENCODING_MAP(opcode, skeleton, k0, ds, de, k1, s1s, s1e, k2, s2s, s2e, \
k3, k3s, k3e, flags, name, fmt, size) \
{skeleton, {{k0, ds, de}, {k1, s1s, s1e}, {k2, s2s, s2e}, \
{k3, k3s, k3e}}, opcode, flags, name, fmt, size}
/* Instruction dump string format keys: !pf, where "!" is the start
* of the key, "p" is which numeric operand to use and "f" is the
* print format.
*
* [p]ositions:
* 0 -> operands[0] (dest)
* 1 -> operands[1] (src1)
* 2 -> operands[2] (src2)
* 3 -> operands[3] (extra)
*
* [f]ormats:
* h -> 4-digit hex
* d -> decimal
* E -> decimal*4
* F -> decimal*2
* c -> branch condition (beq, bne, etc.)
* t -> pc-relative target
* T -> pc-region target
* u -> 1st half of bl[x] target
* v -> 2nd half ob bl[x] target
* R -> register list
* s -> single precision floating point register
* S -> double precision floating point register
* m -> Thumb2 modified immediate
* n -> complimented Thumb2 modified immediate
* M -> Thumb2 16-bit zero-extended immediate
* b -> 4-digit binary
*
* [!] escape. To insert "!", use "!!"
*/
/* NOTE: must be kept in sync with enum MipsOpcode from MipsLIR.h */
MipsEncodingMap EncodingMap[kMipsLast] = {
ENCODING_MAP(kMips32BitData, 0x00000000,
kFmtBitBlt, 31, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
kFmtUnused, -1, -1, IS_UNARY_OP,
"data", "0x!0h(!0d)", 2),
ENCODING_MAP(kMipsAddiu, 0x24000000,
kFmtBitBlt, 20, 16, kFmtBitBlt, 25, 21, kFmtBitBlt, 15, 0,
kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
"addiu", "!0r,!1r,0x!2h(!2d)", 2),
ENCODING_MAP(kMipsAddu, 0x00000021,
kFmtBitBlt, 15, 11, kFmtBitBlt, 25, 21, kFmtBitBlt, 20, 16,
kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
"addu", "!0r,!1r,!2r", 2),
ENCODING_MAP(kMipsAnd, 0x00000024,
kFmtBitBlt, 15, 11, kFmtBitBlt, 25, 21, kFmtBitBlt, 20, 16,
kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
"and", "!0r,!1r,!2r", 2),
ENCODING_MAP(kMipsAndi, 0x30000000,
kFmtBitBlt, 20, 16, kFmtBitBlt, 25, 21, kFmtBitBlt, 15, 0,
kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
"andi", "!0r,!1r,0x!2h(!2d)", 2),
ENCODING_MAP(kMipsB, 0x10000000,
kFmtBitBlt, 15, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
kFmtUnused, -1, -1, NO_OPERAND | IS_BRANCH,
"b", "!0t", 2),
ENCODING_MAP(kMipsBal, 0x04110000,
kFmtBitBlt, 15, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
kFmtUnused, -1, -1, NO_OPERAND | IS_BRANCH | REG_DEF_LR,
"bal", "!0t", 2),
ENCODING_MAP(kMipsBeq, 0x10000000,
kFmtBitBlt, 25, 21, kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0,
kFmtUnused, -1, -1, IS_BINARY_OP | IS_BRANCH | REG_USE01,
"beq", "!0r,!1r,!2t", 2),
ENCODING_MAP(kMipsBeqz, 0x10000000, /* same as beq above with t = $zero */
kFmtBitBlt, 25, 21, kFmtBitBlt, 15, 0, kFmtUnused, -1, -1,
kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH | REG_USE0,
"beqz", "!0r,!1t", 2),
ENCODING_MAP(kMipsBgez, 0x04010000,
kFmtBitBlt, 25, 21, kFmtBitBlt, 15, 0, kFmtUnused, -1, -1,
kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH | REG_USE0,
"bgez", "!0r,!1t", 2),
ENCODING_MAP(kMipsBgtz, 0x1C000000,
kFmtBitBlt, 25, 21, kFmtBitBlt, 15, 0, kFmtUnused, -1, -1,
kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH | REG_USE0,
"bgtz", "!0r,!1t", 2),
ENCODING_MAP(kMipsBlez, 0x18000000,
kFmtBitBlt, 25, 21, kFmtBitBlt, 15, 0, kFmtUnused, -1, -1,
kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH | REG_USE0,
"blez", "!0r,!1t", 2),
ENCODING_MAP(kMipsBltz, 0x04000000,
kFmtBitBlt, 25, 21, kFmtBitBlt, 15, 0, kFmtUnused, -1, -1,
kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH | REG_USE0,
"bltz", "!0r,!1t", 2),
ENCODING_MAP(kMipsBnez, 0x14000000, /* same as bne below with t = $zero */
kFmtBitBlt, 25, 21, kFmtBitBlt, 15, 0, kFmtUnused, -1, -1,
kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH | REG_USE0,
"bnez", "!0r,!1t", 2),
ENCODING_MAP(kMipsBne, 0x14000000,
kFmtBitBlt, 25, 21, kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0,
kFmtUnused, -1, -1, IS_BINARY_OP | IS_BRANCH | REG_USE01,
"bne", "!0r,!1r,!2t", 2),
ENCODING_MAP(kMipsDiv, 0x0000001a,
kFmtUnused, -1, -1, kFmtUnused, -1, -1, kFmtBitBlt, 25, 21,
kFmtBitBlt, 20, 16, IS_QUAD_OP | REG_DEF01 | REG_USE23,
"div", "!2r,!3r", 2),
#if __mips_isa_rev>=2
ENCODING_MAP(kMipsExt, 0x7c000000,
kFmtBitBlt, 20, 16, kFmtBitBlt, 25, 21, kFmtBitBlt, 10, 6,
kFmtBitBlt, 15, 11, IS_QUAD_OP | REG_DEF0 | REG_USE1,
"ext", "!0r,!1r,!2d,!3D", 2),
#endif
ENCODING_MAP(kMipsJal, 0x0c000000,
kFmtBitBlt, 25, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH | REG_DEF_LR,
"jal", "!0T(!0E)", 2),
ENCODING_MAP(kMipsJalr, 0x00000009,
kFmtBitBlt, 15, 11, kFmtBitBlt, 25, 21, kFmtUnused, -1, -1,
kFmtUnused, -1, -1, IS_BINARY_OP | IS_BRANCH | REG_DEF0_USE1,
"jalr", "!0r,!1r", 2),
ENCODING_MAP(kMipsJr, 0x00000008,
kFmtBitBlt, 25, 21, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH | REG_USE0,
"jr", "!0r", 2),
ENCODING_MAP(kMipsLahi, 0x3C000000,
kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0, kFmtUnused, -1, -1,
kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0,
"lahi/lui", "!0r,0x!1h(!1d)", 2),
ENCODING_MAP(kMipsLalo, 0x34000000,
kFmtBitBlt, 20, 16, kFmtBitBlt, 25, 21, kFmtBitBlt, 15, 0,
kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
"lalo/ori", "!0r,!1r,0x!2h(!2d)", 2),
ENCODING_MAP(kMipsLui, 0x3C000000,
kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0, kFmtUnused, -1, -1,
kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0,
"lui", "!0r,0x!1h(!1d)", 2),
ENCODING_MAP(kMipsLb, 0x80000000,
kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0, kFmtBitBlt, 25, 21,
kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE2 | IS_LOAD,
"lb", "!0r,!1d(!2r)", 2),
ENCODING_MAP(kMipsLbu, 0x90000000,
kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0, kFmtBitBlt, 25, 21,
kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE2 | IS_LOAD,
"lbu", "!0r,!1d(!2r)", 2),
ENCODING_MAP(kMipsLh, 0x84000000,
kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0, kFmtBitBlt, 25, 21,
kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE2 | IS_LOAD,
"lh", "!0r,!1d(!2r)", 2),
ENCODING_MAP(kMipsLhu, 0x94000000,
kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0, kFmtBitBlt, 25, 21,
kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE2 | IS_LOAD,
"lhu", "!0r,!1d(!2r)", 2),
ENCODING_MAP(kMipsLw, 0x8C000000,
kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0, kFmtBitBlt, 25, 21,
kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE2 | IS_LOAD,
"lw", "!0r,!1d(!2r)", 2),
ENCODING_MAP(kMipsMfhi, 0x00000010,
kFmtBitBlt, 15, 11, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
"mfhi", "!0r", 2),
ENCODING_MAP(kMipsMflo, 0x00000012,
kFmtBitBlt, 15, 11, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
"mflo", "!0r", 2),
ENCODING_MAP(kMipsMove, 0x00000025, /* or using zero reg */
kFmtBitBlt, 15, 11, kFmtBitBlt, 25, 21, kFmtUnused, -1, -1,
kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
"move", "!0r,!1r", 2),
ENCODING_MAP(kMipsMovz, 0x0000000a,
kFmtBitBlt, 15, 11, kFmtBitBlt, 25, 21, kFmtBitBlt, 20, 16,
kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
"movz", "!0r,!1r,!2r", 2),
ENCODING_MAP(kMipsMul, 0x70000002,
kFmtBitBlt, 15, 11, kFmtBitBlt, 25, 21, kFmtBitBlt, 20, 16,
kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
"mul", "!0r,!1r,!2r", 2),
ENCODING_MAP(kMipsNop, 0x00000000,
kFmtUnused, -1, -1, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
kFmtUnused, -1, -1, NO_OPERAND,
"nop", "", 2),
ENCODING_MAP(kMipsNor, 0x00000027, /* used for "not" too */
kFmtBitBlt, 15, 11, kFmtBitBlt, 25, 21, kFmtBitBlt, 20, 16,
kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
"nor", "!0r,!1r,!2r", 2),
ENCODING_MAP(kMipsOr, 0x00000025,
kFmtBitBlt, 15, 11, kFmtBitBlt, 25, 21, kFmtBitBlt, 20, 16,
kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
"or", "!0r,!1r,!2r", 2),
ENCODING_MAP(kMipsOri, 0x34000000,
kFmtBitBlt, 20, 16, kFmtBitBlt, 25, 21, kFmtBitBlt, 15, 0,
kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
"ori", "!0r,!1r,0x!2h(!2d)", 2),
ENCODING_MAP(kMipsPref, 0xCC000000,
kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0, kFmtBitBlt, 25, 21,
kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE2,
"pref", "!0d,!1d(!2r)", 2),
ENCODING_MAP(kMipsSb, 0xA0000000,
kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0, kFmtBitBlt, 25, 21,
kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE02 | IS_STORE,
"sb", "!0r,!1d(!2r)", 2),
#if __mips_isa_rev>=2
ENCODING_MAP(kMipsSeb, 0x7c000420,
kFmtBitBlt, 15, 11, kFmtBitBlt, 20, 16, kFmtUnused, -1, -1,
kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
"seb", "!0r,!1r", 2),
ENCODING_MAP(kMipsSeh, 0x7c000620,
kFmtBitBlt, 15, 11, kFmtBitBlt, 20, 16, kFmtUnused, -1, -1,
kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
"seh", "!0r,!1r", 2),
#endif
ENCODING_MAP(kMipsSh, 0xA4000000,
kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0, kFmtBitBlt, 25, 21,
kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE02 | IS_STORE,
"sh", "!0r,!1d(!2r)", 2),
ENCODING_MAP(kMipsSll, 0x00000000,
kFmtBitBlt, 15, 11, kFmtBitBlt, 20, 16, kFmtBitBlt, 10, 6,
kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
"sll", "!0r,!1r,0x!2h(!2d)", 2),
ENCODING_MAP(kMipsSllv, 0x00000004,
kFmtBitBlt, 15, 11, kFmtBitBlt, 20, 16, kFmtBitBlt, 25, 21,
kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
"sllv", "!0r,!1r,!2r", 2),
ENCODING_MAP(kMipsSlt, 0x0000002a,
kFmtBitBlt, 15, 11, kFmtBitBlt, 25, 21, kFmtBitBlt, 20, 16,
kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
"slt", "!0r,!1r,!2r", 2),
ENCODING_MAP(kMipsSlti, 0x28000000,
kFmtBitBlt, 20, 16, kFmtBitBlt, 25, 21, kFmtBitBlt, 15, 0,
kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
"slti", "!0r,!1r,0x!2h(!2d)", 2),
ENCODING_MAP(kMipsSltu, 0x0000002b,
kFmtBitBlt, 15, 11, kFmtBitBlt, 25, 21, kFmtBitBlt, 20, 16,
kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
"sltu", "!0r,!1r,!2r", 2),
ENCODING_MAP(kMipsSra, 0x00000003,
kFmtBitBlt, 15, 11, kFmtBitBlt, 20, 16, kFmtBitBlt, 10, 6,
kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
"sra", "!0r,!1r,0x!2h(!2d)", 2),
ENCODING_MAP(kMipsSrav, 0x00000007,
kFmtBitBlt, 15, 11, kFmtBitBlt, 20, 16, kFmtBitBlt, 25, 21,
kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
"srav", "!0r,!1r,!2r", 2),
ENCODING_MAP(kMipsSrl, 0x00000002,
kFmtBitBlt, 15, 11, kFmtBitBlt, 20, 16, kFmtBitBlt, 10, 6,
kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
"srl", "!0r,!1r,0x!2h(!2d)", 2),
ENCODING_MAP(kMipsSrlv, 0x00000006,
kFmtBitBlt, 15, 11, kFmtBitBlt, 20, 16, kFmtBitBlt, 25, 21,
kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
"srlv", "!0r,!1r,!2r", 2),
ENCODING_MAP(kMipsSubu, 0x00000023, /* used for "neg" too */
kFmtBitBlt, 15, 11, kFmtBitBlt, 25, 21, kFmtBitBlt, 20, 16,
kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
"subu", "!0r,!1r,!2r", 2),
ENCODING_MAP(kMipsSw, 0xAC000000,
kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0, kFmtBitBlt, 25, 21,
kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE02 | IS_STORE,
"sw", "!0r,!1d(!2r)", 2),
ENCODING_MAP(kMipsXor, 0x00000026,
kFmtBitBlt, 15, 11, kFmtBitBlt, 25, 21, kFmtBitBlt, 20, 16,
kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
"xor", "!0r,!1r,!2r", 2),
ENCODING_MAP(kMipsXori, 0x38000000,
kFmtBitBlt, 20, 16, kFmtBitBlt, 25, 21, kFmtBitBlt, 15, 0,
kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
"xori", "!0r,!1r,0x!2h(!2d)", 2),
#ifdef __mips_hard_float
ENCODING_MAP(kMipsFadds, 0x46000000,
kFmtSfp, 10, 6, kFmtSfp, 15, 11, kFmtSfp, 20, 16,
kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
"add.s", "!0s,!1s,!2s", 2),
ENCODING_MAP(kMipsFsubs, 0x46000001,
kFmtSfp, 10, 6, kFmtSfp, 15, 11, kFmtSfp, 20, 16,
kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
"sub.s", "!0s,!1s,!2s", 2),
ENCODING_MAP(kMipsFmuls, 0x46000002,
kFmtSfp, 10, 6, kFmtSfp, 15, 11, kFmtSfp, 20, 16,
kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
"mul.s", "!0s,!1s,!2s", 2),
ENCODING_MAP(kMipsFdivs, 0x46000003,
kFmtSfp, 10, 6, kFmtSfp, 15, 11, kFmtSfp, 20, 16,
kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
"div.s", "!0s,!1s,!2s", 2),
ENCODING_MAP(kMipsFaddd, 0x46200000,
kFmtDfp, 10, 6, kFmtDfp, 15, 11, kFmtDfp, 20, 16,
kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
"add.d", "!0S,!1S,!2S", 2),
ENCODING_MAP(kMipsFsubd, 0x46200001,
kFmtDfp, 10, 6, kFmtDfp, 15, 11, kFmtDfp, 20, 16,
kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
"sub.d", "!0S,!1S,!2S", 2),
ENCODING_MAP(kMipsFmuld, 0x46200002,
kFmtDfp, 10, 6, kFmtDfp, 15, 11, kFmtDfp, 20, 16,
kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
"mul.d", "!0S,!1S,!2S", 2),
ENCODING_MAP(kMipsFdivd, 0x46200003,
kFmtDfp, 10, 6, kFmtDfp, 15, 11, kFmtDfp, 20, 16,
kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
"div.d", "!0S,!1S,!2S", 2),
ENCODING_MAP(kMipsFcvtsd, 0x46200020,
kFmtSfp, 10, 6, kFmtDfp, 15, 11, kFmtUnused, -1, -1,
kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
"cvt.s.d", "!0s,!1S", 2),
ENCODING_MAP(kMipsFcvtsw, 0x46800020,
kFmtSfp, 10, 6, kFmtSfp, 15, 11, kFmtUnused, -1, -1,
kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
"cvt.s.w", "!0s,!1s", 2),
ENCODING_MAP(kMipsFcvtds, 0x46000021,
kFmtDfp, 10, 6, kFmtSfp, 15, 11, kFmtUnused, -1, -1,
kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
"cvt.d.s", "!0S,!1s", 2),
ENCODING_MAP(kMipsFcvtdw, 0x46800021,
kFmtDfp, 10, 6, kFmtSfp, 15, 11, kFmtUnused, -1, -1,
kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
"cvt.d.w", "!0S,!1s", 2),
ENCODING_MAP(kMipsFcvtws, 0x46000024,
kFmtSfp, 10, 6, kFmtSfp, 15, 11, kFmtUnused, -1, -1,
kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
"cvt.w.s", "!0s,!1s", 2),
ENCODING_MAP(kMipsFcvtwd, 0x46200024,
kFmtSfp, 10, 6, kFmtDfp, 15, 11, kFmtUnused, -1, -1,
kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
"cvt.w.d", "!0s,!1S", 2),
ENCODING_MAP(kMipsFmovs, 0x46000006,
kFmtSfp, 10, 6, kFmtSfp, 15, 11, kFmtUnused, -1, -1,
kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
"mov.s", "!0s,!1s", 2),
ENCODING_MAP(kMipsFmovd, 0x46200006,
kFmtDfp, 10, 6, kFmtDfp, 15, 11, kFmtUnused, -1, -1,
kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
"mov.d", "!0S,!1S", 2),
ENCODING_MAP(kMipsFlwc1, 0xC4000000,
kFmtSfp, 20, 16, kFmtBitBlt, 15, 0, kFmtBitBlt, 25, 21,
kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE2 | IS_LOAD,
"lwc1", "!0s,!1d(!2r)", 2),
ENCODING_MAP(kMipsFldc1, 0xD4000000,
kFmtDfp, 20, 16, kFmtBitBlt, 15, 0, kFmtBitBlt, 25, 21,
kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE2 | IS_LOAD,
"ldc1", "!0S,!1d(!2r)", 2),
ENCODING_MAP(kMipsFswc1, 0xE4000000,
kFmtSfp, 20, 16, kFmtBitBlt, 15, 0, kFmtBitBlt, 25, 21,
kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE02 | IS_STORE,
"swc1", "!0s,!1d(!2r)", 2),
ENCODING_MAP(kMipsFsdc1, 0xF4000000,
kFmtDfp, 20, 16, kFmtBitBlt, 15, 0, kFmtBitBlt, 25, 21,
kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE02 | IS_STORE,
"sdc1", "!0S,!1d(!2r)", 2),
ENCODING_MAP(kMipsMfc1, 0x44000000,
kFmtBitBlt, 20, 16, kFmtSfp, 15, 11, kFmtUnused, -1, -1,
kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
"mfc1", "!0r,!1s", 2),
ENCODING_MAP(kMipsMtc1, 0x44800000,
kFmtBitBlt, 20, 16, kFmtSfp, 15, 11, kFmtUnused, -1, -1,
kFmtUnused, -1, -1, IS_BINARY_OP | REG_USE0 | REG_DEF1,
"mtc1", "!0r,!1s", 2),
#endif
ENCODING_MAP(kMipsUndefined, 0x64000000,
kFmtUnused, -1, -1, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
kFmtUnused, -1, -1, NO_OPERAND,
"undefined", "", 2),
};
/*
* Assemble the LIR into binary instruction format. Note that we may
* discover that pc-relative displacements may not fit the selected
* instruction. In those cases we will try to substitute a new code
* sequence or request that the trace be shortened and retried.
*/
AssemblerStatus oatAssembleInstructions(CompilationUnit *cUnit,
intptr_t startAddr)
{
UNIMPLEMENTED(FATAL) << "Rework for art code buffer";
#if 0
int *bufferAddr = (int *) cUnit->codeBuffer;
MipsLIR *lir;
for (lir = (MipsLIR *) cUnit->firstLIRInsn; lir; lir = NEXT_LIR(lir)) {
if (lir->opcode < 0) {
continue;
}
if (lir->flags.isNop) {
continue;
}
if (lir->opcode == kMipsB || lir->opcode == kMipsBal) {
MipsLIR *targetLIR = (MipsLIR *) lir->generic.target;
intptr_t pc = lir->generic.offset + 4;
intptr_t target = targetLIR->generic.offset;
int delta = target - pc;
if (delta & 0x3) {
LOG(FATAL) << "PC-rel offset not multiple of 4: " << delta;
}
if (delta > 131068 || delta < -131069) {
LOG(FATAL) << "Unconditional branch out of range: " << delta;
}
lir->operands[0] = delta >> 2;
} else if (lir->opcode >= kMipsBeqz && lir->opcode <= kMipsBnez) {
MipsLIR *targetLIR = (MipsLIR *) lir->generic.target;
intptr_t pc = lir->generic.offset + 4;
intptr_t target = targetLIR->generic.offset;
int delta = target - pc;
if (delta & 0x3) {
LOG(FATAL) << "PC-rel offset not multiple of 4: " << delta;
}
if (delta > 131068 || delta < -131069) {
LOG(FATAL) << "Conditional branch out of range: " << delta;
}
lir->operands[1] = delta >> 2;
} else if (lir->opcode == kMipsBeq || lir->opcode == kMipsBne) {
MipsLIR *targetLIR = (MipsLIR *) lir->generic.target;
intptr_t pc = lir->generic.offset + 4;
intptr_t target = targetLIR->generic.offset;
int delta = target - pc;
if (delta & 0x3) {
LOG(FATAL) << "PC-rel offset not multiple of 4: " << delta;
}
if (delta > 131068 || delta < -131069) {
LOG(FATAL) << "Conditional branch out of range: " << delta;
}
lir->operands[2] = delta >> 2;
} else if (lir->opcode == kMipsJal) {
intptr_t curPC = (startAddr + lir->generic.offset + 4) & ~3;
intptr_t target = lir->operands[0];
/* ensure PC-region branch can be used */
DCHECK_EQ((curPC & 0xF0000000), (target & 0xF0000000));
if (target & 0x3) {
LOG(FATAL) << "Jump target not multiple of 4: " << target;
}
lir->operands[0] = target >> 2;
} else if (lir->opcode == kMipsLahi) { /* load address hi (via lui) */
MipsLIR *targetLIR = (MipsLIR *) lir->generic.target;
intptr_t target = startAddr + targetLIR->generic.offset;
lir->operands[1] = target >> 16;
} else if (lir->opcode == kMipsLalo) { /* load address lo (via ori) */
MipsLIR *targetLIR = (MipsLIR *) lir->generic.target;
intptr_t target = startAddr + targetLIR->generic.offset;
lir->operands[2] = lir->operands[2] + target;
}
MipsEncodingMap *encoder = &EncodingMap[lir->opcode];
u4 bits = encoder->skeleton;
int i;
for (i = 0; i < 4; i++) {
u4 operand;
u4 value;
operand = lir->operands[i];
switch(encoder->fieldLoc[i].kind) {
case kFmtUnused:
break;
case kFmtBitBlt:
if (encoder->fieldLoc[i].start == 0 && encoder->fieldLoc[i].end == 31) {
value = operand;
} else {
value = (operand << encoder->fieldLoc[i].start) &
((1 << (encoder->fieldLoc[i].end + 1)) - 1);
}
bits |= value;
break;
case kFmtDfp: {
DCHECK(DOUBLEREG(operand));
DCHECK_EQ((operand & 0x1), 0);
value = ((operand & FP_REG_MASK) << encoder->fieldLoc[i].start) &
((1 << (encoder->fieldLoc[i].end + 1)) - 1);
bits |= value;
break;
}
case kFmtSfp:
DCHECK(SINGLEREG(operand));
value = ((operand & FP_REG_MASK) << encoder->fieldLoc[i].start) &
((1 << (encoder->fieldLoc[i].end + 1)) - 1);
bits |= value;
break;
default:
LOG(FATAL) << "Bad encoder format: "
<< encoder->fieldLoc[i].kind;
}
}
DCHECK_EQ(encoder->size, 2);
*bufferAddr++ = bits;
}
#endif
return kSuccess;
}
/*
* Target-dependent offset assignment.
* TODO: normalize usage of flags.size and make this target
* independent.
*/
int oatAssignInsnOffsets(CompilationUnit* cUnit)
{
MipsLIR* mipsLIR;
int offset = 0;
for (mipsLIR = (MipsLIR *) cUnit->firstLIRInsn;
mipsLIR;
mipsLIR = NEXT_LIR(mipsLIR)) {
mipsLIR->generic.offset = offset;
if (mipsLIR->opcode >= 0) {
if (!mipsLIR->flags.isNop) {
mipsLIR->flags.size = EncodingMap[mipsLIR->opcode].size * 2;
offset += mipsLIR->flags.size;
}
} else if (mipsLIR->opcode == kMipsPseudoPseudoAlign4) {
if (offset & 0x2) {
offset += 2;
mipsLIR->operands[0] = 1;
} else {
mipsLIR->operands[0] = 0;
}
}
/* Pseudo opcodes don't consume space */
}
return offset;
}
} // namespace art