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:
balazs.kilvady 2015-11-09 03:25:01 -08:00 committed by Commit bot
parent d763c7d089
commit bddf8c9e08
4 changed files with 108 additions and 55 deletions

View File

@ -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);
}

View File

@ -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.

View File

@ -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();
}

View File

@ -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,