/* * Load a class pointer value into a fixed or temp register. Target * register is clobbered, and marked inUse. */ static ArmLIR *loadClassPointer(CompilationUnit *cUnit, int rDest, int value) { ArmLIR *res; cUnit->hasClassLiterals = true; if (dvmCompilerIsTemp(cUnit, rDest)) { dvmCompilerClobber(cUnit, rDest); dvmCompilerMarkInUse(cUnit, rDest); } ArmLIR *dataTarget = scanLiteralPool(cUnit->classPointerList, value, 0); if (dataTarget == NULL) { dataTarget = addWordData(cUnit, &cUnit->classPointerList, value); /* Counts the number of class pointers in this translation */ cUnit->numClassPointers++; } ArmLIR *loadPcRel = (ArmLIR *) dvmCompilerNew(sizeof(ArmLIR), true); loadPcRel->opcode = kThumbLdrPcRel; loadPcRel->generic.target = (LIR *) dataTarget; loadPcRel->operands[0] = rDest; setupResourceMasks(loadPcRel); setMemRefType(loadPcRel, true, kLiteral); loadPcRel->aliasInfo = dataTarget->operands[0]; res = loadPcRel; dvmCompilerAppendLIR(cUnit, (LIR *) loadPcRel); return res; }
/* * Mark load/store instructions that access Dalvik registers through r5FP + * offset. */ static void annotateDalvikRegAccess(ArmLIR *lir, int regId, bool isLoad) { 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; } }
/* * Load a immediate using a shortcut if possible; otherwise * grab from the per-translation literal pool. If target is * a high register, build constant into a low register and copy. * * No additional register clobbering operation performed. Use this version when * 1) rDest is freshly returned from dvmCompilerAllocTemp or * 2) The codegen is under fixed register usage */ static ArmLIR *loadConstantNoClobber(CompilationUnit *cUnit, int rDest, int value) { ArmLIR *res; int tDest = LOWREG(rDest) ? rDest : dvmCompilerAllocTemp(cUnit); /* See if the value can be constructed cheaply */ if ((value >= 0) && (value <= 255)) { res = newLIR2(cUnit, kThumbMovImm, tDest, value); if (rDest != tDest) { opRegReg(cUnit, kOpMov, rDest, tDest); dvmCompilerFreeTemp(cUnit, tDest); } return res; } else if ((value & 0xFFFFFF00) == 0xFFFFFF00) { res = newLIR2(cUnit, kThumbMovImm, tDest, ~value); newLIR2(cUnit, kThumbMvn, tDest, tDest); if (rDest != tDest) { opRegReg(cUnit, kOpMov, rDest, tDest); dvmCompilerFreeTemp(cUnit, tDest); } return res; } /* No shortcut - go ahead and use literal pool */ ArmLIR *dataTarget = scanLiteralPool(cUnit->literalList, value, 255); if (dataTarget == NULL) { dataTarget = addWordData(cUnit, &cUnit->literalList, value); } ArmLIR *loadPcRel = (ArmLIR *) dvmCompilerNew(sizeof(ArmLIR), true); loadPcRel->opcode = kThumbLdrPcRel; loadPcRel->generic.target = (LIR *) dataTarget; loadPcRel->operands[0] = tDest; setupResourceMasks(loadPcRel); setMemRefType(loadPcRel, true, kLiteral); loadPcRel->aliasInfo = dataTarget->operands[0]; res = loadPcRel; dvmCompilerAppendLIR(cUnit, (LIR *) loadPcRel); /* * To save space in the constant pool, we use the ADD_RRI8 instruction to * add up to 255 to an existing constant value. */ if (dataTarget->operands[0] != value) { newLIR2(cUnit, kThumbAddRI8, tDest, value - dataTarget->operands[0]); } if (rDest != tDest) { opRegReg(cUnit, kOpMov, rDest, tDest); dvmCompilerFreeTemp(cUnit, tDest); } return res; }
/* * Set up the proper fields in the resource mask */ static void setupResourceMasks(ArmLIR *lir) { int opcode = lir->opcode; int flags; if (opcode <= 0) { lir->useMask = lir->defMask = 0; return; } flags = getEncoding(lir->opcode)->flags; /* 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 (!skipDefRegMasks(lir)) { 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; } if (flags & SETS_FPSTATUS) { lir->defMask |= ENCODE_FP_STATUS; } /* 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; if (!skipUseRegMasks(lir)) { 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; } if (flags & USES_FPSTATUS) { lir->useMask |= ENCODE_FP_STATUS; } /* Fixup for kThumbPush/lr and kThumbPop/pc */ if (opcode == kThumbPush || opcode == kThumbPop) { u8 r8Mask = getRegMaskCommon(r8); if ((opcode == kThumbPush) && (lir->useMask & r8Mask)) { lir->useMask &= ~r8Mask; lir->useMask |= ENCODE_REG_LR; } else if ((opcode == kThumbPop) && (lir->defMask & r8Mask)) { lir->defMask &= ~r8Mask; lir->defMask |= ENCODE_REG_PC; } } }