Complete MIPS code generation support
With this CL code generation for MIPS is complete (though untested on
actual hardware). Core and the boot classpath compile without issue.
The primary thrust here was to support expanding of short branch
sequences to long form during assembly if the displacement field overflowed.
That led to a general cleanup of creation on LIR nodes outside of the
normal flow.
Also introduced is a README to describe the state of MIPS support, as well
as memory barrier handling.
Change-Id: I251a2ef8d74bc7183406dce9493464be24a9d7f7
diff --git a/src/compiler/codegen/mips/Assemble.cc b/src/compiler/codegen/mips/Assemble.cc
index 5f215ef..a70d9da 100644
--- a/src/compiler/codegen/mips/Assemble.cc
+++ b/src/compiler/codegen/mips/Assemble.cc
@@ -106,44 +106,44 @@
"andi", "!0r,!1r,0x!2h(!2d)", 4),
ENCODING_MAP(kMipsB, 0x10000000,
kFmtBitBlt, 15, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
- kFmtUnused, -1, -1, NO_OPERAND | IS_BRANCH,
+ kFmtUnused, -1, -1, NO_OPERAND | IS_BRANCH | NEEDS_FIXUP,
"b", "!0t!0N", 8),
ENCODING_MAP(kMipsBal, 0x04110000,
kFmtBitBlt, 15, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
- kFmtUnused, -1, -1, NO_OPERAND | IS_BRANCH | REG_DEF_LR,
- "bal", "!0t!0N", 8),
+ kFmtUnused, -1, -1, NO_OPERAND | IS_BRANCH | REG_DEF_LR |
+ NEEDS_FIXUP, "bal", "!0t!0N", 8),
ENCODING_MAP(kMipsBeq, 0x10000000,
kFmtBitBlt, 25, 21, kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0,
- kFmtUnused, -1, -1, IS_BINARY_OP | IS_BRANCH | REG_USE01,
- "beq", "!0r,!1r,!2t!0N", 8),
+ kFmtUnused, -1, -1, IS_BINARY_OP | IS_BRANCH | REG_USE01 |
+ NEEDS_FIXUP, "beq", "!0r,!1r,!2t!0N", 8),
ENCODING_MAP(kMipsBeqz, 0x10000000, /* same as beq above with t = $zero */
kFmtBitBlt, 25, 21, kFmtBitBlt, 15, 0, kFmtUnused, -1, -1,
- kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH | REG_USE0,
- "beqz", "!0r,!1t!0N", 8),
+ kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH | REG_USE0 |
+ NEEDS_FIXUP, "beqz", "!0r,!1t!0N", 8),
ENCODING_MAP(kMipsBgez, 0x04010000,
kFmtBitBlt, 25, 21, kFmtBitBlt, 15, 0, kFmtUnused, -1, -1,
- kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH | REG_USE0,
- "bgez", "!0r,!1t!0N", 8),
+ kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH | REG_USE0 |
+ NEEDS_FIXUP, "bgez", "!0r,!1t!0N", 8),
ENCODING_MAP(kMipsBgtz, 0x1C000000,
kFmtBitBlt, 25, 21, kFmtBitBlt, 15, 0, kFmtUnused, -1, -1,
- kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH | REG_USE0,
- "bgtz", "!0r,!1t!0N", 8),
+ kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH | REG_USE0 |
+ NEEDS_FIXUP, "bgtz", "!0r,!1t!0N", 8),
ENCODING_MAP(kMipsBlez, 0x18000000,
kFmtBitBlt, 25, 21, kFmtBitBlt, 15, 0, kFmtUnused, -1, -1,
- kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH | REG_USE0,
- "blez", "!0r,!1t!0N", 8),
+ kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH | REG_USE0 |
+ NEEDS_FIXUP, "blez", "!0r,!1t!0N", 8),
ENCODING_MAP(kMipsBltz, 0x04000000,
kFmtBitBlt, 25, 21, kFmtBitBlt, 15, 0, kFmtUnused, -1, -1,
- kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH | REG_USE0,
- "bltz", "!0r,!1t!0N", 8),
+ kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH | REG_USE0 |
+ NEEDS_FIXUP, "bltz", "!0r,!1t!0N", 8),
ENCODING_MAP(kMipsBnez, 0x14000000, /* same as bne below with t = $zero */
kFmtBitBlt, 25, 21, kFmtBitBlt, 15, 0, kFmtUnused, -1, -1,
- kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH | REG_USE0,
- "bnez", "!0r,!1t!0N", 8),
+ kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH | REG_USE0 |
+ NEEDS_FIXUP, "bnez", "!0r,!1t!0N", 8),
ENCODING_MAP(kMipsBne, 0x14000000,
kFmtBitBlt, 25, 21, kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0,
- kFmtUnused, -1, -1, IS_BINARY_OP | IS_BRANCH | REG_USE01,
- "bne", "!0r,!1r,!2t!0N", 8),
+ kFmtUnused, -1, -1, IS_BINARY_OP | IS_BRANCH | REG_USE01 |
+ NEEDS_FIXUP, "bne", "!0r,!1r,!2t!0N", 8),
ENCODING_MAP(kMipsDiv, 0x0000001a,
kFmtUnused, -1, -1, kFmtUnused, -1, -1, kFmtBitBlt, 25, 21,
kFmtBitBlt, 20, 16, IS_QUAD_OP | REG_DEF01 | REG_USE23,
@@ -164,8 +164,8 @@
"jalr", "!0r,!1r!0N", 8),
ENCODING_MAP(kMipsJr, 0x00000008,
kFmtBitBlt, 25, 21, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
- kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH | REG_USE0,
- "jr", "!0r!0N", 8),
+ kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH | REG_USE0 |
+ NEEDS_FIXUP, "jr", "!0r!0N", 8),
ENCODING_MAP(kMipsLahi, 0x3C000000,
kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0, kFmtUnused, -1, -1,
kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0,
@@ -400,26 +400,117 @@
#endif
ENCODING_MAP(kMipsDelta, 0x27e00000,
kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0, kFmtUnused, 15, 0,
- kFmtUnused, -1, -1, IS_QUAD_OP | REG_DEF0 | REG_USE_LR,
- "addiu", "!0r,r_ra,0x!1h(!1d)", 4),
+ kFmtUnused, -1, -1, IS_QUAD_OP | REG_DEF0 | REG_USE_LR |
+ NEEDS_FIXUP, "addiu", "!0r,r_ra,0x!1h(!1d)", 4),
ENCODING_MAP(kMipsDeltaHi, 0x3C000000,
kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0, kFmtUnused, -1, -1,
- kFmtUnused, -1, -1, IS_QUAD_OP | REG_DEF0,
+ kFmtUnused, -1, -1, IS_QUAD_OP | REG_DEF0 | NEEDS_FIXUP,
"lui", "!0r,0x!1h(!1d)", 4),
ENCODING_MAP(kMipsDeltaLo, 0x34000000,
kFmtBlt5_2, 16, 21, kFmtBitBlt, 15, 0, kFmtUnused, -1, -1,
- kFmtUnused, -1, -1, IS_QUAD_OP | REG_DEF0_USE0,
+ kFmtUnused, -1, -1, IS_QUAD_OP | REG_DEF0_USE0 | NEEDS_FIXUP,
"ori", "!0r,!0r,0x!1h(!1d)", 4),
- ENCODING_MAP(kMipsCurrPC, 0x0c000000,
+ ENCODING_MAP(kMipsCurrPC, 0x04110020,
kFmtUnused, -1, -1, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
kFmtUnused, -1, -1, NO_OPERAND | IS_BRANCH | REG_DEF_LR,
"pc2ra", "; r_ra <- .+8", 4),
+ ENCODING_MAP(kMipsSync, 0x0000000f,
+ kFmtBitBlt, 10, 6, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
+ kFmtUnused, -1, -1, IS_UNARY_OP,
+ "sync", ";", 4),
ENCODING_MAP(kMipsUndefined, 0x64000000,
kFmtUnused, -1, -1, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
kFmtUnused, -1, -1, NO_OPERAND,
"undefined", "", 4),
};
+
+/*
+ * Convert a short-form branch to long form. Hopefully, this won't happen
+ * very often because the PIC sequence is especially unfortunate.
+ *
+ * Orig conditional branch
+ * -----------------------
+ * beq rs,rt,target
+ *
+ * Long conditional branch
+ * -----------------------
+ * bne rs,rt,hop
+ * bal .+8 ; r_RA <- anchor
+ * lui r_AT, ((target-anchor) >> 16)
+ * anchor:
+ * ori r_AT, r_AT, ((target-anchor) & 0xffff)
+ * addu r_AT, r_AT, r_RA
+ * jr r_AT
+ * hop:
+ *
+ * Orig unconditional branch
+ * -------------------------
+ * b target
+ *
+ * Long unconditional branch
+ * -----------------------
+ * bal .+8 ; r_RA <- anchor
+ * lui r_AT, ((target-anchor) >> 16)
+ * anchor:
+ * ori r_AT, r_AT, ((target-anchor) & 0xffff)
+ * addu r_AT, r_AT, r_RA
+ * jr r_AT
+ *
+ *
+ * NOTE: An out-of-range bal isn't supported because it should
+ * never happen with the current PIC model.
+ */
+void convertShortToLongBranch(CompilationUnit* cUnit, LIR* lir)
+{
+ // For conditional branches we'll need to reverse the sense
+ bool unconditional = false;
+ int opcode = lir->opcode;
+ int dalvikOffset = lir->dalvikOffset;
+ switch(opcode) {
+ case kMipsBal:
+ LOG(FATAL) << "long branch and link unsupported";
+ case kMipsB:
+ unconditional = true;
+ break;
+ case kMipsBeq: opcode = kMipsBne; break;
+ case kMipsBne: opcode = kMipsBeq; break;
+ case kMipsBeqz: opcode = kMipsBnez; break;
+ case kMipsBgez: opcode = kMipsBltz; break;
+ case kMipsBgtz: opcode = kMipsBlez; break;
+ case kMipsBlez: opcode = kMipsBgtz; break;
+ case kMipsBltz: opcode = kMipsBgez; break;
+ case kMipsBnez: opcode = kMipsBeqz; break;
+ default:
+ LOG(FATAL) << "Unexpected branch kind " << (int)opcode;
+ }
+ LIR* hopTarget = NULL;
+ if (!unconditional) {
+ hopTarget = rawLIR(cUnit, dalvikOffset, kPseudoTargetLabel);
+ LIR* hopBranch = rawLIR(cUnit, dalvikOffset, opcode, lir->operands[0],
+ lir->operands[1], 0, 0, hopTarget);
+ oatInsertLIRBefore(lir, hopBranch);
+ }
+ LIR* currPC = rawLIR(cUnit, dalvikOffset, kMipsCurrPC);
+ oatInsertLIRBefore(lir, currPC);
+ LIR* anchor = rawLIR(cUnit, dalvikOffset, kPseudoTargetLabel);
+ LIR* deltaHi = rawLIR(cUnit, dalvikOffset, kMipsDeltaHi, r_AT, 0,
+ (uintptr_t)anchor, 0, lir->target);
+ oatInsertLIRBefore(lir, deltaHi);
+ oatInsertLIRBefore(lir, anchor);
+ LIR* deltaLo = rawLIR(cUnit, dalvikOffset, kMipsDeltaLo, r_AT, 0,
+ (uintptr_t)anchor, 0, lir->target);
+ oatInsertLIRBefore(lir, deltaLo);
+ LIR* addu = rawLIR(cUnit, dalvikOffset, kMipsAddu, r_AT, r_AT, r_RA);
+ oatInsertLIRBefore(lir, addu);
+ LIR* jr = rawLIR(cUnit, dalvikOffset, kMipsJr, r_AT);
+ oatInsertLIRBefore(lir, jr);
+ if (!unconditional) {
+ oatInsertLIRBefore(lir, hopTarget);
+ }
+ lir->flags.isNop = true;
+}
+
/*
* Assemble the LIR into binary instruction format. Note that we may
* discover that pc-relative displacements may not fit the selected
@@ -442,108 +533,112 @@
continue;
}
-// TODO: check for lir->flags.pcRelFixup
-
- if (lir->opcode == kMipsDelta) {
- int offset1 = ((LIR*)lir->operands[2])->offset;
- SwitchTable *tabRec = (SwitchTable*)lir->operands[3];
- int offset2 = tabRec ? tabRec->offset : lir->target->offset;
- int delta = offset2 - offset1;
- if ((delta & 0xffff) == delta) {
- // Fits
- lir->operands[1] = delta;
- } else {
- // Doesn't fit - must expand to kMipsDelta[Hi|Lo] pair
- LIR *newDeltaHi =
- (LIR *)oatNew(cUnit, sizeof(LIR), true,
- kAllocLIR);
- newDeltaHi->dalvikOffset = lir->dalvikOffset;
- newDeltaHi->target = lir->target;
- newDeltaHi->opcode = kMipsDeltaHi;
- newDeltaHi->operands[0] = lir->operands[0];
- newDeltaHi->operands[2] = lir->operands[2];
- newDeltaHi->operands[3] = lir->operands[3];
- oatSetupResourceMasks(newDeltaHi);
- oatInsertLIRBefore((LIR*)lir, (LIR*)newDeltaHi);
- LIR *newDeltaLo =
- (LIR *)oatNew(cUnit, sizeof(LIR), true,
- kAllocLIR);
- newDeltaLo->dalvikOffset = lir->dalvikOffset;
- newDeltaLo->target = lir->target;
- newDeltaLo->opcode = kMipsDeltaLo;
- newDeltaLo->operands[0] = lir->operands[0];
- newDeltaLo->operands[2] = lir->operands[2];
- newDeltaLo->operands[3] = lir->operands[3];
- oatSetupResourceMasks(newDeltaLo);
- oatInsertLIRBefore((LIR*)lir, (LIR*)newDeltaLo);
- lir->flags.isNop = true;
- res = kRetryAll;
+ if (lir->flags.pcRelFixup) {
+ if (lir->opcode == kMipsDelta) {
+ /*
+ * The "Delta" pseudo-ops load the difference between
+ * two pc-relative locations into a the target register
+ * found in operands[0]. The delta is determined by
+ * (label2 - label1), where label1 is a standard
+ * kPseudoTargetLabel and is stored in operands[2].
+ * If operands[3] is null, then label2 is a kPseudoTargetLabel
+ * and is found in lir->target. If operands[3] is non-NULL,
+ * then it is a Switch/Data table.
+ */
+ int offset1 = ((LIR*)lir->operands[2])->offset;
+ SwitchTable *tabRec = (SwitchTable*)lir->operands[3];
+ int offset2 = tabRec ? tabRec->offset : lir->target->offset;
+ int delta = offset2 - offset1;
+ if ((delta & 0xffff) == delta) {
+ // Fits
+ lir->operands[1] = delta;
+ } else {
+ // Doesn't fit - must expand to kMipsDelta[Hi|Lo] pair
+ LIR *newDeltaHi =
+ rawLIR(cUnit, lir->dalvikOffset, kMipsDeltaHi,
+ lir->operands[0], 0, lir->operands[2],
+ lir->operands[3], lir->target);
+ oatInsertLIRBefore((LIR*)lir, (LIR*)newDeltaHi);
+ LIR *newDeltaLo =
+ rawLIR(cUnit, lir->dalvikOffset, kMipsDeltaLo,
+ lir->operands[0], 0, lir->operands[2],
+ lir->operands[3], lir->target);
+ oatInsertLIRBefore((LIR*)lir, (LIR*)newDeltaLo);
+ lir->flags.isNop = true;
+ res = kRetryAll;
+ }
+ } else if (lir->opcode == kMipsDeltaLo) {
+ int offset1 = ((LIR*)lir->operands[2])->offset;
+ SwitchTable *tabRec = (SwitchTable*)lir->operands[3];
+ int offset2 = tabRec ? tabRec->offset : lir->target->offset;
+ int delta = offset2 - offset1;
+ lir->operands[1] = delta & 0xffff;
+ } else if (lir->opcode == kMipsDeltaHi) {
+ int offset1 = ((LIR*)lir->operands[2])->offset;
+ SwitchTable *tabRec = (SwitchTable*)lir->operands[3];
+ int offset2 = tabRec ? tabRec->offset : lir->target->offset;
+ int delta = offset2 - offset1;
+ lir->operands[1] = (delta >> 16) & 0xffff;
+ } else if (lir->opcode == kMipsB || lir->opcode == kMipsBal) {
+ 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) {
+ res = kRetryAll;
+ convertShortToLongBranch(cUnit, lir);
+ } else {
+ lir->operands[0] = delta >> 2;
+ }
+ } else if (lir->opcode >= kMipsBeqz && lir->opcode <= kMipsBnez) {
+ 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) {
+ res = kRetryAll;
+ convertShortToLongBranch(cUnit, lir);
+ } else {
+ lir->operands[1] = delta >> 2;
+ }
+ } else if (lir->opcode == kMipsBeq || lir->opcode == kMipsBne) {
+ 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) {
+ res = kRetryAll;
+ convertShortToLongBranch(cUnit, lir);
+ } else {
+ lir->operands[2] = delta >> 2;
+ }
+ } else if (lir->opcode == kMipsJal) {
+ 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));
+ if (target & 0x3) {
+ LOG(FATAL) << "Jump target not multiple of 4: " << target;
+ }
+ lir->operands[0] = target >> 2;
+ } else if (lir->opcode == kMipsLahi) { /* ld address hi (via lui) */
+ LIR *targetLIR = (LIR *) lir->target;
+ intptr_t target = startAddr + targetLIR->offset;
+ lir->operands[1] = target >> 16;
+ } else if (lir->opcode == kMipsLalo) { /* ld address lo (via ori) */
+ LIR *targetLIR = (LIR *) lir->target;
+ intptr_t target = startAddr + targetLIR->offset;
+ lir->operands[2] = lir->operands[2] + target;
}
- } else if (lir->opcode == kMipsDeltaLo) {
- int offset1 = ((LIR*)lir->operands[2])->offset;
- SwitchTable *tabRec = (SwitchTable*)lir->operands[3];
- int offset2 = tabRec ? tabRec->offset : lir->target->offset;
- int delta = offset2 - offset1;
- lir->operands[1] = delta & 0xffff;
- } else if (lir->opcode == kMipsDeltaHi) {
- int offset1 = ((LIR*)lir->operands[2])->offset;
- SwitchTable *tabRec = (SwitchTable*)lir->operands[3];
- int offset2 = tabRec ? tabRec->offset : lir->target->offset;
- int delta = offset2 - offset1;
- lir->operands[1] = (delta >> 16) & 0xffff;
- } else if (lir->opcode == kMipsB || lir->opcode == kMipsBal) {
- 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) {
- UNIMPLEMENTED(FATAL) << "B out of range, need long sequence: " << delta;
- }
- lir->operands[0] = delta >> 2;
- } else if (lir->opcode >= kMipsBeqz && lir->opcode <= kMipsBnez) {
- 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) {
- UNIMPLEMENTED(FATAL) << "B[eq|ne]z needs long sequence: " << delta;
- }
- lir->operands[1] = delta >> 2;
- } else if (lir->opcode == kMipsBeq || lir->opcode == kMipsBne) {
- 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) {
- UNIMPLEMENTED(FATAL) << "B[eq|ne] needs long sequence: " << delta;
- }
- lir->operands[2] = delta >> 2;
- } else if (lir->opcode == kMipsJal) {
- 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));
- if (target & 0x3) {
- LOG(FATAL) << "Jump target not multiple of 4: " << target;
- }
- lir->operands[0] = target >> 2;
- } else if (lir->opcode == kMipsLahi) { /* load address hi (via lui) */
- 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) */
- LIR *targetLIR = (LIR *) lir->target;
- intptr_t target = startAddr + targetLIR->offset;
- lir->operands[2] = lir->operands[2] + target;
}
/*
diff --git a/src/compiler/codegen/mips/Mips32/Factory.cc b/src/compiler/codegen/mips/Mips32/Factory.cc
index 105677e..ecc0180 100644
--- a/src/compiler/codegen/mips/Mips32/Factory.cc
+++ b/src/compiler/codegen/mips/Mips32/Factory.cc
@@ -28,7 +28,8 @@
r_T0, r_T1, r_T2, r_T3, r_T4, r_T5, r_T6, r_T7,
r_S0, r_S1, r_S2, r_S3, r_S4, r_S5, r_S6, r_S7, r_T8,
r_T9, r_K0, r_K1, r_GP, r_SP, r_FP, r_RA};
-static int reservedRegs[] = {r_ZERO, r_AT, r_S0, r_S1, r_K0, r_K1, r_GP, r_SP, r_RA};
+static int reservedRegs[] = {r_ZERO, r_AT, r_S0, r_S1, r_K0, r_K1, r_GP, r_SP,
+ r_RA};
static int coreTemps[] = {r_V0, r_V1, r_A0, r_A1, r_A2, r_A3, r_T0, r_T1, r_T2,
r_T3, r_T4, r_T5, r_T6, r_T7, r_T8, r_T9};
#ifdef __mips_hard_float
@@ -51,33 +52,31 @@
#ifdef __mips_hard_float
LIR *fpRegCopy(CompilationUnit *cUnit, int rDest, int rSrc)
{
- LIR* res = (LIR *) oatNew(cUnit, sizeof(LIR), true, kAllocLIR);
- res->operands[0] = rDest;
- res->operands[1] = rSrc;
- if (rDest == rSrc) {
- res->flags.isNop = true;
+ int opcode;
+ /* must be both DOUBLE or both not DOUBLE */
+ DCHECK_EQ(DOUBLEREG(rDest),DOUBLEREG(rSrc));
+ if (DOUBLEREG(rDest)) {
+ opcode = kMipsFmovd;
} else {
- /* must be both DOUBLE or both not DOUBLE */
- DCHECK_EQ(DOUBLEREG(rDest),DOUBLEREG(rSrc));
- if (DOUBLEREG(rDest)) {
- res->opcode = kMipsFmovd;
- } else {
- if (SINGLEREG(rDest)) {
- if (SINGLEREG(rSrc)) {
- res->opcode = kMipsFmovs;
- } else {
- /* note the operands are swapped for the mtc1 instr */
- res->opcode = kMipsMtc1;
- res->operands[0] = rSrc;
- res->operands[1] = rDest;
- }
+ if (SINGLEREG(rDest)) {
+ if (SINGLEREG(rSrc)) {
+ opcode = kMipsFmovs;
} else {
- DCHECK(SINGLEREG(rSrc));
- res->opcode = kMipsMfc1;
+ /* note the operands are swapped for the mtc1 instr */
+ int tOpnd = rSrc;
+ rSrc = rDest;
+ rDest = tOpnd;
+ opcode = kMipsMtc1;
}
+ } else {
+ DCHECK(SINGLEREG(rSrc));
+ opcode = kMipsMfc1;
}
}
- setupResourceMasks(res);
+ LIR* res = rawLIR(cUnit, cUnit->currentDalvikOffset, opcode, rSrc, rDest);
+ if (rDest == rSrc) {
+ res->flags.isNop = true;
+ }
return res;
}
#endif
diff --git a/src/compiler/codegen/mips/Mips32/Gen.cc b/src/compiler/codegen/mips/Mips32/Gen.cc
index c975889..2bb2f7a 100644
--- a/src/compiler/codegen/mips/Mips32/Gen.cc
+++ b/src/compiler/codegen/mips/Mips32/Gen.cc
@@ -389,8 +389,7 @@
swapped = true;
break;
default:
- UNIMPLEMENTED(FATAL) << "No support for ConditionCode: "
- << (int) cond;
+ LOG(FATAL) << "No support for ConditionCode: " << (int) cond;
return NULL;
}
if (cmpZero) {
@@ -445,19 +444,12 @@
LIR* opRegCopyNoInsert(CompilationUnit *cUnit, int rDest, int rSrc)
{
- 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);
+ LIR* res = rawLIR(cUnit, cUnit->currentDalvikOffset, kMipsMove,
+ rDest, rSrc);
if (rDest == rSrc) {
res->flags.isNop = true;
}
diff --git a/src/compiler/codegen/mips/MipsLIR.h b/src/compiler/codegen/mips/MipsLIR.h
index 5034623..18f06ae 100644
--- a/src/compiler/codegen/mips/MipsLIR.h
+++ b/src/compiler/codegen/mips/MipsLIR.h
@@ -311,9 +311,17 @@
kMipsRor = 0x3
} MipsShiftEncodings;
-// FIXME: Need support for barriers. Adding these defines to allow compile
-#define kST 0
-#define kSY 1
+// MIPS sync kinds (Note: support for kinds other than kSYNC0 may not exist)
+#define kSYNC0 0x00
+#define kSYNC_WMB 0x04
+#define kSYNC_MB 0x01
+#define kSYNC_ACQUIRE 0x11
+#define kSYNC_RELEASE 0x12
+#define kSYNC_RMB 0x13
+
+// TODO: Use smaller hammer when appropriate for target CPU
+#define kST kSYNC0
+#define kSY kSYNC0
#define isPseudoOpcode(opCode) ((int)(opCode) < 0)
@@ -430,6 +438,7 @@
kMipsDeltaHi, /* Pseudo for lui t, high16(<label>-<label>) */
kMipsDeltaLo, /* Pseudo for ori t, s, low16(<label>-<label>) */
kMipsCurrPC, /* jal to .+8 to materialize pc */
+ kMipsSync, /* sync kind [000000] [0000000000000000] s[10..6] [001111] */
kMipsUndefined, /* undefined [011001xxxxxxxxxxxxxxxx] */
kMipsLast
} MipsOpCode;
@@ -463,7 +472,6 @@
kMemStore,
kPCRelFixup,
kRegUseLR,
-// FIXME: add NEEDS_FIXUP to instruction attributes
} MipsOpFeatureFlags;
#define IS_LOAD (1 << kMemLoad)
diff --git a/src/compiler/codegen/mips/MipsRallocUtil.cc b/src/compiler/codegen/mips/MipsRallocUtil.cc
index 774dffc..3cad4d9 100644
--- a/src/compiler/codegen/mips/MipsRallocUtil.cc
+++ b/src/compiler/codegen/mips/MipsRallocUtil.cc
@@ -47,7 +47,7 @@
*/
void oatMarkPreservedSingle(CompilationUnit* cUnit, int sReg, int reg)
{
- UNIMPLEMENTED(FATAL) << "No support yet for promoted FP regs";
+ LOG(FATAL) << "No support yet for promoted FP regs";
}
void oatFlushRegWide(CompilationUnit* cUnit, int reg1, int reg2)
diff --git a/src/compiler/codegen/mips/README.mips b/src/compiler/codegen/mips/README.mips
new file mode 100644
index 0000000..5add2f3
--- /dev/null
+++ b/src/compiler/codegen/mips/README.mips
@@ -0,0 +1,57 @@
+ Notes on the Mips target (3/4/2012)
+ -----------------------------------
+
+Testing
+
+The initial implementation of Mips support in the compiler is untested on
+actual hardware, and as such should be expected to have many bugs. However,
+the vast majority of code for Mips support is either shared with other
+tested targets, or was taken from the functional Mips JIT compiler. The
+expectation is that when it is first tried out on actual hardware lots of
+small bugs will be flushed out, but it should not take long to get it
+solidly running. The following area are considered most likely to have
+problems that need to be addressed:
+
+ o Endianness. Focus was on little-endian support, and if a big-endian
+ target is desired, you should pay particular attention to the
+ code generation for switch tables, fill array data, 64-bit
+ data handling and the register usage conventions.
+
+ o The memory model. Verify that oatGenMemoryBarrier() generates the
+ appropriate flavor of sync.
+
+Register promotion
+
+The resource masks in the LIR structure are 64-bits wide, which is enough
+room to fully describe def/use info for Arm and x86 instructions. However,
+the larger number of MIPS core and float registers render this too small.
+Currently, the workaround for this limitation is to avoid using floating
+point registers 16-31. These are the callee-save registers, which therefore
+means that no floating point promotion is allowed. Among the solution are:
+ o Expand the def/use mask (which, unfortunately, is a significant change)
+ o The Arm target uses 52 of the 64 bits, so we could support float
+ registers 16-27 without much effort.
+ o We could likely assign the 4 non-register bits (kDalvikReg, kLiteral,
+ kHeapRef & kMustNotAlias) to positions occuped by MIPS registers that
+ don't need def/use bits because they are never modified by code
+ subject to scheduling: r_K0, r_K1, r_SP, r_ZERO, r_S1 (rSELF).
+
+Branch delay slots
+
+Little to no attempt was made to fill branch delay slots. Branch
+instructions in the encoding map are given a length of 8 bytes to include
+an implicit NOP. It should not be too difficult to provide a slot-filling
+pass following successful assembly, but thought should be given to the
+design. Branches are currently treated as scheduling barriers. One
+simple solution would be to copy the instruction at branch targets to the
+slot and adjust the displacement. However, given that code expansion is
+already a problem it would be preferable to use a more sophisticated
+scheduling solution.
+
+Code expansion
+
+Code expansion for the MIPS target is significantly higher than we see
+for Arm and x86. It might make sense to replace the inline code generation
+for some of the more verbose Dalik byte codes with subroutine calls to
+shared helper functions.
+
diff --git a/src/compiler/codegen/mips/mips/ArchVariant.cc b/src/compiler/codegen/mips/mips/ArchVariant.cc
index 32b50e9..6d29fc5 100644
--- a/src/compiler/codegen/mips/mips/ArchVariant.cc
+++ b/src/compiler/codegen/mips/mips/ArchVariant.cc
@@ -52,7 +52,7 @@
void oatGenMemBarrier(CompilationUnit *cUnit, int barrierKind)
{
#if ANDROID_SMP != 0
- // FIXME: what to do here for Mips?
+ newLIR1(cUnit, kMipsSync, barrierKind);
#endif
}