Commit 49a40c22 authored by dusan.m.milosavljevic's avatar dusan.m.milosavljevic Committed by Commit bot

MIPS:[turbofan] Improve boolean materialization compares.

Additionally, improve immediate operand matching for branches
to avoid duplicated constant loading.

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

Cr-Commit-Position: refs/heads/master@{#30604}
parent c7720104
...@@ -49,6 +49,7 @@ Christopher A. Taylor <chris@gameclosure.com> ...@@ -49,6 +49,7 @@ Christopher A. Taylor <chris@gameclosure.com>
Daniel Andersson <kodandersson@gmail.com> Daniel Andersson <kodandersson@gmail.com>
Daniel James <dnljms@gmail.com> Daniel James <dnljms@gmail.com>
Douglas Crosher <dtc-v8@scieneer.com> Douglas Crosher <dtc-v8@scieneer.com>
Dusan Milosavljevic <dusan.m.milosavljevic@gmail.com>
Erich Ocean <erich.ocean@me.com> Erich Ocean <erich.ocean@me.com>
Fedor Indutny <fedor@indutny.com> Fedor Indutny <fedor@indutny.com>
Felix Geisendörfer <haimuiba@gmail.com> Felix Geisendörfer <haimuiba@gmail.com>
......
...@@ -904,15 +904,12 @@ void CodeGenerator::AssembleArchBranch(Instruction* instr, BranchInfo* branch) { ...@@ -904,15 +904,12 @@ void CodeGenerator::AssembleArchBranch(Instruction* instr, BranchInfo* branch) {
Label* tlabel = branch->true_label; Label* tlabel = branch->true_label;
Label* flabel = branch->false_label; Label* flabel = branch->false_label;
Condition cc = kNoCondition; Condition cc = kNoCondition;
// MIPS does not have condition code flags, so compare and branch are // MIPS does not have condition code flags, so compare and branch are
// implemented differently than on the other arch's. The compare operations // implemented differently than on the other arch's. The compare operations
// emit mips pseudo-instructions, which are handled here by branch // emit mips pseudo-instructions, which are handled here by branch
// instructions that do the actual comparison. Essential that the input // instructions that do the actual comparison. Essential that the input
// registers to compare pseudo-op are not modified before this branch op, as // registers to compare pseudo-op are not modified before this branch op, as
// they are tested here. // they are tested here.
// TODO(plind): Add CHECK() to ensure that test/cmp and this branch were
// not separated by other instructions.
if (instr->arch_opcode() == kMipsTst) { if (instr->arch_opcode() == kMipsTst) {
cc = FlagsConditionToConditionTst(branch->condition); cc = FlagsConditionToConditionTst(branch->condition);
...@@ -964,40 +961,104 @@ void CodeGenerator::AssembleArchBoolean(Instruction* instr, ...@@ -964,40 +961,104 @@ void CodeGenerator::AssembleArchBoolean(Instruction* instr,
DCHECK_NE(0u, instr->OutputCount()); DCHECK_NE(0u, instr->OutputCount());
Register result = i.OutputRegister(instr->OutputCount() - 1); Register result = i.OutputRegister(instr->OutputCount() - 1);
Condition cc = kNoCondition; Condition cc = kNoCondition;
// MIPS does not have condition code flags, so compare and branch are // MIPS does not have condition code flags, so compare and branch are
// implemented differently than on the other arch's. The compare operations // implemented differently than on the other arch's. The compare operations
// emit mips psuedo-instructions, which are checked and handled here. // emit mips psuedo-instructions, which are checked and handled here.
// For materializations, we use delay slot to set the result true, and
// in the false case, where we fall thru the branch, we reset the result
// false.
if (instr->arch_opcode() == kMipsTst) { if (instr->arch_opcode() == kMipsTst) {
cc = FlagsConditionToConditionTst(condition); cc = FlagsConditionToConditionTst(condition);
__ And(at, i.InputRegister(0), i.InputOperand(1)); __ And(kScratchReg, i.InputRegister(0), i.InputOperand(1));
__ Branch(USE_DELAY_SLOT, &done, cc, at, Operand(zero_reg)); __ xori(result, zero_reg, 1); // Create 1 for true.
__ li(result, Operand(1)); // In delay slot. if (IsMipsArchVariant(kMips32r6)) {
if (cc == eq) {
__ seleqz(result, result, kScratchReg);
} else {
__ selnez(result, result, kScratchReg);
}
} else {
if (cc == eq) {
__ Movn(result, zero_reg, kScratchReg);
} else {
__ Movz(result, zero_reg, kScratchReg);
}
}
return;
} else if (instr->arch_opcode() == kMipsAddOvf || } else if (instr->arch_opcode() == kMipsAddOvf ||
instr->arch_opcode() == kMipsSubOvf) { instr->arch_opcode() == kMipsSubOvf) {
// kMipsAddOvf, SubOvf emits negative result to 'kCompareReg' on overflow. // kMipsAddOvf, SubOvf emits negative result to 'kCompareReg' on overflow.
cc = FlagsConditionToConditionOvf(condition); cc = FlagsConditionToConditionOvf(condition);
__ Branch(USE_DELAY_SLOT, &done, cc, kCompareReg, Operand(zero_reg)); // Return 1 on overflow.
__ li(result, Operand(1)); // In delay slot. __ Slt(result, kCompareReg, Operand(zero_reg));
if (cc == ge) // Invert result on not overflow.
__ xori(result, result, 1);
return;
} else if (instr->arch_opcode() == kMipsCmp) { } else if (instr->arch_opcode() == kMipsCmp) {
Register left = i.InputRegister(0);
Operand right = i.InputOperand(1);
cc = FlagsConditionToConditionCmp(condition); cc = FlagsConditionToConditionCmp(condition);
__ Branch(USE_DELAY_SLOT, &done, cc, left, right); switch (cc) {
__ li(result, Operand(1)); // In delay slot. case eq:
case ne: {
Register left = i.InputRegister(0);
Operand right = i.InputOperand(1);
__ Subu(kScratchReg, left, right);
__ xori(result, zero_reg, 1);
if (IsMipsArchVariant(kMips32r6)) {
if (cc == eq) {
__ seleqz(result, result, kScratchReg);
} else {
__ selnez(result, result, kScratchReg);
}
} else {
if (cc == eq) {
__ Movn(result, zero_reg, kScratchReg);
} else {
__ Movz(result, zero_reg, kScratchReg);
}
}
} break;
case lt:
case ge: {
Register left = i.InputRegister(0);
Operand right = i.InputOperand(1);
__ Slt(result, left, right);
if (cc == ge) {
__ xori(result, result, 1);
}
} break;
case gt:
case le: {
Register left = i.InputRegister(1);
Operand right = i.InputOperand(0);
__ Slt(result, left, right);
if (cc == le) {
__ xori(result, result, 1);
}
} break;
case lo:
case hs: {
Register left = i.InputRegister(0);
Operand right = i.InputOperand(1);
__ Sltu(result, left, right);
if (cc == hs) {
__ xori(result, result, 1);
}
} break;
case hi:
case ls: {
Register left = i.InputRegister(1);
Operand right = i.InputOperand(0);
__ Sltu(result, left, right);
if (cc == ls) {
__ xori(result, result, 1);
}
} break;
default:
UNREACHABLE();
}
return;
} else if (instr->arch_opcode() == kMipsCmpD || } else if (instr->arch_opcode() == kMipsCmpD ||
instr->arch_opcode() == kMipsCmpS) { instr->arch_opcode() == kMipsCmpS) {
FPURegister left = i.InputDoubleRegister(0); FPURegister left = i.InputDoubleRegister(0);
FPURegister right = i.InputDoubleRegister(1); FPURegister right = i.InputDoubleRegister(1);
bool predicate; bool predicate;
FPUCondition cc = FlagsConditionToConditionCmpFPU(predicate, condition); FPUCondition cc = FlagsConditionToConditionCmpFPU(predicate, condition);
if (!IsMipsArchVariant(kMips32r6)) { if (!IsMipsArchVariant(kMips32r6)) {
...@@ -1032,11 +1093,6 @@ void CodeGenerator::AssembleArchBoolean(Instruction* instr, ...@@ -1032,11 +1093,6 @@ void CodeGenerator::AssembleArchBoolean(Instruction* instr,
TRACE_UNIMPL(); TRACE_UNIMPL();
UNIMPLEMENTED(); UNIMPLEMENTED();
} }
// Fallthrough case is the false materialization.
__ bind(&false_value);
__ li(result, Operand(0));
__ bind(&done);
} }
......
...@@ -775,7 +775,6 @@ static void VisitCompare(InstructionSelector* selector, InstructionCode opcode, ...@@ -775,7 +775,6 @@ static void VisitCompare(InstructionSelector* selector, InstructionCode opcode,
g.Label(cont->true_block()), g.Label(cont->false_block())); g.Label(cont->true_block()), g.Label(cont->false_block()));
} else { } else {
DCHECK(cont->IsSet()); DCHECK(cont->IsSet());
// TODO(plind): Revisit and test this path.
selector->Emit(opcode, g.DefineAsRegister(cont->result()), left, right); selector->Emit(opcode, g.DefineAsRegister(cont->result()), left, right);
} }
} }
...@@ -813,12 +812,32 @@ void VisitWordCompare(InstructionSelector* selector, Node* node, ...@@ -813,12 +812,32 @@ void VisitWordCompare(InstructionSelector* selector, Node* node,
// Match immediates on left or right side of comparison. // Match immediates on left or right side of comparison.
if (g.CanBeImmediate(right, opcode)) { if (g.CanBeImmediate(right, opcode)) {
VisitCompare(selector, opcode, g.UseRegister(left), g.UseImmediate(right), switch (cont->condition()) {
cont); case kSignedLessThan:
case kSignedGreaterThanOrEqual:
case kUnsignedLessThan:
case kUnsignedGreaterThanOrEqual:
VisitCompare(selector, opcode, g.UseRegister(left),
g.UseImmediate(right), cont);
break;
default:
VisitCompare(selector, opcode, g.UseRegister(left),
g.UseRegister(right), cont);
}
} else if (g.CanBeImmediate(left, opcode)) { } else if (g.CanBeImmediate(left, opcode)) {
if (!commutative) cont->Commute(); if (!commutative) cont->Commute();
VisitCompare(selector, opcode, g.UseRegister(right), g.UseImmediate(left), switch (cont->condition()) {
cont); case kSignedLessThan:
case kSignedGreaterThanOrEqual:
case kUnsignedLessThan:
case kUnsignedGreaterThanOrEqual:
VisitCompare(selector, opcode, g.UseRegister(right),
g.UseImmediate(left), cont);
break;
default:
VisitCompare(selector, opcode, g.UseRegister(right),
g.UseRegister(left), cont);
}
} else { } else {
VisitCompare(selector, opcode, g.UseRegister(left), g.UseRegister(right), VisitCompare(selector, opcode, g.UseRegister(left), g.UseRegister(right),
cont); cont);
......
...@@ -975,7 +975,6 @@ void CodeGenerator::AssembleArchBranch(Instruction* instr, BranchInfo* branch) { ...@@ -975,7 +975,6 @@ void CodeGenerator::AssembleArchBranch(Instruction* instr, BranchInfo* branch) {
Label* tlabel = branch->true_label; Label* tlabel = branch->true_label;
Label* flabel = branch->false_label; Label* flabel = branch->false_label;
Condition cc = kNoCondition; Condition cc = kNoCondition;
// MIPS does not have condition code flags, so compare and branch are // MIPS does not have condition code flags, so compare and branch are
// implemented differently than on the other arch's. The compare operations // implemented differently than on the other arch's. The compare operations
// emit mips psuedo-instructions, which are handled here by branch // emit mips psuedo-instructions, which are handled here by branch
...@@ -1034,38 +1033,105 @@ void CodeGenerator::AssembleArchBoolean(Instruction* instr, ...@@ -1034,38 +1033,105 @@ void CodeGenerator::AssembleArchBoolean(Instruction* instr,
DCHECK_NE(0u, instr->OutputCount()); DCHECK_NE(0u, instr->OutputCount());
Register result = i.OutputRegister(instr->OutputCount() - 1); Register result = i.OutputRegister(instr->OutputCount() - 1);
Condition cc = kNoCondition; Condition cc = kNoCondition;
// MIPS does not have condition code flags, so compare and branch are // MIPS does not have condition code flags, so compare and branch are
// implemented differently than on the other arch's. The compare operations // implemented differently than on the other arch's. The compare operations
// emit mips pseudo-instructions, which are checked and handled here. // emit mips pseudo-instructions, which are checked and handled here.
// For materializations, we use delay slot to set the result true, and
// in the false case, where we fall through the branch, we reset the result
// false.
if (instr->arch_opcode() == kMips64Tst) { if (instr->arch_opcode() == kMips64Tst) {
cc = FlagsConditionToConditionTst(condition); cc = FlagsConditionToConditionTst(condition);
__ And(at, i.InputRegister(0), i.InputOperand(1)); __ And(kScratchReg, i.InputRegister(0), i.InputOperand(1));
__ Branch(USE_DELAY_SLOT, &done, cc, at, Operand(zero_reg)); __ xori(result, zero_reg, 1); // Create 1 for true.
__ li(result, Operand(1)); // In delay slot. if (kArchVariant == kMips64r6) {
if (cc == eq) {
__ seleqz(result, result, kScratchReg);
} else {
__ selnez(result, result, kScratchReg);
}
} else {
if (cc == eq) {
__ Movn(result, zero_reg, kScratchReg);
} else {
__ Movz(result, zero_reg, kScratchReg);
}
}
return;
} else if (instr->arch_opcode() == kMips64Dadd || } else if (instr->arch_opcode() == kMips64Dadd ||
instr->arch_opcode() == kMips64Dsub) { instr->arch_opcode() == kMips64Dsub) {
cc = FlagsConditionToConditionOvf(condition); cc = FlagsConditionToConditionOvf(condition);
__ dsra32(kScratchReg, i.OutputRegister(), 0); // Check for overflow creates 1 or 0 for result.
__ sra(at, i.OutputRegister(), 31); __ dsrl32(kScratchReg, i.OutputRegister(), 31);
__ Branch(USE_DELAY_SLOT, &done, cc, at, Operand(kScratchReg)); __ srl(at, i.OutputRegister(), 31);
__ li(result, Operand(1)); // In delay slot. __ xor_(result, kScratchReg, at);
if (cc == eq) // Toggle result for not overflow.
__ xori(result, result, 1);
return;
} else if (instr->arch_opcode() == kMips64Cmp) { } else if (instr->arch_opcode() == kMips64Cmp) {
Register left = i.InputRegister(0);
Operand right = i.InputOperand(1);
cc = FlagsConditionToConditionCmp(condition); cc = FlagsConditionToConditionCmp(condition);
__ Branch(USE_DELAY_SLOT, &done, cc, left, right); switch (cc) {
__ li(result, Operand(1)); // In delay slot. case eq:
case ne: {
Register left = i.InputRegister(0);
Operand right = i.InputOperand(1);
__ Dsubu(kScratchReg, left, right);
__ xori(result, zero_reg, 1);
if (kArchVariant == kMips64r6) {
if (cc == eq) {
__ seleqz(result, result, kScratchReg);
} else {
__ selnez(result, result, kScratchReg);
}
} else {
if (cc == eq) {
__ Movn(result, zero_reg, kScratchReg);
} else {
__ Movz(result, zero_reg, kScratchReg);
}
}
} break;
case lt:
case ge: {
Register left = i.InputRegister(0);
Operand right = i.InputOperand(1);
__ Slt(result, left, right);
if (cc == ge) {
__ xori(result, result, 1);
}
} break;
case gt:
case le: {
Register left = i.InputRegister(1);
Operand right = i.InputOperand(0);
__ Slt(result, left, right);
if (cc == le) {
__ xori(result, result, 1);
}
} break;
case lo:
case hs: {
Register left = i.InputRegister(0);
Operand right = i.InputOperand(1);
__ Sltu(result, left, right);
if (cc == hs) {
__ xori(result, result, 1);
}
} break;
case hi:
case ls: {
Register left = i.InputRegister(1);
Operand right = i.InputOperand(0);
__ Sltu(result, left, right);
if (cc == ls) {
__ xori(result, result, 1);
}
} break;
default:
UNREACHABLE();
}
return;
} else if (instr->arch_opcode() == kMips64CmpD || } else if (instr->arch_opcode() == kMips64CmpD ||
instr->arch_opcode() == kMips64CmpS) { instr->arch_opcode() == kMips64CmpS) {
FPURegister left = i.InputDoubleRegister(0); FPURegister left = i.InputDoubleRegister(0);
FPURegister right = i.InputDoubleRegister(1); FPURegister right = i.InputDoubleRegister(1);
bool predicate; bool predicate;
FPUCondition cc = FlagsConditionToConditionCmpFPU(predicate, condition); FPUCondition cc = FlagsConditionToConditionCmpFPU(predicate, condition);
if (kArchVariant != kMips64r6) { if (kArchVariant != kMips64r6) {
...@@ -1100,10 +1166,6 @@ void CodeGenerator::AssembleArchBoolean(Instruction* instr, ...@@ -1100,10 +1166,6 @@ void CodeGenerator::AssembleArchBoolean(Instruction* instr,
TRACE_UNIMPL(); TRACE_UNIMPL();
UNIMPLEMENTED(); UNIMPLEMENTED();
} }
// Fallthru case is the false materialization.
__ bind(&false_value);
__ li(result, Operand(static_cast<int64_t>(0)));
__ bind(&done);
} }
......
...@@ -967,12 +967,32 @@ void VisitWordCompare(InstructionSelector* selector, Node* node, ...@@ -967,12 +967,32 @@ void VisitWordCompare(InstructionSelector* selector, Node* node,
// Match immediates on left or right side of comparison. // Match immediates on left or right side of comparison.
if (g.CanBeImmediate(right, opcode)) { if (g.CanBeImmediate(right, opcode)) {
VisitCompare(selector, opcode, g.UseRegister(left), g.UseImmediate(right), switch (cont->condition()) {
cont); case kSignedLessThan:
case kSignedGreaterThanOrEqual:
case kUnsignedLessThan:
case kUnsignedGreaterThanOrEqual:
VisitCompare(selector, opcode, g.UseRegister(left),
g.UseImmediate(right), cont);
break;
default:
VisitCompare(selector, opcode, g.UseRegister(left),
g.UseRegister(right), cont);
}
} else if (g.CanBeImmediate(left, opcode)) { } else if (g.CanBeImmediate(left, opcode)) {
if (!commutative) cont->Commute(); if (!commutative) cont->Commute();
VisitCompare(selector, opcode, g.UseRegister(right), g.UseImmediate(left), switch (cont->condition()) {
cont); case kSignedLessThan:
case kSignedGreaterThanOrEqual:
case kUnsignedLessThan:
case kUnsignedGreaterThanOrEqual:
VisitCompare(selector, opcode, g.UseRegister(right),
g.UseImmediate(left), cont);
break;
default:
VisitCompare(selector, opcode, g.UseRegister(right),
g.UseRegister(left), cont);
}
} else { } else {
VisitCompare(selector, opcode, g.UseRegister(left), g.UseRegister(right), VisitCompare(selector, opcode, g.UseRegister(left), g.UseRegister(right),
cont); cont);
......
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