Commit 2c63060f authored by ivica.bogosavljevic's avatar ivica.bogosavljevic Committed by Commit bot

MIPS64: r6 compact branch optimization.

Several ports to enable r6 compact branch optimizations on MIPS64

Port 3573d3cb

Original commit message:
MIPS: r6 compact branch optimization.

Port bddf8c9e

Original commit message:
MIPS: Fix trampoline pool handling in MacroAssembler::BranchShort()

Port 6993cd0d

Original commit message:
MIPS: Fix 'MIPS:r6 compact branch optimization.'

Jic and jialc compact branch ops are fixed as they does
not have 'forbidden slot' restriction. Also COP1 branches
(CTI instructions) added to IsForbiddenAfterBranchInstr().

Port bb332195

Original commit message:
MIPS: Fix trampoline pool handling in MacroAssembler::BranchShort()

Port c91bcf71

Original commit message:
MIPS: Fix trampoline pool handling in MacroAssembler::BranchShort()
for r6.

BUG=

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

Cr-Commit-Position: refs/heads/master@{#33136}
parent f7c7cb8f
......@@ -1646,9 +1646,7 @@ void CodeGenerator::AssembleArchTableSwitch(Instruction* instr) {
__ Branch(GetLabel(i.InputRpo(1)), hs, input, Operand(case_count));
__ BlockTrampolinePoolFor(static_cast<int>(case_count) * 2 + 7);
// Ensure that dd-ed labels use 8 byte aligned addresses.
if ((masm()->pc_offset() & 7) != 0) {
__ nop();
}
__ Align(8);
__ bal(&here);
__ dsll(at, input, 3); // Branch delay slot.
__ bind(&here);
......
......@@ -863,8 +863,6 @@ void PatchInlinedSmiCode(Isolate* isolate, Address address,
Address patch_address =
andi_instruction_address - delta * Instruction::kInstrSize;
Instr instr_at_patch = Assembler::instr_at(patch_address);
Instr branch_instr =
Assembler::instr_at(patch_address + Instruction::kInstrSize);
// This is patching a conditional "jump if not smi/jump if smi" site.
// Enabling by changing from
// andi at, rx, 0
......@@ -884,13 +882,44 @@ void PatchInlinedSmiCode(Isolate* isolate, Address address,
DCHECK(Assembler::IsAndImmediate(instr_at_patch));
patcher.masm()->andi(at, reg, 0);
}
Instr branch_instr =
Assembler::instr_at(patch_address + Instruction::kInstrSize);
DCHECK(Assembler::IsBranch(branch_instr));
if (Assembler::IsBeq(branch_instr)) {
patcher.ChangeBranchCondition(ne);
} else {
DCHECK(Assembler::IsBne(branch_instr));
patcher.ChangeBranchCondition(eq);
uint32_t opcode = Assembler::GetOpcodeField(branch_instr);
// Currently only the 'eq' and 'ne' cond values are supported and the simple
// branch instructions and their r6 variants (with opcode being the branch
// type). There are some special cases (see Assembler::IsBranch()) so
// extending this would be tricky.
DCHECK(opcode == BEQ || // BEQ
opcode == BNE || // BNE
opcode == POP10 || // BEQC
opcode == POP30 || // BNEC
opcode == POP66 || // BEQZC
opcode == POP76); // BNEZC
switch (opcode) {
case BEQ:
opcode = BNE; // change BEQ to BNE.
break;
case POP10:
opcode = POP30; // change BEQC to BNEC.
break;
case POP66:
opcode = POP76; // change BEQZC to BNEZC.
break;
case BNE:
opcode = BEQ; // change BNE to BEQ.
break;
case POP30:
opcode = POP10; // change BNEC to BEQC.
break;
case POP76:
opcode = POP66; // change BNEZC to BEQZC.
break;
default:
UNIMPLEMENTED();
}
patcher.ChangeBranchCondition(branch_instr, opcode);
}
} // namespace internal
} // namespace v8
......
......@@ -438,12 +438,24 @@ void Assembler::CheckTrampolinePoolQuick(int extra_instructions) {
}
void Assembler::emit(Instr x) {
void Assembler::emit(Instr x, CompactBranchType is_compact_branch) {
if (!is_buffer_growth_blocked()) {
CheckBuffer();
}
if (IsPrevInstrCompactBranch()) {
if (Instruction::IsForbiddenAfterBranchInstr(x)) {
// Nop instruction to preceed a CTI in forbidden slot:
Instr nop = SPECIAL | SLL;
*reinterpret_cast<Instr*>(pc_) = nop;
pc_ += kInstrSize;
}
ClearCompactBranchState();
}
*reinterpret_cast<Instr*>(pc_) = x;
pc_ += kInstrSize;
if (is_compact_branch == CompactBranchType::COMPACT_BRANCH) {
EmittedCompactBranchInstruction();
}
CheckTrampolinePoolQuick();
}
......@@ -452,6 +464,14 @@ void Assembler::emit(uint64_t x) {
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();
}
*reinterpret_cast<uint64_t*>(pc_) = x;
pc_ += kInstrSize * 2;
CheckTrampolinePoolQuick();
......
This diff is collapsed.
This diff is collapsed.
......@@ -126,24 +126,28 @@ int FPURegisters::Number(const char* name) {
// -----------------------------------------------------------------------------
// Instructions.
bool Instruction::IsForbiddenInBranchDelay() const {
const int op = OpcodeFieldRaw();
switch (op) {
bool Instruction::IsForbiddenAfterBranchInstr(Instr instr) {
Opcode opcode = static_cast<Opcode>(instr & kOpcodeMask);
switch (opcode) {
case J:
case JAL:
case BEQ:
case BNE:
case BLEZ:
case BGTZ:
case BLEZ: // POP06 bgeuc/bleuc, blezalc, bgezalc
case BGTZ: // POP07 bltuc/bgtuc, bgtzalc, bltzalc
case BEQL:
case BNEL:
case BLEZL:
case BGTZL:
case BLEZL: // POP26 bgezc, blezc, bgec/blec
case BGTZL: // POP27 bgtzc, bltzc, bltc/bgtc
case BC:
case BALC:
case POP10: // beqzalc, bovc, beqc
case POP30: // bnezalc, bnvc, bnec
case POP66: // beqzc, jic
case POP76: // bnezc, jialc
return true;
case REGIMM:
switch (RtFieldRaw()) {
switch (instr & kRtFieldMask) {
case BLTZ:
case BGEZ:
case BLTZAL:
......@@ -154,7 +158,7 @@ bool Instruction::IsForbiddenInBranchDelay() const {
}
break;
case SPECIAL:
switch (FunctionFieldRaw()) {
switch (instr & kFunctionFieldMask) {
case JR:
case JALR:
return true;
......@@ -162,6 +166,17 @@ bool Instruction::IsForbiddenInBranchDelay() const {
return false;
}
break;
case COP1:
switch (instr & kRsFieldMask) {
case BC1:
case BC1EQZ:
case BC1NEZ:
return true;
break;
default:
return false;
}
break;
default:
return false;
}
......@@ -169,8 +184,7 @@ bool Instruction::IsForbiddenInBranchDelay() const {
bool Instruction::IsLinkingInstruction() const {
const int op = OpcodeFieldRaw();
switch (op) {
switch (OpcodeFieldRaw()) {
case JAL:
return true;
case POP76:
......
This diff is collapsed.
......@@ -92,7 +92,7 @@ class Decoder {
void PrintXImm19(Instruction* instr);
void PrintSImm19(Instruction* instr);
void PrintXImm21(Instruction* instr);
void PrintSImm21(Instruction* instr);
void PrintPCImm21(Instruction* instr, int delta_pc, int n_bits);
void PrintXImm26(Instruction* instr);
void PrintSImm26(Instruction* instr);
......@@ -345,6 +345,16 @@ void Decoder::PrintXImm21(Instruction* instr) {
}
// Print 21-bit signed immediate value.
void Decoder::PrintSImm21(Instruction* instr) {
int32_t imm21 = instr->Imm21Value();
// set sign
imm21 <<= (32 - kImm21Bits);
imm21 >>= (32 - kImm21Bits);
out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d", imm21);
}
// Print absoulte address for 21-bit offset or immediate value.
// The absolute address is calculated according following expression:
// PC + delta_pc + (offset << n_bits)
......@@ -622,6 +632,10 @@ int Decoder::FormatOption(Instruction* instr, const char* format) {
} else if (format[3] == '2' && format[4] == '1') {
DCHECK(STRING_STARTS_WITH(format, "imm21"));
switch (format[5]) {
case 's':
DCHECK(STRING_STARTS_WITH(format, "imm21s"));
PrintSImm21(instr);
break;
case 'x':
DCHECK(STRING_STARTS_WITH(format, "imm21x"));
PrintXImm21(instr);
......@@ -1678,14 +1692,14 @@ void Decoder::DecodeTypeImmediate(Instruction* instr) {
if (instr->RsValue() == JIC) {
Format(instr, "jic 'rt, 'imm16s");
} else {
Format(instr, "beqzc 'rs, 'imm21x -> 'imm21p4s2");
Format(instr, "beqzc 'rs, 'imm21s -> 'imm21p4s2");
}
break;
case POP76:
if (instr->RsValue() == JIALC) {
Format(instr, "jialc 'rt, 'imm16x");
Format(instr, "jialc 'rt, 'imm16s");
} else {
Format(instr, "bnezc 'rs, 'imm21x -> 'imm21p4s2");
Format(instr, "bnezc 'rs, 'imm21s -> 'imm21p4s2");
}
break;
// ------------- Arithmetic instructions.
......@@ -1693,13 +1707,18 @@ void Decoder::DecodeTypeImmediate(Instruction* instr) {
if (kArchVariant != kMips64r6) {
Format(instr, "addi 'rt, 'rs, 'imm16s");
} else {
// Check if BOVC or BEQC instruction.
if (instr->RsValue() >= instr->RtValue()) {
int rs_reg = instr->RsValue();
int rt_reg = instr->RtValue();
// Check if BOVC, BEQZALC or BEQC instruction.
if (rs_reg >= rt_reg) {
Format(instr, "bovc 'rs, 'rt, 'imm16s -> 'imm16p4s2");
} else if (instr->RsValue() < instr->RtValue()) {
Format(instr, "beqc 'rs, 'rt, 'imm16s -> 'imm16p4s2");
} else {
UNREACHABLE();
DCHECK(rt_reg > 0);
if (rs_reg == 0) {
Format(instr, "beqzalc 'rt, 'imm16s -> 'imm16p4s2");
} else {
Format(instr, "beqc 'rs, 'rt, 'imm16s -> 'imm16p4s2");
}
}
}
break;
......@@ -1707,13 +1726,18 @@ void Decoder::DecodeTypeImmediate(Instruction* instr) {
if (kArchVariant != kMips64r6) {
Format(instr, "daddi 'rt, 'rs, 'imm16s");
} else {
// Check if BNVC or BNEC instruction.
if (instr->RsValue() >= instr->RtValue()) {
int rs_reg = instr->RsValue();
int rt_reg = instr->RtValue();
// Check if BNVC, BNEZALC or BNEC instruction.
if (rs_reg >= rt_reg) {
Format(instr, "bnvc 'rs, 'rt, 'imm16s -> 'imm16p4s2");
} else if (instr->RsValue() < instr->RtValue()) {
Format(instr, "bnec 'rs, 'rt, 'imm16s -> 'imm16p4s2");
} else {
UNREACHABLE();
DCHECK(rt_reg > 0);
if (rs_reg == 0) {
Format(instr, "bnezalc 'rt, 'imm16s -> 'imm16p4s2");
} else {
Format(instr, "bnec 'rs, 'rt, 'imm16s -> 'imm16p4s2");
}
}
}
break;
......
This diff is collapsed.
......@@ -190,7 +190,7 @@ class MacroAssembler: public Assembler {
#define DECLARE_BRANCH_PROTOTYPES(Name) \
DECLARE_NORELOC_PROTOTYPE(Name, Label*) \
DECLARE_NORELOC_PROTOTYPE(Name, int16_t)
DECLARE_NORELOC_PROTOTYPE(Name, int32_t)
DECLARE_BRANCH_PROTOTYPES(Branch)
DECLARE_BRANCH_PROTOTYPES(BranchAndLink)
......@@ -227,6 +227,8 @@ class MacroAssembler: public Assembler {
Ret(cond, rs, rt, bd);
}
bool IsNear(Label* L, Condition cond, int rs_reg);
void Branch(Label* L,
Condition cond,
Register rs,
......@@ -1772,16 +1774,32 @@ const Operand& rt = Operand(zero_reg), BranchDelaySlot bd = PROTECT
int num_reg_arguments,
int num_double_arguments);
void BranchAndLinkShort(int16_t offset, BranchDelaySlot bdslot = PROTECT);
void BranchAndLinkShort(int16_t offset, Condition cond, Register rs,
const Operand& rt,
BranchDelaySlot bdslot = PROTECT);
inline Register GetRtAsRegisterHelper(const Operand& rt, Register scratch);
inline int32_t GetOffset(int32_t offset, Label* L, OffsetSize bits);
void BranchShortHelperR6(int32_t offset, Label* L);
void BranchShortHelper(int16_t offset, Label* L, BranchDelaySlot bdslot);
bool BranchShortHelperR6(int32_t offset, Label* L, Condition cond,
Register rs, const Operand& rt);
bool BranchShortHelper(int16_t offset, Label* L, Condition cond, Register rs,
const Operand& rt, BranchDelaySlot bdslot);
bool BranchShortCheck(int32_t offset, Label* L, Condition cond, Register rs,
const Operand& rt, BranchDelaySlot bdslot);
void BranchAndLinkShortHelperR6(int32_t offset, Label* L);
void BranchAndLinkShortHelper(int16_t offset, Label* L,
BranchDelaySlot bdslot);
void BranchAndLinkShort(int32_t offset, BranchDelaySlot bdslot = PROTECT);
void BranchAndLinkShort(Label* L, BranchDelaySlot bdslot = PROTECT);
void BranchAndLinkShort(Label* L, Condition cond, Register rs,
const Operand& rt,
BranchDelaySlot bdslot = PROTECT);
void J(Label* L, BranchDelaySlot bdslot);
void Jal(Label* L, BranchDelaySlot bdslot);
bool BranchAndLinkShortHelperR6(int32_t offset, Label* L, Condition cond,
Register rs, const Operand& rt);
bool BranchAndLinkShortHelper(int16_t offset, Label* L, Condition cond,
Register rs, const Operand& rt,
BranchDelaySlot bdslot);
bool BranchAndLinkShortCheck(int32_t offset, Label* L, Condition cond,
Register rs, const Operand& rt,
BranchDelaySlot bdslot);
void BranchLong(Label* L, BranchDelaySlot bdslot);
void BranchAndLinkLong(Label* L, BranchDelaySlot bdslot);
void Jr(Label* L, BranchDelaySlot bdslot);
void Jalr(Label* L, BranchDelaySlot bdslot);
......@@ -1866,7 +1884,7 @@ class CodePatcher {
// Change the condition part of an instruction leaving the rest of the current
// instruction unchanged.
void ChangeBranchCondition(Condition cond);
void ChangeBranchCondition(Instr current_instr, uint32_t new_opcode);
private:
byte* address_; // The address of the code being patched.
......
This diff is collapsed.
......@@ -392,6 +392,18 @@ class Simulator {
// Used for breakpoints and traps.
void SoftwareInterrupt(Instruction* instr);
// Compact branch guard.
void CheckForbiddenSlot(int64_t current_pc) {
Instruction* instr_after_compact_branch =
reinterpret_cast<Instruction*>(current_pc + Instruction::kInstrSize);
if (instr_after_compact_branch->IsForbiddenAfterBranch()) {
V8_Fatal(__FILE__, __LINE__,
"Error: Unexpected instruction 0x%08x immediately after a "
"compact branch instruction.",
*reinterpret_cast<uint32_t*>(instr_after_compact_branch));
}
}
// Stop helper functions.
bool IsWatchpoint(uint64_t code);
void PrintWatchpoint(uint64_t code);
......@@ -414,7 +426,7 @@ class Simulator {
return;
}
if (instr->IsForbiddenInBranchDelay()) {
if (instr->IsForbiddenAfterBranch()) {
V8_Fatal(__FILE__, __LINE__,
"Eror:Unexpected %i opcode in a branch delay slot.",
instr->OpcodeValue());
......
......@@ -38,12 +38,18 @@
using namespace v8::internal;
bool prev_instr_compact_branch = false;
bool DisassembleAndCompare(byte* pc, const char* compare_string) {
disasm::NameConverter converter;
disasm::Disassembler disasm(converter);
EmbeddedVector<char, 128> disasm_buffer;
if (prev_instr_compact_branch) {
disasm.InstructionDecode(disasm_buffer, pc);
pc += 4;
}
disasm.InstructionDecode(disasm_buffer, pc);
if (strcmp(compare_string, disasm_buffer.start()) != 0) {
......@@ -97,8 +103,14 @@ if (failure) { \
int pc_offset = assm.pc_offset(); \
byte *progcounter = &buffer[pc_offset]; \
char str_with_address[100]; \
prev_instr_compact_branch = assm.IsPrevInstrCompactBranch(); \
if (prev_instr_compact_branch) { \
snprintf(str_with_address, sizeof(str_with_address), "%s -> %p", \
compare_string, progcounter + 8 + (offset * 4)); \
} else { \
snprintf(str_with_address, sizeof(str_with_address), "%s -> %p", \
compare_string, progcounter + 4 + (offset * 4)); \
} \
assm.asm_; \
if (!DisassembleAndCompare(progcounter, str_with_address)) failure = true; \
}
......@@ -769,14 +781,6 @@ TEST(Type0) {
COMPARE(jic(t0, -32), "d80cffe0 jic t0, -32");
}
if (kArchVariant == kMips64r6) {
COMPARE_PC_REL_COMPACT(beqzc(a0, 16), "d8800010 beqzc a0, 0x10",
16);
COMPARE_PC_REL_COMPACT(beqzc(a0, 4), "d8800004 beqzc a0, 0x4", 4);
COMPARE_PC_REL_COMPACT(beqzc(a0, -32),
"d89fffe0 beqzc a0, 0x1fffe0", -32);
}
if (kArchVariant == kMips64r6) {
COMPARE(ldpc(v0, 256), "ec580100 ldpc v0, 256");
COMPARE(ldpc(a0, -1), "ec9bffff ldpc a0, -1");
......@@ -792,11 +796,11 @@ TEST(Type0) {
}
if (kArchVariant == kMips64r6) {
COMPARE(jialc(a0, -32768), "f8048000 jialc a0, 0x8000");
COMPARE(jialc(a0, -1), "f804ffff jialc a0, 0xffff");
COMPARE(jialc(v0, 0), "f8020000 jialc v0, 0x0");
COMPARE(jialc(s1, 1), "f8110001 jialc s1, 0x1");
COMPARE(jialc(a0, 32767), "f8047fff jialc a0, 0x7fff");
COMPARE(jialc(a0, -32768), "f8048000 jialc a0, -32768");
COMPARE(jialc(a0, -1), "f804ffff jialc a0, -1");
COMPARE(jialc(v0, 0), "f8020000 jialc v0, 0");
COMPARE(jialc(s1, 1), "f8110001 jialc s1, 1");
COMPARE(jialc(a0, 32767), "f8047fff jialc a0, 32767");
}
VERIFY_RUN();
......@@ -929,17 +933,17 @@ TEST(Type3) {
COMPARE_PC_REL_COMPACT(bnvc(a1, a0, -32768),
"60a48000 bnvc a1, a0, -32768", -32768);
COMPARE_PC_REL_COMPACT(beqzc(a0, 0), "d8800000 beqzc a0, 0x0", 0);
COMPARE_PC_REL_COMPACT(beqzc(a0, 0xfffff), // 0x0fffff == 1048575.
"d88fffff beqzc a0, 0xfffff", 1048575);
COMPARE_PC_REL_COMPACT(beqzc(a0, 0x100000), // 0x100000 == -1048576.
"d8900000 beqzc a0, 0x100000", -1048576);
COMPARE_PC_REL_COMPACT(beqzc(a0, 0), "d8800000 beqzc a0, 0", 0);
COMPARE_PC_REL_COMPACT(beqzc(a0, 1048575), // 0x0fffff == 1048575.
"d88fffff beqzc a0, 1048575", 1048575);
COMPARE_PC_REL_COMPACT(beqzc(a0, -1048576), // 0x100000 == -1048576.
"d8900000 beqzc a0, -1048576", -1048576);
COMPARE_PC_REL_COMPACT(bnezc(a0, 0), "f8800000 bnezc a0, 0x0", 0);
COMPARE_PC_REL_COMPACT(bnezc(a0, 0xfffff), // 0x0fffff == 1048575.
"f88fffff bnezc a0, 0xfffff", 1048575);
COMPARE_PC_REL_COMPACT(bnezc(a0, 0x100000), // 0x100000 == -1048576.
"f8900000 bnezc a0, 0x100000", -1048576);
COMPARE_PC_REL_COMPACT(bnezc(a0, 0), "f8800000 bnezc a0, 0", 0);
COMPARE_PC_REL_COMPACT(bnezc(a0, 1048575), // int21 maximal value.
"f88fffff bnezc a0, 1048575", 1048575);
COMPARE_PC_REL_COMPACT(bnezc(a0, -1048576), // int21 minimal value.
"f8900000 bnezc a0, -1048576", -1048576);
COMPARE_PC_REL_COMPACT(bc(-33554432), "ca000000 bc -33554432",
-33554432);
......@@ -961,8 +965,8 @@ TEST(Type3) {
"18858000 bgeuc a0, a1, -32768", -32768);
COMPARE_PC_REL_COMPACT(bgeuc(a0, a1, -1),
"1885ffff bgeuc a0, a1, -1", -1);
COMPARE_PC_REL_COMPACT(bgeuc(a0, a1, 1),
"18850001 bgeuc a0, a1, 1", 1);
COMPARE_PC_REL_COMPACT(bgeuc(a0, a1, 1), "18850001 bgeuc a0, a1, 1",
1);
COMPARE_PC_REL_COMPACT(bgeuc(a0, a1, 32767),
"18857fff bgeuc a0, a1, 32767", 32767);
......@@ -1076,8 +1080,8 @@ TEST(Type3) {
COMPARE_PC_REL_COMPACT(beqc(a0, a1, -32768),
"20858000 beqc a0, a1, -32768", -32768);
COMPARE_PC_REL_COMPACT(beqc(a0, a1, -1), "2085ffff beqc a0, a1, -1",
-1);
COMPARE_PC_REL_COMPACT(beqc(a0, a1, -1),
"2085ffff beqc a0, a1, -1", -1);
COMPARE_PC_REL_COMPACT(beqc(a0, a1, 1), "20850001 beqc a0, a1, 1",
1);
COMPARE_PC_REL_COMPACT(beqc(a0, a1, 32767),
......
......@@ -240,9 +240,6 @@ TEST(jump_tables4) {
__ daddiu(sp, sp, -8);
__ sd(ra, MemOperand(sp));
if ((masm->pc_offset() & 7) == 0) {
__ nop();
}
__ mov(v0, zero_reg);
......@@ -255,6 +252,7 @@ TEST(jump_tables4) {
__ addiu(v0, v0, 1);
}
__ Align(8);
Label done;
{
__ BlockTrampolinePoolFor(kNumCases * 2 + 6);
......
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