/* * 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; }
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; }
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 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 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 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 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 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 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; }
/* * To avoid possible conflicts, we use a lot of temps here. Note that * our usage of Thumb2 instruction forms avoids the problems with register * reuse for multiply instructions prior to arm6. */ static void genMulLong(CompilationUnit *cUnit, RegLocation rlDest, RegLocation rlSrc1, RegLocation rlSrc2) { RegLocation rlResult; int resLo = dvmCompilerAllocTemp(cUnit); int resHi = dvmCompilerAllocTemp(cUnit); int tmp1 = dvmCompilerAllocTemp(cUnit); rlSrc1 = loadValueWide(cUnit, rlSrc1, kCoreReg); rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg); newLIR3(cUnit, kThumb2MulRRR, tmp1, rlSrc2.lowReg, rlSrc1.highReg); newLIR4(cUnit, kThumb2Umull, resLo, resHi, rlSrc2.lowReg, rlSrc1.lowReg); newLIR4(cUnit, kThumb2Mla, tmp1, rlSrc1.lowReg, rlSrc2.highReg, tmp1); newLIR4(cUnit, kThumb2AddRRR, resHi, tmp1, resHi, 0); dvmCompilerFreeTemp(cUnit, tmp1); rlResult = dvmCompilerGetReturnWide(cUnit); // Just as a template, will patch rlResult.lowReg = resLo; rlResult.highReg = resHi; storeValueWide(cUnit, rlDest, rlResult); }
static bool genInlinedAbsDouble(CompilationUnit *cUnit, MIR *mir) { int offset = offsetof(InterpState, 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, rGLUE, offset, reglo); newLIR2(cUnit, kThumbAndRR, reghi, signMask); dvmCompilerFreeTemp(cUnit, signMask); storeWordDisp(cUnit, rGLUE, offset + 4, reghi); //TUNING: rewrite this to not clobber dvmCompilerClobber(cUnit, reghi); return true; }
/* * Generate array store * */ static void genArrayPut(CompilationUnit *cUnit, MIR *mir, OpSize size, RegLocation rlArray, RegLocation rlIndex, RegLocation rlSrc, int scale) { RegisterClass regClass = dvmCompilerRegClassBySize(size); int lenOffset = OFFSETOF_MEMBER(ArrayObject, length); int dataOffset = OFFSETOF_MEMBER(ArrayObject, contents); int regPtr; rlArray = loadValue(cUnit, rlArray, kCoreReg); rlIndex = loadValue(cUnit, rlIndex, kCoreReg); if (dvmCompilerIsTemp(cUnit, rlArray.lowReg)) { dvmCompilerClobber(cUnit, rlArray.lowReg); regPtr = rlArray.lowReg; } else { regPtr = dvmCompilerAllocTemp(cUnit); genRegCopy(cUnit, regPtr, rlArray.lowReg); } /* null object? */ ArmLIR * pcrLabel = NULL; if (!(mir->OptimizationFlags & MIR_IGNORE_NULL_CHECK)) { pcrLabel = genNullCheck(cUnit, rlArray.sRegLow, rlArray.lowReg, mir->offset, NULL); } if (!(mir->OptimizationFlags & MIR_IGNORE_RANGE_CHECK)) { int regLen = dvmCompilerAllocTemp(cUnit); //NOTE: max live temps(4) here. /* Get len */ loadWordDisp(cUnit, rlArray.lowReg, lenOffset, regLen); /* regPtr -> array data */ opRegImm(cUnit, kOpAdd, regPtr, dataOffset); genBoundsCheck(cUnit, rlIndex.lowReg, regLen, mir->offset, pcrLabel); dvmCompilerFreeTemp(cUnit, regLen); } else { /* regPtr -> array data */ opRegImm(cUnit, kOpAdd, regPtr, dataOffset); } /* at this point, regPtr points to array, 2 live temps */ if ((size == kLong) || (size == kDouble)) { //TODO: need specific wide routine that can handle fp regs if (scale) { int rNewIndex = dvmCompilerAllocTemp(cUnit); opRegRegImm(cUnit, kOpLsl, rNewIndex, rlIndex.lowReg, scale); opRegReg(cUnit, kOpAdd, regPtr, rNewIndex); } else { opRegReg(cUnit, kOpAdd, regPtr, rlIndex.lowReg); } rlSrc = loadValueWide(cUnit, rlSrc, regClass); HEAP_ACCESS_SHADOW(true); storePair(cUnit, regPtr, rlSrc.lowReg, rlSrc.highReg); HEAP_ACCESS_SHADOW(false); dvmCompilerFreeTemp(cUnit, regPtr); } else { rlSrc = loadValue(cUnit, rlSrc, regClass); HEAP_ACCESS_SHADOW(true); storeBaseIndexed(cUnit, regPtr, rlIndex.lowReg, rlSrc.lowReg, scale, size); HEAP_ACCESS_SHADOW(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; }