diff options
Diffstat (limited to 'src/compiler/codegen/mips/Assemble.cc')
| -rw-r--r-- | src/compiler/codegen/mips/Assemble.cc | 492 |
1 files changed, 246 insertions, 246 deletions
diff --git a/src/compiler/codegen/mips/Assemble.cc b/src/compiler/codegen/mips/Assemble.cc index 1d629be541..c19effe2f3 100644 --- a/src/compiler/codegen/mips/Assemble.cc +++ b/src/compiler/codegen/mips/Assemble.cc @@ -463,52 +463,52 @@ MipsEncodingMap EncodingMap[kMipsLast] = { */ 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, 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, 0, lir->target); - oatInsertLIRBefore(lir, deltaHi); - oatInsertLIRBefore(lir, anchor); - LIR* deltaLo = rawLIR(cUnit, dalvikOffset, kMipsDeltaLo, r_AT, 0, - (uintptr_t)anchor, 0, 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; + // 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, 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, 0, lir->target); + oatInsertLIRBefore(lir, deltaHi); + oatInsertLIRBefore(lir, anchor); + LIR* deltaLo = rawLIR(cUnit, dalvikOffset, kMipsDeltaLo, r_AT, 0, + (uintptr_t)anchor, 0, 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; } /* @@ -518,201 +518,201 @@ void convertShortToLongBranch(CompilationUnit* cUnit, LIR* lir) * sequence or request that the trace be shortened and retried. */ AssemblerStatus oatAssembleInstructions(CompilationUnit *cUnit, - intptr_t startAddr) + intptr_t startAddr) { - LIR *lir; - AssemblerStatus res = kSuccess; // Assume success - - for (lir = (LIR *) cUnit->firstLIRInsn; lir; lir = NEXT_LIR(lir)) { - if (lir->opcode < 0) { - continue; - } + LIR *lir; + AssemblerStatus res = kSuccess; // Assume success + for (lir = (LIR *) cUnit->firstLIRInsn; lir; lir = NEXT_LIR(lir)) { + if (lir->opcode < 0) { + continue; + } - if (lir->flags.isNop) { - continue; - } - 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], 0, lir->target); - oatInsertLIRBefore((LIR*)lir, (LIR*)newDeltaHi); - LIR *newDeltaLo = - rawLIR(cUnit, lir->dalvikOffset, kMipsDeltaLo, - lir->operands[0], 0, lir->operands[2], - lir->operands[3], 0, 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; - } - } + if (lir->flags.isNop) { + continue; + } + if (lir->flags.pcRelFixup) { + if (lir->opcode == kMipsDelta) { /* - * If one of the pc-relative instructions expanded we'll have - * to make another pass. Don't bother to fully assemble the - * instruction. + * 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. */ - if (res != kSuccess) { - continue; + 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], 0, lir->target); + oatInsertLIRBefore((LIR*)lir, (LIR*)newDeltaHi); + LIR *newDeltaLo = + rawLIR(cUnit, lir->dalvikOffset, kMipsDeltaLo, + lir->operands[0], 0, lir->operands[2], + lir->operands[3], 0, 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; } - const MipsEncodingMap *encoder = &EncodingMap[lir->opcode]; - u4 bits = encoder->skeleton; - int i; - for (i = 0; i < 4; i++) { - u4 operand; - u4 value; - operand = lir->operands[i]; - switch (encoder->fieldLoc[i].kind) { - case kFmtUnused: - break; - case kFmtBitBlt: - if (encoder->fieldLoc[i].start == 0 && encoder->fieldLoc[i].end == 31) { - value = operand; - } else { - value = (operand << encoder->fieldLoc[i].start) & - ((1 << (encoder->fieldLoc[i].end + 1)) - 1); - } - bits |= value; - break; - case kFmtBlt5_2: - value = (operand & 0x1f); - bits |= (value << encoder->fieldLoc[i].start); - bits |= (value << encoder->fieldLoc[i].end); - break; - case kFmtDfp: { - DCHECK(DOUBLEREG(operand)); - DCHECK((operand & 0x1) == 0); - value = ((operand & FP_REG_MASK) << encoder->fieldLoc[i].start) & - ((1 << (encoder->fieldLoc[i].end + 1)) - 1); - bits |= value; - break; - } - case kFmtSfp: - DCHECK(SINGLEREG(operand)); - value = ((operand & FP_REG_MASK) << encoder->fieldLoc[i].start) & - ((1 << (encoder->fieldLoc[i].end + 1)) - 1); - bits |= value; - break; - default: - LOG(FATAL) << "Bad encoder format: " - << (int)encoder->fieldLoc[i].kind; - } + if (delta > 131068 || delta < -131069) { + res = kRetryAll; + convertShortToLongBranch(cUnit, lir); + } else { + lir->operands[0] = delta >> 2; } - // FIXME: need multi-endian handling here - cUnit->codeBuffer.push_back((bits >> 24) & 0xff); - cUnit->codeBuffer.push_back((bits >> 16) & 0xff); - cUnit->codeBuffer.push_back((bits >> 8) & 0xff); - cUnit->codeBuffer.push_back(bits & 0xff); - // TUNING: replace with proper delay slot handling - if (encoder->size == 8) { - const MipsEncodingMap *encoder = &EncodingMap[kMipsNop]; - u4 bits = encoder->skeleton; - cUnit->codeBuffer.push_back((bits >> 24) & 0xff); - cUnit->codeBuffer.push_back((bits >> 16) & 0xff); - cUnit->codeBuffer.push_back((bits >> 8) & 0xff); - cUnit->codeBuffer.push_back(bits & 0xff); + } 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; + } + } + + /* + * 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; } - return res; + const MipsEncodingMap *encoder = &EncodingMap[lir->opcode]; + u4 bits = encoder->skeleton; + int i; + for (i = 0; i < 4; i++) { + u4 operand; + u4 value; + operand = lir->operands[i]; + switch (encoder->fieldLoc[i].kind) { + case kFmtUnused: + break; + case kFmtBitBlt: + if (encoder->fieldLoc[i].start == 0 && encoder->fieldLoc[i].end == 31) { + value = operand; + } else { + value = (operand << encoder->fieldLoc[i].start) & + ((1 << (encoder->fieldLoc[i].end + 1)) - 1); + } + bits |= value; + break; + case kFmtBlt5_2: + value = (operand & 0x1f); + bits |= (value << encoder->fieldLoc[i].start); + bits |= (value << encoder->fieldLoc[i].end); + break; + case kFmtDfp: { + DCHECK(DOUBLEREG(operand)); + DCHECK((operand & 0x1) == 0); + value = ((operand & FP_REG_MASK) << encoder->fieldLoc[i].start) & + ((1 << (encoder->fieldLoc[i].end + 1)) - 1); + bits |= value; + break; + } + case kFmtSfp: + DCHECK(SINGLEREG(operand)); + value = ((operand & FP_REG_MASK) << encoder->fieldLoc[i].start) & + ((1 << (encoder->fieldLoc[i].end + 1)) - 1); + bits |= value; + break; + default: + LOG(FATAL) << "Bad encoder format: " + << (int)encoder->fieldLoc[i].kind; + } + } + // FIXME: need multi-endian handling here + cUnit->codeBuffer.push_back((bits >> 24) & 0xff); + cUnit->codeBuffer.push_back((bits >> 16) & 0xff); + cUnit->codeBuffer.push_back((bits >> 8) & 0xff); + cUnit->codeBuffer.push_back(bits & 0xff); + // TUNING: replace with proper delay slot handling + if (encoder->size == 8) { + const MipsEncodingMap *encoder = &EncodingMap[kMipsNop]; + u4 bits = encoder->skeleton; + cUnit->codeBuffer.push_back((bits >> 24) & 0xff); + cUnit->codeBuffer.push_back((bits >> 16) & 0xff); + cUnit->codeBuffer.push_back((bits >> 8) & 0xff); + cUnit->codeBuffer.push_back(bits & 0xff); + } + } + return res; } int oatGetInsnSize(LIR* lir) { - return EncodingMap[lir->opcode].size; + return EncodingMap[lir->opcode].size; } /* * Target-dependent offset assignment. @@ -720,29 +720,29 @@ int oatGetInsnSize(LIR* lir) */ int oatAssignInsnOffsets(CompilationUnit* cUnit) { - LIR* mipsLIR; - int offset = 0; + LIR* mipsLIR; + int offset = 0; - for (mipsLIR = (LIR *) cUnit->firstLIRInsn; - mipsLIR; - mipsLIR = NEXT_LIR(mipsLIR)) { - mipsLIR->offset = offset; - if (mipsLIR->opcode >= 0) { - if (!mipsLIR->flags.isNop) { - offset += mipsLIR->flags.size; - } - } else if (mipsLIR->opcode == kPseudoPseudoAlign4) { - if (offset & 0x2) { - offset += 2; - mipsLIR->operands[0] = 1; - } else { - mipsLIR->operands[0] = 0; - } - } - /* Pseudo opcodes don't consume space */ + for (mipsLIR = (LIR *) cUnit->firstLIRInsn; + mipsLIR; + mipsLIR = NEXT_LIR(mipsLIR)) { + mipsLIR->offset = offset; + if (mipsLIR->opcode >= 0) { + if (!mipsLIR->flags.isNop) { + offset += mipsLIR->flags.size; + } + } else if (mipsLIR->opcode == kPseudoPseudoAlign4) { + if (offset & 0x2) { + offset += 2; + mipsLIR->operands[0] = 1; + } else { + mipsLIR->operands[0] = 0; + } } + /* Pseudo opcodes don't consume space */ + } - return offset; + return offset; } } // namespace art |