diff options
Diffstat (limited to 'vm/compiler/codegen/arm/Thumb/Gen.cpp')
| -rw-r--r-- | vm/compiler/codegen/arm/Thumb/Gen.cpp | 276 |
1 files changed, 276 insertions, 0 deletions
diff --git a/vm/compiler/codegen/arm/Thumb/Gen.cpp b/vm/compiler/codegen/arm/Thumb/Gen.cpp new file mode 100644 index 000000000..18ef76286 --- /dev/null +++ b/vm/compiler/codegen/arm/Thumb/Gen.cpp @@ -0,0 +1,276 @@ +/* + * 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 + * + */ + +/* + * Reserve 6 bytes at the beginning of the trace + * +----------------------------+ + * | prof count addr (4 bytes) | + * +----------------------------+ + * | chain cell offset (2 bytes)| + * +----------------------------+ + * + * ...and then code to increment the execution + * + * For continuous profiling (12 bytes): + * + * mov r0, pc @ move adr of "mov r0,pc" + 4 to r0 + * sub r0, #10 @ back up to addr prof count pointer + * ldr r0, [r0] @ get address of counter + * ldr r1, [r0] + * add r1, #1 + * str r1, [r0] + * + * For periodic profiling (4 bytes): + * call TEMPLATE_PERIODIC_PROFILING + * + * and return the size (in bytes) of the generated code. + */ + +static int genTraceProfileEntry(CompilationUnit *cUnit) +{ + intptr_t addr = (intptr_t)dvmJitNextTraceCounter(); + assert(__BYTE_ORDER == __LITTLE_ENDIAN); + newLIR1(cUnit, kArm16BitData, addr & 0xffff); + newLIR1(cUnit, kArm16BitData, (addr >> 16) & 0xffff); + cUnit->chainCellOffsetLIR = + (LIR *) newLIR1(cUnit, kArm16BitData, CHAIN_CELL_OFFSET_TAG); + cUnit->headerSize = 6; + if ((gDvmJit.profileMode == kTraceProfilingContinuous) || + (gDvmJit.profileMode == kTraceProfilingDisabled)) { + /* Thumb instruction used directly here to ensure correct size */ + newLIR2(cUnit, kThumbMovRR_H2L, r0, r15pc); + newLIR2(cUnit, kThumbSubRI8, r0, 10); + newLIR3(cUnit, kThumbLdrRRI5, r0, r0, 0); + newLIR3(cUnit, kThumbLdrRRI5, r1, r0, 0); + newLIR2(cUnit, kThumbAddRI8, r1, 1); + newLIR3(cUnit, kThumbStrRRI5, r1, r0, 0); + return 12; + } else { + int opcode = TEMPLATE_PERIODIC_PROFILING; + newLIR2(cUnit, kThumbBlx1, + (int) gDvmJit.codeCache + templateEntryOffsets[opcode], + (int) gDvmJit.codeCache + templateEntryOffsets[opcode]); + newLIR2(cUnit, kThumbBlx2, + (int) gDvmJit.codeCache + templateEntryOffsets[opcode], + (int) gDvmJit.codeCache + templateEntryOffsets[opcode]); + return 4; + } +} + +/* + * 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 = dvmCompilerEvalLoc(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 = dvmCompilerEvalLoc(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) +{ + RegLocation rlResult; + loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1); + loadValueDirectWideFixed(cUnit, rlSrc2, r2, r3); + genDispatchToHandler(cUnit, TEMPLATE_MUL_LONG); + rlResult = dvmCompilerGetReturnWide(cUnit); + storeValueWide(cUnit, rlDest, rlResult); +} + +static bool partialOverlap(int sreg1, int sreg2) +{ + return abs(sreg1 - sreg2) == 1; +} + +static void genLong3Addr(CompilationUnit *cUnit, MIR *mir, OpKind firstOp, + OpKind secondOp, RegLocation rlDest, + RegLocation rlSrc1, RegLocation rlSrc2) +{ + RegLocation rlResult; + 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) { + // Already 2-operand + rlResult = loadValueWide(cUnit, rlDest, kCoreReg); + rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg); + opRegReg(cUnit, firstOp, rlResult.lowReg, rlSrc2.lowReg); + opRegReg(cUnit, secondOp, rlResult.highReg, rlSrc2.highReg); + storeValueWide(cUnit, rlDest, rlResult); + } else if (rlDest.sRegLow == rlSrc2.sRegLow) { + // Bad case - must use/clobber Src1 and reassign Dest + rlSrc1 = loadValueWide(cUnit, rlSrc1, kCoreReg); + rlResult = loadValueWide(cUnit, rlDest, kCoreReg); + opRegReg(cUnit, firstOp, rlSrc1.lowReg, rlResult.lowReg); + opRegReg(cUnit, secondOp, rlSrc1.highReg, rlResult.highReg); + // Old reg assignments are now invalid + dvmCompilerClobber(cUnit, rlResult.lowReg); + dvmCompilerClobber(cUnit, rlResult.highReg); + dvmCompilerClobber(cUnit, rlSrc1.lowReg); + dvmCompilerClobber(cUnit, rlSrc1.highReg); + rlDest.location = kLocDalvikFrame; + assert(rlSrc1.location == kLocPhysReg); + // Reassign registers - rlDest will now get rlSrc1's old regs + storeValueWide(cUnit, rlDest, rlSrc1); + } else { + // Copy Src1 to Dest + rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg); + rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, false); + loadValueDirectWide(cUnit, rlSrc1, rlResult.lowReg, + rlResult.highReg); + rlResult.location = kLocPhysReg; + opRegReg(cUnit, firstOp, rlResult.lowReg, rlSrc2.lowReg); + opRegReg(cUnit, secondOp, rlResult.highReg, rlSrc2.highReg); + storeValueWide(cUnit, rlDest, rlResult); + } +} + +void dvmCompilerInitializeRegAlloc(CompilationUnit *cUnit) +{ + int numTemps = sizeof(coreTemps)/sizeof(int); + RegisterPool *pool = (RegisterPool *) dvmCompilerNew(sizeof(*pool), true); + cUnit->regPool = pool; + pool->numCoreTemps = numTemps; + pool->coreTemps = (RegisterInfo *) + dvmCompilerNew(numTemps * sizeof(*pool->coreTemps), true); + pool->numFPTemps = 0; + pool->FPTemps = NULL; + dvmCompilerInitPool(pool->coreTemps, coreTemps, pool->numCoreTemps); + dvmCompilerInitPool(pool->FPTemps, NULL, 0); + pool->nullCheckedRegs = + dvmCompilerAllocBitVector(cUnit->numSSARegs, false); +} + +/* Export the Dalvik PC assicated with an instruction to the StackSave area */ +static ArmLIR *genExportPC(CompilationUnit *cUnit, MIR *mir) +{ + ArmLIR *res; + int rDPC = dvmCompilerAllocTemp(cUnit); + int rAddr = dvmCompilerAllocTemp(cUnit); + int offset = offsetof(StackSaveArea, xtra.currentPc); + res = loadConstant(cUnit, rDPC, (int) (cUnit->method->insns + mir->offset)); + newLIR2(cUnit, kThumbMovRR, rAddr, r5FP); + newLIR2(cUnit, kThumbSubRI8, rAddr, sizeof(StackSaveArea) - offset); + storeWordDisp( cUnit, rAddr, 0, rDPC); + return res; +} + +static void genMonitor(CompilationUnit *cUnit, MIR *mir) +{ + genMonitorPortable(cUnit, mir); +} + +static void genCmpLong(CompilationUnit *cUnit, MIR *mir, RegLocation rlDest, + RegLocation rlSrc1, RegLocation rlSrc2) +{ + RegLocation rlResult; + loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1); + loadValueDirectWideFixed(cUnit, rlSrc2, r2, r3); + genDispatchToHandler(cUnit, TEMPLATE_CMP_LONG); + rlResult = dvmCompilerGetReturn(cUnit); + storeValue(cUnit, rlDest, rlResult); +} + +static bool genInlinedAbsFloat(CompilationUnit *cUnit, MIR *mir) +{ + int offset = offsetof(Thread, retval); + RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0); + int reg0 = loadValue(cUnit, rlSrc, kCoreReg).lowReg; + int signMask = dvmCompilerAllocTemp(cUnit); + loadConstant(cUnit, signMask, 0x7fffffff); + newLIR2(cUnit, kThumbAndRR, reg0, signMask); + dvmCompilerFreeTemp(cUnit, signMask); + storeWordDisp(cUnit, r6SELF, offset, reg0); + //TUNING: rewrite this to not clobber + dvmCompilerClobber(cUnit, reg0); + return false; +} + +static bool genInlinedAbsDouble(CompilationUnit *cUnit, MIR *mir) +{ + int offset = offsetof(Thread, retval); + RegLocation rlSrc = dvmCompilerGetSrcWide(cUnit, mir, 0, 1); + RegLocation regSrc = loadValueWide(cUnit, rlSrc, kCoreReg); + int reglo = regSrc.lowReg; + int reghi = regSrc.highReg; + int signMask = dvmCompilerAllocTemp(cUnit); + loadConstant(cUnit, signMask, 0x7fffffff); + storeWordDisp(cUnit, r6SELF, offset, reglo); + newLIR2(cUnit, kThumbAndRR, reghi, signMask); + dvmCompilerFreeTemp(cUnit, signMask); + storeWordDisp(cUnit, r6SELF, offset + 4, reghi); + //TUNING: rewrite this to not clobber + dvmCompilerClobber(cUnit, reghi); + return false; +} + +/* No select in thumb, so we need to branch. Thumb2 will do better */ +static bool genInlinedMinMaxInt(CompilationUnit *cUnit, MIR *mir, bool isMin) +{ + int offset = offsetof(Thread, retval); + RegLocation rlSrc1 = dvmCompilerGetSrc(cUnit, mir, 0); + RegLocation rlSrc2 = dvmCompilerGetSrc(cUnit, mir, 1); + int reg0 = loadValue(cUnit, rlSrc1, kCoreReg).lowReg; + int reg1 = loadValue(cUnit, rlSrc2, kCoreReg).lowReg; + newLIR2(cUnit, kThumbCmpRR, reg0, reg1); + ArmLIR *branch1 = newLIR2(cUnit, kThumbBCond, 2, + isMin ? kArmCondLt : kArmCondGt); + newLIR2(cUnit, kThumbMovRR, reg0, reg1); + ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel); + target->defMask = ENCODE_ALL; + newLIR3(cUnit, kThumbStrRRI5, reg0, r6SELF, offset >> 2); + branch1->generic.target = (LIR *)target; + //TUNING: rewrite this to not clobber + dvmCompilerClobber(cUnit,reg0); + return false; +} + +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); +} |
