diff options
| author | Raghu Gandham <raghu@mips.com> | 2012-05-02 14:27:16 -0700 |
|---|---|---|
| committer | Raghu Gandham <raghu@mips.com> | 2012-05-02 14:27:16 -0700 |
| commit | a8b91c52fd8a90b784835dfe1f8898035266c4dd (patch) | |
| tree | 8a9bb58ee3b78c10cf88a3bac21b7f96d75cd1f7 /vm/compiler/codegen/mips/Mips32/Factory.cpp | |
| parent | a14639df65cc0aefafcddda5aae8b591204e45f9 (diff) | |
[MIPS] Dalvik fast interpreter support and JIT implementation
Change-Id: I9bb4f6875b7061d3ffaee73f204026cb8ba3ed39
Signed-off-by: Raghu Gandham <raghu@mips.com>
Signed-off-by: Chris Dearman <chris@mips.com>
Signed-off-by: Douglas Leung <douglas@mips.com>
Signed-off-by: Don Padgett <don@mips.com>
Diffstat (limited to 'vm/compiler/codegen/mips/Mips32/Factory.cpp')
| -rw-r--r-- | vm/compiler/codegen/mips/Mips32/Factory.cpp | 1015 |
1 files changed, 1015 insertions, 0 deletions
diff --git a/vm/compiler/codegen/mips/Mips32/Factory.cpp b/vm/compiler/codegen/mips/Mips32/Factory.cpp new file mode 100644 index 000000000..9a158b46b --- /dev/null +++ b/vm/compiler/codegen/mips/Mips32/Factory.cpp @@ -0,0 +1,1015 @@ +/* + * Copyright (C) 2009 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 Thumb ISA and is intended to be + * includes by: + * + * Codegen-$(TARGET_ARCH_VARIANT).c + * + */ + +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, r_S0, r_S4}; +#ifdef __mips_hard_float +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 *) dvmCompilerNew(sizeof(MipsLIR), true); + res->operands[0] = rDest; + res->operands[1] = rSrc; + if (rDest == rSrc) { + res->flags.isNop = true; + } else { + /* must be both DOUBLE or both not DOUBLE */ + assert(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 { + assert(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 dvmCompilerAllocTemp 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) { + assert(SINGLEREG(rDest)); + rDest = dvmCompilerAllocTemp(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); + dvmCompilerFreeTemp(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 (dvmCompilerIsTemp(cUnit, rDest)) { + dvmCompilerClobber(cUnit, rDest); + dvmCompilerMarkInUse(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 (dvmCompilerIsTemp(cUnit, rDest)) { + dvmCompilerClobber(cUnit, rDest); + dvmCompilerMarkInUse(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: + LOGE("Jit: bad case in opNone"); + dvmCompilerAbort(cUnit); + } + res = newLIR0(cUnit, opcode); + return res; +} + +static MipsLIR *opCompareBranch(CompilationUnit *cUnit, MipsOpCode opc, int rs, int rt) +{ + MipsLIR *res; + if (rt < 0) { + assert(opc >= kMipsBeqz && opc <= kMipsBnez); + res = newLIR1(cUnit, opc, rs); + } else { + assert(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: + assert(0); + } + return newLIR2(cUnit, opcode, r_RA, rDestSrc); +} + +static MipsLIR *opRegRegImm(CompilationUnit *cUnit, OpKind op, int rDest, + int rSrc1, int value); +static 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: + LOGE("Jit: bad case in opRegImm"); + dvmCompilerAbort(cUnit); + break; + } + if (shortForm) + res = newLIR2(cUnit, opcode, rDestSrc1, absValue); + else { + int rScratch = dvmCompilerAllocTemp(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: + LOGE("Jit: bad case in opRegRegReg"); + dvmCompilerAbort(cUnit); + 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: + assert(value >= 0 && value <= 31); + opcode = kMipsSll; + break; + case kOpLsr: + assert(value >= 0 && value <= 31); + opcode = kMipsSrl; + break; + case kOpAsr: + assert(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: + LOGE("Jit: bad case in opRegRegImm"); + dvmCompilerAbort(cUnit); + 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 = dvmCompilerAllocTemp(cUnit); + res = loadConstant(cUnit, rScratch, value); + newLIR3(cUnit, opcode, rDest, rSrc1, rScratch); + } + } + return res; +} + +static 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: + LOGE("Jit: bad case in opRegReg"); + dvmCompilerAbort(cUnit); + 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 = dvmCompilerAllocTemp(cUnit); + +#ifdef __mips_hard_float + if (FPREG(rDest)) { + assert(SINGLEREG(rDest)); + assert((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: + LOGE("Jit: bad case in loadBaseIndexed"); + dvmCompilerAbort(cUnit); + } + + res = newLIR3(cUnit, opcode, rDest, 0, tReg); +#if defined(WITH_SELF_VERIFICATION) + if (cUnit->heapMemOp) + res->flags.insertWrapper = true; +#endif + dvmCompilerFreeTemp(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 = dvmCompilerAllocTemp(cUnit); + +#ifdef __mips_hard_float + if (FPREG(rSrc)) { + assert(SINGLEREG(rSrc)); + assert((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: + LOGE("Jit: bad case in storeBaseIndexed"); + dvmCompilerAbort(cUnit); + } + res = newLIR3(cUnit, opcode, rSrc, 0, tReg); +#if defined(WITH_SELF_VERIFICATION) + if (cUnit->heapMemOp) + res->flags.insertWrapper = true; +#endif + dvmCompilerFreeTemp(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); + } + +#if defined(WITH_SELF_VERIFICATION) + if (cUnit->heapMemOp) + res->flags.insertWrapper = true; +#endif + 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); + } + +#if defined(WITH_SELF_VERIFICATION) + if (cUnit->heapMemOp) + res->flags.insertWrapper = true; +#endif + 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 { + assert(FPREG(rDestHi)); + assert(rDest == (rDestHi - 1)); + } + rDestHi = rDest + 1; + } +#endif + shortForm = IS_SIMM16_2WORD(displacement); + assert((displacement & 0x3) == 0); + break; + case kWord: + case kSingle: + opcode = kMipsLw; +#ifdef __mips_hard_float + if (FPREG(rDest)) { + opcode = kMipsFlwc1; + assert(SINGLEREG(rDest)); + } +#endif + assert((displacement & 0x3) == 0); + break; + case kUnsignedHalf: + opcode = kMipsLhu; + assert((displacement & 0x1) == 0); + break; + case kSignedHalf: + opcode = kMipsLh; + assert((displacement & 0x1) == 0); + break; + case kUnsignedByte: + opcode = kMipsLbu; + break; + case kSignedByte: + opcode = kMipsLb; + break; + default: + LOGE("Jit: bad case in loadBaseIndexedBody"); + dvmCompilerAbort(cUnit); + } + + 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 = dvmCompilerAllocFreeTemp(cUnit); + res = opRegRegImm(cUnit, kOpAdd, rTmp, rBase, displacement); + load = newLIR3(cUnit, opcode, rDest, LOWORD_OFFSET, rTmp); + load2 = newLIR3(cUnit, opcode, rDestHi, HIWORD_OFFSET, rTmp); + dvmCompilerFreeTemp(cUnit, rTmp); + } else { + int rTmp = (rBase == rDest) ? dvmCompilerAllocFreeTemp(cUnit) + : rDest; + res = loadConstant(cUnit, rTmp, displacement); + load = newLIR3(cUnit, opcode, rDest, rBase, rTmp); + if (rTmp != rDest) + dvmCompilerFreeTemp(cUnit, rTmp); + } + } + + 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 */); + } +#if defined(WITH_SELF_VERIFICATION) + if (load != NULL && cUnit->heapMemOp) + load->flags.insertWrapper = true; + if (load2 != NULL && cUnit->heapMemOp) + load2->flags.insertWrapper = true; +#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 { + assert(FPREG(rSrcHi)); + assert(rSrc == (rSrcHi - 1)); + } + rSrcHi = rSrc + 1; + } +#endif + shortForm = IS_SIMM16_2WORD(displacement); + assert((displacement & 0x3) == 0); + break; + case kWord: + case kSingle: + opcode = kMipsSw; +#ifdef __mips_hard_float + if (FPREG(rSrc)) { + opcode = kMipsFswc1; + assert(SINGLEREG(rSrc)); + } +#endif + assert((displacement & 0x3) == 0); + break; + case kUnsignedHalf: + case kSignedHalf: + opcode = kMipsSh; + assert((displacement & 0x1) == 0); + break; + case kUnsignedByte: + case kSignedByte: + opcode = kMipsSb; + break; + default: + LOGE("Jit: bad case in storeBaseIndexedBody"); + dvmCompilerAbort(cUnit); + } + + 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 = dvmCompilerAllocTemp(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); + } + dvmCompilerFreeTemp(cUnit, rScratch); + } + + 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 */); + } + +#if defined(WITH_SELF_VERIFICATION) + if (store != NULL && cUnit->heapMemOp) + store->flags.insertWrapper = true; + if (store2 != NULL && cUnit->heapMemOp) + store2->flags.insertWrapper = true; +#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 *) dvmCompilerNew(sizeof(MipsLIR), true); + opcode = kMipsMove; + assert(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); + dvmCompilerAppendLIR(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); + assert(FPREG(srcLo) == FPREG(srcHi)); + assert(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 { + LOGE("Jit: bad case in genRegImmCheck"); + dvmCompilerAbort(cUnit); + } + branch = opCompareBranch(cUnit, opc, reg, -1); + } else if (IS_SIMM16(checkValue)) { + if (cond == kMipsCondLt) { + int tReg = dvmCompilerAllocTemp(cUnit); + newLIR3(cUnit, kMipsSlti, tReg, reg, checkValue); + branch = opCompareBranch(cUnit, kMipsBne, tReg, r_ZERO); + dvmCompilerFreeTemp(cUnit, tReg); + } else { + LOGE("Jit: bad case in genRegImmCheck"); + dvmCompilerAbort(cUnit); + } + } else { + LOGE("Jit: bad case in genRegImmCheck"); + dvmCompilerAbort(cUnit); + } + + 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 { + LOGE("Catch blocks not handled yet"); + dvmAbort(); + return NULL; + } + } else { + return genCheckCommon(cUnit, dOffset, branch, pcrLabel); + } +} + +#if defined(WITH_SELF_VERIFICATION) +static void genSelfVerificationPreBranch(CompilationUnit *cUnit, + MipsLIR *origLIR) { +// DOUGLAS - this still needs to be implemented for MIPS. +#if 0 + /* + * We need two separate pushes, since we want r5 to be pushed first. + * Store multiple will push LR first. + */ + MipsLIR *pushFP = (MipsLIR *) dvmCompilerNew(sizeof(MipsLIR), true); + pushFP->opcode = kThumbPush; + pushFP->operands[0] = 1 << r5FP; + setupResourceMasks(pushFP); + dvmCompilerInsertLIRBefore((LIR *) origLIR, (LIR *) pushFP); + + MipsLIR *pushLR = (MipsLIR *) dvmCompilerNew(sizeof(MipsLIR), true); + pushLR->opcode = kThumbPush; + /* Thumb push can handle LR, but is encoded differently at bit 8 */ + pushLR->operands[0] = 1 << 8; + setupResourceMasks(pushLR); + dvmCompilerInsertLIRBefore((LIR *) origLIR, (LIR *) pushLR); +#endif +} + +static void genSelfVerificationPostBranch(CompilationUnit *cUnit, + MipsLIR *origLIR) { +// DOUGLAS - this still needs to be implemented for MIPS. +#if 0 + /* + * Since Thumb cannot pop memory content into LR, we have to pop LR + * to a temp first (r5 in this case). Then we move r5 to LR, then pop the + * original r5 from stack. + */ + /* Pop memory content(LR) into r5 first */ + MipsLIR *popForLR = (MipsLIR *) dvmCompilerNew(sizeof(MipsLIR), true); + popForLR->opcode = kThumbPop; + popForLR->operands[0] = 1 << r5FP; + setupResourceMasks(popForLR); + dvmCompilerInsertLIRAfter((LIR *) origLIR, (LIR *) popForLR); + + MipsLIR *copy = genRegCopyNoInsert(cUnit, r14lr, r5FP); + dvmCompilerInsertLIRAfter((LIR *) popForLR, (LIR *) copy); + + /* Now restore the original r5 */ + MipsLIR *popFP = (MipsLIR *) dvmCompilerNew(sizeof(MipsLIR), true); + popFP->opcode = kThumbPop; + popFP->operands[0] = 1 << r5FP; + setupResourceMasks(popFP); + dvmCompilerInsertLIRAfter((LIR *) copy, (LIR *) popFP); +#endif +} +#endif |
