Improved performance by 50% over existing JIT for some FP benchmarks.
/* Track method-level compilation statistics */
gDvmJit.methodStatsTable = dvmHashTableCreate(32, NULL);
- /*
- * FIXME - temporarily disable optimizations for this intermediate checkin
- */
- gDvmJit.disableOpt = 0x3;
-
dvmUnlockMutex(&gDvmJit.compilerLock);
return true;
#define GET_ELEM_N(LIST, TYPE, N) (((TYPE*) LIST->elemList)[N])
+struct LIR;
+
void dvmInitGrowableList(GrowableList *gList, size_t initLength);
void dvmInsertGrowableList(GrowableList *gList, void *elem);
-
BitVector* dvmCompilerAllocBitVector(int startBits, bool expandable);
bool dvmCompilerSetBit(BitVector* pBits, int num);
void dvmDebugBitVector(char *msg, const BitVector *bv, int length);
+void dvmDumpLIRInsn(struct LIR *lir, unsigned char *baseAddr);
+void dvmDumpResourceMask(struct LIR *lir, u8 mask, const char *prefix);
#endif /* _DALVIK_COMPILER_UTILITY */
int nativeReg; // And the mapped native register
int nativeRegHi; // And the mapped native register
bool isWide; // Whether a pair of registers are alive
+ int fp[32]; // Track the Dalvik register held in a SFP reg
+ int nextFP; // Next index for FP register allocation
} RegisterScoreboard;
void dvmCompilerApplyLocalOptimizations(struct CompilationUnit *cUnit,
case 'd':
sprintf(tbuf,"%d", operand);
break;
- case 'D':
- sprintf(tbuf,"%d", operand+8);
- break;
case 'E':
sprintf(tbuf,"%d", operand*4);
break;
*buf = 0;
}
+void dvmDumpResourceMask(LIR *lir, u8 mask, const char *prefix)
+{
+ char buf[256];
+ buf[0] = 0;
+ ArmLIR *armLIR = (ArmLIR *) lir;
+
+ if (mask == ENCODE_ALL) {
+ strcpy(buf, "all");
+ } else {
+ char num[8];
+ int i;
+
+ for (i = 0; i < kRegEnd; i++) {
+ if (mask & (1ULL << i)) {
+ sprintf(num, "%d ", i);
+ strcat(buf, num);
+ }
+ }
+
+ if (mask & ENCODE_CCODE) {
+ strcat(buf, "cc ");
+ }
+ if (mask & ENCODE_FP_STATUS) {
+ strcat(buf, "fpcc ");
+ }
+ if (armLIR && (mask & ENCODE_DALVIK_REG)) {
+ sprintf(buf + strlen(buf), "dr%d%s", armLIR->aliasInfo & 0xffff,
+ (armLIR->aliasInfo & 0x80000000) ? "(+1)" : "");
+ }
+ }
+ if (buf[0]) {
+ LOGD("%s: %s", prefix, buf);
+ }
+}
+
+/*
+ * Debugging macros
+ */
+#define DUMP_RESOURCE_MASK(X)
+#define DUMP_SSA_REP(X)
+
/* Pretty-print a LIR instruction */
-static void dumpLIRInsn(LIR *arg, unsigned char *baseAddr)
+void dvmDumpLIRInsn(LIR *arg, unsigned char *baseAddr)
{
ArmLIR *lir = (ArmLIR *) arg;
char buf[256];
int offset = lir->generic.offset;
int dest = lir->operands[0];
u2 *cPtr = (u2*)baseAddr;
+ const bool dumpNop = false;
+
/* Handle pseudo-ops individually, and all regular insns as a group */
switch(lir->opCode) {
- case ARM_PSEUDO_IT_BOTTOM:
- LOGD("-------- IT_Bottom");
+ case ARM_PSEUDO_BARRIER:
+ LOGD("-------- BARRIER");
break;
case ARM_PSEUDO_EXTENDED_MIR:
/* intentional fallthrough */
case ARM_PSEUDO_SSA_REP:
- LOGD("-------- %s\n", (char *) dest);
+ DUMP_SSA_REP(LOGD("-------- %s\n", (char *) dest));
break;
case ARM_PSEUDO_TARGET_LABEL:
break;
LOGD("L%#06x:\n", dest);
break;
default:
- if (lir->isNop) {
+ if (lir->isNop && !dumpNop) {
break;
}
buildInsnString(EncodingMap[lir->opCode].name, lir, opName,
baseAddr, 256);
buildInsnString(EncodingMap[lir->opCode].fmt, lir, buf, baseAddr,
256);
- LOGD("%p (%04x): %-8s%s\n",
- baseAddr + offset, offset, opName, buf);
+ LOGD("%p (%04x): %-8s%s%s\n",
+ baseAddr + offset, offset, opName, buf,
+ lir->isNop ? "(nop)" : "");
break;
}
+
+ if (lir->useMask && (!lir->isNop || dumpNop)) {
+ DUMP_RESOURCE_MASK(dvmDumpResourceMask((LIR *) lir,
+ lir->useMask, "use"));
+ }
+ if (lir->defMask && (!lir->isNop || dumpNop)) {
+ DUMP_RESOURCE_MASK(dvmDumpResourceMask((LIR *) lir,
+ lir->defMask, "def"));
+ }
}
/* Dump instructions and constant pool contents */
LOGD("installed code is at %p\n", cUnit->baseAddr);
LOGD("total size is %d bytes\n", cUnit->totalSize);
for (lirInsn = cUnit->firstLIRInsn; lirInsn; lirInsn = lirInsn->next) {
- dumpLIRInsn(lirInsn, cUnit->baseAddr);
+ dvmDumpLIRInsn(lirInsn, cUnit->baseAddr);
}
for (lirInsn = cUnit->wordList; lirInsn; lirInsn = lirInsn->next) {
armLIR = (ArmLIR *) lirInsn;
/* Offset to distinguish DP FP regs */
#define FP_DOUBLE 64
/* Reg types */
+#define REGTYPE(x) (x & (FP_REG_OFFSET | FP_DOUBLE))
#define FPREG(x) ((x & FP_REG_OFFSET) == FP_REG_OFFSET)
#define LOWREG(x) ((x & 0x7) == x)
#define DOUBLEREG(x) ((x & FP_DOUBLE) == FP_DOUBLE)
kRegLR = 14,
kRegPC = 15,
kFPReg0 = 16,
- kITBlock = 48,
- kCCode = 49,
- kFPStatus = 50,
+ kRegEnd = 48,
+ kCCode = kRegEnd,
+ kFPStatus,
+ kDalvikReg,
} ResourceEncodingPos;
-#define ENCODE_GP_REG(N) (1ULL << N)
#define ENCODE_REG_LIST(N) ((u8) N)
#define ENCODE_REG_SP (1ULL << kRegSP)
#define ENCODE_REG_LR (1ULL << kRegLR)
#define ENCODE_REG_PC (1ULL << kRegPC)
-#define ENCODE_SFP_REG(N) (1ULL << (N - FP_REG_OFFSET + kFPReg0))
-#define ENCODE_DFP_REG(N) (3ULL << (((N - FP_DOUBLE) << 1) + kFPReg0))
-#define ENCODE_IT_BLOCK (1ULL << kITBlock)
#define ENCODE_CCODE (1ULL << kCCode)
#define ENCODE_FP_STATUS (1ULL << kFPStatus)
+#define ENCODE_DALVIK_REG (1ULL << kDalvikReg)
+#define ENCODE_ALL (~0ULL)
+
+#define DECODE_ALIAS_INFO_REG(X) (X & 0xffff)
+#define DECODE_ALIAS_INFO_WIDE(X) ((X & 0x80000000) ? 1 : 0)
typedef enum OpSize {
WORD,
* Assemble.c.
*/
typedef enum ArmOpCode {
- ARM_PSEUDO_IT_BOTTOM = -17,
+ ARM_PSEUDO_BARRIER = -17,
ARM_PSEUDO_EXTENDED_MIR = -16,
ARM_PSEUDO_SSA_REP = -15,
ARM_PSEUDO_ENTRY_BLOCK = -14,
kRegDef0,
kRegDef1,
kRegDefSP,
+ kRegDefLR,
kRegDefList0,
kRegDefList1,
kRegUse0,
#define REG_DEF0 (1 << kRegDef0)
#define REG_DEF1 (1 << kRegDef1)
#define REG_DEF_SP (1 << kRegDefSP)
+#define REG_DEF_LR (1 << kRegDefLR)
#define REG_DEF_LIST0 (1 << kRegDefList0)
#define REG_DEF_LIST1 (1 << kRegDefList1)
#define REG_USE0 (1 << kRegUse0)
#define REG_USE1 (1 << kRegUse1)
#define REG_USE2 (1 << kRegUse2)
-#define REG_USE_PC (1 << kRegUsePC)
#define REG_USE_SP (1 << kRegUseSP)
+#define REG_USE_PC (1 << kRegUsePC)
#define REG_USE_LIST0 (1 << kRegUseList0)
#define REG_USE_LIST1 (1 << kRegUseList1)
#define NO_OPERAND (1 << kNoOperand)
#define USES_CCODES (1 << kUsesCCodes)
/* Common combo register usage patterns */
-#define REG_DEF0_USE1 (REG_DEF0 | REG_USE1)
-#define REG_DEF0_USE01 (REG_DEF0 | REG_USE0 | REG_USE1)
-#define REG_DEF0_USE12 (REG_DEF0 | REG_USE1 | REG_USE2)
#define REG_USE01 (REG_USE0 | REG_USE1)
-#define REG_USE012 (REG_USE0 | REG_USE1 | REG_USE2)
+#define REG_USE012 (REG_USE01 | REG_USE2)
+#define REG_USE12 (REG_USE1 | REG_USE2)
+#define REG_DEF0_USE0 (REG_DEF0 | REG_USE0)
+#define REG_DEF0_USE1 (REG_DEF0 | REG_USE1)
+#define REG_DEF0_USE01 (REG_DEF0 | REG_USE01)
+#define REG_DEF0_USE12 (REG_DEF0 | REG_USE12)
+#define REG_DEF01_USE2 (REG_DEF0 | REG_DEF1 | REG_USE2)
/* Instruction assembly fieldLoc kind */
typedef enum ArmEncodingKind {
bool isNop; // LIR is optimized away
int age; // default is 0, set lazily by the optimizer
int size; // 16-bit unit size (1 for thumb, 1 or 2 for thumb2)
+ int aliasInfo; // For Dalvik register access disambiguation
u8 useMask; // Resource mask for use
u8 defMask; // Resource mask for def
} ArmLIR;
* [f]ormats:
* h -> 4-digit hex
* d -> decimal
- * D -> decimal+8 (used to convert 3-bit regnum field to high reg)
* E -> decimal*4
* F -> decimal*2
* c -> branch condition (beq, bne, etc.)
"adds", "r!0d, r!1d, #!2d", 1),
ENCODING_MAP(THUMB_ADD_RI8, 0x3000,
BITBLT, 10, 8, BITBLT, 7, 0, UNUSED, -1, -1, UNUSED, -1, -1,
- IS_BINARY_OP | REG_DEF0 | REG_USE0 | SETS_CCODES,
+ IS_BINARY_OP | REG_DEF0_USE0 | SETS_CCODES,
"adds", "r!0d, r!0d, #!1d", 1),
ENCODING_MAP(THUMB_ADD_RRR, 0x1800,
BITBLT, 2, 0, BITBLT, 5, 3, BITBLT, 8, 6, UNUSED, -1, -1,
"bkpt", "!0d", 1),
ENCODING_MAP(THUMB_BLX_1, 0xf000,
BITBLT, 10, 0, UNUSED, -1, -1, UNUSED, -1, -1, UNUSED, -1, -1,
- IS_BINARY_OP | IS_BRANCH,
+ IS_BINARY_OP | IS_BRANCH | REG_DEF_LR,
"blx_1", "!0u", 1),
ENCODING_MAP(THUMB_BLX_2, 0xe800,
BITBLT, 10, 0, UNUSED, -1, -1, UNUSED, -1, -1, UNUSED, -1, -1,
- IS_BINARY_OP | IS_BRANCH,
+ IS_BINARY_OP | IS_BRANCH | REG_DEF_LR,
"blx_2", "!0v", 1),
ENCODING_MAP(THUMB_BL_1, 0xf000,
BITBLT, 10, 0, UNUSED, -1, -1, UNUSED, -1, -1, UNUSED, -1, -1,
- IS_UNARY_OP | IS_BRANCH,
+ IS_UNARY_OP | IS_BRANCH | REG_DEF_LR,
"bl_1", "!0u", 1),
ENCODING_MAP(THUMB_BL_2, 0xf800,
BITBLT, 10, 0, UNUSED, -1, -1, UNUSED, -1, -1, UNUSED, -1, -1,
- IS_UNARY_OP | IS_BRANCH,
+ IS_UNARY_OP | IS_BRANCH | REG_DEF_LR,
"bl_2", "!0v", 1),
ENCODING_MAP(THUMB_BLX_R, 0x4780,
BITBLT, 6, 3, UNUSED, -1, -1, UNUSED, -1, -1, UNUSED, -1, -1,
- IS_UNARY_OP | IS_BRANCH,
+ IS_UNARY_OP | REG_USE0 | IS_BRANCH | REG_DEF_LR,
"blx", "r!0d", 1),
ENCODING_MAP(THUMB_BX, 0x4700,
BITBLT, 6, 3, UNUSED, -1, -1, UNUSED, -1, -1, UNUSED, -1, -1,
ENCODING_MAP(THUMB_CMP_LH, 0x4540,
BITBLT, 2, 0, BITBLT, 5, 3, UNUSED, -1, -1, UNUSED, -1, -1,
IS_BINARY_OP | REG_USE01 | SETS_CCODES,
- "cmp", "r!0d, r!1D", 1),
+ "cmp", "r!0d, r!1d", 1),
ENCODING_MAP(THUMB_CMP_HL, 0x4580,
BITBLT, 2, 0, BITBLT, 5, 3, UNUSED, -1, -1, UNUSED, -1, -1,
IS_BINARY_OP | REG_USE01 | SETS_CCODES,
- "cmp", "r!0D, r!1d", 1),
+ "cmp", "r!0d, r!1d", 1),
ENCODING_MAP(THUMB_CMP_HH, 0x45c0,
BITBLT, 2, 0, BITBLT, 5, 3, UNUSED, -1, -1, UNUSED, -1, -1,
IS_BINARY_OP | REG_USE01 | SETS_CCODES,
- "cmp", "r!0D, r!1D", 1),
+ "cmp", "r!0d, r!1d", 1),
ENCODING_MAP(THUMB_EOR_RR, 0x4040,
BITBLT, 2, 0, BITBLT, 5, 3, UNUSED, -1, -1, UNUSED, -1, -1,
IS_BINARY_OP | REG_DEF0_USE01 | SETS_CCODES,
"eors", "r!0d, r!1d", 1),
ENCODING_MAP(THUMB_LDMIA, 0xc800,
BITBLT, 10, 8, BITBLT, 7, 0, UNUSED, -1, -1, UNUSED, -1, -1,
- IS_BINARY_OP | REG_DEF0 | REG_USE0 | REG_DEF_LIST1,
+ IS_BINARY_OP | REG_DEF0_USE0 | REG_DEF_LIST1,
"ldmia", "r!0d!!, <!1R>", 1),
ENCODING_MAP(THUMB_LDR_RRI5, 0x6800,
BITBLT, 2, 0, BITBLT, 5, 3, BITBLT, 10, 6, UNUSED, -1, -1,
ENCODING_MAP(THUMB_MOV_RR_H2H, 0x46c0,
BITBLT, 2, 0, BITBLT, 5, 3, UNUSED, -1, -1, UNUSED, -1, -1,
IS_BINARY_OP | REG_DEF0_USE1,
- "mov", "r!0D, r!1D", 1),
+ "mov", "r!0d, r!1d", 1),
ENCODING_MAP(THUMB_MOV_RR_H2L, 0x4640,
BITBLT, 2, 0, BITBLT, 5, 3, UNUSED, -1, -1, UNUSED, -1, -1,
IS_BINARY_OP | REG_DEF0_USE1,
- "mov", "r!0d, r!1D", 1),
+ "mov", "r!0d, r!1d", 1),
ENCODING_MAP(THUMB_MOV_RR_L2H, 0x4680,
BITBLT, 2, 0, BITBLT, 5, 3, UNUSED, -1, -1, UNUSED, -1, -1,
IS_BINARY_OP | REG_DEF0_USE1,
- "mov", "r!0D, r!1d", 1),
+ "mov", "r!0d, r!1d", 1),
ENCODING_MAP(THUMB_MUL, 0x4340,
BITBLT, 2, 0, BITBLT, 5, 3, UNUSED, -1, -1, UNUSED, -1, -1,
IS_BINARY_OP | REG_DEF0_USE01 | SETS_CCODES,
"subs", "r!0d, r!1d, #!2d]", 1),
ENCODING_MAP(THUMB_SUB_RI8, 0x3800,
BITBLT, 10, 8, BITBLT, 7, 0, UNUSED, -1, -1, UNUSED, -1, -1,
- IS_BINARY_OP | REG_DEF0 | REG_USE0 | SETS_CCODES,
+ IS_BINARY_OP | REG_DEF0_USE0 | SETS_CCODES,
"subs", "r!0d, #!1d", 1),
ENCODING_MAP(THUMB_SUB_RRR, 0x1a00,
BITBLT, 2, 0, BITBLT, 5, 3, BITBLT, 8, 6, UNUSED, -1, -1,
BITBLT, 15, 12, BITBLT, 19, 16, BITBLT, 8, 0, UNUSED, -1, -1,
IS_TERTIARY_OP | REG_DEF0_USE1,
"ldr", "r!0d,[r!1d, #-!2d]", 2),
- ENCODING_MAP(THUMB2_CBNZ, 0xb900,
+ ENCODING_MAP(THUMB2_CBNZ, 0xb900, /* Note: does not affect flags */
BITBLT, 2, 0, IMM6, -1, -1, UNUSED, -1, -1, UNUSED, -1, -1,
- IS_BINARY_OP, /* Note: does not affect flags */
+ IS_BINARY_OP | REG_USE0 | IS_BRANCH,
"cbnz", "r!0d,!1t", 1),
- ENCODING_MAP(THUMB2_CBZ, 0xb100,
+ ENCODING_MAP(THUMB2_CBZ, 0xb100, /* Note: does not affect flags */
BITBLT, 2, 0, IMM6, -1, -1, UNUSED, -1, -1, UNUSED, -1, -1,
- IS_BINARY_OP, /* Note: does not affect flags */
+ IS_BINARY_OP | REG_USE0 | IS_BRANCH,
"cbz", "r!0d,!1t", 1),
ENCODING_MAP(THUMB2_ADD_RRI12, 0xf2000000,
BITBLT, 11, 8, BITBLT, 19, 16, IMM12, -1, -1, UNUSED, -1, -1,
"vmov.f64 ", " !0S, !1S", 2),
ENCODING_MAP(THUMB2_LDMIA, 0xe8900000,
BITBLT, 19, 16, BITBLT, 15, 0, UNUSED, -1, -1, UNUSED, -1, -1,
- IS_BINARY_OP | REG_DEF0 | REG_USE0 | REG_DEF_LIST1,
+ IS_BINARY_OP | REG_DEF0_USE0 | REG_DEF_LIST1,
"ldmia", "r!0d!!, <!1R>", 2),
ENCODING_MAP(THUMB2_STMIA, 0xe8800000,
BITBLT, 19, 16, BITBLT, 15, 0, UNUSED, -1, -1, UNUSED, -1, -1,
- IS_BINARY_OP | REG_DEF0 | REG_USE0 | REG_USE_LIST1,
+ IS_BINARY_OP | REG_DEF0_USE0 | REG_USE_LIST1,
"stmia", "r!0d!!, <!1R>", 2),
ENCODING_MAP(THUMB2_ADD_RRR, 0xeb100000, /* setflags encoding */
BITBLT, 11, 8, BITBLT, 19, 16, BITBLT, 3, 0, SHIFT, -1, -1,
"fmsr", "!0s, r!1d", 2),
ENCODING_MAP(THUMB2_FMRRD, 0xec500b10,
BITBLT, 15, 12, BITBLT, 19, 16, DFP, 5, 0, UNUSED, -1, -1,
- IS_TERTIARY_OP | REG_DEF0 | REG_DEF1 | REG_USE2,
+ IS_TERTIARY_OP | REG_DEF01_USE2,
"fmrrd", "r!0d, r!1d, !2S", 2),
ENCODING_MAP(THUMB2_FMDRR, 0xec400b10,
DFP, 5, 0, BITBLT, 15, 12, BITBLT, 19, 16, UNUSED, -1, -1,
"fmdrr", "!0S, r!1d, r!2d", 2),
};
-
/*
* The fake NOP of moving r0 to r0 actually will incur data stalls if r0 is
* not ready. Since r5 (rFP) is not updated often, it is less likely to
if (heapSpacePtr == shadowSpace->heapSpaceTail)
data = *((unsigned int*) addr);
- //LOGD("*** HEAP LOAD: Addr: 0x%x Data: 0x%x", addr, data);
-
int reg = (heapArgSpace->regMap >> 4) & 0xF;
+
+ //LOGD("*** HEAP LOAD: Reg:%d Addr: 0x%x Data: 0x%x", reg, addr, data);
+
selfVerificationLoadDecodeData(heapArgSpace, data, reg);
}
#endif
/*
+ * Mark load/store instructions that access Dalvik registers through rFP +
+ * offset.
+ */
+static void annotateDalvikRegAccess(ArmLIR *lir, int regId, bool isLoad)
+{
+ if (isLoad) {
+ lir->useMask |= ENCODE_DALVIK_REG;
+ } else {
+ lir->defMask |= ENCODE_DALVIK_REG;
+ }
+
+ /*
+ * 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 and mark the corresponding bit(s).
+ */
+static inline void setupRegMask(u8 *mask, int reg)
+{
+ u8 seed;
+ int shift;
+ int regId = reg & 0x1f;
+
+ /*
+ * Each double register is equal to a pair of single-precision FP registers
+ */
+ seed = DOUBLEREG(reg) ? 3 : 1;
+ /* FP register starts at bit position 16 */
+ shift = FPREG(reg) ? kFPReg0 : 0;
+ /* Expand the double register id into single offset */
+ shift += regId;
+ *mask |= seed << shift;
+}
+
+/*
* Set up the proper fields in the resource mask
*/
static void setupResourceMasks(ArmLIR *lir)
/* Set up the mask for resources that are updated */
if (flags & IS_BRANCH) {
lir->defMask |= ENCODE_REG_PC;
+ lir->useMask |= ENCODE_REG_PC;
}
if (flags & REG_DEF0) {
- lir->defMask |= ENCODE_GP_REG(lir->operands[0]);
+ setupRegMask(&lir->defMask, lir->operands[0]);
}
if (flags & REG_DEF1) {
- lir->defMask |= ENCODE_GP_REG(lir->operands[1]);
+ setupRegMask(&lir->defMask, lir->operands[1]);
}
if (flags & REG_DEF_SP) {
lir->defMask |= ENCODE_REG_SP;
}
+ if (flags & REG_DEF_SP) {
+ lir->defMask |= ENCODE_REG_LR;
+ }
+
if (flags & REG_DEF_LIST0) {
lir->defMask |= ENCODE_REG_LIST(lir->operands[0]);
}
/* Conservatively treat the IT block */
if (flags & IS_IT) {
- lir->defMask = -1;
+ lir->defMask = ENCODE_ALL;
}
/* Set up the mask for resources that are used */
for (i = 0; i < 3; i++) {
if (flags & (1 << (kRegUse0 + i))) {
- lir->useMask |= ENCODE_GP_REG(lir->operands[i]);
+ setupRegMask(&lir->useMask, lir->operands[i]);
}
}
}
return NULL;
}
+/*
+ * Generate an ARM_PSEUDO_BARRIER marker to indicate the boundary of special
+ * blocks.
+ */
+static void genBarrier(CompilationUnit *cUnit)
+{
+ ArmLIR *barrier = newLIR0(cUnit, ARM_PSEUDO_BARRIER);
+ /* Mark all resources as being clobbered */
+ barrier->defMask = -1;
+}
+
/* Perform the actual operation for OP_RETURN_* */
static void genReturnCommon(CompilationUnit *cUnit, MIR *mir)
{
opRegRegImm(cUnit, OP_ADD, r4PC, rFP, srcOffset, rNone);
/* load [r0 .. min(numArgs,4)] */
regMask = (1 << ((numArgs < 4) ? numArgs : 4)) - 1;
+ /*
+ * Protect the loadMultiple instruction from being reordered with other
+ * Dalvik stack accesses.
+ */
+ genBarrier(cUnit);
loadMultiple(cUnit, r4PC, regMask);
+ genBarrier(cUnit);
opRegRegImm(cUnit, OP_SUB, r7, rFP,
sizeof(StackSaveArea) + (numArgs << 2), rNone);
if (numArgs > 11) {
loadConstant(cUnit, 5, ((numArgs - 4) >> 2) << 2);
loopLabel = newLIR0(cUnit, ARM_PSEUDO_TARGET_LABEL);
+ loopLabel->defMask = ENCODE_ALL;
}
storeMultiple(cUnit, r7, regMask);
+ /*
+ * Protect the loadMultiple instruction from being reordered with other
+ * Dalvik stack accesses.
+ */
+ genBarrier(cUnit);
loadMultiple(cUnit, r4PC, regMask);
+ genBarrier(cUnit);
/* No need to generate the loop structure if numArgs <= 11 */
if (numArgs > 11) {
opRegImm(cUnit, OP_SUB, rFP, 4, rNone);
/* Generate the loop epilogue - don't use r0 */
if ((numArgs > 4) && (numArgs % 4)) {
regMask = ((1 << (numArgs & 0x3)) - 1) << 1;
+ /*
+ * Protect the loadMultiple instruction from being reordered with other
+ * Dalvik stack accesses.
+ */
+ genBarrier(cUnit);
loadMultiple(cUnit, r4PC, regMask);
+ genBarrier(cUnit);
}
if (numArgs >= 8)
opImm(cUnit, OP_POP, (1 << r0 | 1 << rFP));
} else {
assert(rDestLo < rDestHi);
res = loadValueAddress(cUnit, vSrc, rDestLo);
+ /*
+ * Protect the loadMultiple instruction from being reordered with other
+ * Dalvik stack accesses.
+ */
+ genBarrier(cUnit);
loadMultiple(cUnit, rDestLo, (1<<rDestLo) | (1<<rDestHi));
+ genBarrier(cUnit);
}
return res;
}
} else {
assert(rSrcLo < rSrcHi);
res = loadValueAddress(cUnit, vDest, rScratch);
+ /*
+ * Protect the storeMultiple instruction from being reordered with
+ * other Dalvik stack accesses.
+ */
+ genBarrier(cUnit);
storeMultiple(cUnit, rScratch, (1<<rSrcLo) | (1 << rSrcHi));
+ genBarrier(cUnit);
}
return res;
}
genZeroCheck(cUnit, r0, mir->offset, NULL);
/* check cast passed - branch target here */
ArmLIR *target = newLIR0(cUnit, ARM_PSEUDO_TARGET_LABEL);
+ target->defMask = ENCODE_ALL;
branch1->generic.target = (LIR *)target;
branch2->generic.target = (LIR *)target;
break;
opReg(cUnit, OP_BLX, r4PC);
/* branch target here */
ArmLIR *target = newLIR0(cUnit, ARM_PSEUDO_TARGET_LABEL);
+ target->defMask = ENCODE_ALL;
storeValue(cUnit, r0, mir->dalvikInsn.vA, r1);
branch1->generic.target = (LIR *)target;
branch2->generic.target = (LIR *)target;
/* Remember the first LIR for this block */
if (headLIR == NULL) {
headLIR = boundaryLIR;
+ /* Set the first boundaryLIR as a scheduling barrier */
+ headLIR->defMask = ENCODE_ALL;
}
bool notHandled;
LOGD("dalvik.vm.jit.op = %s", buf);
}
}
+
+/* Common initialization routine for an architecture family */
+bool dvmCompilerArchInit()
+{
+ int i;
+
+ for (i = 0; i < ARM_LAST; i++) {
+ if (EncodingMap[i].opCode != i) {
+ LOGE("Encoding order for %s is wrong: expecting %d, seeing %d",
+ EncodingMap[i].name, i, EncodingMap[i].opCode);
+ dvmAbort();
+ }
+ }
+
+ return compilerArchVariantInit();
+}
* variant code such as ThumbUtilty.c
*/
+static void annotateDalvikRegAccess(ArmLIR *lir, int regId, bool isLoad);
static void setupResourceMasks(ArmLIR *lir);
static ArmLIR *newLIR0(CompilationUnit *cUnit, ArmOpCode opCode);
static ArmLIR *newLIR1(CompilationUnit *cUnit, ArmOpCode opCode,
static inline ArmLIR *genCheckCommon(CompilationUnit *cUnit, int dOffset,
ArmLIR *branch,
ArmLIR *pcrLabel);
+static void genBarrier(CompilationUnit *cUnit);
/* Routines which must be supplied by the variant-specific code */
static void genDispatchToHandler(CompilationUnit *cUnit, TemplateOpCode opCode);
-bool dvmCompilerArchInit(void);
static bool genInlineSqrt(CompilationUnit *cUnit, MIR *mir);
static bool genInlineCos(CompilationUnit *cUnit, MIR *mir);
static bool genInlineSin(CompilationUnit *cUnit, MIR *mir);
int vSrc1, int vSrc2);
static bool genCmpX(CompilationUnit *cUnit, MIR *mir, int vDest, int vSrc1,
int vSrc2);
-
-
+static bool compilerArchVariantInit();
#endif /* _DALVIK_VM_COMPILER_CODEGEN_ARM_CODEGEN_H */
#include "vm/compiler/CompilerInternals.h"
#include "ArmLIR.h"
+#define DEBUG_OPT(X)
+
ArmLIR* dvmCompilerGenCopy(CompilationUnit *cUnit, int rDest, int rSrc);
/* Is this a Dalvik register access? */
static inline bool isDalvikLoad(ArmLIR *lir)
{
- return ((lir->operands[1] == rFP) &&
- ((lir->opCode == THUMB_LDR_RRI5) ||
- (lir->opCode == THUMB2_LDR_RRI12) ||
- (lir->opCode == THUMB2_VLDRS) ||
- (lir->opCode == THUMB2_VLDRD)));
+ return (lir->useMask != ~0ULL) && (lir->useMask & ENCODE_DALVIK_REG);
}
static inline bool isDalvikStore(ArmLIR *lir)
{
- return ((lir->operands[1] == rFP) &&
- ((lir->opCode == THUMB_STR_RRI5) ||
- (lir->opCode == THUMB2_STR_RRI12) ||
- (lir->opCode == THUMB2_VSTRS) ||
- (lir->opCode == THUMB2_VSTRD)));
+ return (lir->defMask != ~0ULL) && (lir->defMask & ENCODE_DALVIK_REG);
}
-/* Double regs overlap float regs. Return true if collision */
-static bool regClobber(int reg1, int reg2)
+static inline bool isDalvikRegisterPartiallyClobbered(ArmLIR *lir1,
+ ArmLIR *lir2)
{
- int reg1a, reg1b;
- int reg2a, reg2b;
- if (!FPREG(reg1) || !FPREG(reg2))
- return (reg1 == reg2);
- if (DOUBLEREG(reg1)) {
- reg1a = reg1 & FP_REG_MASK;
- reg1b = reg1a + 1;
- } else {
- reg1a = reg1b = reg1 & FP_REG_MASK;
- }
- if (DOUBLEREG(reg2)) {
- reg2a = reg2 & FP_REG_MASK;
- reg2b = reg2a + 1;
- } else {
- reg2a = reg2b = reg2 & FP_REG_MASK;
- }
- return (reg1a == reg2a) || (reg1a == reg2b) ||
- (reg1b == reg2a) || (reg1b == reg2b);
+ int reg1Lo = DECODE_ALIAS_INFO_REG(lir1->aliasInfo);
+ int reg1Hi = reg1Lo + DECODE_ALIAS_INFO_WIDE(lir1->aliasInfo);
+ int reg2Lo = DECODE_ALIAS_INFO_REG(lir2->aliasInfo);
+ int reg2Hi = reg2Lo + DECODE_ALIAS_INFO_WIDE(lir2->aliasInfo);
+
+ return (reg1Lo == reg2Hi) || (reg1Hi == reg2Lo);
+}
+
+static void dumpDependentInsnPair(ArmLIR *thisLIR, ArmLIR *checkLIR,
+ const char *optimization)
+{
+ LOGD("************ %s ************", optimization);
+ dvmDumpLIRInsn((LIR *) thisLIR, 0);
+ dvmDumpLIRInsn((LIR *) checkLIR, 0);
}
+
/*
* Perform a pass of top-down walk to
* 1) Eliminate redundant loads and stores
continue;
}
if (isDalvikStore(thisLIR)) {
- int dRegId = thisLIR->operands[2];
+ int dRegId = DECODE_ALIAS_INFO_REG(thisLIR->aliasInfo);
+ int dRegIdHi = dRegId + DECODE_ALIAS_INFO_WIDE(thisLIR->aliasInfo);
int nativeRegId = thisLIR->operands[0];
ArmLIR *checkLIR;
int sinkDistance = 0;
/*
* Add r15 (pc) to the mask to prevent this instruction
- * from sinking past branch instructions.
+ * from sinking past branch instructions. Unset the Dalvik register
+ * bit when checking with native resource constraints.
*/
- u8 stopMask = ENCODE_GP_REG(rpc) | thisLIR->useMask;
+ u8 stopMask = (ENCODE_REG_PC | thisLIR->useMask) &
+ ~ENCODE_DALVIK_REG;
for (checkLIR = NEXT_LIR(thisLIR);
checkLIR != tailLIR;
/* Check if a Dalvik register load is redundant */
if (isDalvikLoad(checkLIR) &&
- checkLIR->operands[2] == dRegId ) {
- if (FPREG(nativeRegId) != FPREG(checkLIR->operands[0])) {
- break; // TODO: handle gen<=>float copies
- }
+ (checkLIR->aliasInfo == thisLIR->aliasInfo) &&
+ (REGTYPE(checkLIR->operands[0]) == REGTYPE(nativeRegId))) {
/* Insert a move to replace the load */
if (checkLIR->operands[0] != nativeRegId) {
ArmLIR *moveLIR;
checkLIR->isNop = true;
continue;
- /* Found a true output dependency - nuke the previous store */
+ /*
+ * Found a true output dependency - nuke the previous store.
+ * The register type doesn't matter here.
+ */
} else if (isDalvikStore(checkLIR) &&
- checkLIR->operands[2] == dRegId) {
+ (checkLIR->aliasInfo == thisLIR->aliasInfo)) {
thisLIR->isNop = true;
break;
/* Find out the latest slot that the store can be sunk into */
} else {
- bool stopHere = false;
-
/* Last instruction reached */
- stopHere |= NEXT_LIR(checkLIR) == tailLIR;
-
- /*
- * Conservatively assume there is a memory dependency
- * for st/ld multiples and reg+reg address mode
- */
- stopHere |= checkLIR->opCode == THUMB_STMIA ||
- checkLIR->opCode == THUMB_LDMIA ||
- checkLIR->opCode == THUMB_STR_RRR ||
- checkLIR->opCode == THUMB_LDR_RRR ||
- checkLIR->opCode == THUMB2_STR_RRR ||
- checkLIR->opCode == THUMB2_LDR_RRR ||
- checkLIR->opCode == THUMB2_STMIA ||
- checkLIR->opCode == THUMB2_LDMIA ||
- checkLIR->opCode == THUMB2_VLDRD ||
- checkLIR->opCode == THUMB2_VSTRD;
-
+ bool stopHere = (NEXT_LIR(checkLIR) == tailLIR);
/* Store data is clobbered */
- stopHere |= (stopMask & checkLIR->defMask) != 0;
+ stopHere |= ((stopMask & checkLIR->defMask) != 0);
+
+ /* Store data partially clobbers the Dalvik register */
+ if (stopHere == false &&
+ ((checkLIR->useMask | checkLIR->defMask) &
+ ENCODE_DALVIK_REG)) {
+ stopHere = isDalvikRegisterPartiallyClobbered(thisLIR,
+ checkLIR);
+ }
/* Found a new place to put the store - move it here */
if (stopHere == true) {
+ DEBUG_OPT(dumpDependentInsnPair(thisLIR, checkLIR,
+ "SINK STORE"));
/* The store can be sunk for at least one cycle */
if (sinkDistance != 0) {
ArmLIR *newStoreLIR =
continue;
}
if (isDalvikLoad(thisLIR)) {
- int dRegId = thisLIR->operands[2];
+ int dRegId = DECODE_ALIAS_INFO_REG(thisLIR->aliasInfo);
+ int dRegIdHi = dRegId + DECODE_ALIAS_INFO_WIDE(thisLIR->aliasInfo);
int nativeRegId = thisLIR->operands[0];
ArmLIR *checkLIR;
int hoistDistance = 0;
- u8 stopUseMask = ENCODE_GP_REG(rpc) | thisLIR->useMask;
- u8 stopDefMask = thisLIR->defMask;
+ u8 stopUseMask = (ENCODE_REG_PC | thisLIR->useMask) &
+ ~ENCODE_DALVIK_REG;
+ u8 stopDefMask = thisLIR->defMask & ~ENCODE_DALVIK_REG;
+ /* First check if the load can be completely elinimated */
for (checkLIR = PREV_LIR(thisLIR);
checkLIR != headLIR;
checkLIR = PREV_LIR(checkLIR)) {
if (checkLIR->isNop) continue;
+ /*
+ * Check if the Dalvik register is previously accessed
+ * with exactly the same type.
+ */
+ if ((isDalvikLoad(checkLIR) || isDalvikStore(checkLIR)) &&
+ (checkLIR->aliasInfo == thisLIR->aliasInfo) &&
+ (checkLIR->operands[0] == nativeRegId)) {
+ /*
+ * If it is previously accessed but with a different type,
+ * the search will terminate later at the point checking
+ * for partially overlapping stores.
+ */
+ thisLIR->isNop = true;
+ break;
+ }
+
+ /*
+ * No earlier use/def can reach this load if:
+ * 1) Head instruction is reached
+ * 2) load target register is clobbered
+ * 3) A branch is seen (stopUseMask has the PC bit set).
+ */
+ if ((checkLIR == headLIR) ||
+ (stopUseMask | stopDefMask) & checkLIR->defMask) {
+ break;
+ }
+
+ /* Store data partially clobbers the Dalvik register */
+ if (isDalvikStore(checkLIR) &&
+ isDalvikRegisterPartiallyClobbered(thisLIR, checkLIR)) {
+ break;
+ }
+ }
+
+ /* The load has been eliminated */
+ if (thisLIR->isNop) continue;
+
+ /*
+ * The load cannot be eliminated. See if it can be hoisted to an
+ * earlier spot.
+ */
+ for (checkLIR = PREV_LIR(thisLIR);
+ /* empty by intention */;
+ checkLIR = PREV_LIR(checkLIR)) {
+
+ if (checkLIR->isNop) continue;
+
/* Check if the current load is redundant */
if ((isDalvikLoad(checkLIR) || isDalvikStore(checkLIR)) &&
- checkLIR->operands[2] == dRegId ) {
- if (FPREG(nativeRegId) != FPREG(checkLIR->operands[0])) {
- break; // TODO: handle gen<=>float copies
- }
+ (checkLIR->aliasInfo == thisLIR->aliasInfo) &&
+ (REGTYPE(checkLIR->operands[0]) == REGTYPE(nativeRegId))) {
/* Insert a move to replace the load */
if (checkLIR->operands[0] != nativeRegId) {
ArmLIR *moveLIR;
dvmCompilerInsertLIRAfter((LIR *) checkLIR,
(LIR *) moveLIR);
}
- cUnit->printMe = true;
thisLIR->isNop = true;
break;
/* Find out if the load can be yanked past the checkLIR */
} else {
- bool stopHere = false;
-
/* Last instruction reached */
- stopHere |= PREV_LIR(checkLIR) == headLIR;
-
- /*
- * Conservatively assume there is a memory dependency
- * for st/ld multiples and reg+reg address mode
- */
- stopHere |= checkLIR->opCode == THUMB_STMIA ||
- checkLIR->opCode == THUMB_LDMIA ||
- checkLIR->opCode == THUMB_STR_RRR ||
- checkLIR->opCode == THUMB_LDR_RRR ||
- checkLIR->opCode == THUMB2_STR_RRR ||
- checkLIR->opCode == THUMB2_LDR_RRR ||
- checkLIR->opCode == THUMB2_STMIA ||
- checkLIR->opCode == THUMB2_LDMIA ||
- checkLIR->opCode == THUMB2_VLDRD ||
- checkLIR->opCode == THUMB2_VSTRD;
+ bool stopHere = (checkLIR == headLIR);
/* Base address is clobbered by checkLIR */
- stopHere |= (stopUseMask & checkLIR->defMask) != 0;
+ stopHere |= ((stopUseMask & checkLIR->defMask) != 0);
/* Load target clobbers use/def in checkLIR */
- stopHere |= (stopDefMask &
- (checkLIR->useMask | checkLIR->defMask)) != 0;
+ stopHere |= ((stopDefMask &
+ (checkLIR->useMask | checkLIR->defMask)) != 0);
+
+ /* Store data partially clobbers the Dalvik register */
+ if (stopHere == false &&
+ (checkLIR->defMask & ENCODE_DALVIK_REG)) {
+ stopHere = isDalvikRegisterPartiallyClobbered(thisLIR,
+ checkLIR);
+ }
+
+ /*
+ * Stop at an earlier Dalvik load if the offset of checkLIR
+ * is not less than thisLIR
+ *
+ * Experiments show that doing
+ *
+ * ldr r1, [r5, #16]
+ * ldr r0, [r5, #20]
+ *
+ * is much faster than
+ *
+ * ldr r0, [r5, #20]
+ * ldr r1, [r5, #16]
+ */
+ if (isDalvikLoad(checkLIR)) {
+ int dRegId2 =
+ DECODE_ALIAS_INFO_REG(checkLIR->aliasInfo);
+ if (dRegId2 <= dRegId) {
+ stopHere = true;
+ }
+ }
/* Found a new place to put the load - move it here */
if (stopHere == true) {
+ DEBUG_OPT(dumpDependentInsnPair(thisLIR, checkLIR,
+ "HOIST LOAD"));
/* The store can be hoisted for at least one cycle */
if (hoistDistance != 0) {
ArmLIR *newLoadLIR =
dvmCompilerInsertLIRAfter((LIR *) checkLIR,
(LIR *) newLoadLIR);
thisLIR->isNop = true;
- cUnit->printMe = true;
}
break;
}
/*
- * Saw a real instruction that the store can be sunk after
+ * Saw a real instruction that hosting the load is
+ * beneficial
*/
if (!isPseudoOpCode(checkLIR->opCode)) {
hoistDistance++;
static inline void resetRegisterScoreboard(CompilationUnit *cUnit)
{
RegisterScoreboard *registerScoreboard = &cUnit->registerScoreboard;
+ int i;
dvmClearAllBits(registerScoreboard->nullCheckedRegs);
registerScoreboard->liveDalvikReg = vNone;
registerScoreboard->nativeReg = vNone;
registerScoreboard->nativeRegHi = vNone;
+ for (i = 0; i < 32; i++) {
+ registerScoreboard->fp[i] = vNone;
+ }
+ registerScoreboard->nextFP = 0;
}
/* Kill the corresponding bit in the null-checked register list */
} else {
return (registerScoreboard->nativeReg + 1) & 3;
}
-
-}
-
-/*
- * Generate a ARM_PSEUDO_IT_BOTTOM marker to indicate the end of an IT block
- */
-static void genITBottom(CompilationUnit *cUnit)
-{
- ArmLIR *itBottom = newLIR0(cUnit, ARM_PSEUDO_IT_BOTTOM);
- /* Mark all resources as being clobbered */
- itBottom->defMask = -1;
}
/*
{
ArmLIR *res;
if (vSrcDest > 255) {
- res = opRegRegImm(cUnit, OP_ADD, r7, rFP, vSrcDest * 4, rNone);
- newLIR3(cUnit, opCode, rSrcDest, r7, 0);
+ opRegRegImm(cUnit, OP_ADD, r7, rFP, vSrcDest * 4, rNone);
+ res = newLIR3(cUnit, opCode, rSrcDest, r7, 0);
} else {
res = newLIR3(cUnit, opCode, rSrcDest, rFP, vSrcDest);
}
return res;
}
+
+static int nextFPReg(CompilationUnit *cUnit, int dalvikReg, bool isDouble)
+{
+ RegisterScoreboard *registerScoreboard = &cUnit->registerScoreboard;
+ int reg;
+
+ if (isDouble) {
+ reg = ((registerScoreboard->nextFP + 1) & ~1) % 32;
+ registerScoreboard->nextFP = reg + 2;
+ registerScoreboard->nextFP %= 32;
+ registerScoreboard->fp[reg] = dalvikReg;
+ return dr0 + reg;
+ }
+ else {
+ reg = registerScoreboard->nextFP++;
+ registerScoreboard->nextFP %= 32;
+ registerScoreboard->fp[reg] = dalvikReg;
+ return fr0 + reg;
+ }
+}
+
+/*
+ * Select a SFP register for the dalvikReg
+ */
+static int selectSFPReg(CompilationUnit *cUnit, int dalvikReg)
+{
+ RegisterScoreboard *registerScoreboard = &cUnit->registerScoreboard;
+ int i;
+
+ if (dalvikReg == vNone) {
+ return nextFPReg(cUnit, dalvikReg, false);;
+ }
+
+ for (i = 0; i < 32; i++) {
+ if (registerScoreboard->fp[i] == dalvikReg) {
+ return fr0 + i;
+ }
+ }
+ return nextFPReg(cUnit, dalvikReg, false);;
+}
+
+/*
+ * Select a DFP register for the dalvikReg
+ */
+static int selectDFPReg(CompilationUnit *cUnit, int dalvikReg)
+{
+ RegisterScoreboard *registerScoreboard = &cUnit->registerScoreboard;
+ int i;
+
+ if (dalvikReg == vNone) {
+ return nextFPReg(cUnit, dalvikReg, true);;
+ }
+
+ for (i = 0; i < 32; i += 2) {
+ if (registerScoreboard->fp[i] == dalvikReg) {
+ return dr0 + i;
+ }
+ }
+ return nextFPReg(cUnit, dalvikReg, true);
+}
+
static ArmLIR *loadFloat(CompilationUnit *cUnit, int vSrc, int rDest)
{
assert(SINGLEREG(rDest));
- return fpVarAccess(cUnit, vSrc, rDest, THUMB2_VLDRS);
+ ArmLIR *lir = fpVarAccess(cUnit, vSrc, rDest, THUMB2_VLDRS);
+ annotateDalvikRegAccess(lir, vSrc, true /* isLoad */);
+ return lir;
}
/* Store a float to a Dalvik register */
-static ArmLIR *storeFloat(CompilationUnit *cUnit, int rSrc, int vDest,
- int rScratch)
+static ArmLIR *storeFloat(CompilationUnit *cUnit, int rSrc, int vDest)
{
+ RegisterScoreboard *registerScoreboard = &cUnit->registerScoreboard;
+
assert(SINGLEREG(rSrc));
- return fpVarAccess(cUnit, vDest, rSrc, THUMB2_VSTRS);
+ registerScoreboard->fp[rSrc % 32] = vDest;
+
+ ArmLIR *lir = fpVarAccess(cUnit, vDest, rSrc, THUMB2_VSTRS);
+ annotateDalvikRegAccess(lir, vDest, false /* isLoad */);
+ return lir;
}
/* Load a double from a Dalvik register */
static ArmLIR *loadDouble(CompilationUnit *cUnit, int vSrc, int rDest)
{
assert(DOUBLEREG(rDest));
- return fpVarAccess(cUnit, vSrc, rDest, THUMB2_VLDRD);
+ ArmLIR *lir = fpVarAccess(cUnit, vSrc, rDest, THUMB2_VLDRD);
+ annotateDalvikRegAccess(lir, vSrc, true /* isLoad */);
+ return lir;
}
/* Store a double to a Dalvik register */
-static ArmLIR *storeDouble(CompilationUnit *cUnit, int rSrc, int vDest,
- int rScratch)
+static ArmLIR *storeDouble(CompilationUnit *cUnit, int rSrc, int vDest)
{
+ RegisterScoreboard *registerScoreboard = &cUnit->registerScoreboard;
+
assert(DOUBLEREG(rSrc));
- return fpVarAccess(cUnit, vDest, rSrc, THUMB2_VSTRD);
-}
+ registerScoreboard->fp[rSrc % 32] = vDest;
+ ArmLIR *lir = fpVarAccess(cUnit, vDest, rSrc, THUMB2_VSTRD);
+ annotateDalvikRegAccess(lir, vDest, false /* isLoad */);
+ return lir;
+}
/*
* Load value from base + displacement. Optionally perform null check
bool nullCheck, int vReg)
{
ArmLIR *first = NULL;
- ArmLIR *res;
+ ArmLIR *res, *load;
ArmOpCode opCode = THUMB_BKPT;
bool shortForm = false;
bool thumb2Form = (displacement < 4092 && displacement >= 0);
int shortMax = 128;
bool allLowRegs = (LOWREG(rBase) && LOWREG(rDest));
+ int encodedDisp = displacement;
+
switch (size) {
case WORD:
if (LOWREG(rDest) && (rBase == rpc) &&
(displacement <= 1020) && (displacement >= 0)) {
shortForm = true;
- displacement >>= 2;
+ encodedDisp >>= 2;
opCode = THUMB_LDR_PC_REL;
} else if (LOWREG(rDest) && (rBase == r13) &&
(displacement <= 1020) && (displacement >= 0)) {
shortForm = true;
- displacement >>= 2;
+ encodedDisp >>= 2;
opCode = THUMB_LDR_SP_REL;
} else if (allLowRegs && displacement < 128 && displacement >= 0) {
assert((displacement & 0x3) == 0);
shortForm = true;
- displacement >>= 2;
+ encodedDisp >>= 2;
opCode = THUMB_LDR_RRI5;
} else if (thumb2Form) {
shortForm = true;
if (allLowRegs && displacement < 64 && displacement >= 0) {
assert((displacement & 0x1) == 0);
shortForm = true;
- displacement >>= 1;
+ encodedDisp >>= 1;
opCode = THUMB_LDRH_RRI5;
} else if (displacement < 4092 && displacement >= 0) {
shortForm = true;
if (nullCheck)
first = genNullCheck(cUnit, vReg, rBase, mir->offset, NULL);
if (shortForm) {
- res = newLIR3(cUnit, opCode, rDest, rBase, displacement);
+ load = res = newLIR3(cUnit, opCode, rDest, rBase, encodedDisp);
} else {
assert(rBase != rDest);
- res = loadConstant(cUnit, rDest, displacement);
- loadBaseIndexed(cUnit, rBase, rDest, rDest, 0, size);
+ res = loadConstant(cUnit, rDest, encodedDisp);
+ load = loadBaseIndexed(cUnit, rBase, rDest, rDest, 0, size);
+ }
+
+ if (rBase == rFP) {
+ annotateDalvikRegAccess(load, displacement >> 2, true /* isLoad */);
}
return (first) ? first : res;
}
int displacement, int rSrc, OpSize size,
int rScratch)
{
- ArmLIR *res;
+ ArmLIR *res, *store;
ArmOpCode opCode = THUMB_BKPT;
bool shortForm = false;
bool thumb2Form = (displacement < 4092 && displacement >= 0);
int shortMax = 128;
bool allLowRegs = (LOWREG(rBase) && LOWREG(rSrc));
+ int encodedDisp = displacement;
+
if (rScratch != -1)
allLowRegs &= LOWREG(rScratch);
switch (size) {
if (allLowRegs && displacement < 128 && displacement >= 0) {
assert((displacement & 0x3) == 0);
shortForm = true;
- displacement >>= 2;
+ encodedDisp >>= 2;
opCode = THUMB_STR_RRI5;
} else if (thumb2Form) {
shortForm = true;
if (displacement < 64 && displacement >= 0) {
assert((displacement & 0x1) == 0);
shortForm = true;
- displacement >>= 1;
+ encodedDisp >>= 1;
opCode = THUMB_STRH_RRI5;
} else if (thumb2Form) {
shortForm = true;
assert(0);
}
if (shortForm) {
- res = newLIR3(cUnit, opCode, rSrc, rBase, displacement);
+ store = res = newLIR3(cUnit, opCode, rSrc, rBase, encodedDisp);
} else {
assert(rScratch != -1);
- res = loadConstant(cUnit, rScratch, displacement);
- storeBaseIndexed(cUnit, rBase, rScratch, rSrc, 0, size);
+ res = loadConstant(cUnit, rScratch, encodedDisp);
+ store = storeBaseIndexed(cUnit, rBase, rScratch, rSrc, 0, size);
+ }
+
+ if (rBase == rFP) {
+ annotateDalvikRegAccess(store, displacement >> 2, false /* isLoad */);
}
return res;
}
branch1->generic.target = (LIR *) genIT(cUnit, ARM_COND_HI, "E");
newLIR2(cUnit, THUMB2_MOV_IMM_SHIFT, r7, modifiedImmediate(-1));
newLIR2(cUnit, THUMB_MOV_IMM, r7, 1);
- genITBottom(cUnit);
+ genBarrier(cUnit);
branch2->generic.target = (LIR *) opRegReg(cUnit, OP_NEG, r7, r7);
branch1->generic.target = (LIR *) storeValue(cUnit, r7, vDest, r4PC);
//TODO: need assertion mechanism to validate IT region size
genIT(cUnit, (isMin) ? ARM_COND_GT : ARM_COND_LT, "");
opRegReg(cUnit, OP_MOV, reg0, reg1);
- genITBottom(cUnit);
+ genBarrier(cUnit);
if (vDest >= 0)
storeValue(cUnit, reg0, vDest, reg1);
else
bool nullCheck, int vReg)
{
ArmLIR *first = NULL;
- ArmLIR *res;
+ ArmLIR *res, *load;
ArmOpCode opCode = THUMB_BKPT;
bool shortForm = false;
int shortMax = 128;
+ int encodedDisp = displacement;
+
switch (size) {
case WORD:
if (LOWREG(rDest) && (rBase == rpc) &&
(displacement <= 1020) && (displacement >= 0)) {
shortForm = true;
- displacement >>= 2;
+ encodedDisp >>= 2;
opCode = THUMB_LDR_PC_REL;
} else if (LOWREG(rDest) && (rBase == r13) &&
(displacement <= 1020) && (displacement >= 0)) {
shortForm = true;
- displacement >>= 2;
+ encodedDisp >>= 2;
opCode = THUMB_LDR_SP_REL;
} else if (displacement < 128 && displacement >= 0) {
assert((displacement & 0x3) == 0);
shortForm = true;
- displacement >>= 2;
+ encodedDisp >>= 2;
opCode = THUMB_LDR_RRI5;
} else {
opCode = THUMB_LDR_RRR;
if (displacement < 64 && displacement >= 0) {
assert((displacement & 0x1) == 0);
shortForm = true;
- displacement >>= 1;
+ encodedDisp >>= 1;
opCode = THUMB_LDRH_RRI5;
} else {
opCode = THUMB_LDRH_RRR;
if (nullCheck)
first = genNullCheck(cUnit, vReg, rBase, mir->offset, NULL);
if (shortForm) {
- res = newLIR3(cUnit, opCode, rDest, rBase, displacement);
+ load = res = newLIR3(cUnit, opCode, rDest, rBase, encodedDisp);
} else {
assert(rBase != rDest);
- res = loadConstant(cUnit, rDest, displacement);
- newLIR3(cUnit, opCode, rDest, rBase, rDest);
+ res = loadConstant(cUnit, rDest, encodedDisp);
+ load = newLIR3(cUnit, opCode, rDest, rBase, rDest);
}
+
+ if (rBase == rFP) {
+ annotateDalvikRegAccess(load, displacement >> 2, true /* isLoad */);
+ }
+
return (first) ? first : res;
}
int displacement, int rSrc, OpSize size,
int rScratch)
{
- ArmLIR *res;
+ ArmLIR *res, *store;
ArmOpCode opCode = THUMB_BKPT;
bool shortForm = false;
int shortMax = 128;
+ int encodedDisp = displacement;
+
switch (size) {
case WORD:
if (displacement < 128 && displacement >= 0) {
assert((displacement & 0x3) == 0);
shortForm = true;
- displacement >>= 2;
+ encodedDisp >>= 2;
opCode = THUMB_STR_RRI5;
} else {
opCode = THUMB_STR_RRR;
if (displacement < 64 && displacement >= 0) {
assert((displacement & 0x1) == 0);
shortForm = true;
- displacement >>= 1;
+ encodedDisp >>= 1;
opCode = THUMB_STRH_RRI5;
} else {
opCode = THUMB_STRH_RRR;
assert(0);
}
if (shortForm) {
- res = newLIR3(cUnit, opCode, rSrc, rBase, displacement);
+ store = res = newLIR3(cUnit, opCode, rSrc, rBase, encodedDisp);
} else {
assert(rScratch != -1);
- res = loadConstant(cUnit, rScratch, displacement);
- newLIR3(cUnit, opCode, rSrc, rBase, rScratch);
+ res = loadConstant(cUnit, rScratch, encodedDisp);
+ store = newLIR3(cUnit, opCode, rSrc, rBase, rScratch);
+ }
+
+ if (rBase == rFP) {
+ annotateDalvikRegAccess(store, displacement >> 2, false /* isLoad */);
}
return res;
}
}
/* Architecture-specific initializations and checks go here */
-bool dvmCompilerArchInit(void)
+static bool compilerArchVariantInit(void)
{
/* First, declare dvmCompiler_TEMPLATE_XXX for each template */
#define JIT_TEMPLATE(X) extern void dvmCompiler_TEMPLATE_##X();
}
/* Architecture-specific initializations and checks go here */
-bool dvmCompilerArchInit(void)
+static bool compilerArchVariantInit(void)
{
/* First, declare dvmCompiler_TEMPLATE_XXX for each template */
#define JIT_TEMPLATE(X) extern void dvmCompiler_TEMPLATE_##X();
}
/* Architecture-specific initializations and checks go here */
-bool dvmCompilerArchInit(void)
+static bool compilerArchVariantInit(void)
{
/* First, declare dvmCompiler_TEMPLATE_XXX for each template */
#define JIT_TEMPLATE(X) extern void dvmCompiler_TEMPLATE_##X();
newLIR3(cUnit, THUMB2_FMRRD, r0, r1, dr1);
newLIR1(cUnit, THUMB_BLX_R, r2);
newLIR3(cUnit, THUMB2_FMDRR, dr0, r0, r1);
+ ArmLIR *label = newLIR0(cUnit, ARM_PSEUDO_TARGET_LABEL);
+ label->defMask = ENCODE_ALL;
+ branch->generic.target = (LIR *)label;
if (vDest >= 0)
- target = storeDouble(cUnit, dr0, vDest, rNone);
+ storeDouble(cUnit, dr0, vDest);
else
- target = newLIR3(cUnit, THUMB2_VSTRD, dr0, rGLUE, offset >> 2);
- branch->generic.target = (LIR *)target;
+ newLIR3(cUnit, THUMB2_VSTRD, dr0, rGLUE, offset >> 2);
resetRegisterScoreboard(cUnit);
return true;
}
default:
return true;
}
- loadFloat(cUnit, vSrc1, fr2);
- loadFloat(cUnit, vSrc2, fr4);
- newLIR3(cUnit, op, fr0, fr2, fr4);
- storeFloat(cUnit, fr0, vDest, 0);
+ int reg0, reg1, reg2;
+ reg1 = selectSFPReg(cUnit, vSrc1);
+ reg2 = selectSFPReg(cUnit, vSrc2);
+ /*
+ * The register mapping is overly optimistic and lazily updated so we
+ * need to detect false sharing here.
+ */
+ if (reg1 == reg2 && vSrc1 != vSrc2) {
+ reg2 = nextFPReg(cUnit, vSrc2, false /* isDouble */);
+ }
+ loadFloat(cUnit, vSrc1, reg1);
+ loadFloat(cUnit, vSrc2, reg2);
+ reg0 = selectSFPReg(cUnit, vDest);
+ newLIR3(cUnit, op, reg0, reg1, reg2);
+ storeFloat(cUnit, reg0, vDest);
return false;
}
default:
return true;
}
- loadDouble(cUnit, vSrc1, dr1);
- loadDouble(cUnit, vSrc2, dr2);
- newLIR3(cUnit, op, dr0, dr1, dr2);
- storeDouble(cUnit, dr0, vDest, rNone);
+
+ int reg0, reg1, reg2;
+ reg1 = selectDFPReg(cUnit, vSrc1);
+ reg2 = selectDFPReg(cUnit, vSrc2);
+ if (reg1 == reg2 && vSrc1 != vSrc2) {
+ reg2 = nextFPReg(cUnit, vSrc2, true /* isDouble */);
+ }
+ loadDouble(cUnit, vSrc1, reg1);
+ loadDouble(cUnit, vSrc2, reg2);
+ /* Rename the new vDest to a new register */
+ reg0 = selectDFPReg(cUnit, vNone);
+ newLIR3(cUnit, op, reg0, reg1, reg2);
+ storeDouble(cUnit, reg0, vDest);
return false;
}
return true;
}
if (longSrc) {
- srcReg = dr1;
+ srcReg = selectDFPReg(cUnit, vSrc2);
loadDouble(cUnit, vSrc2, srcReg);
} else {
- srcReg = fr2;
+ srcReg = selectSFPReg(cUnit, vSrc2);
loadFloat(cUnit, vSrc2, srcReg);
}
if (longDest) {
- newLIR2(cUnit, op, dr0, srcReg);
- storeDouble(cUnit, dr0, vSrc1Dest, rNone);
+ int destReg = selectDFPReg(cUnit, vNone);
+ newLIR2(cUnit, op, destReg, srcReg);
+ storeDouble(cUnit, destReg, vSrc1Dest);
} else {
- newLIR2(cUnit, op, fr0, srcReg);
- storeFloat(cUnit, fr0, vSrc1Dest, 0);
+ int destReg = selectSFPReg(cUnit, vNone);
+ newLIR2(cUnit, op, destReg, srcReg);
+ storeFloat(cUnit, destReg, vSrc1Dest);
}
return false;
}
bool isDouble;
int defaultResult;
bool ltNaNBias;
+ int fpReg1, fpReg2;
switch(mir->dalvikInsn.opCode) {
case OP_CMPL_FLOAT:
return true;
}
if (isDouble) {
- loadDouble(cUnit, vSrc1, dr0);
- loadDouble(cUnit, vSrc2, dr1);
+ fpReg1 = selectDFPReg(cUnit, vSrc1);
+ fpReg2 = selectDFPReg(cUnit, vSrc2);
+ if (fpReg1 == fpReg2 && vSrc1 != vSrc2) {
+ fpReg2 = nextFPReg(cUnit, vSrc2, true /* isDouble */);
+ }
+ loadDouble(cUnit, vSrc1, fpReg1);
+ loadDouble(cUnit, vSrc2, fpReg2);
// Hard-coded use of r7 as temp. Revisit
- loadConstant(cUnit,r7, defaultResult);
- newLIR2(cUnit, THUMB2_VCMPD, dr0, dr1);
+ loadConstant(cUnit, r7, defaultResult);
+ newLIR2(cUnit, THUMB2_VCMPD, fpReg1, fpReg2);
} else {
- loadFloat(cUnit, vSrc1, fr0);
- loadFloat(cUnit, vSrc2, fr2);
+ fpReg1 = selectSFPReg(cUnit, vSrc1);
+ fpReg2 = selectSFPReg(cUnit, vSrc2);
+ if (fpReg1 == fpReg2 && vSrc1 != vSrc2) {
+ fpReg2 = nextFPReg(cUnit, vSrc2, false /* isDouble */);
+ }
+ loadFloat(cUnit, vSrc1, fpReg1);
+ loadFloat(cUnit, vSrc2, fpReg2);
// Hard-coded use of r7 as temp. Revisit
- loadConstant(cUnit,r7, defaultResult);
- newLIR2(cUnit, THUMB2_VCMPS, fr0, fr2);
+ loadConstant(cUnit, r7, defaultResult);
+ newLIR2(cUnit, THUMB2_VCMPS, fpReg1, fpReg2);
}
newLIR0(cUnit, THUMB2_FMSTAT);
genIT(cUnit, (defaultResult == -1) ? ARM_COND_GT : ARM_COND_MI, "");