MIPS: Fix dd() implementations for compact branches.

BUG=

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

Cr-Commit-Position: refs/heads/master@{#33249}
This commit is contained in:
balazs.kilvady 2016-01-12 11:48:51 -08:00 committed by Commit bot
parent 6cfe250868
commit 5091e8f2f5
10 changed files with 235 additions and 77 deletions

View File

@ -437,10 +437,22 @@ void Assembler::CheckTrampolinePoolQuick(int extra_instructions) {
}
void Assembler::emit(Instr x, CompactBranchType is_compact_branch) {
void Assembler::CheckForEmitInForbiddenSlot() {
if (!is_buffer_growth_blocked()) {
CheckBuffer();
}
if (IsPrevInstrCompactBranch()) {
// Nop instruction to preceed a CTI in forbidden slot:
Instr nop = SPECIAL | SLL;
*reinterpret_cast<Instr*>(pc_) = nop;
pc_ += kInstrSize;
ClearCompactBranchState();
}
}
void Assembler::EmitHelper(Instr x, CompactBranchType is_compact_branch) {
if (IsPrevInstrCompactBranch()) {
if (Instruction::IsForbiddenAfterBranchInstr(x)) {
// Nop instruction to preceed a CTI in forbidden slot:
@ -459,6 +471,22 @@ void Assembler::emit(Instr x, CompactBranchType is_compact_branch) {
}
template <typename T>
void Assembler::EmitHelper(T x) {
*reinterpret_cast<T*>(pc_) = x;
pc_ += sizeof(x);
CheckTrampolinePoolQuick();
}
void Assembler::emit(Instr x, CompactBranchType is_compact_branch) {
if (!is_buffer_growth_blocked()) {
CheckBuffer();
}
EmitHelper(x, is_compact_branch);
}
} // namespace internal
} // namespace v8

View File

@ -2865,46 +2865,34 @@ void Assembler::GrowBuffer() {
void Assembler::db(uint8_t data) {
CheckBuffer();
*reinterpret_cast<uint8_t*>(pc_) = data;
pc_ += sizeof(uint8_t);
CheckForEmitInForbiddenSlot();
EmitHelper(data);
}
void Assembler::dd(uint32_t data) {
CheckBuffer();
*reinterpret_cast<uint32_t*>(pc_) = data;
pc_ += sizeof(uint32_t);
CheckForEmitInForbiddenSlot();
EmitHelper(data);
}
void Assembler::dq(uint64_t data) {
CheckBuffer();
*reinterpret_cast<uint64_t*>(pc_) = data;
pc_ += sizeof(uint64_t);
CheckForEmitInForbiddenSlot();
EmitHelper(data);
}
void Assembler::dd(Label* label) {
CheckBuffer();
RecordRelocInfo(RelocInfo::INTERNAL_REFERENCE);
uint32_t data;
CheckForEmitInForbiddenSlot();
if (label->is_bound()) {
data = reinterpret_cast<uint32_t>(buffer_ + label->pos());
} else {
data = jump_address(label);
internal_reference_positions_.insert(label->pos());
}
*reinterpret_cast<uint32_t*>(pc_) = data;
pc_ += sizeof(uint32_t);
}
void Assembler::emit_code_stub_address(Code* stub) {
CheckBuffer();
*reinterpret_cast<uint32_t*>(pc_) =
reinterpret_cast<uint32_t>(stub->instruction_start());
pc_ += sizeof(uint32_t);
RecordRelocInfo(RelocInfo::INTERNAL_REFERENCE);
EmitHelper(data);
}

View File

@ -1049,9 +1049,6 @@ class Assembler : public AssemblerBase {
void dp(uintptr_t data) { dd(data); }
void dd(Label* label);
// Emits the address of the code stub's first instruction.
void emit_code_stub_address(Code* stub);
PositionsRecorder* positions_recorder() { return &positions_recorder_; }
// Postpone the generation of the trampoline pool for the specified number of
@ -1261,6 +1258,11 @@ class Assembler : public AssemblerBase {
void GrowBuffer();
inline void emit(Instr x,
CompactBranchType is_compact_branch = CompactBranchType::NO);
inline void emit(uint64_t x);
inline void CheckForEmitInForbiddenSlot();
template <typename T>
inline void EmitHelper(T x);
inline void EmitHelper(Instr x, CompactBranchType is_compact_branch);
// Instruction generation.
// We have 3 different kind of encoding layout on MIPS.

View File

@ -438,10 +438,22 @@ void Assembler::CheckTrampolinePoolQuick(int extra_instructions) {
}
void Assembler::emit(Instr x, CompactBranchType is_compact_branch) {
void Assembler::CheckForEmitInForbiddenSlot() {
if (!is_buffer_growth_blocked()) {
CheckBuffer();
}
if (IsPrevInstrCompactBranch()) {
// Nop instruction to preceed a CTI in forbidden slot:
Instr nop = SPECIAL | SLL;
*reinterpret_cast<Instr*>(pc_) = nop;
pc_ += kInstrSize;
ClearCompactBranchState();
}
}
void Assembler::EmitHelper(Instr x, CompactBranchType is_compact_branch) {
if (IsPrevInstrCompactBranch()) {
if (Instruction::IsForbiddenAfterBranchInstr(x)) {
// Nop instruction to preceed a CTI in forbidden slot:
@ -460,21 +472,25 @@ void Assembler::emit(Instr x, CompactBranchType is_compact_branch) {
}
void Assembler::emit(uint64_t x) {
template <typename T>
void Assembler::EmitHelper(T x) {
*reinterpret_cast<T*>(pc_) = x;
pc_ += sizeof(x);
CheckTrampolinePoolQuick();
}
void Assembler::emit(Instr x, CompactBranchType is_compact_branch) {
if (!is_buffer_growth_blocked()) {
CheckBuffer();
}
if (IsPrevInstrCompactBranch()) {
// Nop instruction to preceed a CTI in forbidden slot:
Instr nop = SPECIAL | SLL;
*reinterpret_cast<Instr*>(pc_) = nop;
pc_ += kInstrSize;
EmitHelper(x, is_compact_branch);
}
ClearCompactBranchState();
}
*reinterpret_cast<uint64_t*>(pc_) = x;
pc_ += kInstrSize * 2;
CheckTrampolinePoolQuick();
void Assembler::emit(uint64_t data) {
CheckForEmitInForbiddenSlot();
EmitHelper(data);
}

View File

@ -3175,46 +3175,34 @@ void Assembler::GrowBuffer() {
void Assembler::db(uint8_t data) {
CheckBuffer();
*reinterpret_cast<uint8_t*>(pc_) = data;
pc_ += sizeof(uint8_t);
CheckForEmitInForbiddenSlot();
EmitHelper(data);
}
void Assembler::dd(uint32_t data) {
CheckBuffer();
*reinterpret_cast<uint32_t*>(pc_) = data;
pc_ += sizeof(uint32_t);
CheckForEmitInForbiddenSlot();
EmitHelper(data);
}
void Assembler::dq(uint64_t data) {
CheckBuffer();
*reinterpret_cast<uint64_t*>(pc_) = data;
pc_ += sizeof(uint64_t);
CheckForEmitInForbiddenSlot();
EmitHelper(data);
}
void Assembler::dd(Label* label) {
CheckBuffer();
RecordRelocInfo(RelocInfo::INTERNAL_REFERENCE);
uint64_t data;
CheckForEmitInForbiddenSlot();
if (label->is_bound()) {
data = reinterpret_cast<uint64_t>(buffer_ + label->pos());
} else {
data = jump_address(label);
internal_reference_positions_.insert(label->pos());
}
*reinterpret_cast<uint64_t*>(pc_) = data;
pc_ += sizeof(uint64_t);
}
void Assembler::emit_code_stub_address(Code* stub) {
CheckBuffer();
*reinterpret_cast<uint64_t*>(pc_) =
reinterpret_cast<uint64_t>(stub->instruction_start());
pc_ += sizeof(uint64_t);
RecordRelocInfo(RelocInfo::INTERNAL_REFERENCE);
EmitHelper(data);
}

View File

@ -1105,9 +1105,6 @@ class Assembler : public AssemblerBase {
void dp(uintptr_t data) { dq(data); }
void dd(Label* label);
// Emits the address of the code stub's first instruction.
void emit_code_stub_address(Code* stub);
PositionsRecorder* positions_recorder() { return &positions_recorder_; }
// Postpone the generation of the trampoline pool for the specified number of
@ -1329,6 +1326,10 @@ class Assembler : public AssemblerBase {
inline void emit(Instr x,
CompactBranchType is_compact_branch = CompactBranchType::NO);
inline void emit(uint64_t x);
inline void CheckForEmitInForbiddenSlot();
template <typename T>
inline void EmitHelper(T x);
inline void EmitHelper(Instr x, CompactBranchType is_compact_branch);
// Instruction generation.
// We have 3 different kind of encoding layout on MIPS.

View File

@ -5091,9 +5091,8 @@ int32_t run_bc(int32_t offset) {
__ li(t8, 0);
__ li(t9, 2); // A condition for stopping execution.
uint32_t instruction_addiu = 0x24420001; // addiu v0, v0, 1
for (int32_t i = -100; i <= -11; ++i) {
__ dd(instruction_addiu);
__ addiu(v0, v0, 1);
}
__ addiu(t8, t8, 1); // -10
@ -5112,7 +5111,7 @@ int32_t run_bc(int32_t offset) {
__ bc(offset); // -1
for (int32_t i = 0; i <= 99; ++i) {
__ dd(instruction_addiu);
__ addiu(v0, v0, 1);
}
__ pop(ra);

View File

@ -3222,9 +3222,7 @@ TEST(jump_tables1) {
__ daddiu(sp, sp, -8);
__ sd(ra, MemOperand(sp));
if ((assm.pc_offset() & 7) == 0) {
__ nop();
}
__ Align(8);
Label done;
{
@ -3304,9 +3302,7 @@ TEST(jump_tables2) {
__ nop();
}
if ((assm.pc_offset() & 7) == 0) {
__ nop();
}
__ Align(8);
__ bind(&dispatch);
{
__ BlockTrampolinePoolFor(kNumCases * 2 + 7);
@ -3372,6 +3368,7 @@ TEST(jump_tables3) {
Label done, dispatch;
__ b(&dispatch);
__ nop();
for (int i = 0; i < kNumCases; ++i) {
@ -3386,10 +3383,7 @@ TEST(jump_tables3) {
__ nop();
}
__ stop("chk");
if ((assm.pc_offset() & 7) == 0) {
__ nop();
}
__ Align(8);
__ bind(&dispatch);
{
__ BlockTrampolinePoolFor(kNumCases * 2 + 7);
@ -5547,9 +5541,8 @@ int64_t run_bc(int32_t offset) {
__ li(t8, 0);
__ li(t9, 2); // Condition for the stopping execution.
uint32_t instruction_addiu = 0x24420001; // addiu v0, v0, 1
for (int32_t i = -100; i <= -11; ++i) {
__ dd(instruction_addiu);
__ addiu(v0, v0, 1);
}
__ addiu(t8, t8, 1); // -10
@ -5568,7 +5561,7 @@ int64_t run_bc(int32_t offset) {
__ bc(offset); // -1
for (int32_t i = 0; i <= 99; ++i) {
__ dd(instruction_addiu);
__ addiu(v0, v0, 1);
}
__ pop(ra);

View File

@ -261,6 +261,77 @@ TEST(jump_tables4) {
}
TEST(jump_tables5) {
if (!IsMipsArchVariant(kMips32r6)) return;
// Similar to test-assembler-mips jump_tables1, with extra test for emitting a
// compact branch instruction before emission of the dd table.
CcTest::InitializeVM();
Isolate* isolate = CcTest::i_isolate();
HandleScope scope(isolate);
MacroAssembler assembler(isolate, nullptr, 0,
v8::internal::CodeObjectRequired::kYes);
MacroAssembler* masm = &assembler;
const int kNumCases = 512;
int values[kNumCases];
isolate->random_number_generator()->NextBytes(values, sizeof(values));
Label labels[kNumCases];
Label done;
__ addiu(sp, sp, -4);
__ sw(ra, MemOperand(sp));
{
__ BlockTrampolinePoolFor(kNumCases * 2 + 7 + 1);
PredictableCodeSizeScope predictable(
masm, kNumCases * kPointerSize + ((7 + 1) * Assembler::kInstrSize));
Label here;
__ bal(&here);
__ sll(at, a0, 3); // In delay slot.
__ bind(&here);
__ addu(at, at, ra);
__ lw(at, MemOperand(at, 6 * Assembler::kInstrSize));
__ jalr(at);
__ nop(); // Branch delay slot nop.
__ bc(&done);
for (int i = 0; i < kNumCases; ++i) {
__ dd(&labels[i]);
}
}
for (int i = 0; i < kNumCases; ++i) {
__ bind(&labels[i]);
__ lui(v0, (values[i] >> 16) & 0xffff);
__ ori(v0, v0, values[i] & 0xffff);
__ jr(ra);
__ nop();
}
__ bind(&done);
__ lw(ra, MemOperand(sp));
__ addiu(sp, sp, 4);
__ jr(ra);
__ nop();
CodeDesc desc;
masm->GetCode(&desc);
Handle<Code> code = isolate->factory()->NewCode(
desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
#ifdef OBJECT_PRINT
code->Print(std::cout);
#endif
F1 f = FUNCTION_CAST<F1>(code->entry());
for (int i = 0; i < kNumCases; ++i) {
int64_t res = reinterpret_cast<int64_t>(
CALL_GENERATED_CODE(isolate, f, i, 0, 0, 0, 0));
::printf("f(%d) = %" PRId64 "\n", i, res);
CHECK_EQ(values[i], res);
}
}
static uint32_t run_lsa(uint32_t rt, uint32_t rs, int8_t sa) {
Isolate* isolate = CcTest::i_isolate();
HandleScope scope(isolate);

View File

@ -305,6 +305,78 @@ TEST(jump_tables4) {
}
TEST(jump_tables5) {
if (kArchVariant != kMips64r6) return;
// Similar to test-assembler-mips jump_tables1, with extra test for emitting a
// compact branch instruction before emission of the dd table.
CcTest::InitializeVM();
Isolate* isolate = CcTest::i_isolate();
HandleScope scope(isolate);
MacroAssembler assembler(isolate, nullptr, 0,
v8::internal::CodeObjectRequired::kYes);
MacroAssembler* masm = &assembler;
const int kNumCases = 512;
int values[kNumCases];
isolate->random_number_generator()->NextBytes(values, sizeof(values));
Label labels[kNumCases];
Label done;
__ daddiu(sp, sp, -8);
__ sd(ra, MemOperand(sp));
__ Align(8);
{
__ BlockTrampolinePoolFor(kNumCases * 2 + 7 + 1);
PredictableCodeSizeScope predictable(
masm, kNumCases * kPointerSize + ((7 + 1) * Assembler::kInstrSize));
Label here;
__ bal(&here);
__ dsll(at, a0, 3); // In delay slot.
__ bind(&here);
__ daddu(at, at, ra);
__ ld(at, MemOperand(at, 6 * Assembler::kInstrSize));
__ jalr(at);
__ nop(); // Branch delay slot nop.
__ bc(&done);
for (int i = 0; i < kNumCases; ++i) {
__ dd(&labels[i]);
}
}
for (int i = 0; i < kNumCases; ++i) {
__ bind(&labels[i]);
__ lui(v0, (values[i] >> 16) & 0xffff);
__ ori(v0, v0, values[i] & 0xffff);
__ jr(ra);
__ nop();
}
__ bind(&done);
__ ld(ra, MemOperand(sp));
__ daddiu(sp, sp, 8);
__ jr(ra);
__ nop();
CodeDesc desc;
masm->GetCode(&desc);
Handle<Code> code = isolate->factory()->NewCode(
desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
#ifdef OBJECT_PRINT
code->Print(std::cout);
#endif
F1 f = FUNCTION_CAST<F1>(code->entry());
for (int i = 0; i < kNumCases; ++i) {
int64_t res = reinterpret_cast<int64_t>(
CALL_GENERATED_CODE(isolate, f, i, 0, 0, 0, 0));
::printf("f(%d) = %" PRId64 "\n", i, res);
CHECK_EQ(values[i], res);
}
}
static uint64_t run_lsa(uint32_t rt, uint32_t rs, int8_t sa) {
Isolate* isolate = CcTest::i_isolate();
HandleScope scope(isolate);