diff options
21 files changed, 848 insertions, 3114 deletions
diff --git a/src/compiler/CompilerIR.h b/src/compiler/CompilerIR.h index 34ccfb4235..52b12d8bf6 100644 --- a/src/compiler/CompilerIR.h +++ b/src/compiler/CompilerIR.h @@ -445,6 +445,7 @@ typedef enum OpKind { kOp2Byte, kOpCondBr, kOpUncondBr, + kOpBx, kOpInvalid, } OpKind; @@ -477,6 +478,22 @@ typedef enum ThrowKind { kThrowStackOverflow, } ThrowKind; +typedef struct SwitchTable { + int offset; + const u2* table; // Original dex table + int vaddr; // Dalvik offset of switch opcode + LIR* bxInst; // Switch indirect branch instruction + LIR** targets; // Array of case targets +} SwitchTable; + +typedef struct FillArrayData { + int offset; + const u2* table; // Original dex table + int size; + int vaddr; // Dalvik offset of OP_FILL_ARRAY_DATA opcode +} FillArrayData; + + BasicBlock* oatNewBB(CompilationUnit* cUnit, BBType blockType, int blockId); void oatAppendMIR(BasicBlock* bb, MIR* mir); diff --git a/src/compiler/codegen/CodegenUtil.cc b/src/compiler/codegen/CodegenUtil.cc index 4eccf04814..96a9b2176f 100644 --- a/src/compiler/codegen/CodegenUtil.cc +++ b/src/compiler/codegen/CodegenUtil.cc @@ -154,6 +154,7 @@ void setupResourceMasks(LIR* lir) lir->defMask |= ENCODE_REG_LIST(lir->operands[1]); } +#if defined(TARGET_ARM) if (flags & REG_DEF_FPCS_LIST0) { lir->defMask |= ENCODE_REG_FPCS_LIST(lir->operands[0]); } @@ -163,6 +164,7 @@ void setupResourceMasks(LIR* lir) setupRegMask(&lir->defMask, lir->operands[1] + i); } } +#endif if (flags & SETS_CCODES) { lir->defMask |= ENCODE_CCODE; @@ -201,6 +203,7 @@ void setupResourceMasks(LIR* lir) lir->useMask |= ENCODE_REG_LIST(lir->operands[1]); } +#if defined(TARGET_ARM) if (flags & REG_USE_FPCS_LIST0) { lir->useMask |= ENCODE_REG_FPCS_LIST(lir->operands[0]); } @@ -210,6 +213,7 @@ void setupResourceMasks(LIR* lir) setupRegMask(&lir->useMask, lir->operands[1] + i); } } +#endif if (flags & USES_CCODES) { lir->useMask |= ENCODE_CCODE; @@ -231,10 +235,186 @@ void setupResourceMasks(LIR* lir) } /* + * Debugging macros + */ +#define DUMP_RESOURCE_MASK(X) +#define DUMP_SSA_REP(X) + +/* Pretty-print a LIR instruction */ +void oatDumpLIRInsn(CompilationUnit* cUnit, LIR* arg, unsigned char* baseAddr) +{ + LIR* lir = (LIR*) arg; + int offset = lir->offset; + int dest = lir->operands[0]; + const bool dumpNop = false; + + /* Handle pseudo-ops individually, and all regular insns as a group */ + switch(lir->opcode) { + case kPseudoMethodEntry: + LOG(INFO) << "-------- method entry " << + PrettyMethod(cUnit->method_idx, *cUnit->dex_file); + break; + case kPseudoMethodExit: + LOG(INFO) << "-------- Method_Exit"; + break; + case kPseudoBarrier: + LOG(INFO) << "-------- BARRIER"; + break; + case kPseudoExtended: + LOG(INFO) << "-------- " << (char* ) dest; + break; + case kPseudoSSARep: + DUMP_SSA_REP(LOG(INFO) << "-------- kMirOpPhi: " << (char* ) dest); + break; + case kPseudoEntryBlock: + LOG(INFO) << "-------- entry offset: 0x" << std::hex << dest; + break; + case kPseudoDalvikByteCodeBoundary: + LOG(INFO) << "-------- dalvik offset: 0x" << std::hex << + lir->dalvikOffset << " @ " << (char* )lir->operands[0]; + break; + case kPseudoExitBlock: + LOG(INFO) << "-------- exit offset: 0x" << std::hex << dest; + break; + case kPseudoPseudoAlign4: + LOG(INFO) << (intptr_t)baseAddr + offset << " (0x" << std::hex << + offset << "): .align4"; + break; + case kPseudoEHBlockLabel: + LOG(INFO) << "Exception_Handling:"; + break; + case kPseudoTargetLabel: + case kPseudoNormalBlockLabel: + LOG(INFO) << "L" << (intptr_t)lir << ":"; + break; + case kPseudoThrowTarget: + LOG(INFO) << "LT" << (intptr_t)lir << ":"; + break; + case kPseudoSuspendTarget: + LOG(INFO) << "LS" << (intptr_t)lir << ":"; + break; + case kPseudoCaseLabel: + LOG(INFO) << "LC" << (intptr_t)lir << ": Case target 0x" << + std::hex << lir->operands[0] << "|" << std::dec << + lir->operands[0]; + break; + default: + if (lir->flags.isNop && !dumpNop) { + break; + } else { + std::string op_name(buildInsnString(EncodingMap[lir->opcode].name, lir, baseAddr)); + std::string op_operands(buildInsnString(EncodingMap[lir->opcode].fmt, lir, baseAddr)); + LOG(INFO) << StringPrintf("%p (%04x): %-9s%s%s", baseAddr + offset, offset, + op_name.c_str(), op_operands.c_str(), lir->flags.isNop ? "(nop)" : ""); + } + break; + } + + if (lir->useMask && (!lir->flags.isNop || dumpNop)) { + DUMP_RESOURCE_MASK(oatDumpResourceMask((LIR* ) lir, + lir->useMask, "use")); + } + if (lir->defMask && (!lir->flags.isNop || dumpNop)) { + DUMP_RESOURCE_MASK(oatDumpResourceMask((LIR* ) lir, + lir->defMask, "def")); + } +} + +void oatDumpPromotionMap(CompilationUnit *cUnit) +{ + for (int i = 0; i < cUnit->numDalvikRegisters; i++) { + PromotionMap vRegMap = cUnit->promotionMap[i]; + char buf[100]; + if (vRegMap.fpLocation == kLocPhysReg) { + snprintf(buf, 100, " : s%d", vRegMap.fpReg & FP_REG_MASK); + } else { + buf[0] = 0; + } + char buf2[100]; + snprintf(buf2, 100, "V[%02d] -> %s%d%s", i, + vRegMap.coreLocation == kLocPhysReg ? + "r" : "SP+", vRegMap.coreLocation == kLocPhysReg ? + vRegMap.coreReg : oatSRegOffset(cUnit, i), buf); + LOG(INFO) << buf2; + } +} + +void oatDumpFullPromotionMap(CompilationUnit *cUnit) +{ + for (int i = 0; i < cUnit->numDalvikRegisters; i++) { + PromotionMap vRegMap = cUnit->promotionMap[i]; + LOG(INFO) << i << " -> " << "CL:" << (int)vRegMap.coreLocation << + ", CR:" << (int)vRegMap.coreReg << ", FL:" << + (int)vRegMap.fpLocation << ", FR:" << (int)vRegMap.fpReg << + ", - " << (int)vRegMap.firstInPair; + } +} + +/* Dump instructions and constant pool contents */ +void oatCodegenDump(CompilationUnit* cUnit) +{ + LOG(INFO) << "/*"; + LOG(INFO) << "Dumping LIR insns for " + << PrettyMethod(cUnit->method_idx, *cUnit->dex_file); + LIR* lirInsn; + LIR* thisLIR; + int insnsSize = cUnit->insnsSize; + + LOG(INFO) << "Regs (excluding ins) : " << cUnit->numRegs; + LOG(INFO) << "Ins : " << cUnit->numIns; + LOG(INFO) << "Outs : " << cUnit->numOuts; + LOG(INFO) << "CoreSpills : " << cUnit->numCoreSpills; + LOG(INFO) << "FPSpills : " << cUnit->numFPSpills; + LOG(INFO) << "Padding : " << cUnit->numPadding; + LOG(INFO) << "Frame size : " << cUnit->frameSize; + LOG(INFO) << "Start of ins : " << cUnit->insOffset; + LOG(INFO) << "Start of regs : " << cUnit->regsOffset; + LOG(INFO) << "code size is " << cUnit->totalSize << + " bytes, Dalvik size is " << insnsSize * 2; + LOG(INFO) << "expansion factor: " << + (float)cUnit->totalSize / (float)(insnsSize * 2); + oatDumpPromotionMap(cUnit); + for (lirInsn = cUnit->firstLIRInsn; lirInsn; lirInsn = lirInsn->next) { + oatDumpLIRInsn(cUnit, lirInsn, 0); + } + for (lirInsn = cUnit->classPointerList; lirInsn; lirInsn = lirInsn->next) { + thisLIR = (LIR*) lirInsn; + LOG(INFO) << StringPrintf("%x (%04x): .class (%s)", + thisLIR->offset, thisLIR->offset, + ((CallsiteInfo *) thisLIR->operands[0])->classDescriptor); + } + for (lirInsn = cUnit->literalList; lirInsn; lirInsn = lirInsn->next) { + thisLIR = (LIR*) lirInsn; + LOG(INFO) << StringPrintf("%x (%04x): .word (%#x)", + thisLIR->offset, thisLIR->offset, thisLIR->operands[0]); + } + + const DexFile::MethodId& method_id = + cUnit->dex_file->GetMethodId(cUnit->method_idx); + std::string signature(cUnit->dex_file->GetMethodSignature(method_id)); + std::string name(cUnit->dex_file->GetMethodName(method_id)); + std::string descriptor(cUnit->dex_file->GetMethodDeclaringClassDescriptor(method_id)); + + // Dump mapping table + if (cUnit->mappingTable.size() > 0) { + std::string line(StringPrintf("\n MappingTable %s%s_%s_mappingTable[%zu] = {", + descriptor.c_str(), name.c_str(), signature.c_str(), cUnit->mappingTable.size())); + std::replace(line.begin(), line.end(), ';', '_'); + LOG(INFO) << line; + for (uint32_t i = 0; i < cUnit->mappingTable.size(); i+=2) { + line = StringPrintf(" {0x%08x, 0x%04x},", + cUnit->mappingTable[i], cUnit->mappingTable[i+1]); + LOG(INFO) << line; + } + LOG(INFO) <<" };\n\n"; + } +} + +/* * The following are building blocks to construct low-level IRs with 0 - 4 * operands. */ -LIR* newLIR0(CompilationUnit* cUnit, ArmOpcode opcode) +LIR* newLIR0(CompilationUnit* cUnit, int opcode) { LIR* insn = (LIR* ) oatNew(cUnit, sizeof(LIR), true, kAllocLIR); DCHECK(isPseudoOpcode(opcode) || (EncodingMap[opcode].flags & NO_OPERAND)); @@ -245,7 +425,7 @@ LIR* newLIR0(CompilationUnit* cUnit, ArmOpcode opcode) return insn; } -LIR* newLIR1(CompilationUnit* cUnit, ArmOpcode opcode, +LIR* newLIR1(CompilationUnit* cUnit, int opcode, int dest) { LIR* insn = (LIR* ) oatNew(cUnit, sizeof(LIR), true, kAllocLIR); @@ -258,7 +438,7 @@ LIR* newLIR1(CompilationUnit* cUnit, ArmOpcode opcode, return insn; } -LIR* newLIR2(CompilationUnit* cUnit, ArmOpcode opcode, +LIR* newLIR2(CompilationUnit* cUnit, int opcode, int dest, int src1) { LIR* insn = (LIR* ) oatNew(cUnit, sizeof(LIR), true, kAllocLIR); @@ -273,7 +453,7 @@ LIR* newLIR2(CompilationUnit* cUnit, ArmOpcode opcode, return insn; } -LIR* newLIR3(CompilationUnit* cUnit, ArmOpcode opcode, +LIR* newLIR3(CompilationUnit* cUnit, int opcode, int dest, int src1, int src2) { LIR* insn = (LIR* ) oatNew(cUnit, sizeof(LIR), true, kAllocLIR); @@ -293,7 +473,7 @@ LIR* newLIR3(CompilationUnit* cUnit, ArmOpcode opcode, } #if defined(TARGET_ARM) -LIR* newLIR4(CompilationUnit* cUnit, ArmOpcode opcode, +LIR* newLIR4(CompilationUnit* cUnit, int opcode, int dest, int src1, int src2, int info) { LIR* insn = (LIR* ) oatNew(cUnit, sizeof(LIR), true, kAllocLIR); @@ -350,7 +530,7 @@ LIR* scanLiteralPoolWide(LIR* dataTarget, int valLo, int valHi) * instruction streams. */ -/* Add a 32-bit constant either in the constant pool or mixed with code */ +/* Add a 32-bit constant either in the constant pool */ LIR* addWordData(CompilationUnit* cUnit, LIR* *constantListP, int value) { @@ -362,10 +542,6 @@ LIR* addWordData(CompilationUnit* cUnit, LIR* *constantListP, newValue->next = *constantListP; *constantListP = (LIR*) newValue; return newValue; - } else { - /* Add the constant in the middle of code stream */ - newLIR1(cUnit, kArm16BitData, (value & 0xffff)); - newLIR1(cUnit, kArm16BitData, (value >> 16)); } return NULL; } @@ -374,17 +550,10 @@ LIR* addWordData(CompilationUnit* cUnit, LIR* *constantListP, LIR* addWideData(CompilationUnit* cUnit, LIR* *constantListP, int valLo, int valHi) { - LIR* res; //FIXME: hard-coded little endian, need BE variant - if (constantListP == NULL) { - res = addWordData(cUnit, NULL, valLo); - addWordData(cUnit, NULL, valHi); - } else { - // Insert high word into list first - addWordData(cUnit, constantListP, valHi); - res = addWordData(cUnit, constantListP, valLo); - } - return res; + // Insert high word into list first + addWordData(cUnit, constantListP, valHi); + return addWordData(cUnit, constantListP, valLo); } void pushWord(std::vector<uint16_t>&buf, int data) { diff --git a/src/compiler/codegen/CompilerCodegen.h b/src/compiler/codegen/CompilerCodegen.h index ae85bb3d15..26dad8240c 100644 --- a/src/compiler/codegen/CompilerCodegen.h +++ b/src/compiler/codegen/CompilerCodegen.h @@ -35,6 +35,9 @@ int oatAssignInsnOffsets(CompilationUnit* cUnit); void oatCodegenDump(CompilationUnit* cUnit); void oatDumpPromotionMap(CompilationUnit* cUnit); void oatDumpFullPromotionMap(CompilationUnit* cUnit); +std::string buildInsnString(const char* fmt, LIR* lir, + unsigned char* baseAddr); + /* Implemented in codegen/<target>/Ralloc.c */ void oatSimpleRegAlloc(CompilationUnit* cUnit); diff --git a/src/compiler/codegen/GenCommon.cc b/src/compiler/codegen/GenCommon.cc index 7af1aa033c..511c47bdae 100644 --- a/src/compiler/codegen/GenCommon.cc +++ b/src/compiler/codegen/GenCommon.cc @@ -43,19 +43,23 @@ void genBarrier(CompilationUnit* cUnit) barrier->defMask = -1; } -/* Generate conditional branch instructions */ -LIR* genConditionalBranch(CompilationUnit* cUnit, ConditionCode cond, - LIR* target) + +/* Generate unconditional branch instructions */ +LIR* genUnconditionalBranch(CompilationUnit* cUnit, LIR* target) { - LIR* branch = opCondBranch(cUnit, cond); + LIR* branch = opNone(cUnit, kOpUncondBr); branch->target = (LIR*) target; return branch; } -/* Generate unconditional branch instructions */ -LIR* genUnconditionalBranch(CompilationUnit* cUnit, LIR* target) +// FIXME: need to do some work to split out targets with +// condition codes and those without +#if defined(TARGET_ARM) || defined(TARGET_X86) +/* Generate conditional branch instructions */ +LIR* genConditionalBranch(CompilationUnit* cUnit, ConditionCode cond, + LIR* target) { - LIR* branch = opNone(cUnit, kOpUncondBr); + LIR* branch = opCondBranch(cUnit, cond); branch->target = (LIR*) target; return branch; } @@ -72,6 +76,7 @@ LIR* genCheck(CompilationUnit* cUnit, ConditionCode cCode, MIR* mir, oatInsertGrowableList(cUnit, &cUnit->throwLaunchpads, (intptr_t)tgt); return branch; } +#endif LIR* genImmedCheck(CompilationUnit* cUnit, ConditionCode cCode, int reg, int immVal, MIR* mir, ThrowKind kind) @@ -112,8 +117,12 @@ LIR* genRegRegCheck(CompilationUnit* cUnit, ConditionCode cCode, tgt->operands[1] = mir ? mir->offset : 0; tgt->operands[2] = reg1; tgt->operands[3] = reg2; +#if defined(TARGET_MIPS) + LIR* branch = genCompareBranch(cUnit, cCode, reg1, reg2); +#else opRegReg(cUnit, kOpCmp, reg1, reg2); LIR* branch = genConditionalBranch(cUnit, cCode, tgt); +#endif // Remember branch target - will process later oatInsertGrowableList(cUnit, &cUnit->throwLaunchpads, (intptr_t)tgt); return branch; @@ -125,7 +134,6 @@ void genCompareAndBranch(CompilationUnit* cUnit, BasicBlock* bb, MIR* mir, ConditionCode cond; rlSrc1 = loadValue(cUnit, rlSrc1, kCoreReg); rlSrc2 = loadValue(cUnit, rlSrc2, kCoreReg); - opRegReg(cUnit, kOpCmp, rlSrc1.lowReg, rlSrc2.lowReg); Opcode opcode = mir->dalvikInsn.opcode; switch(opcode) { case OP_IF_EQ: @@ -150,7 +158,13 @@ void genCompareAndBranch(CompilationUnit* cUnit, BasicBlock* bb, MIR* mir, cond = (ConditionCode)0; LOG(FATAL) << "Unexpected opcode " << (int)opcode; } +#if defined(TARGET_MIPS) + LIR* branch = genCompareBranch(cUnit, cond, rlSrc1.lowReg, rlSrc2.lowReg); + branch->target = &labelList[bb->taken->id]; +#else + opRegReg(cUnit, kOpCmp, rlSrc1.lowReg, rlSrc2.lowReg); genConditionalBranch(cUnit, cond, &labelList[bb->taken->id]); +#endif genUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]); } @@ -159,7 +173,6 @@ void genCompareZeroAndBranch(CompilationUnit* cUnit, BasicBlock* bb, MIR* mir, { ConditionCode cond; rlSrc = loadValue(cUnit, rlSrc, kCoreReg); - opRegImm(cUnit, kOpCmp, rlSrc.lowReg, 0); Opcode opcode = mir->dalvikInsn.opcode; switch(opcode) { case OP_IF_EQZ: @@ -184,7 +197,13 @@ void genCompareZeroAndBranch(CompilationUnit* cUnit, BasicBlock* bb, MIR* mir, cond = (ConditionCode)0; LOG(FATAL) << "Unexpected opcode " << (int)opcode; } +#if defined(TARGET_MIPS) + LIR* branch = genCmpImmBranch(cUnit, cond, rlSrc.lowReg, 0); + branch->target = &labelList[bb->taken->id]; +#else + opRegImm(cUnit, kOpCmp, rlSrc.lowReg, 0); genConditionalBranch(cUnit, cond, &labelList[bb->taken->id]); +#endif genUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]); } @@ -319,7 +338,11 @@ void genFilledNewArray(CompilationUnit* cUnit, MIR* mir, bool isRange) int rSrc = oatAllocTemp(cUnit); int rDst = oatAllocTemp(cUnit); int rIdx = oatAllocTemp(cUnit); +#if defined(TARGET_ARM) int rVal = rLR; // Using a lot of temps, rLR is known free here +#else + int rVal = oatAllocTemp(cUnit); +#endif // Set up source pointer RegLocation rlFirst = oatGetSrc(cUnit, mir, 0); opRegRegImm(cUnit, kOpAdd, rSrc, rSP, @@ -340,8 +363,9 @@ void genFilledNewArray(CompilationUnit* cUnit, MIR* mir, bool isRange) newLIR3(cUnit, kThumb2SubsRRI12, rIdx, rIdx, 1); LIR* branch = opCondBranch(cUnit, kCondGe); #else + oatFreeTemp(cUnit, rVal); opRegImm(cUnit, kOpSub, rIdx, 1); - LIR* branch = opCompareBranchImm(cUnit, kCondGe, rIdx, 0); + LIR* branch = genCmpImmBranch(cUnit, kCondGe, rIdx, 0); #endif branch->target = (LIR*)target; } else if (!isRange) { @@ -637,11 +661,11 @@ void handleThrowLaunchpads(CompilationUnit *cUnit) funcOffset = OFFSETOF_MEMBER(Thread, pThrowNullPointerFromCode); break; case kThrowArrayBounds: - if (v2 != r0) { + if (v2 != rARG0) { genRegCopy(cUnit, rARG0, v1); genRegCopy(cUnit, rARG1, v2); } else { - if (v1 == r1) { + if (v1 == rARG1) { #if defined(TARGET_ARM) int rTmp = r12; #else @@ -860,7 +884,7 @@ void genConstClass(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest, // TUNING: move slow path to end & remove unconditional branch LIR* target1 = newLIR0(cUnit, kPseudoTargetLabel); target1->defMask = ENCODE_ALL; - // Call out to helper, which will return resolved type in r0 + // Call out to helper, which will return resolved type in rARG0 int rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread, pInitializeTypeFromCode)); genRegCopy(cUnit, rARG1, mReg); @@ -909,7 +933,7 @@ void genConstString(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest, genRegCopy(cUnit, rARG0, rARG2); // .eq opReg(cUnit, kOpBlx, rTgt); // .eq, helper(Method*, string_idx) #else - LIR* branch = genCmpImmBranch(cUnit, kCondNe, 0); + LIR* branch = genCmpImmBranch(cUnit, kCondNe, rRET0, 0); genRegCopy(cUnit, rARG0, rARG2); // .eq opReg(cUnit, kOpBlx, rTgt); LIR* target = newLIR0(cUnit, kPseudoTargetLabel); @@ -961,22 +985,22 @@ void genInstanceof(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest, // May generate a call - use explicit registers oatLockCallTemps(cUnit); uint32_t type_idx = mir->dalvikInsn.vC; - loadCurrMethodDirect(cUnit, rARG1); // r1 <= current Method* + loadCurrMethodDirect(cUnit, rARG1); // rARG1 <= current Method* int classReg = rARG2; // rARG2 will hold the Class* if (!cUnit->compiler->CanAccessTypeWithoutChecks(cUnit->method_idx, cUnit->dex_cache, *cUnit->dex_file, type_idx)) { // Check we have access to type_idx and if not throw IllegalAccessError, - // returns Class* in r0 + // returns Class* in rARG0 int rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread, pInitializeTypeAndVerifyAccessFromCode)); loadConstant(cUnit, rARG0, type_idx); callRuntimeHelper(cUnit, rTgt); // InitializeTypeAndVerifyAccess(idx, method) genRegCopy(cUnit, classReg, rRET0); // Align usage with fast path - loadValueDirectFixed(cUnit, rlSrc, rARG0); // r0 <= ref + loadValueDirectFixed(cUnit, rlSrc, rARG0); // rARG0 <= ref } else { - // Load dex cache entry into classReg (r2) + // Load dex cache entry into classReg (rARG2) loadValueDirectFixed(cUnit, rlSrc, rARG0); // rARG0 <= ref loadWordDisp(cUnit, rARG1, Method::DexCacheResolvedTypesOffset().Int32Value(), @@ -995,7 +1019,7 @@ void genInstanceof(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest, pInitializeTypeFromCode)); loadConstant(cUnit, rARG0, type_idx); callRuntimeHelper(cUnit, rTgt); // InitializeTypeFromCode(idx, method) - genRegCopy(cUnit, r2, rRET0); // Align usage with fast path + genRegCopy(cUnit, rARG2, rRET0); // Align usage with fast path loadValueDirectFixed(cUnit, rlSrc, rARG0); /* reload Ref */ // Rejoin code paths LIR* hopTarget = newLIR0(cUnit, kPseudoTargetLabel); @@ -1021,6 +1045,7 @@ void genInstanceof(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest, genBarrier(cUnit); oatClobberCalleeSave(cUnit); #else + (void)rTgt; // Perhaps a general-purpose kOpSelect operator? UNIMPLEMENTED(FATAL) << "Need non IT implementation"; #endif @@ -1065,18 +1090,18 @@ void genCheckCast(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc) // Need to test presence of type in dex cache at runtime LIR* hopBranch = genCmpImmBranch(cUnit, kCondNe, classReg, 0); // Not resolved - // Call out to helper, which will return resolved type in r0 - loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pInitializeTypeFromCode), rLR); - loadConstant(cUnit, r0, type_idx); - callRuntimeHelper(cUnit, rLR); // InitializeTypeFromCode(idx, method) - genRegCopy(cUnit, classReg, r0); // Align usage with fast path + // Call out to helper, which will return resolved type in rARG0 + int rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread, pInitializeTypeFromCode)); + loadConstant(cUnit, rARG0, type_idx); + callRuntimeHelper(cUnit, rTgt); // InitializeTypeFromCode(idx, method) + genRegCopy(cUnit, classReg, rARG0); // Align usage with fast path // Rejoin code paths LIR* hopTarget = newLIR0(cUnit, kPseudoTargetLabel); hopTarget->defMask = ENCODE_ALL; hopBranch->target = (LIR*)hopTarget; } } - // At this point, classReg (r2) has class + // At this point, classReg (rARG2) has class loadValueDirectFixed(cUnit, rlSrc, rARG0); // rARG0 <= ref /* Null is OK - continue */ LIR* branch1 = genCmpImmBranch(cUnit, kCondEq, rARG0, 0); @@ -1086,8 +1111,12 @@ void genCheckCast(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc) /* rARG1 now contains object->clazz */ int rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread, pCheckCastFromCode)); +#if defined(TARGET_MIPS) + LIR* branch2 = genCompareBranch(cUnit, kCondEq, rARG1, classReg); +#else opRegReg(cUnit, kOpCmp, rARG1, classReg); LIR* branch2 = opCondBranch(cUnit, kCondEq); /* If equal, trivial yes */ +#endif genRegCopy(cUnit, rARG0, rARG1); genRegCopy(cUnit, rARG1, rARG2); callRuntimeHelper(cUnit, rTgt); @@ -1430,7 +1459,7 @@ bool genArithOpInt(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest, funcOffset = OFFSETOF_MEMBER(Thread, pIdiv); retReg = rRET0; break; - /* NOTE: returns in r1 */ + /* NOTE: returns in rARG1 */ case OP_REM_INT: case OP_REM_INT_2ADDR: callOut = true; @@ -1598,8 +1627,12 @@ void genMultiplyByTwoBitMultiplier(CompilationUnit* cUnit, RegLocation rlSrc, RegLocation rlResult, int lit, int firstBit, int secondBit) { +#if defined(TARGET_MIPS) + UNIMPLEMENTED(FATAL) << "Need shift & add primative"; +#else opRegRegRegShift(cUnit, kOpAdd, rlResult.lowReg, rlSrc.lowReg, rlSrc.lowReg, encodeShift(kArmLsl, secondBit - firstBit)); +#endif if (firstBit != 0) { opRegRegImm(cUnit, kOpLsl, rlResult.lowReg, rlResult.lowReg, firstBit); } @@ -1882,7 +1915,7 @@ bool genArithOpLong(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest, genCheck(cUnit, kCondEq, mir, kThrowDivZero); #else opRegRegReg(cUnit, kOpOr, tReg, rARG2, rARG3); - genImmedCheck(cUnit, kCondEq, mir, tReg, 0, mir, kThrowDivZero); + genImmedCheck(cUnit, kCondEq, tReg, 0, mir, kThrowDivZero); oatFreeTemp(cUnit, tReg); #endif } else { @@ -2116,7 +2149,7 @@ void genSuspendTest(CompilationUnit* cUnit, MIR* mir) branch = opCondBranch(cUnit, kCondEq); #else opRegImm(cUnit, kOpSub, rSUSPEND, 1); - branch = opCompareBranchImm(cUnit, kCondEq, rSUSPEND, 0); + branch = genCmpImmBranch(cUnit, kCondEq, rSUSPEND, 0); #endif } LIR* retLab = newLIR0(cUnit, kPseudoTargetLabel); diff --git a/src/compiler/codegen/MethodCodegenDriver.cc b/src/compiler/codegen/MethodCodegenDriver.cc index 6de3a9c3d9..38c2117036 100644 --- a/src/compiler/codegen/MethodCodegenDriver.cc +++ b/src/compiler/codegen/MethodCodegenDriver.cc @@ -102,7 +102,11 @@ void genInvoke(CompilationUnit* cUnit, MIR* mir, InvokeType type, bool isRange) if (DISPLAY_MISSING_TARGETS) { genShowTarget(cUnit); } +#if defined(TARGET_MIPS) + UNIMPLEMENTED(FATAL) << "Need to handle common target register"; +#else opReg(cUnit, kOpBlx, rLR); +#endif oatClobberCalleeSave(cUnit); } diff --git a/src/compiler/codegen/arm/ArchUtility.cc b/src/compiler/codegen/arm/ArchUtility.cc index e1eba44138..be6b44de71 100644 --- a/src/compiler/codegen/arm/ArchUtility.cc +++ b/src/compiler/codegen/arm/ArchUtility.cc @@ -321,180 +321,5 @@ void oatDumpResourceMask(LIR* lir, u8 mask, const char* prefix) } } -/* - * Debugging macros - */ -#define DUMP_RESOURCE_MASK(X) -#define DUMP_SSA_REP(X) - -/* Pretty-print a LIR instruction */ -void oatDumpLIRInsn(CompilationUnit* cUnit, LIR* arg, unsigned char* baseAddr) -{ - LIR* lir = (LIR*) arg; - int offset = lir->offset; - int dest = lir->operands[0]; - const bool dumpNop = false; - - /* Handle pseudo-ops individually, and all regular insns as a group */ - switch(lir->opcode) { - case kPseudoMethodEntry: - LOG(INFO) << "-------- method entry " << - PrettyMethod(cUnit->method_idx, *cUnit->dex_file); - break; - case kPseudoMethodExit: - LOG(INFO) << "-------- Method_Exit"; - break; - case kPseudoBarrier: - LOG(INFO) << "-------- BARRIER"; - break; - case kPseudoExtended: - LOG(INFO) << "-------- " << (char* ) dest; - break; - case kPseudoSSARep: - DUMP_SSA_REP(LOG(INFO) << "-------- kMirOpPhi: " << (char* ) dest); - break; - case kPseudoEntryBlock: - LOG(INFO) << "-------- entry offset: 0x" << std::hex << dest; - break; - case kPseudoDalvikByteCodeBoundary: - LOG(INFO) << "-------- dalvik offset: 0x" << std::hex << - lir->dalvikOffset << " @ " << (char* )lir->operands[0]; - break; - case kPseudoExitBlock: - LOG(INFO) << "-------- exit offset: 0x" << std::hex << dest; - break; - case kPseudoPseudoAlign4: - LOG(INFO) << (intptr_t)baseAddr + offset << " (0x" << std::hex << - offset << "): .align4"; - break; - case kPseudoEHBlockLabel: - LOG(INFO) << "Exception_Handling:"; - break; - case kPseudoTargetLabel: - case kPseudoNormalBlockLabel: - LOG(INFO) << "L" << (intptr_t)lir << ":"; - break; - case kPseudoThrowTarget: - LOG(INFO) << "LT" << (intptr_t)lir << ":"; - break; - case kPseudoSuspendTarget: - LOG(INFO) << "LS" << (intptr_t)lir << ":"; - break; - case kPseudoCaseLabel: - LOG(INFO) << "LC" << (intptr_t)lir << ": Case target 0x" << - std::hex << lir->operands[0] << "|" << std::dec << - lir->operands[0]; - break; - default: - if (lir->flags.isNop && !dumpNop) { - break; - } else { - std::string op_name(buildInsnString(EncodingMap[lir->opcode].name, lir, baseAddr)); - std::string op_operands(buildInsnString(EncodingMap[lir->opcode].fmt, lir, baseAddr)); - LOG(INFO) << StringPrintf("%p (%04x): %-9s%s%s", baseAddr + offset, offset, - op_name.c_str(), op_operands.c_str(), lir->flags.isNop ? "(nop)" : ""); - } - break; - } - - if (lir->useMask && (!lir->flags.isNop || dumpNop)) { - DUMP_RESOURCE_MASK(oatDumpResourceMask((LIR* ) lir, - lir->useMask, "use")); - } - if (lir->defMask && (!lir->flags.isNop || dumpNop)) { - DUMP_RESOURCE_MASK(oatDumpResourceMask((LIR* ) lir, - lir->defMask, "def")); - } -} - -void oatDumpPromotionMap(CompilationUnit *cUnit) -{ - for (int i = 0; i < cUnit->numDalvikRegisters; i++) { - PromotionMap vRegMap = cUnit->promotionMap[i]; - char buf[100]; - if (vRegMap.fpLocation == kLocPhysReg) { - snprintf(buf, 100, " : s%d", vRegMap.fpReg & FP_REG_MASK); - } else { - buf[0] = 0; - } - char buf2[100]; - snprintf(buf2, 100, "V[%02d] -> %s%d%s", i, - vRegMap.coreLocation == kLocPhysReg ? - "r" : "SP+", vRegMap.coreLocation == kLocPhysReg ? - vRegMap.coreReg : oatSRegOffset(cUnit, i), buf); - LOG(INFO) << buf2; - } -} - -void oatDumpFullPromotionMap(CompilationUnit *cUnit) -{ - for (int i = 0; i < cUnit->numDalvikRegisters; i++) { - PromotionMap vRegMap = cUnit->promotionMap[i]; - LOG(INFO) << i << " -> " << "CL:" << (int)vRegMap.coreLocation << - ", CR:" << (int)vRegMap.coreReg << ", FL:" << - (int)vRegMap.fpLocation << ", FR:" << (int)vRegMap.fpReg << - ", - " << (int)vRegMap.firstInPair; - } -} - -/* Dump instructions and constant pool contents */ -void oatCodegenDump(CompilationUnit* cUnit) -{ - LOG(INFO) << "/*"; - LOG(INFO) << "Dumping LIR insns for " - << PrettyMethod(cUnit->method_idx, *cUnit->dex_file); - LIR* lirInsn; - LIR* armLIR; - int insnsSize = cUnit->insnsSize; - - LOG(INFO) << "Regs (excluding ins) : " << cUnit->numRegs; - LOG(INFO) << "Ins : " << cUnit->numIns; - LOG(INFO) << "Outs : " << cUnit->numOuts; - LOG(INFO) << "CoreSpills : " << cUnit->numCoreSpills; - LOG(INFO) << "FPSpills : " << cUnit->numFPSpills; - LOG(INFO) << "Padding : " << cUnit->numPadding; - LOG(INFO) << "Frame size : " << cUnit->frameSize; - LOG(INFO) << "Start of ins : " << cUnit->insOffset; - LOG(INFO) << "Start of regs : " << cUnit->regsOffset; - LOG(INFO) << "code size is " << cUnit->totalSize << - " bytes, Dalvik size is " << insnsSize * 2; - LOG(INFO) << "expansion factor: " << - (float)cUnit->totalSize / (float)(insnsSize * 2); - oatDumpPromotionMap(cUnit); - for (lirInsn = cUnit->firstLIRInsn; lirInsn; lirInsn = lirInsn->next) { - oatDumpLIRInsn(cUnit, lirInsn, 0); - } - for (lirInsn = cUnit->classPointerList; lirInsn; lirInsn = lirInsn->next) { - armLIR = (LIR*) lirInsn; - LOG(INFO) << StringPrintf("%x (%04x): .class (%s)", - armLIR->offset, armLIR->offset, - ((CallsiteInfo *) armLIR->operands[0])->classDescriptor); - } - for (lirInsn = cUnit->literalList; lirInsn; lirInsn = lirInsn->next) { - armLIR = (LIR*) lirInsn; - LOG(INFO) << StringPrintf("%x (%04x): .word (%#x)", - armLIR->offset, armLIR->offset, armLIR->operands[0]); - } - - const DexFile::MethodId& method_id = - cUnit->dex_file->GetMethodId(cUnit->method_idx); - std::string signature(cUnit->dex_file->GetMethodSignature(method_id)); - std::string name(cUnit->dex_file->GetMethodName(method_id)); - std::string descriptor(cUnit->dex_file->GetMethodDeclaringClassDescriptor(method_id)); - - // Dump mapping table - if (cUnit->mappingTable.size() > 0) { - std::string line(StringPrintf("\n MappingTable %s%s_%s_mappingTable[%zu] = {", - descriptor.c_str(), name.c_str(), signature.c_str(), cUnit->mappingTable.size())); - std::replace(line.begin(), line.end(), ';', '_'); - LOG(INFO) << line; - for (uint32_t i = 0; i < cUnit->mappingTable.size(); i+=2) { - line = StringPrintf(" {0x%08x, 0x%04x},", - cUnit->mappingTable[i], cUnit->mappingTable[i+1]); - LOG(INFO) << line; - } - LOG(INFO) <<" };\n\n"; - } -} } // namespace art diff --git a/src/compiler/codegen/arm/ArmLIR.h b/src/compiler/codegen/arm/ArmLIR.h index 196bddb37f..e4e9eb83b1 100644 --- a/src/compiler/codegen/arm/ArmLIR.h +++ b/src/compiler/codegen/arm/ArmLIR.h @@ -745,22 +745,6 @@ typedef enum ArmTargetOptHints { extern const ArmEncodingMap EncodingMap[kArmLast]; -typedef struct SwitchTable { - int offset; - const u2* table; // Original dex table - int vaddr; // Dalvik offset of switch opcode - LIR* bxInst; // Switch indirect branch instruction - LIR** targets; // Array of case targets -} SwitchTable; - -typedef struct FillArrayData { - int offset; - const u2* table; // Original dex table - int size; - int vaddr; // Dalvik offset of OP_FILL_ARRAY_DATA opcode -} FillArrayData; - - } // namespace art #endif // ART_SRC_COMPILER_CODEGEN_ARM_ARMLIR_H_ diff --git a/src/compiler/codegen/arm/ArmRallocUtil.cc b/src/compiler/codegen/arm/ArmRallocUtil.cc index a020687210..d44d7cf970 100644 --- a/src/compiler/codegen/arm/ArmRallocUtil.cc +++ b/src/compiler/codegen/arm/ArmRallocUtil.cc @@ -116,6 +116,22 @@ void oatClobberCalleeSave(CompilationUnit *cUnit) oatClobber(cUnit, r3); oatClobber(cUnit, r12); oatClobber(cUnit, r14lr); + oatClobber(cUnit, fr0); + oatClobber(cUnit, fr1); + oatClobber(cUnit, fr2); + oatClobber(cUnit, fr3); + oatClobber(cUnit, fr4); + oatClobber(cUnit, fr5); + oatClobber(cUnit, fr6); + oatClobber(cUnit, fr7); + oatClobber(cUnit, fr8); + oatClobber(cUnit, fr9); + oatClobber(cUnit, fr10); + oatClobber(cUnit, fr11); + oatClobber(cUnit, fr12); + oatClobber(cUnit, fr13); + oatClobber(cUnit, fr14); + oatClobber(cUnit, fr15); } extern RegLocation oatGetReturnWide(CompilationUnit* cUnit) diff --git a/src/compiler/codegen/arm/Codegen.h b/src/compiler/codegen/arm/Codegen.h index a565cb1f37..49e39db837 100644 --- a/src/compiler/codegen/arm/Codegen.h +++ b/src/compiler/codegen/arm/Codegen.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011 The Android Open Source Project + * Copyright (C) 2012 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. diff --git a/src/compiler/codegen/mips/ArchFactory.cc b/src/compiler/codegen/mips/ArchFactory.cc index cb9645de56..2cb0731e0c 100644 --- a/src/compiler/codegen/mips/ArchFactory.cc +++ b/src/compiler/codegen/mips/ArchFactory.cc @@ -22,1096 +22,68 @@ * */ -#define SLOW_FIELD_PATH (cUnit->enableDebug & (1 << kDebugSlowFieldPath)) -#define SLOW_INVOKE_PATH (cUnit->enableDebug & (1 << kDebugSlowInvokePath)) -#define SLOW_STRING_PATH (cUnit->enableDebug & (1 << kDebugSlowStringPath)) -#define SLOW_TYPE_PATH (cUnit->enableDebug & (1 << kDebugSlowTypePath)) -#define EXERCISE_SLOWEST_FIELD_PATH (cUnit->enableDebug & \ - (1 << kDebugSlowestFieldPath)) -#define EXERCISE_SLOWEST_STRING_PATH (cUnit->enableDebug & \ - (1 << kDebugSlowestStringPath)) -#define EXERCISE_RESOLVE_METHOD (cUnit->enableDebug & \ - (1 << kDebugExerciseResolveMethod)) - -// FIXME - this is the Mips version, change to MIPS - namespace art { -STATIC void genDebuggerUpdate(CompilationUnit* cUnit, int32_t offset); - -/* Generate unconditional branch instructions */ -STATIC MipsLIR* genUnconditionalBranch(CompilationUnit* cUnit, MipsLIR* target) -{ - MipsLIR* branch = opNone(cUnit, kOpUncondBr); - branch->generic.target = (LIR*) target; - return branch; -} - -STATIC MipsLIR* callRuntimeHelper(CompilationUnit* cUnit, int reg) -{ - oatClobberCalleeSave(cUnit); - return opReg(cUnit, kOpBlx, reg); -} - -/* - * Mark garbage collection card. Skip if the value we're storing is null. - */ -STATIC void markGCCard(CompilationUnit* cUnit, int valReg, int tgtAddrReg) -{ - int regCardBase = oatAllocTemp(cUnit); - int regCardNo = oatAllocTemp(cUnit); - MipsLIR* branchOver = opCompareBranchCC(cUnit, kMipsCondEq, valReg, r_ZERO); - loadWordDisp(cUnit, rSELF, Thread::CardTableOffset().Int32Value(), - regCardBase); - opRegRegImm(cUnit, kOpLsr, regCardNo, tgtAddrReg, GC_CARD_SHIFT); - storeBaseIndexed(cUnit, regCardBase, regCardNo, regCardBase, 0, - kUnsignedByte); - MipsLIR* target = newLIR0(cUnit, kPseudoTargetLabel); - target->defMask = ENCODE_ALL; - branchOver->generic.target = (LIR*)target; - oatFreeTemp(cUnit, regCardBase); - oatFreeTemp(cUnit, regCardNo); -} - -/* - * Utiltiy to load the current Method*. Broken out - * to allow easy change between placing the current Method* in a - * dedicated register or its home location in the frame. - */ -STATIC void loadCurrMethodDirect(CompilationUnit *cUnit, int rTgt) -{ -#if defined(METHOD_IN_REG) - genRegCopy(cUnit, rTgt, rMETHOD); -#else - loadWordDisp(cUnit, rSP, 0, rTgt); -#endif -} - -STATIC int loadCurrMethod(CompilationUnit *cUnit) -{ -#if defined(METHOD_IN_REG) - return rMETHOD; -#else - int mReg = oatAllocTemp(cUnit); - loadCurrMethodDirect(cUnit, mReg); - return mReg; -#endif -} - -STATIC MipsLIR* genImmedCheck(CompilationUnit* cUnit, MipsConditionCode cCode, - int reg, int immVal, MIR* mir, MipsThrowKind kind) -{ - MipsLIR* tgt = (MipsLIR*)oatNew(cUnit, sizeof(MipsLIR), true, kAllocLIR); - tgt->opcode = kPseudoThrowTarget; - tgt->operands[0] = kind; - tgt->operands[1] = mir->offset; - MipsLIR* branch; - if (cCode == kMipsCondAl) { - branch = genUnconditionalBranch(cUnit, tgt); - } else { - int tReg; - if (immVal == 0) { - tReg = r_ZERO; - } else { - tReg = oatAllocTemp(cUnit); - loadConstant(cUnit, tReg, immVal); - } - branch = opCompareBranchCC(cUnit, cCode, reg, tReg); - branch->generic.target = (LIR*)tgt; - } - // Remember branch target - will process later - oatInsertGrowableList(cUnit, &cUnit->throwLaunchpads, (intptr_t)tgt); - return branch; -} - -/* Perform null-check on a register. */ -STATIC MipsLIR* genNullCheck(CompilationUnit* cUnit, int sReg, int mReg, - MIR* mir) -{ - if (!(cUnit->disableOpt & (1 << kNullCheckElimination)) && - mir->optimizationFlags & MIR_IGNORE_NULL_CHECK) { - return NULL; - } - return genImmedCheck(cUnit, kMipsCondEq, mReg, 0, mir, kMipsThrowNullPointer); -} - -/* Perform check on two registers */ -STATIC TGT_LIR* genRegRegCheck(CompilationUnit* cUnit, MipsConditionCode cCode, - int reg1, int reg2, MIR* mir, MipsThrowKind kind) -{ - MipsLIR* tgt = (MipsLIR*)oatNew(cUnit, sizeof(MipsLIR), true, kAllocLIR); - tgt->opcode = kPseudoThrowTarget; - tgt->operands[0] = kind; - tgt->operands[1] = mir ? mir->offset : 0; - tgt->operands[2] = reg1; - tgt->operands[3] = reg2; - opRegReg(cUnit, kOpCmp, reg1, reg2); - MipsLIR* branch = genConditionalBranch(cUnit, cCode, tgt); - // Remember branch target - will process later - oatInsertGrowableList(cUnit, &cUnit->throwLaunchpads, (intptr_t)tgt); - return branch; -} - -/* - * Let helper function take care of everything. Will call - * Array::AllocFromCode(type_idx, method, count); - * Note: AllocFromCode will handle checks for errNegativeArraySize. - */ -STATIC void genNewArray(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest, - RegLocation rlSrc) -{ - oatFlushAllRegs(cUnit); /* Everything to home location */ - oatLockCallTemps(cUnit); - int addrReg = oatAllocTemp(cUnit); - uint32_t type_idx = mir->dalvikInsn.vC; - if (cUnit->compiler->CanAccessTypeWithoutChecks(cUnit->method_idx, - cUnit->dex_cache, - *cUnit->dex_file, - type_idx)) { - loadWordDisp(cUnit, rSELF, - OFFSETOF_MEMBER(Thread, pAllocArrayFromCode), addrReg); - } else { - loadWordDisp(cUnit, rSELF, - OFFSETOF_MEMBER(Thread, pAllocArrayFromCodeWithAccessCheck), addrReg); - } - loadCurrMethodDirect(cUnit, r_ARG1); // arg1 <- Method* - loadConstant(cUnit, r_ARG0, type_idx); // arg0 <- type_id - loadValueDirectFixed(cUnit, rlSrc, r_ARG2); // arg2 <- count - callRuntimeHelper(cUnit, addrReg); - RegLocation rlResult = oatGetReturn(cUnit); - storeValue(cUnit, rlDest, rlResult); -} - -/* - * Similar to genNewArray, but with post-allocation initialization. - * Verifier guarantees we're dealing with an array class. Current - * code throws runtime exception "bad Filled array req" for 'D' and 'J'. - * Current code also throws internal unimp if not 'L', '[' or 'I'. - */ -STATIC void genFilledNewArray(CompilationUnit* cUnit, MIR* mir, bool isRange) -{ - DecodedInstruction* dInsn = &mir->dalvikInsn; - int elems = dInsn->vA; - int typeId = dInsn->vB; - oatFlushAllRegs(cUnit); /* Everything to home location */ - oatLockCallTemps(cUnit); - int addrReg = oatAllocTemp(cUnit); - if (cUnit->compiler->CanAccessTypeWithoutChecks(cUnit->method_idx, - cUnit->dex_cache, - *cUnit->dex_file, - typeId)) { - loadWordDisp(cUnit, rSELF, - OFFSETOF_MEMBER(Thread, pCheckAndAllocArrayFromCode), - addrReg); - } else { - loadWordDisp(cUnit, rSELF, - OFFSETOF_MEMBER(Thread, - pCheckAndAllocArrayFromCodeWithAccessCheck), addrReg); - } - loadCurrMethodDirect(cUnit, r_ARG1); // arg1 <- Method* - loadConstant(cUnit, r_ARG0, typeId); // arg0 <- type_id - loadConstant(cUnit, r_ARG2, elems); // arg2 <- count - callRuntimeHelper(cUnit, addrReg); - /* - * NOTE: the implicit target for OP_FILLED_NEW_ARRAY is the - * return region. Because AllocFromCode placed the new array - * in r_V0, we'll just lock it into place. When debugger support is - * added, it may be necessary to additionally copy all return - * values to a home location in thread-local storage - */ - oatLockTemp(cUnit, r_V0); - - // Having a range of 0 is legal - if (isRange && (dInsn->vA > 0)) { - /* - * Bit of ugliness here. We're going generate a mem copy loop - * on the register range, but it is possible that some regs - * in the range have been promoted. This is unlikely, but - * before generating the copy, we'll just force a flush - * of any regs in the source range that have been promoted to - * home location. - */ - for (unsigned int i = 0; i < dInsn->vA; i++) { - RegLocation loc = oatUpdateLoc(cUnit, - oatGetSrc(cUnit, mir, i)); - if (loc.location == kLocPhysReg) { - storeBaseDisp(cUnit, rSP, oatSRegOffset(cUnit, loc.sRegLow), - loc.lowReg, kWord); - } - } - /* - * TUNING note: generated code here could be much improved, but - * this is an uncommon operation and isn't especially performance - * critical. - */ - int rSrc = oatAllocTemp(cUnit); - int rDst = oatAllocTemp(cUnit); - int rIdx = oatAllocTemp(cUnit); - int rVal = oatAllocTemp(cUnit); - // Set up source pointer - RegLocation rlFirst = oatGetSrc(cUnit, mir, 0); - opRegRegImm(cUnit, kOpAdd, rSrc, rSP, - oatSRegOffset(cUnit, rlFirst.sRegLow)); - // Set up the target pointer - opRegRegImm(cUnit, kOpAdd, rDst, r_V0, - Array::DataOffset().Int32Value()); - // Set up the loop counter (known to be > 0) - loadConstant(cUnit, rIdx, dInsn->vA - 1); - // Generate the copy loop. Going backwards for convenience - MipsLIR* target = newLIR0(cUnit, kPseudoTargetLabel); - target->defMask = ENCODE_ALL; - // Copy next element - loadBaseIndexed(cUnit, rSrc, rIdx, rVal, 2, kWord); - storeBaseIndexed(cUnit, rDst, rIdx, rVal, 2, kWord); - opRegImm(cUnit, kOpSub, rIdx, 1); - MipsLIR* branch = opCompareBranchCC(cUnit, kMipsCondGe, rIdx, r_ZERO); - branch->generic.target = (LIR*)target; - } else if (!isRange) { - // TUNING: interleave - for (unsigned int i = 0; i < dInsn->vA; i++) { - RegLocation rlArg = loadValue(cUnit, - oatGetSrc(cUnit, mir, i), kCoreReg); - storeBaseDisp(cUnit, r_V0, - Array::DataOffset().Int32Value() + - i * 4, rlArg.lowReg, kWord); - // If the loadValue caused a temp to be allocated, free it - if (oatIsTemp(cUnit, rlArg.lowReg)) { - oatFreeTemp(cUnit, rlArg.lowReg); - } - } - } -} - -STATIC void genSput(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc, - bool isLongOrDouble, bool isObject) -{ - int fieldOffset; - int ssbIndex; - bool isVolatile; - bool isReferrersClass; - uint32_t fieldIdx = mir->dalvikInsn.vB; - bool fastPath = - cUnit->compiler->ComputeStaticFieldInfo(fieldIdx, cUnit, - fieldOffset, ssbIndex, - isReferrersClass, isVolatile, true); - if (fastPath && !SLOW_FIELD_PATH) { - DCHECK_GE(fieldOffset, 0); - int rBase; - int rMethod; - if (isReferrersClass) { - // Fast path, static storage base is this method's class - rMethod = loadCurrMethod(cUnit); - rBase = oatAllocTemp(cUnit); - loadWordDisp(cUnit, rMethod, - Method::DeclaringClassOffset().Int32Value(), rBase); - } else { - // Medium path, static storage base in a different class which - // requires checks that the other class is initialized. - DCHECK_GE(ssbIndex, 0); - // May do runtime call so everything to home locations. - oatFlushAllRegs(cUnit); - // Using fixed register to sync with possible call to runtime - // support. - oatLockCallTemps(cUnit); - rMethod = r1; - oatLockTemp(cUnit, rMethod); - loadCurrMethodDirect(cUnit, rMethod); - rBase = r0; - oatLockTemp(cUnit, rBase); - loadWordDisp(cUnit, rMethod, - Method::DexCacheInitializedStaticStorageOffset().Int32Value(), - rBase); - loadWordDisp(cUnit, rBase, - Array::DataOffset().Int32Value() + sizeof(int32_t*) * - ssbIndex, rBase); - // rBase now points at appropriate static storage base (Class*) - // or NULL if not initialized. Check for NULL and call helper if NULL. - // TUNING: fast path should fall through - MipsLIR* branchOver = opCmpImmBranchCC(cUnit, kMipsCondNe, - rBase, 0); - loadWordDisp(cUnit, rSELF, - OFFSETOF_MEMBER(Thread, pInitializeStaticStorage), rLR); - loadConstant(cUnit, r0, ssbIndex); - callRuntimeHelper(cUnit, rLR); - MipsLIR* skipTarget = newLIR0(cUnit, kPseudoTargetLabel); - skipTarget->defMask = ENCODE_ALL; - branchOver->generic.target = (LIR*)skipTarget; - } - // rBase now holds static storage base - oatFreeTemp(cUnit, rMethod); - if (isLongOrDouble) { - rlSrc = oatGetSrcWide(cUnit, mir, 0, 1); - rlSrc = loadValueWide(cUnit, rlSrc, kAnyReg); - } else { - rlSrc = oatGetSrc(cUnit, mir, 0); - rlSrc = loadValue(cUnit, rlSrc, kAnyReg); - } - if (isVolatile) { - oatGenMemBarrier(cUnit, kST); - } - if (isLongOrDouble) { - storeBaseDispWide(cUnit, rBase, fieldOffset, rlSrc.lowReg, - rlSrc.highReg); - } else { - storeWordDisp(cUnit, rBase, fieldOffset, rlSrc.lowReg); - } - if (isVolatile) { - oatGenMemBarrier(cUnit, kSY); - } - if (isObject) { - markGCCard(cUnit, rlSrc.lowReg, rBase); - } - oatFreeTemp(cUnit, rBase); - } else { - oatFlushAllRegs(cUnit); // Everything to home locations - int setterOffset = isLongOrDouble ? OFFSETOF_MEMBER(Thread, pSet64Static) : - (isObject ? OFFSETOF_MEMBER(Thread, pSetObjStatic) - : OFFSETOF_MEMBER(Thread, pSet32Static)); - loadWordDisp(cUnit, rSELF, setterOffset, rLR); - loadConstant(cUnit, r0, fieldIdx); - if (isLongOrDouble) { - loadValueDirectWideFixed(cUnit, rlSrc, r2, r3); - } else { - loadValueDirect(cUnit, rlSrc, r1); - } - callRuntimeHelper(cUnit, rLR); - } -} - -STATIC void genSget(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest, - bool isLongOrDouble, bool isObject) -{ - UNIMPLEMENTED(FATAL) << "Needs mips version"; -#if 0 - int fieldOffset; - int ssbIndex; - bool isVolatile; - bool isReferrersClass; - uint32_t fieldIdx = mir->dalvikInsn.vB; - bool fastPath = - cUnit->compiler->ComputeStaticFieldInfo(fieldIdx, cUnit, - fieldOffset, ssbIndex, - isReferrersClass, isVolatile, false); - if (fastPath && !SLOW_FIELD_PATH) { - DCHECK_GE(fieldOffset, 0); - int rBase; - int rMethod; - if (isReferrersClass) { - // Fast path, static storage base is this method's class - rMethod = loadCurrMethod(cUnit); - rBase = oatAllocTemp(cUnit); - loadWordDisp(cUnit, rMethod, - Method::DeclaringClassOffset().Int32Value(), rBase); - } else { - // Medium path, static storage base in a different class which - // requires checks that the other class is initialized - DCHECK_GE(ssbIndex, 0); - // May do runtime call so everything to home locations. - oatFlushAllRegs(cUnit); - // Using fixed register to sync with possible call to runtime - // support - rMethod = r1; - oatLockTemp(cUnit, rMethod); - loadCurrMethodDirect(cUnit, rMethod); - rBase = r0; - oatLockTemp(cUnit, rBase); - loadWordDisp(cUnit, rMethod, - Method::DexCacheInitializedStaticStorageOffset().Int32Value(), - rBase); - loadWordDisp(cUnit, rBase, - Array::DataOffset().Int32Value() + sizeof(int32_t*) * ssbIndex, - rBase); - // rBase now points at appropriate static storage base (Class*) - // or NULL if not initialized. Check for NULL and call helper if NULL. - // TUNING: fast path should fall through - MipsLIR* branchOver = opCmpImmBranchCC(cUnit, kMipsCondNe, rBase, 0); - loadWordDisp(cUnit, rSELF, - OFFSETOF_MEMBER(Thread, pInitializeStaticStorage), rLR); - loadConstant(cUnit, r0, ssbIndex); - callRuntimeHelper(cUnit, rLR); - MipsLIR* skipTarget = newLIR0(cUnit, kPseudoTargetLabel); - skipTarget->defMask = ENCODE_ALL; - branchOver->generic.target = (LIR*)skipTarget; - } - // rBase now holds static storage base - oatFreeTemp(cUnit, rMethod); - rlDest = isLongOrDouble ? oatGetDestWide(cUnit, mir, 0, 1) - : oatGetDest(cUnit, mir, 0); - RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true); - if (isVolatile) { - oatGenMemBarrier(cUnit, kSY); - } - if (isLongOrDouble) { - loadBaseDispWide(cUnit, NULL, rBase, fieldOffset, rlResult.lowReg, - rlResult.highReg, INVALID_SREG); - } else { - loadWordDisp(cUnit, rBase, fieldOffset, rlResult.lowReg); - } - oatFreeTemp(cUnit, rBase); - if (isLongOrDouble) { - storeValueWide(cUnit, rlDest, rlResult); - } else { - storeValue(cUnit, rlDest, rlResult); - } - } else { - oatFlushAllRegs(cUnit); // Everything to home locations - int getterOffset = isLongOrDouble ? OFFSETOF_MEMBER(Thread, pGet64Static) : - (isObject ? OFFSETOF_MEMBER(Thread, pGetObjStatic) - : OFFSETOF_MEMBER(Thread, pGet32Static)); - loadWordDisp(cUnit, rSELF, getterOffset, rLR); - loadConstant(cUnit, r0, fieldIdx); - callRuntimeHelper(cUnit, rLR); - if (isLongOrDouble) { - RegLocation rlResult = oatGetReturnWide(cUnit); - storeValueWide(cUnit, rlDest, rlResult); - } else { - RegLocation rlResult = oatGetReturn(cUnit); - storeValue(cUnit, rlDest, rlResult); - } - } -#endif -} - -typedef int (*NextCallInsn)(CompilationUnit*, MIR*, int, uint32_t dexIdx, - uint32_t methodIdx); - -/* - * Bit of a hack here - in leiu of a real scheduling pass, - * emit the next instruction in static & direct invoke sequences. - */ -STATIC int nextSDCallInsn(CompilationUnit* cUnit, MIR* mir, - int state, uint32_t dexIdx, uint32_t unused) -{ - UNIMPLEMENTED(FATAL) << "Needs mips version"; -#if 0 - switch(state) { - case 0: // Get the current Method* [sets r0] - loadCurrMethodDirect(cUnit, r0); - break; - case 1: // Get method->code_and_direct_methods_ - loadWordDisp(cUnit, r0, - Method::GetDexCacheCodeAndDirectMethodsOffset().Int32Value(), - r0); - break; - case 2: // Grab target method* and target code_ - loadWordDisp(cUnit, r0, - CodeAndDirectMethods::CodeOffsetInBytes(dexIdx), rLR); - loadWordDisp(cUnit, r0, - CodeAndDirectMethods::MethodOffsetInBytes(dexIdx), r0); - break; - default: - return -1; - } -#endif - return state + 1; -} - -/* - * Bit of a hack here - in leiu of a real scheduling pass, - * emit the next instruction in a virtual invoke sequence. - * We can use rLR as a temp prior to target address loading - * Note also that we'll load the first argument ("this") into - * r1 here rather than the standard loadArgRegs. - */ -STATIC int nextVCallInsn(CompilationUnit* cUnit, MIR* mir, - int state, uint32_t dexIdx, uint32_t methodIdx) -{ - UNIMPLEMENTED(FATAL) << "Needs mips version"; -#if 0 - RegLocation rlArg; - /* - * This is the fast path in which the target virtual method is - * fully resolved at compile time. - */ - switch(state) { - case 0: // Get "this" [set r1] - rlArg = oatGetSrc(cUnit, mir, 0); - loadValueDirectFixed(cUnit, rlArg, r1); - break; - case 1: // Is "this" null? [use r1] - genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir); - // get this->klass_ [use r1, set rLR] - loadWordDisp(cUnit, r1, Object::ClassOffset().Int32Value(), rLR); - break; - case 2: // Get this->klass_->vtable [usr rLR, set rLR] - loadWordDisp(cUnit, rLR, Class::VTableOffset().Int32Value(), rLR); - break; - case 3: // Get target method [use rLR, set r0] - loadWordDisp(cUnit, rLR, (methodIdx * 4) + - Array::DataOffset().Int32Value(), r0); - break; - case 4: // Get the target compiled code address [uses r0, sets rLR] - loadWordDisp(cUnit, r0, Method::GetCodeOffset().Int32Value(), rLR); - break; - default: - return -1; - } -#endif - return state + 1; -} +void genDebuggerUpdate(CompilationUnit* cUnit, int32_t offset); /* - * Interleave launch code for INVOKE_SUPER. See comments - * for nextVCallIns. + * In the Arm code a it is typical to use the link register + * to hold the target address. However, for Mips we must + * ensure that all branch instructions can be restarted if + * there is a trap in the shadow. Allocate a temp register. */ -STATIC int nextSuperCallInsn(CompilationUnit* cUnit, MIR* mir, - int state, uint32_t dexIdx, uint32_t methodIdx) -{ - UNIMPLEMENTED(FATAL) << "Needs mips version"; -#if 0 - /* - * This is the fast path in which the target virtual method is - * fully resolved at compile time. Note also that this path assumes - * that the check to verify that the target method index falls - * within the size of the super's vtable has been done at compile-time. - */ - RegLocation rlArg; - switch(state) { - case 0: // Get current Method* [set r0] - loadCurrMethodDirect(cUnit, r0); - // Load "this" [set r1] - rlArg = oatGetSrc(cUnit, mir, 0); - loadValueDirectFixed(cUnit, rlArg, r1); - // Get method->declaring_class_ [use r0, set rLR] - loadWordDisp(cUnit, r0, Method::DeclaringClassOffset().Int32Value(), - rLR); - // Is "this" null? [use r1] - genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir); - break; - case 1: // Get method->declaring_class_->super_class [usr rLR, set rLR] - loadWordDisp(cUnit, rLR, Class::SuperClassOffset().Int32Value(), - rLR); - break; - case 2: // Get ...->super_class_->vtable [u/s rLR] - loadWordDisp(cUnit, rLR, Class::VTableOffset().Int32Value(), rLR); - break; - case 3: // Get target method [use rLR, set r0] - loadWordDisp(cUnit, rLR, (methodIdx * 4) + - Array::DataOffset().Int32Value(), r0); - break; - case 4: // Get the target compiled code address [uses r0, sets rLR] - loadWordDisp(cUnit, r0, Method::GetCodeOffset().Int32Value(), rLR); - break; - default: - return -1; - } -#endif - return state + 1; -} - -STATIC int nextInvokeInsnSP(CompilationUnit* cUnit, MIR* mir, int trampoline, - int state, uint32_t dexIdx, uint32_t methodIdx) -{ - UNIMPLEMENTED(FATAL) << "Needs mips version"; -#if 0 - /* - * This handles the case in which the base method is not fully - * resolved at compile time, we bail to a runtime helper. - */ - if (state == 0) { - // Load trampoline target - loadWordDisp(cUnit, rSELF, trampoline, rLR); - // Load r0 with method index - loadConstant(cUnit, r0, dexIdx); - return 1; - } -#endif - return -1; -} - -STATIC int nextStaticCallInsnSP(CompilationUnit* cUnit, MIR* mir, - int state, uint32_t dexIdx, uint32_t methodIdx) -{ - int trampoline = OFFSETOF_MEMBER(Thread, pInvokeStaticTrampolineWithAccessCheck); - return nextInvokeInsnSP(cUnit, mir, trampoline, state, dexIdx, 0); -} - -STATIC int nextDirectCallInsnSP(CompilationUnit* cUnit, MIR* mir, - int state, uint32_t dexIdx, uint32_t methodIdx) +int loadHelper(CompilationUnit* cUnit, int offset) { - int trampoline = OFFSETOF_MEMBER(Thread, pInvokeDirectTrampolineWithAccessCheck); - return nextInvokeInsnSP(cUnit, mir, trampoline, state, dexIdx, 0); + int tReg = oatAllocTemp(cUnit); + loadWordDisp(cUnit, rSELF, offset, tReg); + return tReg; } -STATIC int nextSuperCallInsnSP(CompilationUnit* cUnit, MIR* mir, - int state, uint32_t dexIdx, uint32_t methodIdx) +void spillCoreRegs(CompilationUnit* cUnit) { - int trampoline = OFFSETOF_MEMBER(Thread, pInvokeSuperTrampolineWithAccessCheck); - return nextInvokeInsnSP(cUnit, mir, trampoline, state, dexIdx, 0); -} - -STATIC int nextVCallInsnSP(CompilationUnit* cUnit, MIR* mir, - int state, uint32_t dexIdx, uint32_t methodIdx) -{ - int trampoline = OFFSETOF_MEMBER(Thread, pInvokeVirtualTrampolineWithAccessCheck); - return nextInvokeInsnSP(cUnit, mir, trampoline, state, dexIdx, 0); -} - -/* - * All invoke-interface calls bounce off of art_invoke_interface_trampoline, - * which will locate the target and continue on via a tail call. - */ -STATIC int nextInterfaceCallInsn(CompilationUnit* cUnit, MIR* mir, - int state, uint32_t dexIdx, uint32_t unused) -{ - int trampoline = OFFSETOF_MEMBER(Thread, pInvokeInterfaceTrampoline); - return nextInvokeInsnSP(cUnit, mir, trampoline, state, dexIdx, 0); -} - -STATIC int nextInterfaceCallInsnWithAccessCheck(CompilationUnit* cUnit, - MIR* mir, int state, - uint32_t dexIdx, - uint32_t unused) -{ - int trampoline = OFFSETOF_MEMBER(Thread, pInvokeInterfaceTrampolineWithAccessCheck); - return nextInvokeInsnSP(cUnit, mir, trampoline, state, dexIdx, 0); -} - -STATIC int loadArgRegs(CompilationUnit* cUnit, MIR* mir, - DecodedInstruction* dInsn, int callState, - NextCallInsn nextCallInsn, uint32_t dexIdx, - uint32_t methodIdx, bool skipThis) -{ - UNIMPLEMENTED(FATAL) << "Needs mips version"; -#if 0 - int nextReg = r1; - int nextArg = 0; - if (skipThis) { - nextReg++; - nextArg++; - } - for (; (nextReg <= r3) && (nextArg < mir->ssaRep->numUses); nextReg++) { - RegLocation rlArg = oatGetRawSrc(cUnit, mir, nextArg++); - rlArg = oatUpdateRawLoc(cUnit, rlArg); - if (rlArg.wide && (nextReg <= r2)) { - loadValueDirectWideFixed(cUnit, rlArg, nextReg, nextReg + 1); - nextReg++; - nextArg++; - } else { - rlArg.wide = false; - loadValueDirectFixed(cUnit, rlArg, nextReg); - } - callState = nextCallInsn(cUnit, mir, callState, dexIdx, methodIdx); + if (cUnit->numCoreSpills == 0) { + return; } -#endif - return callState; -} - -/* - * Load up to 5 arguments, the first three of which will be in - * r1 .. r3. On entry r0 contains the current method pointer, - * and as part of the load sequence, it must be replaced with - * the target method pointer. Note, this may also be called - * for "range" variants if the number of arguments is 5 or fewer. - */ -STATIC int genDalvikArgsNoRange(CompilationUnit* cUnit, MIR* mir, - DecodedInstruction* dInsn, int callState, - MipsLIR** pcrLabel, NextCallInsn nextCallInsn, - uint32_t dexIdx, uint32_t methodIdx, - bool skipThis) -{ - UNIMPLEMENTED(FATAL) << "Needs mips version"; -#if 0 - RegLocation rlArg; - - /* If no arguments, just return */ - if (dInsn->vA == 0) - return callState; - - callState = nextCallInsn(cUnit, mir, callState, dexIdx, methodIdx); - - DCHECK_LE(dInsn->vA, 5U); - if (dInsn->vA > 3) { - uint32_t nextUse = 3; - //Detect special case of wide arg spanning arg3/arg4 - RegLocation rlUse0 = oatGetRawSrc(cUnit, mir, 0); - RegLocation rlUse1 = oatGetRawSrc(cUnit, mir, 1); - RegLocation rlUse2 = oatGetRawSrc(cUnit, mir, 2); - if (((!rlUse0.wide && !rlUse1.wide) || rlUse0.wide) && - rlUse2.wide) { - int reg; - // Wide spans, we need the 2nd half of uses[2]. - rlArg = oatUpdateLocWide(cUnit, rlUse2); - if (rlArg.location == kLocPhysReg) { - reg = rlArg.highReg; - } else { - // r2 & r3 can safely be used here - reg = r3; - loadWordDisp(cUnit, rSP, - oatSRegOffset(cUnit, rlArg.sRegLow) + 4, reg); - callState = nextCallInsn(cUnit, mir, callState, dexIdx, - methodIdx); - } - storeBaseDisp(cUnit, rSP, (nextUse + 1) * 4, reg, kWord); - storeBaseDisp(cUnit, rSP, 16 /* (3+1)*4 */, reg, kWord); - callState = nextCallInsn(cUnit, mir, callState, dexIdx, methodIdx); - nextUse++; - } - // Loop through the rest - while (nextUse < dInsn->vA) { - int lowReg; - int highReg; - rlArg = oatGetRawSrc(cUnit, mir, nextUse); - rlArg = oatUpdateRawLoc(cUnit, rlArg); - if (rlArg.location == kLocPhysReg) { - lowReg = rlArg.lowReg; - highReg = rlArg.highReg; - } else { - lowReg = r2; - highReg = r3; - if (rlArg.wide) { - loadValueDirectWideFixed(cUnit, rlArg, lowReg, highReg); - } else { - loadValueDirectFixed(cUnit, rlArg, lowReg); - } - callState = nextCallInsn(cUnit, mir, callState, dexIdx, - methodIdx); - } - int outsOffset = (nextUse + 1) * 4; - if (rlArg.wide) { - storeBaseDispWide(cUnit, rSP, outsOffset, lowReg, highReg); - nextUse += 2; - } else { - storeWordDisp(cUnit, rSP, outsOffset, lowReg); - nextUse++; - } - callState = nextCallInsn(cUnit, mir, callState, dexIdx, methodIdx); + uint32_t mask = cUnit->coreSpillMask; + int offset = cUnit->numCoreSpills * 4; + opRegImm(cUnit, kOpSub, rSP, offset); + for (int reg = 0; mask; mask >>= 1, reg++) { + if (mask & 0x1) { + offset -= 4; + storeWordDisp(cUnit, rSP, offset, reg); } } - - callState = loadArgRegs(cUnit, mir, dInsn, callState, nextCallInsn, - dexIdx, methodIdx, skipThis); - - if (pcrLabel) { - *pcrLabel = genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir); - } -#endif - return callState; } -/* - * May have 0+ arguments (also used for jumbo). Note that - * source virtual registers may be in physical registers, so may - * need to be flushed to home location before copying. This - * applies to arg3 and above (see below). - * - * Two general strategies: - * If < 20 arguments - * Pass args 3-18 using vldm/vstm block copy - * Pass arg0, arg1 & arg2 in r1-r3 - * If 20+ arguments - * Pass args arg19+ using memcpy block copy - * Pass arg0, arg1 & arg2 in r1-r3 - * - */ -STATIC int genDalvikArgsRange(CompilationUnit* cUnit, MIR* mir, - DecodedInstruction* dInsn, int callState, - MipsLIR** pcrLabel, NextCallInsn nextCallInsn, - uint32_t dexIdx, uint32_t methodIdx, - bool skipThis) +void unSpillCoreRegs(CompilationUnit* cUnit) { - UNIMPLEMENTED(FATAL) << "Needs mips version"; -#if 0 - int firstArg = dInsn->vC; - int numArgs = dInsn->vA; - - // If we can treat it as non-range (Jumbo ops will use range form) - if (numArgs <= 5) - return genDalvikArgsNoRange(cUnit, mir, dInsn, callState, pcrLabel, - nextCallInsn, dexIdx, methodIdx, - skipThis); - /* - * Make sure range list doesn't span the break between in normal - * Dalvik vRegs and the ins. - */ - int highestArg = oatGetSrc(cUnit, mir, numArgs-1).sRegLow; - int boundaryReg = cUnit->numDalvikRegisters - cUnit->numIns; - if ((firstArg < boundaryReg) && (highestArg >= boundaryReg)) { - LOG(FATAL) << "Argument list spanned locals & args"; - } - - /* - * First load the non-register arguments. Both forms expect all - * of the source arguments to be in their home frame location, so - * scan the sReg names and flush any that have been promoted to - * frame backing storage. - */ - // Scan the rest of the args - if in physReg flush to memory - for (int nextArg = 0; nextArg < numArgs;) { - RegLocation loc = oatGetRawSrc(cUnit, mir, nextArg); - if (loc.wide) { - loc = oatUpdateLocWide(cUnit, loc); - if ((nextArg >= 2) && (loc.location == kLocPhysReg)) { - storeBaseDispWide(cUnit, rSP, - oatSRegOffset(cUnit, loc.sRegLow), - loc.lowReg, loc.highReg); - } - nextArg += 2; - } else { - loc = oatUpdateLoc(cUnit, loc); - if ((nextArg >= 3) && (loc.location == kLocPhysReg)) { - storeBaseDisp(cUnit, rSP, oatSRegOffset(cUnit, loc.sRegLow), - loc.lowReg, kWord); - } - nextArg++; - } - } - - int startOffset = oatSRegOffset(cUnit, - cUnit->regLocation[mir->ssaRep->uses[3]].sRegLow); - int outsOffset = 4 /* Method* */ + (3 * 4); - if (numArgs >= 20) { - // Generate memcpy - opRegRegImm(cUnit, kOpAdd, r0, rSP, outsOffset); - opRegRegImm(cUnit, kOpAdd, r1, rSP, startOffset); - loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pMemcpy), rLR); - loadConstant(cUnit, r2, (numArgs - 3) * 4); - callRuntimeHelper(cUnit, rLR); - // Restore Method* - loadCurrMethodDirect(cUnit, r0); - } else { - // Use vldm/vstm pair using r3 as a temp - int regsLeft = std::min(numArgs - 3, 16); - callState = nextCallInsn(cUnit, mir, callState, dexIdx, methodIdx); - opRegRegImm(cUnit, kOpAdd, r3, rSP, startOffset); - MipsLIR* ld = newLIR3(cUnit, kThumb2Vldms, r3, fr0, regsLeft); - //TUNING: loosen barrier - ld->defMask = ENCODE_ALL; - setMemRefType(ld, true /* isLoad */, kDalvikReg); - callState = nextCallInsn(cUnit, mir, callState, dexIdx, methodIdx); - opRegRegImm(cUnit, kOpAdd, r3, rSP, 4 /* Method* */ + (3 * 4)); - callState = nextCallInsn(cUnit, mir, callState, dexIdx, methodIdx); - MipsLIR* st = newLIR3(cUnit, kThumb2Vstms, r3, fr0, regsLeft); - setMemRefType(st, false /* isLoad */, kDalvikReg); - st->defMask = ENCODE_ALL; - callState = nextCallInsn(cUnit, mir, callState, dexIdx, methodIdx); - } - - callState = loadArgRegs(cUnit, mir, dInsn, callState, nextCallInsn, - dexIdx, methodIdx, skipThis); - - callState = nextCallInsn(cUnit, mir, callState, dexIdx, methodIdx); - if (pcrLabel) { - *pcrLabel = genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir); - } -#endif - return callState; -} - -// Debugging routine - if null target, branch to DebugMe -STATIC void genShowTarget(CompilationUnit* cUnit) -{ - UNIMPLEMENTED(FATAL) << "Needs mips version"; -#if 0 - MipsLIR* branchOver = opCmpImmBranch(cUnit, kMipsCondNe, rLR, 0); - loadWordDisp(cUnit, rSELF, - OFFSETOF_MEMBER(Thread, pDebugMe), rLR); - MipsLIR* target = newLIR0(cUnit, kPseudoTargetLabel); - target->defMask = -1; - branchOver->generic.target = (LIR*)target; -#endif -} - -STATIC void genThrowVerificationError(CompilationUnit* cUnit, MIR* mir) -{ - UNIMPLEMENTED(FATAL) << "Needs mips version"; -#if 0 - loadWordDisp(cUnit, rSELF, - OFFSETOF_MEMBER(Thread, pThrowVerificationErrorFromCode), rLR); - loadConstant(cUnit, r0, mir->dalvikInsn.vA); - loadConstant(cUnit, r1, mir->dalvikInsn.vB); - callRuntimeHelper(cUnit, rLR); -#endif -} - -STATIC void genCompareAndBranch(CompilationUnit* cUnit, BasicBlock* bb, - MIR* mir, RegLocation rlSrc1, - RegLocation rlSrc2, MipsLIR* labelList) -{ - UNIMPLEMENTED(FATAL) << "Needs mips version"; -#if 0 - MipsConditionCode cond; - rlSrc1 = loadValue(cUnit, rlSrc1, kCoreReg); - rlSrc2 = loadValue(cUnit, rlSrc2, kCoreReg); - opRegReg(cUnit, kOpCmp, rlSrc1.lowReg, rlSrc2.lowReg); - Opcode opcode = mir->dalvikInsn.opcode; - switch(opcode) { - case OP_IF_EQ: - cond = kMipsCondEq; - break; - case OP_IF_NE: - cond = kMipsCondNe; - break; - case OP_IF_LT: - cond = kMipsCondLt; - break; - case OP_IF_GE: - cond = kMipsCondGe; - break; - case OP_IF_GT: - cond = kMipsCondGt; - break; - case OP_IF_LE: - cond = kMipsCondLe; - break; - default: - cond = (MipsConditionCode)0; - LOG(FATAL) << "Unexpected opcode " << (int)opcode; - } - genConditionalBranch(cUnit, cond, &labelList[bb->taken->id]); - genUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]); -#endif -} - -STATIC void genCompareZeroAndBranch(CompilationUnit* cUnit, BasicBlock* bb, - MIR* mir, RegLocation rlSrc, - MipsLIR* labelList) -{ - UNIMPLEMENTED(FATAL) << "Needs mips version"; -#if 0 - MipsConditionCode cond; - rlSrc = loadValue(cUnit, rlSrc, kCoreReg); - opRegImm(cUnit, kOpCmp, rlSrc.lowReg, 0); - Opcode opcode = mir->dalvikInsn.opcode; - switch(opcode) { - case OP_IF_EQZ: - cond = kMipsCondEq; - break; - case OP_IF_NEZ: - cond = kMipsCondNe; - break; - case OP_IF_LTZ: - cond = kMipsCondLt; - break; - case OP_IF_GEZ: - cond = kMipsCondGe; - break; - case OP_IF_GTZ: - cond = kMipsCondGt; - break; - case OP_IF_LEZ: - cond = kMipsCondLe; - break; - default: - cond = (MipsConditionCode)0; - LOG(FATAL) << "Unexpected opcode " << (int)opcode; - } - genConditionalBranch(cUnit, cond, &labelList[bb->taken->id]); - genUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]); -#endif -} - -STATIC void genIntToLong(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest, - RegLocation rlSrc) -{ - UNIMPLEMENTED(FATAL) << "Needs mips version"; -#if 0 - RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true); - if (rlSrc.location == kLocPhysReg) { - genRegCopy(cUnit, rlResult.lowReg, rlSrc.lowReg); - } else { - loadValueDirect(cUnit, rlSrc, rlResult.lowReg); - } - opRegRegImm(cUnit, kOpAsr, rlResult.highReg, - rlResult.lowReg, 31); - storeValueWide(cUnit, rlDest, rlResult); -#endif -} - -STATIC void genIntNarrowing(CompilationUnit* cUnit, MIR* mir, - RegLocation rlDest, RegLocation rlSrc) -{ - UNIMPLEMENTED(FATAL) << "Needs mips version"; -#if 0 - rlSrc = loadValue(cUnit, rlSrc, kCoreReg); - RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true); - OpKind op = kOpInvalid; - switch(mir->dalvikInsn.opcode) { - case OP_INT_TO_BYTE: - op = kOp2Byte; - break; - case OP_INT_TO_SHORT: - op = kOp2Short; - break; - case OP_INT_TO_CHAR: - op = kOp2Char; - break; - default: - LOG(ERROR) << "Bad int conversion type"; - } - opRegReg(cUnit, op, rlResult.lowReg, rlSrc.lowReg); - storeValue(cUnit, rlDest, rlResult); -#endif -} - -/* - * If there are any ins passed in registers that have not been promoted - * to a callee-save register, flush them to the frame. Perform intial - * assignment of promoted arguments. - */ -STATIC void flushIns(CompilationUnit* cUnit) -{ - UNIMPLEMENTED(FATAL) << "Needs mips version"; -#if 0 - if (cUnit->numIns == 0) + if (cUnit->numCoreSpills == 0) { return; - int firstArgReg = r1; - int lastArgReg = r3; - int startVReg = cUnit->numDalvikRegisters - cUnit->numIns; - /* - * Arguments passed in registers should be flushed - * to their backing locations in the frame for now. - * Also, we need to do initial assignment for promoted - * arguments. NOTE: an older version of dx had an issue - * in which it would reuse static method argument registers. - * This could result in the same Dalvik virtual register - * being promoted to both core and fp regs. In those - * cases, copy argument to both. This will be uncommon - * enough that it isn't worth attempting to optimize. - */ - for (int i = 0; i < cUnit->numIns; i++) { - PromotionMap vMap = cUnit->promotionMap[startVReg + i]; - if (i <= (lastArgReg - firstArgReg)) { - // If arriving in register - if (vMap.coreLocation == kLocPhysReg) { - genRegCopy(cUnit, vMap.coreReg, firstArgReg + i); - } - if (vMap.fpLocation == kLocPhysReg) { - genRegCopy(cUnit, vMap.fpReg, firstArgReg + i); - } - // Also put a copy in memory in case we're partially promoted - storeBaseDisp(cUnit, rSP, oatSRegOffset(cUnit, startVReg + i), - firstArgReg + i, kWord); - } else { - // If arriving in frame & promoted - if (vMap.coreLocation == kLocPhysReg) { - loadWordDisp(cUnit, rSP, oatSRegOffset(cUnit, startVReg + i), - vMap.coreReg); - } - if (vMap.fpLocation == kLocPhysReg) { - loadWordDisp(cUnit, rSP, oatSRegOffset(cUnit, startVReg + i), - vMap.fpReg); - } + } + uint32_t mask = cUnit->coreSpillMask; + int offset = cUnit->frameSize; + for (int reg = 0; mask; mask >>= 1, reg++) { + if (mask & 0x1) { + offset -= 4; + loadWordDisp(cUnit, rSP, offset, reg); } } -#endif + opRegImm(cUnit, kOpAdd, rSP, cUnit->frameSize); } -STATIC void genEntrySequence(CompilationUnit* cUnit, BasicBlock* bb) +void genEntrySequence(CompilationUnit* cUnit, BasicBlock* bb) { - UNIMPLEMENTED(FATAL) << "Needs mips version"; -#if 0 int spillCount = cUnit->numCoreSpills + cUnit->numFPSpills; /* - * On entry, r0, r1, r2 & r3 are live. Let the register allocation - * mechanism know so it doesn't try to use any of them when + * On entry, rARG0, rARG1, rARG2 & rARG3 are live. Let the register + * allocation mechanism know so it doesn't try to use any of them when * expanding the frame or flushing. This leaves the utility * code with a single temp: r12. This should be enough. */ - oatLockTemp(cUnit, r0); - oatLockTemp(cUnit, r1); - oatLockTemp(cUnit, r2); - oatLockTemp(cUnit, r3); + oatLockTemp(cUnit, rARG0); + oatLockTemp(cUnit, rARG1); + oatLockTemp(cUnit, rARG2); + oatLockTemp(cUnit, rARG3); /* * We can safely skip the stack overflow check if we're @@ -1121,33 +93,28 @@ STATIC void genEntrySequence(CompilationUnit* cUnit, BasicBlock* bb) ((size_t)cUnit->frameSize < Thread::kStackOverflowReservedBytes)); newLIR0(cUnit, kPseudoMethodEntry); + int checkReg = oatAllocTemp(cUnit); + int newSP = oatAllocTemp(cUnit); if (!skipOverflowCheck) { /* Load stack limit */ loadWordDisp(cUnit, rSELF, - Thread::StackEndOffset().Int32Value(), r12); + Thread::StackEndOffset().Int32Value(), checkReg); } /* Spill core callee saves */ - newLIR1(cUnit, kThumb2Push, cUnit->coreSpillMask); - /* Need to spill any FP regs? */ - if (cUnit->numFPSpills) { - /* - * NOTE: fp spills are a little different from core spills in that - * they are pushed as a contiguous block. When promoting from - * the fp set, we must allocate all singles from s16..highest-promoted - */ - newLIR1(cUnit, kThumb2VPushCS, cUnit->numFPSpills); - } + spillCoreRegs(cUnit); + /* NOTE: promotion of FP regs currently unsupported, thus no FP spill */ + DCHECK_EQ(cUnit->numFPSpills, 0); if (!skipOverflowCheck) { - opRegRegImm(cUnit, kOpSub, rLR, rSP, + opRegRegImm(cUnit, kOpSub, newSP, rSP, cUnit->frameSize - (spillCount * 4)); - genRegRegCheck(cUnit, kMipsCondCc, rLR, r12, NULL, - kMipsThrowStackOverflow); - genRegCopy(cUnit, rSP, rLR); // Establish stack + genRegRegCheck(cUnit, kCondCc, newSP, checkReg, NULL, + kThrowStackOverflow); + genRegCopy(cUnit, rSP, newSP); // Establish stack } else { opRegImm(cUnit, kOpSub, rSP, cUnit->frameSize - (spillCount * 4)); } - storeBaseDisp(cUnit, rSP, 0, r0, kWord); + storeBaseDisp(cUnit, rSP, 0, rARG0, kWord); flushIns(cUnit); if (cUnit->genDebugger) { @@ -1157,46 +124,28 @@ STATIC void genEntrySequence(CompilationUnit* cUnit, BasicBlock* bb) genDebuggerUpdate(cUnit, DEBUGGER_METHOD_ENTRY); } - oatFreeTemp(cUnit, r0); - oatFreeTemp(cUnit, r1); - oatFreeTemp(cUnit, r2); - oatFreeTemp(cUnit, r3); -#endif + oatFreeTemp(cUnit, rARG0); + oatFreeTemp(cUnit, rARG1); + oatFreeTemp(cUnit, rARG2); + oatFreeTemp(cUnit, rARG3); } -STATIC void genExitSequence(CompilationUnit* cUnit, BasicBlock* bb) +void genExitSequence(CompilationUnit* cUnit, BasicBlock* bb) { - UNIMPLEMENTED(FATAL) << "Needs mips version"; -#if 0 - int spillCount = cUnit->numCoreSpills + cUnit->numFPSpills; /* - * In the exit path, r0/r1 are live - make sure they aren't + * In the exit path, rRET0/rRET1 are live - make sure they aren't * allocated by the register utilities as temps. */ - oatLockTemp(cUnit, r0); - oatLockTemp(cUnit, r1); + oatLockTemp(cUnit, rRET0); + oatLockTemp(cUnit, rRET1); newLIR0(cUnit, kPseudoMethodExit); /* If we're compiling for the debugger, generate an update callout */ if (cUnit->genDebugger) { genDebuggerUpdate(cUnit, DEBUGGER_METHOD_EXIT); } - opRegImm(cUnit, kOpAdd, rSP, cUnit->frameSize - (spillCount * 4)); - /* Need to restore any FP callee saves? */ - if (cUnit->numFPSpills) { - newLIR1(cUnit, kThumb2VPopCS, cUnit->numFPSpills); - } - if (cUnit->coreSpillMask & (1 << rLR)) { - /* Unspill rLR to rPC */ - cUnit->coreSpillMask &= ~(1 << rLR); - cUnit->coreSpillMask |= (1 << rPC); - } - newLIR1(cUnit, kThumb2Pop, cUnit->coreSpillMask); - if (!(cUnit->coreSpillMask & (1 << rPC))) { - /* We didn't pop to rPC, so must do a bv rLR */ - newLIR1(cUnit, kThumbBx, rLR); - } -#endif + unSpillCoreRegs(cUnit); + opReg(cUnit, kOpBx, rLINK); } /* @@ -1206,18 +155,15 @@ STATIC void genExitSequence(CompilationUnit* cUnit, BasicBlock* bb) */ void removeRedundantBranches(CompilationUnit* cUnit) { - UNIMPLEMENTED(FATAL) << "Needs mips version"; -#if 0 - MipsLIR* thisLIR; + LIR* thisLIR; - for (thisLIR = (MipsLIR*) cUnit->firstLIRInsn; - thisLIR != (MipsLIR*) cUnit->lastLIRInsn; + for (thisLIR = (LIR*) cUnit->firstLIRInsn; + thisLIR != (LIR*) cUnit->lastLIRInsn; thisLIR = NEXT_LIR(thisLIR)) { /* Branch to the next instruction */ - if ((thisLIR->opcode == kThumbBUncond) || - (thisLIR->opcode == kThumb2BUncond)) { - MipsLIR* nextLIR = thisLIR; + if (thisLIR->opcode == kMipsB) { + LIR* nextLIR = thisLIR; while (true) { nextLIR = NEXT_LIR(nextLIR); @@ -1225,7 +171,7 @@ void removeRedundantBranches(CompilationUnit* cUnit) /* * Is the branch target the next instruction? */ - if (nextLIR == (MipsLIR*) thisLIR->generic.target) { + if (nextLIR == (LIR*) thisLIR->target) { thisLIR->flags.isNop = true; break; } @@ -1236,116 +182,13 @@ void removeRedundantBranches(CompilationUnit* cUnit) * might be the last real instruction. */ if (!isPseudoOpcode(nextLIR->opcode) || - (nextLIR = (MipsLIR*) cUnit->lastLIRInsn)) + (nextLIR = (LIR*) cUnit->lastLIRInsn)) break; } } } -#endif } -STATIC void handleSuspendLaunchpads(CompilationUnit *cUnit) -{ - UNIMPLEMENTED(FATAL) << "Needs mips version"; -#if 0 - MipsLIR** suspendLabel = - (MipsLIR **) cUnit->suspendLaunchpads.elemList; - int numElems = cUnit->suspendLaunchpads.numUsed; - - for (int i = 0; i < numElems; i++) { - /* TUNING: move suspend count load into helper */ - MipsLIR* lab = suspendLabel[i]; - MipsLIR* resumeLab = (MipsLIR*)lab->operands[0]; - cUnit->currentDalvikOffset = lab->operands[1]; - oatAppendLIR(cUnit, (LIR *)lab); - loadWordDisp(cUnit, rSELF, - OFFSETOF_MEMBER(Thread, pTestSuspendFromCode), rLR); - if (!cUnit->genDebugger) { - // use rSUSPEND for suspend count - loadWordDisp(cUnit, rSELF, - Thread::SuspendCountOffset().Int32Value(), rSUSPEND); - } - opReg(cUnit, kOpBlx, rLR); - if ( cUnit->genDebugger) { - // use rSUSPEND for update debugger - loadWordDisp(cUnit, rSELF, - OFFSETOF_MEMBER(Thread, pUpdateDebuggerFromCode), rSUSPEND); - } - genUnconditionalBranch(cUnit, resumeLab); - } -#endif -} - -STATIC void handleThrowLaunchpads(CompilationUnit *cUnit) -{ - UNIMPLEMENTED(FATAL) << "Needs mips version"; -#if 0 - MipsLIR** throwLabel = - (MipsLIR **) cUnit->throwLaunchpads.elemList; - int numElems = cUnit->throwLaunchpads.numUsed; - int i; - - for (i = 0; i < numElems; i++) { - MipsLIR* lab = throwLabel[i]; - cUnit->currentDalvikOffset = lab->operands[1]; - oatAppendLIR(cUnit, (LIR *)lab); - int funcOffset = 0; - int v1 = lab->operands[2]; - int v2 = lab->operands[3]; - switch(lab->operands[0]) { - case kMipsThrowNullPointer: - funcOffset = OFFSETOF_MEMBER(Thread, pThrowNullPointerFromCode); - break; - case kMipsThrowArrayBounds: - if (v2 != r0) { - genRegCopy(cUnit, r0, v1); - genRegCopy(cUnit, r1, v2); - } else { - if (v1 == r1) { - genRegCopy(cUnit, r12, v1); - genRegCopy(cUnit, r1, v2); - genRegCopy(cUnit, r0, r12); - } else { - genRegCopy(cUnit, r1, v2); - genRegCopy(cUnit, r0, v1); - } - } - funcOffset = OFFSETOF_MEMBER(Thread, pThrowArrayBoundsFromCode); - break; - case kMipsThrowDivZero: - funcOffset = OFFSETOF_MEMBER(Thread, pThrowDivZeroFromCode); - break; - case kMipsThrowVerificationError: - loadConstant(cUnit, r0, v1); - loadConstant(cUnit, r1, v2); - funcOffset = - OFFSETOF_MEMBER(Thread, pThrowVerificationErrorFromCode); - break; - case kMipsThrowNegArraySize: - genRegCopy(cUnit, r0, v1); - funcOffset = - OFFSETOF_MEMBER(Thread, pThrowNegArraySizeFromCode); - break; - case kMipsThrowNoSuchMethod: - genRegCopy(cUnit, r0, v1); - funcOffset = - OFFSETOF_MEMBER(Thread, pThrowNoSuchMethodFromCode); - break; - case kMipsThrowStackOverflow: - funcOffset = - OFFSETOF_MEMBER(Thread, pThrowStackOverflowFromCode); - // Restore stack alignment - opRegImm(cUnit, kOpAdd, rSP, - (cUnit->numCoreSpills + cUnit->numFPSpills) * 4); - break; - default: - LOG(FATAL) << "Unexpected throw kind: " << lab->operands[0]; - } - loadWordDisp(cUnit, rSELF, funcOffset, rLR); - callRuntimeHelper(cUnit, rLR); - } -#endif -} /* Common initialization routine for an architecture family */ bool oatArchInit() @@ -1363,10 +206,4 @@ bool oatArchInit() return oatArchVariantInit(); } -/* Needed by the Assembler */ -void oatSetupResourceMasks(MipsLIR* lir) -{ - setupResourceMasks(lir); -} - } // namespace art diff --git a/src/compiler/codegen/mips/ArchUtility.cc b/src/compiler/codegen/mips/ArchUtility.cc index 2e8d4170d5..7f7aeb3b90 100644 --- a/src/compiler/codegen/mips/ArchUtility.cc +++ b/src/compiler/codegen/mips/ArchUtility.cc @@ -22,6 +22,33 @@ namespace art { +MipsConditionCode oatMipsConditionEncoding(ConditionCode code) +{ + MipsConditionCode res; + switch(code) { + case kCondEq: res = kMipsCondEq; break; + case kCondNe: res = kMipsCondNe; break; + case kCondCs: res = kMipsCondCs; break; + case kCondCc: res = kMipsCondCc; break; + case kCondMi: res = kMipsCondMi; break; + case kCondPl: res = kMipsCondPl; break; + case kCondVs: res = kMipsCondVs; break; + case kCondVc: res = kMipsCondVc; break; + case kCondHi: res = kMipsCondHi; break; + case kCondLs: res = kMipsCondLs; break; + case kCondGe: res = kMipsCondGe; break; + case kCondLt: res = kMipsCondLt; break; + case kCondGt: res = kMipsCondGt; break; + case kCondLe: res = kMipsCondLe; break; + case kCondAl: res = kMipsCondAl; break; + case kCondNv: res = kMipsCondNv; break; + default: + LOG(FATAL) << "Bad condition code" << (int)code; + res = (MipsConditionCode)0; // Quiet gcc + } + return res; +} + /* For dumping instructions */ #define MIPS_REG_COUNT 32 static const char *mipsRegName[MIPS_REG_COUNT] = { @@ -35,7 +62,7 @@ static const char *mipsRegName[MIPS_REG_COUNT] = { * Interpret a format string and build a string no longer than size * See format key in Assemble.c. */ -STATIC std::string buildInsnString(const char *fmt, MipsLIR *lir, unsigned char* baseAddr) +std::string buildInsnString(const char *fmt, LIR *lir, unsigned char* baseAddr) { std::string buf; int i; @@ -118,9 +145,9 @@ STATIC std::string buildInsnString(const char *fmt, MipsLIR *lir, unsigned char* break; case 't': sprintf(tbuf,"0x%08x (L%p)", - (int) baseAddr + lir->generic.offset + 4 + + (int) baseAddr + lir->offset + 4 + (operand << 2), - lir->generic.target); + lir->target); break; case 'T': sprintf(tbuf,"0x%08x", @@ -130,7 +157,7 @@ STATIC std::string buildInsnString(const char *fmt, MipsLIR *lir, unsigned char* int offset_1 = lir->operands[0]; int offset_2 = NEXT_LIR(lir)->operands[0]; intptr_t target = - ((((intptr_t) baseAddr + lir->generic.offset + 4) & + ((((intptr_t) baseAddr + lir->offset + 4) & ~3) + (offset_1 << 21 >> 9) + (offset_2 << 1)) & 0xfffffffc; sprintf(tbuf, "%p", (void *) target); @@ -163,7 +190,7 @@ void oatDumpResourceMask(LIR *lir, u8 mask, const char *prefix) { char buf[256]; buf[0] = 0; - MipsLIR *mipsLIR = (MipsLIR *) lir; + LIR *mipsLIR = (LIR *) lir; if (mask == ENCODE_ALL) { strcpy(buf, "all"); @@ -205,180 +232,4 @@ void oatDumpResourceMask(LIR *lir, u8 mask, const char *prefix) } } -/* - * Debugging macros - */ -#define DUMP_RESOURCE_MASK(X) -#define DUMP_SSA_REP(X) - -/* Pretty-print a LIR instruction */ -void oatDumpLIRInsn(CompilationUnit* cUnit, LIR* arg, unsigned char* baseAddr) -{ - MipsLIR* lir = (MipsLIR*) arg; - int offset = lir->generic.offset; - int dest = lir->operands[0]; - const bool dumpNop = false; - - /* Handle pseudo-ops individually, and all regular insns as a group */ - switch(lir->opcode) { - case kPseudoMethodEntry: - LOG(INFO) << "-------- method entry " << - PrettyMethod(cUnit->method_idx, *cUnit->dex_file); - break; - case kPseudoMethodExit: - LOG(INFO) << "-------- Method_Exit"; - break; - case kPseudoBarrier: - LOG(INFO) << "-------- BARRIER"; - break; - case kPseudoExtended: - LOG(INFO) << "-------- " << (char* ) dest; - break; - case kPseudoSSARep: - DUMP_SSA_REP(LOG(INFO) << "-------- kMirOpPhi: " << (char* ) dest); - break; - case kPseudoEntryBlock: - LOG(INFO) << "-------- entry offset: 0x" << std::hex << dest; - break; - case kPseudoDalvikByteCodeBoundary: - LOG(INFO) << "-------- dalvik offset: 0x" << std::hex << - lir->generic.dalvikOffset << " @ " << (char* )lir->operands[0]; - break; - case kPseudoExitBlock: - LOG(INFO) << "-------- exit offset: 0x" << std::hex << dest; - break; - case kPseudoPseudoAlign4: - LOG(INFO) << (intptr_t)baseAddr + offset << " (0x" << std::hex << - offset << "): .align4"; - break; - case kPseudoEHBlockLabel: - LOG(INFO) << "Exception_Handling:"; - break; - case kPseudoTargetLabel: - case kPseudoNormalBlockLabel: - LOG(INFO) << "L" << (intptr_t)lir << ":"; - break; - case kPseudoThrowTarget: - LOG(INFO) << "LT" << (intptr_t)lir << ":"; - break; - case kPseudoSuspendTarget: - LOG(INFO) << "LS" << (intptr_t)lir << ":"; - break; - case kPseudoCaseLabel: - LOG(INFO) << "LC" << (intptr_t)lir << ": Case target 0x" << - std::hex << lir->operands[0] << "|" << std::dec << - lir->operands[0]; - break; - default: - if (lir->flags.isNop && !dumpNop) { - break; - } else { - std::string op_name(buildInsnString(EncodingMap[lir->opcode].name, lir, baseAddr)); - std::string op_operands(buildInsnString(EncodingMap[lir->opcode].fmt, lir, baseAddr)); - LOG(INFO) << StringPrintf("%p (%04x): %-9s%s%s", baseAddr + offset, offset, - op_name.c_str(), op_operands.c_str(), lir->flags.isNop ? "(nop)" : ""); - } - break; - } - - if (lir->useMask && (!lir->flags.isNop || dumpNop)) { - DUMP_RESOURCE_MASK(oatDumpResourceMask((LIR* ) lir, - lir->useMask, "use")); - } - if (lir->defMask && (!lir->flags.isNop || dumpNop)) { - DUMP_RESOURCE_MASK(oatDumpResourceMask((LIR* ) lir, - lir->defMask, "def")); - } -} - -void oatDumpPromotionMap(CompilationUnit *cUnit) -{ - for (int i = 0; i < cUnit->numDalvikRegisters; i++) { - PromotionMap vRegMap = cUnit->promotionMap[i]; - char buf[100]; - if (vRegMap.fpLocation == kLocPhysReg) { - snprintf(buf, 100, " : s%d", vRegMap.fpReg & FP_REG_MASK); - } else { - buf[0] = 0; - } - char buf2[100]; - snprintf(buf2, 100, "V[%02d] -> %s%d%s", i, - vRegMap.coreLocation == kLocPhysReg ? - "r" : "SP+", vRegMap.coreLocation == kLocPhysReg ? - vRegMap.coreReg : oatSRegOffset(cUnit, i), buf); - LOG(INFO) << buf2; - } -} - -void oatDumpFullPromotionMap(CompilationUnit *cUnit) -{ - for (int i = 0; i < cUnit->numDalvikRegisters; i++) { - PromotionMap vRegMap = cUnit->promotionMap[i]; - LOG(INFO) << i << " -> " << "CL:" << (int)vRegMap.coreLocation << - ", CR:" << (int)vRegMap.coreReg << ", FL:" << - (int)vRegMap.fpLocation << ", FR:" << (int)vRegMap.fpReg << - ", - " << (int)vRegMap.firstInPair; - } -} - -/* Dump instructions and constant pool contents */ -void oatCodegenDump(CompilationUnit* cUnit) -{ - LOG(INFO) << "/*"; - LOG(INFO) << "Dumping LIR insns for " - << PrettyMethod(cUnit->method_idx, *cUnit->dex_file); - LIR* lirInsn; - MipsLIR* mipsLIR; - int insnsSize = cUnit->insnsSize; - - LOG(INFO) << "Regs (excluding ins) : " << cUnit->numRegs; - LOG(INFO) << "Ins : " << cUnit->numIns; - LOG(INFO) << "Outs : " << cUnit->numOuts; - LOG(INFO) << "CoreSpills : " << cUnit->numCoreSpills; - LOG(INFO) << "FPSpills : " << cUnit->numFPSpills; - LOG(INFO) << "Padding : " << cUnit->numPadding; - LOG(INFO) << "Frame size : " << cUnit->frameSize; - LOG(INFO) << "Start of ins : " << cUnit->insOffset; - LOG(INFO) << "Start of regs : " << cUnit->regsOffset; - LOG(INFO) << "code size is " << cUnit->totalSize << - " bytes, Dalvik size is " << insnsSize * 2; - LOG(INFO) << "expansion factor: " << - (float)cUnit->totalSize / (float)(insnsSize * 2); - oatDumpPromotionMap(cUnit); - for (lirInsn = cUnit->firstLIRInsn; lirInsn; lirInsn = lirInsn->next) { - oatDumpLIRInsn(cUnit, lirInsn, 0); - } - for (lirInsn = cUnit->classPointerList; lirInsn; lirInsn = lirInsn->next) { - mipsLIR = (MipsLIR*) lirInsn; - LOG(INFO) << StringPrintf("%x (%04x): .class (%s)", - mipsLIR->generic.offset, mipsLIR->generic.offset, - ((CallsiteInfo *) mipsLIR->operands[0])->classDescriptor); - } - for (lirInsn = cUnit->literalList; lirInsn; lirInsn = lirInsn->next) { - mipsLIR = (MipsLIR*) lirInsn; - LOG(INFO) << StringPrintf("%x (%04x): .word (%#x)", - mipsLIR->generic.offset, mipsLIR->generic.offset, mipsLIR->operands[0]); - } - - const DexFile::MethodId& method_id = - cUnit->dex_file->GetMethodId(cUnit->method_idx); - std::string signature(cUnit->dex_file->GetMethodSignature(method_id)); - std::string name(cUnit->dex_file->GetMethodName(method_id)); - std::string descriptor(cUnit->dex_file->GetMethodDeclaringClassDescriptor(method_id)); - - // Dump mapping table - if (cUnit->mappingTable.size() > 0) { - std::string line(StringPrintf("\n MappingTable %s%s_%s_mappingTable[%zu] = {", - descriptor.c_str(), name.c_str(), signature.c_str(), cUnit->mappingTable.size())); - std::replace(line.begin(), line.end(), ';', '_'); - LOG(INFO) << line; - for (uint32_t i = 0; i < cUnit->mappingTable.size(); i+=2) { - line = StringPrintf(" {0x%08x, 0x%04x},", - cUnit->mappingTable[i], cUnit->mappingTable[i+1]); - LOG(INFO) << line; - } - LOG(INFO) <<" };\n\n"; - } -} - } // namespace art diff --git a/src/compiler/codegen/mips/Assemble.cc b/src/compiler/codegen/mips/Assemble.cc index 5b6e6ed771..cb355c0b31 100644 --- a/src/compiler/codegen/mips/Assemble.cc +++ b/src/compiler/codegen/mips/Assemble.cc @@ -75,7 +75,7 @@ namespace art { * * [!] escape. To insert "!", use "!!" */ -/* NOTE: must be kept in sync with enum MipsOpcode from MipsLIR.h */ +/* NOTE: must be kept in sync with enum MipsOpcode from LIR.h */ MipsEncodingMap EncodingMap[kMipsLast] = { ENCODING_MAP(kMips32BitData, 0x00000000, kFmtBitBlt, 31, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1, @@ -406,12 +406,10 @@ MipsEncodingMap EncodingMap[kMipsLast] = { AssemblerStatus oatAssembleInstructions(CompilationUnit *cUnit, intptr_t startAddr) { - UNIMPLEMENTED(FATAL) << "Rework for art code buffer"; -#if 0 - int *bufferAddr = (int *) cUnit->codeBuffer; - MipsLIR *lir; + LIR *lir; + AssemblerStatus res = kSuccess; // Assume success - for (lir = (MipsLIR *) cUnit->firstLIRInsn; lir; lir = NEXT_LIR(lir)) { + for (lir = (LIR *) cUnit->firstLIRInsn; lir; lir = NEXT_LIR(lir)) { if (lir->opcode < 0) { continue; } @@ -422,43 +420,43 @@ AssemblerStatus oatAssembleInstructions(CompilationUnit *cUnit, } if (lir->opcode == kMipsB || lir->opcode == kMipsBal) { - MipsLIR *targetLIR = (MipsLIR *) lir->generic.target; - intptr_t pc = lir->generic.offset + 4; - intptr_t target = targetLIR->generic.offset; + LIR *targetLIR = (LIR *) lir->target; + intptr_t pc = lir->offset + 4; + intptr_t target = targetLIR->offset; int delta = target - pc; if (delta & 0x3) { LOG(FATAL) << "PC-rel offset not multiple of 4: " << delta; } if (delta > 131068 || delta < -131069) { - LOG(FATAL) << "Unconditional branch out of range: " << delta; + UNIMPLEMENTED(FATAL) << "B out of range, need long sequence: " << delta; } lir->operands[0] = delta >> 2; } else if (lir->opcode >= kMipsBeqz && lir->opcode <= kMipsBnez) { - MipsLIR *targetLIR = (MipsLIR *) lir->generic.target; - intptr_t pc = lir->generic.offset + 4; - intptr_t target = targetLIR->generic.offset; + LIR *targetLIR = (LIR *) lir->target; + intptr_t pc = lir->offset + 4; + intptr_t target = targetLIR->offset; int delta = target - pc; if (delta & 0x3) { LOG(FATAL) << "PC-rel offset not multiple of 4: " << delta; } if (delta > 131068 || delta < -131069) { - LOG(FATAL) << "Conditional branch out of range: " << delta; + UNIMPLEMENTED(FATAL) << "B[eq|ne]z needs long sequence: " << delta; } lir->operands[1] = delta >> 2; } else if (lir->opcode == kMipsBeq || lir->opcode == kMipsBne) { - MipsLIR *targetLIR = (MipsLIR *) lir->generic.target; - intptr_t pc = lir->generic.offset + 4; - intptr_t target = targetLIR->generic.offset; + LIR *targetLIR = (LIR *) lir->target; + intptr_t pc = lir->offset + 4; + intptr_t target = targetLIR->offset; int delta = target - pc; if (delta & 0x3) { LOG(FATAL) << "PC-rel offset not multiple of 4: " << delta; } if (delta > 131068 || delta < -131069) { - LOG(FATAL) << "Conditional branch out of range: " << delta; + UNIMPLEMENTED(FATAL) << "B[eq|ne] needs long sequence: " << delta; } lir->operands[2] = delta >> 2; } else if (lir->opcode == kMipsJal) { - intptr_t curPC = (startAddr + lir->generic.offset + 4) & ~3; + intptr_t curPC = (startAddr + lir->offset + 4) & ~3; intptr_t target = lir->operands[0]; /* ensure PC-region branch can be used */ DCHECK_EQ((curPC & 0xF0000000), (target & 0xF0000000)); @@ -467,16 +465,24 @@ AssemblerStatus oatAssembleInstructions(CompilationUnit *cUnit, } lir->operands[0] = target >> 2; } else if (lir->opcode == kMipsLahi) { /* load address hi (via lui) */ - MipsLIR *targetLIR = (MipsLIR *) lir->generic.target; - intptr_t target = startAddr + targetLIR->generic.offset; + LIR *targetLIR = (LIR *) lir->target; + intptr_t target = startAddr + targetLIR->offset; lir->operands[1] = target >> 16; } else if (lir->opcode == kMipsLalo) { /* load address lo (via ori) */ - MipsLIR *targetLIR = (MipsLIR *) lir->generic.target; - intptr_t target = startAddr + targetLIR->generic.offset; + LIR *targetLIR = (LIR *) lir->target; + intptr_t target = startAddr + targetLIR->offset; lir->operands[2] = lir->operands[2] + target; } - MipsEncodingMap *encoder = &EncodingMap[lir->opcode]; + /* + * If one of the pc-relative instructions expanded we'll have + * to make another pass. Don't bother to fully assemble the + * instruction. + */ + if (res != kSuccess) { + continue; + } + const MipsEncodingMap *encoder = &EncodingMap[lir->opcode]; u4 bits = encoder->skeleton; int i; for (i = 0; i < 4; i++) { @@ -497,7 +503,7 @@ AssemblerStatus oatAssembleInstructions(CompilationUnit *cUnit, break; case kFmtDfp: { DCHECK(DOUBLEREG(operand)); - DCHECK_EQ((operand & 0x1), 0); + DCHECK((operand & 0x1) == 0); value = ((operand & FP_REG_MASK) << encoder->fieldLoc[i].start) & ((1 << (encoder->fieldLoc[i].end + 1)) - 1); bits |= value; @@ -511,14 +517,15 @@ AssemblerStatus oatAssembleInstructions(CompilationUnit *cUnit, break; default: LOG(FATAL) << "Bad encoder format: " - << encoder->fieldLoc[i].kind; + << (int)encoder->fieldLoc[i].kind; } } DCHECK_EQ(encoder->size, 2); - *bufferAddr++ = bits; + // FIXME: need multi-endian handling here + cUnit->codeBuffer.push_back((bits >> 16) & 0xffff); + cUnit->codeBuffer.push_back(bits & 0xffff); } -#endif - return kSuccess; + return res; } /* @@ -528,13 +535,13 @@ AssemblerStatus oatAssembleInstructions(CompilationUnit *cUnit, */ int oatAssignInsnOffsets(CompilationUnit* cUnit) { - MipsLIR* mipsLIR; + LIR* mipsLIR; int offset = 0; - for (mipsLIR = (MipsLIR *) cUnit->firstLIRInsn; - mipsLIR; - mipsLIR = NEXT_LIR(mipsLIR)) { - mipsLIR->generic.offset = offset; + for (mipsLIR = (LIR *) cUnit->firstLIRInsn; + mipsLIR; + mipsLIR = NEXT_LIR(mipsLIR)) { + mipsLIR->offset = offset; if (mipsLIR->opcode >= 0) { if (!mipsLIR->flags.isNop) { mipsLIR->flags.size = EncodingMap[mipsLIR->opcode].size * 2; diff --git a/src/compiler/codegen/mips/Codegen.h b/src/compiler/codegen/mips/Codegen.h index b350dae035..355693c678 100644 --- a/src/compiler/codegen/mips/Codegen.h +++ b/src/compiler/codegen/mips/Codegen.h @@ -27,30 +27,72 @@ namespace art { #if defined(_CODEGEN_C) -/* - * loadConstant() sometimes needs to add a small imm to a pre-existing constant - */ -STATIC MipsLIR *opRegImm(CompilationUnit* cUnit, OpKind op, int rDestSrc1, - int value); -STATIC MipsLIR *opRegReg(CompilationUnit* cUnit, OpKind op, int rDestSrc1, - int rSrc2); +LIR *opRegImm(CompilationUnit* cUnit, OpKind op, int rDestSrc1, int value); +LIR *opRegReg(CompilationUnit* cUnit, OpKind op, int rDestSrc1, int rSrc2); -/* Forward decalraton the portable versions due to circular dependency */ -STATIC bool genArithOpFloatPortable(CompilationUnit* cUnit, MIR* mir, +/* Forward declaraton the portable versions due to circular dependency */ +bool genArithOpFloatPortable(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest, RegLocation rlSrc1, RegLocation rlSrc2); -STATIC bool genArithOpDoublePortable(CompilationUnit* cUnit, MIR* mir, +bool genArithOpDoublePortable(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest, RegLocation rlSrc1, RegLocation rlSrc2); -STATIC bool genConversionPortable(CompilationUnit* cUnit, MIR* mir); +bool genConversionPortable(CompilationUnit* cUnit, MIR* mir); + +MipsConditionCode oatMipsConditionEncoding(ConditionCode code); + +int loadHelper(CompilationUnit* cUnit, int offset); +LIR* callRuntimeHelper(CompilationUnit* cUnit, int reg); +RegLocation getRetLoc(CompilationUnit* cUnit); +LIR* loadConstant(CompilationUnit* cUnit, int reg, int immVal); +void genRegCopyWide(CompilationUnit* cUnit, int destLo, int destHi, + int srcLo, int srcHi); +LIR* genRegCopy(CompilationUnit* cUnit, int rDest, int rSrc); +LIR* genCmpImmBranch(CompilationUnit* cUnit, ConditionCode cond, int reg, + int checkValue); +void freeRegLocTemps(CompilationUnit* cUnit, RegLocation rlKeep, + RegLocation rlFree); + + +/* + * Return most flexible allowed register class based on size. + * Bug: 2813841 + * Must use a core register for data types narrower than word (due + * to possible unaligned load/store. + */ +inline RegisterClass oatRegClassBySize(OpSize size) +{ + return (size == kUnsignedHalf || + size == kSignedHalf || + size == kUnsignedByte || + size == kSignedByte ) ? kCoreReg : kAnyReg; +} + +/* + * Construct an s4 from two consecutive half-words of switch data. + * This needs to check endianness because the DEX optimizer only swaps + * half-words in instruction stream. + * + * "switchData" must be 32-bit aligned. + */ +#if __BYTE_ORDER == __LITTLE_ENDIAN +inline s4 s4FromSwitchData(const void* switchData) { + return *(s4*) switchData; +} +#else +inline s4 s4FromSwitchData(const void* switchData) { + u2* data = switchData; + return data[0] | (((s4) data[1]) << 16); +} +#endif #endif -extern void oatSetupResourceMasks(MipsLIR* lir); +extern void oatSetupResourceMasks(LIR* lir); -extern MipsLIR* oatRegCopyNoInsert(CompilationUnit* cUnit, int rDest, +extern LIR* oatRegCopyNoInsert(CompilationUnit* cUnit, int rDest, int rSrc); } // namespace art diff --git a/src/compiler/codegen/mips/CodegenCommon.cc b/src/compiler/codegen/mips/CodegenCommon.cc deleted file mode 100644 index 8dbb9a3506..0000000000 --- a/src/compiler/codegen/mips/CodegenCommon.cc +++ /dev/null @@ -1,319 +0,0 @@ -/* - * Copyright (C) 2012 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. - */ - -namespace art { - -/* - * This file contains codegen and support common to all supported - * Mips variants. It is included by: - * - * Codegen-$(TARGET_ARCH_VARIANT).c - * - * which combines this common code with specific support found in the - * applicable directory below this one. - */ - -static void setMemRefType(MipsLIR *lir, bool isLoad, int memType) -{ - /* MIPSTODO simplify setMemRefType() */ - u8 *maskPtr; - u8 mask = ENCODE_MEM;; - DCHECK(EncodingMap[lir->opcode].flags & (IS_LOAD | IS_STORE)); - - if (isLoad) { - maskPtr = &lir->useMask; - } else { - maskPtr = &lir->defMask; - } - /* Clear out the memref flags */ - *maskPtr &= ~mask; - /* ..and then add back the one we need */ - switch(memType) { - case kLiteral: - DCHECK(isLoad); - *maskPtr |= ENCODE_LITERAL; - break; - case kDalvikReg: - *maskPtr |= ENCODE_DALVIK_REG; - break; - case kHeapRef: - *maskPtr |= ENCODE_HEAP_REF; - break; - case kMustNotAlias: - /* Currently only loads can be marked as kMustNotAlias */ - DCHECK(!(EncodingMap[lir->opcode].flags & IS_STORE)); - *maskPtr |= ENCODE_MUST_NOT_ALIAS; - break; - default: - LOG(FATAL) << "Oat: invalid memref kind - " << memType; - } -} - -/* - * Mark load/store instructions that access Dalvik registers through rFP + - * offset. - */ -STATIC void annotateDalvikRegAccess(MipsLIR *lir, int regId, bool isLoad) -{ - /* MIPSTODO simplify annotateDalvikRegAccess() */ - setMemRefType(lir, isLoad, kDalvikReg); - - /* - * Store the Dalvik register id in aliasInfo. Mark he MSB if it is a 64-bit - * access. - */ - lir->aliasInfo = regId; - if (DOUBLEREG(lir->operands[0])) { - lir->aliasInfo |= 0x80000000; - } -} - -/* - * Decode the register id - */ -STATIC inline u8 getRegMaskCommon(int reg) -{ - u8 seed; - int shift; - int regId = reg & 0x1f; - - /* - * Each double register is equal to a pair of single-precision FP registers - */ - if (!DOUBLEREG(reg)) { - seed = 1; - } else { - DCHECK_EQ((regId & 1), 0); /* double registers must be even */ - seed = 3; - } - - if (FPREG(reg)) { - DCHECK_LT(regId, 16); /* only 16 fp regs */ - shift = kFPReg0; - } else if (EXTRAREG(reg)) { - DCHECK_LT(regId, 3); /* only 3 extra regs */ - shift = kFPRegEnd; - } else { - shift = 0; - } - - /* Expand the double register id into single offset */ - shift += regId; - return (seed << shift); -} - -/* - * Mark the corresponding bit(s). - */ -STATIC inline void setupRegMask(u8 *mask, int reg) -{ - *mask |= getRegMaskCommon(reg); -} - -/* - * Set up the proper fields in the resource mask - */ -STATIC void setupResourceMasks(MipsLIR *lir) -{ - /* MIPSTODO simplify setupResourceMasks() */ - int opcode = lir->opcode; - int flags; - - if (opcode <= 0) { - lir->useMask = lir->defMask = 0; - return; - } - - flags = EncodingMap[lir->opcode].flags; - - // TODO: do we need this for MIPS? if so, add to inst table defs -#if 0 - if (flags & NEEDS_FIXUP) { - lir->flags.pcRelFixup = true; - } -#endif - - /* Set up the mask for resources that are updated */ - if (flags & (IS_LOAD | IS_STORE)) { - /* Default to heap - will catch specialized classes later */ - setMemRefType(lir, flags & IS_LOAD, kHeapRef); - } - - /* - * Conservatively assume the branch here will call out a function that in - * turn will trash everything. - */ - if (flags & IS_BRANCH) { - lir->defMask = lir->useMask = ENCODE_ALL; - return; - } - - if (flags & REG_DEF0) { - setupRegMask(&lir->defMask, lir->operands[0]); - } - - if (flags & REG_DEF1) { - setupRegMask(&lir->defMask, lir->operands[1]); - } - - if (flags & REG_DEF_SP) { - lir->defMask |= ENCODE_REG_SP; - } - - if (flags & REG_DEF_LR) { - lir->defMask |= ENCODE_REG_LR; - } - - if (flags & REG_DEF_LIST0) { - lir->defMask |= ENCODE_REG_LIST(lir->operands[0]); - } - - if (flags & REG_DEF_LIST1) { - lir->defMask |= ENCODE_REG_LIST(lir->operands[1]); - } - - if (flags & SETS_CCODES) { - lir->defMask |= ENCODE_CCODE; - } - - // TODO: needed for MIPS? - /* Conservatively treat the IT block */ - if (flags & IS_IT) { - lir->defMask = ENCODE_ALL; - } - - if (flags & (REG_USE0 | REG_USE1 | REG_USE2 | REG_USE3)) { - int i; - - for (i = 0; i < 4; i++) { - if (flags & (1 << (kRegUse0 + i))) { - setupRegMask(&lir->useMask, lir->operands[i]); - } - } - } - - if (flags & REG_USE_PC) { - lir->useMask |= ENCODE_REG_PC; - } - - if (flags & REG_USE_SP) { - lir->useMask |= ENCODE_REG_SP; - } - - if (flags & REG_USE_LIST0) { - lir->useMask |= ENCODE_REG_LIST(lir->operands[0]); - } - - if (flags & REG_USE_LIST1) { - lir->useMask |= ENCODE_REG_LIST(lir->operands[1]); - } - - if (flags & USES_CCODES) { - lir->useMask |= ENCODE_CCODE; - } -} - -/* - * The following are building blocks to construct low-level IRs with 0 - 4 - * operands. - */ -MipsLIR *newLIR0(CompilationUnit *cUnit, MipsOpCode opcode) -{ - MipsLIR *insn = (MipsLIR *) oatNew(cUnit, sizeof(MipsLIR), true, kAllocLIR); - DCHECK(isPseudoOpcode(opcode) || (EncodingMap[opcode].flags & NO_OPERAND)); - insn->opcode = opcode; - setupResourceMasks(insn); - insn->generic.dalvikOffset = cUnit->currentDalvikOffset; - oatAppendLIR(cUnit, (LIR *) insn); - return insn; -} - -MipsLIR *newLIR1(CompilationUnit *cUnit, MipsOpCode opcode, - int dest) -{ - MipsLIR *insn = (MipsLIR *) oatNew(cUnit, sizeof(MipsLIR), true, kAllocLIR); - DCHECK(isPseudoOpcode(opcode) || (EncodingMap[opcode].flags & IS_UNARY_OP)); - insn->opcode = opcode; - insn->operands[0] = dest; - setupResourceMasks(insn); - insn->generic.dalvikOffset = cUnit->currentDalvikOffset; - oatAppendLIR(cUnit, (LIR *) insn); - return insn; -} - -MipsLIR *newLIR2(CompilationUnit *cUnit, MipsOpCode opcode, - int dest, int src1) -{ - MipsLIR *insn = (MipsLIR *) oatNew(cUnit, sizeof(MipsLIR), true, kAllocLIR); - DCHECK(isPseudoOpcode(opcode) || - (EncodingMap[opcode].flags & IS_BINARY_OP)); - insn->opcode = opcode; - insn->operands[0] = dest; - insn->operands[1] = src1; - setupResourceMasks(insn); - insn->generic.dalvikOffset = cUnit->currentDalvikOffset; - oatAppendLIR(cUnit, (LIR *) insn); - return insn; -} - -MipsLIR *newLIR3(CompilationUnit *cUnit, MipsOpCode opcode, - int dest, int src1, int src2) -{ - MipsLIR *insn = (MipsLIR *) oatNew(cUnit, sizeof(MipsLIR), true, kAllocLIR); - if (!(EncodingMap[opcode].flags & IS_TERTIARY_OP)) { - LOG(FATAL) << "Bad LIR3: " << EncodingMap[opcode].name; - } - DCHECK(isPseudoOpcode(opcode) || - (EncodingMap[opcode].flags & IS_TERTIARY_OP)); - insn->opcode = opcode; - insn->operands[0] = dest; - insn->operands[1] = src1; - insn->operands[2] = src2; - setupResourceMasks(insn); - insn->generic.dalvikOffset = cUnit->currentDalvikOffset; - oatAppendLIR(cUnit, (LIR *) insn); - return insn; -} - -MipsLIR *newLIR4(CompilationUnit *cUnit, MipsOpCode opcode, - int dest, int src1, int src2, int info) -{ - MipsLIR *insn = (MipsLIR *) oatNew(cUnit, sizeof(MipsLIR), true, kAllocLIR); - DCHECK(isPseudoOpcode(opcode) || - (EncodingMap[opcode].flags & IS_QUAD_OP)); - insn->opcode = opcode; - insn->operands[0] = dest; - insn->operands[1] = src1; - insn->operands[2] = src2; - insn->operands[3] = info; - setupResourceMasks(insn); - insn->generic.dalvikOffset = cUnit->currentDalvikOffset; - oatAppendLIR(cUnit, (LIR *) insn); - return insn; -} - -/* - * Generate an kPseudoBarrier marker to indicate the boundary of special - * blocks. - */ -static void genBarrier(CompilationUnit *cUnit) -{ - MipsLIR *barrier = newLIR0(cUnit, kPseudoBarrier); - /* Mark all resources as being clobbered */ - barrier->defMask = -1; -} - -} // namespace art diff --git a/src/compiler/codegen/mips/FP/MipsFP.cc b/src/compiler/codegen/mips/FP/MipsFP.cc index 7eb2a1ae68..acbac7f6d9 100644 --- a/src/compiler/codegen/mips/FP/MipsFP.cc +++ b/src/compiler/codegen/mips/FP/MipsFP.cc @@ -16,42 +16,8 @@ namespace art { -extern void oatFlushRegWideForV5TEVFP(CompilationUnit *cUnit, - int reg1, int reg2); -extern void oatFlushRegForV5TEVFP(CompilationUnit *cUnit, int reg); - -/* First, flush any registers associated with this value */ -void loadValueAddress(CompilationUnit *cUnit, RegLocation rlSrc, - int rDest) -{ - UNIMPLEMENTED(FATAL) << "Need Mips implementation"; -#if 0 - rlSrc = rlSrc.wide ? oatUpdateLocWide(cUnit, rlSrc) : - oatUpdateLoc(cUnit, rlSrc); - if (rlSrc.location == kLocPhysReg) { - if (rlSrc.wide) { - oatFlushRegWideForV5TEVFP(cUnit, rlSrc.lowReg, - rlSrc.highReg); - } else { - oatFlushRegForV5TEVFP(cUnit, rlSrc.lowReg); - } - } - opRegRegImm(cUnit, kOpAdd, rDest, rFP, - oatS2VReg(cUnit, rlSrc.sRegLow) << 2); -#endif -} - -/* - * TUNING: On some implementations, it is quicker to pass addresses - * to the handlers rather than load the operands into core registers - * and then move the values to FP regs in the handlers. Other implementations - * may prefer passing data in registers (and the latter approach would - * yeild cleaner register handling - avoiding the requirement that operands - * be flushed to memory prior to the call). - */ -static bool genArithOpFloat(CompilationUnit *cUnit, MIR *mir, - RegLocation rlDest, RegLocation rlSrc1, - RegLocation rlSrc2) +bool genArithOpFloat(CompilationUnit *cUnit, MIR *mir, RegLocation rlDest, + RegLocation rlSrc1, RegLocation rlSrc2) { #ifdef __mips_hard_float int op = kMipsNop; @@ -89,60 +55,14 @@ static bool genArithOpFloat(CompilationUnit *cUnit, MIR *mir, rlSrc1 = loadValue(cUnit, rlSrc1, kFPReg); rlSrc2 = loadValue(cUnit, rlSrc2, kFPReg); rlResult = oatEvalLoc(cUnit, rlDest, kFPReg, true); - newLIR3(cUnit, (MipsOpCode)op, rlResult.lowReg, rlSrc1.lowReg, rlSrc2.lowReg); + newLIR3(cUnit, (MipsOpCode)op, rlResult.lowReg, rlSrc1.lowReg, + rlSrc2.lowReg); storeValue(cUnit, rlDest, rlResult); return false; #else - UNIMPLEMENTED(FATAL) << "Need Mips implementation"; + UNIMPLEMENTED(FATAL) << "Need Mips soft float implementation"; return false; -#if 0 - TemplateOpcode opcode; - - /* - * 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: - opcode = TEMPLATE_ADD_FLOAT_VFP; - break; - case OP_SUB_FLOAT_2ADDR: - case OP_SUB_FLOAT: - opcode = TEMPLATE_SUB_FLOAT_VFP; - break; - case OP_DIV_FLOAT_2ADDR: - case OP_DIV_FLOAT: - opcode = TEMPLATE_DIV_FLOAT_VFP; - break; - case OP_MUL_FLOAT_2ADDR: - case OP_MUL_FLOAT: - opcode = TEMPLATE_MUL_FLOAT_VFP; - break; - case OP_REM_FLOAT_2ADDR: - case OP_REM_FLOAT: - case OP_NEG_FLOAT: { - return genArithOpFloatPortable(cUnit, mir, rlDest, rlSrc1, rlSrc2); - } - default: - return true; - } - loadValueAddress(cUnit, rlDest, r_A0); - oatClobber(cUnit, r_A0); - loadValueAddress(cUnit, rlSrc1, r_A1); - oatClobber(cUnit, r_A1); - loadValueAddress(cUnit, rlSrc2, r_A2); - UNIMP(FATAL) << "Need callout to handler"; -#if 0 - genDispatchToHandler(cUnit, opcode); -#endif - rlDest = oatUpdateLoc(cUnit, rlDest); - if (rlDest.location == kLocPhysReg) { - oatClobber(cUnit, rlDest.lowReg); - } - return false; -#endif #endif } @@ -192,64 +112,19 @@ static bool genArithOpDouble(CompilationUnit *cUnit, MIR *mir, storeValueWide(cUnit, rlDest, rlResult); return false; #else - UNIMPLEMENTED(FATAL) << "Need Mips implementation"; - return false; -#if 0 - TemplateOpcode opcode; - - switch (mir->dalvikInsn.opcode) { - case OP_ADD_DOUBLE_2ADDR: - case OP_ADD_DOUBLE: - opcode = TEMPLATE_ADD_DOUBLE_VFP; - break; - case OP_SUB_DOUBLE_2ADDR: - case OP_SUB_DOUBLE: - opcode = TEMPLATE_SUB_DOUBLE_VFP; - break; - case OP_DIV_DOUBLE_2ADDR: - case OP_DIV_DOUBLE: - opcode = TEMPLATE_DIV_DOUBLE_VFP; - break; - case OP_MUL_DOUBLE_2ADDR: - case OP_MUL_DOUBLE: - opcode = TEMPLATE_MUL_DOUBLE_VFP; - break; - case OP_REM_DOUBLE_2ADDR: - case OP_REM_DOUBLE: - case OP_NEG_DOUBLE: { - return genArithOpDoublePortable(cUnit, mir, rlDest, rlSrc1, - rlSrc2); - } - default: - return true; - } - loadValueAddress(cUnit, rlDest, r_A0); - oatClobber(cUnit, r_A0); - loadValueAddress(cUnit, rlSrc1, r_A1); - oatClobber(cUnit, r_A1); - loadValueAddress(cUnit, rlSrc2, r_A2); - UNIMP(FATAL) << "Need callout to handler"; -#if 0 - genDispatchToHandler(cUnit, opcode); -#endif - rlDest = oatUpdateLocWide(cUnit, rlDest); - if (rlDest.location == kLocPhysReg) { - oatClobber(cUnit, rlDest.lowReg); - oatClobber(cUnit, rlDest.highReg); - } + UNIMPLEMENTED(FATAL) << "Need Mips soft float implementation"; return false; #endif -#endif } static bool genConversion(CompilationUnit *cUnit, MIR *mir) { +#ifdef __mips_hard_float Opcode opcode = mir->dalvikInsn.opcode; bool longSrc = false; bool longDest = false; RegLocation rlSrc; RegLocation rlDest; -#ifdef __mips_hard_float int op = kMipsNop; int srcReg; RegLocation rlResult; @@ -306,77 +181,8 @@ static bool genConversion(CompilationUnit *cUnit, MIR *mir) } return false; #else - UNIMPLEMENTED(FATAL) << "Need Mips implementation"; + UNIMPLEMENTED(FATAL) << "Need Mips soft float implementation"; return false; -#if 0 - TemplateOpcode templateOpcode; - switch (opcode) { - case OP_INT_TO_FLOAT: - longSrc = false; - longDest = false; - templateOpcode = TEMPLATE_INT_TO_FLOAT_VFP; - break; - case OP_FLOAT_TO_INT: - longSrc = false; - longDest = false; - templateOpcode = TEMPLATE_FLOAT_TO_INT_VFP; - break; - case OP_DOUBLE_TO_FLOAT: - longSrc = true; - longDest = false; - templateOpcode = TEMPLATE_DOUBLE_TO_FLOAT_VFP; - break; - case OP_FLOAT_TO_DOUBLE: - longSrc = false; - longDest = true; - templateOpcode = TEMPLATE_FLOAT_TO_DOUBLE_VFP; - break; - case OP_INT_TO_DOUBLE: - longSrc = false; - longDest = true; - templateOpcode = TEMPLATE_INT_TO_DOUBLE_VFP; - break; - case OP_DOUBLE_TO_INT: - longSrc = true; - longDest = false; - templateOpcode = TEMPLATE_DOUBLE_TO_INT_VFP; - 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 = oatGetSrcWide(cUnit, mir, 0, 1); - } else { - rlSrc = oatGetSrc(cUnit, mir, 0); - } - - if (longDest) { - rlDest = oatGetDestWide(cUnit, mir, 0, 1); - } else { - rlDest = oatGetDest(cUnit, mir, 0); - } - loadValueAddress(cUnit, rlDest, r_A0); - oatClobber(cUnit, r_A0); - loadValueAddress(cUnit, rlSrc, r_A1); - UNIMP(FATAL) << "Need callout to handler"; -#if 0 - genDispatchToHandler(cUnit, templateOpcode); -#endif - if (rlDest.wide) { - rlDest = oatUpdateLocWide(cUnit, rlDest); - oatClobber(cUnit, rlDest.highReg); - } else { - rlDest = oatUpdateLoc(cUnit, rlDest); - } - oatClobber(cUnit, rlDest.lowReg); - return false; -#endif #endif } diff --git a/src/compiler/codegen/mips/Mips32/Factory.cc b/src/compiler/codegen/mips/Mips32/Factory.cc index f76adff3bd..71220c0be7 100644 --- a/src/compiler/codegen/mips/Mips32/Factory.cc +++ b/src/compiler/codegen/mips/Mips32/Factory.cc @@ -38,19 +38,24 @@ static int fpTemps[] = {r_F0, r_F1, r_F2, r_F3, r_F4, r_F5, r_F6, r_F7, r_F8, r_F9, r_F10, r_F11, r_F12, r_F13, r_F14, r_F15}; #endif +void genBarrier(CompilationUnit *cUnit); +LIR* genCompareBranch(CompilationUnit* cUnit, ConditionCode cond, int src1, + int src2); +LIR* opCompareBranch(CompilationUnit* cUnit, MipsOpCode opc, int src1, + int src2); void storePair(CompilationUnit *cUnit, int base, int lowReg, int highReg); void loadPair(CompilationUnit *cUnit, int base, int lowReg, int highReg); -MipsLIR *loadWordDisp(CompilationUnit *cUnit, int rBase, int displacement, +LIR *loadWordDisp(CompilationUnit *cUnit, int rBase, int displacement, int rDest); -MipsLIR *storeWordDisp(CompilationUnit *cUnit, int rBase, +LIR *storeWordDisp(CompilationUnit *cUnit, int rBase, int displacement, int rSrc); -MipsLIR *loadConstant(CompilationUnit *cUnit, int rDest, int value); +LIR *loadConstant(CompilationUnit *cUnit, int rDest, int value); #ifdef __mips_hard_float -MipsLIR *fpRegCopy(CompilationUnit *cUnit, int rDest, int rSrc) +LIR *fpRegCopy(CompilationUnit *cUnit, int rDest, int rSrc) { - MipsLIR* res = (MipsLIR *) oatNew(cUnit, sizeof(MipsLIR), true, kAllocLIR); + LIR* res = (LIR *) oatNew(cUnit, sizeof(LIR), true, kAllocLIR); res->operands[0] = rDest; res->operands[1] = rSrc; if (rDest == rSrc) { @@ -90,10 +95,10 @@ MipsLIR *fpRegCopy(CompilationUnit *cUnit, int rDest, int rSrc) * 1) rDest is freshly returned from oatAllocTemp or * 2) The codegen is under fixed register usage */ -MipsLIR *loadConstantNoClobber(CompilationUnit *cUnit, int rDest, +LIR *loadConstantNoClobber(CompilationUnit *cUnit, int rDest, int value) { - MipsLIR *res; + LIR *res; #ifdef __mips_hard_float int rDestSave = rDest; @@ -127,22 +132,9 @@ MipsLIR *loadConstantNoClobber(CompilationUnit *cUnit, int rDest, return res; } -/* - * Load an immediate value into a fixed or temp register. Target - * register is clobbered, and marked inUse. - */ -MipsLIR *loadConstant(CompilationUnit *cUnit, int rDest, int value) -{ - if (oatIsTemp(cUnit, rDest)) { - oatClobber(cUnit, rDest); - oatMarkInUse(cUnit, rDest); - } - return loadConstantNoClobber(cUnit, rDest, value); -} - -MipsLIR *opNone(CompilationUnit *cUnit, OpKind op) +LIR *opNone(CompilationUnit *cUnit, OpKind op) { - MipsLIR *res; + LIR *res; MipsOpCode opcode = kMipsNop; switch (op) { case kOpUncondBr: @@ -156,28 +148,28 @@ MipsLIR *opNone(CompilationUnit *cUnit, OpKind op) } -MipsLIR *opCmpBranchCC(CompilationUnit *cUnit, MipsConditionCode cc, +LIR *opCmpBranchCC(CompilationUnit *cUnit, MipsConditionCode cc, int rs, int rt) { UNIMPLEMENTED(FATAL); return 0; } -MipsLIR *opCmpImmBranchCC(CompilationUnit *cUnit, MipsConditionCode cc, +LIR *opCmpImmBranchCC(CompilationUnit *cUnit, MipsConditionCode cc, int rs, int immVal) { UNIMPLEMENTED(FATAL); return 0; } -MipsLIR *opCmpImmBranch(CompilationUnit *cUnit, MipsOpCode cc, +LIR *opCmpImmBranch(CompilationUnit *cUnit, MipsOpCode cc, int rs, int immVal) { UNIMPLEMENTED(FATAL); return 0; } -MipsLIR *opCmpBranch(CompilationUnit *cUnit, MipsOpCode opc, int rs, int rt) +LIR *opCmpBranch(CompilationUnit *cUnit, MipsOpCode opc, int rs, int rt) { - MipsLIR *res; + LIR *res; if (rt < 0) { DCHECK(opc >= kMipsBeqz && opc <= kMipsBnez); res = newLIR1(cUnit, opc, rs); @@ -188,9 +180,9 @@ MipsLIR *opCmpBranch(CompilationUnit *cUnit, MipsOpCode opc, int rs, int rt) return res; } -MipsLIR *loadMultiple(CompilationUnit *cUnit, int rBase, int rMask); +LIR *loadMultiple(CompilationUnit *cUnit, int rBase, int rMask); -MipsLIR *opReg(CompilationUnit *cUnit, OpKind op, int rDestSrc) +LIR *opReg(CompilationUnit *cUnit, OpKind op, int rDestSrc) { MipsOpCode opcode = kMipsNop; switch (op) { @@ -203,12 +195,12 @@ MipsLIR *opReg(CompilationUnit *cUnit, OpKind op, int rDestSrc) return newLIR2(cUnit, opcode, r_RA, rDestSrc); } -MipsLIR *opRegRegImm(CompilationUnit *cUnit, OpKind op, int rDest, +LIR *opRegRegImm(CompilationUnit *cUnit, OpKind op, int rDest, int rSrc1, int value); -MipsLIR *opRegImm(CompilationUnit *cUnit, OpKind op, int rDestSrc1, +LIR *opRegImm(CompilationUnit *cUnit, OpKind op, int rDestSrc1, int value) { - MipsLIR *res; + LIR *res; bool neg = (value < 0); int absValue = (neg) ? -value : value; bool shortForm = (absValue & 0xff) == absValue; @@ -237,7 +229,7 @@ MipsLIR *opRegImm(CompilationUnit *cUnit, OpKind op, int rDestSrc1, return res; } -MipsLIR *opRegRegReg(CompilationUnit *cUnit, OpKind op, int rDest, +LIR *opRegRegReg(CompilationUnit *cUnit, OpKind op, int rDest, int rSrc1, int rSrc2) { MipsOpCode opcode = kMipsNop; @@ -276,10 +268,10 @@ MipsLIR *opRegRegReg(CompilationUnit *cUnit, OpKind op, int rDest, return newLIR3(cUnit, opcode, rDest, rSrc1, rSrc2); } -MipsLIR *opRegRegImm(CompilationUnit *cUnit, OpKind op, int rDest, +LIR *opRegRegImm(CompilationUnit *cUnit, OpKind op, int rDest, int rSrc1, int value) { - MipsLIR *res; + LIR *res; MipsOpCode opcode = kMipsNop; bool shortForm = true; @@ -366,11 +358,11 @@ MipsLIR *opRegRegImm(CompilationUnit *cUnit, OpKind op, int rDest, return res; } -MipsLIR *opRegReg(CompilationUnit *cUnit, OpKind op, int rDestSrc1, +LIR *opRegReg(CompilationUnit *cUnit, OpKind op, int rDestSrc1, int rSrc2) { MipsOpCode opcode = kMipsNop; - MipsLIR *res; + LIR *res; switch (op) { case kOpMov: opcode = kMipsMove; @@ -411,21 +403,21 @@ MipsLIR *opRegReg(CompilationUnit *cUnit, OpKind op, int rDestSrc1, return newLIR2(cUnit, opcode, rDestSrc1, rSrc2); } -MipsLIR *loadConstantValueWide(CompilationUnit *cUnit, int rDestLo, +LIR *loadConstantValueWide(CompilationUnit *cUnit, int rDestLo, int rDestHi, int valLo, int valHi) { - MipsLIR *res; + LIR *res; res = loadConstantNoClobber(cUnit, rDestLo, valLo); loadConstantNoClobber(cUnit, rDestHi, valHi); return res; } /* Load value from base + scaled index. */ -MipsLIR *loadBaseIndexed(CompilationUnit *cUnit, int rBase, +LIR *loadBaseIndexed(CompilationUnit *cUnit, int rBase, int rIndex, int rDest, int scale, OpSize size) { - MipsLIR *first = NULL; - MipsLIR *res; + LIR *first = NULL; + LIR *res; MipsOpCode opcode = kMipsNop; int tReg = oatAllocTemp(cUnit); @@ -478,11 +470,11 @@ MipsLIR *loadBaseIndexed(CompilationUnit *cUnit, int rBase, } /* store value base base + scaled index. */ -MipsLIR *storeBaseIndexed(CompilationUnit *cUnit, int rBase, +LIR *storeBaseIndexed(CompilationUnit *cUnit, int rBase, int rIndex, int rSrc, int scale, OpSize size) { - MipsLIR *first = NULL; - MipsLIR *res; + LIR *first = NULL; + LIR *res; MipsOpCode opcode = kMipsNop; int rNewIndex = rIndex; int tReg = oatAllocTemp(cUnit); @@ -530,11 +522,11 @@ MipsLIR *storeBaseIndexed(CompilationUnit *cUnit, int rBase, return first; } -MipsLIR *loadMultiple(CompilationUnit *cUnit, int rBase, int rMask) +LIR *loadMultiple(CompilationUnit *cUnit, int rBase, int rMask) { int i; int loadCnt = 0; - MipsLIR *res = NULL ; + LIR *res = NULL ; genBarrier(cUnit); for (i = 0; i < 8; i++, rMask >>= 1) { @@ -552,11 +544,11 @@ MipsLIR *loadMultiple(CompilationUnit *cUnit, int rBase, int rMask) return res; /* NULL always returned which should be ok since no callers use it */ } -MipsLIR *storeMultiple(CompilationUnit *cUnit, int rBase, int rMask) +LIR *storeMultiple(CompilationUnit *cUnit, int rBase, int rMask) { int i; int storeCnt = 0; - MipsLIR *res = NULL ; + LIR *res = NULL ; genBarrier(cUnit); for (i = 0; i < 8; i++, rMask >>= 1) { @@ -574,7 +566,7 @@ MipsLIR *storeMultiple(CompilationUnit *cUnit, int rBase, int rMask) return res; /* NULL always returned which should be ok since no callers use it */ } -MipsLIR *loadBaseDispBody(CompilationUnit *cUnit, MIR *mir, int rBase, +LIR *loadBaseDispBody(CompilationUnit *cUnit, MIR *mir, int rBase, int displacement, int rDest, int rDestHi, OpSize size, int sReg) /* @@ -586,9 +578,9 @@ MipsLIR *loadBaseDispBody(CompilationUnit *cUnit, MIR *mir, int rBase, * rlp and then restore. */ { - MipsLIR *res; - MipsLIR *load = NULL; - MipsLIR *load2 = NULL; + LIR *res; + LIR *load = NULL; + LIR *load2 = NULL; MipsOpCode opcode = kMipsNop; bool shortForm = IS_SIMM16(displacement); bool pair = false; @@ -680,7 +672,7 @@ MipsLIR *loadBaseDispBody(CompilationUnit *cUnit, MIR *mir, int rBase, return load; } -MipsLIR *loadBaseDisp(CompilationUnit *cUnit, MIR *mir, int rBase, +LIR *loadBaseDisp(CompilationUnit *cUnit, MIR *mir, int rBase, int displacement, int rDest, OpSize size, int sReg) { @@ -688,7 +680,7 @@ MipsLIR *loadBaseDisp(CompilationUnit *cUnit, MIR *mir, int rBase, size, sReg); } -MipsLIR *loadBaseDispWide(CompilationUnit *cUnit, MIR *mir, int rBase, +LIR *loadBaseDispWide(CompilationUnit *cUnit, MIR *mir, int rBase, int displacement, int rDestLo, int rDestHi, int sReg) { @@ -696,13 +688,13 @@ MipsLIR *loadBaseDispWide(CompilationUnit *cUnit, MIR *mir, int rBase, kLong, sReg); } -MipsLIR *storeBaseDispBody(CompilationUnit *cUnit, int rBase, +LIR *storeBaseDispBody(CompilationUnit *cUnit, int rBase, int displacement, int rSrc, int rSrcHi, OpSize size) { - MipsLIR *res; - MipsLIR *store = NULL; - MipsLIR *store2 = NULL; + LIR *res; + LIR *store = NULL; + LIR *store2 = NULL; MipsOpCode opcode = kMipsNop; bool shortForm = IS_SIMM16(displacement); bool pair = false; @@ -785,13 +777,13 @@ MipsLIR *storeBaseDispBody(CompilationUnit *cUnit, int rBase, return res; } -MipsLIR *storeBaseDisp(CompilationUnit *cUnit, int rBase, +LIR *storeBaseDisp(CompilationUnit *cUnit, int rBase, int displacement, int rSrc, OpSize size) { return storeBaseDispBody(cUnit, rBase, displacement, rSrc, -1, size); } -MipsLIR *storeBaseDispWide(CompilationUnit *cUnit, int rBase, +LIR *storeBaseDispWide(CompilationUnit *cUnit, int rBase, int displacement, int rSrcLo, int rSrcHi) { return storeBaseDispBody(cUnit, rBase, displacement, rSrcLo, rSrcHi, kLong); @@ -803,83 +795,12 @@ void loadPair(CompilationUnit *cUnit, int base, int lowReg, int highReg) loadWordDisp(cUnit, base, HIWORD_OFFSET , highReg); } -MipsLIR* genRegCopyNoInsert(CompilationUnit *cUnit, int rDest, int rSrc) -{ - MipsLIR* res; - MipsOpCode opcode; -#ifdef __mips_hard_float - if (FPREG(rDest) || FPREG(rSrc)) - return fpRegCopy(cUnit, rDest, rSrc); -#endif - res = (MipsLIR *) oatNew(cUnit, sizeof(MipsLIR), true, kAllocLIR); - opcode = kMipsMove; - DCHECK(LOWREG(rDest) && LOWREG(rSrc)); - res->operands[0] = rDest; - res->operands[1] = rSrc; - res->opcode = opcode; - setupResourceMasks(res); - if (rDest == rSrc) { - res->flags.isNop = true; - } - return res; -} - -MipsLIR* genRegCopy(CompilationUnit *cUnit, int rDest, int rSrc) -{ - MipsLIR *res = genRegCopyNoInsert(cUnit, rDest, rSrc); - oatAppendLIR(cUnit, (LIR*)res); - return res; -} - -void genRegCopyWide(CompilationUnit *cUnit, int destLo, int destHi, - int srcLo, int srcHi) -{ -#ifdef __mips_hard_float - bool destFP = FPREG(destLo) && FPREG(destHi); - bool srcFP = FPREG(srcLo) && FPREG(srcHi); - DCHECK_EQ(FPREG(srcLo), FPREG(srcHi)); - DCHECK_EQ(FPREG(destLo), FPREG(destHi)); - if (destFP) { - if (srcFP) { - genRegCopy(cUnit, S2D(destLo, destHi), S2D(srcLo, srcHi)); - } else { - /* note the operands are swapped for the mtc1 instr */ - newLIR2(cUnit, kMipsMtc1, srcLo, destLo); - newLIR2(cUnit, kMipsMtc1, srcHi, destHi); - } - } else { - if (srcFP) { - newLIR2(cUnit, kMipsMfc1, destLo, srcLo); - newLIR2(cUnit, kMipsMfc1, destHi, srcHi); - } else { - // Handle overlap - if (srcHi == destLo) { - genRegCopy(cUnit, destHi, srcHi); - genRegCopy(cUnit, destLo, srcLo); - } else { - genRegCopy(cUnit, destLo, srcLo); - genRegCopy(cUnit, destHi, srcHi); - } - } - } -#else - // Handle overlap - if (srcHi == destLo) { - genRegCopy(cUnit, destHi, srcHi); - genRegCopy(cUnit, destLo, srcLo); - } else { - genRegCopy(cUnit, destLo, srcLo); - genRegCopy(cUnit, destHi, srcHi); - } -#endif -} - -inline MipsLIR *genRegImmCheck(CompilationUnit *cUnit, +LIR *genRegImmCheck(CompilationUnit *cUnit, MipsConditionCode cond, int reg, int checkValue, int dOffset, - MipsLIR *pcrLabel) + LIR *pcrLabel) { - MipsLIR *branch = NULL; + LIR *branch = NULL; if (checkValue == 0) { MipsOpCode opc = kMipsNop; @@ -918,9 +839,9 @@ inline MipsLIR *genRegImmCheck(CompilationUnit *cUnit, if (cUnit->jitMode == kJitMethod) { BasicBlock *bb = cUnit->curBlock; if (bb->taken) { - MipsLIR *exceptionLabel = (MipsLIR *) cUnit->blockLabelList; + LIR *exceptionLabel = (LIR *) cUnit->blockLabelList; exceptionLabel += bb->taken->id; - branch->generic.target = (LIR *) exceptionLabel; + branch->target = (LIR *) exceptionLabel; return exceptionLabel; } else { LOG(FATAL) << "Catch blocks not handled yet"; diff --git a/src/compiler/codegen/mips/Mips32/Gen.cc b/src/compiler/codegen/mips/Mips32/Gen.cc index 880169272e..0b2b15ac45 100644 --- a/src/compiler/codegen/mips/Mips32/Gen.cc +++ b/src/compiler/codegen/mips/Mips32/Gen.cc @@ -24,377 +24,6 @@ namespace art { -// FIXME: need the following: -void genSuspendTest(CompilationUnit* cUnit, MIR* mir) {} -void genMonitorEnter(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc) {} -void genMonitorExit(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc) {} -void genCheckCast(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc) {} -void genInstanceof(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest, - RegLocation rlSrc) {} -void genNewInstance(CompilationUnit* cUnit, MIR* mir, - RegLocation rlDest) {} -void genThrow(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc) {} -void genConstString(CompilationUnit* cUnit, MIR* mir, - RegLocation rlDest, RegLocation rlSrc) {} -void genConstClass(CompilationUnit* cUnit, MIR* mir, - RegLocation rlDest, RegLocation rlSrc) {} -void genArrayGet(CompilationUnit* cUnit, MIR* mir, OpSize size, - RegLocation rlArray, RegLocation rlIndex, - RegLocation rlDest, int scale) {} -void genArrayPut(CompilationUnit* cUnit, MIR* mir, OpSize size, - RegLocation rlArray, RegLocation rlIndex, - RegLocation rlSrc, int scale) {} -void genArrayObjPut(CompilationUnit* cUnit, MIR* mir, - RegLocation rlArray, RegLocation rlIndex, - RegLocation rlSrc, int scale) {} -void genIPut(CompilationUnit* cUnit, MIR* mir, OpSize size, - RegLocation rlSrc, RegLocation rlObj, - bool isLongOrDouble, bool isObject) {} -bool genArithOpInt(CompilationUnit* cUnit, MIR* mir, - RegLocation rlDest, RegLocation rlSrc1, - RegLocation rlSrc2) { return 0; } -bool genArithOpLong(CompilationUnit* cUnit, MIR* mir, - RegLocation rlDest, RegLocation rlSrc1, - RegLocation rlSrc2) { return 0; } -bool genShiftOpLong(CompilationUnit* cUnit, MIR* mir, - RegLocation rlDest, RegLocation rlSrc1, - RegLocation rlShift) { return 0; } -bool genArithOpIntLit(CompilationUnit* cUnit, MIR* mir, - RegLocation rlDest, RegLocation rlSrc, - int lit) { return 0; } -void oatArchDump(void) {}; -void genDebuggerUpdate(CompilationUnit* cUnit, int32_t offset) {}; - - - - -STATIC bool genConversionCall(CompilationUnit* cUnit, MIR* mir, int funcOffset, - int srcSize, int tgtSize) -{ - UNIMPLEMENTED(FATAL) << "Need Mips implementation"; - return 0; -#if 0 - /* - * Don't optimize the register usage since it calls out to support - * functions - */ - RegLocation rlSrc; - RegLocation rlDest; - oatFlushAllRegs(cUnit); /* Send everything to home location */ - loadWordDisp(cUnit, rSELF, funcOffset, rLR); - if (srcSize == 1) { - rlSrc = oatGetSrc(cUnit, mir, 0); - loadValueDirectFixed(cUnit, rlSrc, r0); - } else { - rlSrc = oatGetSrcWide(cUnit, mir, 0, 1); - loadValueDirectWideFixed(cUnit, rlSrc, r0, r1); - } - callRuntimeHelper(cUnit, rLR); - if (tgtSize == 1) { - RegLocation rlResult; - rlDest = oatGetDest(cUnit, mir, 0); - rlResult = oatGetReturn(cUnit); - storeValue(cUnit, rlDest, rlResult); - } else { - RegLocation rlResult; - rlDest = oatGetDestWide(cUnit, mir, 0, 1); - rlResult = oatGetReturnWide(cUnit); - storeValueWide(cUnit, rlDest, rlResult); - } - return false; -#endif -} - -bool genArithOpFloatPortable(CompilationUnit* cUnit, MIR* mir, - RegLocation rlDest, RegLocation rlSrc1, - RegLocation rlSrc2) -{ - UNIMPLEMENTED(FATAL) << "Need Mips implementation"; - return 0; -#if 0 - RegLocation rlResult; - int funcOffset; - - switch (mir->dalvikInsn.opcode) { - case OP_ADD_FLOAT_2ADDR: - case OP_ADD_FLOAT: - funcOffset = OFFSETOF_MEMBER(Thread, pFadd); - break; - case OP_SUB_FLOAT_2ADDR: - case OP_SUB_FLOAT: - funcOffset = OFFSETOF_MEMBER(Thread, pFsub); - break; - case OP_DIV_FLOAT_2ADDR: - case OP_DIV_FLOAT: - funcOffset = OFFSETOF_MEMBER(Thread, pFdiv); - break; - case OP_MUL_FLOAT_2ADDR: - case OP_MUL_FLOAT: - funcOffset = OFFSETOF_MEMBER(Thread, pFmul); - break; - case OP_REM_FLOAT_2ADDR: - case OP_REM_FLOAT: - funcOffset = OFFSETOF_MEMBER(Thread, pFmodf); - break; - case OP_NEG_FLOAT: { - genNegFloat(cUnit, rlDest, rlSrc1); - return false; - } - default: - return true; - } - oatFlushAllRegs(cUnit); /* Send everything to home location */ - loadWordDisp(cUnit, rSELF, funcOffset, rLR); - loadValueDirectFixed(cUnit, rlSrc1, r0); - loadValueDirectFixed(cUnit, rlSrc2, r1); - callRuntimeHelper(cUnit, rLR); - rlResult = oatGetReturn(cUnit); - storeValue(cUnit, rlDest, rlResult); - return false; -#endif -} - -bool genArithOpDoublePortable(CompilationUnit* cUnit, MIR* mir, - RegLocation rlDest, RegLocation rlSrc1, - RegLocation rlSrc2) -{ - UNIMPLEMENTED(FATAL) << "Need Mips implementation"; - return 0; -#if 0 - RegLocation rlResult; - int funcOffset; - - switch (mir->dalvikInsn.opcode) { - case OP_ADD_DOUBLE_2ADDR: - case OP_ADD_DOUBLE: - funcOffset = OFFSETOF_MEMBER(Thread, pDadd); - break; - case OP_SUB_DOUBLE_2ADDR: - case OP_SUB_DOUBLE: - funcOffset = OFFSETOF_MEMBER(Thread, pDsub); - break; - case OP_DIV_DOUBLE_2ADDR: - case OP_DIV_DOUBLE: - funcOffset = OFFSETOF_MEMBER(Thread, pDdiv); - break; - case OP_MUL_DOUBLE_2ADDR: - case OP_MUL_DOUBLE: - funcOffset = OFFSETOF_MEMBER(Thread, pDmul); - break; - case OP_REM_DOUBLE_2ADDR: - case OP_REM_DOUBLE: - funcOffset = OFFSETOF_MEMBER(Thread, pFmod); - break; - case OP_NEG_DOUBLE: { - genNegDouble(cUnit, rlDest, rlSrc1); - return false; - } - default: - return true; - } - oatFlushAllRegs(cUnit); /* Send everything to home location */ - loadWordDisp(cUnit, rSELF, funcOffset, rLR); - loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1); - loadValueDirectWideFixed(cUnit, rlSrc2, r2, r3); - callRuntimeHelper(cUnit, rLR); - rlResult = oatGetReturnWide(cUnit); - storeValueWide(cUnit, rlDest, rlResult); - return false; -#endif -} - -bool genConversionPortable(CompilationUnit* cUnit, MIR* mir) -{ - UNIMPLEMENTED(FATAL) << "Need Mips implementation"; - return 0; -#if 0 - Opcode opcode = mir->dalvikInsn.opcode; - - switch (opcode) { - case OP_INT_TO_FLOAT: - return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, pI2f), - 1, 1); - case OP_FLOAT_TO_INT: - return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, pF2iz), - 1, 1); - case OP_DOUBLE_TO_FLOAT: - return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, pD2f), - 2, 1); - case OP_FLOAT_TO_DOUBLE: - return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, pF2d), - 1, 2); - case OP_INT_TO_DOUBLE: - return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, pI2d), - 1, 2); - case OP_DOUBLE_TO_INT: - return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, pD2iz), - 2, 1); - case OP_FLOAT_TO_LONG: - return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, - pF2l), 1, 2); - case OP_LONG_TO_FLOAT: - return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, pL2f), - 2, 1); - case OP_DOUBLE_TO_LONG: - return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, - pD2l), 2, 2); - case OP_LONG_TO_DOUBLE: - return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, pL2d), - 2, 2); - default: - return true; - } - return false; -#endif -} - - - - - -STATIC RegLocation getRetLoc(CompilationUnit* cUnit); - -void warnIfUnresolved(CompilationUnit* cUnit, int fieldIdx, Field* field) { - if (field == NULL) { - const DexFile::FieldId& field_id = cUnit->dex_file->GetFieldId(fieldIdx); - std::string class_name(cUnit->dex_file->GetFieldDeclaringClassDescriptor(field_id)); - std::string field_name(cUnit->dex_file->GetFieldName(field_id)); - LOG(INFO) << "Field " << PrettyDescriptor(class_name) << "." << field_name - << " unresolved at compile time"; - } else { - // We also use the slow path for wide volatile fields. - } -} - -/* - * Construct an s4 from two consecutive half-words of switch data. - * This needs to check endianness because the DEX optimizer only swaps - * half-words in instruction stream. - * - * "switchData" must be 32-bit aligned. - */ -#if __BYTE_ORDER == __LITTLE_ENDIAN -STATIC inline s4 s4FromSwitchData(const void* switchData) { - return *(s4*) switchData; -} -#else -STATIC inline s4 s4FromSwitchData(const void* switchData) { - u2* data = switchData; - return data[0] | (((s4) data[1]) << 16); -} -#endif -/* - * Insert a kPseudoCaseLabel at the beginning of the Dalvik - * offset vaddr. This label will be used to fix up the case - * branch table during the assembly phase. Be sure to set - * all resource flags on this to prevent code motion across - * target boundaries. KeyVal is just there for debugging. - */ -STATIC MipsLIR* insertCaseLabel(CompilationUnit* cUnit, int vaddr, int keyVal) -{ - std::map<unsigned int, LIR*>::iterator it; - it = cUnit->boundaryMap.find(vaddr); - if (it == cUnit->boundaryMap.end()) { - LOG(FATAL) << "Error: didn't find vaddr 0x" << std::hex << vaddr; - } - MipsLIR* newLabel = (MipsLIR*)oatNew(cUnit, sizeof(MipsLIR), true, kAllocLIR); - newLabel->generic.dalvikOffset = vaddr; - newLabel->opcode = kPseudoCaseLabel; - newLabel->operands[0] = keyVal; - oatInsertLIRAfter(it->second, (LIR*)newLabel); - return newLabel; -} - -STATIC void markPackedCaseLabels(CompilationUnit* cUnit, SwitchTable *tabRec) -{ - const u2* table = tabRec->table; - int baseVaddr = tabRec->vaddr; - int *targets = (int*)&table[4]; - int entries = table[1]; - int lowKey = s4FromSwitchData(&table[2]); - for (int i = 0; i < entries; i++) { - tabRec->targets[i] = insertCaseLabel(cUnit, baseVaddr + targets[i], - i + lowKey); - } -} - -STATIC void markSparseCaseLabels(CompilationUnit* cUnit, SwitchTable *tabRec) -{ - const u2* table = tabRec->table; - int baseVaddr = tabRec->vaddr; - int entries = table[1]; - int* keys = (int*)&table[2]; - int* targets = &keys[entries]; - for (int i = 0; i < entries; i++) { - tabRec->targets[i] = insertCaseLabel(cUnit, baseVaddr + targets[i], - keys[i]); - } -} - -void oatProcessSwitchTables(CompilationUnit* cUnit) -{ - GrowableListIterator iterator; - oatGrowableListIteratorInit(&cUnit->switchTables, &iterator); - while (true) { - SwitchTable *tabRec = (SwitchTable *) oatGrowableListIteratorNext( - &iterator); - if (tabRec == NULL) break; - if (tabRec->table[0] == kPackedSwitchSignature) - markPackedCaseLabels(cUnit, tabRec); - else if (tabRec->table[0] == kSparseSwitchSignature) - markSparseCaseLabels(cUnit, tabRec); - else { - LOG(FATAL) << "Invalid switch table"; - } - } -} - -STATIC void dumpSparseSwitchTable(const u2* table) - /* - * Sparse switch data format: - * ushort ident = 0x0200 magic value - * ushort size number of entries in the table; > 0 - * int keys[size] keys, sorted low-to-high; 32-bit aligned - * int targets[size] branch targets, relative to switch opcode - * - * Total size is (2+size*4) 16-bit code units. - */ -{ - u2 ident = table[0]; - int entries = table[1]; - int* keys = (int*)&table[2]; - int* targets = &keys[entries]; - LOG(INFO) << "Sparse switch table - ident:0x" << std::hex << ident << - ", entries: " << std::dec << entries; - for (int i = 0; i < entries; i++) { - LOG(INFO) << " Key[" << keys[i] << "] -> 0x" << std::hex << - targets[i]; - } -} - -STATIC void dumpPackedSwitchTable(const u2* table) - /* - * Packed switch data format: - * ushort ident = 0x0100 magic value - * ushort size number of entries in the table - * int first_key first (and lowest) switch case value - * int targets[size] branch targets, relative to switch opcode - * - * Total size is (4+size*2) 16-bit code units. - */ -{ - u2 ident = table[0]; - int* targets = (int*)&table[4]; - int entries = table[1]; - int lowKey = s4FromSwitchData(&table[2]); - LOG(INFO) << "Packed switch table - ident:0x" << std::hex << ident << - ", entries: " << std::dec << entries << ", lowKey: " << lowKey; - for (int i = 0; i < entries; i++) { - LOG(INFO) << " Key[" << (i + lowKey) << "] -> 0x" << std::hex << - targets[i]; - } -} - /* * The sparse table in the literal pool is an array of <key,displacement> * pairs. For each set, we'll load them as a pair using ldmia. @@ -414,10 +43,9 @@ STATIC void dumpPackedSwitchTable(const u2* table) * add rPC, rDisp ; This is the branch from which we compute displacement * cbnz rIdx, lp */ -STATIC void genSparseSwitch(CompilationUnit* cUnit, MIR* mir, - RegLocation rlSrc) +void genSparseSwitch(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc) { - UNIMPLEMENTED(FATAL) << "Need Mips implementation"; + UNIMPLEMENTED(FATAL) << "Needs Mips sparse switch"; #if 0 const u2* table = cUnit->insns + mir->offset + mir->dalvikInsn.vB; if (cUnit->printMe) { @@ -429,8 +57,8 @@ STATIC void genSparseSwitch(CompilationUnit* cUnit, MIR* mir, tabRec->table = table; tabRec->vaddr = mir->offset; int size = table[1]; - tabRec->targets = (MipsLIR* *)oatNew(cUnit, size * sizeof(MipsLIR*), true, - kAllocLIR); + tabRec->targets = (LIR* *)oatNew(cUnit, size * sizeof(LIR*), true, + kAllocLIR); oatInsertGrowableList(cUnit, &cUnit->switchTables, (intptr_t)tabRec); // Get the switch value @@ -451,26 +79,26 @@ STATIC void genSparseSwitch(CompilationUnit* cUnit, MIR* mir, int rIdx = oatAllocTemp(cUnit); loadConstant(cUnit, rIdx, size); // Establish loop branch target - MipsLIR* target = newLIR0(cUnit, kPseudoTargetLabel); + LIR* target = newLIR0(cUnit, kPseudoTargetLabel); target->defMask = ENCODE_ALL; // Load next key/disp newLIR2(cUnit, kThumb2LdmiaWB, rBase, (1 << rKey) | (1 << rDisp)); opRegReg(cUnit, kOpCmp, rKey, rlSrc.lowReg); // Go if match. NOTE: No instruction set switch here - must stay Thumb2 - genIT(cUnit, kMipsCondEq, ""); - MipsLIR* switchBranch = newLIR1(cUnit, kThumb2AddPCR, rDisp); + genIT(cUnit, kArmCondEq, ""); + LIR* switchBranch = newLIR1(cUnit, kThumb2AddPCR, rDisp); tabRec->bxInst = switchBranch; // Needs to use setflags encoding here newLIR3(cUnit, kThumb2SubsRRI12, rIdx, rIdx, 1); - MipsLIR* branch = opCondBranch(cUnit, kMipsCondNe); - branch->generic.target = (LIR*)target; + LIR* branch = opCondBranch(cUnit, kCondNe); + branch->target = (LIR*)target; #endif } -STATIC void genPackedSwitch(CompilationUnit* cUnit, MIR* mir, - RegLocation rlSrc) + +void genPackedSwitch(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc) { - UNIMPLEMENTED(FATAL) << "Need Mips implementation"; + UNIMPLEMENTED(FATAL) << "Need Mips packed switch"; #if 0 const u2* table = cUnit->insns + mir->offset + mir->dalvikInsn.vB; if (cUnit->printMe) { @@ -482,7 +110,7 @@ STATIC void genPackedSwitch(CompilationUnit* cUnit, MIR* mir, tabRec->table = table; tabRec->vaddr = mir->offset; int size = table[1]; - tabRec->targets = (MipsLIR* *)oatNew(cUnit, size * sizeof(MipsLIR*), true, + tabRec->targets = (LIR* *)oatNew(cUnit, size * sizeof(LIR*), true, kAllocLIR); oatInsertGrowableList(cUnit, &cUnit->switchTables, (intptr_t)tabRec); @@ -502,20 +130,20 @@ STATIC void genPackedSwitch(CompilationUnit* cUnit, MIR* mir, } // Bounds check - if < 0 or >= size continue following switch opRegImm(cUnit, kOpCmp, keyReg, size-1); - MipsLIR* branchOver = opCondBranch(cUnit, kMipsCondHi); + LIR* branchOver = opCondBranch(cUnit, kCondHi); // Load the displacement from the switch table int dispReg = oatAllocTemp(cUnit); loadBaseIndexed(cUnit, tableBase, keyReg, dispReg, 2, kWord); // ..and go! NOTE: No instruction set switch here - must stay Thumb2 - MipsLIR* switchBranch = newLIR1(cUnit, kThumb2AddPCR, dispReg); + LIR* switchBranch = newLIR1(cUnit, kThumb2AddPCR, dispReg); tabRec->bxInst = switchBranch; /* branchOver target here */ - MipsLIR* target = newLIR0(cUnit, kPseudoTargetLabel); + LIR* target = newLIR0(cUnit, kPseudoTargetLabel); target->defMask = ENCODE_ALL; - branchOver->generic.target = (LIR*)target; + branchOver->target = (LIR*)target; #endif } @@ -529,10 +157,9 @@ STATIC void genPackedSwitch(CompilationUnit* cUnit, MIR* mir, * * Total size is 4+(width * size + 1)/2 16-bit code units. */ -STATIC void genFillArrayData(CompilationUnit* cUnit, MIR* mir, - RegLocation rlSrc) +void genFillArrayData(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc) { - UNIMPLEMENTED(FATAL) << "Need Mips implementation"; + UNIMPLEMENTED(FATAL) << "Needs Mips FillArrayData"; #if 0 const u2* table = cUnit->insns + mir->offset + mir->dalvikInsn.vB; // Add the table to the list - we'll process it later @@ -548,7 +175,7 @@ STATIC void genFillArrayData(CompilationUnit* cUnit, MIR* mir, // Making a call - use explicit registers oatFlushAllRegs(cUnit); /* Everything to home location */ - loadValueDirectFixed(cUnit, rlSrc, r0); + loadValueDirectFixed(cUnit, rlSrc, rARG0); loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pHandleFillArrayDataFromCode), rLR); // Materialize a pointer to the fill data image @@ -557,275 +184,186 @@ STATIC void genFillArrayData(CompilationUnit* cUnit, MIR* mir, #endif } -STATIC void genIGet(CompilationUnit* cUnit, MIR* mir, OpSize size, - RegLocation rlDest, RegLocation rlObj, - bool isLongOrDouble, bool isObject) +/* + * TODO: implement fast path to short-circuit thin-lock case + */ +void genMonitorEnter(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc) { - UNIMPLEMENTED(FATAL) << "Need Mips implementation"; -#if 0 - int fieldOffset; - bool isVolatile; - uint32_t fieldIdx = mir->dalvikInsn.vC; - bool fastPath = - cUnit->compiler->ComputeInstanceFieldInfo(fieldIdx, cUnit, - fieldOffset, isVolatile, false); - if (fastPath && !SLOW_FIELD_PATH) { - RegLocation rlResult; - RegisterClass regClass = oatRegClassBySize(size); - DCHECK_GE(fieldOffset, 0); - rlObj = loadValue(cUnit, rlObj, kCoreReg); - if (isLongOrDouble) { - DCHECK(rlDest.wide); - genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir);/* null obj? */ - int regPtr = oatAllocTemp(cUnit); - opRegRegImm(cUnit, kOpAdd, regPtr, rlObj.lowReg, fieldOffset); - rlResult = oatEvalLoc(cUnit, rlDest, regClass, true); - loadPair(cUnit, regPtr, rlResult.lowReg, rlResult.highReg); - if (isVolatile) { - oatGenMemBarrier(cUnit, kSY); - } - oatFreeTemp(cUnit, regPtr); - storeValueWide(cUnit, rlDest, rlResult); - } else { - rlResult = oatEvalLoc(cUnit, rlDest, regClass, true); - genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir);/* null object? */ - loadBaseDisp(cUnit, mir, rlObj.lowReg, fieldOffset, rlResult.lowReg, - kWord, rlObj.sRegLow); - if (isVolatile) { - oatGenMemBarrier(cUnit, kSY); - } - storeValue(cUnit, rlDest, rlResult); - } - } else { - int getterOffset = isLongOrDouble ? OFFSETOF_MEMBER(Thread, pGet64Instance) : - (isObject ? OFFSETOF_MEMBER(Thread, pGetObjInstance) - : OFFSETOF_MEMBER(Thread, pGet32Instance)); - loadWordDisp(cUnit, rSELF, getterOffset, rLR); - loadValueDirect(cUnit, rlObj, r1); - loadConstant(cUnit, r0, fieldIdx); - callRuntimeHelper(cUnit, rLR); - if (isLongOrDouble) { - RegLocation rlResult = oatGetReturnWide(cUnit); - storeValueWide(cUnit, rlDest, rlResult); - } else { - RegLocation rlResult = oatGetReturn(cUnit); - storeValue(cUnit, rlDest, rlResult); - } - } -#endif + oatFlushAllRegs(cUnit); + loadValueDirectFixed(cUnit, rlSrc, rARG0); // Get obj + oatLockCallTemps(cUnit); // Prepare for explicit register usage + genNullCheck(cUnit, rlSrc.sRegLow, rARG0, mir); + // Go expensive route - artLockObjectFromCode(self, obj); + int rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread, pLockObjectFromCode)); + callRuntimeHelper(cUnit, rTgt); } /* - * Perform a "reg cmp imm" operation and jump to the PCR region if condition - * satisfies. + * TODO: implement fast path to short-circuit thin-lock case */ -STATIC void genNegFloat(CompilationUnit *cUnit, RegLocation rlDest, - RegLocation rlSrc) +void genMonitorExit(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc) { - RegLocation rlResult; - rlSrc = loadValue(cUnit, rlSrc, kCoreReg); - rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true); - opRegRegImm(cUnit, kOpAdd, rlResult.lowReg, - rlSrc.lowReg, 0x80000000); - storeValue(cUnit, rlDest, rlResult); + oatFlushAllRegs(cUnit); + loadValueDirectFixed(cUnit, rlSrc, rARG0); // Get obj + oatLockCallTemps(cUnit); // Prepare for explicit register usage + genNullCheck(cUnit, rlSrc.sRegLow, rARG0, mir); + // Go expensive route - UnlockObjectFromCode(obj); + int rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread, pUnlockObjectFromCode)); + callRuntimeHelper(cUnit, rTgt); } -STATIC void genNegDouble(CompilationUnit *cUnit, RegLocation rlDest, - RegLocation rlSrc) +/* + * Compare two 64-bit values + * x = y return 0 + * x < y return -1 + * x > y return 1 + * + * slt t0, x.hi, y.hi; # (x.hi < y.hi) ? 1:0 + * sgt t1, x.hi, y.hi; # (y.hi > x.hi) ? 1:0 + * subu res, t0, t1 # res = -1:1:0 for [ < > = ] + * bnez res, finish + * sltu t0, x.lo, y.lo + * sgtu r1, x.lo, y.lo + * subu res, t0, t1 + * finish: + * + */ +void genCmpLong(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest, + RegLocation rlSrc1, RegLocation rlSrc2) { - RegLocation rlResult; - rlSrc = loadValueWide(cUnit, rlSrc, kCoreReg); - rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true); - opRegRegImm(cUnit, kOpAdd, rlResult.highReg, rlSrc.highReg, - 0x80000000); - genRegCopy(cUnit, rlResult.lowReg, rlSrc.lowReg); - storeValueWide(cUnit, rlDest, rlResult); + rlSrc1 = loadValueWide(cUnit, rlSrc1, kCoreReg); + rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg); + int t0 = oatAllocTemp(cUnit); + int t1 = oatAllocTemp(cUnit); + RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true); + newLIR3(cUnit, kMipsSlt, t0, rlSrc1.highReg, rlSrc2.highReg); + newLIR3(cUnit, kMipsSlt, t1, rlSrc2.highReg, rlSrc1.highReg); + newLIR3(cUnit, kMipsSubu, rlResult.lowReg, t1, t0); + LIR* branch = genCmpImmBranch(cUnit, kCondNe, rlResult.lowReg, 0); + newLIR3(cUnit, kMipsSltu, t0, rlSrc1.lowReg, rlSrc2.lowReg); + newLIR3(cUnit, kMipsSltu, t1, rlSrc2.lowReg, rlSrc1.lowReg); + newLIR3(cUnit, kMipsSubu, rlResult.lowReg, t1, t0); + oatFreeTemp(cUnit, t0); + oatFreeTemp(cUnit, t1); + LIR* target = newLIR0(cUnit, kPseudoTargetLabel); + target->defMask = ENCODE_ALL; + branch->target = (LIR*)target; + storeValue(cUnit, rlDest, rlResult); } -STATIC void genMulLong(CompilationUnit *cUnit, RegLocation rlDest, - RegLocation rlSrc1, RegLocation rlSrc2) +LIR* genCompareBranch(CompilationUnit* cUnit, ConditionCode cond, int src1, + int src2) { - UNIMPLEMENTED(FATAL) << "Need Mips implementation"; -#if 0 - RegLocation rlResult; - loadValueDirectWideFixed(cUnit, rlSrc1, r_ARG0, r_ARG1); - loadValueDirectWideFixed(cUnit, rlSrc2, r_ARG2, r_ARG3); - genDispatchToHandler(cUnit, TEMPLATE_MUL_LONG); - rlResult = oatGetReturnWide(cUnit); - storeValueWide(cUnit, rlDest, rlResult); -#endif + if (cond == kCondEq) { + return newLIR2(cUnit, kMipsBeq, src1, src2); + } else if (cond == kCondNe) { + return newLIR2(cUnit, kMipsBne, src1, src2); + } + //int rRes = oatAllocTemp(cUnit); + switch(cond) { + case kCondEq: return newLIR2(cUnit, kMipsBeq, src1, src2); + case kCondNe: return newLIR2(cUnit, kMipsBne, src1, src2); + default: + UNIMPLEMENTED(FATAL) << "Need to flesh out genCompareBranch"; + return NULL; + } } -STATIC bool partialOverlap(int sreg1, int sreg2) +LIR* genCmpImmBranch(CompilationUnit* cUnit, ConditionCode cond, int reg, + int checkValue) { - return abs(sreg1 - sreg2) == 1; + if (checkValue != 0) { + // TUNING: handle s16 & kCondLt/Mi case using slti + int tReg = oatAllocTemp(cUnit); + loadConstant(cUnit, tReg, checkValue); + return genCompareBranch(cUnit, cond, reg, tReg); + } + MipsOpCode opc; + switch(cond) { + case kCondEq: opc = kMipsBeqz; break; + case kCondGe: opc = kMipsBgez; break; + case kCondGt: opc = kMipsBgtz; break; + case kCondLe: opc = kMipsBlez; break; + //case KCondMi: + case kCondLt: opc = kMipsBltz; break; + case kCondNe: opc = kMipsBnez; break; + default: + int tReg = oatAllocTemp(cUnit); + loadConstant(cUnit, tReg, checkValue); + return genCompareBranch(cUnit, cond, reg, tReg); + } + return newLIR1(cUnit, opc, reg); } -STATIC void withCarryHelper(CompilationUnit *cUnit, MipsOpCode opc, - RegLocation rlDest, RegLocation rlSrc1, - RegLocation rlSrc2, int sltuSrc1, int sltuSrc2) +LIR* genRegCopyNoInsert(CompilationUnit *cUnit, int rDest, int rSrc) { - int tReg = oatAllocTemp(cUnit); - newLIR3(cUnit, opc, rlDest.lowReg, rlSrc1.lowReg, rlSrc2.lowReg); - newLIR3(cUnit, kMipsSltu, tReg, sltuSrc1, sltuSrc2); - newLIR3(cUnit, opc, rlDest.highReg, rlSrc1.highReg, rlSrc2.highReg); - newLIR3(cUnit, opc, rlDest.highReg, rlDest.highReg, tReg); - oatFreeTemp(cUnit, tReg); + LIR* res; + MipsOpCode opcode; +#ifdef __mips_hard_float + if (FPREG(rDest) || FPREG(rSrc)) + return fpRegCopy(cUnit, rDest, rSrc); +#endif + res = (LIR *) oatNew(cUnit, sizeof(LIR), true, kAllocLIR); + opcode = kMipsMove; + assert(LOWREG(rDest) && LOWREG(rSrc)); + res->operands[0] = rDest; + res->operands[1] = rSrc; + res->opcode = opcode; + setupResourceMasks(res); + if (rDest == rSrc) { + res->flags.isNop = true; + } + return res; } -STATIC void genLong3Addr(CompilationUnit *cUnit, MIR *mir, OpKind firstOp, - OpKind secondOp, RegLocation rlDest, - RegLocation rlSrc1, RegLocation rlSrc2) +LIR* genRegCopy(CompilationUnit *cUnit, int rDest, int rSrc) { - UNIMPLEMENTED(FATAL) << "Need Mips implementation"; -#if 0 - RegLocation rlResult; - int carryOp = (secondOp == kOpAdc || secondOp == kOpSbc); + LIR *res = genRegCopyNoInsert(cUnit, rDest, rSrc); + oatAppendLIR(cUnit, (LIR*)res); + return res; +} - 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) { - rlResult = loadValueWide(cUnit, rlDest, kCoreReg); - rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg); - if (!carryOp) { - opRegRegReg(cUnit, firstOp, rlResult.lowReg, rlResult.lowReg, rlSrc2.lowReg); - opRegRegReg(cUnit, secondOp, rlResult.highReg, rlResult.highReg, rlSrc2.highReg); - } else if (secondOp == kOpAdc) { - withCarryHelper(cUnit, kMipsAddu, rlResult, rlResult, rlSrc2, - rlResult.lowReg, rlSrc2.lowReg); - } else { - int tReg = oatAllocTemp(cUnit); - newLIR2(cUnit, kMipsMove, tReg, rlResult.lowReg); - withCarryHelper(cUnit, kMipsSubu, rlResult, rlResult, rlSrc2, - tReg, rlResult.lowReg); - oatFreeTemp(cUnit, tReg); - } - storeValueWide(cUnit, rlDest, rlResult); - } else if (rlDest.sRegLow == rlSrc2.sRegLow) { - rlResult = loadValueWide(cUnit, rlDest, kCoreReg); - rlSrc1 = loadValueWide(cUnit, rlSrc1, kCoreReg); - if (!carryOp) { - opRegRegReg(cUnit, firstOp, rlResult.lowReg, rlSrc1.lowReg, rlResult.lowReg); - opRegRegReg(cUnit, secondOp, rlResult.highReg, rlSrc1.highReg, rlResult.highReg); - } else if (secondOp == kOpAdc) { - withCarryHelper(cUnit, kMipsAddu, rlResult, rlSrc1, rlResult, - rlResult.lowReg, rlSrc1.lowReg); +void genRegCopyWide(CompilationUnit *cUnit, int destLo, int destHi, + int srcLo, int srcHi) +{ +#ifdef __mips_hard_float + bool destFP = FPREG(destLo) && FPREG(destHi); + bool srcFP = FPREG(srcLo) && FPREG(srcHi); + assert(FPREG(srcLo) == FPREG(srcHi)); + assert(FPREG(destLo) == FPREG(destHi)); + if (destFP) { + if (srcFP) { + genRegCopy(cUnit, S2D(destLo, destHi), S2D(srcLo, srcHi)); } else { - withCarryHelper(cUnit, kMipsSubu, rlResult, rlSrc1, rlResult, - rlSrc1.lowReg, rlResult.lowReg); + /* note the operands are swapped for the mtc1 instr */ + newLIR2(cUnit, kMipsMtc1, srcLo, destLo); + newLIR2(cUnit, kMipsMtc1, srcHi, destHi); } - storeValueWide(cUnit, rlDest, rlResult); } else { - rlSrc1 = loadValueWide(cUnit, rlSrc1, kCoreReg); - rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg); - rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true); - if (!carryOp) { - opRegRegReg(cUnit, firstOp, rlResult.lowReg, rlSrc1.lowReg, rlSrc2.lowReg); - opRegRegReg(cUnit, secondOp, rlResult.highReg, rlSrc1.highReg, rlSrc2.highReg); - } else if (secondOp == kOpAdc) { - withCarryHelper(cUnit, kMipsAddu, rlResult, rlSrc1, rlSrc2, - rlResult.lowReg, rlSrc1.lowReg); + if (srcFP) { + newLIR2(cUnit, kMipsMfc1, destLo, srcLo); + newLIR2(cUnit, kMipsMfc1, destHi, srcHi); } else { - withCarryHelper(cUnit, kMipsSubu, rlResult, rlSrc1, rlSrc2, - rlSrc1.lowReg, rlResult.lowReg); + // Handle overlap + if (srcHi == destLo) { + genRegCopy(cUnit, destHi, srcHi); + genRegCopy(cUnit, destLo, srcLo); + } else { + genRegCopy(cUnit, destLo, srcLo); + genRegCopy(cUnit, destHi, srcHi); + } } - storeValueWide(cUnit, rlDest, rlResult); } -#endif -} - -void oatInitializeRegAlloc(CompilationUnit* cUnit) -{ - int numRegs = sizeof(coreRegs)/sizeof(*coreRegs); - int numReserved = sizeof(reservedRegs)/sizeof(*reservedRegs); - int numTemps = sizeof(coreTemps)/sizeof(*coreTemps); -#ifdef __mips_hard_float - int numFPRegs = sizeof(fpRegs)/sizeof(*fpRegs); - int numFPTemps = sizeof(fpTemps)/sizeof(*fpTemps); #else - int numFPRegs = 0; - int numFPTemps = 0; -#endif - RegisterPool *pool = (RegisterPool *)oatNew(cUnit, sizeof(*pool), true, - kAllocRegAlloc); - cUnit->regPool = pool; - pool->numCoreRegs = numRegs; - pool->coreRegs = (RegisterInfo *) - oatNew(cUnit, numRegs * sizeof(*cUnit->regPool->coreRegs), - true, kAllocRegAlloc); - pool->numFPRegs = numFPRegs; - pool->FPRegs = numFPRegs == 0 ? NULL : (RegisterInfo *) - oatNew(cUnit, numFPRegs * sizeof(*cUnit->regPool->FPRegs), true, - kAllocRegAlloc); - oatInitPool(pool->coreRegs, coreRegs, pool->numCoreRegs); - oatInitPool(pool->FPRegs, fpRegs, pool->numFPRegs); - // Keep special registers from being allocated - for (int i = 0; i < numReserved; i++) { - if (NO_SUSPEND && !cUnit->genDebugger && - (reservedRegs[i] == rSUSPEND)) { - //To measure cost of suspend check - continue; - } - oatMarkInUse(cUnit, reservedRegs[i]); - } - // Mark temp regs - all others not in use can be used for promotion - for (int i = 0; i < numTemps; i++) { - oatMarkTemp(cUnit, coreTemps[i]); - } - for (int i = 0; i < numFPTemps; i++) { - oatMarkTemp(cUnit, fpTemps[i]); - } - // Construct the alias map. - cUnit->phiAliasMap = (int*)oatNew(cUnit, cUnit->numSSARegs * - sizeof(cUnit->phiAliasMap[0]), false, - kAllocDFInfo); - for (int i = 0; i < cUnit->numSSARegs; i++) { - cUnit->phiAliasMap[i] = i; - } - for (MIR* phi = cUnit->phiList; phi; phi = phi->meta.phiNext) { - int defReg = phi->ssaRep->defs[0]; - for (int i = 0; i < phi->ssaRep->numUses; i++) { - for (int j = 0; j < cUnit->numSSARegs; j++) { - if (cUnit->phiAliasMap[j] == phi->ssaRep->uses[i]) { - cUnit->phiAliasMap[j] = defReg; - } - } - } + // Handle overlap + if (srcHi == destLo) { + genRegCopy(cUnit, destHi, srcHi); + genRegCopy(cUnit, destLo, srcLo); + } else { + genRegCopy(cUnit, destLo, srcLo); + genRegCopy(cUnit, destHi, srcHi); } -} - -STATIC void genMonitor(CompilationUnit *cUnit, MIR *mir) -{ - UNIMPLEMENTED(FATAL) << "Need Mips implementation"; -#if 0 - genMonitorPortable(cUnit, mir); #endif } -STATIC void genCmpLong(CompilationUnit *cUnit, MIR *mir, RegLocation rlDest, - RegLocation rlSrc1, RegLocation rlSrc2) -{ - UNIMPLEMENTED(FATAL) << "Need Mips implementation"; -#if 0 - RegLocation rlResult; - loadValueDirectWideFixed(cUnit, rlSrc1, r_ARG0, r_ARG1); - loadValueDirectWideFixed(cUnit, rlSrc2, r_ARG2, r_ARG3); - genDispatchToHandler(cUnit, TEMPLATE_CMP_LONG); - rlResult = oatGetReturn(cUnit); - storeValue(cUnit, rlDest, rlResult); -#endif -} - -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); -} - } // namespace art diff --git a/src/compiler/codegen/mips/Mips32/Ralloc.cc b/src/compiler/codegen/mips/Mips32/Ralloc.cc index e0912d77b8..f8440a45da 100644 --- a/src/compiler/codegen/mips/Mips32/Ralloc.cc +++ b/src/compiler/codegen/mips/Mips32/Ralloc.cc @@ -61,4 +61,76 @@ int oatAllocTypedTemp(CompilationUnit *cUnit, bool fpHint, int regClass) return oatAllocTemp(cUnit); } +void oatInitializeRegAlloc(CompilationUnit* cUnit) +{ + int numRegs = sizeof(coreRegs)/sizeof(*coreRegs); + int numReserved = sizeof(reservedRegs)/sizeof(*reservedRegs); + int numTemps = sizeof(coreTemps)/sizeof(*coreTemps); +#ifdef __mips_hard_float + int numFPRegs = sizeof(fpRegs)/sizeof(*fpRegs); + int numFPTemps = sizeof(fpTemps)/sizeof(*fpTemps); +#else + int numFPRegs = 0; + int numFPTemps = 0; +#endif + RegisterPool *pool = (RegisterPool *)oatNew(cUnit, sizeof(*pool), true, + kAllocRegAlloc); + cUnit->regPool = pool; + pool->numCoreRegs = numRegs; + pool->coreRegs = (RegisterInfo *) + oatNew(cUnit, numRegs * sizeof(*cUnit->regPool->coreRegs), + true, kAllocRegAlloc); + pool->numFPRegs = numFPRegs; + pool->FPRegs = (RegisterInfo *) + oatNew(cUnit, numFPRegs * sizeof(*cUnit->regPool->FPRegs), true, + kAllocRegAlloc); + oatInitPool(pool->coreRegs, coreRegs, pool->numCoreRegs); + oatInitPool(pool->FPRegs, fpRegs, pool->numFPRegs); + // Keep special registers from being allocated + for (int i = 0; i < numReserved; i++) { + if (NO_SUSPEND && !cUnit->genDebugger && + (reservedRegs[i] == rSUSPEND)) { + //To measure cost of suspend check + continue; + } + oatMarkInUse(cUnit, reservedRegs[i]); + } + // Mark temp regs - all others not in use can be used for promotion + for (int i = 0; i < numTemps; i++) { + oatMarkTemp(cUnit, coreTemps[i]); + } + for (int i = 0; i < numFPTemps; i++) { + oatMarkTemp(cUnit, fpTemps[i]); + } + // Construct the alias map. + cUnit->phiAliasMap = (int*)oatNew(cUnit, cUnit->numSSARegs * + sizeof(cUnit->phiAliasMap[0]), false, + kAllocDFInfo); + for (int i = 0; i < cUnit->numSSARegs; i++) { + cUnit->phiAliasMap[i] = i; + } + for (MIR* phi = cUnit->phiList; phi; phi = phi->meta.phiNext) { + int defReg = phi->ssaRep->defs[0]; + for (int i = 0; i < phi->ssaRep->numUses; i++) { + for (int j = 0; j < cUnit->numSSARegs; j++) { + if (cUnit->phiAliasMap[j] == phi->ssaRep->uses[i]) { + cUnit->phiAliasMap[j] = defReg; + } + } + } + } +} + +void freeRegLocTemps(CompilationUnit* cUnit, RegLocation rlKeep, + RegLocation rlFree) +{ + if ((rlFree.lowReg != rlKeep.lowReg) && (rlFree.lowReg != rlKeep.highReg) && + (rlFree.highReg != rlKeep.lowReg) && (rlFree.highReg != rlKeep.highReg)) { + // No overlap, free both + oatFreeTemp(cUnit, rlFree.lowReg); + oatFreeTemp(cUnit, rlFree.highReg); + } +} + + } // namespace art diff --git a/src/compiler/codegen/mips/MipsLIR.h b/src/compiler/codegen/mips/MipsLIR.h index 44f0c5a2b9..93956d5d5f 100644 --- a/src/compiler/codegen/mips/MipsLIR.h +++ b/src/compiler/codegen/mips/MipsLIR.h @@ -149,10 +149,10 @@ namespace art { INVALID_SREG} #define LOC_C_RETURN_ALT {kLocPhysReg, 0, 0, 0, 0, 0, 1, r_F0, INVALID_REG, \ INVALID_SREG} -#define LOC_C_RETURN_WIDE {kLocPhysReg, 1, 0, 0, 0, 0, 1, r_V0, r_V1,\ - INVALID_SREG} -#define LOC_C_RETURN_WIDE_ALT {kLocPhysReg, 1, 0, 0, 0, 0, 1, r_F0, r_F1,\ +#define LOC_C_RETURN_WIDE {kLocPhysReg, 1, 0, 0, 0, 0, 1, r_RESULT0, r_RESULT1,\ INVALID_SREG} +#define LOC_C_RETURN_WIDE_ALT {kLocPhysReg, 1, 0, 0, 0, 0, 1, r_FRESULT0,\ + r_FRESULT1, INVALID_SREG} typedef enum ResourceEncodingPos { kGPReg0 = 0, @@ -194,25 +194,6 @@ typedef enum ResourceEncodingPos { #define DECODE_ALIAS_INFO_WIDE(X) ((X & 0x80000000) ? 1 : 0) /* - * FIXME: - * Originally had r4PC as r_S0, rFP as r_S1, rSELF as r_S2, rINST as r_S4 - * Remap - don't need r4PC, rFP or rINST. Might make sense to keep - * Method* in one of these since we have so many registers to play with. - */ - -#define rSUSPEND r_S0 -#define rSELF r_S1 -#define rSP r_SP - -#define rARG0 r_ARG0 -#define rARG1 r_ARG1 -#define rARG2 r_ARG2 -#define rARG3 r_ARG3 - -#define rRET0 r_V0 -#define rRET1 r_V1 - -/* * Annotate special-purpose core registers: */ @@ -307,6 +288,21 @@ typedef enum NativeRegisterPool { r_PC, } NativeRegisterPool; +/* + * Target-independent aliases + */ + +#define rSUSPEND r_S0 +#define rSELF r_S1 +#define rSP r_SP +#define rARG0 r_ARG0 +#define rARG1 r_ARG1 +#define rARG2 r_ARG2 +#define rARG3 r_ARG3 +#define rRET0 r_RESULT0 +#define rRET1 r_RESULT1 +#define rLINK r_RA + /* Shift encodings */ typedef enum MipsShiftEncodings { kMipsLsl = 0x0, @@ -335,15 +331,9 @@ typedef enum MipsConditionCode { kMipsCondNv = 0xf, /* 1111 */ } MipsConditionCode; -typedef enum MipsThrowKind { - kMipsThrowNullPointer, - kMipsThrowDivZero, - kMipsThrowArrayBounds, - kMipsThrowVerificationError, - kMipsThrowNegArraySize, - kMipsThrowNoSuchMethod, - kMipsThrowStackOverflow, -} MipsThrowKind; +// FIXME: Need support for barriers. Adding these defines to allow compile +#define kST 0 +#define kSY 1 #define isPseudoOpcode(opCode) ((int)(opCode) < 0) @@ -487,6 +477,8 @@ typedef enum MipsOpFeatureFlags { kUsesCCodes, kMemLoad, kMemStore, + kPCRelFixup, +// FIXME: add NEEDS_FIXUP to instruction attributes } MipsOpFeatureFlags; #define IS_LOAD (1 << kMemLoad) @@ -514,6 +506,12 @@ typedef enum MipsOpFeatureFlags { #define IS_IT (1 << kIsIT) #define SETS_CCODES (1 << kSetsCCodes) #define USES_CCODES (1 << kUsesCCodes) +#define NEEDS_FIXUP (1 << kPCRelFixup) + +/* attributes, included for compatibility */ +#define REG_DEF_FPCS_LIST0 (0) +#define REG_DEF_FPCS_LIST2 (0) + /* Common combo register usage patterns */ #define REG_USE01 (REG_USE0 | REG_USE1) @@ -559,63 +557,6 @@ typedef enum MipsTargetOptHints { extern MipsEncodingMap EncodingMap[kMipsLast]; -/* - * Each instance of this struct holds a pseudo or real LIR instruction: - * - pseudo ones (eg labels and marks) and will be discarded by the assembler. - * - real ones will be assembled - * - * FIXME: notes below are Arm-specific. We have 32 core registers instead - * of 16, and no IT blocks. Must widen this or overload in order to - * support all 32 FP regs. Perhaps use r0 for ccodes, eliminate IT block - * and overload gp with fp status word? (or just use a single bit for - * both core and fp condition code/status word? - * - * Machine resources are encoded into a 64-bit vector, where the encodings are - * as following: - * - [ 0..15]: general purpose registers including PC, SP, and LR - * - [16..47]: floating-point registers where d0 is expanded to s[01] and s0 - * starts at bit 16 - * - [48]: IT block - * - [49]: integer condition code - * - [50]: floatint-point status word - */ -typedef struct MipsLIR { - LIR generic; - MipsOpCode opcode; - int operands[4]; // [0..3] = [dest, src1, src2, extra] - struct { - bool isNop:1; // LIR is optimized away - bool pcRelFixup:1; // May need pc-relative fixup - unsigned int age:4; // default is 0, set lazily by the optimizer - unsigned int size:3; // in bytes - unsigned int unused:23; - } flags; - int aliasInfo; // For Dalvik register access & litpool disambiguation - u8 useMask; // Resource mask for use - u8 defMask; // Resource mask for def -} MipsLIR; - -typedef struct SwitchTable { - int offset; - const u2* table; // Original dex table - int vaddr; // Dalvik offset of switch opcode - MipsLIR* bxInst; // Switch indirect branch instruction - MipsLIR** targets; // Array of case targets -} SwitchTable; - -typedef struct FillArrayData { - int offset; - const u2* table; // Original dex table - int size; - int vaddr; // Dalvik offset of OP_FILL_ARRAY_DATA opcode -} FillArrayData; - -/* Utility macros to traverse the LIR/MipsLIR list */ -#define NEXT_LIR(lir) ((MipsLIR *) lir->generic.next) -#define PREV_LIR(lir) ((MipsLIR *) lir->generic.prev) - -#define NEXT_LIR_LVALUE(lir) (lir)->generic.next -#define PREV_LIR_LVALUE(lir) (lir)->generic.prev #define IS_UIMM16(v) ((0 <= (v)) && ((v) <= 65535)) #define IS_SIMM16(v) ((-32768 <= (v)) && ((v) <= 32766)) diff --git a/src/compiler/codegen/mips/MipsRallocUtil.cc b/src/compiler/codegen/mips/MipsRallocUtil.cc index 0dfbfa5065..504375b572 100644 --- a/src/compiler/codegen/mips/MipsRallocUtil.cc +++ b/src/compiler/codegen/mips/MipsRallocUtil.cc @@ -48,20 +48,6 @@ void oatAdjustSpillMask(CompilationUnit* cUnit) void oatMarkPreservedSingle(CompilationUnit* cUnit, int sReg, int reg) { UNIMPLEMENTED(FATAL) << "No support yet for promoted FP regs"; -#if 0 - DCHECK_GE(reg, FP_REG_MASK + FP_CALLEE_SAVE_BASE); - reg = (reg & FP_REG_MASK) - FP_CALLEE_SAVE_BASE; - // Ensure fpVmapTable is large enough - int tableSize = cUnit->fpVmapTable.size(); - for (int i = tableSize; i < (reg + 1); i++) { - cUnit->fpVmapTable.push_back(INVALID_VREG); - } - // Add the current mapping - cUnit->fpVmapTable[reg] = sReg; - // Size of fpVmapTable is high-water mark, use to set mask - cUnit->numFPSpills = cUnit->fpVmapTable.size(); - cUnit->fpSpillMask = ((1 << cUnit->numFPSpills) - 1) << FP_CALLEE_SAVE_BASE; -#endif } void oatFlushRegWide(CompilationUnit* cUnit, int reg1, int reg2) @@ -159,10 +145,10 @@ extern void oatClobberCalleeSave(CompilationUnit *cUnit) extern RegLocation oatGetReturnWide(CompilationUnit* cUnit) { RegLocation res = LOC_C_RETURN_WIDE; - oatClobber(cUnit, r_V0); - oatClobber(cUnit, r_V1); - oatMarkInUse(cUnit, r_V0); - oatMarkInUse(cUnit, r_V1); + oatClobber(cUnit, res.lowReg); + oatClobber(cUnit, res.highReg); + oatMarkInUse(cUnit, res.lowReg); + oatMarkInUse(cUnit, res.highReg); oatMarkPair(cUnit, res.lowReg, res.highReg); return res; } @@ -170,10 +156,10 @@ extern RegLocation oatGetReturnWide(CompilationUnit* cUnit) extern RegLocation oatGetReturnWideAlt(CompilationUnit* cUnit) { RegLocation res = LOC_C_RETURN_WIDE_ALT; - oatClobber(cUnit, r_F0); - oatClobber(cUnit, r_F1); - oatMarkInUse(cUnit, r_F0); - oatMarkInUse(cUnit, r_F1); + oatClobber(cUnit, res.lowReg); + oatClobber(cUnit, res.highReg); + oatMarkInUse(cUnit, res.lowReg); + oatMarkInUse(cUnit, res.highReg); oatMarkPair(cUnit, res.lowReg, res.highReg); return res; } @@ -181,16 +167,16 @@ extern RegLocation oatGetReturnWideAlt(CompilationUnit* cUnit) extern RegLocation oatGetReturn(CompilationUnit* cUnit) { RegLocation res = LOC_C_RETURN; - oatClobber(cUnit, r_V0); - oatMarkInUse(cUnit, r_V0); + oatClobber(cUnit, res.lowReg); + oatMarkInUse(cUnit, res.lowReg); return res; } extern RegLocation oatGetReturnAlt(CompilationUnit* cUnit) { RegLocation res = LOC_C_RETURN_ALT; - oatClobber(cUnit, r_F0); - oatMarkInUse(cUnit, r_F0); + oatClobber(cUnit, res.lowReg); + oatMarkInUse(cUnit, res.lowReg); return res; } @@ -203,25 +189,25 @@ extern RegisterInfo* oatGetRegInfo(CompilationUnit* cUnit, int reg) /* To be used when explicitly managing register use */ extern void oatLockCallTemps(CompilationUnit* cUnit) { - oatLockTemp(cUnit, r_A0); - oatLockTemp(cUnit, r_A1); - oatLockTemp(cUnit, r_A2); - oatLockTemp(cUnit, r_A3); + oatLockTemp(cUnit, rARG0); + oatLockTemp(cUnit, rARG1); + oatLockTemp(cUnit, rARG2); + oatLockTemp(cUnit, rARG3); } /* To be used when explicitly managing register use */ extern void oatFreeCallTemps(CompilationUnit* cUnit) { - oatFreeTemp(cUnit, r_A0); - oatFreeTemp(cUnit, r_A1); - oatFreeTemp(cUnit, r_A2); - oatFreeTemp(cUnit, r_A3); + oatFreeTemp(cUnit, rARG0); + oatFreeTemp(cUnit, rARG1); + oatFreeTemp(cUnit, rARG2); + oatFreeTemp(cUnit, rARG3); } /* Convert an instruction to a NOP */ -STATIC void oatNopLIR( LIR* lir) +void oatNopLIR( LIR* lir) { - ((MipsLIR*)lir)->flags.isNop = true; + ((LIR*)lir)->flags.isNop = true; } } // namespace art diff --git a/src/compiler/codegen/mips/mips/Codegen.cc b/src/compiler/codegen/mips/mips/Codegen.cc index 22a7c94209..71f43e55fd 100644 --- a/src/compiler/codegen/mips/mips/Codegen.cc +++ b/src/compiler/codegen/mips/mips/Codegen.cc @@ -15,7 +15,7 @@ */ #define _CODEGEN_C -#define TGT_LIR MipsLIR +#define TARGET_MIPS #include "../../../Dalvik.h" #include "../../../CompilerInternals.h" @@ -24,12 +24,16 @@ #include "../Codegen.h" /* Mips codegen building blocks */ -#include "../CodegenCommon.cc" +#include "../../CodegenUtil.cc" /* Mips-specific factory utilities */ #include "../Mips32/Factory.cc" -/* Target indepedent factory utilities */ +/* Target independent factory utilities */ #include "../../CodegenFactory.cc" +/* Target independent gen routines */ +#include "../../GenCommon.cc" +/* Shared invoke gen routines */ +#include "../../GenInvoke.cc" /* Mips-specific factory utilities */ #include "../ArchFactory.cc" @@ -47,8 +51,5 @@ /* Target-independent local optimizations */ #include "../../LocalOptimizations.cc" -/* Common codegen utility code */ -#include "../../CodegenUtil.cc" - /* Architecture manifest */ #include "ArchVariant.cc" |