static void genLong3Addr(CompilationUnit *cUnit, MIR *mir, OpKind firstOp, OpKind secondOp, RegLocation rlDest, RegLocation rlSrc1, RegLocation rlSrc2) { RegLocation rlResult; rlSrc1 = loadValueWide(cUnit, rlSrc1, kCoreReg); rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg); rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true); opRegRegReg(cUnit, firstOp, rlResult.lowReg, rlSrc1.lowReg, rlSrc2.lowReg); opRegRegReg(cUnit, secondOp, rlResult.highReg, rlSrc1.highReg, rlSrc2.highReg); storeValueWide(cUnit, rlDest, rlResult); }
static RegLocation loadValue(CompilationUnit *cUnit, RegLocation rlSrc, RegisterClass opKind) { rlSrc = dvmCompilerEvalLoc(cUnit, rlSrc, opKind, false); if (rlSrc.location == kLocDalvikFrame) { loadValueDirect(cUnit, rlSrc, rlSrc.lowReg); rlSrc.location = kLocPhysReg; dvmCompilerMarkLive(cUnit, rlSrc.lowReg, rlSrc.sRegLow); } else if (rlSrc.location == kLocRetval) { loadWordDisp(cUnit, rGLUE, offsetof(InterpState, retval), rlSrc.lowReg); rlSrc.location = kLocPhysReg; dvmCompilerClobber(cUnit, rlSrc.lowReg); } return rlSrc; }
static bool genInlinedMinMaxInt(CompilationUnit *cUnit, MIR *mir, bool isMin) { RegLocation rlSrc1 = dvmCompilerGetSrc(cUnit, mir, 0); RegLocation rlSrc2 = dvmCompilerGetSrc(cUnit, mir, 1); rlSrc1 = loadValue(cUnit, rlSrc1, kCoreReg); rlSrc2 = loadValue(cUnit, rlSrc2, kCoreReg); RegLocation rlDest = inlinedTarget(cUnit, mir, false); RegLocation rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true); opRegReg(cUnit, kOpCmp, rlSrc1.lowReg, rlSrc2.lowReg); genIT(cUnit, (isMin) ? kArmCondGt : kArmCondLt, "E"); opRegReg(cUnit, kOpMov, rlResult.lowReg, rlSrc2.lowReg); opRegReg(cUnit, kOpMov, rlResult.lowReg, rlSrc1.lowReg); genBarrier(cUnit); storeValue(cUnit, rlDest, rlResult); return false; }
static bool genArithOpDouble(CompilationUnit *cUnit, MIR *mir, RegLocation rlDest, RegLocation rlSrc1, RegLocation rlSrc2) { int op = kThumbBkpt; RegLocation rlResult; switch (mir->dalvikInsn.opcode) { case OP_ADD_DOUBLE_2ADDR: case OP_ADD_DOUBLE: op = kThumb2Vaddd; break; case OP_SUB_DOUBLE_2ADDR: case OP_SUB_DOUBLE: op = kThumb2Vsubd; break; case OP_DIV_DOUBLE_2ADDR: case OP_DIV_DOUBLE: op = kThumb2Vdivd; break; case OP_MUL_DOUBLE_2ADDR: case OP_MUL_DOUBLE: op = kThumb2Vmuld; break; case OP_REM_DOUBLE_2ADDR: case OP_REM_DOUBLE: case OP_NEG_DOUBLE: { return genArithOpDoublePortable(cUnit, mir, rlDest, rlSrc1, rlSrc2); } default: return true; } rlSrc1 = loadValueWide(cUnit, rlSrc1, kFPReg); assert(rlSrc1.wide); rlSrc2 = loadValueWide(cUnit, rlSrc2, kFPReg); assert(rlSrc2.wide); rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kFPReg, true); assert(rlDest.wide); assert(rlResult.wide); newLIR3(cUnit, (ArmOpcode)op, S2D(rlResult.lowReg, rlResult.highReg), S2D(rlSrc1.lowReg, rlSrc1.highReg), S2D(rlSrc2.lowReg, rlSrc2.highReg)); storeValueWide(cUnit, rlDest, rlResult); return false; }
static bool genArithOpFloat(CompilationUnit *cUnit, MIR *mir, RegLocation rlDest, RegLocation rlSrc1, RegLocation rlSrc2) { int op = kThumbBkpt; RegLocation rlResult; /* * Don't attempt to optimize register usage since these opcodes call out to * the handlers. */ switch (mir->dalvikInsn.opcode) { case OP_ADD_FLOAT_2ADDR: case OP_ADD_FLOAT: op = kThumb2Vadds; break; case OP_SUB_FLOAT_2ADDR: case OP_SUB_FLOAT: op = kThumb2Vsubs; break; case OP_DIV_FLOAT_2ADDR: case OP_DIV_FLOAT: op = kThumb2Vdivs; break; case OP_MUL_FLOAT_2ADDR: case OP_MUL_FLOAT: op = kThumb2Vmuls; break; case OP_REM_FLOAT_2ADDR: case OP_REM_FLOAT: case OP_NEG_FLOAT: { return genArithOpFloatPortable(cUnit, mir, rlDest, rlSrc1, rlSrc2); } default: return true; } rlSrc1 = loadValue(cUnit, rlSrc1, kFPReg); rlSrc2 = loadValue(cUnit, rlSrc2, kFPReg); rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kFPReg, true); newLIR3(cUnit, (ArmOpcode)op, rlResult.lowReg, rlSrc1.lowReg, rlSrc2.lowReg); storeValue(cUnit, rlDest, rlResult); return false; }
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); } }
static RegLocation loadValueWide(CompilationUnit *cUnit, RegLocation rlSrc, RegisterClass opKind) { assert(rlSrc.wide); rlSrc = dvmCompilerEvalLoc(cUnit, rlSrc, opKind, false); // if (rlSrc.location == kLocDalvikFrame) { loadValueDirectWide(cUnit, rlSrc, rlSrc.lowReg, rlSrc.highReg); rlSrc.location = kLocPhysReg; dvmCompilerMarkLive(cUnit, rlSrc.lowReg, rlSrc.sRegLow); dvmCompilerMarkLive(cUnit, rlSrc.highReg, dvmCompilerSRegHi(rlSrc.sRegLow)); // } else if (rlSrc.location == kLocRetval) { // loadBaseDispWide(cUnit, NULL, rGLUE, offsetof(InterpState, retval), // rlSrc.lowReg, rlSrc.highReg, INVALID_SREG); // rlSrc.location = kLocPhysReg; // dvmCompilerClobber(cUnit, rlSrc.lowReg); // dvmCompilerClobber(cUnit, rlSrc.highReg); // } return rlSrc; }
static void storeValue(CompilationUnit *cUnit, RegLocation rlDest, RegLocation rlSrc) { LOG("rlDest.location is %d\nrlSrc.location is %d\n", rlDest.location, rlSrc.location); LIR *defStart; LIR *defEnd; assert(!rlDest.wide); assert(!rlSrc.wide); //eric //dvmCompilerKillNullCheckedLoc(cUnit, rlDest); rlSrc = dvmCompilerUpdateLoc(cUnit, rlSrc); //eric:if the register is DalvikFrame, so change it to physical rlDest = dvmCompilerUpdateLoc(cUnit, rlDest); LOG(">>>>>>>>>>>>>sRegLow is %d<<<<<<<<<<<<\n", rlDest.sRegLow); if (rlSrc.location == kLocPhysReg) { LOG(">>>>>>>>>>>>>>>The function is %s<<<<<<<<<<<<<<<<<\n", __func__); LOG(">>>>>>>>>>>>>>>the Src reg is phy<<<<<<<<<<<<<<<<<\n"); if (dvmCompilerIsLive(cUnit, rlSrc.lowReg) || (rlDest.location == kLocPhysReg)) { // Src is live or Dest has assigned reg. rlDest = dvmCompilerEvalLoc(cUnit, rlDest, kAnyReg, false); genRegCopy(cUnit, rlDest.lowReg, rlSrc.lowReg); } else { // Just re-assign the registers. Dest gets Src's regs rlDest.lowReg = rlSrc.lowReg; dvmCompilerClobber(cUnit, rlSrc.lowReg); } } else { LOG(">>>>>>>>>>>>>>>The function is %s<<<<<<<<<<<<<<<<<\n", __func__); LOG("the Src reg is not phy\n"); // Load Src either into promoted Dest or temps allocated for Dest rlDest = dvmCompilerEvalLoc(cUnit, rlDest, kAnyReg, false); loadValueDirect(cUnit, rlSrc, rlDest.lowReg); } LOG(">>>>>>>>>>>>>sRegLow is %d<<<<<<<<<<<<\n", rlDest.sRegLow); // Dest is now live and dirty (until/if we flush it to home location) dvmCompilerMarkLive(cUnit, rlDest.lowReg, rlDest.sRegLow); dvmCompilerMarkDirty(cUnit, rlDest.lowReg); if (rlDest.location == kLocRetval) { //eric //storeBaseDisp(cUnit, rGLUE, offsetof(InterpState, retval), rlDest.lowReg, kWord); storeBaseDisp(cUnit, rGLUE, 8, rlDest.lowReg, kWord); dvmCompilerClobber(cUnit, rlDest.lowReg); } else { dvmCompilerResetDefLoc(cUnit, rlDest); //if (dvmCompilerLiveOut(cUnit, rlDest.sRegLow)) { if (true) { //eric // defStart = (LIR *)cUnit->lastLIRInsn; LOG(">>>>>>>>>>>>>sRegLow is %d<<<<<<<<<<<<\n", rlDest.sRegLow); int vReg = dvmCompilerS2VReg(cUnit, rlDest.sRegLow); LOG(">>>>>>>>>>>>>vReg is v%d<<<<<<<<<<<<<\n", vReg); storeBaseDisp(cUnit, rFP, vReg << 2, rlDest.lowReg, kWord); // storeBaseDisp(cUnit, rFP, 20, rlDest.lowReg, kWord); dvmCompilerMarkClean(cUnit, rlDest.lowReg); // defEnd = (LIR *)cUnit->lastLIRInsn; // dvmCompilerMarkDef(cUnit, rlDest, defStart, defEnd); } } }
static void storeValueWide(CompilationUnit *cUnit, RegLocation rlDest, RegLocation rlSrc) { LIR *defStart; LIR *defEnd; assert(FPREG(rlSrc.lowReg)==FPREG(rlSrc.highReg)); assert(rlDest.wide); assert(rlSrc.wide); // dvmCompilerKillNullCheckedLoc(cUnit, rlDest); if (rlSrc.location == kLocPhysReg) { if (dvmCompilerIsLive(cUnit, rlSrc.lowReg) || dvmCompilerIsLive(cUnit, rlSrc.highReg) || (rlDest.location == kLocPhysReg)) { // Src is live or Dest has assigned reg. rlDest = dvmCompilerEvalLoc(cUnit, rlDest, kAnyReg, false); genRegCopyWide(cUnit, rlDest.lowReg, rlDest.highReg, rlSrc.lowReg, rlSrc.highReg); } else { // Just re-assign the registers. Dest gets Src's regs rlDest.lowReg = rlSrc.lowReg; rlDest.highReg = rlSrc.highReg; dvmCompilerClobber(cUnit, rlSrc.lowReg); dvmCompilerClobber(cUnit, rlSrc.highReg); } } else { // Load Src either into promoted Dest or temps allocated for Dest rlDest = dvmCompilerEvalLoc(cUnit, rlDest, kAnyReg, false); loadValueDirectWide(cUnit, rlSrc, rlDest.lowReg, rlDest.highReg); } // Dest is now live and dirty (until/if we flush it to home location) dvmCompilerMarkLive(cUnit, rlDest.lowReg, rlDest.sRegLow); dvmCompilerMarkLive(cUnit, rlDest.highReg, dvmCompilerSRegHi(rlDest.sRegLow)); dvmCompilerMarkDirty(cUnit, rlDest.lowReg); dvmCompilerMarkDirty(cUnit, rlDest.highReg); dvmCompilerMarkPair(cUnit, rlDest.lowReg, rlDest.highReg); if (rlDest.location == kLocRetval) { //storeBaseDispWide(cUnit, rGLUE, offsetof(InterpState, retval), // rlDest.lowReg, rlDest.highReg); storeBaseDispWide(cUnit, rGLUE, 8, rlDest.lowReg, rlDest.highReg); dvmCompilerClobber(cUnit, rlDest.lowReg); dvmCompilerClobber(cUnit, rlDest.highReg); } else { dvmCompilerResetDefLocWide(cUnit, rlDest); if (dvmCompilerLiveOut(cUnit, rlDest.sRegLow) || dvmCompilerLiveOut(cUnit, dvmCompilerSRegHi(rlDest.sRegLow))) { //defStart = (LIR *)cUnit->lastLIRInsn; int vReg = dvmCompilerS2VReg(cUnit, rlDest.sRegLow); assert((vReg+1) == dvmCompilerS2VReg(cUnit, dvmCompilerSRegHi(rlDest.sRegLow))); storeBaseDispWide(cUnit, rFP, vReg << 2, rlDest.lowReg, rlDest.highReg); dvmCompilerMarkClean(cUnit, rlDest.lowReg); dvmCompilerMarkClean(cUnit, rlDest.highReg); //defEnd = (LIR *)cUnit->lastLIRInsn; //dvmCompilerMarkDefWide(cUnit, rlDest, defStart, defEnd); } } }
/* * Generate array load */ static void genArrayGet(CompilationUnit *cUnit, MIR *mir, OpSize size, RegLocation rlArray, RegLocation rlIndex, RegLocation rlDest, int scale) { RegisterClass regClass = dvmCompilerRegClassBySize(size); int lenOffset = OFFSETOF_MEMBER(ArrayObject, length); int dataOffset = OFFSETOF_MEMBER(ArrayObject, contents); RegLocation rlResult; rlArray = loadValue(cUnit, rlArray, kCoreReg); rlIndex = loadValue(cUnit, rlIndex, kCoreReg); int regPtr; /* null object? */ ArmLIR * pcrLabel = NULL; if (!(mir->OptimizationFlags & MIR_IGNORE_NULL_CHECK)) { pcrLabel = genNullCheck(cUnit, rlArray.sRegLow, rlArray.lowReg, mir->offset, NULL); } regPtr = dvmCompilerAllocTemp(cUnit); if (!(mir->OptimizationFlags & MIR_IGNORE_RANGE_CHECK)) { int regLen = dvmCompilerAllocTemp(cUnit); /* Get len */ loadWordDisp(cUnit, rlArray.lowReg, lenOffset, regLen); /* regPtr -> array data */ opRegRegImm(cUnit, kOpAdd, regPtr, rlArray.lowReg, dataOffset); genBoundsCheck(cUnit, rlIndex.lowReg, regLen, mir->offset, pcrLabel); dvmCompilerFreeTemp(cUnit, regLen); } else { /* regPtr -> array data */ opRegRegImm(cUnit, kOpAdd, regPtr, rlArray.lowReg, dataOffset); } if ((size == kLong) || (size == kDouble)) { if (scale) { int rNewIndex = dvmCompilerAllocTemp(cUnit); opRegRegImm(cUnit, kOpLsl, rNewIndex, rlIndex.lowReg, scale); opRegReg(cUnit, kOpAdd, regPtr, rNewIndex); dvmCompilerFreeTemp(cUnit, rNewIndex); } else { opRegReg(cUnit, kOpAdd, regPtr, rlIndex.lowReg); } rlResult = dvmCompilerEvalLoc(cUnit, rlDest, regClass, true); HEAP_ACCESS_SHADOW(true); loadPair(cUnit, regPtr, rlResult.lowReg, rlResult.highReg); HEAP_ACCESS_SHADOW(false); dvmCompilerFreeTemp(cUnit, regPtr); storeValueWide(cUnit, rlDest, rlResult); } else { rlResult = dvmCompilerEvalLoc(cUnit, rlDest, regClass, true); HEAP_ACCESS_SHADOW(true); loadBaseIndexed(cUnit, regPtr, rlIndex.lowReg, rlResult.lowReg, scale, size); HEAP_ACCESS_SHADOW(false); dvmCompilerFreeTemp(cUnit, regPtr); storeValue(cUnit, rlDest, rlResult); } }
static bool genCmpFP(CompilationUnit *cUnit, MIR *mir, RegLocation rlDest, RegLocation rlSrc1, RegLocation rlSrc2) { bool isDouble; int defaultResult; RegLocation rlResult; if(!genCmpFPThumb2(cUnit, mir, rlDest, rlSrc1, rlSrc2)) return false; 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 genBarrier(cUnit); genIT(cUnit, kArmCondEq, ""); loadConstant(cUnit, rlResult.lowReg, 0); genBarrier(cUnit); storeValue(cUnit, rlDest, rlResult); return false; }
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; }