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[2] instruction used directly here to ensure correct size */ newLIR2(cUnit, kThumb2LdrPcReln12, r0, 8); newLIR3(cUnit, kThumbLdrRRI5, r1, r0, 0); newLIR2(cUnit, kThumbAddRI8, r1, 1); newLIR3(cUnit, kThumbStrRRI5, r1, r0, 0); return 10; } 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; } }
static bool genInlineSqrt(CompilationUnit *cUnit, MIR *mir) { ArmLIR *branch; RegLocation rlSrc = dvmCompilerGetSrcWide(cUnit, mir, 0, 1); RegLocation rlDest = inlinedTargetWide(cUnit, mir, true); rlSrc = loadValueWide(cUnit, rlSrc, kFPReg); RegLocation rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kFPReg, true); newLIR2(cUnit, kThumb2Vsqrtd, S2D(rlResult.lowReg, rlResult.highReg), S2D(rlSrc.lowReg, rlSrc.highReg)); newLIR2(cUnit, kThumb2Vcmpd, S2D(rlResult.lowReg, rlResult.highReg), S2D(rlResult.lowReg, rlResult.highReg)); newLIR0(cUnit, kThumb2Fmstat); branch = newLIR2(cUnit, kThumbBCond, 0, kArmCondEq); dvmCompilerClobberCallRegs(cUnit); LOAD_FUNC_ADDR(cUnit, r2, (int) (double (*)(double)) sqrt); newLIR3(cUnit, kThumb2Fmrrd, r0, r1, S2D(rlSrc.lowReg, rlSrc.highReg)); newLIR1(cUnit, kThumbBlxR, r2); newLIR3(cUnit, kThumb2Fmdrr, S2D(rlResult.lowReg, rlResult.highReg), r0, r1); ArmLIR *label = newLIR0(cUnit, kArmPseudoTargetLabel); label->defMask = ENCODE_ALL; branch->generic.target = (LIR *)label; storeValueWide(cUnit, rlDest, rlResult); return false; }
static bool genCmpFP(CompilationUnit *cUnit, MIR *mir, RegLocation rlDest, RegLocation rlSrc1, RegLocation rlSrc2) { bool isDouble; int defaultResult; bool ltNaNBias; RegLocation rlResult; switch(mir->dalvikInsn.opCode) { case OP_CMPL_FLOAT: isDouble = false; defaultResult = -1; break; case OP_CMPG_FLOAT: isDouble = false; defaultResult = 1; break; case OP_CMPL_DOUBLE: isDouble = true; defaultResult = -1; break; case OP_CMPG_DOUBLE: isDouble = true; defaultResult = 1; break; default: return true; } if (isDouble) { rlSrc1 = loadValueWide(cUnit, rlSrc1, kFPReg); rlSrc2 = loadValueWide(cUnit, rlSrc2, kFPReg); dvmCompilerClobberSReg(cUnit, rlDest.sRegLow); rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true); loadConstant(cUnit, rlResult.lowReg, defaultResult); newLIR2(cUnit, kThumb2Vcmpd, S2D(rlSrc1.lowReg, r1Src2.highReg), S2D(rlSrc2.lowReg, rlSrc2.highReg)); } else { rlSrc1 = loadValue(cUnit, rlSrc1, kFPReg); rlSrc2 = loadValue(cUnit, rlSrc2, kFPReg); dvmCompilerClobberSReg(cUnit, rlDest.sRegLow); rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true); loadConstant(cUnit, rlResult.lowReg, defaultResult); newLIR2(cUnit, kThumb2Vcmps, rlSrc1.lowReg, rlSrc2.lowReg); } assert(!FPREG(rlResult.lowReg)); newLIR0(cUnit, kThumb2Fmstat); genIT(cUnit, (defaultResult == -1) ? kArmCondGt : kArmCondMi, ""); newLIR2(cUnit, kThumb2MovImmShift, rlResult.lowReg, modifiedImmediate(-defaultResult)); // Must not alter ccodes genIT(cUnit, kArmCondEq, ""); loadConstant(cUnit, rlResult.lowReg, 0); storeValue(cUnit, rlDest, rlResult); return 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, rFP); newLIR2(cUnit, kThumbSubRI8, rAddr, sizeof(StackSaveArea) - offset); storeWordDisp( cUnit, rAddr, 0, rDPC); return res; }
/* * Handle simple case (thin lock) inline. If it's complicated, bail * out to the heavyweight lock/unlock routines. We'll use dedicated * registers here in order to be in the right position in case we * to bail to dvm[Lock/Unlock]Object(self, object) * * r0 -> self pointer [arg0 for dvm[Lock/Unlock]Object * r1 -> object [arg1 for dvm[Lock/Unlock]Object * r2 -> intial contents of object->lock, later result of strex * r3 -> self->threadId * r7 -> temp to hold new lock value [unlock only] * r4 -> allow to be used by utilities as general temp * * The result of the strex is 0 if we acquire the lock. * * See comments in Sync.c for the layout of the lock word. * Of particular interest to this code is the test for the * simple case - which we handle inline. For monitor enter, the * simple case is thin lock, held by no-one. For monitor exit, * the simple case is thin lock, held by the unlocking thread with * a recurse count of 0. * * A minor complication is that there is a field in the lock word * unrelated to locking: the hash state. This field must be ignored, but * preserved. * */ static void genMonitorEnter(CompilationUnit *cUnit, MIR *mir) { RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0); bool enter = (mir->dalvikInsn.opCode == OP_MONITOR_ENTER); ArmLIR *target; ArmLIR *hopTarget; ArmLIR *branch; ArmLIR *hopBranch; assert(LW_SHAPE_THIN == 0); loadValueDirectFixed(cUnit, rlSrc, r1); // Get obj dvmCompilerLockAllTemps(cUnit); // Prepare for explicit register usage dvmCompilerFreeTemp(cUnit, r4PC); // Free up r4 for general use loadWordDisp(cUnit, rGLUE, offsetof(InterpState, self), r0); // Get self genNullCheck(cUnit, rlSrc.sRegLow, r1, mir->offset, NULL); loadWordDisp(cUnit, r0, offsetof(Thread, threadId), r3); // Get threadId newLIR3(cUnit, kThumb2Ldrex, r2, r1, offsetof(Object, lock) >> 2); // Get object->lock opRegImm(cUnit, kOpLsl, r3, LW_LOCK_OWNER_SHIFT); // Align owner // Is lock unheld on lock or held by us (==threadId) on unlock? newLIR4(cUnit, kThumb2Bfi, r3, r2, 0, LW_LOCK_OWNER_SHIFT - 1); newLIR3(cUnit, kThumb2Bfc, r2, LW_HASH_STATE_SHIFT, LW_LOCK_OWNER_SHIFT - 1); hopBranch = newLIR2(cUnit, kThumb2Cbnz, r2, 0); newLIR4(cUnit, kThumb2Strex, r2, r3, r1, offsetof(Object, lock) >> 2); branch = newLIR2(cUnit, kThumb2Cbz, r2, 0); hopTarget = newLIR0(cUnit, kArmPseudoTargetLabel); hopTarget->defMask = ENCODE_ALL; hopBranch->generic.target = (LIR *)hopTarget; // Clear the lock ArmLIR *inst = newLIR0(cUnit, kThumb2Clrex); // ...and make it a scheduling barrier inst->defMask = ENCODE_ALL; // Export PC (part 1) loadConstant(cUnit, r3, (int) (cUnit->method->insns + mir->offset)); /* Get dPC of next insn */ loadConstant(cUnit, r4PC, (int)(cUnit->method->insns + mir->offset + dexGetInstrWidthAbs(gDvm.instrWidth, OP_MONITOR_ENTER))); // Export PC (part 2) newLIR3(cUnit, kThumb2StrRRI8Predec, r3, rFP, sizeof(StackSaveArea) - offsetof(StackSaveArea, xtra.currentPc)); /* Call template, and don't return */ genDispatchToHandler(cUnit, TEMPLATE_MONITOR_ENTER); // Resume here target = newLIR0(cUnit, kArmPseudoTargetLabel); target->defMask = ENCODE_ALL; branch->generic.target = (LIR *)target; }
/* * 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; }
/* * Generate a Thumb2 IT instruction, which can nullify up to * four subsequent instructions based on a condition and its * inverse. The condition applies to the first instruction, which * is executed if the condition is met. The string "guide" consists * of 0 to 3 chars, and applies to the 2nd through 4th instruction. * A "T" means the instruction is executed if the condition is * met, and an "E" means the instruction is executed if the condition * is not met. */ static ArmLIR *genIT(CompilationUnit *cUnit, ArmConditionCode code, const char *guide) { int mask; int condBit = code & 1; int altBit = condBit ^ 1; int mask3 = 0; int mask2 = 0; int mask1 = 0; //Note: case fallthroughs intentional switch(strlen(guide)) { case 3: mask1 = (guide[2] == 'T') ? condBit : altBit; case 2: mask2 = (guide[1] == 'T') ? condBit : altBit; case 1: mask3 = (guide[0] == 'T') ? condBit : altBit; break; case 0: break; default: LOGE("Jit: bad case in genIT"); dvmCompilerAbort(cUnit); } mask = (mask3 << 3) | (mask2 << 2) | (mask1 << 1) | (1 << (3 - strlen(guide))); return newLIR2(cUnit, kThumb2It, code, mask); }
/* * 64-bit 3way compare function. * mov r7, #-1 * cmp op1hi, op2hi * blt done * bgt flip * sub r7, op1lo, op2lo (treat as unsigned) * beq done * ite hi * mov(hi) r7, #-1 * mov(!hi) r7, #1 * flip: * neg r7 * done: */ static void genCmpLong(CompilationUnit *cUnit, MIR *mir, RegLocation rlDest, RegLocation rlSrc1, RegLocation rlSrc2) { RegLocation rlTemp = LOC_C_RETURN; // Just using as template, will change ArmLIR *target1; ArmLIR *target2; rlSrc1 = loadValueWide(cUnit, rlSrc1, kCoreReg); rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg); rlTemp.lowReg = dvmCompilerAllocTemp(cUnit); loadConstant(cUnit, rlTemp.lowReg, -1); opRegReg(cUnit, kOpCmp, rlSrc1.highReg, rlSrc2.highReg); ArmLIR *branch1 = opCondBranch(cUnit, kArmCondLt); ArmLIR *branch2 = opCondBranch(cUnit, kArmCondGt); opRegRegReg(cUnit, kOpSub, rlTemp.lowReg, rlSrc1.lowReg, rlSrc2.lowReg); ArmLIR *branch3 = opCondBranch(cUnit, kArmCondEq); genIT(cUnit, kArmCondHi, "E"); newLIR2(cUnit, kThumb2MovImmShift, rlTemp.lowReg, modifiedImmediate(-1)); loadConstant(cUnit, rlTemp.lowReg, 1); genBarrier(cUnit); target2 = newLIR0(cUnit, kArmPseudoTargetLabel); target2->defMask = -1; opRegReg(cUnit, kOpNeg, rlTemp.lowReg, rlTemp.lowReg); target1 = newLIR0(cUnit, kArmPseudoTargetLabel); target1->defMask = -1; storeValue(cUnit, rlDest, rlTemp); branch1->generic.target = (LIR *)target1; branch2->generic.target = (LIR *)target2; branch3->generic.target = branch1->generic.target; }
/* * Jump to the out-of-line handler in ARM mode to finish executing the * remaining of more complex instructions. */ static void genDispatchToHandler(CompilationUnit *cUnit, TemplateOpCode opCode) { /* * NOTE - In practice BLX only needs one operand, but since the assembler * may abort itself and retry due to other out-of-range conditions we * cannot really use operand[0] to store the absolute target address since * it may get clobbered by the final relative offset. Therefore, * we fake BLX_1 is a two operand instruction and the absolute target * address is stored in operand[1]. */ dvmCompilerClobberHandlerRegs(cUnit); 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]); }
static void genNegFloat(CompilationUnit *cUnit, RegLocation rlDest, RegLocation rlSrc) { RegLocation rlResult; rlSrc = loadValue(cUnit, rlSrc, kFPReg); rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kFPReg, true); newLIR2(cUnit, kThumb2Vnegs, rlResult.lowReg, rlSrc.lowReg); storeValue(cUnit, rlDest, rlResult); }
/* 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(InterpState, 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, rGLUE, offset >> 2); branch1->generic.target = (LIR *)target; //TUNING: rewrite this to not clobber dvmCompilerClobber(cUnit,reg0); return false; }
static void genNegDouble(CompilationUnit *cUnit, RegLocation rlDest, RegLocation rlSrc) { RegLocation rlResult; rlSrc = loadValueWide(cUnit, rlSrc, kFPReg); rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kFPReg, true); newLIR2(cUnit, kThumb2Vnegd, S2D(rlResult.lowReg, rlResult.highReg), S2D(rlSrc.lowReg, rlSrc.highReg)); storeValueWide(cUnit, rlDest, rlResult); }
static bool genInlinedAbsFloat(CompilationUnit *cUnit, MIR *mir) { RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0); RegLocation rlDest = inlinedTarget(cUnit, mir, true); rlSrc = loadValue(cUnit, rlSrc, kFPReg); RegLocation rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kFPReg, true); newLIR2(cUnit, kThumb2Vabss, rlResult.lowReg, rlSrc.lowReg); storeValue(cUnit, rlDest, rlResult); return false; }
static bool genInlinedAbsDouble(CompilationUnit *cUnit, MIR *mir) { RegLocation rlSrc = dvmCompilerGetSrcWide(cUnit, mir, 0, 1); RegLocation rlDest = inlinedTargetWide(cUnit, mir, true); rlSrc = loadValueWide(cUnit, rlSrc, kFPReg); RegLocation rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kFPReg, true); newLIR2(cUnit, kThumb2Vabsd, S2D(rlResult.lowReg, rlResult.highReg), S2D(rlSrc.lowReg, rlSrc.highReg)); storeValueWide(cUnit, rlDest, rlResult); return false; }
static bool genInlineSqrt(CompilationUnit *cUnit, MIR *mir) { int offset = offsetof(InterpState, retval); int vSrc = mir->dalvikInsn.vA; loadDouble(cUnit, vSrc, dr1); newLIR2(cUnit, THUMB2_VSQRTD, dr0, dr1); assert(offset & 0x3 == 0); /* Must be word aligned */ assert(offset < 1024); newLIR3(cUnit, THUMB2_VSTRD, dr0, rGLUE, offset >> 2); return true; }
/* * Jump to the out-of-line handler in ARM mode to finish executing the * remaining of more complex instructions. */ static void genDispatchToHandler(CompilationUnit *cUnit, TemplateOpCode opCode) { #if USE_IN_CACHE_HANDLER /* * NOTE - In practice BLX only needs one operand, but since the assembler * may abort itself and retry due to other out-of-range conditions we * cannot really use operand[0] to store the absolute target address since * it may get clobbered by the final relative offset. Therefore, * we fake BLX_1 is a two operand instruction and the absolute target * address is stored in operand[1]. */ newLIR2(cUnit, THUMB_BLX_1, (int) gDvmJit.codeCache + templateEntryOffsets[opCode], (int) gDvmJit.codeCache + templateEntryOffsets[opCode]); newLIR2(cUnit, THUMB_BLX_2, (int) gDvmJit.codeCache + templateEntryOffsets[opCode], (int) gDvmJit.codeCache + templateEntryOffsets[opCode]); #else /* * In case we want to access the statically compiled handlers for * debugging purposes, define USE_IN_CACHE_HANDLER to 0 */ void *templatePtr; #define JIT_TEMPLATE(X) extern void dvmCompiler_TEMPLATE_##X(); #include "../../../template/armv5te-vfp/TemplateOpList.h" #undef JIT_TEMPLATE switch (opCode) { #define JIT_TEMPLATE(X) \ case TEMPLATE_##X: { templatePtr = dvmCompiler_TEMPLATE_##X; break; } #include "../../../template/armv5te-vfp/TemplateOpList.h" #undef JIT_TEMPLATE default: templatePtr = NULL; } loadConstant(cUnit, r7, (int) templatePtr); newLIR1(cUnit, THUMB_BLX_R, r7); #endif }
static bool genInlinedAbsFloat(CompilationUnit *cUnit, MIR *mir) { int offset = offsetof(InterpState, 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, rGLUE, offset, reg0); //TUNING: rewrite this to not clobber dvmCompilerClobber(cUnit, reg0); return true; }
static bool genInlinedAbsDouble(CompilationUnit *cUnit, MIR *mir) { int offset = offsetof(Thread, interpSave.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; }
/* * Jump to the out-of-line handler to finish executing the * remaining of more complex instructions. */ static void genDispatchToHandler(CompilationUnit *cUnit, TemplateOpcode opCode) { /* * We're jumping from a trace to a template. Using jal is preferable to jalr, * but we need to ensure source and target addresses allow the use of jal. * This should almost always be the case, but if source and target are in * different 256mb regions then use jalr. The test below is very conservative * since we don't have a source address yet, but this is ok for now given that * we expect this case to be very rare. The test can be made less conservative * as needed in the future in coordination with address assignment during * the assembly process. */ dvmCompilerClobberHandlerRegs(cUnit); int targetAddr = (int) gDvmJit.codeCache + templateEntryOffsets[opCode]; int maxSourceAddr = (int) gDvmJit.codeCache + gDvmJit.codeCacheSize; if ((targetAddr & 0xF0000000) == (maxSourceAddr & 0xF0000000)) { newLIR1(cUnit, kMipsJal, targetAddr); } else { loadConstant(cUnit, r_T9, targetAddr); newLIR2(cUnit, kMipsJalr, r_RA, r_T9); } }
static bool genConversion(CompilationUnit *cUnit, MIR *mir) { Opcode opcode = mir->dalvikInsn.opcode; int op = kThumbBkpt; bool longSrc = false; bool longDest = false; int srcReg; RegLocation rlSrc; RegLocation rlDest; RegLocation rlResult; switch (opcode) { case OP_INT_TO_FLOAT: longSrc = false; longDest = false; op = kThumb2VcvtIF; break; case OP_FLOAT_TO_INT: longSrc = false; longDest = false; op = kThumb2VcvtFI; break; case OP_DOUBLE_TO_FLOAT: longSrc = true; longDest = false; op = kThumb2VcvtDF; break; case OP_FLOAT_TO_DOUBLE: longSrc = false; longDest = true; op = kThumb2VcvtFd; break; case OP_INT_TO_DOUBLE: longSrc = false; longDest = true; op = kThumb2VcvtID; break; case OP_DOUBLE_TO_INT: longSrc = true; longDest = false; op = kThumb2VcvtDI; break; case OP_LONG_TO_DOUBLE: case OP_FLOAT_TO_LONG: case OP_LONG_TO_FLOAT: case OP_DOUBLE_TO_LONG: return genConversionPortable(cUnit, mir); default: return true; } if (longSrc) { rlSrc = dvmCompilerGetSrcWide(cUnit, mir, 0, 1); rlSrc = loadValueWide(cUnit, rlSrc, kFPReg); srcReg = S2D(rlSrc.lowReg, rlSrc.highReg); } else { rlSrc = dvmCompilerGetSrc(cUnit, mir, 0); rlSrc = loadValue(cUnit, rlSrc, kFPReg); srcReg = rlSrc.lowReg; } if (longDest) { rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1); rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kFPReg, true); newLIR2(cUnit, (ArmOpcode)op, S2D(rlResult.lowReg, rlResult.highReg), srcReg); storeValueWide(cUnit, rlDest, rlResult); } else { rlDest = dvmCompilerGetDest(cUnit, mir, 0); rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kFPReg, true); newLIR2(cUnit, (ArmOpcode)op, rlResult.lowReg, srcReg); storeValue(cUnit, rlDest, rlResult); } return false; }
static ArmLIR *opCondBranch(CompilationUnit *cUnit, ArmConditionCode cc) { return newLIR2(cUnit, kThumbBCond, 0 /* offset to be patched */, cc); }
/* Handle the content in each basic block */ static bool methodBlockCodeGen(CompilationUnit *cUnit, BasicBlock *bb) { MIR *mir; ArmLIR *labelList = (ArmLIR *) cUnit->blockLabelList; int blockId = bb->id; cUnit->curBlock = bb; labelList[blockId].operands[0] = bb->startOffset; /* Insert the block label */ labelList[blockId].opcode = kArmPseudoNormalBlockLabel; dvmCompilerAppendLIR(cUnit, (LIR *) &labelList[blockId]); dvmCompilerClobberAllRegs(cUnit); dvmCompilerResetNullCheck(cUnit); ArmLIR *headLIR = NULL; if (bb->blockType == kEntryBlock) { /* r0 = callsitePC */ opImm(cUnit, kOpPush, (1 << r0 | 1 << r1 | 1 << r5FP | 1 << r14lr)); opRegImm(cUnit, kOpSub, r5FP, sizeof(StackSaveArea) + cUnit->method->registersSize * 4); } else if (bb->blockType == kExitBlock) { /* No need to pop r0 and r1 */ opRegImm(cUnit, kOpAdd, r13sp, 8); opImm(cUnit, kOpPop, (1 << r5FP | 1 << r15pc)); } for (mir = bb->firstMIRInsn; mir; mir = mir->next) { dvmCompilerResetRegPool(cUnit); if (gDvmJit.disableOpt & (1 << kTrackLiveTemps)) { dvmCompilerClobberAllRegs(cUnit); } if (gDvmJit.disableOpt & (1 << kSuppressLoads)) { dvmCompilerResetDefTracking(cUnit); } Opcode dalvikOpcode = mir->dalvikInsn.opcode; InstructionFormat dalvikFormat = dexGetFormatFromOpcode(dalvikOpcode); ArmLIR *boundaryLIR; /* * Don't generate the boundary LIR unless we are debugging this * trace or we need a scheduling barrier. */ if (headLIR == NULL || cUnit->printMe == true) { boundaryLIR = newLIR2(cUnit, kArmPseudoDalvikByteCodeBoundary, mir->offset, (int) dvmCompilerGetDalvikDisassembly( &mir->dalvikInsn, "")); /* Remember the first LIR for this block */ if (headLIR == NULL) { headLIR = boundaryLIR; /* Set the first boundaryLIR as a scheduling barrier */ headLIR->defMask = ENCODE_ALL; } } /* Don't generate the SSA annotation unless verbose mode is on */ if (cUnit->printMe && mir->ssaRep) { char *ssaString = dvmCompilerGetSSAString(cUnit, mir->ssaRep); newLIR1(cUnit, kArmPseudoSSARep, (int) ssaString); } bool notHandled; switch (dalvikFormat) { case kFmt10t: case kFmt20t: case kFmt30t: notHandled = handleMethodFmt10t_Fmt20t_Fmt30t(cUnit, mir, bb, labelList); break; case kFmt10x: notHandled = handleMethodFmt10x(cUnit, mir); break; case kFmt11n: case kFmt31i: notHandled = handleMethodFmt11n_Fmt31i(cUnit, mir); break; case kFmt11x: notHandled = handleMethodFmt11x(cUnit, mir, bb, labelList); break; case kFmt12x: notHandled = handleMethodFmt12x(cUnit, mir); break; case kFmt20bc: notHandled = handleMethodFmt20bc(cUnit, mir); break; case kFmt21c: case kFmt31c: notHandled = handleMethodFmt21c_Fmt31c(cUnit, mir); break; case kFmt21h: notHandled = handleMethodFmt21h(cUnit, mir); break; case kFmt21s: notHandled = handleMethodFmt21s(cUnit, mir); break; case kFmt21t: notHandled = handleMethodFmt21t(cUnit, mir, bb, labelList); break; case kFmt22b: case kFmt22s: notHandled = handleMethodFmt22b_Fmt22s(cUnit, mir); break; case kFmt22c: notHandled = handleMethodFmt22c(cUnit, mir); break; case kFmt22cs: notHandled = handleMethodFmt22cs(cUnit, mir); break; case kFmt22t: notHandled = handleMethodFmt22t(cUnit, mir, bb, labelList); break; case kFmt22x: case kFmt32x: notHandled = handleMethodFmt22x_Fmt32x(cUnit, mir); break; case kFmt23x: notHandled = handleMethodFmt23x(cUnit, mir); break; case kFmt31t: notHandled = handleMethodFmt31t(cUnit, mir); break; case kFmt3rc: case kFmt35c: notHandled = handleMethodFmt35c_3rc(cUnit, mir, bb, labelList); break; case kFmt3rms: case kFmt35ms: notHandled = handleMethodFmt35ms_3rms(cUnit, mir, bb, labelList); break; case kFmt35mi: case kFmt3rmi: notHandled = handleMethodExecuteInline(cUnit, mir); break; case kFmt51l: notHandled = handleMethodFmt51l(cUnit, mir); break; default: notHandled = true; break; } /* FIXME - to be implemented */ if (notHandled == true && dalvikOpcode >= kNumPackedOpcodes) { notHandled = false; } if (notHandled) { ALOGE("%#06x: Opcode %#x (%s) / Fmt %d not handled", mir->offset, dalvikOpcode, dexGetOpcodeName(dalvikOpcode), dalvikFormat); dvmCompilerAbort(cUnit); break; } } if (headLIR) { /* * Eliminate redundant loads/stores and delay stores into later * slots */ dvmCompilerApplyLocalOptimizations(cUnit, (LIR *) headLIR, cUnit->lastLIRInsn); /* * Generate an unconditional branch to the fallthrough block. */ if (bb->fallThrough) { genUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]); } } return false; }
static bool genConversion(CompilationUnit *cUnit, MIR *mir) { OpCode opCode = mir->dalvikInsn.opCode; int vSrc1Dest = mir->dalvikInsn.vA; int vSrc2 = mir->dalvikInsn.vB; int op = THUMB_BKPT; bool longSrc = false; bool longDest = false; int srcReg; int tgtReg; switch (opCode) { case OP_INT_TO_FLOAT: longSrc = false; longDest = false; op = THUMB2_VCVTIF; break; case OP_FLOAT_TO_INT: longSrc = false; longDest = false; op = THUMB2_VCVTFI; break; case OP_DOUBLE_TO_FLOAT: longSrc = true; longDest = false; op = THUMB2_VCVTDF; break; case OP_FLOAT_TO_DOUBLE: longSrc = false; longDest = true; op = THUMB2_VCVTFD; break; case OP_INT_TO_DOUBLE: longSrc = false; longDest = true; op = THUMB2_VCVTID; break; case OP_DOUBLE_TO_INT: longSrc = true; longDest = false; op = THUMB2_VCVTDI; break; case OP_FLOAT_TO_LONG: case OP_LONG_TO_FLOAT: case OP_DOUBLE_TO_LONG: case OP_LONG_TO_DOUBLE: return genConversionPortable(cUnit, mir); default: return true; } if (longSrc) { srcReg = dr1; loadDouble(cUnit, vSrc2, srcReg); } else { srcReg = fr2; loadFloat(cUnit, vSrc2, srcReg); } if (longDest) { newLIR2(cUnit, op, dr0, srcReg); storeDouble(cUnit, dr0, vSrc1Dest, 0); } else { newLIR2(cUnit, op, fr0, srcReg); storeFloat(cUnit, fr0, vSrc1Dest, 0); } return false; }