Index: src/mips64/assembler-mips64.cc |
diff --git a/src/mips64/assembler-mips64.cc b/src/mips64/assembler-mips64.cc |
index 2bec3f064a3eeb99838d81cbd0c52fb72eedf5d7..75c94459753661348ad10d64cbd5e37f9871ad3f 100644 |
--- a/src/mips64/assembler-mips64.cc |
+++ b/src/mips64/assembler-mips64.cc |
@@ -637,7 +637,7 @@ int Assembler::target_at(int pos, bool is_internal) { |
} |
} |
// Check we have a branch or jump instruction. |
- DCHECK(IsBranch(instr) || IsLui(instr)); |
+ DCHECK(IsBranch(instr) || IsJ(instr) || IsJal(instr) || IsLui(instr)); |
// Do NOT change this to <<2. We rely on arithmetic shifts here, assuming |
// the compiler uses arithmetic shifts for signed integers. |
if (IsBranch(instr)) { |
@@ -673,8 +673,18 @@ int Assembler::target_at(int pos, bool is_internal) { |
return pos - delta; |
} |
} else { |
- UNREACHABLE(); |
- return 0; |
+ DCHECK(IsJ(instr) || IsJal(instr)); |
+ int32_t imm28 = (instr & static_cast<int32_t>(kImm26Mask)) << 2; |
+ if (imm28 == kEndOfJumpChain) { |
+ // EndOfChain sentinel is returned directly, not relative to pc or pos. |
+ return kEndOfChain; |
+ } else { |
+ uint64_t instr_address = reinterpret_cast<int64_t>(buffer_ + pos); |
+ instr_address &= kImm28Mask; |
+ int delta = static_cast<int>(instr_address - imm28); |
+ DCHECK(pos > delta); |
+ return pos - delta; |
+ } |
} |
} |
@@ -694,7 +704,7 @@ void Assembler::target_at_put(int pos, int target_pos, bool is_internal) { |
return; |
} |
- DCHECK(IsBranch(instr) || IsLui(instr)); |
+ DCHECK(IsBranch(instr) || IsJ(instr) || IsJal(instr) || IsLui(instr)); |
if (IsBranch(instr)) { |
int32_t imm18 = target_pos - (pos + kBranchPCOffset); |
DCHECK((imm18 & 3) == 0); |
@@ -725,7 +735,16 @@ void Assembler::target_at_put(int pos, int target_pos, bool is_internal) { |
instr_at_put(pos + 3 * Assembler::kInstrSize, |
instr_ori2 | (imm & kImm16Mask)); |
} else { |
- UNREACHABLE(); |
+ DCHECK(IsJ(instr) || IsJal(instr)); |
+ uint64_t imm28 = reinterpret_cast<uint64_t>(buffer_) + target_pos; |
+ imm28 &= kImm28Mask; |
+ DCHECK((imm28 & 3) == 0); |
+ |
+ instr &= ~kImm26Mask; |
+ uint32_t imm26 = imm28 >> 2; |
+ DCHECK(is_uint26(imm26)); |
+ |
+ instr_at_put(pos, instr | (imm26 & kImm26Mask)); |
} |
} |
@@ -787,7 +806,8 @@ void Assembler::bind_to(Label* L, int pos) { |
} |
target_at_put(fixup_pos, pos, false); |
} else { |
- DCHECK(IsJ(instr) || IsLui(instr) || IsEmittedConstant(instr)); |
+ DCHECK(IsJ(instr) || IsJal(instr) || IsLui(instr) || |
+ IsEmittedConstant(instr)); |
target_at_put(fixup_pos, pos, false); |
} |
} |
@@ -984,7 +1004,6 @@ uint64_t Assembler::jump_address(Label* L) { |
return kEndOfJumpChain; |
} |
} |
- |
uint64_t imm = reinterpret_cast<uint64_t>(buffer_) + target_pos; |
DCHECK((imm & 3) == 0); |
@@ -1359,12 +1378,14 @@ void Assembler::bnezc(Register rs, int32_t offset) { |
void Assembler::j(int64_t target) { |
#if DEBUG |
// Get pc of delay slot. |
- uint64_t ipc = reinterpret_cast<uint64_t>(pc_ + 1 * kInstrSize); |
- bool in_range = (ipc ^ static_cast<uint64_t>(target) >> |
- (kImm26Bits + kImmFieldShift)) == 0; |
- DCHECK(in_range && ((target & 3) == 0)); |
+ if (target != kEndOfJumpChain) { |
+ uint64_t ipc = reinterpret_cast<uint64_t>(pc_ + 1 * kInstrSize); |
+ bool in_range = ((ipc ^ static_cast<uint64_t>(target)) >> |
+ (kImm26Bits + kImmFieldShift)) == 0; |
+ DCHECK(in_range && ((target & 3) == 0)); |
+ } |
#endif |
- GenInstrJump(J, target >> 2); |
+ GenInstrJump(J, (target >> 2) & kImm26Mask); |
} |
@@ -1385,13 +1406,15 @@ void Assembler::jr(Register rs) { |
void Assembler::jal(int64_t target) { |
#ifdef DEBUG |
// Get pc of delay slot. |
- uint64_t ipc = reinterpret_cast<uint64_t>(pc_ + 1 * kInstrSize); |
- bool in_range = (ipc ^ static_cast<uint64_t>(target) >> |
- (kImm26Bits + kImmFieldShift)) == 0; |
- DCHECK(in_range && ((target & 3) == 0)); |
+ if (target != kEndOfJumpChain) { |
+ uint64_t ipc = reinterpret_cast<uint64_t>(pc_ + 1 * kInstrSize); |
+ bool in_range = ((ipc ^ static_cast<uint64_t>(target)) >> |
+ (kImm26Bits + kImmFieldShift)) == 0; |
+ DCHECK(in_range && ((target & 3) == 0)); |
+ } |
#endif |
positions_recorder()->WriteRecordedPositions(); |
- GenInstrJump(JAL, target >> 2); |
+ GenInstrJump(JAL, (target >> 2) & kImm26Mask); |
} |
@@ -2764,6 +2787,7 @@ int Assembler::RelocateInternalReference(RelocInfo::Mode rmode, byte* pc, |
} |
Instr instr = instr_at(pc); |
DCHECK(RelocInfo::IsInternalReferenceEncoded(rmode)); |
+ DCHECK(IsJ(instr) || IsLui(instr) || IsJal(instr)); |
if (IsLui(instr)) { |
Instr instr_lui = instr_at(pc + 0 * Assembler::kInstrSize); |
Instr instr_ori = instr_at(pc + 1 * Assembler::kInstrSize); |
@@ -2795,8 +2819,21 @@ int Assembler::RelocateInternalReference(RelocInfo::Mode rmode, byte* pc, |
instr_ori2 | (imm & kImm16Mask)); |
return 4; // Number of instructions patched. |
} else { |
- UNREACHABLE(); |
- return 0; // Number of instructions patched. |
+ uint32_t imm28 = (instr & static_cast<int32_t>(kImm26Mask)) << 2; |
+ if (static_cast<int32_t>(imm28) == kEndOfJumpChain) { |
+ return 0; // Number of instructions patched. |
+ } |
+ |
+ imm28 += pc_delta; |
+ imm28 &= kImm28Mask; |
+ DCHECK((imm28 & 3) == 0); |
+ |
+ instr &= ~kImm26Mask; |
+ uint32_t imm26 = imm28 >> 2; |
+ DCHECK(is_uint26(imm26)); |
+ |
+ instr_at_put(pc, instr | (imm26 & kImm26Mask)); |
+ return 1; // Number of instructions patched. |
} |
} |
@@ -2958,14 +2995,8 @@ void Assembler::CheckTrampolinePool() { |
// references until associated instructions are emitted and available |
// to be patched. |
RecordRelocInfo(RelocInfo::INTERNAL_REFERENCE_ENCODED); |
- // TODO(plind): Verify this, presume I cannot use macro-assembler |
- // here. |
- lui(at, (imm64 >> 32) & kImm16Mask); |
- ori(at, at, (imm64 >> 16) & kImm16Mask); |
- dsll(at, at, 16); |
- ori(at, at, imm64 & kImm16Mask); |
+ j(imm64); |
} |
- jr(at); |
nop(); |
} |
bind(&after_pool); |