Multi-target support
This CL represents a step towards splitting out the target dependent
and target independent portions of the compiler, and also adds in the
beginning of a MIPS compiler based on the MIPS AOSP Jit submission.
More polish is clearly needed, but the split is here probably pretty
close. The MIPS code will not compile at this point (and there is no
makefile target at present), but it's pretty close.
There should be no changes in functionality of the Arm compiler in this
CL - just moved stuff around.
Change-Id: Ia66b2847e22644a1ec63e66bf5f2fee722f963d4
diff --git a/src/compiler/codegen/mips/Mips32/Factory.cc b/src/compiler/codegen/mips/Mips32/Factory.cc
new file mode 100644
index 0000000..ffbb223
--- /dev/null
+++ b/src/compiler/codegen/mips/Mips32/Factory.cc
@@ -0,0 +1,942 @@
+/*
+ * 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.
+ */
+
+namespace art {
+
+/*
+ * This file contains codegen for the MIPS32 ISA and is intended to be
+ * includes by:
+ *
+ * Codegen-$(TARGET_ARCH_VARIANT).c
+ *
+ */
+
+static int coreRegs[] = {r_ZERO, r_AT, r_V0, r_V1, r_A0, r_A1, r_A2, r_A3,
+ r_T0, r_T1, r_T2, r_T3, r_T4, r_T5, r_T6, r_T7,
+ r_S0, r_S1, r_S2, r_S3, r_S4, r_S5, r_S6, r_S7, r_T8,
+ r_T9, r_K0, r_K1, r_GP, r_SP, r_FP, r_RA};
+static int reservedRegs[] = {r_ZERO, r_AT, r_S0, r_S1, r_K0, r_K1, r_GP, r_SP};
+static int coreTemps[] = {r_V0, r_V1, r_A0, r_A1, r_A2, r_A3, r_T0, r_T1, r_T2,
+ r_T3, r_T4, r_T5, r_T6, r_T7, r_T8, r_T9};
+#ifdef __mips_hard_float
+static int fpRegs[] = {r_F0, r_F1, r_F2, r_F3, r_F4, r_F5, r_F6, r_F7,
+ r_F8, r_F9, r_F10, r_F11, r_F12, r_F13, r_F14, r_F15};
+static int fpTemps[] = {r_F0, r_F1, r_F2, r_F3, r_F4, r_F5, r_F6, r_F7,
+ r_F8, r_F9, r_F10, r_F11, r_F12, r_F13, r_F14, r_F15};
+#endif
+
+static void storePair(CompilationUnit *cUnit, int base, int lowReg,
+ int highReg);
+static void loadPair(CompilationUnit *cUnit, int base, int lowReg, int highReg);
+static MipsLIR *loadWordDisp(CompilationUnit *cUnit, int rBase, int displacement,
+ int rDest);
+static MipsLIR *storeWordDisp(CompilationUnit *cUnit, int rBase,
+ int displacement, int rSrc);
+static MipsLIR *genRegRegCheck(CompilationUnit *cUnit,
+ MipsConditionCode cond,
+ int reg1, int reg2, int dOffset,
+ MipsLIR *pcrLabel);
+static MipsLIR *loadConstant(CompilationUnit *cUnit, int rDest, int value);
+
+#ifdef __mips_hard_float
+static MipsLIR *fpRegCopy(CompilationUnit *cUnit, int rDest, int rSrc)
+{
+ MipsLIR* res = (MipsLIR *) oatNew(cUnit, sizeof(MipsLIR), true, kAllocLIR);
+ res->operands[0] = rDest;
+ res->operands[1] = rSrc;
+ if (rDest == rSrc) {
+ res->flags.isNop = true;
+ } else {
+ /* must be both DOUBLE or both not DOUBLE */
+ DCHECK_EQ(DOUBLEREG(rDest),DOUBLEREG(rSrc));
+ if (DOUBLEREG(rDest)) {
+ res->opcode = kMipsFmovd;
+ } else {
+ if (SINGLEREG(rDest)) {
+ if (SINGLEREG(rSrc)) {
+ res->opcode = kMipsFmovs;
+ } else {
+ /* note the operands are swapped for the mtc1 instr */
+ res->opcode = kMipsMtc1;
+ res->operands[0] = rSrc;
+ res->operands[1] = rDest;
+ }
+ } else {
+ DCHECK(SINGLEREG(rSrc));
+ res->opcode = kMipsMfc1;
+ }
+ }
+ }
+ setupResourceMasks(res);
+ return res;
+}
+#endif
+
+/*
+ * Load a immediate using a shortcut if possible; otherwise
+ * grab from the per-translation literal pool. If target is
+ * a high register, build constant into a low register and copy.
+ *
+ * No additional register clobbering operation performed. Use this version when
+ * 1) rDest is freshly returned from oatAllocTemp or
+ * 2) The codegen is under fixed register usage
+ */
+static MipsLIR *loadConstantNoClobber(CompilationUnit *cUnit, int rDest,
+ int value)
+{
+ MipsLIR *res;
+
+#ifdef __mips_hard_float
+ int rDestSave = rDest;
+ int isFpReg = FPREG(rDest);
+ if (isFpReg) {
+ DCHECK(SINGLEREG(rDest));
+ rDest = oatAllocTemp(cUnit);
+ }
+#endif
+
+ /* See if the value can be constructed cheaply */
+ if (value == 0) {
+ res = newLIR2(cUnit, kMipsMove, rDest, r_ZERO);
+ } else if ((value > 0) && (value <= 65535)) {
+ res = newLIR3(cUnit, kMipsOri, rDest, r_ZERO, value);
+ } else if ((value < 0) && (value >= -32768)) {
+ res = newLIR3(cUnit, kMipsAddiu, rDest, r_ZERO, value);
+ } else {
+ res = newLIR2(cUnit, kMipsLui, rDest, value>>16);
+ if (value & 0xffff)
+ newLIR3(cUnit, kMipsOri, rDest, rDest, value);
+ }
+
+#ifdef __mips_hard_float
+ if (isFpReg) {
+ newLIR2(cUnit, kMipsMtc1, rDest, rDestSave);
+ oatFreeTemp(cUnit, rDest);
+ }
+#endif
+
+ return res;
+}
+
+/*
+ * Load an immediate value into a fixed or temp register. Target
+ * register is clobbered, and marked inUse.
+ */
+static MipsLIR *loadConstant(CompilationUnit *cUnit, int rDest, int value)
+{
+ if (oatIsTemp(cUnit, rDest)) {
+ oatClobber(cUnit, rDest);
+ oatMarkInUse(cUnit, rDest);
+ }
+ return loadConstantNoClobber(cUnit, rDest, value);
+}
+
+/*
+ * Load a class pointer value into a fixed or temp register. Target
+ * register is clobbered, and marked inUse.
+ */
+static MipsLIR *loadClassPointer(CompilationUnit *cUnit, int rDest, int value)
+{
+ MipsLIR *res;
+ if (oatIsTemp(cUnit, rDest)) {
+ oatClobber(cUnit, rDest);
+ oatMarkInUse(cUnit, rDest);
+ }
+ res = newLIR2(cUnit, kMipsLui, rDest, value>>16);
+ if (value & 0xffff)
+ newLIR3(cUnit, kMipsOri, rDest, rDest, value);
+ return res;
+}
+
+static MipsLIR *opNone(CompilationUnit *cUnit, OpKind op)
+{
+ MipsLIR *res;
+ MipsOpCode opcode = kMipsNop;
+ switch (op) {
+ case kOpUncondBr:
+ opcode = kMipsB;
+ break;
+ default:
+ LOG(FATAL) << "Bad case in opNone";
+ }
+ res = newLIR0(cUnit, opcode);
+ return res;
+}
+
+static MipsLIR *opCompareBranch(CompilationUnit *cUnit, MipsOpCode opc, int rs, int rt)
+{
+ MipsLIR *res;
+ if (rt < 0) {
+ DCHECK(opc >= kMipsBeqz && opc <= kMipsBnez);
+ res = newLIR1(cUnit, opc, rs);
+ } else {
+ DCHECK(opc == kMipsBeq || opc == kMipsBne);
+ res = newLIR2(cUnit, opc, rs, rt);
+ }
+ return res;
+}
+
+static MipsLIR *loadMultiple(CompilationUnit *cUnit, int rBase, int rMask);
+
+static MipsLIR *opReg(CompilationUnit *cUnit, OpKind op, int rDestSrc)
+{
+ MipsOpCode opcode = kMipsNop;
+ switch (op) {
+ case kOpBlx:
+ opcode = kMipsJalr;
+ break;
+ default:
+ LOG(FATAL) << "Bad case in opReg";
+ }
+ return newLIR2(cUnit, opcode, r_RA, rDestSrc);
+}
+
+static MipsLIR *opRegRegImm(CompilationUnit *cUnit, OpKind op, int rDest,
+ int rSrc1, int value);
+MipsLIR *opRegImm(CompilationUnit *cUnit, OpKind op, int rDestSrc1,
+ int value)
+{
+ MipsLIR *res;
+ bool neg = (value < 0);
+ int absValue = (neg) ? -value : value;
+ bool shortForm = (absValue & 0xff) == absValue;
+ MipsOpCode opcode = kMipsNop;
+ switch (op) {
+ case kOpAdd:
+ return opRegRegImm(cUnit, op, rDestSrc1, rDestSrc1, value);
+ break;
+ case kOpSub:
+ return opRegRegImm(cUnit, op, rDestSrc1, rDestSrc1, value);
+ break;
+ default:
+ LOG(FATAL) << "Bad case in opRegImm";
+ break;
+ }
+ if (shortForm)
+ res = newLIR2(cUnit, opcode, rDestSrc1, absValue);
+ else {
+ int rScratch = oatAllocTemp(cUnit);
+ res = loadConstant(cUnit, rScratch, value);
+ if (op == kOpCmp)
+ newLIR2(cUnit, opcode, rDestSrc1, rScratch);
+ else
+ newLIR3(cUnit, opcode, rDestSrc1, rDestSrc1, rScratch);
+ }
+ return res;
+}
+
+static MipsLIR *opRegRegReg(CompilationUnit *cUnit, OpKind op, int rDest,
+ int rSrc1, int rSrc2)
+{
+ MipsOpCode opcode = kMipsNop;
+ switch (op) {
+ case kOpAdd:
+ opcode = kMipsAddu;
+ break;
+ case kOpSub:
+ opcode = kMipsSubu;
+ break;
+ case kOpAnd:
+ opcode = kMipsAnd;
+ break;
+ case kOpMul:
+ opcode = kMipsMul;
+ break;
+ case kOpOr:
+ opcode = kMipsOr;
+ break;
+ case kOpXor:
+ opcode = kMipsXor;
+ break;
+ case kOpLsl:
+ opcode = kMipsSllv;
+ break;
+ case kOpLsr:
+ opcode = kMipsSrlv;
+ break;
+ case kOpAsr:
+ opcode = kMipsSrav;
+ break;
+ default:
+ LOG(FATAL) << "bad case in opRegRegReg";
+ break;
+ }
+ return newLIR3(cUnit, opcode, rDest, rSrc1, rSrc2);
+}
+
+static MipsLIR *opRegRegImm(CompilationUnit *cUnit, OpKind op, int rDest,
+ int rSrc1, int value)
+{
+ MipsLIR *res;
+ MipsOpCode opcode = kMipsNop;
+ bool shortForm = true;
+
+ switch(op) {
+ case kOpAdd:
+ if (IS_SIMM16(value)) {
+ opcode = kMipsAddiu;
+ }
+ else {
+ shortForm = false;
+ opcode = kMipsAddu;
+ }
+ break;
+ case kOpSub:
+ if (IS_SIMM16((-value))) {
+ value = -value;
+ opcode = kMipsAddiu;
+ }
+ else {
+ shortForm = false;
+ opcode = kMipsSubu;
+ }
+ break;
+ case kOpLsl:
+ DCHECK(value >= 0 && value <= 31);
+ opcode = kMipsSll;
+ break;
+ case kOpLsr:
+ DCHECK(value >= 0 && value <= 31);
+ opcode = kMipsSrl;
+ break;
+ case kOpAsr:
+ DCHECK(value >= 0 && value <= 31);
+ opcode = kMipsSra;
+ break;
+ case kOpAnd:
+ if (IS_UIMM16((value))) {
+ opcode = kMipsAndi;
+ }
+ else {
+ shortForm = false;
+ opcode = kMipsAnd;
+ }
+ break;
+ case kOpOr:
+ if (IS_UIMM16((value))) {
+ opcode = kMipsOri;
+ }
+ else {
+ shortForm = false;
+ opcode = kMipsOr;
+ }
+ break;
+ case kOpXor:
+ if (IS_UIMM16((value))) {
+ opcode = kMipsXori;
+ }
+ else {
+ shortForm = false;
+ opcode = kMipsXor;
+ }
+ break;
+ case kOpMul:
+ shortForm = false;
+ opcode = kMipsMul;
+ break;
+ default:
+ LOG(FATAL) << "Bad case in opRegRegImm";
+ break;
+ }
+
+ if (shortForm)
+ res = newLIR3(cUnit, opcode, rDest, rSrc1, value);
+ else {
+ if (rDest != rSrc1) {
+ res = loadConstant(cUnit, rDest, value);
+ newLIR3(cUnit, opcode, rDest, rSrc1, rDest);
+ } else {
+ int rScratch = oatAllocTemp(cUnit);
+ res = loadConstant(cUnit, rScratch, value);
+ newLIR3(cUnit, opcode, rDest, rSrc1, rScratch);
+ }
+ }
+ return res;
+}
+
+MipsLIR *opRegReg(CompilationUnit *cUnit, OpKind op, int rDestSrc1,
+ int rSrc2)
+{
+ MipsOpCode opcode = kMipsNop;
+ MipsLIR *res;
+ switch (op) {
+ case kOpMov:
+ opcode = kMipsMove;
+ break;
+ case kOpMvn:
+ return newLIR3(cUnit, kMipsNor, rDestSrc1, rSrc2, r_ZERO);
+ case kOpNeg:
+ return newLIR3(cUnit, kMipsSubu, rDestSrc1, r_ZERO, rSrc2);
+ case kOpAdd:
+ case kOpAnd:
+ case kOpMul:
+ case kOpOr:
+ case kOpSub:
+ case kOpXor:
+ return opRegRegReg(cUnit, op, rDestSrc1, rDestSrc1, rSrc2);
+ case kOp2Byte:
+#if __mips_isa_rev>=2
+ res = newLIR2(cUnit, kMipsSeb, rDestSrc1, rSrc2);
+#else
+ res = opRegRegImm(cUnit, kOpLsl, rDestSrc1, rSrc2, 24);
+ opRegRegImm(cUnit, kOpAsr, rDestSrc1, rDestSrc1, 24);
+#endif
+ return res;
+ case kOp2Short:
+#if __mips_isa_rev>=2
+ res = newLIR2(cUnit, kMipsSeh, rDestSrc1, rSrc2);
+#else
+ res = opRegRegImm(cUnit, kOpLsl, rDestSrc1, rSrc2, 16);
+ opRegRegImm(cUnit, kOpAsr, rDestSrc1, rDestSrc1, 16);
+#endif
+ return res;
+ case kOp2Char:
+ return newLIR3(cUnit, kMipsAndi, rDestSrc1, rSrc2, 0xFFFF);
+ default:
+ LOG(FATAL) << "Bad case in opRegReg";
+ break;
+ }
+ return newLIR2(cUnit, opcode, rDestSrc1, rSrc2);
+}
+
+static MipsLIR *loadConstantValueWide(CompilationUnit *cUnit, int rDestLo,
+ int rDestHi, int valLo, int valHi)
+{
+ MipsLIR *res;
+ res = loadConstantNoClobber(cUnit, rDestLo, valLo);
+ loadConstantNoClobber(cUnit, rDestHi, valHi);
+ return res;
+}
+
+/* Load value from base + scaled index. */
+static MipsLIR *loadBaseIndexed(CompilationUnit *cUnit, int rBase,
+ int rIndex, int rDest, int scale, OpSize size)
+{
+ MipsLIR *first = NULL;
+ MipsLIR *res;
+ MipsOpCode opcode = kMipsNop;
+ int tReg = oatAllocTemp(cUnit);
+
+#ifdef __mips_hard_float
+ if (FPREG(rDest)) {
+ DCHECK(SINGLEREG(rDest));
+ DCHECK((size == kWord) || (size == kSingle));
+ size = kSingle;
+ } else {
+ if (size == kSingle)
+ size = kWord;
+ }
+#endif
+
+ if (!scale) {
+ first = newLIR3(cUnit, kMipsAddu, tReg , rBase, rIndex);
+ } else {
+ first = opRegRegImm(cUnit, kOpLsl, tReg, rIndex, scale);
+ newLIR3(cUnit, kMipsAddu, tReg , rBase, tReg);
+ }
+
+ switch (size) {
+#ifdef __mips_hard_float
+ case kSingle:
+ opcode = kMipsFlwc1;
+ break;
+#endif
+ case kWord:
+ opcode = kMipsLw;
+ break;
+ case kUnsignedHalf:
+ opcode = kMipsLhu;
+ break;
+ case kSignedHalf:
+ opcode = kMipsLh;
+ break;
+ case kUnsignedByte:
+ opcode = kMipsLbu;
+ break;
+ case kSignedByte:
+ opcode = kMipsLb;
+ break;
+ default:
+ LOG(FATAL) << "Bad case in loadBaseIndexed";
+ }
+
+ res = newLIR3(cUnit, opcode, rDest, 0, tReg);
+ oatFreeTemp(cUnit, tReg);
+ return (first) ? first : res;
+}
+
+/* store value base base + scaled index. */
+static MipsLIR *storeBaseIndexed(CompilationUnit *cUnit, int rBase,
+ int rIndex, int rSrc, int scale, OpSize size)
+{
+ MipsLIR *first = NULL;
+ MipsLIR *res;
+ MipsOpCode opcode = kMipsNop;
+ int rNewIndex = rIndex;
+ int tReg = oatAllocTemp(cUnit);
+
+#ifdef __mips_hard_float
+ if (FPREG(rSrc)) {
+ DCHECK(SINGLEREG(rSrc));
+ DCHECK((size == kWord) || (size == kSingle));
+ size = kSingle;
+ } else {
+ if (size == kSingle)
+ size = kWord;
+ }
+#endif
+
+ if (!scale) {
+ first = newLIR3(cUnit, kMipsAddu, tReg , rBase, rIndex);
+ } else {
+ first = opRegRegImm(cUnit, kOpLsl, tReg, rIndex, scale);
+ newLIR3(cUnit, kMipsAddu, tReg , rBase, tReg);
+ }
+
+ switch (size) {
+#ifdef __mips_hard_float
+ case kSingle:
+ opcode = kMipsFswc1;
+ break;
+#endif
+ case kWord:
+ opcode = kMipsSw;
+ break;
+ case kUnsignedHalf:
+ case kSignedHalf:
+ opcode = kMipsSh;
+ break;
+ case kUnsignedByte:
+ case kSignedByte:
+ opcode = kMipsSb;
+ break;
+ default:
+ LOG(FATAL) << "Bad case in storeBaseIndexed";
+ }
+ res = newLIR3(cUnit, opcode, rSrc, 0, tReg);
+ oatFreeTemp(cUnit, rNewIndex);
+ return first;
+}
+
+static MipsLIR *loadMultiple(CompilationUnit *cUnit, int rBase, int rMask)
+{
+ int i;
+ int loadCnt = 0;
+ MipsLIR *res = NULL ;
+ genBarrier(cUnit);
+
+ for (i = 0; i < 8; i++, rMask >>= 1) {
+ if (rMask & 0x1) { /* map r0 to MIPS r_A0 */
+ newLIR3(cUnit, kMipsLw, i+r_A0, loadCnt*4, rBase);
+ loadCnt++;
+ }
+ }
+
+ if (loadCnt) {/* increment after */
+ newLIR3(cUnit, kMipsAddiu, rBase, rBase, loadCnt*4);
+ }
+
+ genBarrier(cUnit);
+ return res; /* NULL always returned which should be ok since no callers use it */
+}
+
+static MipsLIR *storeMultiple(CompilationUnit *cUnit, int rBase, int rMask)
+{
+ int i;
+ int storeCnt = 0;
+ MipsLIR *res = NULL ;
+ genBarrier(cUnit);
+
+ for (i = 0; i < 8; i++, rMask >>= 1) {
+ if (rMask & 0x1) { /* map r0 to MIPS r_A0 */
+ newLIR3(cUnit, kMipsSw, i+r_A0, storeCnt*4, rBase);
+ storeCnt++;
+ }
+ }
+
+ if (storeCnt) { /* increment after */
+ newLIR3(cUnit, kMipsAddiu, rBase, rBase, storeCnt*4);
+ }
+
+ genBarrier(cUnit);
+ return res; /* NULL always returned which should be ok since no callers use it */
+}
+
+static MipsLIR *loadBaseDispBody(CompilationUnit *cUnit, MIR *mir, int rBase,
+ int displacement, int rDest, int rDestHi,
+ OpSize size, int sReg)
+/*
+ * Load value from base + displacement. Optionally perform null check
+ * on base (which must have an associated sReg and MIR). If not
+ * performing null check, incoming MIR can be null. IMPORTANT: this
+ * code must not allocate any new temps. If a new register is needed
+ * and base and dest are the same, spill some other register to
+ * rlp and then restore.
+ */
+{
+ MipsLIR *res;
+ MipsLIR *load = NULL;
+ MipsLIR *load2 = NULL;
+ MipsOpCode opcode = kMipsNop;
+ bool shortForm = IS_SIMM16(displacement);
+ bool pair = false;
+
+ switch (size) {
+ case kLong:
+ case kDouble:
+ pair = true;
+ opcode = kMipsLw;
+#ifdef __mips_hard_float
+ if (FPREG(rDest)) {
+ opcode = kMipsFlwc1;
+ if (DOUBLEREG(rDest)) {
+ rDest = rDest - FP_DOUBLE;
+ } else {
+ DCHECK(FPREG(rDestHi));
+ DCHECK(rDest == (rDestHi - 1));
+ }
+ rDestHi = rDest + 1;
+ }
+#endif
+ shortForm = IS_SIMM16_2WORD(displacement);
+ DCHECK_EQ((displacement & 0x3), 0);
+ break;
+ case kWord:
+ case kSingle:
+ opcode = kMipsLw;
+#ifdef __mips_hard_float
+ if (FPREG(rDest)) {
+ opcode = kMipsFlwc1;
+ DCHECK(SINGLEREG(rDest));
+ }
+#endif
+ DCHECK_EQ((displacement & 0x3), 0);
+ break;
+ case kUnsignedHalf:
+ opcode = kMipsLhu;
+ DCHECK_EQ((displacement & 0x1), 0);
+ break;
+ case kSignedHalf:
+ opcode = kMipsLh;
+ DCHECK_EQ((displacement & 0x1), 0);
+ break;
+ case kUnsignedByte:
+ opcode = kMipsLbu;
+ break;
+ case kSignedByte:
+ opcode = kMipsLb;
+ break;
+ default:
+ LOG(FATAL) << "Bad case in loadBaseIndexedBody";
+ }
+
+ if (shortForm) {
+ if (!pair) {
+ load = res = newLIR3(cUnit, opcode, rDest, displacement, rBase);
+ } else {
+ load = res = newLIR3(cUnit, opcode, rDest, displacement + LOWORD_OFFSET, rBase);
+ load2 = newLIR3(cUnit, opcode, rDestHi, displacement + HIWORD_OFFSET, rBase);
+ }
+ } else {
+ if (pair) {
+ int rTmp = oatAllocFreeTemp(cUnit);
+ res = opRegRegImm(cUnit, kOpAdd, rTmp, rBase, displacement);
+ load = newLIR3(cUnit, opcode, rDest, LOWORD_OFFSET, rTmp);
+ load2 = newLIR3(cUnit, opcode, rDestHi, HIWORD_OFFSET, rTmp);
+ oatFreeTemp(cUnit, rTmp);
+ } else {
+ int rTmp = (rBase == rDest) ? oatAllocFreeTemp(cUnit)
+ : rDest;
+ res = loadConstant(cUnit, rTmp, displacement);
+ load = newLIR3(cUnit, opcode, rDest, rBase, rTmp);
+ if (rTmp != rDest)
+ oatFreeTemp(cUnit, rTmp);
+ }
+ }
+
+ UNIMPLEMENTED(FATAL) << "Needs art conversion";
+#if 0
+ if (rBase == rFP) {
+ if (load != NULL)
+ annotateDalvikRegAccess(load, (displacement + (pair ? LOWORD_OFFSET : 0)) >> 2,
+ true /* isLoad */);
+ if (load2 != NULL)
+ annotateDalvikRegAccess(load2, (displacement + HIWORD_OFFSET) >> 2,
+ true /* isLoad */);
+ }
+#endif
+ return load;
+}
+
+static MipsLIR *loadBaseDisp(CompilationUnit *cUnit, MIR *mir, int rBase,
+ int displacement, int rDest, OpSize size,
+ int sReg)
+{
+ return loadBaseDispBody(cUnit, mir, rBase, displacement, rDest, -1,
+ size, sReg);
+}
+
+static MipsLIR *loadBaseDispWide(CompilationUnit *cUnit, MIR *mir, int rBase,
+ int displacement, int rDestLo, int rDestHi,
+ int sReg)
+{
+ return loadBaseDispBody(cUnit, mir, rBase, displacement, rDestLo, rDestHi,
+ kLong, sReg);
+}
+
+static MipsLIR *storeBaseDispBody(CompilationUnit *cUnit, int rBase,
+ int displacement, int rSrc, int rSrcHi,
+ OpSize size)
+{
+ MipsLIR *res;
+ MipsLIR *store = NULL;
+ MipsLIR *store2 = NULL;
+ MipsOpCode opcode = kMipsNop;
+ bool shortForm = IS_SIMM16(displacement);
+ bool pair = false;
+
+ switch (size) {
+ case kLong:
+ case kDouble:
+ pair = true;
+ opcode = kMipsSw;
+#ifdef __mips_hard_float
+ if (FPREG(rSrc)) {
+ opcode = kMipsFswc1;
+ if (DOUBLEREG(rSrc)) {
+ rSrc = rSrc - FP_DOUBLE;
+ } else {
+ DCHECK(FPREG(rSrcHi));
+ DCHECK_EQ(rSrc, (rSrcHi - 1));
+ }
+ rSrcHi = rSrc + 1;
+ }
+#endif
+ shortForm = IS_SIMM16_2WORD(displacement);
+ DCHECK_EQ((displacement & 0x3), 0);
+ break;
+ case kWord:
+ case kSingle:
+ opcode = kMipsSw;
+#ifdef __mips_hard_float
+ if (FPREG(rSrc)) {
+ opcode = kMipsFswc1;
+ DCHECK(SINGLEREG(rSrc));
+ }
+#endif
+ DCHECK_EQ((displacement & 0x3), 0);
+ break;
+ case kUnsignedHalf:
+ case kSignedHalf:
+ opcode = kMipsSh;
+ DCHECK_EQ((displacement & 0x1), 0);
+ break;
+ case kUnsignedByte:
+ case kSignedByte:
+ opcode = kMipsSb;
+ break;
+ default:
+ LOG(FATAL) << "Bad case in storeBaseIndexedBody";
+ }
+
+ if (shortForm) {
+ if (!pair) {
+ store = res = newLIR3(cUnit, opcode, rSrc, displacement, rBase);
+ } else {
+ store = res = newLIR3(cUnit, opcode, rSrc, displacement + LOWORD_OFFSET, rBase);
+ store2 = newLIR3(cUnit, opcode, rSrcHi, displacement + HIWORD_OFFSET, rBase);
+ }
+ } else {
+ int rScratch = oatAllocTemp(cUnit);
+ res = opRegRegImm(cUnit, kOpAdd, rScratch, rBase, displacement);
+ if (!pair) {
+ store = newLIR3(cUnit, opcode, rSrc, 0, rScratch);
+ } else {
+ store = newLIR3(cUnit, opcode, rSrc, LOWORD_OFFSET, rScratch);
+ store2 = newLIR3(cUnit, opcode, rSrcHi, HIWORD_OFFSET, rScratch);
+ }
+ oatFreeTemp(cUnit, rScratch);
+ }
+
+ UNIMPLEMENTED(FATAL) << "Needs art conversion";
+#if 0
+ if (rBase == rFP) {
+ if (store != NULL)
+ annotateDalvikRegAccess(store, (displacement + (pair ? LOWORD_OFFSET : 0)) >> 2,
+ false /* isLoad */);
+ if (store2 != NULL)
+ annotateDalvikRegAccess(store2, (displacement + HIWORD_OFFSET) >> 2,
+ false /* isLoad */);
+ }
+#endif
+
+ return res;
+}
+
+static MipsLIR *storeBaseDisp(CompilationUnit *cUnit, int rBase,
+ int displacement, int rSrc, OpSize size)
+{
+ return storeBaseDispBody(cUnit, rBase, displacement, rSrc, -1, size);
+}
+
+static MipsLIR *storeBaseDispWide(CompilationUnit *cUnit, int rBase,
+ int displacement, int rSrcLo, int rSrcHi)
+{
+ return storeBaseDispBody(cUnit, rBase, displacement, rSrcLo, rSrcHi, kLong);
+}
+
+static void storePair(CompilationUnit *cUnit, int base, int lowReg, int highReg)
+{
+ storeWordDisp(cUnit, base, LOWORD_OFFSET, lowReg);
+ storeWordDisp(cUnit, base, HIWORD_OFFSET, highReg);
+}
+
+static void loadPair(CompilationUnit *cUnit, int base, int lowReg, int highReg)
+{
+ loadWordDisp(cUnit, base, LOWORD_OFFSET , lowReg);
+ loadWordDisp(cUnit, base, HIWORD_OFFSET , highReg);
+}
+
+static MipsLIR* genRegCopyNoInsert(CompilationUnit *cUnit, int rDest, int rSrc)
+{
+ MipsLIR* res;
+ MipsOpCode opcode;
+#ifdef __mips_hard_float
+ if (FPREG(rDest) || FPREG(rSrc))
+ return fpRegCopy(cUnit, rDest, rSrc);
+#endif
+ res = (MipsLIR *) oatNew(cUnit, sizeof(MipsLIR), true, kAllocLIR);
+ opcode = kMipsMove;
+ DCHECK(LOWREG(rDest) && LOWREG(rSrc));
+ res->operands[0] = rDest;
+ res->operands[1] = rSrc;
+ res->opcode = opcode;
+ setupResourceMasks(res);
+ if (rDest == rSrc) {
+ res->flags.isNop = true;
+ }
+ return res;
+}
+
+static MipsLIR* genRegCopy(CompilationUnit *cUnit, int rDest, int rSrc)
+{
+ MipsLIR *res = genRegCopyNoInsert(cUnit, rDest, rSrc);
+ oatAppendLIR(cUnit, (LIR*)res);
+ return res;
+}
+
+static void genRegCopyWide(CompilationUnit *cUnit, int destLo, int destHi,
+ int srcLo, int srcHi)
+{
+#ifdef __mips_hard_float
+ bool destFP = FPREG(destLo) && FPREG(destHi);
+ bool srcFP = FPREG(srcLo) && FPREG(srcHi);
+ DCHECK_EQ(FPREG(srcLo), FPREG(srcHi));
+ DCHECK_EQ(FPREG(destLo), FPREG(destHi));
+ if (destFP) {
+ if (srcFP) {
+ genRegCopy(cUnit, S2D(destLo, destHi), S2D(srcLo, srcHi));
+ } else {
+ /* note the operands are swapped for the mtc1 instr */
+ newLIR2(cUnit, kMipsMtc1, srcLo, destLo);
+ newLIR2(cUnit, kMipsMtc1, srcHi, destHi);
+ }
+ } else {
+ if (srcFP) {
+ newLIR2(cUnit, kMipsMfc1, destLo, srcLo);
+ newLIR2(cUnit, kMipsMfc1, destHi, srcHi);
+ } else {
+ // Handle overlap
+ if (srcHi == destLo) {
+ genRegCopy(cUnit, destHi, srcHi);
+ genRegCopy(cUnit, destLo, srcLo);
+ } else {
+ genRegCopy(cUnit, destLo, srcLo);
+ genRegCopy(cUnit, destHi, srcHi);
+ }
+ }
+ }
+#else
+ // Handle overlap
+ if (srcHi == destLo) {
+ genRegCopy(cUnit, destHi, srcHi);
+ genRegCopy(cUnit, destLo, srcLo);
+ } else {
+ genRegCopy(cUnit, destLo, srcLo);
+ genRegCopy(cUnit, destHi, srcHi);
+ }
+#endif
+}
+
+static inline MipsLIR *genRegImmCheck(CompilationUnit *cUnit,
+ MipsConditionCode cond, int reg,
+ int checkValue, int dOffset,
+ MipsLIR *pcrLabel)
+{
+ MipsLIR *branch = NULL;
+
+ if (checkValue == 0) {
+ MipsOpCode opc = kMipsNop;
+ if (cond == kMipsCondEq) {
+ opc = kMipsBeqz;
+ } else if (cond == kMipsCondNe) {
+ opc = kMipsBnez;
+ } else if (cond == kMipsCondLt || cond == kMipsCondMi) {
+ opc = kMipsBltz;
+ } else if (cond == kMipsCondLe) {
+ opc = kMipsBlez;
+ } else if (cond == kMipsCondGt) {
+ opc = kMipsBgtz;
+ } else if (cond == kMipsCondGe) {
+ opc = kMipsBgez;
+ } else {
+ LOG(FATAL) << "Bad case in genRegImmCheck";
+ }
+ branch = opCompareBranch(cUnit, opc, reg, -1);
+ } else if (IS_SIMM16(checkValue)) {
+ if (cond == kMipsCondLt) {
+ int tReg = oatAllocTemp(cUnit);
+ newLIR3(cUnit, kMipsSlti, tReg, reg, checkValue);
+ branch = opCompareBranch(cUnit, kMipsBne, tReg, r_ZERO);
+ oatFreeTemp(cUnit, tReg);
+ } else {
+ LOG(FATAL) << "Bad case in genRegImmCheck";
+ }
+ } else {
+ LOG(FATAL) << "Bad case in genRegImmCheck";
+ }
+
+ UNIMPLEMENTED(FATAL) << "Needs art conversion";
+ return NULL;
+#if 0
+ if (cUnit->jitMode == kJitMethod) {
+ BasicBlock *bb = cUnit->curBlock;
+ if (bb->taken) {
+ MipsLIR *exceptionLabel = (MipsLIR *) cUnit->blockLabelList;
+ exceptionLabel += bb->taken->id;
+ branch->generic.target = (LIR *) exceptionLabel;
+ return exceptionLabel;
+ } else {
+ LOG(FATAL) << "Catch blocks not handled yet";
+ return NULL;
+ }
+ } else {
+ return genCheckCommon(cUnit, dOffset, branch, pcrLabel);
+ }
+#endif
+}
+
+} // namespace art
diff --git a/src/compiler/codegen/mips/Mips32/Gen.cc b/src/compiler/codegen/mips/Mips32/Gen.cc
new file mode 100644
index 0000000..f49cdab
--- /dev/null
+++ b/src/compiler/codegen/mips/Mips32/Gen.cc
@@ -0,0 +1,649 @@
+/*
+ * 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.
+ */
+
+/*
+ * This file contains codegen for the Mips ISA and is intended to be
+ * includes by:
+ *
+ * Codegen-$(TARGET_ARCH_VARIANT).c
+ *
+ */
+
+namespace art {
+
+// FIXME: need the following:
+void genSuspendTest(CompilationUnit* cUnit, MIR* mir) {}
+void genMonitorEnter(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc) {}
+void genMonitorExit(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc) {}
+void genCheckCast(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc) {}
+void genInstanceof(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
+ RegLocation rlSrc) {}
+void genNewInstance(CompilationUnit* cUnit, MIR* mir,
+ RegLocation rlDest) {}
+void genThrow(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc) {}
+void genConstString(CompilationUnit* cUnit, MIR* mir,
+ RegLocation rlDest, RegLocation rlSrc) {}
+void genConstClass(CompilationUnit* cUnit, MIR* mir,
+ RegLocation rlDest, RegLocation rlSrc) {}
+void genArrayGet(CompilationUnit* cUnit, MIR* mir, OpSize size,
+ RegLocation rlArray, RegLocation rlIndex,
+ RegLocation rlDest, int scale) {}
+void genArrayPut(CompilationUnit* cUnit, MIR* mir, OpSize size,
+ RegLocation rlArray, RegLocation rlIndex,
+ RegLocation rlSrc, int scale) {}
+void genArrayObjPut(CompilationUnit* cUnit, MIR* mir,
+ RegLocation rlArray, RegLocation rlIndex,
+ RegLocation rlSrc, int scale) {}
+void genIPut(CompilationUnit* cUnit, MIR* mir, OpSize size,
+ RegLocation rlSrc, RegLocation rlObj,
+ bool isLongOrDouble, bool isObject) {}
+bool genArithOpInt(CompilationUnit* cUnit, MIR* mir,
+ RegLocation rlDest, RegLocation rlSrc1,
+ RegLocation rlSrc2) { return 0; }
+bool genArithOpLong(CompilationUnit* cUnit, MIR* mir,
+ RegLocation rlDest, RegLocation rlSrc1,
+ RegLocation rlSrc2) { return 0; }
+bool genShiftOpLong(CompilationUnit* cUnit, MIR* mir,
+ RegLocation rlDest, RegLocation rlSrc1,
+ RegLocation rlShift) { return 0; }
+bool genArithOpIntLit(CompilationUnit* cUnit, MIR* mir,
+ RegLocation rlDest, RegLocation rlSrc,
+ int lit) { return 0; }
+
+
+
+
+
+
+
+
+STATIC RegLocation getRetLoc(CompilationUnit* cUnit);
+
+void warnIfUnresolved(CompilationUnit* cUnit, int fieldIdx, Field* field) {
+ if (field == NULL) {
+ const DexFile::FieldId& field_id = cUnit->dex_file->GetFieldId(fieldIdx);
+ std::string class_name(cUnit->dex_file->GetFieldDeclaringClassDescriptor(field_id));
+ std::string field_name(cUnit->dex_file->GetFieldName(field_id));
+ LOG(INFO) << "Field " << PrettyDescriptor(class_name) << "." << field_name
+ << " unresolved at compile time";
+ } else {
+ // We also use the slow path for wide volatile fields.
+ }
+}
+
+/*
+ * Construct an s4 from two consecutive half-words of switch data.
+ * This needs to check endianness because the DEX optimizer only swaps
+ * half-words in instruction stream.
+ *
+ * "switchData" must be 32-bit aligned.
+ */
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+STATIC inline s4 s4FromSwitchData(const void* switchData) {
+ return *(s4*) switchData;
+}
+#else
+STATIC inline s4 s4FromSwitchData(const void* switchData) {
+ u2* data = switchData;
+ return data[0] | (((s4) data[1]) << 16);
+}
+#endif
+/*
+ * Insert a kMipsPseudoCaseLabel at the beginning of the Dalvik
+ * offset vaddr. This label will be used to fix up the case
+ * branch table during the assembly phase. Be sure to set
+ * all resource flags on this to prevent code motion across
+ * target boundaries. KeyVal is just there for debugging.
+ */
+STATIC MipsLIR* insertCaseLabel(CompilationUnit* cUnit, int vaddr, int keyVal)
+{
+ std::map<unsigned int, LIR*>::iterator it;
+ it = cUnit->boundaryMap.find(vaddr);
+ if (it == cUnit->boundaryMap.end()) {
+ LOG(FATAL) << "Error: didn't find vaddr 0x" << std::hex << vaddr;
+ }
+ MipsLIR* newLabel = (MipsLIR*)oatNew(cUnit, sizeof(MipsLIR), true, kAllocLIR);
+ newLabel->generic.dalvikOffset = vaddr;
+ newLabel->opcode = kMipsPseudoCaseLabel;
+ newLabel->operands[0] = keyVal;
+ oatInsertLIRAfter(it->second, (LIR*)newLabel);
+ return newLabel;
+}
+
+STATIC void markPackedCaseLabels(CompilationUnit* cUnit, SwitchTable *tabRec)
+{
+ const u2* table = tabRec->table;
+ int baseVaddr = tabRec->vaddr;
+ int *targets = (int*)&table[4];
+ int entries = table[1];
+ int lowKey = s4FromSwitchData(&table[2]);
+ for (int i = 0; i < entries; i++) {
+ tabRec->targets[i] = insertCaseLabel(cUnit, baseVaddr + targets[i],
+ i + lowKey);
+ }
+}
+
+STATIC void markSparseCaseLabels(CompilationUnit* cUnit, SwitchTable *tabRec)
+{
+ const u2* table = tabRec->table;
+ int baseVaddr = tabRec->vaddr;
+ int entries = table[1];
+ int* keys = (int*)&table[2];
+ int* targets = &keys[entries];
+ for (int i = 0; i < entries; i++) {
+ tabRec->targets[i] = insertCaseLabel(cUnit, baseVaddr + targets[i],
+ keys[i]);
+ }
+}
+
+void oatProcessSwitchTables(CompilationUnit* cUnit)
+{
+ GrowableListIterator iterator;
+ oatGrowableListIteratorInit(&cUnit->switchTables, &iterator);
+ while (true) {
+ SwitchTable *tabRec = (SwitchTable *) oatGrowableListIteratorNext(
+ &iterator);
+ if (tabRec == NULL) break;
+ if (tabRec->table[0] == kPackedSwitchSignature)
+ markPackedCaseLabels(cUnit, tabRec);
+ else if (tabRec->table[0] == kSparseSwitchSignature)
+ markSparseCaseLabels(cUnit, tabRec);
+ else {
+ LOG(FATAL) << "Invalid switch table";
+ }
+ }
+}
+
+STATIC void dumpSparseSwitchTable(const u2* table)
+ /*
+ * Sparse switch data format:
+ * ushort ident = 0x0200 magic value
+ * ushort size number of entries in the table; > 0
+ * int keys[size] keys, sorted low-to-high; 32-bit aligned
+ * int targets[size] branch targets, relative to switch opcode
+ *
+ * Total size is (2+size*4) 16-bit code units.
+ */
+{
+ u2 ident = table[0];
+ int entries = table[1];
+ int* keys = (int*)&table[2];
+ int* targets = &keys[entries];
+ LOG(INFO) << "Sparse switch table - ident:0x" << std::hex << ident <<
+ ", entries: " << std::dec << entries;
+ for (int i = 0; i < entries; i++) {
+ LOG(INFO) << " Key[" << keys[i] << "] -> 0x" << std::hex <<
+ targets[i];
+ }
+}
+
+STATIC void dumpPackedSwitchTable(const u2* table)
+ /*
+ * Packed switch data format:
+ * ushort ident = 0x0100 magic value
+ * ushort size number of entries in the table
+ * int first_key first (and lowest) switch case value
+ * int targets[size] branch targets, relative to switch opcode
+ *
+ * Total size is (4+size*2) 16-bit code units.
+ */
+{
+ u2 ident = table[0];
+ int* targets = (int*)&table[4];
+ int entries = table[1];
+ int lowKey = s4FromSwitchData(&table[2]);
+ LOG(INFO) << "Packed switch table - ident:0x" << std::hex << ident <<
+ ", entries: " << std::dec << entries << ", lowKey: " << lowKey;
+ for (int i = 0; i < entries; i++) {
+ LOG(INFO) << " Key[" << (i + lowKey) << "] -> 0x" << std::hex <<
+ targets[i];
+ }
+}
+
+/*
+ * The sparse table in the literal pool is an array of <key,displacement>
+ * pairs. For each set, we'll load them as a pair using ldmia.
+ * This means that the register number of the temp we use for the key
+ * must be lower than the reg for the displacement.
+ *
+ * The test loop will look something like:
+ *
+ * adr rBase, <table>
+ * ldr rVal, [rSP, vRegOff]
+ * mov rIdx, #tableSize
+ * lp:
+ * ldmia rBase!, {rKey, rDisp}
+ * sub rIdx, #1
+ * cmp rVal, rKey
+ * ifeq
+ * add rPC, rDisp ; This is the branch from which we compute displacement
+ * cbnz rIdx, lp
+ */
+STATIC void genSparseSwitch(CompilationUnit* cUnit, MIR* mir,
+ RegLocation rlSrc)
+{
+ UNIMPLEMENTED(FATAL) << "Need Mips implementation";
+#if 0
+ const u2* table = cUnit->insns + mir->offset + mir->dalvikInsn.vB;
+ if (cUnit->printMe) {
+ dumpSparseSwitchTable(table);
+ }
+ // Add the table to the list - we'll process it later
+ SwitchTable *tabRec = (SwitchTable *)oatNew(cUnit, sizeof(SwitchTable),
+ true, kAllocData);
+ tabRec->table = table;
+ tabRec->vaddr = mir->offset;
+ int size = table[1];
+ tabRec->targets = (MipsLIR* *)oatNew(cUnit, size * sizeof(MipsLIR*), true,
+ kAllocLIR);
+ oatInsertGrowableList(cUnit, &cUnit->switchTables, (intptr_t)tabRec);
+
+ // Get the switch value
+ rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
+ int rBase = oatAllocTemp(cUnit);
+ /* Allocate key and disp temps */
+ int rKey = oatAllocTemp(cUnit);
+ int rDisp = oatAllocTemp(cUnit);
+ // Make sure rKey's register number is less than rDisp's number for ldmia
+ if (rKey > rDisp) {
+ int tmp = rDisp;
+ rDisp = rKey;
+ rKey = tmp;
+ }
+ // Materialize a pointer to the switch table
+ newLIR3(cUnit, kThumb2Adr, rBase, 0, (intptr_t)tabRec);
+ // Set up rIdx
+ int rIdx = oatAllocTemp(cUnit);
+ loadConstant(cUnit, rIdx, size);
+ // Establish loop branch target
+ MipsLIR* target = newLIR0(cUnit, kMipsPseudoTargetLabel);
+ target->defMask = ENCODE_ALL;
+ // Load next key/disp
+ newLIR2(cUnit, kThumb2LdmiaWB, rBase, (1 << rKey) | (1 << rDisp));
+ opRegReg(cUnit, kOpCmp, rKey, rlSrc.lowReg);
+ // Go if match. NOTE: No instruction set switch here - must stay Thumb2
+ genIT(cUnit, kMipsCondEq, "");
+ MipsLIR* switchBranch = newLIR1(cUnit, kThumb2AddPCR, rDisp);
+ tabRec->bxInst = switchBranch;
+ // Needs to use setflags encoding here
+ newLIR3(cUnit, kThumb2SubsRRI12, rIdx, rIdx, 1);
+ MipsLIR* branch = opCondBranch(cUnit, kMipsCondNe);
+ branch->generic.target = (LIR*)target;
+#endif
+}
+
+STATIC void genPackedSwitch(CompilationUnit* cUnit, MIR* mir,
+ RegLocation rlSrc)
+{
+ UNIMPLEMENTED(FATAL) << "Need Mips implementation";
+#if 0
+ const u2* table = cUnit->insns + mir->offset + mir->dalvikInsn.vB;
+ if (cUnit->printMe) {
+ dumpPackedSwitchTable(table);
+ }
+ // Add the table to the list - we'll process it later
+ SwitchTable *tabRec = (SwitchTable *)oatNew(cUnit, sizeof(SwitchTable),
+ true, kAllocData);
+ tabRec->table = table;
+ tabRec->vaddr = mir->offset;
+ int size = table[1];
+ tabRec->targets = (MipsLIR* *)oatNew(cUnit, size * sizeof(MipsLIR*), true,
+ kAllocLIR);
+ oatInsertGrowableList(cUnit, &cUnit->switchTables, (intptr_t)tabRec);
+
+ // Get the switch value
+ rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
+ int tableBase = oatAllocTemp(cUnit);
+ // Materialize a pointer to the switch table
+ newLIR3(cUnit, kThumb2Adr, tableBase, 0, (intptr_t)tabRec);
+ int lowKey = s4FromSwitchData(&table[2]);
+ int keyReg;
+ // Remove the bias, if necessary
+ if (lowKey == 0) {
+ keyReg = rlSrc.lowReg;
+ } else {
+ keyReg = oatAllocTemp(cUnit);
+ opRegRegImm(cUnit, kOpSub, keyReg, rlSrc.lowReg, lowKey);
+ }
+ // Bounds check - if < 0 or >= size continue following switch
+ opRegImm(cUnit, kOpCmp, keyReg, size-1);
+ MipsLIR* branchOver = opCondBranch(cUnit, kMipsCondHi);
+
+ // Load the displacement from the switch table
+ int dispReg = oatAllocTemp(cUnit);
+ loadBaseIndexed(cUnit, tableBase, keyReg, dispReg, 2, kWord);
+
+ // ..and go! NOTE: No instruction set switch here - must stay Thumb2
+ MipsLIR* switchBranch = newLIR1(cUnit, kThumb2AddPCR, dispReg);
+ tabRec->bxInst = switchBranch;
+
+ /* branchOver target here */
+ MipsLIR* target = newLIR0(cUnit, kMipsPseudoTargetLabel);
+ target->defMask = ENCODE_ALL;
+ branchOver->generic.target = (LIR*)target;
+#endif
+}
+
+/*
+ * Array data table format:
+ * ushort ident = 0x0300 magic value
+ * ushort width width of each element in the table
+ * uint size number of elements in the table
+ * ubyte data[size*width] table of data values (may contain a single-byte
+ * padding at the end)
+ *
+ * Total size is 4+(width * size + 1)/2 16-bit code units.
+ */
+STATIC void genFillArrayData(CompilationUnit* cUnit, MIR* mir,
+ RegLocation rlSrc)
+{
+ UNIMPLEMENTED(FATAL) << "Need Mips implementation";
+#if 0
+ const u2* table = cUnit->insns + mir->offset + mir->dalvikInsn.vB;
+ // Add the table to the list - we'll process it later
+ FillArrayData *tabRec = (FillArrayData *)
+ oatNew(cUnit, sizeof(FillArrayData), true, kAllocData);
+ tabRec->table = table;
+ tabRec->vaddr = mir->offset;
+ u2 width = tabRec->table[1];
+ u4 size = tabRec->table[2] | (((u4)tabRec->table[3]) << 16);
+ tabRec->size = (size * width) + 8;
+
+ oatInsertGrowableList(cUnit, &cUnit->fillArrayData, (intptr_t)tabRec);
+
+ // Making a call - use explicit registers
+ oatFlushAllRegs(cUnit); /* Everything to home location */
+ loadValueDirectFixed(cUnit, rlSrc, r0);
+ loadWordDisp(cUnit, rSELF,
+ OFFSETOF_MEMBER(Thread, pHandleFillArrayDataFromCode), rLR);
+ // Materialize a pointer to the fill data image
+ newLIR3(cUnit, kThumb2Adr, r1, 0, (intptr_t)tabRec);
+ callRuntimeHelper(cUnit, rLR);
+#endif
+}
+
+STATIC void genIGet(CompilationUnit* cUnit, MIR* mir, OpSize size,
+ RegLocation rlDest, RegLocation rlObj,
+ bool isLongOrDouble, bool isObject)
+{
+ UNIMPLEMENTED(FATAL) << "Need Mips implementation";
+#if 0
+ int fieldOffset;
+ bool isVolatile;
+ uint32_t fieldIdx = mir->dalvikInsn.vC;
+ bool fastPath =
+ cUnit->compiler->ComputeInstanceFieldInfo(fieldIdx, cUnit,
+ fieldOffset, isVolatile, false);
+ if (fastPath && !SLOW_FIELD_PATH) {
+ RegLocation rlResult;
+ RegisterClass regClass = oatRegClassBySize(size);
+ DCHECK_GE(fieldOffset, 0);
+ rlObj = loadValue(cUnit, rlObj, kCoreReg);
+ if (isLongOrDouble) {
+ DCHECK(rlDest.wide);
+ genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir);/* null obj? */
+ int regPtr = oatAllocTemp(cUnit);
+ opRegRegImm(cUnit, kOpAdd, regPtr, rlObj.lowReg, fieldOffset);
+ rlResult = oatEvalLoc(cUnit, rlDest, regClass, true);
+ loadPair(cUnit, regPtr, rlResult.lowReg, rlResult.highReg);
+ if (isVolatile) {
+ oatGenMemBarrier(cUnit, kSY);
+ }
+ oatFreeTemp(cUnit, regPtr);
+ storeValueWide(cUnit, rlDest, rlResult);
+ } else {
+ rlResult = oatEvalLoc(cUnit, rlDest, regClass, true);
+ genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir);/* null object? */
+ loadBaseDisp(cUnit, mir, rlObj.lowReg, fieldOffset, rlResult.lowReg,
+ kWord, rlObj.sRegLow);
+ if (isVolatile) {
+ oatGenMemBarrier(cUnit, kSY);
+ }
+ storeValue(cUnit, rlDest, rlResult);
+ }
+ } else {
+ int getterOffset = isLongOrDouble ? OFFSETOF_MEMBER(Thread, pGet64Instance) :
+ (isObject ? OFFSETOF_MEMBER(Thread, pGetObjInstance)
+ : OFFSETOF_MEMBER(Thread, pGet32Instance));
+ loadWordDisp(cUnit, rSELF, getterOffset, rLR);
+ loadValueDirect(cUnit, rlObj, r1);
+ loadConstant(cUnit, r0, fieldIdx);
+ callRuntimeHelper(cUnit, rLR);
+ if (isLongOrDouble) {
+ RegLocation rlResult = oatGetReturnWide(cUnit);
+ storeValueWide(cUnit, rlDest, rlResult);
+ } else {
+ RegLocation rlResult = oatGetReturn(cUnit);
+ storeValue(cUnit, rlDest, rlResult);
+ }
+ }
+#endif
+}
+
+/*
+ * Perform a "reg cmp imm" operation and jump to the PCR region if condition
+ * satisfies.
+ */
+STATIC void genNegFloat(CompilationUnit *cUnit, RegLocation rlDest,
+ RegLocation rlSrc)
+{
+ RegLocation rlResult;
+ rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
+ rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
+ opRegRegImm(cUnit, kOpAdd, rlResult.lowReg,
+ rlSrc.lowReg, 0x80000000);
+ storeValue(cUnit, rlDest, rlResult);
+}
+
+STATIC void genNegDouble(CompilationUnit *cUnit, RegLocation rlDest,
+ RegLocation rlSrc)
+{
+ RegLocation rlResult;
+ rlSrc = loadValueWide(cUnit, rlSrc, kCoreReg);
+ rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
+ opRegRegImm(cUnit, kOpAdd, rlResult.highReg, rlSrc.highReg,
+ 0x80000000);
+ genRegCopy(cUnit, rlResult.lowReg, rlSrc.lowReg);
+ storeValueWide(cUnit, rlDest, rlResult);
+}
+
+STATIC void genMulLong(CompilationUnit *cUnit, RegLocation rlDest,
+ RegLocation rlSrc1, RegLocation rlSrc2)
+{
+ UNIMPLEMENTED(FATAL) << "Need Mips implementation";
+#if 0
+ RegLocation rlResult;
+ loadValueDirectWideFixed(cUnit, rlSrc1, r_ARG0, r_ARG1);
+ loadValueDirectWideFixed(cUnit, rlSrc2, r_ARG2, r_ARG3);
+ genDispatchToHandler(cUnit, TEMPLATE_MUL_LONG);
+ rlResult = oatGetReturnWide(cUnit);
+ storeValueWide(cUnit, rlDest, rlResult);
+#endif
+}
+
+STATIC bool partialOverlap(int sreg1, int sreg2)
+{
+ return abs(sreg1 - sreg2) == 1;
+}
+
+STATIC void withCarryHelper(CompilationUnit *cUnit, MipsOpCode opc,
+ RegLocation rlDest, RegLocation rlSrc1,
+ RegLocation rlSrc2, int sltuSrc1, int sltuSrc2)
+{
+ int tReg = oatAllocTemp(cUnit);
+ newLIR3(cUnit, opc, rlDest.lowReg, rlSrc1.lowReg, rlSrc2.lowReg);
+ newLIR3(cUnit, kMipsSltu, tReg, sltuSrc1, sltuSrc2);
+ newLIR3(cUnit, opc, rlDest.highReg, rlSrc1.highReg, rlSrc2.highReg);
+ newLIR3(cUnit, opc, rlDest.highReg, rlDest.highReg, tReg);
+ oatFreeTemp(cUnit, tReg);
+}
+
+STATIC void genLong3Addr(CompilationUnit *cUnit, MIR *mir, OpKind firstOp,
+ OpKind secondOp, RegLocation rlDest,
+ RegLocation rlSrc1, RegLocation rlSrc2)
+{
+ UNIMPLEMENTED(FATAL) << "Need Mips implementation";
+#if 0
+ RegLocation rlResult;
+ int carryOp = (secondOp == kOpAdc || secondOp == kOpSbc);
+
+ if (partialOverlap(rlSrc1.sRegLow,rlSrc2.sRegLow) ||
+ partialOverlap(rlSrc1.sRegLow,rlDest.sRegLow) ||
+ partialOverlap(rlSrc2.sRegLow,rlDest.sRegLow)) {
+ // Rare case - not enough registers to properly handle
+ genInterpSingleStep(cUnit, mir);
+ } else if (rlDest.sRegLow == rlSrc1.sRegLow) {
+ rlResult = loadValueWide(cUnit, rlDest, kCoreReg);
+ rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
+ if (!carryOp) {
+ opRegRegReg(cUnit, firstOp, rlResult.lowReg, rlResult.lowReg, rlSrc2.lowReg);
+ opRegRegReg(cUnit, secondOp, rlResult.highReg, rlResult.highReg, rlSrc2.highReg);
+ } else if (secondOp == kOpAdc) {
+ withCarryHelper(cUnit, kMipsAddu, rlResult, rlResult, rlSrc2,
+ rlResult.lowReg, rlSrc2.lowReg);
+ } else {
+ int tReg = oatAllocTemp(cUnit);
+ newLIR2(cUnit, kMipsMove, tReg, rlResult.lowReg);
+ withCarryHelper(cUnit, kMipsSubu, rlResult, rlResult, rlSrc2,
+ tReg, rlResult.lowReg);
+ oatFreeTemp(cUnit, tReg);
+ }
+ storeValueWide(cUnit, rlDest, rlResult);
+ } else if (rlDest.sRegLow == rlSrc2.sRegLow) {
+ rlResult = loadValueWide(cUnit, rlDest, kCoreReg);
+ rlSrc1 = loadValueWide(cUnit, rlSrc1, kCoreReg);
+ if (!carryOp) {
+ opRegRegReg(cUnit, firstOp, rlResult.lowReg, rlSrc1.lowReg, rlResult.lowReg);
+ opRegRegReg(cUnit, secondOp, rlResult.highReg, rlSrc1.highReg, rlResult.highReg);
+ } else if (secondOp == kOpAdc) {
+ withCarryHelper(cUnit, kMipsAddu, rlResult, rlSrc1, rlResult,
+ rlResult.lowReg, rlSrc1.lowReg);
+ } else {
+ withCarryHelper(cUnit, kMipsSubu, rlResult, rlSrc1, rlResult,
+ rlSrc1.lowReg, rlResult.lowReg);
+ }
+ storeValueWide(cUnit, rlDest, rlResult);
+ } else {
+ rlSrc1 = loadValueWide(cUnit, rlSrc1, kCoreReg);
+ rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
+ rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
+ if (!carryOp) {
+ opRegRegReg(cUnit, firstOp, rlResult.lowReg, rlSrc1.lowReg, rlSrc2.lowReg);
+ opRegRegReg(cUnit, secondOp, rlResult.highReg, rlSrc1.highReg, rlSrc2.highReg);
+ } else if (secondOp == kOpAdc) {
+ withCarryHelper(cUnit, kMipsAddu, rlResult, rlSrc1, rlSrc2,
+ rlResult.lowReg, rlSrc1.lowReg);
+ } else {
+ withCarryHelper(cUnit, kMipsSubu, rlResult, rlSrc1, rlSrc2,
+ rlSrc1.lowReg, rlResult.lowReg);
+ }
+ storeValueWide(cUnit, rlDest, rlResult);
+ }
+#endif
+}
+
+void oatInitializeRegAlloc(CompilationUnit* cUnit)
+{
+ int numRegs = sizeof(coreRegs)/sizeof(*coreRegs);
+ int numReserved = sizeof(reservedRegs)/sizeof(*reservedRegs);
+ int numTemps = sizeof(coreTemps)/sizeof(*coreTemps);
+#ifdef __mips_hard_float
+ int numFPRegs = sizeof(fpRegs)/sizeof(*fpRegs);
+ int numFPTemps = sizeof(fpTemps)/sizeof(*fpTemps);
+#else
+ int numFPRegs = 0;
+ int numFPTemps = 0;
+#endif
+ RegisterPool *pool = (RegisterPool *)oatNew(cUnit, sizeof(*pool), true,
+ kAllocRegAlloc);
+ cUnit->regPool = pool;
+ pool->numCoreRegs = numRegs;
+ pool->coreRegs = (RegisterInfo *)
+ oatNew(cUnit, numRegs * sizeof(*cUnit->regPool->coreRegs),
+ true, kAllocRegAlloc);
+ pool->numFPRegs = numFPRegs;
+ pool->FPRegs = numFPRegs == 0 ? NULL : (RegisterInfo *)
+ oatNew(cUnit, numFPRegs * sizeof(*cUnit->regPool->FPRegs), true,
+ kAllocRegAlloc);
+ oatInitPool(pool->coreRegs, coreRegs, pool->numCoreRegs);
+ oatInitPool(pool->FPRegs, fpRegs, pool->numFPRegs);
+ // Keep special registers from being allocated
+ for (int i = 0; i < numReserved; i++) {
+ if (NO_SUSPEND && !cUnit->genDebugger &&
+ (reservedRegs[i] == rSUSPEND)) {
+ //To measure cost of suspend check
+ continue;
+ }
+ oatMarkInUse(cUnit, reservedRegs[i]);
+ }
+ // Mark temp regs - all others not in use can be used for promotion
+ for (int i = 0; i < numTemps; i++) {
+ oatMarkTemp(cUnit, coreTemps[i]);
+ }
+ for (int i = 0; i < numFPTemps; i++) {
+ oatMarkTemp(cUnit, fpTemps[i]);
+ }
+ // Construct the alias map.
+ cUnit->phiAliasMap = (int*)oatNew(cUnit, cUnit->numSSARegs *
+ sizeof(cUnit->phiAliasMap[0]), false,
+ kAllocDFInfo);
+ for (int i = 0; i < cUnit->numSSARegs; i++) {
+ cUnit->phiAliasMap[i] = i;
+ }
+ for (MIR* phi = cUnit->phiList; phi; phi = phi->meta.phiNext) {
+ int defReg = phi->ssaRep->defs[0];
+ for (int i = 0; i < phi->ssaRep->numUses; i++) {
+ for (int j = 0; j < cUnit->numSSARegs; j++) {
+ if (cUnit->phiAliasMap[j] == phi->ssaRep->uses[i]) {
+ cUnit->phiAliasMap[j] = defReg;
+ }
+ }
+ }
+ }
+}
+
+STATIC void genMonitor(CompilationUnit *cUnit, MIR *mir)
+{
+ UNIMPLEMENTED(FATAL) << "Need Mips implementation";
+#if 0
+ genMonitorPortable(cUnit, mir);
+#endif
+}
+
+STATIC void genCmpLong(CompilationUnit *cUnit, MIR *mir, RegLocation rlDest,
+ RegLocation rlSrc1, RegLocation rlSrc2)
+{
+ UNIMPLEMENTED(FATAL) << "Need Mips implementation";
+#if 0
+ RegLocation rlResult;
+ loadValueDirectWideFixed(cUnit, rlSrc1, r_ARG0, r_ARG1);
+ loadValueDirectWideFixed(cUnit, rlSrc2, r_ARG2, r_ARG3);
+ genDispatchToHandler(cUnit, TEMPLATE_CMP_LONG);
+ rlResult = oatGetReturn(cUnit);
+ storeValue(cUnit, rlDest, rlResult);
+#endif
+}
+
+STATIC void genMultiplyByTwoBitMultiplier(CompilationUnit *cUnit,
+ RegLocation rlSrc, RegLocation rlResult, int lit,
+ int firstBit, int secondBit)
+{
+ // We can't implement "add src, src, src, lsl#shift" on Thumb, so we have
+ // to do a regular multiply.
+ opRegRegImm(cUnit, kOpMul, rlResult.lowReg, rlSrc.lowReg, lit);
+}
+
+} // namespace art
diff --git a/src/compiler/codegen/mips/Mips32/Ralloc.cc b/src/compiler/codegen/mips/Mips32/Ralloc.cc
new file mode 100644
index 0000000..e0912d7
--- /dev/null
+++ b/src/compiler/codegen/mips/Mips32/Ralloc.cc
@@ -0,0 +1,64 @@
+/*
+ * 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.
+ */
+
+namespace art {
+
+/*
+ * This file contains codegen for the Mips ISA and is intended to be
+ * includes by:
+ *
+ * Codegen-$(TARGET_ARCH_VARIANT).c
+ *
+ */
+
+/*
+ * Alloc a pair of core registers, or a double. Low reg in low byte,
+ * high reg in next byte.
+ */
+int oatAllocTypedTempPair(CompilationUnit *cUnit, bool fpHint,
+ int regClass)
+{
+ int highReg;
+ int lowReg;
+ int res = 0;
+
+#ifdef __mips_hard_float
+ if (((regClass == kAnyReg) && fpHint) || (regClass == kFPReg)) {
+ lowReg = oatAllocTempDouble(cUnit);
+ highReg = lowReg + 1;
+ res = (lowReg & 0xff) | ((highReg & 0xff) << 8);
+ return res;
+ }
+#endif
+
+ lowReg = oatAllocTemp(cUnit);
+ highReg = oatAllocTemp(cUnit);
+ res = (lowReg & 0xff) | ((highReg & 0xff) << 8);
+ return res;
+}
+
+int oatAllocTypedTemp(CompilationUnit *cUnit, bool fpHint, int regClass)
+{
+#ifdef __mips_hard_float
+ if (((regClass == kAnyReg) && fpHint) || (regClass == kFPReg))
+{
+ return oatAllocTempFloat(cUnit);
+}
+#endif
+ return oatAllocTemp(cUnit);
+}
+
+} // namespace art