MIPS: Adapt long branches to use bc & balc on r6.
BUG= Review URL: https://codereview.chromium.org/1431813002 Cr-Commit-Position: refs/heads/master@{#31878}
This commit is contained in:
parent
d763c7d089
commit
bddf8c9e08
@ -849,12 +849,13 @@ void Assembler::bind_to(Label* L, int pos) {
|
||||
target_at_put(fixup_pos, pos, is_internal);
|
||||
} else {
|
||||
if (IsBranch(instr)) {
|
||||
if (dist > kMaxBranchOffset) {
|
||||
int branch_offset = BranchOffset(instr);
|
||||
if (dist > branch_offset) {
|
||||
if (trampoline_pos == kInvalidSlotPos) {
|
||||
trampoline_pos = get_trampoline_entry(fixup_pos);
|
||||
CHECK(trampoline_pos != kInvalidSlotPos);
|
||||
}
|
||||
CHECK((trampoline_pos - fixup_pos) <= kMaxBranchOffset);
|
||||
CHECK((trampoline_pos - fixup_pos) <= branch_offset);
|
||||
target_at_put(fixup_pos, trampoline_pos, false);
|
||||
fixup_pos = trampoline_pos;
|
||||
dist = pos - fixup_pos;
|
||||
@ -894,22 +895,46 @@ void Assembler::next(Label* L, bool is_internal) {
|
||||
|
||||
bool Assembler::is_near(Label* L) {
|
||||
DCHECK(L->is_bound());
|
||||
return ((pc_offset() - L->pos()) < kMaxBranchOffset - 4 * kInstrSize);
|
||||
return pc_offset() - L->pos() < kMaxBranchOffset - 4 * kInstrSize;
|
||||
}
|
||||
|
||||
|
||||
bool Assembler::is_near(Label* L, OffsetSize bits) {
|
||||
if (L == nullptr || !L->is_bound()) return true;
|
||||
return ((pc_offset() - L->pos()) <
|
||||
(1 << (bits + 2 - 1)) - 1 - 5 * kInstrSize);
|
||||
return pc_offset() - L->pos() < (1 << (bits + 2 - 1)) - 1 - 5 * kInstrSize;
|
||||
}
|
||||
|
||||
|
||||
bool Assembler::is_near_branch(Label* L) {
|
||||
DCHECK(L->is_bound());
|
||||
int max_offset =
|
||||
IsMipsArchVariant(kMips32r6) ? kMaxCompactBranchOffset : kMaxBranchOffset;
|
||||
return pc_offset() - L->pos() < max_offset - 4 * kInstrSize;
|
||||
return IsMipsArchVariant(kMips32r6) ? is_near_r6(L) : is_near_pre_r6(L);
|
||||
}
|
||||
|
||||
|
||||
int Assembler::BranchOffset(Instr instr) {
|
||||
// At pre-R6 and for other R6 branches the offset is 16 bits.
|
||||
int bits = OffsetSize::kOffset16;
|
||||
|
||||
if (IsMipsArchVariant(kMips32r6)) {
|
||||
uint32_t opcode = GetOpcodeField(instr);
|
||||
switch (opcode) {
|
||||
// Checks BC or BALC.
|
||||
case BC:
|
||||
case BALC:
|
||||
bits = OffsetSize::kOffset26;
|
||||
break;
|
||||
|
||||
// Checks BEQZC or BNEZC.
|
||||
case POP66:
|
||||
case POP76:
|
||||
if (GetRsField(instr) != 0) bits = OffsetSize::kOffset21;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return (1 << (bits + 2 - 1)) - 1;
|
||||
}
|
||||
|
||||
|
||||
@ -1398,6 +1423,7 @@ void Assembler::beqc(Register rs, Register rt, int16_t offset) {
|
||||
void Assembler::beqzc(Register rs, int32_t offset) {
|
||||
DCHECK(IsMipsArchVariant(kMips32r6));
|
||||
DCHECK(!(rs.is(zero_reg)));
|
||||
DCHECK(is_int21(offset));
|
||||
GenInstrImmediate(POP66, rs, offset, CompactBranchType::COMPACT_BRANCH);
|
||||
}
|
||||
|
||||
@ -1416,6 +1442,7 @@ void Assembler::bnec(Register rs, Register rt, int16_t offset) {
|
||||
void Assembler::bnezc(Register rs, int32_t offset) {
|
||||
DCHECK(IsMipsArchVariant(kMips32r6));
|
||||
DCHECK(!(rs.is(zero_reg)));
|
||||
DCHECK(is_int21(offset));
|
||||
GenInstrImmediate(POP76, rs, offset, CompactBranchType::COMPACT_BRANCH);
|
||||
}
|
||||
|
||||
@ -1818,7 +1845,7 @@ void Assembler::lwpc(Register rs, int32_t offset19) {
|
||||
|
||||
void Assembler::auipc(Register rs, int16_t imm16) {
|
||||
DCHECK(IsMipsArchVariant(kMips32r6));
|
||||
DCHECK(rs.is_valid() && is_int16(imm16));
|
||||
DCHECK(rs.is_valid());
|
||||
uint32_t imm21 = AUIPC << kImm16Bits | (imm16 & kImm16Mask);
|
||||
GenInstrImmediate(PCREL, rs, imm21);
|
||||
}
|
||||
@ -1826,7 +1853,7 @@ void Assembler::auipc(Register rs, int16_t imm16) {
|
||||
|
||||
void Assembler::aluipc(Register rs, int16_t imm16) {
|
||||
DCHECK(IsMipsArchVariant(kMips32r6));
|
||||
DCHECK(rs.is_valid() && is_int16(imm16));
|
||||
DCHECK(rs.is_valid());
|
||||
uint32_t imm21 = ALUIPC << kImm16Bits | (imm16 & kImm16Mask);
|
||||
GenInstrImmediate(PCREL, rs, imm21);
|
||||
}
|
||||
|
@ -416,6 +416,16 @@ class Assembler : public AssemblerBase {
|
||||
bool is_near(Label* L);
|
||||
bool is_near(Label* L, OffsetSize bits);
|
||||
bool is_near_branch(Label* L);
|
||||
inline bool is_near_pre_r6(Label* L) {
|
||||
DCHECK(!IsMipsArchVariant(kMips32r6));
|
||||
return pc_offset() - L->pos() < kMaxBranchOffset - 4 * kInstrSize;
|
||||
}
|
||||
inline bool is_near_r6(Label* L) {
|
||||
DCHECK(IsMipsArchVariant(kMips32r6));
|
||||
return pc_offset() - L->pos() < kMaxCompactBranchOffset - 4 * kInstrSize;
|
||||
}
|
||||
|
||||
int BranchOffset(Instr instr);
|
||||
|
||||
// Returns the branch offset to the given label from the current code
|
||||
// position. Links the label to the current position if it is still unbound.
|
||||
|
@ -1441,7 +1441,7 @@ void MacroAssembler::BranchFCommon(SecondaryField sizeField, Label* target,
|
||||
c(UN, D, cmp1, cmp2);
|
||||
bc1f(&skip);
|
||||
nop();
|
||||
Jr(nan, bd);
|
||||
BranchLong(nan, bd);
|
||||
bind(&skip);
|
||||
} else {
|
||||
c(UN, D, cmp1, cmp2);
|
||||
@ -1459,7 +1459,7 @@ void MacroAssembler::BranchFCommon(SecondaryField sizeField, Label* target,
|
||||
cmp(UN, L, kDoubleCompareReg, cmp1, cmp2);
|
||||
bc1eqz(&skip, kDoubleCompareReg);
|
||||
nop();
|
||||
Jr(nan, bd);
|
||||
BranchLong(nan, bd);
|
||||
bind(&skip);
|
||||
} else {
|
||||
cmp(UN, L, kDoubleCompareReg, cmp1, cmp2);
|
||||
@ -1478,7 +1478,7 @@ void MacroAssembler::BranchFCommon(SecondaryField sizeField, Label* target,
|
||||
Label skip;
|
||||
Condition neg_cond = NegateFpuCondition(cond);
|
||||
BranchShortF(sizeField, &skip, neg_cond, cmp1, cmp2, bd);
|
||||
Jr(target, bd);
|
||||
BranchLong(target, bd);
|
||||
bind(&skip);
|
||||
} else {
|
||||
BranchShortF(sizeField, target, cond, cmp1, cmp2, bd);
|
||||
@ -1957,11 +1957,11 @@ void MacroAssembler::Branch(Label* L, BranchDelaySlot bdslot) {
|
||||
if (is_near_branch(L)) {
|
||||
BranchShort(L, bdslot);
|
||||
} else {
|
||||
Jr(L, bdslot);
|
||||
BranchLong(L, bdslot);
|
||||
}
|
||||
} else {
|
||||
if (is_trampoline_emitted()) {
|
||||
Jr(L, bdslot);
|
||||
BranchLong(L, bdslot);
|
||||
} else {
|
||||
BranchShort(L, bdslot);
|
||||
}
|
||||
@ -1978,10 +1978,10 @@ void MacroAssembler::Branch(Label* L, Condition cond, Register rs,
|
||||
Label skip;
|
||||
Condition neg_cond = NegateCondition(cond);
|
||||
BranchShort(&skip, neg_cond, rs, rt);
|
||||
Jr(L, bdslot);
|
||||
BranchLong(L, bdslot);
|
||||
bind(&skip);
|
||||
} else {
|
||||
Jr(L, bdslot);
|
||||
BranchLong(L, bdslot);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@ -1990,10 +1990,10 @@ void MacroAssembler::Branch(Label* L, Condition cond, Register rs,
|
||||
Label skip;
|
||||
Condition neg_cond = NegateCondition(cond);
|
||||
BranchShort(&skip, neg_cond, rs, rt);
|
||||
Jr(L, bdslot);
|
||||
BranchLong(L, bdslot);
|
||||
bind(&skip);
|
||||
} else {
|
||||
Jr(L, bdslot);
|
||||
BranchLong(L, bdslot);
|
||||
}
|
||||
} else {
|
||||
BranchShort(L, cond, rs, rt, bdslot);
|
||||
@ -2014,6 +2014,7 @@ void MacroAssembler::Branch(Label* L,
|
||||
|
||||
void MacroAssembler::BranchShortHelper(int16_t offset, Label* L,
|
||||
BranchDelaySlot bdslot) {
|
||||
DCHECK(L == nullptr || offset == 0);
|
||||
offset = GetOffset(offset, L, OffsetSize::kOffset16);
|
||||
b(offset);
|
||||
|
||||
@ -2024,6 +2025,7 @@ void MacroAssembler::BranchShortHelper(int16_t offset, Label* L,
|
||||
|
||||
|
||||
void MacroAssembler::BranchShortHelperR6(int32_t offset, Label* L) {
|
||||
DCHECK(L == nullptr || offset == 0);
|
||||
offset = GetOffset(offset, L, OffsetSize::kOffset26);
|
||||
bc(offset);
|
||||
}
|
||||
@ -2085,6 +2087,7 @@ Register MacroAssembler::GetRtAsRegisterHelper(const Operand& rt,
|
||||
bool MacroAssembler::BranchShortHelperR6(int32_t offset, Label* L,
|
||||
Condition cond, Register rs,
|
||||
const Operand& rt) {
|
||||
DCHECK(L == nullptr || offset == 0);
|
||||
Register scratch = rs.is(at) ? t8 : at;
|
||||
OffsetSize bits = OffsetSize::kOffset16;
|
||||
|
||||
@ -2362,6 +2365,7 @@ bool MacroAssembler::BranchShortHelperR6(int32_t offset, Label* L,
|
||||
bool MacroAssembler::BranchShortHelper(int16_t offset, Label* L, Condition cond,
|
||||
Register rs, const Operand& rt,
|
||||
BranchDelaySlot bdslot) {
|
||||
DCHECK(L == nullptr || offset == 0);
|
||||
if (!is_near(L, OffsetSize::kOffset16)) return false;
|
||||
|
||||
Register scratch = at;
|
||||
@ -2548,11 +2552,11 @@ void MacroAssembler::BranchAndLink(Label* L, BranchDelaySlot bdslot) {
|
||||
if (is_near_branch(L)) {
|
||||
BranchAndLinkShort(L, bdslot);
|
||||
} else {
|
||||
Jalr(L, bdslot);
|
||||
BranchAndLinkLong(L, bdslot);
|
||||
}
|
||||
} else {
|
||||
if (is_trampoline_emitted()) {
|
||||
Jalr(L, bdslot);
|
||||
BranchAndLinkLong(L, bdslot);
|
||||
} else {
|
||||
BranchAndLinkShort(L, bdslot);
|
||||
}
|
||||
@ -2568,7 +2572,7 @@ void MacroAssembler::BranchAndLink(Label* L, Condition cond, Register rs,
|
||||
Label skip;
|
||||
Condition neg_cond = NegateCondition(cond);
|
||||
BranchShort(&skip, neg_cond, rs, rt);
|
||||
Jalr(L, bdslot);
|
||||
BranchAndLinkLong(L, bdslot);
|
||||
bind(&skip);
|
||||
}
|
||||
} else {
|
||||
@ -2576,7 +2580,7 @@ void MacroAssembler::BranchAndLink(Label* L, Condition cond, Register rs,
|
||||
Label skip;
|
||||
Condition neg_cond = NegateCondition(cond);
|
||||
BranchShort(&skip, neg_cond, rs, rt);
|
||||
Jalr(L, bdslot);
|
||||
BranchAndLinkLong(L, bdslot);
|
||||
bind(&skip);
|
||||
} else {
|
||||
BranchAndLinkShortCheck(0, L, cond, rs, rt, bdslot);
|
||||
@ -2587,6 +2591,7 @@ void MacroAssembler::BranchAndLink(Label* L, Condition cond, Register rs,
|
||||
|
||||
void MacroAssembler::BranchAndLinkShortHelper(int16_t offset, Label* L,
|
||||
BranchDelaySlot bdslot) {
|
||||
DCHECK(L == nullptr || offset == 0);
|
||||
offset = GetOffset(offset, L, OffsetSize::kOffset16);
|
||||
bal(offset);
|
||||
|
||||
@ -2597,6 +2602,7 @@ void MacroAssembler::BranchAndLinkShortHelper(int16_t offset, Label* L,
|
||||
|
||||
|
||||
void MacroAssembler::BranchAndLinkShortHelperR6(int32_t offset, Label* L) {
|
||||
DCHECK(L == nullptr || offset == 0);
|
||||
offset = GetOffset(offset, L, OffsetSize::kOffset26);
|
||||
balc(offset);
|
||||
}
|
||||
@ -2626,6 +2632,7 @@ void MacroAssembler::BranchAndLinkShort(Label* L, BranchDelaySlot bdslot) {
|
||||
bool MacroAssembler::BranchAndLinkShortHelperR6(int32_t offset, Label* L,
|
||||
Condition cond, Register rs,
|
||||
const Operand& rt) {
|
||||
DCHECK(L == nullptr || offset == 0);
|
||||
Register scratch = rs.is(at) ? t8 : at;
|
||||
OffsetSize bits = OffsetSize::kOffset16;
|
||||
|
||||
@ -2783,6 +2790,7 @@ bool MacroAssembler::BranchAndLinkShortHelper(int16_t offset, Label* L,
|
||||
Condition cond, Register rs,
|
||||
const Operand& rt,
|
||||
BranchDelaySlot bdslot) {
|
||||
DCHECK(L == nullptr || offset == 0);
|
||||
if (!is_near(L, OffsetSize::kOffset16)) return false;
|
||||
|
||||
Register scratch = t8;
|
||||
@ -3081,43 +3089,51 @@ void MacroAssembler::Ret(Condition cond,
|
||||
}
|
||||
|
||||
|
||||
void MacroAssembler::Jr(Label* L, BranchDelaySlot bdslot) {
|
||||
BlockTrampolinePoolScope block_trampoline_pool(this);
|
||||
void MacroAssembler::BranchLong(Label* L, BranchDelaySlot bdslot) {
|
||||
if (IsMipsArchVariant(kMips32r6) && bdslot == PROTECT &&
|
||||
(!L->is_bound() || is_near_r6(L))) {
|
||||
BranchShortHelperR6(0, L);
|
||||
} else {
|
||||
BlockTrampolinePoolScope block_trampoline_pool(this);
|
||||
uint32_t imm32;
|
||||
imm32 = jump_address(L);
|
||||
{
|
||||
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, (imm32 & kHiMask) >> kLuiShift);
|
||||
ori(at, at, (imm32 & kImm16Mask));
|
||||
}
|
||||
jr(at);
|
||||
|
||||
uint32_t imm32;
|
||||
imm32 = jump_address(L);
|
||||
{ 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, (imm32 & kHiMask) >> kLuiShift);
|
||||
ori(at, at, (imm32 & kImm16Mask));
|
||||
// Emit a nop in the branch delay slot if required.
|
||||
if (bdslot == PROTECT) nop();
|
||||
}
|
||||
jr(at);
|
||||
|
||||
// Emit a nop in the branch delay slot if required.
|
||||
if (bdslot == PROTECT)
|
||||
nop();
|
||||
}
|
||||
|
||||
|
||||
void MacroAssembler::Jalr(Label* L, BranchDelaySlot bdslot) {
|
||||
BlockTrampolinePoolScope block_trampoline_pool(this);
|
||||
void MacroAssembler::BranchAndLinkLong(Label* L, BranchDelaySlot bdslot) {
|
||||
if (IsMipsArchVariant(kMips32r6) && bdslot == PROTECT &&
|
||||
(!L->is_bound() || is_near_r6(L))) {
|
||||
BranchAndLinkShortHelperR6(0, L);
|
||||
} else {
|
||||
BlockTrampolinePoolScope block_trampoline_pool(this);
|
||||
uint32_t imm32;
|
||||
imm32 = jump_address(L);
|
||||
{
|
||||
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, (imm32 & kHiMask) >> kLuiShift);
|
||||
ori(at, at, (imm32 & kImm16Mask));
|
||||
}
|
||||
jalr(at);
|
||||
|
||||
uint32_t imm32;
|
||||
imm32 = jump_address(L);
|
||||
{ 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, (imm32 & kHiMask) >> kLuiShift);
|
||||
ori(at, at, (imm32 & kImm16Mask));
|
||||
// Emit a nop in the branch delay slot if required.
|
||||
if (bdslot == PROTECT) nop();
|
||||
}
|
||||
jalr(at);
|
||||
|
||||
// Emit a nop in the branch delay slot if required.
|
||||
if (bdslot == PROTECT)
|
||||
nop();
|
||||
}
|
||||
|
||||
|
||||
|
@ -1659,8 +1659,8 @@ const Operand& rt = Operand(zero_reg), BranchDelaySlot bd = PROTECT
|
||||
bool BranchAndLinkShortCheck(int32_t offset, Label* L, Condition cond,
|
||||
Register rs, const Operand& rt,
|
||||
BranchDelaySlot bdslot);
|
||||
void Jr(Label* L, BranchDelaySlot bdslot);
|
||||
void Jalr(Label* L, BranchDelaySlot bdslot);
|
||||
void BranchLong(Label* L, BranchDelaySlot bdslot);
|
||||
void BranchAndLinkLong(Label* L, BranchDelaySlot bdslot);
|
||||
|
||||
// Common implementation of BranchF functions for the different formats.
|
||||
void BranchFCommon(SecondaryField sizeField, Label* target, Label* nan,
|
||||
|
Loading…
Reference in New Issue
Block a user