Commit 3def7348 authored by Ivica Bogosavljevic's avatar Ivica Bogosavljevic Committed by Commit Bot

MIPS: Implement PC relative trampolines

Change-Id: Iecbc7b5b4f8cbea99cb83982d0b5f0db78dfa89e
Reviewed-on: https://chromium-review.googlesource.com/1128964
Commit-Queue: Ivica Bogosavljevic <ivica.bogosavljevic@mips.com>
Reviewed-by: 's avatarMiran Karić <miran.karic@mips.com>
Cr-Commit-Position: refs/heads/master@{#54429}
parent 71dddd14
......@@ -311,13 +311,6 @@ void Assembler::CheckBuffer() {
}
void Assembler::CheckTrampolinePoolQuick(int extra_instructions) {
if (pc_offset() >= next_buffer_check_ - extra_instructions * kInstrSize) {
CheckTrampolinePool();
}
}
void Assembler::CheckForEmitInForbiddenSlot() {
if (!is_buffer_growth_blocked()) {
CheckBuffer();
......
......@@ -664,6 +664,19 @@ bool Assembler::IsOri(Instr instr) {
return opcode == ORI;
}
bool Assembler::IsMov(Instr instr, Register rd, Register rs) {
uint32_t opcode = GetOpcodeField(instr);
uint32_t rd_field = GetRd(instr);
uint32_t rs_field = GetRs(instr);
uint32_t rt_field = GetRt(instr);
uint32_t rd_reg = static_cast<uint32_t>(rd.code());
uint32_t rs_reg = static_cast<uint32_t>(rs.code());
uint32_t function_field = GetFunctionField(instr);
// Checks if the instruction is a OR with zero_reg argument (aka MOV).
bool res = opcode == SPECIAL && function_field == OR && rd_field == rd_reg &&
rs_field == rs_reg && rt_field == 0;
return res;
}
bool Assembler::IsNop(Instr instr, unsigned int type) {
// See Assembler::nop(type).
......@@ -898,10 +911,38 @@ void Assembler::target_at_put(int32_t pos, int32_t target_pos,
return;
}
DCHECK(IsBranch(instr) || IsLui(instr));
DCHECK(IsBranch(instr) || IsLui(instr) || IsMov(instr, t8, ra));
if (IsBranch(instr)) {
instr = SetBranchOffset(pos, target_pos, instr);
instr_at_put(pos, instr);
} else if (IsMov(instr, t8, ra)) {
Instr instr_lui = instr_at(pos + 4 * Assembler::kInstrSize);
Instr instr_ori = instr_at(pos + 5 * Assembler::kInstrSize);
DCHECK(IsLui(instr_lui));
DCHECK(IsOri(instr_ori));
int32_t imm_short = target_pos - (pos + Assembler::kBranchPCOffset);
if (is_int16(imm_short)) {
// Optimize by converting to regular branch with 16-bit
// offset
Instr instr_b = BEQ;
instr_b = SetBranchOffset(pos, target_pos, instr_b);
instr_at_put(pos, instr_b);
instr_at_put(pos + 1 * Assembler::kInstrSize, 0);
} else {
int32_t imm = target_pos - (pos + Assembler::kLongBranchPCOffset);
DCHECK_EQ(imm & 3, 0);
instr_lui &= ~kImm16Mask;
instr_ori &= ~kImm16Mask;
instr_at_put(pos + 4 * Assembler::kInstrSize,
instr_lui | ((imm >> 16) & kImm16Mask));
instr_at_put(pos + 5 * Assembler::kInstrSize,
instr_ori | (imm & kImm16Mask));
}
} else {
Instr instr1 = instr_at(pos + 0 * Assembler::kInstrSize);
Instr instr2 = instr_at(pos + 1 * Assembler::kInstrSize);
......@@ -3785,49 +3826,37 @@ void Assembler::CheckTrampolinePool() {
bc(&after_pool);
} else {
b(&after_pool);
nop();
}
nop();
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);
UseScratchRegisterScope temps(this);
Register scratch = temps.hasAvailable() ? temps.Acquire() : t8;
lui(scratch, lui_offset);
jic(scratch, jic_offset);
}
CheckBuffer();
}
} else {
for (int i = 0; i < unbound_labels_count_; i++) {
uint32_t imm32;
imm32 = jump_address(&after_pool);
UseScratchRegisterScope temps(this);
Register scratch = temps.hasAvailable() ? temps.Acquire() : t8;
{
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(scratch, (imm32 & kHiMask) >> kLuiShift);
ori(scratch, scratch, (imm32 & kImm16Mask));
for (int i = 0; i < unbound_labels_count_; i++) {
{
// printf("Generate trampoline %d\n", i);
// Buffer growth (and relocation) must be blocked for internal
// references until associated instructions are emitted and
// available to be patched.
if (IsMipsArchVariant(kMips32r6)) {
bc(&after_pool);
nop();
} else {
Label find_pc;
or_(t8, ra, zero_reg);
bal(&find_pc);
or_(t9, ra, zero_reg);
bind(&find_pc);
or_(ra, t8, zero_reg);
lui(t8, 0);
ori(t8, t8, 0);
addu(t9, t9, t8);
// Instruction jr will take or_ from the next trampoline.
// in its branch delay slot. This is the expected behavior
// in order to decrease size of trampoline pool.
jr(t9);
}
CheckBuffer();
jr(scratch);
nop();
}
}
nop();
bind(&after_pool);
trampoline_ = Trampoline(pool_start, unbound_labels_count_);
......
......@@ -612,6 +612,11 @@ class Assembler : public AssemblerBase {
// Difference between address of current opcode and target address offset.
static constexpr int kBranchPCOffset = 4;
// Difference between address of current opcode and target address offset,
// when we are generatinga sequence of instructions for long relative PC
// branches
static constexpr int kLongBranchPCOffset = 12;
// Here we are patching the address in the LUI/ORI instruction pair.
// These values are used in the serialization process and must be zero for
// MIPS platform, as Code, Embedded Object or External-reference pointers
......@@ -644,11 +649,8 @@ class Assembler : public AssemblerBase {
// Max offset for compact branch instructions with 26-bit offset field
static constexpr int kMaxCompactBranchOffset = (1 << (28 - 1)) - 1;
#ifdef _MIPS_ARCH_MIPS32R6
static constexpr int kTrampolineSlotsSize = 2 * kInstrSize;
#else
static constexpr int kTrampolineSlotsSize = 4 * kInstrSize;
#endif
static constexpr int kTrampolineSlotsSize =
IsMipsArchVariant(kMips32r6) ? 2 * kInstrSize : 8 * kInstrSize;
RegList* GetScratchRegisterList() { return &scratch_register_list_; }
......@@ -1765,6 +1767,7 @@ class Assembler : public AssemblerBase {
static bool IsBeqc(Instr instr);
static bool IsBnec(Instr instr);
static bool IsJicOrJialc(Instr instr);
static bool IsMov(Instr instr, Register rd, Register rs);
static bool IsJump(Instr instr);
static bool IsJ(Instr instr);
......@@ -1881,6 +1884,9 @@ class Assembler : public AssemblerBase {
void EndBlockTrampolinePool() {
trampoline_pool_blocked_nesting_--;
if (trampoline_pool_blocked_nesting_ == 0) {
CheckTrampolinePoolQuick(1);
}
}
bool is_trampoline_pool_blocked() const {
......@@ -1916,7 +1922,11 @@ class Assembler : public AssemblerBase {
}
}
inline void CheckTrampolinePoolQuick(int extra_instructions = 0);
inline void CheckTrampolinePoolQuick(int extra_instructions = 0) {
if (pc_offset() >= next_buffer_check_ - extra_instructions * kInstrSize) {
CheckTrampolinePool();
}
}
inline void CheckBuffer();
......
......@@ -212,6 +212,7 @@ void MacroAssembler::RecordWriteField(Register object, int offset,
Addu(dst, object, Operand(offset - kHeapObjectTag));
if (emit_debug_code()) {
BlockTrampolinePoolScope block_trampoline_pool(this);
Label ok;
And(t8, dst, Operand(kPointerSize - 1));
Branch(&ok, eq, t8, Operand(zero_reg));
......@@ -799,6 +800,7 @@ void TurboAssembler::Slt(Register rd, Register rs, const Operand& rt) {
slti(rd, rs, rt.immediate());
} else {
// li handles the relocation.
BlockTrampolinePoolScope block_trampoline_pool(this);
UseScratchRegisterScope temps(this);
Register scratch = rd == at ? t8 : temps.Acquire();
DCHECK(rs != scratch);
......@@ -822,6 +824,7 @@ void TurboAssembler::Sltu(Register rd, Register rs, const Operand& rt) {
sltiu(rd, rs, static_cast<uint16_t>(rt.immediate()));
} else {
// li handles the relocation.
BlockTrampolinePoolScope block_trampoline_pool(this);
UseScratchRegisterScope temps(this);
Register scratch = rd == at ? t8 : temps.Acquire();
DCHECK(rs != scratch);
......@@ -836,6 +839,7 @@ void TurboAssembler::Sle(Register rd, Register rs, const Operand& rt) {
slt(rd, rt.rm(), rs);
} else {
// li handles the relocation.
BlockTrampolinePoolScope block_trampoline_pool(this);
UseScratchRegisterScope temps(this);
Register scratch = temps.hasAvailable() ? temps.Acquire() : t8;
DCHECK(rs != scratch);
......@@ -850,6 +854,7 @@ void TurboAssembler::Sleu(Register rd, Register rs, const Operand& rt) {
sltu(rd, rt.rm(), rs);
} else {
// li handles the relocation.
BlockTrampolinePoolScope block_trampoline_pool(this);
UseScratchRegisterScope temps(this);
Register scratch = temps.hasAvailable() ? temps.Acquire() : t8;
DCHECK(rs != scratch);
......@@ -874,6 +879,7 @@ void TurboAssembler::Sgt(Register rd, Register rs, const Operand& rt) {
slt(rd, rt.rm(), rs);
} else {
// li handles the relocation.
BlockTrampolinePoolScope block_trampoline_pool(this);
UseScratchRegisterScope temps(this);
Register scratch = temps.hasAvailable() ? temps.Acquire() : t8;
DCHECK(rs != scratch);
......@@ -887,6 +893,7 @@ void TurboAssembler::Sgtu(Register rd, Register rs, const Operand& rt) {
sltu(rd, rt.rm(), rs);
} else {
// li handles the relocation.
BlockTrampolinePoolScope block_trampoline_pool(this);
UseScratchRegisterScope temps(this);
Register scratch = temps.hasAvailable() ? temps.Acquire() : t8;
DCHECK(rs != scratch);
......@@ -904,6 +911,7 @@ void TurboAssembler::Ror(Register rd, Register rs, const Operand& rt) {
}
} else {
if (rt.is_reg()) {
BlockTrampolinePoolScope block_trampoline_pool(this);
UseScratchRegisterScope temps(this);
Register scratch = temps.hasAvailable() ? temps.Acquire() : t8;
subu(scratch, zero_reg, rt.rm());
......@@ -995,6 +1003,7 @@ void TurboAssembler::ByteSwapSigned(Register dest, Register src,
sll(dest, dest, 16);
sra(dest, dest, 16);
} else {
BlockTrampolinePoolScope block_trampoline_pool(this);
Register tmp = at;
Register tmp2 = t8;
DCHECK(dest != tmp && dest != tmp2);
......@@ -1275,6 +1284,7 @@ void TurboAssembler::Sdc1(FPURegister fd, const MemOperand& src) {
swc1(nextfpreg,
MemOperand(tmp.rm(), tmp.offset() + Register::kExponentOffset));
} else {
BlockTrampolinePoolScope block_trampoline_pool(this);
DCHECK(IsFp64Mode() || IsFpxxMode());
// Currently we support FPXX and FP64 on Mips32r2 and Mips32r6
DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
......@@ -1653,6 +1663,7 @@ void TurboAssembler::Ins(Register rt, Register rs, uint16_t pos,
ins_(rt, rs, pos, size);
} else {
DCHECK(rt != t8 && rs != t8);
BlockTrampolinePoolScope block_trampoline_pool(this);
UseScratchRegisterScope temps(this);
Register scratch = temps.Acquire();
Subu(scratch, zero_reg, Operand(1));
......@@ -1824,6 +1835,7 @@ void TurboAssembler::Trunc_uw_s(FPURegister fd, FPURegister fs,
void TurboAssembler::Trunc_w_d(FPURegister fd, FPURegister fs) {
if (IsMipsArchVariant(kLoongson) && fd == fs) {
BlockTrampolinePoolScope block_trampoline_pool(this);
Mfhc1(t8, fs);
trunc_w_d(fd, fs);
Mthc1(t8, fs);
......@@ -1834,6 +1846,7 @@ void TurboAssembler::Trunc_w_d(FPURegister fd, FPURegister fs) {
void TurboAssembler::Round_w_d(FPURegister fd, FPURegister fs) {
if (IsMipsArchVariant(kLoongson) && fd == fs) {
BlockTrampolinePoolScope block_trampoline_pool(this);
Mfhc1(t8, fs);
round_w_d(fd, fs);
Mthc1(t8, fs);
......@@ -1844,6 +1857,7 @@ void TurboAssembler::Round_w_d(FPURegister fd, FPURegister fs) {
void TurboAssembler::Floor_w_d(FPURegister fd, FPURegister fs) {
if (IsMipsArchVariant(kLoongson) && fd == fs) {
BlockTrampolinePoolScope block_trampoline_pool(this);
Mfhc1(t8, fs);
floor_w_d(fd, fs);
Mthc1(t8, fs);
......@@ -1854,6 +1868,7 @@ void TurboAssembler::Floor_w_d(FPURegister fd, FPURegister fs) {
void TurboAssembler::Ceil_w_d(FPURegister fd, FPURegister fs) {
if (IsMipsArchVariant(kLoongson) && fd == fs) {
BlockTrampolinePoolScope block_trampoline_pool(this);
Mfhc1(t8, fs);
ceil_w_d(fd, fs);
Mthc1(t8, fs);
......@@ -2314,6 +2329,7 @@ void TurboAssembler::Move(FPURegister dst, uint64_t src) {
void TurboAssembler::LoadZeroOnCondition(Register rd, Register rs,
const Operand& rt, Condition cond) {
BlockTrampolinePoolScope block_trampoline_pool(this);
switch (cond) {
case cc_always:
mov(rd, zero_reg);
......@@ -2463,6 +2479,7 @@ void TurboAssembler::Movn(Register rd, Register rs, Register rt) {
void TurboAssembler::Movt(Register rd, Register rs, uint16_t cc) {
if (IsMipsArchVariant(kLoongson)) {
BlockTrampolinePoolScope block_trampoline_pool(this);
// Tests an FP condition code and then conditionally move rs to rd.
// We do not currently use any FPU cc bit other than bit 0.
DCHECK_EQ(cc, 0);
......@@ -2488,6 +2505,7 @@ void TurboAssembler::Movt(Register rd, Register rs, uint16_t cc) {
void TurboAssembler::Movf(Register rd, Register rs, uint16_t cc) {
if (IsMipsArchVariant(kLoongson)) {
BlockTrampolinePoolScope block_trampoline_pool(this);
// Tests an FP condition code and then conditionally move rs to rd.
// We do not currently use any FPU cc bit other than bit 0.
DCHECK_EQ(cc, 0);
......@@ -2513,6 +2531,7 @@ void TurboAssembler::Movf(Register rd, Register rs, uint16_t cc) {
void TurboAssembler::Clz(Register rd, Register rs) {
if (IsMipsArchVariant(kLoongson)) {
BlockTrampolinePoolScope block_trampoline_pool(this);
DCHECK(rd != t8 && rd != t9 && rs != t8 && rs != t9);
Register mask = t8;
Register scratch = t9;
......@@ -2589,6 +2608,7 @@ void TurboAssembler::Popcnt(Register rd, Register rs) {
uint32_t B2 = 0x0F0F0F0F; // (T)~(T)0/255*15
uint32_t value = 0x01010101; // (T)~(T)0/255
uint32_t shift = 24; // (sizeof(T) - 1) * BITS_PER_BYTE
BlockTrampolinePoolScope block_trampoline_pool(this);
UseScratchRegisterScope temps(this);
Register scratch = temps.Acquire();
Register scratch2 = t8;
......@@ -2677,6 +2697,7 @@ void MacroAssembler::EmitFPUTruncate(FPURoundingMode rounding_mode,
void TurboAssembler::TryInlineTruncateDoubleToI(Register result,
DoubleRegister double_input,
Label* done) {
BlockTrampolinePoolScope block_trampoline_pool(this);
DoubleRegister single_scratch = kScratchDoubleReg.low();
UseScratchRegisterScope temps(this);
Register scratch = temps.Acquire();
......@@ -3749,6 +3770,7 @@ void TurboAssembler::Jump(Handle<Code> code, RelocInfo::Mode rmode,
Condition cond, Register rs, const Operand& rt,
BranchDelaySlot bd) {
DCHECK(RelocInfo::IsCodeTarget(rmode));
BlockTrampolinePoolScope block_trampoline_pool(this);
if (FLAG_embedded_builtins) {
if (root_array_available_ && options().isolate_independent_code) {
IndirectLoadConstant(t9, code);
......@@ -4526,6 +4548,7 @@ bool TurboAssembler::AllowThisStubCall(CodeStub* stub) {
void TurboAssembler::AddOverflow(Register dst, Register left,
const Operand& right, Register overflow) {
BlockTrampolinePoolScope block_trampoline_pool(this);
Register right_reg = no_reg;
Register scratch = t8;
if (!right.is_reg()) {
......@@ -4555,6 +4578,7 @@ void TurboAssembler::AddOverflow(Register dst, Register left,
void TurboAssembler::SubOverflow(Register dst, Register left,
const Operand& right, Register overflow) {
BlockTrampolinePoolScope block_trampoline_pool(this);
Register right_reg = no_reg;
Register scratch = t8;
if (!right.is_reg()) {
......@@ -4584,6 +4608,7 @@ void TurboAssembler::SubOverflow(Register dst, Register left,
void TurboAssembler::MulOverflow(Register dst, Register left,
const Operand& right, Register overflow) {
BlockTrampolinePoolScope block_trampoline_pool(this);
Register right_reg = no_reg;
Register scratch = t8;
Register scratch2 = t9;
......@@ -4772,6 +4797,7 @@ void TurboAssembler::StubPrologue(StackFrame::Type type) {
void TurboAssembler::Prologue() { PushStandardFrame(a1); }
void TurboAssembler::EnterFrame(StackFrame::Type type) {
BlockTrampolinePoolScope block_trampoline_pool(this);
int stack_offset = -3 * kPointerSize;
const int fp_offset = 1 * kPointerSize;
addiu(sp, sp, stack_offset);
......@@ -4808,6 +4834,7 @@ void MacroAssembler::LeaveBuiltinFrame(Register context, Register target,
void MacroAssembler::EnterExitFrame(bool save_doubles, int stack_space,
StackFrame::Type frame_type) {
BlockTrampolinePoolScope block_trampoline_pool(this);
DCHECK(frame_type == StackFrame::EXIT ||
frame_type == StackFrame::BUILTIN_EXIT);
......@@ -4893,6 +4920,7 @@ void MacroAssembler::EnterExitFrame(bool save_doubles, int stack_space,
void MacroAssembler::LeaveExitFrame(bool save_doubles, Register argument_count,
bool do_return,
bool argument_count_is_length) {
BlockTrampolinePoolScope block_trampoline_pool(this);
// Optionally restore all double registers.
if (save_doubles) {
// Remember: we only need to restore every 2nd double FPU value.
......@@ -5036,6 +5064,7 @@ void MacroAssembler::AssertSmi(Register object) {
void MacroAssembler::AssertConstructor(Register object) {
if (emit_debug_code()) {
BlockTrampolinePoolScope block_trampoline_pool(this);
STATIC_ASSERT(kSmiTag == 0);
SmiTst(object, t8);
Check(ne, AbortReason::kOperandIsASmiAndNotAConstructor, t8,
......@@ -5050,6 +5079,7 @@ void MacroAssembler::AssertConstructor(Register object) {
void MacroAssembler::AssertFunction(Register object) {
if (emit_debug_code()) {
BlockTrampolinePoolScope block_trampoline_pool(this);
STATIC_ASSERT(kSmiTag == 0);
SmiTst(object, t8);
Check(ne, AbortReason::kOperandIsASmiAndNotAFunction, t8,
......@@ -5063,6 +5093,7 @@ void MacroAssembler::AssertFunction(Register object) {
void MacroAssembler::AssertBoundFunction(Register object) {
if (emit_debug_code()) {
BlockTrampolinePoolScope block_trampoline_pool(this);
STATIC_ASSERT(kSmiTag == 0);
SmiTst(object, t8);
Check(ne, AbortReason::kOperandIsASmiAndNotABoundFunction, t8,
......@@ -5075,6 +5106,7 @@ void MacroAssembler::AssertBoundFunction(Register object) {
void MacroAssembler::AssertGeneratorObject(Register object) {
if (!emit_debug_code()) return;
BlockTrampolinePoolScope block_trampoline_pool(this);
STATIC_ASSERT(kSmiTag == 0);
SmiTst(object, t8);
Check(ne, AbortReason::kOperandIsASmiAndNotAGeneratorObject, t8,
......@@ -5132,9 +5164,12 @@ void TurboAssembler::Float32Max(FPURegister dst, FPURegister src1,
BranchTrueShortF(&return_left);
// Operands are equal, but check for +/-0.
mfc1(t8, src1);
Branch(&return_left, eq, t8, Operand(zero_reg));
Branch(&return_right);
{
BlockTrampolinePoolScope block_trampoline_pool(this);
mfc1(t8, src1);
Branch(&return_left, eq, t8, Operand(zero_reg));
Branch(&return_right);
}
bind(&return_right);
if (src2 != dst) {
......@@ -5178,9 +5213,12 @@ void TurboAssembler::Float32Min(FPURegister dst, FPURegister src1,
BranchTrueShortF(&return_right);
// Left equals right => check for -0.
mfc1(t8, src1);
Branch(&return_right, eq, t8, Operand(zero_reg));
Branch(&return_left);
{
BlockTrampolinePoolScope block_trampoline_pool(this);
mfc1(t8, src1);
Branch(&return_right, eq, t8, Operand(zero_reg));
Branch(&return_left);
}
bind(&return_right);
if (src2 != dst) {
......@@ -5224,9 +5262,12 @@ void TurboAssembler::Float64Max(DoubleRegister dst, DoubleRegister src1,
BranchTrueShortF(&return_left);
// Left equals right => check for -0.
Mfhc1(t8, src1);
Branch(&return_left, eq, t8, Operand(zero_reg));
Branch(&return_right);
{
BlockTrampolinePoolScope block_trampoline_pool(this);
Mfhc1(t8, src1);
Branch(&return_left, eq, t8, Operand(zero_reg));
Branch(&return_right);
}
bind(&return_right);
if (src2 != dst) {
......@@ -5271,9 +5312,12 @@ void TurboAssembler::Float64Min(DoubleRegister dst, DoubleRegister src1,
BranchTrueShortF(&return_right);
// Left equals right => check for -0.
Mfhc1(t8, src1);
Branch(&return_right, eq, t8, Operand(zero_reg));
Branch(&return_left);
{
BlockTrampolinePoolScope block_trampoline_pool(this);
Mfhc1(t8, src1);
Branch(&return_right, eq, t8, Operand(zero_reg));
Branch(&return_left);
}
bind(&return_right);
if (src2 != dst) {
......@@ -5347,6 +5391,7 @@ void TurboAssembler::CallCFunction(ExternalReference function,
// Linux/MIPS convention demands that register t9 contains
// the address of the function being call in case of
// Position independent code
BlockTrampolinePoolScope block_trampoline_pool(this);
li(t9, function);
CallCFunctionHelper(t9, 0, num_reg_arguments, num_double_arguments);
}
......@@ -5400,17 +5445,20 @@ void TurboAssembler::CallCFunctionHelper(Register function_base,
// allow preemption, so the return address in the link register
// stays correct.
if (function_base != t9) {
mov(t9, function_base);
function_base = t9;
}
{
BlockTrampolinePoolScope block_trampoline_pool(this);
if (function_base != t9) {
mov(t9, function_base);
function_base = t9;
}
if (function_offset != 0) {
addiu(t9, t9, function_offset);
function_offset = 0;
}
if (function_offset != 0) {
addiu(t9, t9, function_offset);
function_offset = 0;
}
Call(function_base, function_offset);
Call(function_base, function_offset);
}
int stack_passed_arguments = CalculateStackPassedWords(
num_reg_arguments, num_double_arguments);
......
......@@ -273,13 +273,6 @@ void Assembler::CheckBuffer() {
}
void Assembler::CheckTrampolinePoolQuick(int extra_instructions) {
if (pc_offset() >= next_buffer_check_ - extra_instructions * kInstrSize) {
CheckTrampolinePool();
}
}
void Assembler::CheckForEmitInForbiddenSlot() {
if (!is_buffer_growth_blocked()) {
CheckBuffer();
......
......@@ -585,6 +585,19 @@ bool Assembler::IsBnec(Instr instr) {
return opcode == POP30 && rs != 0 && rs < rt; // && rt != 0
}
bool Assembler::IsMov(Instr instr, Register rd, Register rs) {
uint32_t opcode = GetOpcodeField(instr);
uint32_t rd_field = GetRd(instr);
uint32_t rs_field = GetRs(instr);
uint32_t rt_field = GetRt(instr);
uint32_t rd_reg = static_cast<uint32_t>(rd.code());
uint32_t rs_reg = static_cast<uint32_t>(rs.code());
uint32_t function_field = GetFunctionField(instr);
// Checks if the instruction is a OR with zero_reg argument (aka MOV).
bool res = opcode == SPECIAL && function_field == OR && rd_field == rd_reg &&
rs_field == rs_reg && rt_field == 0;
return res;
}
bool Assembler::IsJump(Instr instr) {
uint32_t opcode = GetOpcodeField(instr);
......@@ -865,6 +878,34 @@ void Assembler::target_at_put(int pos, int target_pos, bool is_internal) {
instr_ori | ((imm >> 16) & kImm16Mask));
instr_at_put(pos + 3 * Assembler::kInstrSize,
instr_ori2 | (imm & kImm16Mask));
} else if (IsMov(instr, t8, ra)) {
Instr instr_lui = instr_at(pos + 4 * Assembler::kInstrSize);
Instr instr_ori = instr_at(pos + 5 * Assembler::kInstrSize);
DCHECK(IsLui(instr_lui));
DCHECK(IsOri(instr_ori));
int32_t imm_short = target_pos - (pos + Assembler::kBranchPCOffset);
if (is_int16(imm_short)) {
// Optimize by converting to regular branch with 16-bit
// offset
Instr instr_b = BEQ;
instr_b = SetBranchOffset(pos, target_pos, instr_b);
instr_at_put(pos, instr_b);
instr_at_put(pos + 1 * Assembler::kInstrSize, 0);
} else {
int32_t imm = target_pos - (pos + Assembler::kLongBranchPCOffset);
DCHECK_EQ(imm & 3, 0);
instr_lui &= ~kImm16Mask;
instr_ori &= ~kImm16Mask;
instr_at_put(pos + 4 * Assembler::kInstrSize,
instr_lui | ((imm >> 16) & kImm16Mask));
instr_at_put(pos + 5 * Assembler::kInstrSize,
instr_ori | (imm & kImm16Mask));
}
} else if (IsJ(instr) || IsJal(instr)) {
int32_t imm28 = target_pos - pos;
DCHECK_EQ(imm28 & 3, 0);
......@@ -4143,15 +4184,30 @@ void Assembler::CheckTrampolinePool() {
int pool_start = pc_offset();
for (int i = 0; i < unbound_labels_count_; i++) {
{ 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
// to be patched.
RecordRelocInfo(RelocInfo::INTERNAL_REFERENCE_ENCODED);
j(&after_pool);
if (kArchVariant == kMips64r6) {
bc(&after_pool);
nop();
} else {
Label find_pc;
or_(t8, ra, zero_reg);
bal(&find_pc);
or_(t9, ra, zero_reg);
bind(&find_pc);
or_(ra, t8, zero_reg);
lui(t8, 0);
ori(t8, t8, 0);
daddu(t9, t9, t8);
// Instruction jr will take or_ from the next trampoline.
// in its branch delay slot. This is the expected behavior
// in order to decrease size of trampoline pool.
jr(t9);
}
}
nop();
}
nop();
bind(&after_pool);
trampoline_ = Trampoline(pool_start, unbound_labels_count_);
......
......@@ -622,6 +622,11 @@ class Assembler : public AssemblerBase {
// Difference between address of current opcode and target address offset.
static constexpr int kBranchPCOffset = 4;
// Difference between address of current opcode and target address offset,
// when we are generatinga sequence of instructions for long relative PC
// branches
static constexpr int kLongBranchPCOffset = 12;
// Here we are patching the address in the LUI/ORI instruction pair.
// These values are used in the serialization process and must be zero for
// MIPS platform, as Code, Embedded Object or External-reference pointers
......@@ -655,7 +660,8 @@ class Assembler : public AssemblerBase {
// Max offset for compact branch instructions with 26-bit offset field
static constexpr int kMaxCompactBranchOffset = (1 << (28 - 1)) - 1;
static constexpr int kTrampolineSlotsSize = 2 * kInstrSize;
static constexpr int kTrampolineSlotsSize =
kArchVariant == kMips64r6 ? 2 * kInstrSize : 8 * kInstrSize;
RegList* GetScratchRegisterList() { return &scratch_register_list_; }
......@@ -1845,6 +1851,7 @@ class Assembler : public AssemblerBase {
static bool IsJ(Instr instr);
static bool IsLui(Instr instr);
static bool IsOri(Instr instr);
static bool IsMov(Instr instr, Register rd, Register rs);
static bool IsJal(Instr instr);
static bool IsJr(Instr instr);
......@@ -1950,6 +1957,9 @@ class Assembler : public AssemblerBase {
void EndBlockTrampolinePool() {
trampoline_pool_blocked_nesting_--;
if (trampoline_pool_blocked_nesting_ == 0) {
CheckTrampolinePoolQuick(1);
}
}
bool is_trampoline_pool_blocked() const {
......@@ -1985,7 +1995,11 @@ class Assembler : public AssemblerBase {
}
}
inline void CheckTrampolinePoolQuick(int extra_instructions = 0);
void CheckTrampolinePoolQuick(int extra_instructions = 0) {
if (pc_offset() >= next_buffer_check_ - extra_instructions * kInstrSize) {
CheckTrampolinePool();
}
}
private:
// Avoid overflows for displacements etc.
......
......@@ -212,6 +212,7 @@ void MacroAssembler::RecordWriteField(Register object, int offset,
Daddu(dst, object, Operand(offset - kHeapObjectTag));
if (emit_debug_code()) {
BlockTrampolinePoolScope block_trampoline_pool(this);
Label ok;
And(t8, dst, Operand(kPointerSize - 1));
Branch(&ok, eq, t8, Operand(zero_reg));
......@@ -938,6 +939,7 @@ void TurboAssembler::Slt(Register rd, Register rs, const Operand& rt) {
} else {
// li handles the relocation.
UseScratchRegisterScope temps(this);
BlockTrampolinePoolScope block_trampoline_pool(this);
Register scratch = temps.hasAvailable() ? temps.Acquire() : t8;
DCHECK(rs != scratch);
li(scratch, rt);
......@@ -961,6 +963,7 @@ void TurboAssembler::Sltu(Register rd, Register rs, const Operand& rt) {
} else {
// li handles the relocation.
UseScratchRegisterScope temps(this);
BlockTrampolinePoolScope block_trampoline_pool(this);
Register scratch = temps.hasAvailable() ? temps.Acquire() : t8;
DCHECK(rs != scratch);
li(scratch, rt);
......@@ -976,6 +979,7 @@ void TurboAssembler::Sle(Register rd, Register rs, const Operand& rt) {
// li handles the relocation.
UseScratchRegisterScope temps(this);
Register scratch = temps.hasAvailable() ? temps.Acquire() : t8;
BlockTrampolinePoolScope block_trampoline_pool(this);
DCHECK(rs != scratch);
li(scratch, rt);
slt(rd, scratch, rs);
......@@ -990,6 +994,7 @@ void TurboAssembler::Sleu(Register rd, Register rs, const Operand& rt) {
// li handles the relocation.
UseScratchRegisterScope temps(this);
Register scratch = temps.hasAvailable() ? temps.Acquire() : t8;
BlockTrampolinePoolScope block_trampoline_pool(this);
DCHECK(rs != scratch);
li(scratch, rt);
sltu(rd, scratch, rs);
......@@ -1014,6 +1019,7 @@ void TurboAssembler::Sgt(Register rd, Register rs, const Operand& rt) {
// li handles the relocation.
UseScratchRegisterScope temps(this);
Register scratch = temps.hasAvailable() ? temps.Acquire() : t8;
BlockTrampolinePoolScope block_trampoline_pool(this);
DCHECK(rs != scratch);
li(scratch, rt);
slt(rd, scratch, rs);
......@@ -1027,6 +1033,7 @@ void TurboAssembler::Sgtu(Register rd, Register rs, const Operand& rt) {
// li handles the relocation.
UseScratchRegisterScope temps(this);
Register scratch = temps.hasAvailable() ? temps.Acquire() : t8;
BlockTrampolinePoolScope block_trampoline_pool(this);
DCHECK(rs != scratch);
li(scratch, rt);
sltu(rd, scratch, rs);
......@@ -2115,11 +2122,14 @@ void TurboAssembler::Neg_d(FPURegister fd, FPURegister fs) {
void TurboAssembler::Cvt_d_uw(FPURegister fd, FPURegister fs) {
// Move the data from fs to t8.
BlockTrampolinePoolScope block_trampoline_pool(this);
mfc1(t8, fs);
Cvt_d_uw(fd, t8);
}
void TurboAssembler::Cvt_d_uw(FPURegister fd, Register rs) {
BlockTrampolinePoolScope block_trampoline_pool(this);
// Convert rs to a FP value in fd.
DCHECK(rs != t9);
DCHECK(rs != at);
......@@ -2131,12 +2141,14 @@ void TurboAssembler::Cvt_d_uw(FPURegister fd, Register rs) {
}
void TurboAssembler::Cvt_d_ul(FPURegister fd, FPURegister fs) {
BlockTrampolinePoolScope block_trampoline_pool(this);
// Move the data from fs to t8.
dmfc1(t8, fs);
Cvt_d_ul(fd, t8);
}
void TurboAssembler::Cvt_d_ul(FPURegister fd, Register rs) {
BlockTrampolinePoolScope block_trampoline_pool(this);
// Convert rs to a FP value in fd.
DCHECK(rs != t9);
......@@ -2164,12 +2176,14 @@ void TurboAssembler::Cvt_d_ul(FPURegister fd, Register rs) {
}
void TurboAssembler::Cvt_s_uw(FPURegister fd, FPURegister fs) {
BlockTrampolinePoolScope block_trampoline_pool(this);
// Move the data from fs to t8.
mfc1(t8, fs);
Cvt_s_uw(fd, t8);
}
void TurboAssembler::Cvt_s_uw(FPURegister fd, Register rs) {
BlockTrampolinePoolScope block_trampoline_pool(this);
// Convert rs to a FP value in fd.
DCHECK(rs != t9);
DCHECK(rs != at);
......@@ -2181,12 +2195,14 @@ void TurboAssembler::Cvt_s_uw(FPURegister fd, Register rs) {
}
void TurboAssembler::Cvt_s_ul(FPURegister fd, FPURegister fs) {
BlockTrampolinePoolScope block_trampoline_pool(this);
// Move the data from fs to t8.
dmfc1(t8, fs);
Cvt_s_ul(fd, t8);
}
void TurboAssembler::Cvt_s_ul(FPURegister fd, Register rs) {
BlockTrampolinePoolScope block_trampoline_pool(this);
// Convert rs to a FP value in fd.
DCHECK(rs != t9);
......@@ -2237,6 +2253,7 @@ void MacroAssembler::Trunc_l_d(FPURegister fd, FPURegister fs) {
void MacroAssembler::Trunc_l_ud(FPURegister fd,
FPURegister fs,
FPURegister scratch) {
BlockTrampolinePoolScope block_trampoline_pool(this);
// Load to GPR.
dmfc1(t8, fs);
// Reset sign bit.
......@@ -2842,6 +2859,7 @@ void TurboAssembler::Movn(Register rd, Register rs, Register rt) {
void TurboAssembler::LoadZeroOnCondition(Register rd, Register rs,
const Operand& rt, Condition cond) {
BlockTrampolinePoolScope block_trampoline_pool(this);
switch (cond) {
case cc_always:
mov(rd, zero_reg);
......@@ -3059,6 +3077,7 @@ void TurboAssembler::Popcnt(Register rd, Register rs) {
uint32_t shift = 24; // (sizeof(T) - 1) * BITS_PER_BYTE
UseScratchRegisterScope temps(this);
BlockTrampolinePoolScope block_trampoline_pool(this);
Register scratch = temps.Acquire();
Register scratch2 = t8;
srl(scratch, rs, 1);
......@@ -3087,6 +3106,7 @@ void TurboAssembler::Dpopcnt(Register rd, Register rs) {
uint64_t shift = 24; // (sizeof(T) - 1) * BITS_PER_BYTE
UseScratchRegisterScope temps(this);
BlockTrampolinePoolScope block_trampoline_pool(this);
Register scratch = temps.Acquire();
Register scratch2 = t8;
dsrl(scratch, rs, 1);
......@@ -3176,6 +3196,7 @@ void TurboAssembler::TryInlineTruncateDoubleToI(Register result,
Label* done) {
DoubleRegister single_scratch = kScratchDoubleReg.low();
UseScratchRegisterScope temps(this);
BlockTrampolinePoolScope block_trampoline_pool(this);
Register scratch = temps.Acquire();
Register scratch2 = t9;
......@@ -3374,6 +3395,7 @@ bool TurboAssembler::BranchShortHelperR6(int32_t offset, Label* L,
const Operand& rt) {
DCHECK(L == nullptr || offset == 0);
UseScratchRegisterScope temps(this);
BlockTrampolinePoolScope block_trampoline_pool(this);
Register scratch = temps.hasAvailable() ? temps.Acquire() : t8;
// Be careful to always use shifted_branch_offset only just before the
......@@ -3588,6 +3610,7 @@ bool TurboAssembler::BranchShortHelper(int16_t offset, Label* L, Condition cond,
if (!is_near(L, OffsetSize::kOffset16)) return false;
UseScratchRegisterScope temps(this);
BlockTrampolinePoolScope block_trampoline_pool(this);
Register scratch = temps.hasAvailable() ? temps.Acquire() : t8;
int32_t offset32;
......@@ -4153,9 +4176,12 @@ void TurboAssembler::Jump(intptr_t target, RelocInfo::Mode rmode,
}
// The first instruction of 'li' may be placed in the delay slot.
// This is not an issue, t9 is expected to be clobbered anyway.
li(t9, Operand(target, rmode));
Jump(t9, al, zero_reg, Operand(zero_reg), bd);
bind(&skip);
{
BlockTrampolinePoolScope block_trampoline_pool(this);
li(t9, Operand(target, rmode));
Jump(t9, al, zero_reg, Operand(zero_reg), bd);
bind(&skip);
}
}
void TurboAssembler::Jump(Address target, RelocInfo::Mode rmode, Condition cond,
......@@ -4169,6 +4195,7 @@ void TurboAssembler::Jump(Handle<Code> code, RelocInfo::Mode rmode,
BranchDelaySlot bd) {
DCHECK(RelocInfo::IsCodeTarget(rmode));
if (FLAG_embedded_builtins) {
BlockTrampolinePoolScope block_trampoline_pool(this);
if (root_array_available_ && options().isolate_independent_code) {
IndirectLoadConstant(t9, code);
Daddu(t9, t9, Operand(Code::kHeaderSize - kHeapObjectTag));
......@@ -4833,6 +4860,7 @@ bool TurboAssembler::AllowThisStubCall(CodeStub* stub) {
void TurboAssembler::DaddOverflow(Register dst, Register left,
const Operand& right, Register overflow) {
BlockTrampolinePoolScope block_trampoline_pool(this);
Register right_reg = no_reg;
Register scratch = t8;
if (!right.is_reg()) {
......@@ -4862,6 +4890,7 @@ void TurboAssembler::DaddOverflow(Register dst, Register left,
void TurboAssembler::DsubOverflow(Register dst, Register left,
const Operand& right, Register overflow) {
BlockTrampolinePoolScope block_trampoline_pool(this);
Register right_reg = no_reg;
Register scratch = t8;
if (!right.is_reg()) {
......@@ -4891,6 +4920,7 @@ void TurboAssembler::DsubOverflow(Register dst, Register left,
void TurboAssembler::MulOverflow(Register dst, Register left,
const Operand& right, Register overflow) {
BlockTrampolinePoolScope block_trampoline_pool(this);
Register right_reg = no_reg;
Register scratch = t8;
if (!right.is_reg()) {
......@@ -5081,6 +5111,7 @@ void TurboAssembler::StubPrologue(StackFrame::Type type) {
void TurboAssembler::Prologue() { PushStandardFrame(a1); }
void TurboAssembler::EnterFrame(StackFrame::Type type) {
BlockTrampolinePoolScope block_trampoline_pool(this);
int stack_offset = -3 * kPointerSize;
const int fp_offset = 1 * kPointerSize;
daddiu(sp, sp, stack_offset);
......@@ -5152,17 +5183,20 @@ void MacroAssembler::EnterExitFrame(bool save_doubles, int stack_space,
Sd(zero_reg, MemOperand(fp, ExitFrameConstants::kSPOffset));
}
// Accessed from ExitFrame::code_slot.
li(t8, CodeObject(), CONSTANT_SIZE);
Sd(t8, MemOperand(fp, ExitFrameConstants::kCodeOffset));
{
BlockTrampolinePoolScope block_trampoline_pool(this);
// Accessed from ExitFrame::code_slot.
li(t8, CodeObject(), CONSTANT_SIZE);
Sd(t8, MemOperand(fp, ExitFrameConstants::kCodeOffset));
// Save the frame pointer and the context in top.
li(t8,
ExternalReference::Create(IsolateAddressId::kCEntryFPAddress, isolate()));
Sd(fp, MemOperand(t8));
li(t8,
ExternalReference::Create(IsolateAddressId::kContextAddress, isolate()));
Sd(cp, MemOperand(t8));
// Save the frame pointer and the context in top.
li(t8, ExternalReference::Create(IsolateAddressId::kCEntryFPAddress,
isolate()));
Sd(fp, MemOperand(t8));
li(t8,
ExternalReference::Create(IsolateAddressId::kContextAddress, isolate()));
Sd(cp, MemOperand(t8));
}
const int frame_alignment = MacroAssembler::ActivationFrameAlignment();
if (save_doubles) {
......@@ -5198,6 +5232,7 @@ void MacroAssembler::EnterExitFrame(bool save_doubles, int stack_space,
void MacroAssembler::LeaveExitFrame(bool save_doubles, Register argument_count,
bool do_return,
bool argument_count_is_length) {
BlockTrampolinePoolScope block_trampoline_pool(this);
// Optionally restore all double registers.
if (save_doubles) {
// Remember: we only need to restore every 2nd double FPU value.
......@@ -5361,6 +5396,7 @@ void MacroAssembler::AssertSmi(Register object) {
void MacroAssembler::AssertConstructor(Register object) {
if (emit_debug_code()) {
BlockTrampolinePoolScope block_trampoline_pool(this);
STATIC_ASSERT(kSmiTag == 0);
SmiTst(object, t8);
Check(ne, AbortReason::kOperandIsASmiAndNotAConstructor, t8,
......@@ -5375,6 +5411,7 @@ void MacroAssembler::AssertConstructor(Register object) {
void MacroAssembler::AssertFunction(Register object) {
if (emit_debug_code()) {
BlockTrampolinePoolScope block_trampoline_pool(this);
STATIC_ASSERT(kSmiTag == 0);
SmiTst(object, t8);
Check(ne, AbortReason::kOperandIsASmiAndNotAFunction, t8,
......@@ -5388,6 +5425,7 @@ void MacroAssembler::AssertFunction(Register object) {
void MacroAssembler::AssertBoundFunction(Register object) {
if (emit_debug_code()) {
BlockTrampolinePoolScope block_trampoline_pool(this);
STATIC_ASSERT(kSmiTag == 0);
SmiTst(object, t8);
Check(ne, AbortReason::kOperandIsASmiAndNotABoundFunction, t8,
......@@ -5400,6 +5438,7 @@ void MacroAssembler::AssertBoundFunction(Register object) {
void MacroAssembler::AssertGeneratorObject(Register object) {
if (!emit_debug_code()) return;
BlockTrampolinePoolScope block_trampoline_pool(this);
STATIC_ASSERT(kSmiTag == 0);
SmiTst(object, t8);
Check(ne, AbortReason::kOperandIsASmiAndNotAGeneratorObject, t8,
......@@ -5457,10 +5496,13 @@ void TurboAssembler::Float32Max(FPURegister dst, FPURegister src1,
BranchTrueShortF(&return_left);
// Operands are equal, but check for +/-0.
mfc1(t8, src1);
dsll32(t8, t8, 0);
Branch(&return_left, eq, t8, Operand(zero_reg));
Branch(&return_right);
{
BlockTrampolinePoolScope block_trampoline_pool(this);
mfc1(t8, src1);
dsll32(t8, t8, 0);
Branch(&return_left, eq, t8, Operand(zero_reg));
Branch(&return_right);
}
bind(&return_right);
if (src2 != dst) {
......@@ -5504,10 +5546,13 @@ void TurboAssembler::Float32Min(FPURegister dst, FPURegister src1,
BranchTrueShortF(&return_right);
// Left equals right => check for -0.
mfc1(t8, src1);
dsll32(t8, t8, 0);
Branch(&return_right, eq, t8, Operand(zero_reg));
Branch(&return_left);
{
BlockTrampolinePoolScope block_trampoline_pool(this);
mfc1(t8, src1);
dsll32(t8, t8, 0);
Branch(&return_right, eq, t8, Operand(zero_reg));
Branch(&return_left);
}
bind(&return_right);
if (src2 != dst) {
......@@ -5551,9 +5596,12 @@ void TurboAssembler::Float64Max(FPURegister dst, FPURegister src1,
BranchTrueShortF(&return_left);
// Left equals right => check for -0.
dmfc1(t8, src1);
Branch(&return_left, eq, t8, Operand(zero_reg));
Branch(&return_right);
{
BlockTrampolinePoolScope block_trampoline_pool(this);
dmfc1(t8, src1);
Branch(&return_left, eq, t8, Operand(zero_reg));
Branch(&return_right);
}
bind(&return_right);
if (src2 != dst) {
......@@ -5597,9 +5645,12 @@ void TurboAssembler::Float64Min(FPURegister dst, FPURegister src1,
BranchTrueShortF(&return_right);
// Left equals right => check for -0.
dmfc1(t8, src1);
Branch(&return_right, eq, t8, Operand(zero_reg));
Branch(&return_left);
{
BlockTrampolinePoolScope block_trampoline_pool(this);
dmfc1(t8, src1);
Branch(&return_right, eq, t8, Operand(zero_reg));
Branch(&return_left);
}
bind(&return_right);
if (src2 != dst) {
......@@ -5672,6 +5723,7 @@ void TurboAssembler::PrepareCallCFunction(int num_reg_arguments,
void TurboAssembler::CallCFunction(ExternalReference function,
int num_reg_arguments,
int num_double_arguments) {
BlockTrampolinePoolScope block_trampoline_pool(this);
li(t9, function);
CallCFunctionHelper(t9, num_reg_arguments, num_double_arguments);
}
......@@ -5725,14 +5777,16 @@ void TurboAssembler::CallCFunctionHelper(Register function,
// Just call directly. The function called cannot cause a GC, or
// allow preemption, so the return address in the link register
// stays correct.
{
BlockTrampolinePoolScope block_trampoline_pool(this);
if (function != t9) {
mov(t9, function);
function = t9;
}
if (function != t9) {
mov(t9, function);
function = t9;
Call(function);
}
Call(function);
int stack_passed_arguments = CalculateStackPassedWords(
num_reg_arguments, num_double_arguments);
......
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