Commit c129aa4d authored by bmeurer's avatar bmeurer Committed by Commit bot

[turbofan] Introduce DeoptimizeIf And DeoptimizeUnless common operators.

These macro operators represent a conditional eager deoptimization exit
without explicit branching, which greatly reduces overhead of both
scheduling and register allocation, and thereby greatly reduces overall
compilation time, esp. when there are a lot of eager deoptimization
exits.

R=jarin@chromium.org

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

Cr-Commit-Position: refs/heads/master@{#34239}
parent 9146bc5e
...@@ -54,6 +54,7 @@ class ArmOperandConverter final : public InstructionOperandConverter { ...@@ -54,6 +54,7 @@ class ArmOperandConverter final : public InstructionOperandConverter {
SBit OutputSBit() const { SBit OutputSBit() const {
switch (instr_->flags_mode()) { switch (instr_->flags_mode()) {
case kFlags_branch: case kFlags_branch:
case kFlags_deoptimize:
case kFlags_set: case kFlags_set:
return SetCC; return SetCC;
case kFlags_none: case kFlags_none:
...@@ -409,7 +410,7 @@ void CodeGenerator::AssemblePrepareTailCall(int stack_param_delta) { ...@@ -409,7 +410,7 @@ void CodeGenerator::AssemblePrepareTailCall(int stack_param_delta) {
void CodeGenerator::AssembleArchInstruction(Instruction* instr) { void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
ArmOperandConverter i(this, instr); ArmOperandConverter i(this, instr);
masm()->MaybeCheckConstPool(); __ MaybeCheckConstPool();
switch (ArchOpcodeField::decode(instr->opcode())) { switch (ArchOpcodeField::decode(instr->opcode())) {
case kArchCallCodeObject: { case kArchCallCodeObject: {
...@@ -1155,7 +1156,11 @@ void CodeGenerator::AssembleDeoptimizerCall( ...@@ -1155,7 +1156,11 @@ void CodeGenerator::AssembleDeoptimizerCall(
int deoptimization_id, Deoptimizer::BailoutType bailout_type) { int deoptimization_id, Deoptimizer::BailoutType bailout_type) {
Address deopt_entry = Deoptimizer::GetDeoptimizationEntry( Address deopt_entry = Deoptimizer::GetDeoptimizationEntry(
isolate(), deoptimization_id, bailout_type); isolate(), deoptimization_id, bailout_type);
// TODO(turbofan): We should be able to generate better code by sharing the
// actual final call site and just bl'ing to it here, similar to what we do
// in the lithium backend.
__ Call(deopt_entry, RelocInfo::RUNTIME_ENTRY); __ Call(deopt_entry, RelocInfo::RUNTIME_ENTRY);
__ CheckConstPool(false, false);
} }
......
...@@ -237,8 +237,13 @@ void VisitBinop(InstructionSelector* selector, Node* node, ...@@ -237,8 +237,13 @@ void VisitBinop(InstructionSelector* selector, Node* node,
DCHECK_GE(arraysize(outputs), output_count); DCHECK_GE(arraysize(outputs), output_count);
DCHECK_NE(kMode_None, AddressingModeField::decode(opcode)); DCHECK_NE(kMode_None, AddressingModeField::decode(opcode));
selector->Emit(cont->Encode(opcode), output_count, outputs, input_count, opcode = cont->Encode(opcode);
inputs); if (cont->IsDeoptimize()) {
selector->EmitDeoptimize(opcode, output_count, outputs, input_count, inputs,
cont->frame_state());
} else {
selector->Emit(opcode, output_count, outputs, input_count, inputs);
}
} }
...@@ -691,8 +696,13 @@ void VisitShift(InstructionSelector* selector, Node* node, ...@@ -691,8 +696,13 @@ void VisitShift(InstructionSelector* selector, Node* node,
DCHECK_GE(arraysize(outputs), output_count); DCHECK_GE(arraysize(outputs), output_count);
DCHECK_NE(kMode_None, AddressingModeField::decode(opcode)); DCHECK_NE(kMode_None, AddressingModeField::decode(opcode));
selector->Emit(cont->Encode(opcode), output_count, outputs, input_count, opcode = cont->Encode(opcode);
inputs); if (cont->IsDeoptimize()) {
selector->EmitDeoptimize(opcode, output_count, outputs, input_count, inputs,
cont->frame_state());
} else {
selector->Emit(opcode, output_count, outputs, input_count, inputs);
}
} }
...@@ -1284,6 +1294,9 @@ void VisitCompare(InstructionSelector* selector, InstructionCode opcode, ...@@ -1284,6 +1294,9 @@ void VisitCompare(InstructionSelector* selector, InstructionCode opcode,
if (cont->IsBranch()) { if (cont->IsBranch()) {
selector->Emit(opcode, g.NoOutput(), left, right, selector->Emit(opcode, g.NoOutput(), left, right,
g.Label(cont->true_block()), g.Label(cont->false_block())); g.Label(cont->true_block()), g.Label(cont->false_block()));
} else if (cont->IsDeoptimize()) {
selector->EmitDeoptimize(opcode, g.NoOutput(), left, right,
cont->frame_state());
} else { } else {
DCHECK(cont->IsSet()); DCHECK(cont->IsSet());
selector->Emit(opcode, g.DefineAsRegister(cont->result()), left, right); selector->Emit(opcode, g.DefineAsRegister(cont->result()), left, right);
...@@ -1357,8 +1370,7 @@ void VisitWordCompare(InstructionSelector* selector, Node* node, ...@@ -1357,8 +1370,7 @@ void VisitWordCompare(InstructionSelector* selector, Node* node,
if (cont->IsBranch()) { if (cont->IsBranch()) {
inputs[input_count++] = g.Label(cont->true_block()); inputs[input_count++] = g.Label(cont->true_block());
inputs[input_count++] = g.Label(cont->false_block()); inputs[input_count++] = g.Label(cont->false_block());
} else { } else if (cont->IsSet()) {
DCHECK(cont->IsSet());
outputs[output_count++] = g.DefineAsRegister(cont->result()); outputs[output_count++] = g.DefineAsRegister(cont->result());
} }
...@@ -1366,8 +1378,13 @@ void VisitWordCompare(InstructionSelector* selector, Node* node, ...@@ -1366,8 +1378,13 @@ void VisitWordCompare(InstructionSelector* selector, Node* node,
DCHECK_GE(arraysize(inputs), input_count); DCHECK_GE(arraysize(inputs), input_count);
DCHECK_GE(arraysize(outputs), output_count); DCHECK_GE(arraysize(outputs), output_count);
selector->Emit(cont->Encode(opcode), output_count, outputs, input_count, opcode = cont->Encode(opcode);
inputs); if (cont->IsDeoptimize()) {
selector->EmitDeoptimize(opcode, output_count, outputs, input_count, inputs,
cont->frame_state());
} else {
selector->Emit(opcode, output_count, outputs, input_count, inputs);
}
} }
...@@ -1482,7 +1499,11 @@ void VisitWordCompareZero(InstructionSelector* selector, Node* user, ...@@ -1482,7 +1499,11 @@ void VisitWordCompareZero(InstructionSelector* selector, Node* user,
if (cont->IsBranch()) { if (cont->IsBranch()) {
selector->Emit(opcode, g.NoOutput(), value_operand, value_operand, selector->Emit(opcode, g.NoOutput(), value_operand, value_operand,
g.Label(cont->true_block()), g.Label(cont->false_block())); g.Label(cont->true_block()), g.Label(cont->false_block()));
} else if (cont->IsDeoptimize()) {
selector->EmitDeoptimize(opcode, g.NoOutput(), value_operand, value_operand,
cont->frame_state());
} else { } else {
DCHECK(cont->IsSet());
selector->Emit(opcode, g.DefineAsRegister(cont->result()), value_operand, selector->Emit(opcode, g.DefineAsRegister(cont->result()), value_operand,
value_operand); value_operand);
} }
...@@ -1490,13 +1511,23 @@ void VisitWordCompareZero(InstructionSelector* selector, Node* user, ...@@ -1490,13 +1511,23 @@ void VisitWordCompareZero(InstructionSelector* selector, Node* user,
} // namespace } // namespace
void InstructionSelector::VisitBranch(Node* branch, BasicBlock* tbranch, void InstructionSelector::VisitBranch(Node* branch, BasicBlock* tbranch,
BasicBlock* fbranch) { BasicBlock* fbranch) {
FlagsContinuation cont(kNotEqual, tbranch, fbranch); FlagsContinuation cont(kNotEqual, tbranch, fbranch);
VisitWordCompareZero(this, branch, branch->InputAt(0), &cont); VisitWordCompareZero(this, branch, branch->InputAt(0), &cont);
} }
void InstructionSelector::VisitDeoptimizeIf(Node* node) {
FlagsContinuation cont =
FlagsContinuation::ForDeoptimize(kNotEqual, node->InputAt(1));
VisitWordCompareZero(this, node, node->InputAt(0), &cont);
}
void InstructionSelector::VisitDeoptimizeUnless(Node* node) {
FlagsContinuation cont =
FlagsContinuation::ForDeoptimize(kEqual, node->InputAt(1));
VisitWordCompareZero(this, node, node->InputAt(0), &cont);
}
void InstructionSelector::VisitSwitch(Node* node, const SwitchInfo& sw) { void InstructionSelector::VisitSwitch(Node* node, const SwitchInfo& sw) {
ArmOperandGenerator g(this); ArmOperandGenerator g(this);
...@@ -1527,7 +1558,7 @@ void InstructionSelector::VisitSwitch(Node* node, const SwitchInfo& sw) { ...@@ -1527,7 +1558,7 @@ void InstructionSelector::VisitSwitch(Node* node, const SwitchInfo& sw) {
void InstructionSelector::VisitWord32Equal(Node* const node) { void InstructionSelector::VisitWord32Equal(Node* const node) {
FlagsContinuation cont(kEqual, node); FlagsContinuation cont = FlagsContinuation::ForSet(kEqual, node);
Int32BinopMatcher m(node); Int32BinopMatcher m(node);
if (m.right().Is(0)) { if (m.right().Is(0)) {
return VisitWordCompareZero(this, m.node(), m.left().node(), &cont); return VisitWordCompareZero(this, m.node(), m.left().node(), &cont);
...@@ -1537,32 +1568,34 @@ void InstructionSelector::VisitWord32Equal(Node* const node) { ...@@ -1537,32 +1568,34 @@ void InstructionSelector::VisitWord32Equal(Node* const node) {
void InstructionSelector::VisitInt32LessThan(Node* node) { void InstructionSelector::VisitInt32LessThan(Node* node) {
FlagsContinuation cont(kSignedLessThan, node); FlagsContinuation cont = FlagsContinuation::ForSet(kSignedLessThan, node);
VisitWordCompare(this, node, &cont); VisitWordCompare(this, node, &cont);
} }
void InstructionSelector::VisitInt32LessThanOrEqual(Node* node) { void InstructionSelector::VisitInt32LessThanOrEqual(Node* node) {
FlagsContinuation cont(kSignedLessThanOrEqual, node); FlagsContinuation cont =
FlagsContinuation::ForSet(kSignedLessThanOrEqual, node);
VisitWordCompare(this, node, &cont); VisitWordCompare(this, node, &cont);
} }
void InstructionSelector::VisitUint32LessThan(Node* node) { void InstructionSelector::VisitUint32LessThan(Node* node) {
FlagsContinuation cont(kUnsignedLessThan, node); FlagsContinuation cont = FlagsContinuation::ForSet(kUnsignedLessThan, node);
VisitWordCompare(this, node, &cont); VisitWordCompare(this, node, &cont);
} }
void InstructionSelector::VisitUint32LessThanOrEqual(Node* node) { void InstructionSelector::VisitUint32LessThanOrEqual(Node* node) {
FlagsContinuation cont(kUnsignedLessThanOrEqual, node); FlagsContinuation cont =
FlagsContinuation::ForSet(kUnsignedLessThanOrEqual, node);
VisitWordCompare(this, node, &cont); VisitWordCompare(this, node, &cont);
} }
void InstructionSelector::VisitInt32AddWithOverflow(Node* node) { void InstructionSelector::VisitInt32AddWithOverflow(Node* node) {
if (Node* ovf = NodeProperties::FindProjection(node, 1)) { if (Node* ovf = NodeProperties::FindProjection(node, 1)) {
FlagsContinuation cont(kOverflow, ovf); FlagsContinuation cont = FlagsContinuation::ForSet(kOverflow, ovf);
return VisitBinop(this, node, kArmAdd, kArmAdd, &cont); return VisitBinop(this, node, kArmAdd, kArmAdd, &cont);
} }
FlagsContinuation cont; FlagsContinuation cont;
...@@ -1572,7 +1605,7 @@ void InstructionSelector::VisitInt32AddWithOverflow(Node* node) { ...@@ -1572,7 +1605,7 @@ void InstructionSelector::VisitInt32AddWithOverflow(Node* node) {
void InstructionSelector::VisitInt32SubWithOverflow(Node* node) { void InstructionSelector::VisitInt32SubWithOverflow(Node* node) {
if (Node* ovf = NodeProperties::FindProjection(node, 1)) { if (Node* ovf = NodeProperties::FindProjection(node, 1)) {
FlagsContinuation cont(kOverflow, ovf); FlagsContinuation cont = FlagsContinuation::ForSet(kOverflow, ovf);
return VisitBinop(this, node, kArmSub, kArmRsb, &cont); return VisitBinop(this, node, kArmSub, kArmRsb, &cont);
} }
FlagsContinuation cont; FlagsContinuation cont;
...@@ -1581,37 +1614,39 @@ void InstructionSelector::VisitInt32SubWithOverflow(Node* node) { ...@@ -1581,37 +1614,39 @@ void InstructionSelector::VisitInt32SubWithOverflow(Node* node) {
void InstructionSelector::VisitFloat32Equal(Node* node) { void InstructionSelector::VisitFloat32Equal(Node* node) {
FlagsContinuation cont(kEqual, node); FlagsContinuation cont = FlagsContinuation::ForSet(kEqual, node);
VisitFloat32Compare(this, node, &cont); VisitFloat32Compare(this, node, &cont);
} }
void InstructionSelector::VisitFloat32LessThan(Node* node) { void InstructionSelector::VisitFloat32LessThan(Node* node) {
FlagsContinuation cont(kFloatLessThan, node); FlagsContinuation cont = FlagsContinuation::ForSet(kFloatLessThan, node);
VisitFloat32Compare(this, node, &cont); VisitFloat32Compare(this, node, &cont);
} }
void InstructionSelector::VisitFloat32LessThanOrEqual(Node* node) { void InstructionSelector::VisitFloat32LessThanOrEqual(Node* node) {
FlagsContinuation cont(kFloatLessThanOrEqual, node); FlagsContinuation cont =
FlagsContinuation::ForSet(kFloatLessThanOrEqual, node);
VisitFloat32Compare(this, node, &cont); VisitFloat32Compare(this, node, &cont);
} }
void InstructionSelector::VisitFloat64Equal(Node* node) { void InstructionSelector::VisitFloat64Equal(Node* node) {
FlagsContinuation cont(kEqual, node); FlagsContinuation cont = FlagsContinuation::ForSet(kEqual, node);
VisitFloat64Compare(this, node, &cont); VisitFloat64Compare(this, node, &cont);
} }
void InstructionSelector::VisitFloat64LessThan(Node* node) { void InstructionSelector::VisitFloat64LessThan(Node* node) {
FlagsContinuation cont(kFloatLessThan, node); FlagsContinuation cont = FlagsContinuation::ForSet(kFloatLessThan, node);
VisitFloat64Compare(this, node, &cont); VisitFloat64Compare(this, node, &cont);
} }
void InstructionSelector::VisitFloat64LessThanOrEqual(Node* node) { void InstructionSelector::VisitFloat64LessThanOrEqual(Node* node) {
FlagsContinuation cont(kFloatLessThanOrEqual, node); FlagsContinuation cont =
FlagsContinuation::ForSet(kFloatLessThanOrEqual, node);
VisitFloat64Compare(this, node, &cont); VisitFloat64Compare(this, node, &cont);
} }
......
...@@ -15,11 +15,11 @@ namespace compiler { ...@@ -15,11 +15,11 @@ namespace compiler {
BranchElimination::BranchElimination(Editor* editor, JSGraph* js_graph, BranchElimination::BranchElimination(Editor* editor, JSGraph* js_graph,
Zone* zone) Zone* zone)
: AdvancedReducer(editor), : AdvancedReducer(editor),
jsgraph_(js_graph),
node_conditions_(zone, js_graph->graph()->NodeCount()), node_conditions_(zone, js_graph->graph()->NodeCount()),
zone_(zone), zone_(zone),
dead_(js_graph->graph()->NewNode(js_graph->common()->Dead())) {} dead_(js_graph->graph()->NewNode(js_graph->common()->Dead())) {}
BranchElimination::~BranchElimination() {} BranchElimination::~BranchElimination() {}
...@@ -27,6 +27,9 @@ Reduction BranchElimination::Reduce(Node* node) { ...@@ -27,6 +27,9 @@ Reduction BranchElimination::Reduce(Node* node) {
switch (node->opcode()) { switch (node->opcode()) {
case IrOpcode::kDead: case IrOpcode::kDead:
return NoChange(); return NoChange();
case IrOpcode::kDeoptimizeIf:
case IrOpcode::kDeoptimizeUnless:
return ReduceDeoptimizeConditional(node);
case IrOpcode::kMerge: case IrOpcode::kMerge:
return ReduceMerge(node); return ReduceMerge(node);
case IrOpcode::kLoop: case IrOpcode::kLoop:
...@@ -76,6 +79,41 @@ Reduction BranchElimination::ReduceBranch(Node* node) { ...@@ -76,6 +79,41 @@ Reduction BranchElimination::ReduceBranch(Node* node) {
return TakeConditionsFromFirstControl(node); return TakeConditionsFromFirstControl(node);
} }
Reduction BranchElimination::ReduceDeoptimizeConditional(Node* node) {
DCHECK(node->opcode() == IrOpcode::kDeoptimizeIf ||
node->opcode() == IrOpcode::kDeoptimizeUnless);
bool condition_is_true = node->opcode() == IrOpcode::kDeoptimizeUnless;
Node* condition = NodeProperties::GetValueInput(node, 0);
Node* frame_state = NodeProperties::GetValueInput(node, 1);
Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node);
ControlPathConditions const* conditions = node_conditions_.Get(control);
// If we do not know anything about the predecessor, do not propagate just
// yet because we will have to recompute anyway once we compute the
// predecessor.
if (conditions == nullptr) {
DCHECK_NULL(node_conditions_.Get(node));
return NoChange();
}
Maybe<bool> condition_value = conditions->LookupCondition(condition);
if (condition_value.IsJust()) {
// If we know the condition we can discard the branch.
if (condition_is_true == condition_value.FromJust()) {
// We don't to update the conditions here, because we're replacing with
// the {control} node that already contains the right information.
return Replace(control);
} else {
control = graph()->NewNode(common()->Deoptimize(DeoptimizeKind::kEager),
frame_state, effect, control);
// TODO(bmeurer): This should be on the AdvancedReducer somehow.
NodeProperties::MergeControlToEnd(graph(), common(), control);
Revisit(graph()->end());
return Replace(dead());
}
}
return UpdateConditions(
node, conditions->AddCondition(zone_, condition, condition_is_true));
}
Reduction BranchElimination::ReduceIf(Node* node, bool is_true_branch) { Reduction BranchElimination::ReduceIf(Node* node, bool is_true_branch) {
// Add the condition to the list arriving from the input branch. // Add the condition to the list arriving from the input branch.
...@@ -264,6 +302,12 @@ bool BranchElimination::ControlPathConditions::operator==( ...@@ -264,6 +302,12 @@ bool BranchElimination::ControlPathConditions::operator==(
return false; return false;
} }
Graph* BranchElimination::graph() const { return jsgraph()->graph(); }
CommonOperatorBuilder* BranchElimination::common() const {
return jsgraph()->common();
}
} // namespace compiler } // namespace compiler
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
...@@ -11,6 +11,8 @@ namespace v8 { ...@@ -11,6 +11,8 @@ namespace v8 {
namespace internal { namespace internal {
namespace compiler { namespace compiler {
// Forward declarations.
class CommonOperatorBuilder;
class JSGraph; class JSGraph;
...@@ -73,6 +75,7 @@ class BranchElimination final : public AdvancedReducer { ...@@ -73,6 +75,7 @@ class BranchElimination final : public AdvancedReducer {
}; };
Reduction ReduceBranch(Node* node); Reduction ReduceBranch(Node* node);
Reduction ReduceDeoptimizeConditional(Node* node);
Reduction ReduceIf(Node* node, bool is_true_branch); Reduction ReduceIf(Node* node, bool is_true_branch);
Reduction ReduceLoop(Node* node); Reduction ReduceLoop(Node* node);
Reduction ReduceMerge(Node* node); Reduction ReduceMerge(Node* node);
...@@ -84,7 +87,11 @@ class BranchElimination final : public AdvancedReducer { ...@@ -84,7 +87,11 @@ class BranchElimination final : public AdvancedReducer {
const ControlPathConditions* conditions); const ControlPathConditions* conditions);
Node* dead() const { return dead_; } Node* dead() const { return dead_; }
Graph* graph() const;
JSGraph* jsgraph() const { return jsgraph_; }
CommonOperatorBuilder* common() const;
JSGraph* const jsgraph_;
PathConditionsForControlNodes node_conditions_; PathConditionsForControlNodes node_conditions_;
Zone* zone_; Zone* zone_;
Node* dead_; Node* dead_;
......
...@@ -139,6 +139,19 @@ class InstructionOperandConverter { ...@@ -139,6 +139,19 @@ class InstructionOperandConverter {
Instruction* instr_; Instruction* instr_;
}; };
// Eager deoptimization exit.
class DeoptimizationExit : public ZoneObject {
public:
explicit DeoptimizationExit(int deoptimization_id)
: deoptimization_id_(deoptimization_id) {}
int deoptimization_id() const { return deoptimization_id_; }
Label* label() { return &label_; }
private:
int const deoptimization_id_;
Label label_;
};
// Generator for out-of-line code that is emitted after the main code is done. // Generator for out-of-line code that is emitted after the main code is done.
class OutOfLineCode : public ZoneObject { class OutOfLineCode : public ZoneObject {
......
...@@ -31,7 +31,6 @@ class CodeGenerator::JumpTable final : public ZoneObject { ...@@ -31,7 +31,6 @@ class CodeGenerator::JumpTable final : public ZoneObject {
size_t const target_count_; size_t const target_count_;
}; };
CodeGenerator::CodeGenerator(Frame* frame, Linkage* linkage, CodeGenerator::CodeGenerator(Frame* frame, Linkage* linkage,
InstructionSequence* code, CompilationInfo* info) InstructionSequence* code, CompilationInfo* info)
: frame_access_state_(new (code->zone()) FrameAccessState(frame)), : frame_access_state_(new (code->zone()) FrameAccessState(frame)),
...@@ -45,6 +44,7 @@ CodeGenerator::CodeGenerator(Frame* frame, Linkage* linkage, ...@@ -45,6 +44,7 @@ CodeGenerator::CodeGenerator(Frame* frame, Linkage* linkage,
resolver_(this), resolver_(this),
safepoints_(code->zone()), safepoints_(code->zone()),
handlers_(code->zone()), handlers_(code->zone()),
deoptimization_exits_(code->zone()),
deoptimization_states_(code->zone()), deoptimization_states_(code->zone()),
deoptimization_literals_(code->zone()), deoptimization_literals_(code->zone()),
inlined_function_count_(0), inlined_function_count_(0),
...@@ -158,6 +158,12 @@ Handle<Code> CodeGenerator::GenerateCode() { ...@@ -158,6 +158,12 @@ Handle<Code> CodeGenerator::GenerateCode() {
} }
} }
// Assemble all eager deoptimization exits.
for (DeoptimizationExit* exit : deoptimization_exits_) {
masm()->bind(exit->label());
AssembleDeoptimizerCall(exit->deoptimization_id(), Deoptimizer::EAGER);
}
// Ensure there is space for lazy deoptimization in the code. // Ensure there is space for lazy deoptimization in the code.
if (info->ShouldEnsureSpaceForLazyDeopt()) { if (info->ShouldEnsureSpaceForLazyDeopt()) {
int target_offset = masm()->pc_offset() + Deoptimizer::patch_size(); int target_offset = masm()->pc_offset() + Deoptimizer::patch_size();
...@@ -291,34 +297,59 @@ void CodeGenerator::AssembleInstruction(Instruction* instr) { ...@@ -291,34 +297,59 @@ void CodeGenerator::AssembleInstruction(Instruction* instr) {
FlagsMode mode = FlagsModeField::decode(instr->opcode()); FlagsMode mode = FlagsModeField::decode(instr->opcode());
FlagsCondition condition = FlagsConditionField::decode(instr->opcode()); FlagsCondition condition = FlagsConditionField::decode(instr->opcode());
if (mode == kFlags_branch) { switch (mode) {
// Assemble a branch after this instruction. case kFlags_branch: {
InstructionOperandConverter i(this, instr); // Assemble a branch after this instruction.
RpoNumber true_rpo = i.InputRpo(instr->InputCount() - 2); InstructionOperandConverter i(this, instr);
RpoNumber false_rpo = i.InputRpo(instr->InputCount() - 1); RpoNumber true_rpo = i.InputRpo(instr->InputCount() - 2);
RpoNumber false_rpo = i.InputRpo(instr->InputCount() - 1);
if (true_rpo == false_rpo) {
// redundant branch. if (true_rpo == false_rpo) {
if (!IsNextInAssemblyOrder(true_rpo)) { // redundant branch.
AssembleArchJump(true_rpo); if (!IsNextInAssemblyOrder(true_rpo)) {
AssembleArchJump(true_rpo);
}
return;
} }
return; if (IsNextInAssemblyOrder(true_rpo)) {
// true block is next, can fall through if condition negated.
std::swap(true_rpo, false_rpo);
condition = NegateFlagsCondition(condition);
}
BranchInfo branch;
branch.condition = condition;
branch.true_label = GetLabel(true_rpo);
branch.false_label = GetLabel(false_rpo);
branch.fallthru = IsNextInAssemblyOrder(false_rpo);
// Assemble architecture-specific branch.
AssembleArchBranch(instr, &branch);
break;
} }
if (IsNextInAssemblyOrder(true_rpo)) { case kFlags_deoptimize: {
// true block is next, can fall through if condition negated. // Assemble a conditional eager deoptimization after this instruction.
std::swap(true_rpo, false_rpo); InstructionOperandConverter i(this, instr);
condition = NegateFlagsCondition(condition); size_t frame_state_offset = MiscField::decode(instr->opcode());
DeoptimizationExit* const exit =
AddDeoptimizationExit(instr, frame_state_offset);
Label continue_label;
BranchInfo branch;
branch.condition = condition;
branch.true_label = exit->label();
branch.false_label = &continue_label;
branch.fallthru = true;
// Assemble architecture-specific branch.
AssembleArchBranch(instr, &branch);
masm()->bind(&continue_label);
break;
}
case kFlags_set: {
// Assemble a boolean materialization after this instruction.
AssembleArchBoolean(instr, condition);
break;
}
case kFlags_none: {
break;
} }
BranchInfo branch;
branch.condition = condition;
branch.true_label = GetLabel(true_rpo);
branch.false_label = GetLabel(false_rpo);
branch.fallthru = IsNextInAssemblyOrder(false_rpo);
// Assemble architecture-specific branch.
AssembleArchBranch(instr, &branch);
} else if (mode == kFlags_set) {
// Assemble a boolean materialization after this instruction.
AssembleArchBoolean(instr, condition);
} }
} }
...@@ -714,6 +745,15 @@ void CodeGenerator::MarkLazyDeoptSite() { ...@@ -714,6 +745,15 @@ void CodeGenerator::MarkLazyDeoptSite() {
last_lazy_deopt_pc_ = masm()->pc_offset(); last_lazy_deopt_pc_ = masm()->pc_offset();
} }
DeoptimizationExit* CodeGenerator::AddDeoptimizationExit(
Instruction* instr, size_t frame_state_offset) {
int const deoptimization_id = BuildTranslation(
instr, -1, frame_state_offset, OutputFrameStateCombine::Ignore());
DeoptimizationExit* const exit =
new (zone()) DeoptimizationExit(deoptimization_id);
deoptimization_exits_.push_back(exit);
return exit;
}
int CodeGenerator::TailCallFrameStackSlotDelta(int stack_param_delta) { int CodeGenerator::TailCallFrameStackSlotDelta(int stack_param_delta) {
CallDescriptor* descriptor = linkage()->GetIncomingDescriptor(); CallDescriptor* descriptor = linkage()->GetIncomingDescriptor();
......
...@@ -16,6 +16,7 @@ namespace internal { ...@@ -16,6 +16,7 @@ namespace internal {
namespace compiler { namespace compiler {
// Forward declarations. // Forward declarations.
class DeoptimizationExit;
class FrameAccessState; class FrameAccessState;
class Linkage; class Linkage;
class OutOfLineCode; class OutOfLineCode;
...@@ -144,10 +145,10 @@ class CodeGenerator final : public GapResolver::Assembler { ...@@ -144,10 +145,10 @@ class CodeGenerator final : public GapResolver::Assembler {
void RecordCallPosition(Instruction* instr); void RecordCallPosition(Instruction* instr);
void PopulateDeoptimizationData(Handle<Code> code); void PopulateDeoptimizationData(Handle<Code> code);
int DefineDeoptimizationLiteral(Handle<Object> literal); int DefineDeoptimizationLiteral(Handle<Object> literal);
FrameStateDescriptor* GetFrameStateDescriptor( FrameStateDescriptor* GetFrameStateDescriptor(Instruction* instr,
Instruction* instr, size_t frame_access_state_offset); size_t frame_state_offset);
int BuildTranslation(Instruction* instr, int pc_offset, int BuildTranslation(Instruction* instr, int pc_offset,
size_t frame_access_state_offset, size_t frame_state_offset,
OutputFrameStateCombine state_combine); OutputFrameStateCombine state_combine);
void BuildTranslationForFrameStateDescriptor( void BuildTranslationForFrameStateDescriptor(
FrameStateDescriptor* descriptor, InstructionOperandIterator* iter, FrameStateDescriptor* descriptor, InstructionOperandIterator* iter,
...@@ -165,6 +166,9 @@ class CodeGenerator final : public GapResolver::Assembler { ...@@ -165,6 +166,9 @@ class CodeGenerator final : public GapResolver::Assembler {
void EnsureSpaceForLazyDeopt(); void EnsureSpaceForLazyDeopt();
void MarkLazyDeoptSite(); void MarkLazyDeoptSite();
DeoptimizationExit* AddDeoptimizationExit(Instruction* instr,
size_t frame_state_offset);
// Converts the delta in the number of stack parameter passed from a tail // Converts the delta in the number of stack parameter passed from a tail
// caller to the callee into the distance (in pointers) the SP must be // caller to the callee into the distance (in pointers) the SP must be
// adjusted, taking frame elision and other relevant factors into // adjusted, taking frame elision and other relevant factors into
...@@ -210,6 +214,7 @@ class CodeGenerator final : public GapResolver::Assembler { ...@@ -210,6 +214,7 @@ class CodeGenerator final : public GapResolver::Assembler {
GapResolver resolver_; GapResolver resolver_;
SafepointTableBuilder safepoints_; SafepointTableBuilder safepoints_;
ZoneVector<HandlerInfo> handlers_; ZoneVector<HandlerInfo> handlers_;
ZoneDeque<DeoptimizationExit*> deoptimization_exits_;
ZoneDeque<DeoptimizationState*> deoptimization_states_; ZoneDeque<DeoptimizationState*> deoptimization_states_;
ZoneDeque<Handle<Object>> deoptimization_literals_; ZoneDeque<Handle<Object>> deoptimization_literals_;
size_t inlined_function_count_; size_t inlined_function_count_;
......
...@@ -57,6 +57,9 @@ Reduction CommonOperatorReducer::Reduce(Node* node) { ...@@ -57,6 +57,9 @@ Reduction CommonOperatorReducer::Reduce(Node* node) {
switch (node->opcode()) { switch (node->opcode()) {
case IrOpcode::kBranch: case IrOpcode::kBranch:
return ReduceBranch(node); return ReduceBranch(node);
case IrOpcode::kDeoptimizeIf:
case IrOpcode::kDeoptimizeUnless:
return ReduceDeoptimizeConditional(node);
case IrOpcode::kMerge: case IrOpcode::kMerge:
return ReduceMerge(node); return ReduceMerge(node);
case IrOpcode::kEffectPhi: case IrOpcode::kEffectPhi:
...@@ -123,6 +126,37 @@ Reduction CommonOperatorReducer::ReduceBranch(Node* node) { ...@@ -123,6 +126,37 @@ Reduction CommonOperatorReducer::ReduceBranch(Node* node) {
return Replace(dead()); return Replace(dead());
} }
Reduction CommonOperatorReducer::ReduceDeoptimizeConditional(Node* node) {
DCHECK(node->opcode() == IrOpcode::kDeoptimizeIf ||
node->opcode() == IrOpcode::kDeoptimizeUnless);
bool condition_is_true = node->opcode() == IrOpcode::kDeoptimizeUnless;
Node* condition = NodeProperties::GetValueInput(node, 0);
Node* frame_state = NodeProperties::GetValueInput(node, 1);
Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node);
// Swap DeoptimizeIf/DeoptimizeUnless on {node} if {cond} is a BooleaNot
// and use the input to BooleanNot as new condition for {node}. Note we
// assume that {cond} was already properly optimized before we get here
// (as guaranteed by the graph reduction logic).
if (condition->opcode() == IrOpcode::kBooleanNot) {
NodeProperties::ReplaceValueInput(node, condition->InputAt(0), 0);
NodeProperties::ChangeOp(node, condition_is_true
? common()->DeoptimizeIf()
: common()->DeoptimizeUnless());
return Changed(node);
}
Decision const decision = DecideCondition(condition);
if (decision == Decision::kUnknown) return NoChange();
if (condition_is_true == (decision == Decision::kTrue)) {
return Replace(control);
}
control = graph()->NewNode(common()->Deoptimize(DeoptimizeKind::kEager),
frame_state, effect, control);
// TODO(bmeurer): This should be on the AdvancedReducer somehow.
NodeProperties::MergeControlToEnd(graph(), common(), control);
Revisit(graph()->end());
return Replace(dead());
}
Reduction CommonOperatorReducer::ReduceMerge(Node* node) { Reduction CommonOperatorReducer::ReduceMerge(Node* node) {
DCHECK_EQ(IrOpcode::kMerge, node->opcode()); DCHECK_EQ(IrOpcode::kMerge, node->opcode());
......
...@@ -30,6 +30,7 @@ class CommonOperatorReducer final : public AdvancedReducer { ...@@ -30,6 +30,7 @@ class CommonOperatorReducer final : public AdvancedReducer {
private: private:
Reduction ReduceBranch(Node* node); Reduction ReduceBranch(Node* node);
Reduction ReduceDeoptimizeConditional(Node* node);
Reduction ReduceMerge(Node* node); Reduction ReduceMerge(Node* node);
Reduction ReduceEffectPhi(Node* node); Reduction ReduceEffectPhi(Node* node);
Reduction ReducePhi(Node* node); Reduction ReducePhi(Node* node);
......
...@@ -142,21 +142,21 @@ std::ostream& operator<<(std::ostream& os, ParameterInfo const& i) { ...@@ -142,21 +142,21 @@ std::ostream& operator<<(std::ostream& os, ParameterInfo const& i) {
return os; return os;
} }
#define CACHED_OP_LIST(V) \
#define CACHED_OP_LIST(V) \ V(Dead, Operator::kFoldable, 0, 0, 0, 1, 1, 1) \
V(Dead, Operator::kFoldable, 0, 0, 0, 1, 1, 1) \ V(DeoptimizeIf, Operator::kFoldable, 2, 1, 1, 0, 0, 1) \
V(IfTrue, Operator::kKontrol, 0, 0, 1, 0, 0, 1) \ V(DeoptimizeUnless, Operator::kFoldable, 2, 1, 1, 0, 0, 1) \
V(IfFalse, Operator::kKontrol, 0, 0, 1, 0, 0, 1) \ V(IfTrue, Operator::kKontrol, 0, 0, 1, 0, 0, 1) \
V(IfSuccess, Operator::kKontrol, 0, 0, 1, 0, 0, 1) \ V(IfFalse, Operator::kKontrol, 0, 0, 1, 0, 0, 1) \
V(IfDefault, Operator::kKontrol, 0, 0, 1, 0, 0, 1) \ V(IfSuccess, Operator::kKontrol, 0, 0, 1, 0, 0, 1) \
V(Throw, Operator::kKontrol, 1, 1, 1, 0, 0, 1) \ V(IfDefault, Operator::kKontrol, 0, 0, 1, 0, 0, 1) \
V(Terminate, Operator::kKontrol, 0, 1, 1, 0, 0, 1) \ V(Throw, Operator::kKontrol, 1, 1, 1, 0, 0, 1) \
V(OsrNormalEntry, Operator::kFoldable, 0, 1, 1, 0, 1, 1) \ V(Terminate, Operator::kKontrol, 0, 1, 1, 0, 0, 1) \
V(OsrLoopEntry, Operator::kFoldable, 0, 1, 1, 0, 1, 1) \ V(OsrNormalEntry, Operator::kFoldable, 0, 1, 1, 0, 1, 1) \
V(BeginRegion, Operator::kNoThrow, 0, 1, 0, 0, 1, 0) \ V(OsrLoopEntry, Operator::kFoldable, 0, 1, 1, 0, 1, 1) \
V(BeginRegion, Operator::kNoThrow, 0, 1, 0, 0, 1, 0) \
V(FinishRegion, Operator::kNoThrow, 1, 1, 0, 1, 1, 0) V(FinishRegion, Operator::kNoThrow, 1, 1, 0, 1, 1, 0)
#define CACHED_RETURN_LIST(V) \ #define CACHED_RETURN_LIST(V) \
V(1) \ V(1) \
V(2) \ V(2) \
......
...@@ -133,6 +133,8 @@ class CommonOperatorBuilder final : public ZoneObject { ...@@ -133,6 +133,8 @@ class CommonOperatorBuilder final : public ZoneObject {
const Operator* IfDefault(); const Operator* IfDefault();
const Operator* Throw(); const Operator* Throw();
const Operator* Deoptimize(DeoptimizeKind kind); const Operator* Deoptimize(DeoptimizeKind kind);
const Operator* DeoptimizeIf();
const Operator* DeoptimizeUnless();
const Operator* Return(int value_input_count = 1); const Operator* Return(int value_input_count = 1);
const Operator* Terminate(); const Operator* Terminate();
......
...@@ -404,10 +404,11 @@ void InstructionSelector::VisitCheckedStore(Node* node) { ...@@ -404,10 +404,11 @@ void InstructionSelector::VisitCheckedStore(Node* node) {
} }
} }
namespace {
// Shared routine for multiple binary operations. // Shared routine for multiple binary operations.
static void VisitBinop(InstructionSelector* selector, Node* node, void VisitBinop(InstructionSelector* selector, Node* node,
InstructionCode opcode, FlagsContinuation* cont) { InstructionCode opcode, FlagsContinuation* cont) {
IA32OperandGenerator g(selector); IA32OperandGenerator g(selector);
Int32BinopMatcher m(node); Int32BinopMatcher m(node);
Node* left = m.left().node(); Node* left = m.left().node();
...@@ -456,18 +457,24 @@ static void VisitBinop(InstructionSelector* selector, Node* node, ...@@ -456,18 +457,24 @@ static void VisitBinop(InstructionSelector* selector, Node* node,
DCHECK_GE(arraysize(inputs), input_count); DCHECK_GE(arraysize(inputs), input_count);
DCHECK_GE(arraysize(outputs), output_count); DCHECK_GE(arraysize(outputs), output_count);
selector->Emit(cont->Encode(opcode), output_count, outputs, input_count, opcode = cont->Encode(opcode);
inputs); if (cont->IsDeoptimize()) {
selector->EmitDeoptimize(opcode, output_count, outputs, input_count, inputs,
cont->frame_state());
} else {
selector->Emit(opcode, output_count, outputs, input_count, inputs);
}
} }
// Shared routine for multiple binary operations. // Shared routine for multiple binary operations.
static void VisitBinop(InstructionSelector* selector, Node* node, void VisitBinop(InstructionSelector* selector, Node* node,
InstructionCode opcode) { InstructionCode opcode) {
FlagsContinuation cont; FlagsContinuation cont;
VisitBinop(selector, node, opcode, &cont); VisitBinop(selector, node, opcode, &cont);
} }
} // namespace
void InstructionSelector::VisitWord32And(Node* node) { void InstructionSelector::VisitWord32And(Node* node) {
VisitBinop(this, node, kIA32And); VisitBinop(this, node, kIA32And);
...@@ -1007,6 +1014,9 @@ void VisitCompareWithMemoryOperand(InstructionSelector* selector, ...@@ -1007,6 +1014,9 @@ void VisitCompareWithMemoryOperand(InstructionSelector* selector,
inputs[input_count++] = g.Label(cont->true_block()); inputs[input_count++] = g.Label(cont->true_block());
inputs[input_count++] = g.Label(cont->false_block()); inputs[input_count++] = g.Label(cont->false_block());
selector->Emit(opcode, 0, nullptr, input_count, inputs); selector->Emit(opcode, 0, nullptr, input_count, inputs);
} else if (cont->IsDeoptimize()) {
selector->EmitDeoptimize(opcode, 0, nullptr, input_count, inputs,
cont->frame_state());
} else { } else {
DCHECK(cont->IsSet()); DCHECK(cont->IsSet());
InstructionOperand output = g.DefineAsRegister(cont->result()); InstructionOperand output = g.DefineAsRegister(cont->result());
...@@ -1034,13 +1044,16 @@ void VisitCompare(InstructionSelector* selector, InstructionCode opcode, ...@@ -1034,13 +1044,16 @@ void VisitCompare(InstructionSelector* selector, InstructionCode opcode,
InstructionOperand left, InstructionOperand right, InstructionOperand left, InstructionOperand right,
FlagsContinuation* cont) { FlagsContinuation* cont) {
IA32OperandGenerator g(selector); IA32OperandGenerator g(selector);
opcode = cont->Encode(opcode);
if (cont->IsBranch()) { if (cont->IsBranch()) {
selector->Emit(cont->Encode(opcode), g.NoOutput(), left, right, selector->Emit(opcode, g.NoOutput(), left, right,
g.Label(cont->true_block()), g.Label(cont->false_block())); g.Label(cont->true_block()), g.Label(cont->false_block()));
} else if (cont->IsDeoptimize()) {
selector->EmitDeoptimize(opcode, g.NoOutput(), left, right,
cont->frame_state());
} else { } else {
DCHECK(cont->IsSet()); DCHECK(cont->IsSet());
selector->Emit(cont->Encode(opcode), g.DefineAsByteRegister(cont->result()), selector->Emit(opcode, g.DefineAsByteRegister(cont->result()), left, right);
left, right);
} }
} }
...@@ -1125,6 +1138,9 @@ void VisitWordCompare(InstructionSelector* selector, Node* node, ...@@ -1125,6 +1138,9 @@ void VisitWordCompare(InstructionSelector* selector, Node* node,
if (cont->IsBranch()) { if (cont->IsBranch()) {
selector->Emit(opcode, g.NoOutput(), g.Label(cont->true_block()), selector->Emit(opcode, g.NoOutput(), g.Label(cont->true_block()),
g.Label(cont->false_block())); g.Label(cont->false_block()));
} else if (cont->IsDeoptimize()) {
selector->EmitDeoptimize(opcode, 0, nullptr, 0, nullptr,
cont->frame_state());
} else { } else {
DCHECK(cont->IsSet()); DCHECK(cont->IsSet());
selector->Emit(opcode, g.DefineAsRegister(cont->result())); selector->Emit(opcode, g.DefineAsRegister(cont->result()));
...@@ -1227,13 +1243,23 @@ void VisitWordCompareZero(InstructionSelector* selector, Node* user, ...@@ -1227,13 +1243,23 @@ void VisitWordCompareZero(InstructionSelector* selector, Node* user,
} // namespace } // namespace
void InstructionSelector::VisitBranch(Node* branch, BasicBlock* tbranch, void InstructionSelector::VisitBranch(Node* branch, BasicBlock* tbranch,
BasicBlock* fbranch) { BasicBlock* fbranch) {
FlagsContinuation cont(kNotEqual, tbranch, fbranch); FlagsContinuation cont(kNotEqual, tbranch, fbranch);
VisitWordCompareZero(this, branch, branch->InputAt(0), &cont); VisitWordCompareZero(this, branch, branch->InputAt(0), &cont);
} }
void InstructionSelector::VisitDeoptimizeIf(Node* node) {
FlagsContinuation cont =
FlagsContinuation::ForDeoptimize(kNotEqual, node->InputAt(1));
VisitWordCompareZero(this, node, node->InputAt(0), &cont);
}
void InstructionSelector::VisitDeoptimizeUnless(Node* node) {
FlagsContinuation cont =
FlagsContinuation::ForDeoptimize(kEqual, node->InputAt(1));
VisitWordCompareZero(this, node, node->InputAt(0), &cont);
}
void InstructionSelector::VisitSwitch(Node* node, const SwitchInfo& sw) { void InstructionSelector::VisitSwitch(Node* node, const SwitchInfo& sw) {
IA32OperandGenerator g(this); IA32OperandGenerator g(this);
...@@ -1264,7 +1290,7 @@ void InstructionSelector::VisitSwitch(Node* node, const SwitchInfo& sw) { ...@@ -1264,7 +1290,7 @@ void InstructionSelector::VisitSwitch(Node* node, const SwitchInfo& sw) {
void InstructionSelector::VisitWord32Equal(Node* const node) { void InstructionSelector::VisitWord32Equal(Node* const node) {
FlagsContinuation cont(kEqual, node); FlagsContinuation cont = FlagsContinuation::ForSet(kEqual, node);
Int32BinopMatcher m(node); Int32BinopMatcher m(node);
if (m.right().Is(0)) { if (m.right().Is(0)) {
return VisitWordCompareZero(this, m.node(), m.left().node(), &cont); return VisitWordCompareZero(this, m.node(), m.left().node(), &cont);
...@@ -1274,32 +1300,34 @@ void InstructionSelector::VisitWord32Equal(Node* const node) { ...@@ -1274,32 +1300,34 @@ void InstructionSelector::VisitWord32Equal(Node* const node) {
void InstructionSelector::VisitInt32LessThan(Node* node) { void InstructionSelector::VisitInt32LessThan(Node* node) {
FlagsContinuation cont(kSignedLessThan, node); FlagsContinuation cont = FlagsContinuation::ForSet(kSignedLessThan, node);
VisitWordCompare(this, node, &cont); VisitWordCompare(this, node, &cont);
} }
void InstructionSelector::VisitInt32LessThanOrEqual(Node* node) { void InstructionSelector::VisitInt32LessThanOrEqual(Node* node) {
FlagsContinuation cont(kSignedLessThanOrEqual, node); FlagsContinuation cont =
FlagsContinuation::ForSet(kSignedLessThanOrEqual, node);
VisitWordCompare(this, node, &cont); VisitWordCompare(this, node, &cont);
} }
void InstructionSelector::VisitUint32LessThan(Node* node) { void InstructionSelector::VisitUint32LessThan(Node* node) {
FlagsContinuation cont(kUnsignedLessThan, node); FlagsContinuation cont = FlagsContinuation::ForSet(kUnsignedLessThan, node);
VisitWordCompare(this, node, &cont); VisitWordCompare(this, node, &cont);
} }
void InstructionSelector::VisitUint32LessThanOrEqual(Node* node) { void InstructionSelector::VisitUint32LessThanOrEqual(Node* node) {
FlagsContinuation cont(kUnsignedLessThanOrEqual, node); FlagsContinuation cont =
FlagsContinuation::ForSet(kUnsignedLessThanOrEqual, node);
VisitWordCompare(this, node, &cont); VisitWordCompare(this, node, &cont);
} }
void InstructionSelector::VisitInt32AddWithOverflow(Node* node) { void InstructionSelector::VisitInt32AddWithOverflow(Node* node) {
if (Node* ovf = NodeProperties::FindProjection(node, 1)) { if (Node* ovf = NodeProperties::FindProjection(node, 1)) {
FlagsContinuation cont(kOverflow, ovf); FlagsContinuation cont = FlagsContinuation::ForSet(kOverflow, ovf);
return VisitBinop(this, node, kIA32Add, &cont); return VisitBinop(this, node, kIA32Add, &cont);
} }
FlagsContinuation cont; FlagsContinuation cont;
...@@ -1309,7 +1337,7 @@ void InstructionSelector::VisitInt32AddWithOverflow(Node* node) { ...@@ -1309,7 +1337,7 @@ void InstructionSelector::VisitInt32AddWithOverflow(Node* node) {
void InstructionSelector::VisitInt32SubWithOverflow(Node* node) { void InstructionSelector::VisitInt32SubWithOverflow(Node* node) {
if (Node* ovf = NodeProperties::FindProjection(node, 1)) { if (Node* ovf = NodeProperties::FindProjection(node, 1)) {
FlagsContinuation cont(kOverflow, ovf); FlagsContinuation cont = FlagsContinuation::ForSet(kOverflow, ovf);
return VisitBinop(this, node, kIA32Sub, &cont); return VisitBinop(this, node, kIA32Sub, &cont);
} }
FlagsContinuation cont; FlagsContinuation cont;
...@@ -1318,37 +1346,41 @@ void InstructionSelector::VisitInt32SubWithOverflow(Node* node) { ...@@ -1318,37 +1346,41 @@ void InstructionSelector::VisitInt32SubWithOverflow(Node* node) {
void InstructionSelector::VisitFloat32Equal(Node* node) { void InstructionSelector::VisitFloat32Equal(Node* node) {
FlagsContinuation cont(kUnorderedEqual, node); FlagsContinuation cont = FlagsContinuation::ForSet(kUnorderedEqual, node);
VisitFloat32Compare(this, node, &cont); VisitFloat32Compare(this, node, &cont);
} }
void InstructionSelector::VisitFloat32LessThan(Node* node) { void InstructionSelector::VisitFloat32LessThan(Node* node) {
FlagsContinuation cont(kUnsignedGreaterThan, node); FlagsContinuation cont =
FlagsContinuation::ForSet(kUnsignedGreaterThan, node);
VisitFloat32Compare(this, node, &cont); VisitFloat32Compare(this, node, &cont);
} }
void InstructionSelector::VisitFloat32LessThanOrEqual(Node* node) { void InstructionSelector::VisitFloat32LessThanOrEqual(Node* node) {
FlagsContinuation cont(kUnsignedGreaterThanOrEqual, node); FlagsContinuation cont =
FlagsContinuation::ForSet(kUnsignedGreaterThanOrEqual, node);
VisitFloat32Compare(this, node, &cont); VisitFloat32Compare(this, node, &cont);
} }
void InstructionSelector::VisitFloat64Equal(Node* node) { void InstructionSelector::VisitFloat64Equal(Node* node) {
FlagsContinuation cont(kUnorderedEqual, node); FlagsContinuation cont = FlagsContinuation::ForSet(kUnorderedEqual, node);
VisitFloat64Compare(this, node, &cont); VisitFloat64Compare(this, node, &cont);
} }
void InstructionSelector::VisitFloat64LessThan(Node* node) { void InstructionSelector::VisitFloat64LessThan(Node* node) {
FlagsContinuation cont(kUnsignedGreaterThan, node); FlagsContinuation cont =
FlagsContinuation::ForSet(kUnsignedGreaterThan, node);
VisitFloat64Compare(this, node, &cont); VisitFloat64Compare(this, node, &cont);
} }
void InstructionSelector::VisitFloat64LessThanOrEqual(Node* node) { void InstructionSelector::VisitFloat64LessThanOrEqual(Node* node) {
FlagsContinuation cont(kUnsignedGreaterThanOrEqual, node); FlagsContinuation cont =
FlagsContinuation::ForSet(kUnsignedGreaterThanOrEqual, node);
VisitFloat64Compare(this, node, &cont); VisitFloat64Compare(this, node, &cont);
} }
......
...@@ -110,7 +110,12 @@ enum AddressingMode { ...@@ -110,7 +110,12 @@ enum AddressingMode {
std::ostream& operator<<(std::ostream& os, const AddressingMode& am); std::ostream& operator<<(std::ostream& os, const AddressingMode& am);
// The mode of the flags continuation (see below). // The mode of the flags continuation (see below).
enum FlagsMode { kFlags_none = 0, kFlags_branch = 1, kFlags_set = 2 }; enum FlagsMode {
kFlags_none = 0,
kFlags_branch = 1,
kFlags_deoptimize = 2,
kFlags_set = 3
};
std::ostream& operator<<(std::ostream& os, const FlagsMode& fm); std::ostream& operator<<(std::ostream& os, const FlagsMode& fm);
......
...@@ -303,22 +303,32 @@ class FlagsContinuation final { ...@@ -303,22 +303,32 @@ class FlagsContinuation final {
DCHECK_NOT_NULL(false_block); DCHECK_NOT_NULL(false_block);
} }
// Creates a new flags continuation from the given condition and result node. // Creates a new flags continuation for an eager deoptimization exit.
FlagsContinuation(FlagsCondition condition, Node* result) static FlagsContinuation ForDeoptimize(FlagsCondition condition,
: mode_(kFlags_set), condition_(condition), result_(result) { Node* frame_state) {
DCHECK_NOT_NULL(result); return FlagsContinuation(kFlags_deoptimize, condition, frame_state);
}
// Creates a new flags continuation for a boolean value.
static FlagsContinuation ForSet(FlagsCondition condition, Node* result) {
return FlagsContinuation(kFlags_set, condition, result);
} }
bool IsNone() const { return mode_ == kFlags_none; } bool IsNone() const { return mode_ == kFlags_none; }
bool IsBranch() const { return mode_ == kFlags_branch; } bool IsBranch() const { return mode_ == kFlags_branch; }
bool IsDeoptimize() const { return mode_ == kFlags_deoptimize; }
bool IsSet() const { return mode_ == kFlags_set; } bool IsSet() const { return mode_ == kFlags_set; }
FlagsCondition condition() const { FlagsCondition condition() const {
DCHECK(!IsNone()); DCHECK(!IsNone());
return condition_; return condition_;
} }
Node* frame_state() const {
DCHECK(IsDeoptimize());
return frame_state_or_result_;
}
Node* result() const { Node* result() const {
DCHECK(IsSet()); DCHECK(IsSet());
return result_; return frame_state_or_result_;
} }
BasicBlock* true_block() const { BasicBlock* true_block() const {
DCHECK(IsBranch()); DCHECK(IsBranch());
...@@ -355,11 +365,20 @@ class FlagsContinuation final { ...@@ -355,11 +365,20 @@ class FlagsContinuation final {
} }
private: private:
FlagsMode mode_; FlagsContinuation(FlagsMode mode, FlagsCondition condition,
Node* frame_state_or_result)
: mode_(mode),
condition_(condition),
frame_state_or_result_(frame_state_or_result) {
DCHECK_NOT_NULL(frame_state_or_result);
}
FlagsMode const mode_;
FlagsCondition condition_; FlagsCondition condition_;
Node* result_; // Only valid if mode_ == kFlags_set. Node* frame_state_or_result_; // Only valid if mode_ == kFlags_deoptimize
BasicBlock* true_block_; // Only valid if mode_ == kFlags_branch. // or mode_ == kFlags_set.
BasicBlock* false_block_; // Only valid if mode_ == kFlags_branch. BasicBlock* true_block_; // Only valid if mode_ == kFlags_branch.
BasicBlock* false_block_; // Only valid if mode_ == kFlags_branch.
}; };
} // namespace compiler } // namespace compiler
......
...@@ -873,6 +873,10 @@ void InstructionSelector::VisitNode(Node* node) { ...@@ -873,6 +873,10 @@ void InstructionSelector::VisitNode(Node* node) {
} }
case IrOpcode::kCall: case IrOpcode::kCall:
return VisitCall(node); return VisitCall(node);
case IrOpcode::kDeoptimizeIf:
return VisitDeoptimizeIf(node);
case IrOpcode::kDeoptimizeUnless:
return VisitDeoptimizeUnless(node);
case IrOpcode::kFrameState: case IrOpcode::kFrameState:
case IrOpcode::kStateValues: case IrOpcode::kStateValues:
case IrOpcode::kObjectState: case IrOpcode::kObjectState:
...@@ -1627,25 +1631,41 @@ void InstructionSelector::VisitReturn(Node* ret) { ...@@ -1627,25 +1631,41 @@ void InstructionSelector::VisitReturn(Node* ret) {
} }
} }
Instruction* InstructionSelector::EmitDeoptimize(InstructionCode opcode,
InstructionOperand output,
InstructionOperand a,
InstructionOperand b,
Node* frame_state) {
size_t output_count = output.IsInvalid() ? 0 : 1;
InstructionOperand inputs[] = {a, b};
size_t input_count = arraysize(inputs);
return EmitDeoptimize(opcode, output_count, &output, input_count, inputs,
frame_state);
}
void InstructionSelector::VisitDeoptimize(DeoptimizeKind kind, Node* value) { Instruction* InstructionSelector::EmitDeoptimize(
InstructionCode opcode, size_t output_count, InstructionOperand* outputs,
size_t input_count, InstructionOperand* inputs, Node* frame_state) {
OperandGenerator g(this); OperandGenerator g(this);
FrameStateDescriptor* const descriptor = GetFrameStateDescriptor(frame_state);
FrameStateDescriptor* desc = GetFrameStateDescriptor(value);
InstructionOperandVector args(instruction_zone()); InstructionOperandVector args(instruction_zone());
args.reserve(desc->GetTotalSize() + 1); // Include deopt id. args.reserve(input_count + 1 + descriptor->GetTotalSize());
for (size_t i = 0; i < input_count; ++i) {
InstructionSequence::StateId state_id = args.push_back(inputs[i]);
sequence()->AddFrameStateDescriptor(desc); }
opcode |= MiscField::encode(static_cast<int>(input_count));
InstructionSequence::StateId const state_id =
sequence()->AddFrameStateDescriptor(descriptor);
args.push_back(g.TempImmediate(state_id.ToInt())); args.push_back(g.TempImmediate(state_id.ToInt()));
StateObjectDeduplicator deduplicator(instruction_zone()); StateObjectDeduplicator deduplicator(instruction_zone());
AddInputsToFrameStateDescriptor(descriptor, frame_state, &g, &deduplicator,
AddInputsToFrameStateDescriptor(desc, value, &g, &deduplicator, &args, &args, FrameStateInputKind::kAny,
FrameStateInputKind::kAny,
instruction_zone()); instruction_zone());
return Emit(opcode, output_count, outputs, args.size(), &args.front(), 0,
nullptr);
}
void InstructionSelector::VisitDeoptimize(DeoptimizeKind kind, Node* value) {
InstructionCode opcode = kArchDeoptimize; InstructionCode opcode = kArchDeoptimize;
switch (kind) { switch (kind) {
case DeoptimizeKind::kEager: case DeoptimizeKind::kEager:
...@@ -1655,7 +1675,7 @@ void InstructionSelector::VisitDeoptimize(DeoptimizeKind kind, Node* value) { ...@@ -1655,7 +1675,7 @@ void InstructionSelector::VisitDeoptimize(DeoptimizeKind kind, Node* value) {
opcode |= MiscField::encode(Deoptimizer::SOFT); opcode |= MiscField::encode(Deoptimizer::SOFT);
break; break;
} }
Emit(opcode, 0, nullptr, args.size(), &args.front(), 0, nullptr); EmitDeoptimize(opcode, 0, nullptr, 0, nullptr, value);
} }
......
...@@ -99,6 +99,17 @@ class InstructionSelector final { ...@@ -99,6 +99,17 @@ class InstructionSelector final {
InstructionOperand* temps = nullptr); InstructionOperand* temps = nullptr);
Instruction* Emit(Instruction* instr); Instruction* Emit(Instruction* instr);
// ===========================================================================
// ===== Architecture-independent deoptimization exit emission methods. ======
// ===========================================================================
Instruction* EmitDeoptimize(InstructionCode opcode, InstructionOperand output,
InstructionOperand a, InstructionOperand b,
Node* frame_state);
Instruction* EmitDeoptimize(InstructionCode opcode, size_t output_count,
InstructionOperand* outputs, size_t input_count,
InstructionOperand* inputs, Node* frame_state);
// =========================================================================== // ===========================================================================
// ============== Architecture-independent CPU feature methods. ============== // ============== Architecture-independent CPU feature methods. ==============
// =========================================================================== // ===========================================================================
...@@ -243,6 +254,8 @@ class InstructionSelector final { ...@@ -243,6 +254,8 @@ class InstructionSelector final {
void VisitProjection(Node* node); void VisitProjection(Node* node);
void VisitConstant(Node* node); void VisitConstant(Node* node);
void VisitCall(Node* call, BasicBlock* handler = nullptr); void VisitCall(Node* call, BasicBlock* handler = nullptr);
void VisitDeoptimizeIf(Node* node);
void VisitDeoptimizeUnless(Node* node);
void VisitTailCall(Node* call); void VisitTailCall(Node* call);
void VisitGoto(BasicBlock* target); void VisitGoto(BasicBlock* target);
void VisitBranch(Node* input, BasicBlock* tbranch, BasicBlock* fbranch); void VisitBranch(Node* input, BasicBlock* tbranch, BasicBlock* fbranch);
......
...@@ -393,6 +393,8 @@ std::ostream& operator<<(std::ostream& os, const FlagsMode& fm) { ...@@ -393,6 +393,8 @@ std::ostream& operator<<(std::ostream& os, const FlagsMode& fm) {
return os; return os;
case kFlags_branch: case kFlags_branch:
return os << "branch"; return os << "branch";
case kFlags_deoptimize:
return os << "deoptimize";
case kFlags_set: case kFlags_set:
return os << "set"; return os << "set";
} }
......
...@@ -329,16 +329,8 @@ Reduction JSCallReducer::ReduceJSCallFunction(Node* node) { ...@@ -329,16 +329,8 @@ Reduction JSCallReducer::ReduceJSCallFunction(Node* node) {
Node* check = effect = Node* check = effect =
graph()->NewNode(javascript()->StrictEqual(), target, array_function, graph()->NewNode(javascript()->StrictEqual(), target, array_function,
context, effect, control); context, effect, control);
Node* branch = control = graph()->NewNode(common()->DeoptimizeUnless(), check, frame_state,
graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control); effect, control);
Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
Node* deoptimize =
graph()->NewNode(common()->Deoptimize(DeoptimizeKind::kEager),
frame_state, effect, if_false);
// TODO(bmeurer): This should be on the AdvancedReducer somehow.
NodeProperties::MergeControlToEnd(graph(), common(), deoptimize);
Revisit(graph()->end());
control = graph()->NewNode(common()->IfTrue(), branch);
// Turn the {node} into a {JSCreateArray} call. // Turn the {node} into a {JSCreateArray} call.
NodeProperties::ReplaceValueInput(node, array_function, 0); NodeProperties::ReplaceValueInput(node, array_function, 0);
...@@ -355,16 +347,8 @@ Reduction JSCallReducer::ReduceJSCallFunction(Node* node) { ...@@ -355,16 +347,8 @@ Reduction JSCallReducer::ReduceJSCallFunction(Node* node) {
Node* check = effect = Node* check = effect =
graph()->NewNode(javascript()->StrictEqual(), target, target_function, graph()->NewNode(javascript()->StrictEqual(), target, target_function,
context, effect, control); context, effect, control);
Node* branch = control = graph()->NewNode(common()->DeoptimizeUnless(), check,
graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control); frame_state, effect, control);
Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
Node* deoptimize =
graph()->NewNode(common()->Deoptimize(DeoptimizeKind::kEager),
frame_state, effect, if_false);
// TODO(bmeurer): This should be on the AdvancedReducer somehow.
NodeProperties::MergeControlToEnd(graph(), common(), deoptimize);
Revisit(graph()->end());
control = graph()->NewNode(common()->IfTrue(), branch);
// Specialize the JSCallFunction node to the {target_function}. // Specialize the JSCallFunction node to the {target_function}.
NodeProperties::ReplaceValueInput(node, target_function, 0); NodeProperties::ReplaceValueInput(node, target_function, 0);
...@@ -473,16 +457,8 @@ Reduction JSCallReducer::ReduceJSCallConstruct(Node* node) { ...@@ -473,16 +457,8 @@ Reduction JSCallReducer::ReduceJSCallConstruct(Node* node) {
Node* check = effect = Node* check = effect =
graph()->NewNode(javascript()->StrictEqual(), target, array_function, graph()->NewNode(javascript()->StrictEqual(), target, array_function,
context, effect, control); context, effect, control);
Node* branch = control = graph()->NewNode(common()->DeoptimizeUnless(), check, frame_state,
graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control); effect, control);
Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
Node* deoptimize =
graph()->NewNode(common()->Deoptimize(DeoptimizeKind::kEager),
frame_state, effect, if_false);
// TODO(bmeurer): This should be on the AdvancedReducer somehow.
NodeProperties::MergeControlToEnd(graph(), common(), deoptimize);
Revisit(graph()->end());
control = graph()->NewNode(common()->IfTrue(), branch);
// Turn the {node} into a {JSCreateArray} call. // Turn the {node} into a {JSCreateArray} call.
NodeProperties::ReplaceEffectInput(node, effect); NodeProperties::ReplaceEffectInput(node, effect);
...@@ -505,16 +481,8 @@ Reduction JSCallReducer::ReduceJSCallConstruct(Node* node) { ...@@ -505,16 +481,8 @@ Reduction JSCallReducer::ReduceJSCallConstruct(Node* node) {
Node* check = effect = Node* check = effect =
graph()->NewNode(javascript()->StrictEqual(), target, target_function, graph()->NewNode(javascript()->StrictEqual(), target, target_function,
context, effect, control); context, effect, control);
Node* branch = control = graph()->NewNode(common()->DeoptimizeUnless(), check,
graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control); frame_state, effect, control);
Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
Node* deoptimize =
graph()->NewNode(common()->Deoptimize(DeoptimizeKind::kEager),
frame_state, effect, if_false);
// TODO(bmeurer): This should be on the AdvancedReducer somehow.
NodeProperties::MergeControlToEnd(graph(), common(), deoptimize);
Revisit(graph()->end());
control = graph()->NewNode(common()->IfTrue(), branch);
// Specialize the JSCallConstruct node to the {target_function}. // Specialize the JSCallConstruct node to the {target_function}.
NodeProperties::ReplaceValueInput(node, target_function, 0); NodeProperties::ReplaceValueInput(node, target_function, 0);
......
...@@ -20,7 +20,7 @@ class JSOperatorBuilder; ...@@ -20,7 +20,7 @@ class JSOperatorBuilder;
// Performs strength reduction on {JSCallConstruct} and {JSCallFunction} nodes, // Performs strength reduction on {JSCallConstruct} and {JSCallFunction} nodes,
// which might allow inlining or other optimizations to be performed afterwards. // which might allow inlining or other optimizations to be performed afterwards.
class JSCallReducer final : public AdvancedReducer { class JSCallReducer final : public Reducer {
public: public:
// Flags that control the mode of operation. // Flags that control the mode of operation.
enum Flag { enum Flag {
...@@ -29,12 +29,9 @@ class JSCallReducer final : public AdvancedReducer { ...@@ -29,12 +29,9 @@ class JSCallReducer final : public AdvancedReducer {
}; };
typedef base::Flags<Flag> Flags; typedef base::Flags<Flag> Flags;
JSCallReducer(Editor* editor, JSGraph* jsgraph, Flags flags, JSCallReducer(JSGraph* jsgraph, Flags flags,
MaybeHandle<Context> native_context) MaybeHandle<Context> native_context)
: AdvancedReducer(editor), : jsgraph_(jsgraph), flags_(flags), native_context_(native_context) {}
jsgraph_(jsgraph),
flags_(flags),
native_context_(native_context) {}
Reduction Reduce(Node* node) final; Reduction Reduce(Node* node) final;
......
...@@ -45,6 +45,8 @@ Reduction JSGenericLowering::Reduce(Node* node) { ...@@ -45,6 +45,8 @@ Reduction JSGenericLowering::Reduce(Node* node) {
JS_OP_LIST(DECLARE_CASE) JS_OP_LIST(DECLARE_CASE)
#undef DECLARE_CASE #undef DECLARE_CASE
case IrOpcode::kBranch: case IrOpcode::kBranch:
case IrOpcode::kDeoptimizeIf:
case IrOpcode::kDeoptimizeUnless:
// TODO(mstarzinger): If typing is enabled then simplified lowering will // TODO(mstarzinger): If typing is enabled then simplified lowering will
// have inserted the correct ChangeBoolToBit, otherwise we need to perform // have inserted the correct ChangeBoolToBit, otherwise we need to perform
// poor-man's representation inference here and insert manual change. // poor-man's representation inference here and insert manual change.
......
...@@ -171,16 +171,8 @@ Reduction JSGlobalObjectSpecialization::ReduceJSStoreGlobal(Node* node) { ...@@ -171,16 +171,8 @@ Reduction JSGlobalObjectSpecialization::ReduceJSStoreGlobal(Node* node) {
Node* check = Node* check =
graph()->NewNode(simplified()->ReferenceEqual(Type::Tagged()), value, graph()->NewNode(simplified()->ReferenceEqual(Type::Tagged()), value,
jsgraph()->Constant(property_cell_value)); jsgraph()->Constant(property_cell_value));
Node* branch = control = graph()->NewNode(common()->DeoptimizeUnless(), check,
graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control); frame_state, effect, control);
Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
Node* deoptimize =
graph()->NewNode(common()->Deoptimize(DeoptimizeKind::kEager),
frame_state, effect, if_false);
// TODO(bmeurer): This should be on the AdvancedReducer somehow.
NodeProperties::MergeControlToEnd(graph(), common(), deoptimize);
Revisit(graph()->end());
control = graph()->NewNode(common()->IfTrue(), branch);
break; break;
} }
case PropertyCellType::kConstantType: { case PropertyCellType::kConstantType: {
...@@ -191,16 +183,8 @@ Reduction JSGlobalObjectSpecialization::ReduceJSStoreGlobal(Node* node) { ...@@ -191,16 +183,8 @@ Reduction JSGlobalObjectSpecialization::ReduceJSStoreGlobal(Node* node) {
Type* property_cell_value_type = Type::TaggedSigned(); Type* property_cell_value_type = Type::TaggedSigned();
if (property_cell_value->IsHeapObject()) { if (property_cell_value->IsHeapObject()) {
// Deoptimize if the {value} is a Smi. // Deoptimize if the {value} is a Smi.
Node* branch = graph()->NewNode(common()->Branch(BranchHint::kFalse), control = graph()->NewNode(common()->DeoptimizeIf(), check, frame_state,
check, control); effect, control);
Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
Node* deoptimize =
graph()->NewNode(common()->Deoptimize(DeoptimizeKind::kEager),
frame_state, effect, if_true);
// TODO(bmeurer): This should be on the AdvancedReducer somehow.
NodeProperties::MergeControlToEnd(graph(), common(), deoptimize);
Revisit(graph()->end());
control = graph()->NewNode(common()->IfFalse(), branch);
// Load the {value} map check against the {property_cell} map. // Load the {value} map check against the {property_cell} map.
Node* value_map = effect = Node* value_map = effect =
...@@ -213,16 +197,8 @@ Reduction JSGlobalObjectSpecialization::ReduceJSStoreGlobal(Node* node) { ...@@ -213,16 +197,8 @@ Reduction JSGlobalObjectSpecialization::ReduceJSStoreGlobal(Node* node) {
jsgraph()->HeapConstant(property_cell_value_map)); jsgraph()->HeapConstant(property_cell_value_map));
property_cell_value_type = Type::TaggedPointer(); property_cell_value_type = Type::TaggedPointer();
} }
Node* branch = control = graph()->NewNode(common()->DeoptimizeUnless(), check,
graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control); frame_state, effect, control);
Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
Node* deoptimize =
graph()->NewNode(common()->Deoptimize(DeoptimizeKind::kEager),
frame_state, effect, if_false);
// TODO(bmeurer): This should be on the AdvancedReducer somehow.
NodeProperties::MergeControlToEnd(graph(), common(), deoptimize);
Revisit(graph()->end());
control = graph()->NewNode(common()->IfTrue(), branch);
effect = graph()->NewNode( effect = graph()->NewNode(
simplified()->StoreField( simplified()->StoreField(
AccessBuilder::ForPropertyCellValue(property_cell_value_type)), AccessBuilder::ForPropertyCellValue(property_cell_value_type)),
......
...@@ -85,10 +85,6 @@ class JSNativeContextSpecialization final : public AdvancedReducer { ...@@ -85,10 +85,6 @@ class JSNativeContextSpecialization final : public AdvancedReducer {
Handle<Context> native_context, Handle<Context> native_context,
Handle<JSObject> holder); Handle<JSObject> holder);
// Assuming that {if_projection} is either IfTrue or IfFalse, adds a hint on
// the dominating Branch that {if_projection} is the unlikely (deferred) case.
void MarkAsDeferred(Node* if_projection);
// Retrieve the native context from the given {node} if known. // Retrieve the native context from the given {node} if known.
MaybeHandle<Context> GetNativeContext(Node* node); MaybeHandle<Context> GetNativeContext(Node* node);
......
...@@ -114,8 +114,13 @@ static void VisitBinop(InstructionSelector* selector, Node* node, ...@@ -114,8 +114,13 @@ static void VisitBinop(InstructionSelector* selector, Node* node,
DCHECK_GE(arraysize(inputs), input_count); DCHECK_GE(arraysize(inputs), input_count);
DCHECK_GE(arraysize(outputs), output_count); DCHECK_GE(arraysize(outputs), output_count);
selector->Emit(cont->Encode(opcode), output_count, outputs, input_count, opcode = cont->Encode(opcode);
inputs); if (cont->IsDeoptimize()) {
selector->EmitDeoptimize(opcode, output_count, outputs, input_count, inputs,
cont->frame_state());
} else {
selector->Emit(opcode, output_count, outputs, input_count, inputs);
}
} }
...@@ -979,6 +984,9 @@ static void VisitCompare(InstructionSelector* selector, InstructionCode opcode, ...@@ -979,6 +984,9 @@ static void VisitCompare(InstructionSelector* selector, InstructionCode opcode,
if (cont->IsBranch()) { if (cont->IsBranch()) {
selector->Emit(opcode, g.NoOutput(), left, right, selector->Emit(opcode, g.NoOutput(), left, right,
g.Label(cont->true_block()), g.Label(cont->false_block())); g.Label(cont->true_block()), g.Label(cont->false_block()));
} else if (cont->IsDeoptimize()) {
selector->EmitDeoptimize(opcode, g.NoOutput(), left, right,
cont->frame_state());
} else { } else {
DCHECK(cont->IsSet()); DCHECK(cont->IsSet());
selector->Emit(opcode, g.DefineAsRegister(cont->result()), left, right); selector->Emit(opcode, g.DefineAsRegister(cont->result()), left, right);
...@@ -1084,9 +1092,6 @@ void VisitWordCompare(InstructionSelector* selector, Node* node, ...@@ -1084,9 +1092,6 @@ void VisitWordCompare(InstructionSelector* selector, Node* node,
VisitWordCompare(selector, node, kMipsCmp, cont, false); VisitWordCompare(selector, node, kMipsCmp, cont, false);
} }
} // namespace
// Shared routine for word comparisons against zero. // Shared routine for word comparisons against zero.
void VisitWordCompareZero(InstructionSelector* selector, Node* user, void VisitWordCompareZero(InstructionSelector* selector, Node* user,
Node* value, FlagsContinuation* cont) { Node* value, FlagsContinuation* cont) {
...@@ -1175,12 +1180,17 @@ void VisitWordCompareZero(InstructionSelector* selector, Node* user, ...@@ -1175,12 +1180,17 @@ void VisitWordCompareZero(InstructionSelector* selector, Node* user,
if (cont->IsBranch()) { if (cont->IsBranch()) {
selector->Emit(opcode, g.NoOutput(), value_operand, g.TempImmediate(0), selector->Emit(opcode, g.NoOutput(), value_operand, g.TempImmediate(0),
g.Label(cont->true_block()), g.Label(cont->false_block())); g.Label(cont->true_block()), g.Label(cont->false_block()));
} else if (cont->IsDeoptimize()) {
selector->EmitDeoptimize(opcode, g.NoOutput(), value_operand,
g.TempImmediate(0), cont->frame_state());
} else { } else {
DCHECK(cont->IsSet());
selector->Emit(opcode, g.DefineAsRegister(cont->result()), value_operand, selector->Emit(opcode, g.DefineAsRegister(cont->result()), value_operand,
g.TempImmediate(0)); g.TempImmediate(0));
} }
} }
} // namespace
void InstructionSelector::VisitBranch(Node* branch, BasicBlock* tbranch, void InstructionSelector::VisitBranch(Node* branch, BasicBlock* tbranch,
BasicBlock* fbranch) { BasicBlock* fbranch) {
...@@ -1188,6 +1198,17 @@ void InstructionSelector::VisitBranch(Node* branch, BasicBlock* tbranch, ...@@ -1188,6 +1198,17 @@ void InstructionSelector::VisitBranch(Node* branch, BasicBlock* tbranch,
VisitWordCompareZero(this, branch, branch->InputAt(0), &cont); VisitWordCompareZero(this, branch, branch->InputAt(0), &cont);
} }
void InstructionSelector::VisitDeoptimizeIf(Node* node) {
FlagsContinuation cont =
FlagsContinuation::ForDeoptimize(kNotEqual, node->InputAt(1));
VisitWordCompareZero(this, node, node->InputAt(0), &cont);
}
void InstructionSelector::VisitDeoptimizeUnless(Node* node) {
FlagsContinuation cont =
FlagsContinuation::ForDeoptimize(kEqual, node->InputAt(1));
VisitWordCompareZero(this, node, node->InputAt(0), &cont);
}
void InstructionSelector::VisitSwitch(Node* node, const SwitchInfo& sw) { void InstructionSelector::VisitSwitch(Node* node, const SwitchInfo& sw) {
MipsOperandGenerator g(this); MipsOperandGenerator g(this);
...@@ -1218,7 +1239,7 @@ void InstructionSelector::VisitSwitch(Node* node, const SwitchInfo& sw) { ...@@ -1218,7 +1239,7 @@ void InstructionSelector::VisitSwitch(Node* node, const SwitchInfo& sw) {
void InstructionSelector::VisitWord32Equal(Node* const node) { void InstructionSelector::VisitWord32Equal(Node* const node) {
FlagsContinuation cont(kEqual, node); FlagsContinuation cont = FlagsContinuation::ForSet(kEqual, node);
Int32BinopMatcher m(node); Int32BinopMatcher m(node);
if (m.right().Is(0)) { if (m.right().Is(0)) {
return VisitWordCompareZero(this, m.node(), m.left().node(), &cont); return VisitWordCompareZero(this, m.node(), m.left().node(), &cont);
...@@ -1228,32 +1249,34 @@ void InstructionSelector::VisitWord32Equal(Node* const node) { ...@@ -1228,32 +1249,34 @@ void InstructionSelector::VisitWord32Equal(Node* const node) {
void InstructionSelector::VisitInt32LessThan(Node* node) { void InstructionSelector::VisitInt32LessThan(Node* node) {
FlagsContinuation cont(kSignedLessThan, node); FlagsContinuation cont = FlagsContinuation::ForSet(kSignedLessThan, node);
VisitWordCompare(this, node, &cont); VisitWordCompare(this, node, &cont);
} }
void InstructionSelector::VisitInt32LessThanOrEqual(Node* node) { void InstructionSelector::VisitInt32LessThanOrEqual(Node* node) {
FlagsContinuation cont(kSignedLessThanOrEqual, node); FlagsContinuation cont =
FlagsContinuation::ForSet(kSignedLessThanOrEqual, node);
VisitWordCompare(this, node, &cont); VisitWordCompare(this, node, &cont);
} }
void InstructionSelector::VisitUint32LessThan(Node* node) { void InstructionSelector::VisitUint32LessThan(Node* node) {
FlagsContinuation cont(kUnsignedLessThan, node); FlagsContinuation cont = FlagsContinuation::ForSet(kUnsignedLessThan, node);
VisitWordCompare(this, node, &cont); VisitWordCompare(this, node, &cont);
} }
void InstructionSelector::VisitUint32LessThanOrEqual(Node* node) { void InstructionSelector::VisitUint32LessThanOrEqual(Node* node) {
FlagsContinuation cont(kUnsignedLessThanOrEqual, node); FlagsContinuation cont =
FlagsContinuation::ForSet(kUnsignedLessThanOrEqual, node);
VisitWordCompare(this, node, &cont); VisitWordCompare(this, node, &cont);
} }
void InstructionSelector::VisitInt32AddWithOverflow(Node* node) { void InstructionSelector::VisitInt32AddWithOverflow(Node* node) {
if (Node* ovf = NodeProperties::FindProjection(node, 1)) { if (Node* ovf = NodeProperties::FindProjection(node, 1)) {
FlagsContinuation cont(kOverflow, ovf); FlagsContinuation cont = FlagsContinuation::ForSet(kOverflow, ovf);
return VisitBinop(this, node, kMipsAddOvf, &cont); return VisitBinop(this, node, kMipsAddOvf, &cont);
} }
FlagsContinuation cont; FlagsContinuation cont;
...@@ -1263,7 +1286,7 @@ void InstructionSelector::VisitInt32AddWithOverflow(Node* node) { ...@@ -1263,7 +1286,7 @@ void InstructionSelector::VisitInt32AddWithOverflow(Node* node) {
void InstructionSelector::VisitInt32SubWithOverflow(Node* node) { void InstructionSelector::VisitInt32SubWithOverflow(Node* node) {
if (Node* ovf = NodeProperties::FindProjection(node, 1)) { if (Node* ovf = NodeProperties::FindProjection(node, 1)) {
FlagsContinuation cont(kOverflow, ovf); FlagsContinuation cont = FlagsContinuation::ForSet(kOverflow, ovf);
return VisitBinop(this, node, kMipsSubOvf, &cont); return VisitBinop(this, node, kMipsSubOvf, &cont);
} }
FlagsContinuation cont; FlagsContinuation cont;
...@@ -1272,37 +1295,39 @@ void InstructionSelector::VisitInt32SubWithOverflow(Node* node) { ...@@ -1272,37 +1295,39 @@ void InstructionSelector::VisitInt32SubWithOverflow(Node* node) {
void InstructionSelector::VisitFloat32Equal(Node* node) { void InstructionSelector::VisitFloat32Equal(Node* node) {
FlagsContinuation cont(kEqual, node); FlagsContinuation cont = FlagsContinuation::ForSet(kEqual, node);
VisitFloat32Compare(this, node, &cont); VisitFloat32Compare(this, node, &cont);
} }
void InstructionSelector::VisitFloat32LessThan(Node* node) { void InstructionSelector::VisitFloat32LessThan(Node* node) {
FlagsContinuation cont(kUnsignedLessThan, node); FlagsContinuation cont = FlagsContinuation::ForSet(kUnsignedLessThan, node);
VisitFloat32Compare(this, node, &cont); VisitFloat32Compare(this, node, &cont);
} }
void InstructionSelector::VisitFloat32LessThanOrEqual(Node* node) { void InstructionSelector::VisitFloat32LessThanOrEqual(Node* node) {
FlagsContinuation cont(kUnsignedLessThanOrEqual, node); FlagsContinuation cont =
FlagsContinuation::ForSet(kUnsignedLessThanOrEqual, node);
VisitFloat32Compare(this, node, &cont); VisitFloat32Compare(this, node, &cont);
} }
void InstructionSelector::VisitFloat64Equal(Node* node) { void InstructionSelector::VisitFloat64Equal(Node* node) {
FlagsContinuation cont(kEqual, node); FlagsContinuation cont = FlagsContinuation::ForSet(kEqual, node);
VisitFloat64Compare(this, node, &cont); VisitFloat64Compare(this, node, &cont);
} }
void InstructionSelector::VisitFloat64LessThan(Node* node) { void InstructionSelector::VisitFloat64LessThan(Node* node) {
FlagsContinuation cont(kUnsignedLessThan, node); FlagsContinuation cont = FlagsContinuation::ForSet(kUnsignedLessThan, node);
VisitFloat64Compare(this, node, &cont); VisitFloat64Compare(this, node, &cont);
} }
void InstructionSelector::VisitFloat64LessThanOrEqual(Node* node) { void InstructionSelector::VisitFloat64LessThanOrEqual(Node* node) {
FlagsContinuation cont(kUnsignedLessThanOrEqual, node); FlagsContinuation cont =
FlagsContinuation::ForSet(kUnsignedLessThanOrEqual, node);
VisitFloat64Compare(this, node, &cont); VisitFloat64Compare(this, node, &cont);
} }
......
...@@ -119,8 +119,13 @@ static void VisitBinop(InstructionSelector* selector, Node* node, ...@@ -119,8 +119,13 @@ static void VisitBinop(InstructionSelector* selector, Node* node,
DCHECK_GE(arraysize(inputs), input_count); DCHECK_GE(arraysize(inputs), input_count);
DCHECK_GE(arraysize(outputs), output_count); DCHECK_GE(arraysize(outputs), output_count);
selector->Emit(cont->Encode(opcode), output_count, outputs, input_count, opcode = cont->Encode(opcode);
inputs); if (cont->IsDeoptimize()) {
selector->EmitDeoptimize(opcode, output_count, outputs, input_count, inputs,
cont->frame_state());
} else {
selector->Emit(opcode, output_count, outputs, input_count, inputs);
}
} }
...@@ -1431,6 +1436,9 @@ static void VisitCompare(InstructionSelector* selector, InstructionCode opcode, ...@@ -1431,6 +1436,9 @@ static void VisitCompare(InstructionSelector* selector, InstructionCode opcode,
if (cont->IsBranch()) { if (cont->IsBranch()) {
selector->Emit(opcode, g.NoOutput(), left, right, selector->Emit(opcode, g.NoOutput(), left, right,
g.Label(cont->true_block()), g.Label(cont->false_block())); g.Label(cont->true_block()), g.Label(cont->false_block()));
} else if (cont->IsDeoptimize()) {
selector->EmitDeoptimize(opcode, g.NoOutput(), left, right,
cont->frame_state());
} else { } else {
DCHECK(cont->IsSet()); DCHECK(cont->IsSet());
selector->Emit(opcode, g.DefineAsRegister(cont->result()), left, right); selector->Emit(opcode, g.DefineAsRegister(cont->result()), left, right);
...@@ -1542,7 +1550,6 @@ void VisitWord64Compare(InstructionSelector* selector, Node* node, ...@@ -1542,7 +1550,6 @@ void VisitWord64Compare(InstructionSelector* selector, Node* node,
VisitWordCompare(selector, node, kMips64Cmp, cont, false); VisitWordCompare(selector, node, kMips64Cmp, cont, false);
} }
} // namespace
void EmitWordCompareZero(InstructionSelector* selector, Node* value, void EmitWordCompareZero(InstructionSelector* selector, Node* value,
...@@ -1677,6 +1684,7 @@ void VisitWordCompareZero(InstructionSelector* selector, Node* user, ...@@ -1677,6 +1684,7 @@ void VisitWordCompareZero(InstructionSelector* selector, Node* user,
EmitWordCompareZero(selector, value, cont); EmitWordCompareZero(selector, value, cont);
} }
} // namespace
void InstructionSelector::VisitBranch(Node* branch, BasicBlock* tbranch, void InstructionSelector::VisitBranch(Node* branch, BasicBlock* tbranch,
BasicBlock* fbranch) { BasicBlock* fbranch) {
...@@ -1684,6 +1692,17 @@ void InstructionSelector::VisitBranch(Node* branch, BasicBlock* tbranch, ...@@ -1684,6 +1692,17 @@ void InstructionSelector::VisitBranch(Node* branch, BasicBlock* tbranch,
VisitWordCompareZero(this, branch, branch->InputAt(0), &cont); VisitWordCompareZero(this, branch, branch->InputAt(0), &cont);
} }
void InstructionSelector::VisitDeoptimizeIf(Node* node) {
FlagsContinuation cont =
FlagsContinuation::ForDeoptimize(kNotEqual, node->InputAt(1));
VisitWordCompareZero(this, node, node->InputAt(0), &cont);
}
void InstructionSelector::VisitDeoptimizeUnless(Node* node) {
FlagsContinuation cont =
FlagsContinuation::ForDeoptimize(kEqual, node->InputAt(1));
VisitWordCompareZero(this, node, node->InputAt(0), &cont);
}
void InstructionSelector::VisitSwitch(Node* node, const SwitchInfo& sw) { void InstructionSelector::VisitSwitch(Node* node, const SwitchInfo& sw) {
Mips64OperandGenerator g(this); Mips64OperandGenerator g(this);
...@@ -1714,7 +1733,7 @@ void InstructionSelector::VisitSwitch(Node* node, const SwitchInfo& sw) { ...@@ -1714,7 +1733,7 @@ void InstructionSelector::VisitSwitch(Node* node, const SwitchInfo& sw) {
void InstructionSelector::VisitWord32Equal(Node* const node) { void InstructionSelector::VisitWord32Equal(Node* const node) {
FlagsContinuation cont(kEqual, node); FlagsContinuation cont = FlagsContinuation::ForSet(kEqual, node);
Int32BinopMatcher m(node); Int32BinopMatcher m(node);
if (m.right().Is(0)) { if (m.right().Is(0)) {
return VisitWordCompareZero(this, m.node(), m.left().node(), &cont); return VisitWordCompareZero(this, m.node(), m.left().node(), &cont);
...@@ -1725,32 +1744,34 @@ void InstructionSelector::VisitWord32Equal(Node* const node) { ...@@ -1725,32 +1744,34 @@ void InstructionSelector::VisitWord32Equal(Node* const node) {
void InstructionSelector::VisitInt32LessThan(Node* node) { void InstructionSelector::VisitInt32LessThan(Node* node) {
FlagsContinuation cont(kSignedLessThan, node); FlagsContinuation cont = FlagsContinuation::ForSet(kSignedLessThan, node);
VisitWord32Compare(this, node, &cont); VisitWord32Compare(this, node, &cont);
} }
void InstructionSelector::VisitInt32LessThanOrEqual(Node* node) { void InstructionSelector::VisitInt32LessThanOrEqual(Node* node) {
FlagsContinuation cont(kSignedLessThanOrEqual, node); FlagsContinuation cont =
FlagsContinuation::ForSet(kSignedLessThanOrEqual, node);
VisitWord32Compare(this, node, &cont); VisitWord32Compare(this, node, &cont);
} }
void InstructionSelector::VisitUint32LessThan(Node* node) { void InstructionSelector::VisitUint32LessThan(Node* node) {
FlagsContinuation cont(kUnsignedLessThan, node); FlagsContinuation cont = FlagsContinuation::ForSet(kUnsignedLessThan, node);
VisitWord32Compare(this, node, &cont); VisitWord32Compare(this, node, &cont);
} }
void InstructionSelector::VisitUint32LessThanOrEqual(Node* node) { void InstructionSelector::VisitUint32LessThanOrEqual(Node* node) {
FlagsContinuation cont(kUnsignedLessThanOrEqual, node); FlagsContinuation cont =
FlagsContinuation::ForSet(kUnsignedLessThanOrEqual, node);
VisitWord32Compare(this, node, &cont); VisitWord32Compare(this, node, &cont);
} }
void InstructionSelector::VisitInt32AddWithOverflow(Node* node) { void InstructionSelector::VisitInt32AddWithOverflow(Node* node) {
if (Node* ovf = NodeProperties::FindProjection(node, 1)) { if (Node* ovf = NodeProperties::FindProjection(node, 1)) {
FlagsContinuation cont(kOverflow, ovf); FlagsContinuation cont = FlagsContinuation::ForSet(kOverflow, ovf);
return VisitBinop(this, node, kMips64Dadd, &cont); return VisitBinop(this, node, kMips64Dadd, &cont);
} }
FlagsContinuation cont; FlagsContinuation cont;
...@@ -1760,7 +1781,7 @@ void InstructionSelector::VisitInt32AddWithOverflow(Node* node) { ...@@ -1760,7 +1781,7 @@ void InstructionSelector::VisitInt32AddWithOverflow(Node* node) {
void InstructionSelector::VisitInt32SubWithOverflow(Node* node) { void InstructionSelector::VisitInt32SubWithOverflow(Node* node) {
if (Node* ovf = NodeProperties::FindProjection(node, 1)) { if (Node* ovf = NodeProperties::FindProjection(node, 1)) {
FlagsContinuation cont(kOverflow, ovf); FlagsContinuation cont = FlagsContinuation::ForSet(kOverflow, ovf);
return VisitBinop(this, node, kMips64Dsub, &cont); return VisitBinop(this, node, kMips64Dsub, &cont);
} }
FlagsContinuation cont; FlagsContinuation cont;
...@@ -1770,7 +1791,7 @@ void InstructionSelector::VisitInt32SubWithOverflow(Node* node) { ...@@ -1770,7 +1791,7 @@ void InstructionSelector::VisitInt32SubWithOverflow(Node* node) {
void InstructionSelector::VisitInt64AddWithOverflow(Node* node) { void InstructionSelector::VisitInt64AddWithOverflow(Node* node) {
if (Node* ovf = NodeProperties::FindProjection(node, 1)) { if (Node* ovf = NodeProperties::FindProjection(node, 1)) {
FlagsContinuation cont(kOverflow, ovf); FlagsContinuation cont = FlagsContinuation::ForSet(kOverflow, ovf);
return VisitBinop(this, node, kMips64DaddOvf, &cont); return VisitBinop(this, node, kMips64DaddOvf, &cont);
} }
FlagsContinuation cont; FlagsContinuation cont;
...@@ -1780,7 +1801,7 @@ void InstructionSelector::VisitInt64AddWithOverflow(Node* node) { ...@@ -1780,7 +1801,7 @@ void InstructionSelector::VisitInt64AddWithOverflow(Node* node) {
void InstructionSelector::VisitInt64SubWithOverflow(Node* node) { void InstructionSelector::VisitInt64SubWithOverflow(Node* node) {
if (Node* ovf = NodeProperties::FindProjection(node, 1)) { if (Node* ovf = NodeProperties::FindProjection(node, 1)) {
FlagsContinuation cont(kOverflow, ovf); FlagsContinuation cont = FlagsContinuation::ForSet(kOverflow, ovf);
return VisitBinop(this, node, kMips64DsubOvf, &cont); return VisitBinop(this, node, kMips64DsubOvf, &cont);
} }
FlagsContinuation cont; FlagsContinuation cont;
...@@ -1789,7 +1810,7 @@ void InstructionSelector::VisitInt64SubWithOverflow(Node* node) { ...@@ -1789,7 +1810,7 @@ void InstructionSelector::VisitInt64SubWithOverflow(Node* node) {
void InstructionSelector::VisitWord64Equal(Node* const node) { void InstructionSelector::VisitWord64Equal(Node* const node) {
FlagsContinuation cont(kEqual, node); FlagsContinuation cont = FlagsContinuation::ForSet(kEqual, node);
Int64BinopMatcher m(node); Int64BinopMatcher m(node);
if (m.right().Is(0)) { if (m.right().Is(0)) {
return VisitWordCompareZero(this, m.node(), m.left().node(), &cont); return VisitWordCompareZero(this, m.node(), m.left().node(), &cont);
...@@ -1800,61 +1821,65 @@ void InstructionSelector::VisitWord64Equal(Node* const node) { ...@@ -1800,61 +1821,65 @@ void InstructionSelector::VisitWord64Equal(Node* const node) {
void InstructionSelector::VisitInt64LessThan(Node* node) { void InstructionSelector::VisitInt64LessThan(Node* node) {
FlagsContinuation cont(kSignedLessThan, node); FlagsContinuation cont = FlagsContinuation::ForSet(kSignedLessThan, node);
VisitWord64Compare(this, node, &cont); VisitWord64Compare(this, node, &cont);
} }
void InstructionSelector::VisitInt64LessThanOrEqual(Node* node) { void InstructionSelector::VisitInt64LessThanOrEqual(Node* node) {
FlagsContinuation cont(kSignedLessThanOrEqual, node); FlagsContinuation cont =
FlagsContinuation::ForSet(kSignedLessThanOrEqual, node);
VisitWord64Compare(this, node, &cont); VisitWord64Compare(this, node, &cont);
} }
void InstructionSelector::VisitUint64LessThan(Node* node) { void InstructionSelector::VisitUint64LessThan(Node* node) {
FlagsContinuation cont(kUnsignedLessThan, node); FlagsContinuation cont = FlagsContinuation::ForSet(kUnsignedLessThan, node);
VisitWord64Compare(this, node, &cont); VisitWord64Compare(this, node, &cont);
} }
void InstructionSelector::VisitUint64LessThanOrEqual(Node* node) { void InstructionSelector::VisitUint64LessThanOrEqual(Node* node) {
FlagsContinuation cont(kUnsignedLessThanOrEqual, node); FlagsContinuation cont =
FlagsContinuation::ForSet(kUnsignedLessThanOrEqual, node);
VisitWord64Compare(this, node, &cont); VisitWord64Compare(this, node, &cont);
} }
void InstructionSelector::VisitFloat32Equal(Node* node) { void InstructionSelector::VisitFloat32Equal(Node* node) {
FlagsContinuation cont(kEqual, node); FlagsContinuation cont = FlagsContinuation::ForSet(kEqual, node);
VisitFloat32Compare(this, node, &cont); VisitFloat32Compare(this, node, &cont);
} }
void InstructionSelector::VisitFloat32LessThan(Node* node) { void InstructionSelector::VisitFloat32LessThan(Node* node) {
FlagsContinuation cont(kUnsignedLessThan, node); FlagsContinuation cont = FlagsContinuation::ForSet(kUnsignedLessThan, node);
VisitFloat32Compare(this, node, &cont); VisitFloat32Compare(this, node, &cont);
} }
void InstructionSelector::VisitFloat32LessThanOrEqual(Node* node) { void InstructionSelector::VisitFloat32LessThanOrEqual(Node* node) {
FlagsContinuation cont(kUnsignedLessThanOrEqual, node); FlagsContinuation cont =
FlagsContinuation::ForSet(kUnsignedLessThanOrEqual, node);
VisitFloat32Compare(this, node, &cont); VisitFloat32Compare(this, node, &cont);
} }
void InstructionSelector::VisitFloat64Equal(Node* node) { void InstructionSelector::VisitFloat64Equal(Node* node) {
FlagsContinuation cont(kEqual, node); FlagsContinuation cont = FlagsContinuation::ForSet(kEqual, node);
VisitFloat64Compare(this, node, &cont); VisitFloat64Compare(this, node, &cont);
} }
void InstructionSelector::VisitFloat64LessThan(Node* node) { void InstructionSelector::VisitFloat64LessThan(Node* node) {
FlagsContinuation cont(kUnsignedLessThan, node); FlagsContinuation cont = FlagsContinuation::ForSet(kUnsignedLessThan, node);
VisitFloat64Compare(this, node, &cont); VisitFloat64Compare(this, node, &cont);
} }
void InstructionSelector::VisitFloat64LessThanOrEqual(Node* node) { void InstructionSelector::VisitFloat64LessThanOrEqual(Node* node) {
FlagsContinuation cont(kUnsignedLessThanOrEqual, node); FlagsContinuation cont =
FlagsContinuation::ForSet(kUnsignedLessThanOrEqual, node);
VisitFloat64Compare(this, node, &cont); VisitFloat64Compare(this, node, &cont);
} }
......
...@@ -21,6 +21,8 @@ ...@@ -21,6 +21,8 @@
V(IfDefault) \ V(IfDefault) \
V(Merge) \ V(Merge) \
V(Deoptimize) \ V(Deoptimize) \
V(DeoptimizeIf) \
V(DeoptimizeUnless) \
V(Return) \ V(Return) \
V(TailCall) \ V(TailCall) \
V(Terminate) \ V(Terminate) \
......
...@@ -539,7 +539,7 @@ struct InliningPhase { ...@@ -539,7 +539,7 @@ struct InliningPhase {
data->common()); data->common());
CommonOperatorReducer common_reducer(&graph_reducer, data->graph(), CommonOperatorReducer common_reducer(&graph_reducer, data->graph(),
data->common(), data->machine()); data->common(), data->machine());
JSCallReducer call_reducer(&graph_reducer, data->jsgraph(), JSCallReducer call_reducer(data->jsgraph(),
data->info()->is_deoptimization_enabled() data->info()->is_deoptimization_enabled()
? JSCallReducer::kDeoptimizationEnabled ? JSCallReducer::kDeoptimizationEnabled
: JSCallReducer::kNoFlags, : JSCallReducer::kNoFlags,
......
...@@ -862,6 +862,12 @@ class RepresentationSelector { ...@@ -862,6 +862,12 @@ class RepresentationSelector {
case IrOpcode::kHeapConstant: case IrOpcode::kHeapConstant:
return VisitLeaf(node, NodeOutputInfo::AnyTagged()); return VisitLeaf(node, NodeOutputInfo::AnyTagged());
case IrOpcode::kDeoptimizeIf:
case IrOpcode::kDeoptimizeUnless:
ProcessInput(node, 0, UseInfo::Bool());
ProcessInput(node, 1, UseInfo::AnyTagged());
ProcessRemainingInputs(node, 2);
break;
case IrOpcode::kBranch: case IrOpcode::kBranch:
ProcessInput(node, 0, UseInfo::Bool()); ProcessInput(node, 0, UseInfo::Bool());
EnqueueInput(node, NodeProperties::FirstControlIndex(node)); EnqueueInput(node, NodeProperties::FirstControlIndex(node));
......
...@@ -114,6 +114,8 @@ class Typer::Visitor : public Reducer { ...@@ -114,6 +114,8 @@ class Typer::Visitor : public Reducer {
DECLARE_CASE(IfDefault) DECLARE_CASE(IfDefault)
DECLARE_CASE(Merge) DECLARE_CASE(Merge)
DECLARE_CASE(Deoptimize) DECLARE_CASE(Deoptimize)
DECLARE_CASE(DeoptimizeIf)
DECLARE_CASE(DeoptimizeUnless)
DECLARE_CASE(Return) DECLARE_CASE(Return)
DECLARE_CASE(TailCall) DECLARE_CASE(TailCall)
DECLARE_CASE(Terminate) DECLARE_CASE(Terminate)
...@@ -158,6 +160,8 @@ class Typer::Visitor : public Reducer { ...@@ -158,6 +160,8 @@ class Typer::Visitor : public Reducer {
DECLARE_CASE(IfDefault) DECLARE_CASE(IfDefault)
DECLARE_CASE(Merge) DECLARE_CASE(Merge)
DECLARE_CASE(Deoptimize) DECLARE_CASE(Deoptimize)
DECLARE_CASE(DeoptimizeIf)
DECLARE_CASE(DeoptimizeUnless)
DECLARE_CASE(Return) DECLARE_CASE(Return)
DECLARE_CASE(TailCall) DECLARE_CASE(TailCall)
DECLARE_CASE(Terminate) DECLARE_CASE(Terminate)
......
...@@ -274,6 +274,11 @@ void Verifier::Visitor::Check(Node* node) { ...@@ -274,6 +274,11 @@ void Verifier::Visitor::Check(Node* node) {
// Type is empty. // Type is empty.
CheckNotTyped(node); CheckNotTyped(node);
break; break;
case IrOpcode::kDeoptimizeIf:
case IrOpcode::kDeoptimizeUnless:
// Type is empty.
CheckNotTyped(node);
break;
case IrOpcode::kDeoptimize: case IrOpcode::kDeoptimize:
case IrOpcode::kReturn: case IrOpcode::kReturn:
case IrOpcode::kThrow: case IrOpcode::kThrow:
......
...@@ -177,6 +177,9 @@ ...@@ -177,6 +177,9 @@
# issue 4078: # issue 4078:
'allocation-site-info': [PASS, NO_VARIANTS], 'allocation-site-info': [PASS, NO_VARIANTS],
# TODO(turbofan): The escape analysis needs some investigation.
'compiler/escape-analysis-deopt-5': [PASS, NO_VARIANTS],
############################################################################## ##############################################################################
# Too slow in debug mode with --stress-opt mode. # Too slow in debug mode with --stress-opt mode.
'compiler/regress-stacktrace-methods': [PASS, ['mode == debug', SKIP]], 'compiler/regress-stacktrace-methods': [PASS, ['mode == debug', SKIP]],
......
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