[arm64] Emit CBZ for deoptimisations.

Emit the compare and branch on zero (CBZ) instruction when
possible for deoptimisations, as we do for normal branches.

BUG=

Review-Url: https://codereview.chromium.org/2448113002
Cr-Commit-Position: refs/heads/master@{#40568}
This commit is contained in:
georgia.kouveli 2016-10-25 08:23:49 -07:00 committed by Commit bot
parent 99e845cc9f
commit 3836fc074b
3 changed files with 41 additions and 9 deletions

View File

@ -2152,6 +2152,20 @@ FlagsCondition MapForCbz(FlagsCondition cond) {
}
}
void EmitBranchOrDeoptimize(InstructionSelector* selector,
InstructionCode opcode, InstructionOperand value,
FlagsContinuation* cont) {
Arm64OperandGenerator g(selector);
if (cont->IsBranch()) {
selector->Emit(cont->Encode(opcode), g.NoOutput(), value,
g.Label(cont->true_block()), g.Label(cont->false_block()));
} else {
DCHECK(cont->IsDeoptimize());
selector->EmitDeoptimize(cont->Encode(opcode), g.NoOutput(), value,
cont->reason(), cont->frame_state());
}
}
// Try to emit TBZ, TBNZ, CBZ or CBNZ for certain comparisons of {node}
// against zero, depending on the condition.
bool TryEmitCbzOrTbz(InstructionSelector* selector, Node* node, Node* user,
@ -2160,12 +2174,16 @@ bool TryEmitCbzOrTbz(InstructionSelector* selector, Node* node, Node* user,
USE(m_user);
DCHECK(m_user.right().Is(0) || m_user.left().Is(0));
// Only handle branches.
if (!cont->IsBranch()) return false;
// Only handle branches and deoptimisations.
if (!cont->IsBranch() && !cont->IsDeoptimize()) return false;
switch (cond) {
case kSignedLessThan:
case kSignedGreaterThanOrEqual: {
// We don't generate TBZ/TBNZ for deoptimisations, as they have a
// shorter range than conditional branches and generating them for
// deoptimisations results in more veneers.
if (cont->IsDeoptimize()) return false;
Arm64OperandGenerator g(selector);
cont->Overwrite(MapForTbz(cond));
Int32Matcher m(node);
@ -2192,9 +2210,8 @@ bool TryEmitCbzOrTbz(InstructionSelector* selector, Node* node, Node* user,
case kUnsignedGreaterThan: {
Arm64OperandGenerator g(selector);
cont->Overwrite(MapForCbz(cond));
selector->Emit(cont->Encode(kArm64CompareAndBranch32), g.NoOutput(),
g.UseRegister(node), g.Label(cont->true_block()),
g.Label(cont->false_block()));
EmitBranchOrDeoptimize(selector, kArm64CompareAndBranch32,
g.UseRegister(node), cont);
return true;
}
default:
@ -2380,10 +2397,10 @@ void VisitWordCompareZero(InstructionSelector* selector, Node* user,
kLogical64Imm);
}
// Merge the Word64Equal(x, 0) comparison into a cbz instruction.
if (cont->IsBranch()) {
selector->Emit(cont->Encode(kArm64CompareAndBranch), g.NoOutput(),
g.UseRegister(left), g.Label(cont->true_block()),
g.Label(cont->false_block()));
if (cont->IsBranch() || cont->IsDeoptimize()) {
EmitBranchOrDeoptimize(selector,
cont->Encode(kArm64CompareAndBranch),
g.UseRegister(left), cont);
return;
}
}

View File

@ -2017,6 +2017,18 @@ void InstructionSelector::VisitReturn(Node* ret) {
}
}
Instruction* InstructionSelector::EmitDeoptimize(InstructionCode opcode,
InstructionOperand output,
InstructionOperand a,
DeoptimizeReason reason,
Node* frame_state) {
size_t output_count = output.IsInvalid() ? 0 : 1;
InstructionOperand inputs[] = {a};
size_t input_count = arraysize(inputs);
return EmitDeoptimize(opcode, output_count, &output, input_count, inputs,
reason, frame_state);
}
Instruction* InstructionSelector::EmitDeoptimize(
InstructionCode opcode, InstructionOperand output, InstructionOperand a,
InstructionOperand b, DeoptimizeReason reason, Node* frame_state) {

View File

@ -110,6 +110,9 @@ class V8_EXPORT_PRIVATE InstructionSelector final {
// ===== Architecture-independent deoptimization exit emission methods. ======
// ===========================================================================
Instruction* EmitDeoptimize(InstructionCode opcode, InstructionOperand output,
InstructionOperand a, DeoptimizeReason reason,
Node* frame_state);
Instruction* EmitDeoptimize(InstructionCode opcode, InstructionOperand output,
InstructionOperand a, InstructionOperand b,
DeoptimizeReason reason, Node* frame_state);