diff options
Diffstat (limited to 'vm/compiler/codegen/arm/Thumb/Factory.cpp')
| -rw-r--r-- | vm/compiler/codegen/arm/Thumb/Factory.cpp | 914 |
1 files changed, 914 insertions, 0 deletions
diff --git a/vm/compiler/codegen/arm/Thumb/Factory.cpp b/vm/compiler/codegen/arm/Thumb/Factory.cpp new file mode 100644 index 000000000..7b51df160 --- /dev/null +++ b/vm/compiler/codegen/arm/Thumb/Factory.cpp @@ -0,0 +1,914 @@ +/* + * 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[] = {r0, r1, r2, r3, r4PC, r7}; + +static void storePair(CompilationUnit *cUnit, int base, int lowReg, + int highReg); +static void loadPair(CompilationUnit *cUnit, int base, int lowReg, int highReg); +static ArmLIR *loadWordDisp(CompilationUnit *cUnit, int rBase, int displacement, + int rDest); +static ArmLIR *storeWordDisp(CompilationUnit *cUnit, int rBase, + int displacement, int rSrc); +static ArmLIR *genRegRegCheck(CompilationUnit *cUnit, + ArmConditionCode cond, + int reg1, int reg2, int dOffset, + ArmLIR *pcrLabel); + + +/* + * 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 ArmLIR *loadConstantNoClobber(CompilationUnit *cUnit, int rDest, + int value) +{ + ArmLIR *res; + int tDest = LOWREG(rDest) ? rDest : dvmCompilerAllocTemp(cUnit); + /* See if the value can be constructed cheaply */ + if ((value >= 0) && (value <= 255)) { + res = newLIR2(cUnit, kThumbMovImm, tDest, value); + if (rDest != tDest) { + opRegReg(cUnit, kOpMov, rDest, tDest); + dvmCompilerFreeTemp(cUnit, tDest); + } + return res; + } else if ((value & 0xFFFFFF00) == 0xFFFFFF00) { + res = newLIR2(cUnit, kThumbMovImm, tDest, ~value); + newLIR2(cUnit, kThumbMvn, tDest, tDest); + if (rDest != tDest) { + opRegReg(cUnit, kOpMov, rDest, tDest); + dvmCompilerFreeTemp(cUnit, tDest); + } + return res; + } + /* No shortcut - go ahead and use literal pool */ + ArmLIR *dataTarget = scanLiteralPool(cUnit->literalList, value, 255); + if (dataTarget == NULL) { + dataTarget = addWordData(cUnit, &cUnit->literalList, value); + } + ArmLIR *loadPcRel = (ArmLIR *) dvmCompilerNew(sizeof(ArmLIR), true); + loadPcRel->opcode = kThumbLdrPcRel; + loadPcRel->generic.target = (LIR *) dataTarget; + loadPcRel->operands[0] = tDest; + setupResourceMasks(loadPcRel); + setMemRefType(loadPcRel, true, kLiteral); + loadPcRel->aliasInfo = dataTarget->operands[0]; + res = loadPcRel; + dvmCompilerAppendLIR(cUnit, (LIR *) loadPcRel); + + /* + * To save space in the constant pool, we use the ADD_RRI8 instruction to + * add up to 255 to an existing constant value. + */ + if (dataTarget->operands[0] != value) { + newLIR2(cUnit, kThumbAddRI8, tDest, value - dataTarget->operands[0]); + } + if (rDest != tDest) { + opRegReg(cUnit, kOpMov, rDest, tDest); + dvmCompilerFreeTemp(cUnit, tDest); + } + return res; +} + +/* + * Load an immediate value into a fixed or temp register. Target + * register is clobbered, and marked inUse. + */ +static ArmLIR *loadConstant(CompilationUnit *cUnit, int rDest, int value) +{ + if (dvmCompilerIsTemp(cUnit, rDest)) { + dvmCompilerClobber(cUnit, rDest); + dvmCompilerMarkInUse(cUnit, rDest); + } + return loadConstantNoClobber(cUnit, rDest, value); +} + +static ArmLIR *opNone(CompilationUnit *cUnit, OpKind op) +{ + ArmOpcode opcode = kThumbBkpt; + switch (op) { + case kOpUncondBr: + opcode = kThumbBUncond; + break; + default: + LOGE("Jit: bad case in opNone"); + dvmCompilerAbort(cUnit); + } + return newLIR0(cUnit, opcode); +} + +static ArmLIR *opCondBranch(CompilationUnit *cUnit, ArmConditionCode cc) +{ + return newLIR2(cUnit, kThumbBCond, 0 /* offset to be patched */, cc); +} + +static ArmLIR *opImm(CompilationUnit *cUnit, OpKind op, int value) +{ + ArmOpcode opcode = kThumbBkpt; + switch (op) { + case kOpPush: + opcode = kThumbPush; + break; + case kOpPop: + opcode = kThumbPop; + break; + default: + LOGE("Jit: bad case in opCondBranch"); + dvmCompilerAbort(cUnit); + } + return newLIR1(cUnit, opcode, value); +} + +static ArmLIR *opReg(CompilationUnit *cUnit, OpKind op, int rDestSrc) +{ + ArmOpcode opcode = kThumbBkpt; + switch (op) { + case kOpBlx: + opcode = kThumbBlxR; + break; + default: + LOGE("Jit: bad case in opReg"); + dvmCompilerAbort(cUnit); + } + return newLIR1(cUnit, opcode, rDestSrc); +} + +static ArmLIR *opRegImm(CompilationUnit *cUnit, OpKind op, int rDestSrc1, + int value) +{ + ArmLIR *res; + bool neg = (value < 0); + int absValue = (neg) ? -value : value; + bool shortForm = (absValue & 0xff) == absValue; + ArmOpcode opcode = kThumbBkpt; + switch (op) { + case kOpAdd: + if ( !neg && (rDestSrc1 == r13sp) && (value <= 508)) { /* sp */ + assert((value & 0x3) == 0); + return newLIR1(cUnit, kThumbAddSpI7, value >> 2); + } else if (shortForm) { + opcode = (neg) ? kThumbSubRI8 : kThumbAddRI8; + } else + opcode = kThumbAddRRR; + break; + case kOpSub: + if (!neg && (rDestSrc1 == r13sp) && (value <= 508)) { /* sp */ + assert((value & 0x3) == 0); + return newLIR1(cUnit, kThumbSubSpI7, value >> 2); + } else if (shortForm) { + opcode = (neg) ? kThumbAddRI8 : kThumbSubRI8; + } else + opcode = kThumbSubRRR; + break; + case kOpCmp: + if (neg) + shortForm = false; + if (LOWREG(rDestSrc1) && shortForm) { + opcode = kThumbCmpRI8; + } else if (LOWREG(rDestSrc1)) { + opcode = kThumbCmpRR; + } else { + shortForm = false; + opcode = kThumbCmpHL; + } + 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 ArmLIR *opRegRegReg(CompilationUnit *cUnit, OpKind op, int rDest, + int rSrc1, int rSrc2) +{ + ArmOpcode opcode = kThumbBkpt; + switch (op) { + case kOpAdd: + opcode = kThumbAddRRR; + break; + case kOpSub: + opcode = kThumbSubRRR; + break; + default: + if (rDest == rSrc1) { + return opRegReg(cUnit, op, rDest, rSrc2); + } else if (rDest == rSrc2) { + assert(dvmCompilerIsTemp(cUnit, rSrc1)); + dvmCompilerClobber(cUnit, rSrc1); + opRegReg(cUnit, op, rSrc1, rSrc2); + return opRegReg(cUnit, kOpMov, rDest, rSrc1); + } else { + opRegReg(cUnit, kOpMov, rDest, rSrc1); + return opRegReg(cUnit, op, rDest, rSrc2); + } + break; + } + return newLIR3(cUnit, opcode, rDest, rSrc1, rSrc2); +} + +static ArmLIR *opRegRegImm(CompilationUnit *cUnit, OpKind op, int rDest, + int rSrc1, int value) +{ + ArmLIR *res; + bool neg = (value < 0); + int absValue = (neg) ? -value : value; + ArmOpcode opcode = kThumbBkpt; + bool shortForm = (absValue & 0x7) == absValue; + switch(op) { + case kOpAdd: + if (rDest == rSrc1) + return opRegImm(cUnit, op, rDest, value); + if ((rSrc1 == r13sp) && (value <= 1020)) { /* sp */ + assert((value & 0x3) == 0); + shortForm = true; + opcode = kThumbAddSpRel; + value >>= 2; + } else if ((rSrc1 == r15pc) && (value <= 1020)) { /* pc */ + assert((value & 0x3) == 0); + shortForm = true; + opcode = kThumbAddPcRel; + value >>= 2; + } else if (shortForm) { + opcode = (neg) ? kThumbSubRRI3 : kThumbAddRRI3; + } else if ((absValue > 0) && (absValue <= (255 + 7))) { + /* Two shots - 1st handle the 7 */ + opcode = (neg) ? kThumbSubRRI3 : kThumbAddRRI3; + res = newLIR3(cUnit, opcode, rDest, rSrc1, 7); + opcode = (neg) ? kThumbSubRI8 : kThumbAddRI8; + newLIR2(cUnit, opcode, rDest, absValue - 7); + return res; + } else + opcode = kThumbAddRRR; + break; + + case kOpSub: + if (rDest == rSrc1) + return opRegImm(cUnit, op, rDest, value); + if (shortForm) { + opcode = (neg) ? kThumbAddRRI3 : kThumbSubRRI3; + } else if ((absValue > 0) && (absValue <= (255 + 7))) { + /* Two shots - 1st handle the 7 */ + opcode = (neg) ? kThumbAddRRI3 : kThumbSubRRI3; + res = newLIR3(cUnit, opcode, rDest, rSrc1, 7); + opcode = (neg) ? kThumbAddRI8 : kThumbSubRI8; + newLIR2(cUnit, opcode, rDest, absValue - 7); + return res; + } else + opcode = kThumbSubRRR; + break; + case kOpLsl: + shortForm = (!neg && value <= 31); + opcode = kThumbLslRRI5; + break; + case kOpLsr: + shortForm = (!neg && value <= 31); + opcode = kThumbLsrRRI5; + break; + case kOpAsr: + shortForm = (!neg && value <= 31); + opcode = kThumbAsrRRI5; + break; + case kOpMul: + case kOpAnd: + case kOpOr: + case kOpXor: + if (rDest == rSrc1) { + int rScratch = dvmCompilerAllocTemp(cUnit); + res = loadConstant(cUnit, rScratch, value); + opRegReg(cUnit, op, rDest, rScratch); + } else { + res = loadConstant(cUnit, rDest, value); + opRegReg(cUnit, op, rDest, rSrc1); + } + return res; + default: + LOGE("Jit: bad case in opRegRegImm"); + dvmCompilerAbort(cUnit); + break; + } + if (shortForm) + res = newLIR3(cUnit, opcode, rDest, rSrc1, absValue); + 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 ArmLIR *opRegReg(CompilationUnit *cUnit, OpKind op, int rDestSrc1, + int rSrc2) +{ + ArmLIR *res; + ArmOpcode opcode = kThumbBkpt; + switch (op) { + case kOpAdc: + opcode = kThumbAdcRR; + break; + case kOpAnd: + opcode = kThumbAndRR; + break; + case kOpBic: + opcode = kThumbBicRR; + break; + case kOpCmn: + opcode = kThumbCmnRR; + break; + case kOpCmp: + opcode = kThumbCmpRR; + break; + case kOpXor: + opcode = kThumbEorRR; + break; + case kOpMov: + if (LOWREG(rDestSrc1) && LOWREG(rSrc2)) + opcode = kThumbMovRR; + else if (!LOWREG(rDestSrc1) && !LOWREG(rSrc2)) + opcode = kThumbMovRR_H2H; + else if (LOWREG(rDestSrc1)) + opcode = kThumbMovRR_H2L; + else + opcode = kThumbMovRR_L2H; + break; + case kOpMul: + opcode = kThumbMul; + break; + case kOpMvn: + opcode = kThumbMvn; + break; + case kOpNeg: + opcode = kThumbNeg; + break; + case kOpOr: + opcode = kThumbOrr; + break; + case kOpSbc: + opcode = kThumbSbc; + break; + case kOpTst: + opcode = kThumbTst; + break; + case kOpLsl: + opcode = kThumbLslRR; + break; + case kOpLsr: + opcode = kThumbLsrRR; + break; + case kOpAsr: + opcode = kThumbAsrRR; + break; + case kOpRor: + opcode = kThumbRorRR; + case kOpAdd: + case kOpSub: + return opRegRegReg(cUnit, op, rDestSrc1, rDestSrc1, rSrc2); + case kOp2Byte: + res = opRegRegImm(cUnit, kOpLsl, rDestSrc1, rSrc2, 24); + opRegRegImm(cUnit, kOpAsr, rDestSrc1, rDestSrc1, 24); + return res; + case kOp2Short: + res = opRegRegImm(cUnit, kOpLsl, rDestSrc1, rSrc2, 16); + opRegRegImm(cUnit, kOpAsr, rDestSrc1, rDestSrc1, 16); + return res; + case kOp2Char: + res = opRegRegImm(cUnit, kOpLsl, rDestSrc1, rSrc2, 16); + opRegRegImm(cUnit, kOpLsr, rDestSrc1, rDestSrc1, 16); + return res; + default: + LOGE("Jit: bad case in opRegReg"); + dvmCompilerAbort(cUnit); + break; + } + return newLIR2(cUnit, opcode, rDestSrc1, rSrc2); +} + +static ArmLIR *loadConstantValueWide(CompilationUnit *cUnit, int rDestLo, + int rDestHi, int valLo, int valHi) +{ + ArmLIR *res; + res = loadConstantNoClobber(cUnit, rDestLo, valLo); + loadConstantNoClobber(cUnit, rDestHi, valHi); + return res; +} + +/* Load value from base + scaled index. */ +static ArmLIR *loadBaseIndexed(CompilationUnit *cUnit, int rBase, + int rIndex, int rDest, int scale, OpSize size) +{ + ArmLIR *first = NULL; + ArmLIR *res; + ArmOpcode opcode = kThumbBkpt; + int rNewIndex = rIndex; + if (scale) { + // Scale the index, but can't trash the original. + rNewIndex = dvmCompilerAllocTemp(cUnit); + first = opRegRegImm(cUnit, kOpLsl, rNewIndex, rIndex, scale); + } + switch (size) { + case kWord: + opcode = kThumbLdrRRR; + break; + case kUnsignedHalf: + opcode = kThumbLdrhRRR; + break; + case kSignedHalf: + opcode = kThumbLdrshRRR; + break; + case kUnsignedByte: + opcode = kThumbLdrbRRR; + break; + case kSignedByte: + opcode = kThumbLdrsbRRR; + break; + default: + LOGE("Jit: bad case in loadBaseIndexed"); + dvmCompilerAbort(cUnit); + } + res = newLIR3(cUnit, opcode, rDest, rBase, rNewIndex); +#if defined(WITH_SELF_VERIFICATION) + if (cUnit->heapMemOp) + res->flags.insertWrapper = true; +#endif + if (scale) + dvmCompilerFreeTemp(cUnit, rNewIndex); + return (first) ? first : res; +} + +/* store value base base + scaled index. */ +static ArmLIR *storeBaseIndexed(CompilationUnit *cUnit, int rBase, + int rIndex, int rSrc, int scale, OpSize size) +{ + ArmLIR *first = NULL; + ArmLIR *res; + ArmOpcode opcode = kThumbBkpt; + int rNewIndex = rIndex; + if (scale) { + rNewIndex = dvmCompilerAllocTemp(cUnit); + first = opRegRegImm(cUnit, kOpLsl, rNewIndex, rIndex, scale); + } + switch (size) { + case kWord: + opcode = kThumbStrRRR; + break; + case kUnsignedHalf: + case kSignedHalf: + opcode = kThumbStrhRRR; + break; + case kUnsignedByte: + case kSignedByte: + opcode = kThumbStrbRRR; + break; + default: + LOGE("Jit: bad case in storeBaseIndexed"); + dvmCompilerAbort(cUnit); + } + res = newLIR3(cUnit, opcode, rSrc, rBase, rNewIndex); +#if defined(WITH_SELF_VERIFICATION) + if (cUnit->heapMemOp) + res->flags.insertWrapper = true; +#endif + if (scale) + dvmCompilerFreeTemp(cUnit, rNewIndex); + return (first) ? first : res; +} + +static ArmLIR *loadMultiple(CompilationUnit *cUnit, int rBase, int rMask) +{ + ArmLIR *res; + genBarrier(cUnit); + res = newLIR2(cUnit, kThumbLdmia, rBase, rMask); +#if defined(WITH_SELF_VERIFICATION) + if (cUnit->heapMemOp) + res->flags.insertWrapper = true; +#endif + genBarrier(cUnit); + return res; +} + +static ArmLIR *storeMultiple(CompilationUnit *cUnit, int rBase, int rMask) +{ + ArmLIR *res; + genBarrier(cUnit); + res = newLIR2(cUnit, kThumbStmia, rBase, rMask); +#if defined(WITH_SELF_VERIFICATION) + if (cUnit->heapMemOp) + res->flags.insertWrapper = true; +#endif + genBarrier(cUnit); + return res; +} + +static ArmLIR *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. + */ +{ + ArmLIR *res; + ArmLIR *load = NULL; + ArmLIR *load2 = NULL; + ArmOpcode opcode = kThumbBkpt; + bool shortForm = false; + int encodedDisp = displacement; + bool pair = false; + + switch (size) { + case kLong: + case kDouble: + pair = true; + if ((displacement < 124) && (displacement >= 0)) { + assert((displacement & 0x3) == 0); + shortForm = true; + encodedDisp >>= 2; + opcode = kThumbLdrRRI5; + } else { + opcode = kThumbLdrRRR; + } + break; + case kWord: + if (LOWREG(rDest) && (rBase == r15pc) && + (displacement <= 1020) && (displacement >= 0)) { + shortForm = true; + encodedDisp >>= 2; + opcode = kThumbLdrPcRel; + } else if (LOWREG(rDest) && (rBase == r13sp) && + (displacement <= 1020) && (displacement >= 0)) { + shortForm = true; + encodedDisp >>= 2; + opcode = kThumbLdrSpRel; + } else if (displacement < 128 && displacement >= 0) { + assert((displacement & 0x3) == 0); + shortForm = true; + encodedDisp >>= 2; + opcode = kThumbLdrRRI5; + } else { + opcode = kThumbLdrRRR; + } + break; + case kUnsignedHalf: + if (displacement < 64 && displacement >= 0) { + assert((displacement & 0x1) == 0); + shortForm = true; + encodedDisp >>= 1; + opcode = kThumbLdrhRRI5; + } else { + opcode = kThumbLdrhRRR; + } + break; + case kSignedHalf: + opcode = kThumbLdrshRRR; + break; + case kUnsignedByte: + if (displacement < 32 && displacement >= 0) { + shortForm = true; + opcode = kThumbLdrbRRI5; + } else { + opcode = kThumbLdrbRRR; + } + break; + case kSignedByte: + opcode = kThumbLdrsbRRR; + break; + default: + LOGE("Jit: bad case in loadBaseIndexedBody"); + dvmCompilerAbort(cUnit); + } + if (shortForm) { + load = res = newLIR3(cUnit, opcode, rDest, rBase, encodedDisp); + if (pair) { + load2 = newLIR3(cUnit, opcode, rDestHi, rBase, encodedDisp+1); + } + } else { + if (pair) { + int rTmp = dvmCompilerAllocFreeTemp(cUnit); + res = opRegRegImm(cUnit, kOpAdd, rTmp, rBase, displacement); + load = newLIR3(cUnit, kThumbLdrRRI5, rDest, rTmp, 0); + load2 = newLIR3(cUnit, kThumbLdrRRI5, rDestHi, rTmp, 1); + dvmCompilerFreeTemp(cUnit, rTmp); + } else { + int rTmp = (rBase == rDest) ? dvmCompilerAllocFreeTemp(cUnit) + : rDest; + res = loadConstant(cUnit, rTmp, displacement); + load = newLIR3(cUnit, opcode, rDest, rBase, rTmp); + if (rBase == r5FP) + annotateDalvikRegAccess(load, displacement >> 2, + true /* isLoad */); + if (rTmp != rDest) + dvmCompilerFreeTemp(cUnit, rTmp); + } + } + if (rBase == r5FP) { + if (load != NULL) + annotateDalvikRegAccess(load, displacement >> 2, + true /* isLoad */); + if (load2 != NULL) + annotateDalvikRegAccess(load2, (displacement >> 2) + 1, + 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 res; +} + +static ArmLIR *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 ArmLIR *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 ArmLIR *storeBaseDispBody(CompilationUnit *cUnit, int rBase, + int displacement, int rSrc, int rSrcHi, + OpSize size) +{ + ArmLIR *res; + ArmLIR *store = NULL; + ArmLIR *store2 = NULL; + ArmOpcode opcode = kThumbBkpt; + bool shortForm = false; + int encodedDisp = displacement; + bool pair = false; + + switch (size) { + case kLong: + case kDouble: + pair = true; + if ((displacement < 124) && (displacement >= 0)) { + assert((displacement & 0x3) == 0); + pair = true; + shortForm = true; + encodedDisp >>= 2; + opcode = kThumbStrRRI5; + } else { + opcode = kThumbStrRRR; + } + break; + case kWord: + if (displacement < 128 && displacement >= 0) { + assert((displacement & 0x3) == 0); + shortForm = true; + encodedDisp >>= 2; + opcode = kThumbStrRRI5; + } else { + opcode = kThumbStrRRR; + } + break; + case kUnsignedHalf: + case kSignedHalf: + if (displacement < 64 && displacement >= 0) { + assert((displacement & 0x1) == 0); + shortForm = true; + encodedDisp >>= 1; + opcode = kThumbStrhRRI5; + } else { + opcode = kThumbStrhRRR; + } + break; + case kUnsignedByte: + case kSignedByte: + if (displacement < 32 && displacement >= 0) { + shortForm = true; + opcode = kThumbStrbRRI5; + } else { + opcode = kThumbStrbRRR; + } + break; + default: + LOGE("Jit: bad case in storeBaseIndexedBody"); + dvmCompilerAbort(cUnit); + } + if (shortForm) { + store = res = newLIR3(cUnit, opcode, rSrc, rBase, encodedDisp); + if (pair) { + store2 = newLIR3(cUnit, opcode, rSrcHi, rBase, encodedDisp + 1); + } + } else { + int rScratch = dvmCompilerAllocTemp(cUnit); + if (pair) { + res = opRegRegImm(cUnit, kOpAdd, rScratch, rBase, displacement); + store = newLIR3(cUnit, kThumbStrRRI5, rSrc, rScratch, 0); + store2 = newLIR3(cUnit, kThumbStrRRI5, rSrcHi, rScratch, 1); + } else { + res = loadConstant(cUnit, rScratch, displacement); + store = newLIR3(cUnit, opcode, rSrc, rBase, rScratch); + } + dvmCompilerFreeTemp(cUnit, rScratch); + } + if (rBase == r5FP) { + if (store != NULL) + annotateDalvikRegAccess(store, displacement >> 2, + false /* isLoad */); + if (store2 != NULL) + annotateDalvikRegAccess(store2, (displacement >> 2) + 1, + 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 ArmLIR *storeBaseDisp(CompilationUnit *cUnit, int rBase, + int displacement, int rSrc, OpSize size) +{ + return storeBaseDispBody(cUnit, rBase, displacement, rSrc, -1, size); +} + +static ArmLIR *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) +{ + if (lowReg < highReg) { + storeMultiple(cUnit, base, (1 << lowReg) | (1 << highReg)); + } else { + storeWordDisp(cUnit, base, 0, lowReg); + storeWordDisp(cUnit, base, 4, highReg); + } +} + +static void loadPair(CompilationUnit *cUnit, int base, int lowReg, int highReg) +{ + if (lowReg < highReg) { + loadMultiple(cUnit, base, (1 << lowReg) | (1 << highReg)); + } else { + loadWordDisp(cUnit, base, 0 , lowReg); + loadWordDisp(cUnit, base, 4 , highReg); + } +} + +static ArmLIR* genRegCopyNoInsert(CompilationUnit *cUnit, int rDest, int rSrc) +{ + ArmLIR* res; + ArmOpcode opcode; + res = (ArmLIR *) dvmCompilerNew(sizeof(ArmLIR), true); + if (LOWREG(rDest) && LOWREG(rSrc)) + opcode = kThumbMovRR; + else if (!LOWREG(rDest) && !LOWREG(rSrc)) + opcode = kThumbMovRR_H2H; + else if (LOWREG(rDest)) + opcode = kThumbMovRR_H2L; + else + opcode = kThumbMovRR_L2H; + + res->operands[0] = rDest; + res->operands[1] = rSrc; + res->opcode = opcode; + setupResourceMasks(res); + if (rDest == rSrc) { + res->flags.isNop = true; + } + return res; +} + +static ArmLIR* genRegCopy(CompilationUnit *cUnit, int rDest, int rSrc) +{ + ArmLIR *res = genRegCopyNoInsert(cUnit, rDest, rSrc); + dvmCompilerAppendLIR(cUnit, (LIR*)res); + return res; +} + +static void genRegCopyWide(CompilationUnit *cUnit, int destLo, int destHi, + int srcLo, int srcHi) +{ + // Handle overlap + if (srcHi == destLo) { + genRegCopy(cUnit, destHi, srcHi); + genRegCopy(cUnit, destLo, srcLo); + } else { + genRegCopy(cUnit, destLo, srcLo); + genRegCopy(cUnit, destHi, srcHi); + } +} + +static ArmLIR *genCmpImmBranch(CompilationUnit *cUnit, + ArmConditionCode cond, int reg, + int checkValue) +{ + if ((checkValue & 0xff) != checkValue) { + int tReg = dvmCompilerAllocTemp(cUnit); + loadConstant(cUnit, tReg, checkValue); + newLIR2(cUnit, kThumbCmpRR, reg, tReg); + dvmCompilerFreeTemp(cUnit, tReg); + } else { + newLIR2(cUnit, kThumbCmpRI8, reg, checkValue); + } + ArmLIR *branch = newLIR2(cUnit, kThumbBCond, 0, cond); + return branch; +} + +#if defined(WITH_SELF_VERIFICATION) +static void genSelfVerificationPreBranch(CompilationUnit *cUnit, + ArmLIR *origLIR) { + /* + * We need two separate pushes, since we want r5 to be pushed first. + * Store multiple will push LR first. + */ + ArmLIR *pushFP = (ArmLIR *) dvmCompilerNew(sizeof(ArmLIR), true); + pushFP->opcode = kThumbPush; + pushFP->operands[0] = 1 << r5FP; + setupResourceMasks(pushFP); + dvmCompilerInsertLIRBefore((LIR *) origLIR, (LIR *) pushFP); + + ArmLIR *pushLR = (ArmLIR *) dvmCompilerNew(sizeof(ArmLIR), 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); +} + +static void genSelfVerificationPostBranch(CompilationUnit *cUnit, + ArmLIR *origLIR) { + /* + * 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 */ + ArmLIR *popForLR = (ArmLIR *) dvmCompilerNew(sizeof(ArmLIR), true); + popForLR->opcode = kThumbPop; + popForLR->operands[0] = 1 << r5FP; + setupResourceMasks(popForLR); + dvmCompilerInsertLIRAfter((LIR *) origLIR, (LIR *) popForLR); + + ArmLIR *copy = genRegCopyNoInsert(cUnit, r14lr, r5FP); + dvmCompilerInsertLIRAfter((LIR *) popForLR, (LIR *) copy); + + /* Now restore the original r5 */ + ArmLIR *popFP = (ArmLIR *) dvmCompilerNew(sizeof(ArmLIR), true); + popFP->opcode = kThumbPop; + popFP->operands[0] = 1 << r5FP; + setupResourceMasks(popFP); + dvmCompilerInsertLIRAfter((LIR *) copy, (LIR *) popFP); +} +#endif |
