Index: src/mips64/assembler-mips64.h |
diff --git a/src/mips64/assembler-mips64.h b/src/mips64/assembler-mips64.h |
index cdc8a34b453b9e2e78b79349025ca3c26218cccd..3b151c0a79c674c963089d8680ea2d1c7c7dcff9 100644 |
--- a/src/mips64/assembler-mips64.h |
+++ b/src/mips64/assembler-mips64.h |
@@ -411,27 +411,46 @@ class Assembler : public AssemblerBase { |
// Note: The same Label can be used for forward and backward branches |
// but it may be bound only once. |
void bind(Label* L); // Binds an unbound label L to current code position. |
+ |
+ enum OffsetSize : int { kOffset26 = 26, kOffset21 = 21, kOffset16 = 16 }; |
+ |
// Determines if Label is bound and near enough so that branch instruction |
// can be used to reach it, instead of jump instruction. |
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(!(kArchVariant == kMips64r6)); |
+ return pc_offset() - L->pos() < kMaxBranchOffset - 4 * kInstrSize; |
+ } |
+ inline bool is_near_r6(Label* L) { |
+ DCHECK(kArchVariant == kMips64r6); |
+ 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. |
// Manages the jump elimination optimization if the second parameter is true. |
- int32_t branch_offset(Label* L, bool jump_elimination_allowed); |
- int32_t branch_offset_compact(Label* L, bool jump_elimination_allowed); |
- int32_t branch_offset21(Label* L, bool jump_elimination_allowed); |
- int32_t branch_offset21_compact(Label* L, bool jump_elimination_allowed); |
- int32_t shifted_branch_offset(Label* L, bool jump_elimination_allowed) { |
- int32_t o = branch_offset(L, jump_elimination_allowed); |
- DCHECK((o & 3) == 0); // Assert the offset is aligned. |
- return o >> 2; |
- } |
- int32_t shifted_branch_offset_compact(Label* L, |
- bool jump_elimination_allowed) { |
- int32_t o = branch_offset_compact(L, jump_elimination_allowed); |
- DCHECK((o & 3) == 0); // Assert the offset is aligned. |
- return o >> 2; |
+ int32_t branch_offset_helper(Label* L, OffsetSize bits); |
+ inline int32_t branch_offset(Label* L) { |
+ return branch_offset_helper(L, OffsetSize::kOffset16); |
+ } |
+ inline int32_t branch_offset21(Label* L) { |
+ return branch_offset_helper(L, OffsetSize::kOffset21); |
+ } |
+ inline int32_t branch_offset26(Label* L) { |
+ return branch_offset_helper(L, OffsetSize::kOffset26); |
+ } |
+ inline int32_t shifted_branch_offset(Label* L) { |
+ return branch_offset(L) >> 2; |
+ } |
+ inline int32_t shifted_branch_offset21(Label* L) { |
+ return branch_offset21(L) >> 2; |
+ } |
+ inline int32_t shifted_branch_offset26(Label* L) { |
+ return branch_offset26(L) >> 2; |
} |
uint64_t jump_address(Label* L); |
uint64_t jump_offset(Label* L); |
@@ -572,112 +591,111 @@ class Assembler : public AssemblerBase { |
// --------Branch-and-jump-instructions---------- |
// We don't use likely variant of instructions. |
void b(int16_t offset); |
- void b(Label* L) { b(branch_offset(L, false)>>2); } |
+ inline void b(Label* L) { b(shifted_branch_offset(L)); } |
void bal(int16_t offset); |
- void bal(Label* L) { bal(branch_offset(L, false)>>2); } |
+ inline void bal(Label* L) { bal(shifted_branch_offset(L)); } |
void bc(int32_t offset); |
- void bc(Label* L) { bc(branch_offset(L, false) >> 2); } |
+ inline void bc(Label* L) { bc(shifted_branch_offset26(L)); } |
void balc(int32_t offset); |
- void balc(Label* L) { balc(branch_offset(L, false) >> 2); } |
+ inline void balc(Label* L) { balc(shifted_branch_offset26(L)); } |
void beq(Register rs, Register rt, int16_t offset); |
- void beq(Register rs, Register rt, Label* L) { |
- beq(rs, rt, branch_offset(L, false) >> 2); |
+ inline void beq(Register rs, Register rt, Label* L) { |
+ beq(rs, rt, shifted_branch_offset(L)); |
} |
void bgez(Register rs, int16_t offset); |
void bgezc(Register rt, int16_t offset); |
- void bgezc(Register rt, Label* L) { |
- bgezc(rt, branch_offset_compact(L, false)>>2); |
+ inline void bgezc(Register rt, Label* L) { |
+ bgezc(rt, shifted_branch_offset(L)); |
} |
void bgeuc(Register rs, Register rt, int16_t offset); |
- void bgeuc(Register rs, Register rt, Label* L) { |
- bgeuc(rs, rt, branch_offset_compact(L, false)>>2); |
+ inline void bgeuc(Register rs, Register rt, Label* L) { |
+ bgeuc(rs, rt, shifted_branch_offset(L)); |
} |
void bgec(Register rs, Register rt, int16_t offset); |
- void bgec(Register rs, Register rt, Label* L) { |
- bgec(rs, rt, branch_offset_compact(L, false)>>2); |
+ inline void bgec(Register rs, Register rt, Label* L) { |
+ bgec(rs, rt, shifted_branch_offset(L)); |
} |
void bgezal(Register rs, int16_t offset); |
void bgezalc(Register rt, int16_t offset); |
- void bgezalc(Register rt, Label* L) { |
- bgezalc(rt, branch_offset_compact(L, false)>>2); |
+ inline void bgezalc(Register rt, Label* L) { |
+ bgezalc(rt, shifted_branch_offset(L)); |
} |
void bgezall(Register rs, int16_t offset); |
- void bgezall(Register rs, Label* L) { |
- bgezall(rs, branch_offset(L, false)>>2); |
+ inline void bgezall(Register rs, Label* L) { |
+ bgezall(rs, branch_offset(L) >> 2); |
} |
void bgtz(Register rs, int16_t offset); |
void bgtzc(Register rt, int16_t offset); |
- void bgtzc(Register rt, Label* L) { |
- bgtzc(rt, branch_offset_compact(L, false)>>2); |
+ inline void bgtzc(Register rt, Label* L) { |
+ bgtzc(rt, shifted_branch_offset(L)); |
} |
void blez(Register rs, int16_t offset); |
void blezc(Register rt, int16_t offset); |
- void blezc(Register rt, Label* L) { |
- blezc(rt, branch_offset_compact(L, false)>>2); |
+ inline void blezc(Register rt, Label* L) { |
+ blezc(rt, shifted_branch_offset(L)); |
} |
void bltz(Register rs, int16_t offset); |
void bltzc(Register rt, int16_t offset); |
- void bltzc(Register rt, Label* L) { |
- bltzc(rt, branch_offset_compact(L, false)>>2); |
+ inline void bltzc(Register rt, Label* L) { |
+ bltzc(rt, shifted_branch_offset(L)); |
} |
void bltuc(Register rs, Register rt, int16_t offset); |
- void bltuc(Register rs, Register rt, Label* L) { |
- bltuc(rs, rt, branch_offset_compact(L, false)>>2); |
+ inline void bltuc(Register rs, Register rt, Label* L) { |
+ bltuc(rs, rt, shifted_branch_offset(L)); |
} |
void bltc(Register rs, Register rt, int16_t offset); |
- void bltc(Register rs, Register rt, Label* L) { |
- bltc(rs, rt, branch_offset_compact(L, false)>>2); |
+ inline void bltc(Register rs, Register rt, Label* L) { |
+ bltc(rs, rt, shifted_branch_offset(L)); |
} |
- |
void bltzal(Register rs, int16_t offset); |
void blezalc(Register rt, int16_t offset); |
- void blezalc(Register rt, Label* L) { |
- blezalc(rt, branch_offset_compact(L, false)>>2); |
+ inline void blezalc(Register rt, Label* L) { |
+ blezalc(rt, shifted_branch_offset(L)); |
} |
void bltzalc(Register rt, int16_t offset); |
- void bltzalc(Register rt, Label* L) { |
- bltzalc(rt, branch_offset_compact(L, false)>>2); |
+ inline void bltzalc(Register rt, Label* L) { |
+ bltzalc(rt, shifted_branch_offset(L)); |
} |
void bgtzalc(Register rt, int16_t offset); |
- void bgtzalc(Register rt, Label* L) { |
- bgtzalc(rt, branch_offset_compact(L, false)>>2); |
+ inline void bgtzalc(Register rt, Label* L) { |
+ bgtzalc(rt, shifted_branch_offset(L)); |
} |
void beqzalc(Register rt, int16_t offset); |
- void beqzalc(Register rt, Label* L) { |
- beqzalc(rt, branch_offset_compact(L, false)>>2); |
+ inline void beqzalc(Register rt, Label* L) { |
+ beqzalc(rt, shifted_branch_offset(L)); |
} |
void beqc(Register rs, Register rt, int16_t offset); |
- void beqc(Register rs, Register rt, Label* L) { |
- beqc(rs, rt, branch_offset_compact(L, false)>>2); |
+ inline void beqc(Register rs, Register rt, Label* L) { |
+ beqc(rs, rt, shifted_branch_offset(L)); |
} |
void beqzc(Register rs, int32_t offset); |
- void beqzc(Register rs, Label* L) { |
- beqzc(rs, branch_offset21_compact(L, false)>>2); |
+ inline void beqzc(Register rs, Label* L) { |
+ beqzc(rs, shifted_branch_offset21(L)); |
} |
void bnezalc(Register rt, int16_t offset); |
- void bnezalc(Register rt, Label* L) { |
- bnezalc(rt, branch_offset_compact(L, false)>>2); |
+ inline void bnezalc(Register rt, Label* L) { |
+ bnezalc(rt, shifted_branch_offset(L)); |
} |
void bnec(Register rs, Register rt, int16_t offset); |
- void bnec(Register rs, Register rt, Label* L) { |
- bnec(rs, rt, branch_offset_compact(L, false)>>2); |
+ inline void bnec(Register rs, Register rt, Label* L) { |
+ bnec(rs, rt, shifted_branch_offset(L)); |
} |
void bnezc(Register rt, int32_t offset); |
- void bnezc(Register rt, Label* L) { |
- bnezc(rt, branch_offset21_compact(L, false)>>2); |
+ inline void bnezc(Register rt, Label* L) { |
+ bnezc(rt, shifted_branch_offset21(L)); |
} |
void bne(Register rs, Register rt, int16_t offset); |
- void bne(Register rs, Register rt, Label* L) { |
- bne(rs, rt, branch_offset(L, false)>>2); |
+ inline void bne(Register rs, Register rt, Label* L) { |
+ bne(rs, rt, shifted_branch_offset(L)); |
} |
void bovc(Register rs, Register rt, int16_t offset); |
- void bovc(Register rs, Register rt, Label* L) { |
- bovc(rs, rt, branch_offset_compact(L, false)>>2); |
+ inline void bovc(Register rs, Register rt, Label* L) { |
+ bovc(rs, rt, shifted_branch_offset(L)); |
} |
void bnvc(Register rs, Register rt, int16_t offset); |
- void bnvc(Register rs, Register rt, Label* L) { |
- bnvc(rs, rt, branch_offset_compact(L, false)>>2); |
+ inline void bnvc(Register rs, Register rt, Label* L) { |
+ bnvc(rs, rt, shifted_branch_offset(L)); |
} |
// Never use the int16_t b(l)cond version with a branch offset |
@@ -975,12 +993,12 @@ class Assembler : public AssemblerBase { |
void cmp_d(FPUCondition cond, FPURegister fd, FPURegister fs, FPURegister ft); |
void bc1eqz(int16_t offset, FPURegister ft); |
- void bc1eqz(Label* L, FPURegister ft) { |
- bc1eqz(branch_offset(L, false)>>2, ft); |
+ inline void bc1eqz(Label* L, FPURegister ft) { |
+ bc1eqz(shifted_branch_offset(L), ft); |
} |
void bc1nez(int16_t offset, FPURegister ft); |
- void bc1nez(Label* L, FPURegister ft) { |
- bc1nez(branch_offset(L, false)>>2, ft); |
+ inline void bc1nez(Label* L, FPURegister ft) { |
+ bc1nez(shifted_branch_offset(L), ft); |
} |
// Conditions and branches for non MIPSr6. |
@@ -990,12 +1008,12 @@ class Assembler : public AssemblerBase { |
void c_d(FPUCondition cond, FPURegister ft, FPURegister fs, uint16_t cc = 0); |
void bc1f(int16_t offset, uint16_t cc = 0); |
- void bc1f(Label* L, uint16_t cc = 0) { |
- bc1f(branch_offset(L, false)>>2, cc); |
+ inline void bc1f(Label* L, uint16_t cc = 0) { |
+ bc1f(shifted_branch_offset(L), cc); |
} |
void bc1t(int16_t offset, uint16_t cc = 0); |
- void bc1t(Label* L, uint16_t cc = 0) { |
- bc1t(branch_offset(L, false)>>2, cc); |
+ inline void bc1t(Label* L, uint16_t cc = 0) { |
+ bc1t(shifted_branch_offset(L), cc); |
} |
void fcmp(FPURegister src1, const double src2, FPUCondition cond); |
@@ -1116,8 +1134,16 @@ class Assembler : public AssemblerBase { |
// Check if an instruction is a branch of some kind. |
static bool IsBranch(Instr instr); |
+ static bool IsBc(Instr instr); |
+ static bool IsBzc(Instr instr); |
+ |
static bool IsBeq(Instr instr); |
static bool IsBne(Instr instr); |
+ static bool IsBeqzc(Instr instr); |
+ static bool IsBnezc(Instr instr); |
+ static bool IsBeqc(Instr instr); |
+ static bool IsBnec(Instr instr); |
+ |
static bool IsJump(Instr instr); |
static bool IsJ(Instr instr); |
@@ -1176,6 +1202,8 @@ class Assembler : public AssemblerBase { |
UNREACHABLE(); |
} |
+ bool IsPrevInstrCompactBranch() { return prev_instr_compact_branch_; } |
+ |
protected: |
// Relocation for a type-recording IC has the AST id added to it. This |
// member variable is a way to pass the information from the call site to |
@@ -1242,6 +1270,15 @@ class Assembler : public AssemblerBase { |
return block_buffer_growth_; |
} |
+ void EmitForbiddenSlotInstruction() { |
+ if (IsPrevInstrCompactBranch()) { |
+ nop(); |
+ ClearCompactBranchState(); |
+ } |
+ } |
+ |
+ inline void CheckTrampolinePoolQuick(int extra_instructions = 0); |
+ |
private: |
// Buffer size and constant pool distance are checked together at regular |
// intervals of kBufferCheckInterval emitted bytes. |
@@ -1281,12 +1318,15 @@ class Assembler : public AssemblerBase { |
// The bound position, before this we cannot do instruction elimination. |
int last_bound_pos_; |
+ // Readable constants for compact branch handling in emit() |
+ enum class CompactBranchType : bool { NO = false, COMPACT_BRANCH = true }; |
+ |
// Code emission. |
inline void CheckBuffer(); |
void GrowBuffer(); |
- inline void emit(Instr x); |
+ inline void emit(Instr x, |
+ CompactBranchType is_compact_branch = CompactBranchType::NO); |
inline void emit(uint64_t x); |
- inline void CheckTrampolinePoolQuick(int extra_instructions = 0); |
// Instruction generation. |
// We have 3 different kind of encoding layout on MIPS. |
@@ -1338,21 +1378,22 @@ class Assembler : public AssemblerBase { |
SecondaryField func = NULLSF); |
- void GenInstrImmediate(Opcode opcode, |
- Register rs, |
- Register rt, |
- int32_t j); |
- void GenInstrImmediate(Opcode opcode, |
- Register rs, |
- SecondaryField SF, |
- int32_t j); |
- void GenInstrImmediate(Opcode opcode, |
- Register r1, |
- FPURegister r2, |
- int32_t j); |
- void GenInstrImmediate(Opcode opcode, Register rs, int32_t j); |
- void GenInstrImmediate(Opcode opcode, int32_t offset26); |
- |
+ void GenInstrImmediate( |
+ Opcode opcode, Register rs, Register rt, int32_t j, |
+ CompactBranchType is_compact_branch = CompactBranchType::NO); |
+ void GenInstrImmediate( |
+ Opcode opcode, Register rs, SecondaryField SF, int32_t j, |
+ CompactBranchType is_compact_branch = CompactBranchType::NO); |
+ void GenInstrImmediate( |
+ Opcode opcode, Register r1, FPURegister r2, int32_t j, |
+ CompactBranchType is_compact_branch = CompactBranchType::NO); |
+ void GenInstrImmediate( |
+ Opcode opcode, Register rs, int32_t offset21, |
+ CompactBranchType is_compact_branch = CompactBranchType::NO); |
+ void GenInstrImmediate(Opcode opcode, Register rs, uint32_t offset21); |
+ void GenInstrImmediate( |
+ Opcode opcode, int32_t offset26, |
+ CompactBranchType is_compact_branch = CompactBranchType::NO); |
void GenInstrJump(Opcode opcode, |
uint32_t address); |
@@ -1426,12 +1467,17 @@ class Assembler : public AssemblerBase { |
bool trampoline_emitted_; |
static const int kTrampolineSlotsSize = 2 * kInstrSize; |
static const int kMaxBranchOffset = (1 << (18 - 1)) - 1; |
+ static const int kMaxCompactBranchOffset = (1 << (28 - 1)) - 1; |
static const int kInvalidSlotPos = -1; |
// Internal reference positions, required for unbounded internal reference |
// labels. |
std::set<int64_t> internal_reference_positions_; |
+ void EmittedCompactBranchInstruction() { prev_instr_compact_branch_ = true; } |
+ void ClearCompactBranchState() { prev_instr_compact_branch_ = false; } |
+ bool prev_instr_compact_branch_ = false; |
+ |
Trampoline trampoline_; |
bool internal_trampoline_exception_; |