Commit c766f739 authored by Miran.Karic's avatar Miran.Karic Committed by Commit bot

MIPS: Replace JR/JALR with JIC/JIALC for r6

This is the first step in process of replacing JR and JALR instructions
with JIC and JIALC for r6. Trampoline in r6 now uses JIC. Also
BranchLong and BranchAndLinkLong MacroAssembler functions now use JIC
and JIALC in r6 if branch delay slot is not used.

BUG=

Review URL: https://codereview.chromium.org/1573983002

Cr-Commit-Position: refs/heads/master@{#34236}
parent e3453a86
...@@ -160,19 +160,30 @@ Address Assembler::target_address_from_return_address(Address pc) { ...@@ -160,19 +160,30 @@ Address Assembler::target_address_from_return_address(Address pc) {
void Assembler::set_target_internal_reference_encoded_at(Address pc, void Assembler::set_target_internal_reference_encoded_at(Address pc,
Address target) { Address target) {
// Encoded internal references are lui/ori load of 32-bit abolute address. Instr instr1 = Assembler::instr_at(pc + 0 * Assembler::kInstrSize);
Instr instr_lui = Assembler::instr_at(pc + 0 * Assembler::kInstrSize); Instr instr2 = Assembler::instr_at(pc + 1 * Assembler::kInstrSize);
Instr instr_ori = Assembler::instr_at(pc + 1 * Assembler::kInstrSize); DCHECK(Assembler::IsLui(instr1));
DCHECK(Assembler::IsLui(instr_lui)); DCHECK(Assembler::IsOri(instr2) || Assembler::IsJicOrJialc(instr2));
DCHECK(Assembler::IsOri(instr_ori)); instr1 &= ~kImm16Mask;
instr_lui &= ~kImm16Mask; instr2 &= ~kImm16Mask;
instr_ori &= ~kImm16Mask;
int32_t imm = reinterpret_cast<int32_t>(target); int32_t imm = reinterpret_cast<int32_t>(target);
DCHECK((imm & 3) == 0); DCHECK((imm & 3) == 0);
if (Assembler::IsJicOrJialc(instr2)) {
// Encoded internal references are lui/jic load of 32-bit absolute address.
uint32_t lui_offset_u, jic_offset_u;
Assembler::UnpackTargetAddressUnsigned(imm, lui_offset_u, jic_offset_u);
Assembler::instr_at_put(pc + 0 * Assembler::kInstrSize,
instr1 | lui_offset_u);
Assembler::instr_at_put(pc + 1 * Assembler::kInstrSize,
instr2 | jic_offset_u);
} else {
// Encoded internal references are lui/ori load of 32-bit absolute address.
Assembler::instr_at_put(pc + 0 * Assembler::kInstrSize, Assembler::instr_at_put(pc + 0 * Assembler::kInstrSize,
instr_lui | ((imm >> kLuiShift) & kImm16Mask)); instr1 | ((imm >> kLuiShift) & kImm16Mask));
Assembler::instr_at_put(pc + 1 * Assembler::kInstrSize, Assembler::instr_at_put(pc + 1 * Assembler::kInstrSize,
instr_ori | (imm & kImm16Mask)); instr2 | (imm & kImm16Mask));
}
// Currently used only by deserializer, and all code will be flushed // Currently used only by deserializer, and all code will be flushed
// after complete deserialization, no need to flush on each reference. // after complete deserialization, no need to flush on each reference.
...@@ -230,14 +241,19 @@ Address RelocInfo::target_internal_reference() { ...@@ -230,14 +241,19 @@ Address RelocInfo::target_internal_reference() {
if (rmode_ == INTERNAL_REFERENCE) { if (rmode_ == INTERNAL_REFERENCE) {
return Memory::Address_at(pc_); return Memory::Address_at(pc_);
} else { } else {
// Encoded internal references are lui/ori load of 32-bit abolute address. // Encoded internal references are lui/ori or lui/jic load of 32-bit
// absolute address.
DCHECK(rmode_ == INTERNAL_REFERENCE_ENCODED); DCHECK(rmode_ == INTERNAL_REFERENCE_ENCODED);
Instr instr_lui = Assembler::instr_at(pc_ + 0 * Assembler::kInstrSize); Instr instr1 = Assembler::instr_at(pc_ + 0 * Assembler::kInstrSize);
Instr instr_ori = Assembler::instr_at(pc_ + 1 * Assembler::kInstrSize); Instr instr2 = Assembler::instr_at(pc_ + 1 * Assembler::kInstrSize);
DCHECK(Assembler::IsLui(instr_lui)); DCHECK(Assembler::IsLui(instr1));
DCHECK(Assembler::IsOri(instr_ori)); DCHECK(Assembler::IsOri(instr2) || Assembler::IsJicOrJialc(instr2));
int32_t imm = (instr_lui & static_cast<int32_t>(kImm16Mask)) << kLuiShift; if (Assembler::IsJicOrJialc(instr2)) {
imm |= (instr_ori & static_cast<int32_t>(kImm16Mask)); return reinterpret_cast<Address>(
Assembler::CreateTargetAddress(instr1, instr2));
}
int32_t imm = (instr1 & static_cast<int32_t>(kImm16Mask)) << kLuiShift;
imm |= (instr2 & static_cast<int32_t>(kImm16Mask));
return reinterpret_cast<Address>(imm); return reinterpret_cast<Address>(imm);
} }
} }
......
...@@ -534,6 +534,11 @@ bool Assembler::IsBnec(Instr instr) { ...@@ -534,6 +534,11 @@ bool Assembler::IsBnec(Instr instr) {
return opcode == POP30 && rs != 0 && rs < rt; // && rt != 0 return opcode == POP30 && rs != 0 && rs < rt; // && rt != 0
} }
bool Assembler::IsJicOrJialc(Instr instr) {
uint32_t opcode = GetOpcodeField(instr);
uint32_t rs = GetRsField(instr);
return (opcode == POP66 || opcode == POP76) && rs == 0;
}
bool Assembler::IsJump(Instr instr) { bool Assembler::IsJump(Instr instr) {
uint32_t opcode = GetOpcodeField(instr); uint32_t opcode = GetOpcodeField(instr);
...@@ -546,7 +551,6 @@ bool Assembler::IsJump(Instr instr) { ...@@ -546,7 +551,6 @@ bool Assembler::IsJump(Instr instr) {
((function_field == JALR) || (rd_field == 0 && (function_field == JR)))); ((function_field == JALR) || (rd_field == 0 && (function_field == JR))));
} }
bool Assembler::IsJ(Instr instr) { bool Assembler::IsJ(Instr instr) {
uint32_t opcode = GetOpcodeField(instr); uint32_t opcode = GetOpcodeField(instr);
// Checks if the instruction is a jump. // Checks if the instruction is a jump.
...@@ -697,6 +701,47 @@ static inline int32_t AddBranchOffset(int pos, Instr instr) { ...@@ -697,6 +701,47 @@ static inline int32_t AddBranchOffset(int pos, Instr instr) {
} }
} }
uint32_t Assembler::CreateTargetAddress(Instr instr_lui, Instr instr_jic) {
DCHECK(IsLui(instr_lui) && IsJicOrJialc(instr_jic));
int16_t jic_offset = GetImmediate16(instr_jic);
int16_t lui_offset = GetImmediate16(instr_lui);
if (jic_offset < 0) {
lui_offset += kImm16Mask;
}
uint32_t lui_offset_u = (static_cast<uint32_t>(lui_offset)) << kLuiShift;
uint32_t jic_offset_u = static_cast<uint32_t>(jic_offset) & kImm16Mask;
return lui_offset_u | jic_offset_u;
}
// Use just lui and jic instructions. Insert lower part of the target address in
// jic offset part. Since jic sign-extends offset and then add it with register,
// before that addition, difference between upper part of the target address and
// upper part of the sign-extended offset (0xffff or 0x0000), will be inserted
// in jic register with lui instruction.
void Assembler::UnpackTargetAddress(uint32_t address, int16_t& lui_offset,
int16_t& jic_offset) {
lui_offset = (address & kHiMask) >> kLuiShift;
jic_offset = address & kLoMask;
if (jic_offset < 0) {
lui_offset -= kImm16Mask;
}
}
void Assembler::UnpackTargetAddressUnsigned(uint32_t address,
uint32_t& lui_offset,
uint32_t& jic_offset) {
int16_t lui_offset16 = (address & kHiMask) >> kLuiShift;
int16_t jic_offset16 = address & kLoMask;
if (jic_offset16 < 0) {
lui_offset16 -= kImm16Mask;
}
lui_offset = static_cast<uint32_t>(lui_offset16) & kImm16Mask;
jic_offset = static_cast<uint32_t>(jic_offset16) & kImm16Mask;
}
int Assembler::target_at(int pos, bool is_internal) { int Assembler::target_at(int pos, bool is_internal) {
Instr instr = instr_at(pos); Instr instr = instr_at(pos);
...@@ -724,11 +769,16 @@ int Assembler::target_at(int pos, bool is_internal) { ...@@ -724,11 +769,16 @@ int Assembler::target_at(int pos, bool is_internal) {
if (IsBranch(instr)) { if (IsBranch(instr)) {
return AddBranchOffset(pos, instr); return AddBranchOffset(pos, instr);
} else { } else {
Instr instr_lui = instr_at(pos + 0 * Assembler::kInstrSize); Instr instr1 = instr_at(pos + 0 * Assembler::kInstrSize);
Instr instr_ori = instr_at(pos + 1 * Assembler::kInstrSize); Instr instr2 = instr_at(pos + 1 * Assembler::kInstrSize);
DCHECK(IsOri(instr_ori)); DCHECK(IsOri(instr2) || IsJicOrJialc(instr2));
int32_t imm = (instr_lui & static_cast<int32_t>(kImm16Mask)) << kLuiShift; int32_t imm;
imm |= (instr_ori & static_cast<int32_t>(kImm16Mask)); if (IsJicOrJialc(instr2)) {
imm = CreateTargetAddress(instr1, instr2);
} else {
imm = (instr1 & static_cast<int32_t>(kImm16Mask)) << kLuiShift;
imm |= (instr2 & static_cast<int32_t>(kImm16Mask));
}
if (imm == kEndOfJumpChain) { if (imm == kEndOfJumpChain) {
// EndOfChain sentinel is returned directly, not relative to pc or pos. // EndOfChain sentinel is returned directly, not relative to pc or pos.
...@@ -781,19 +831,26 @@ void Assembler::target_at_put(int32_t pos, int32_t target_pos, ...@@ -781,19 +831,26 @@ void Assembler::target_at_put(int32_t pos, int32_t target_pos,
instr = SetBranchOffset(pos, target_pos, instr); instr = SetBranchOffset(pos, target_pos, instr);
instr_at_put(pos, instr); instr_at_put(pos, instr);
} else { } else {
Instr instr_lui = instr_at(pos + 0 * Assembler::kInstrSize); Instr instr1 = instr_at(pos + 0 * Assembler::kInstrSize);
Instr instr_ori = instr_at(pos + 1 * Assembler::kInstrSize); Instr instr2 = instr_at(pos + 1 * Assembler::kInstrSize);
DCHECK(IsOri(instr_ori)); DCHECK(IsOri(instr2) || IsJicOrJialc(instr2));
uint32_t imm = reinterpret_cast<uint32_t>(buffer_) + target_pos; uint32_t imm = reinterpret_cast<uint32_t>(buffer_) + target_pos;
DCHECK((imm & 3) == 0); DCHECK((imm & 3) == 0);
DCHECK(IsLui(instr1) && (IsJicOrJialc(instr2) || IsOri(instr2)));
instr_lui &= ~kImm16Mask; instr1 &= ~kImm16Mask;
instr_ori &= ~kImm16Mask; instr2 &= ~kImm16Mask;
if (IsJicOrJialc(instr2)) {
uint32_t lui_offset_u, jic_offset_u;
UnpackTargetAddressUnsigned(imm, lui_offset_u, jic_offset_u);
instr_at_put(pos + 0 * Assembler::kInstrSize, instr1 | lui_offset_u);
instr_at_put(pos + 1 * Assembler::kInstrSize, instr2 | jic_offset_u);
} else {
instr_at_put(pos + 0 * Assembler::kInstrSize, instr_at_put(pos + 0 * Assembler::kInstrSize,
instr_lui | ((imm & kHiMask) >> kLuiShift)); instr1 | ((imm & kHiMask) >> kLuiShift));
instr_at_put(pos + 1 * Assembler::kInstrSize, instr_at_put(pos + 1 * Assembler::kInstrSize,
instr_ori | (imm & kImm16Mask)); instr2 | (imm & kImm16Mask));
}
} }
} }
...@@ -2790,24 +2847,36 @@ int Assembler::RelocateInternalReference(RelocInfo::Mode rmode, byte* pc, ...@@ -2790,24 +2847,36 @@ int Assembler::RelocateInternalReference(RelocInfo::Mode rmode, byte* pc,
} else { } else {
DCHECK(RelocInfo::IsInternalReferenceEncoded(rmode)); DCHECK(RelocInfo::IsInternalReferenceEncoded(rmode));
if (IsLui(instr)) { if (IsLui(instr)) {
Instr instr_lui = instr_at(pc + 0 * Assembler::kInstrSize); Instr instr1 = instr_at(pc + 0 * Assembler::kInstrSize);
Instr instr_ori = instr_at(pc + 1 * Assembler::kInstrSize); Instr instr2 = instr_at(pc + 1 * Assembler::kInstrSize);
DCHECK(IsOri(instr_ori)); DCHECK(IsOri(instr2) || IsJicOrJialc(instr2));
int32_t imm = (instr_lui & static_cast<int32_t>(kImm16Mask)) << kLuiShift; int32_t imm;
imm |= (instr_ori & static_cast<int32_t>(kImm16Mask)); if (IsJicOrJialc(instr2)) {
imm = CreateTargetAddress(instr1, instr2);
} else {
imm = (instr1 & static_cast<int32_t>(kImm16Mask)) << kLuiShift;
imm |= (instr2 & static_cast<int32_t>(kImm16Mask));
}
if (imm == kEndOfJumpChain) { if (imm == kEndOfJumpChain) {
return 0; // Number of instructions patched. return 0; // Number of instructions patched.
} }
imm += pc_delta; imm += pc_delta;
DCHECK((imm & 3) == 0); DCHECK((imm & 3) == 0);
instr1 &= ~kImm16Mask;
instr_lui &= ~kImm16Mask; instr2 &= ~kImm16Mask;
instr_ori &= ~kImm16Mask;
if (IsJicOrJialc(instr2)) {
uint32_t lui_offset_u, jic_offset_u;
Assembler::UnpackTargetAddressUnsigned(imm, lui_offset_u, jic_offset_u);
instr_at_put(pc + 0 * Assembler::kInstrSize, instr1 | lui_offset_u);
instr_at_put(pc + 1 * Assembler::kInstrSize, instr2 | jic_offset_u);
} else {
instr_at_put(pc + 0 * Assembler::kInstrSize, instr_at_put(pc + 0 * Assembler::kInstrSize,
instr_lui | ((imm >> kLuiShift) & kImm16Mask)); instr1 | ((imm >> kLuiShift) & kImm16Mask));
instr_at_put(pc + 1 * Assembler::kInstrSize, instr_at_put(pc + 1 * Assembler::kInstrSize,
instr_ori | (imm & kImm16Mask)); instr2 | (imm & kImm16Mask));
}
return 2; // Number of instructions patched. return 2; // Number of instructions patched.
} else { } else {
UNREACHABLE(); UNREACHABLE();
...@@ -2964,20 +3033,41 @@ void Assembler::CheckTrampolinePool() { ...@@ -2964,20 +3033,41 @@ void Assembler::CheckTrampolinePool() {
} }
int pool_start = pc_offset(); int pool_start = pc_offset();
if (IsMipsArchVariant(kMips32r6)) {
for (int i = 0; i < unbound_labels_count_; i++) {
uint32_t imm32;
imm32 = jump_address(&after_pool);
uint32_t lui_offset, jic_offset;
UnpackTargetAddressUnsigned(imm32, lui_offset, jic_offset);
{
BlockGrowBufferScope block_buf_growth(this);
// Buffer growth (and relocation) must be blocked for internal
// references until associated instructions are emitted and
// available to be patched.
RecordRelocInfo(RelocInfo::INTERNAL_REFERENCE_ENCODED);
lui(at, lui_offset);
jic(at, jic_offset);
}
CheckBuffer();
}
} else {
for (int i = 0; i < unbound_labels_count_; i++) { for (int i = 0; i < unbound_labels_count_; i++) {
uint32_t imm32; uint32_t imm32;
imm32 = jump_address(&after_pool); imm32 = jump_address(&after_pool);
{ BlockGrowBufferScope block_buf_growth(this); {
BlockGrowBufferScope block_buf_growth(this);
// Buffer growth (and relocation) must be blocked for internal // Buffer growth (and relocation) must be blocked for internal
// references until associated instructions are emitted and available // references until associated instructions are emitted and
// to be patched. // available to be patched.
RecordRelocInfo(RelocInfo::INTERNAL_REFERENCE_ENCODED); RecordRelocInfo(RelocInfo::INTERNAL_REFERENCE_ENCODED);
lui(at, (imm32 & kHiMask) >> kLuiShift); lui(at, (imm32 & kHiMask) >> kLuiShift);
ori(at, at, (imm32 & kImm16Mask)); ori(at, at, (imm32 & kImm16Mask));
} }
CheckBuffer();
jr(at); jr(at);
nop(); nop();
} }
}
bind(&after_pool); bind(&after_pool);
trampoline_ = Trampoline(pool_start, unbound_labels_count_); trampoline_ = Trampoline(pool_start, unbound_labels_count_);
...@@ -3000,10 +3090,10 @@ Address Assembler::target_address_at(Address pc) { ...@@ -3000,10 +3090,10 @@ Address Assembler::target_address_at(Address pc) {
Instr instr1 = instr_at(pc); Instr instr1 = instr_at(pc);
Instr instr2 = instr_at(pc + kInstrSize); Instr instr2 = instr_at(pc + kInstrSize);
// Interpret 2 instructions generated by li: lui/ori // Interpret 2 instructions generated by li: lui/ori
if ((GetOpcodeField(instr1) == LUI) && (GetOpcodeField(instr2) == ORI)) { if (IsLui(instr1) && IsOri(instr2)) {
// Assemble the 32 bit value. // Assemble the 32 bit value.
return reinterpret_cast<Address>( return reinterpret_cast<Address>((GetImmediate16(instr1) << kLuiShift) |
(GetImmediate16(instr1) << 16) | GetImmediate16(instr2)); GetImmediate16(instr2));
} }
// We should never get here, force a bad address if we do. // We should never get here, force a bad address if we do.
...@@ -3024,6 +3114,8 @@ void Assembler::QuietNaN(HeapObject* object) { ...@@ -3024,6 +3114,8 @@ void Assembler::QuietNaN(HeapObject* object) {
// On Mips, a target address is stored in a lui/ori instruction pair, each // On Mips, a target address is stored in a lui/ori instruction pair, each
// of which load 16 bits of the 32-bit address to a register. // of which load 16 bits of the 32-bit address to a register.
// Patching the address must replace both instr, and flush the i-cache. // Patching the address must replace both instr, and flush the i-cache.
// On r6, target address is stored in a lui/jic pair, and both instr have to be
// patched.
// //
// There is an optimization below, which emits a nop when the address // There is an optimization below, which emits a nop when the address
// fits in just 16 bits. This is unlikely to help, and should be benchmarked, // fits in just 16 bits. This is unlikely to help, and should be benchmarked,
...@@ -3039,15 +3131,27 @@ void Assembler::set_target_address_at(Isolate* isolate, Address pc, ...@@ -3039,15 +3131,27 @@ void Assembler::set_target_address_at(Isolate* isolate, Address pc,
#ifdef DEBUG #ifdef DEBUG
// Check we have the result from a li macro-instruction, using instr pair. // Check we have the result from a li macro-instruction, using instr pair.
Instr instr1 = instr_at(pc); Instr instr1 = instr_at(pc);
CHECK((GetOpcodeField(instr1) == LUI && GetOpcodeField(instr2) == ORI)); CHECK(IsLui(instr1) && (IsOri(instr2) || IsJicOrJialc(instr2)));
#endif #endif
if (IsJicOrJialc(instr2)) {
// Must use 2 instructions to insure patchable code => use lui and jic
uint32_t lui_offset, jic_offset;
Assembler::UnpackTargetAddressUnsigned(itarget, lui_offset, jic_offset);
*p &= ~kImm16Mask;
*(p + 1) &= ~kImm16Mask;
*p |= lui_offset;
*(p + 1) |= jic_offset;
} else {
// Must use 2 instructions to insure patchable code => just use lui and ori. // Must use 2 instructions to insure patchable code => just use lui and ori.
// lui rt, upper-16. // lui rt, upper-16.
// ori rt rt, lower-16. // ori rt rt, lower-16.
*p = LUI | rt_code | ((itarget & kHiMask) >> kLuiShift); *p = LUI | rt_code | ((itarget & kHiMask) >> kLuiShift);
*(p + 1) = ORI | rt_code | (rt_code << 5) | (itarget & kImm16Mask); *(p + 1) = ORI | rt_code | (rt_code << 5) | (itarget & kImm16Mask);
}
if (icache_flush_mode != SKIP_ICACHE_FLUSH) { if (icache_flush_mode != SKIP_ICACHE_FLUSH) {
Assembler::FlushICache(isolate, pc, 2 * sizeof(int32_t)); Assembler::FlushICache(isolate, pc, 2 * sizeof(int32_t));
......
...@@ -1082,6 +1082,7 @@ class Assembler : public AssemblerBase { ...@@ -1082,6 +1082,7 @@ class Assembler : public AssemblerBase {
static bool IsBnezc(Instr instr); static bool IsBnezc(Instr instr);
static bool IsBeqc(Instr instr); static bool IsBeqc(Instr instr);
static bool IsBnec(Instr instr); static bool IsBnec(Instr instr);
static bool IsJicOrJialc(Instr instr);
static bool IsJump(Instr instr); static bool IsJump(Instr instr);
static bool IsJ(Instr instr); static bool IsJ(Instr instr);
...@@ -1121,12 +1122,20 @@ class Assembler : public AssemblerBase { ...@@ -1121,12 +1122,20 @@ class Assembler : public AssemblerBase {
static int32_t GetBranchOffset(Instr instr); static int32_t GetBranchOffset(Instr instr);
static bool IsLw(Instr instr); static bool IsLw(Instr instr);
static int16_t GetLwOffset(Instr instr); static int16_t GetLwOffset(Instr instr);
static int16_t GetJicOrJialcOffset(Instr instr);
static int16_t GetLuiOffset(Instr instr);
static Instr SetLwOffset(Instr instr, int16_t offset); static Instr SetLwOffset(Instr instr, int16_t offset);
static bool IsSw(Instr instr); static bool IsSw(Instr instr);
static Instr SetSwOffset(Instr instr, int16_t offset); static Instr SetSwOffset(Instr instr, int16_t offset);
static bool IsAddImmediate(Instr instr); static bool IsAddImmediate(Instr instr);
static Instr SetAddImmediateOffset(Instr instr, int16_t offset); static Instr SetAddImmediateOffset(Instr instr, int16_t offset);
static uint32_t CreateTargetAddress(Instr instr_lui, Instr instr_jic);
static void UnpackTargetAddress(uint32_t address, int16_t& lui_offset,
int16_t& jic_offset);
static void UnpackTargetAddressUnsigned(uint32_t address,
uint32_t& lui_offset,
uint32_t& jic_offset);
static bool IsAndImmediate(Instr instr); static bool IsAndImmediate(Instr instr);
static bool IsEmittedConstant(Instr instr); static bool IsEmittedConstant(Instr instr);
...@@ -1213,6 +1222,8 @@ class Assembler : public AssemblerBase { ...@@ -1213,6 +1222,8 @@ class Assembler : public AssemblerBase {
inline void CheckTrampolinePoolQuick(int extra_instructions = 0); inline void CheckTrampolinePoolQuick(int extra_instructions = 0);
inline void CheckBuffer();
private: private:
inline static void set_target_internal_reference_encoded_at(Address pc, inline static void set_target_internal_reference_encoded_at(Address pc,
Address target); Address target);
...@@ -1259,7 +1270,6 @@ class Assembler : public AssemblerBase { ...@@ -1259,7 +1270,6 @@ class Assembler : public AssemblerBase {
enum class CompactBranchType : bool { NO = false, COMPACT_BRANCH = true }; enum class CompactBranchType : bool { NO = false, COMPACT_BRANCH = true };
// Code emission. // Code emission.
inline void CheckBuffer();
void GrowBuffer(); void GrowBuffer();
inline void emit(Instr x, inline void emit(Instr x,
CompactBranchType is_compact_branch = CompactBranchType::NO); CompactBranchType is_compact_branch = CompactBranchType::NO);
...@@ -1406,7 +1416,11 @@ class Assembler : public AssemblerBase { ...@@ -1406,7 +1416,11 @@ class Assembler : public AssemblerBase {
// branch instruction generation, where we use jump instructions rather // branch instruction generation, where we use jump instructions rather
// than regular branch instructions. // than regular branch instructions.
bool trampoline_emitted_; bool trampoline_emitted_;
#ifdef _MIPS_ARCH_MIPS32R6
static const int kTrampolineSlotsSize = 2 * kInstrSize;
#else
static const int kTrampolineSlotsSize = 4 * kInstrSize; static const int kTrampolineSlotsSize = 4 * kInstrSize;
#endif
static const int kMaxBranchOffset = (1 << (18 - 1)) - 1; static const int kMaxBranchOffset = (1 << (18 - 1)) - 1;
static const int kMaxCompactBranchOffset = (1 << (28 - 1)) - 1; static const int kMaxCompactBranchOffset = (1 << (28 - 1)) - 1;
static const int kInvalidSlotPos = -1; static const int kInvalidSlotPos = -1;
......
...@@ -3198,19 +3198,36 @@ void MacroAssembler::BranchLong(Label* L, BranchDelaySlot bdslot) { ...@@ -3198,19 +3198,36 @@ void MacroAssembler::BranchLong(Label* L, BranchDelaySlot bdslot) {
BlockTrampolinePoolScope block_trampoline_pool(this); BlockTrampolinePoolScope block_trampoline_pool(this);
uint32_t imm32; uint32_t imm32;
imm32 = jump_address(L); imm32 = jump_address(L);
if (IsMipsArchVariant(kMips32r6) && bdslot != USE_DELAY_SLOT) {
uint32_t lui_offset, jic_offset;
UnpackTargetAddressUnsigned(imm32, lui_offset, jic_offset);
{ {
BlockGrowBufferScope block_buf_growth(this); BlockGrowBufferScope block_buf_growth(this);
// Buffer growth (and relocation) must be blocked for internal references // Buffer growth (and relocation) must be blocked for internal
// until associated instructions are emitted and available to be patched. // references until associated instructions are emitted and
// available to be patched.
RecordRelocInfo(RelocInfo::INTERNAL_REFERENCE_ENCODED);
lui(at, lui_offset);
jic(at, jic_offset);
}
CheckBuffer();
} else {
{
BlockGrowBufferScope block_buf_growth(this);
// Buffer growth (and relocation) must be blocked for internal
// references
// until associated instructions are emitted and available to be
// patched.
RecordRelocInfo(RelocInfo::INTERNAL_REFERENCE_ENCODED); RecordRelocInfo(RelocInfo::INTERNAL_REFERENCE_ENCODED);
lui(at, (imm32 & kHiMask) >> kLuiShift); lui(at, (imm32 & kHiMask) >> kLuiShift);
ori(at, at, (imm32 & kImm16Mask)); ori(at, at, (imm32 & kImm16Mask));
} }
CheckBuffer();
jr(at); jr(at);
// Emit a nop in the branch delay slot if required. // Emit a nop in the branch delay slot if required.
if (bdslot == PROTECT) nop(); if (bdslot == PROTECT) nop();
} }
}
} }
...@@ -3222,19 +3239,35 @@ void MacroAssembler::BranchAndLinkLong(Label* L, BranchDelaySlot bdslot) { ...@@ -3222,19 +3239,35 @@ void MacroAssembler::BranchAndLinkLong(Label* L, BranchDelaySlot bdslot) {
BlockTrampolinePoolScope block_trampoline_pool(this); BlockTrampolinePoolScope block_trampoline_pool(this);
uint32_t imm32; uint32_t imm32;
imm32 = jump_address(L); imm32 = jump_address(L);
if (IsMipsArchVariant(kMips32r6) && bdslot != USE_DELAY_SLOT) {
uint32_t lui_offset, jic_offset;
UnpackTargetAddressUnsigned(imm32, lui_offset, jic_offset);
{ {
BlockGrowBufferScope block_buf_growth(this); BlockGrowBufferScope block_buf_growth(this);
// Buffer growth (and relocation) must be blocked for internal references // Buffer growth (and relocation) must be blocked for internal
// until associated instructions are emitted and available to be patched. // references until associated instructions are emitted and
// available to be patched.
RecordRelocInfo(RelocInfo::INTERNAL_REFERENCE_ENCODED);
lui(at, lui_offset);
jialc(at, jic_offset);
}
CheckBuffer();
} else {
{
BlockGrowBufferScope block_buf_growth(this);
// Buffer growth (and relocation) must be blocked for internal
// references
// until associated instructions are emitted and available to be
// patched.
RecordRelocInfo(RelocInfo::INTERNAL_REFERENCE_ENCODED); RecordRelocInfo(RelocInfo::INTERNAL_REFERENCE_ENCODED);
lui(at, (imm32 & kHiMask) >> kLuiShift); lui(at, (imm32 & kHiMask) >> kLuiShift);
ori(at, at, (imm32 & kImm16Mask)); ori(at, at, (imm32 & kImm16Mask));
} }
jalr(at); jalr(at);
// Emit a nop in the branch delay slot if required. // Emit a nop in the branch delay slot if required.
if (bdslot == PROTECT) nop(); if (bdslot == PROTECT) nop();
} }
}
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment