Commit e144335f authored by jarin's avatar jarin Committed by Commit bot

[turbofan] Insert sigma nodes for loop variable backedge.

If we infer loop variable bounds, we need to insert a type rename node
(sigma) to make sure that simplified lowering can choose representations
consistently.

Review-Url: https://codereview.chromium.org/2222513002
Cr-Commit-Position: refs/heads/master@{#38391}
parent ff1c3cdb
...@@ -191,6 +191,11 @@ RegionObservability RegionObservabilityOf(Operator const* op) { ...@@ -191,6 +191,11 @@ RegionObservability RegionObservabilityOf(Operator const* op) {
return OpParameter<RegionObservability>(op); return OpParameter<RegionObservability>(op);
} }
Type* TypeGuardTypeOf(Operator const* op) {
DCHECK_EQ(IrOpcode::kTypeGuard, op->opcode());
return OpParameter<Type*>(op);
}
std::ostream& operator<<(std::ostream& os, std::ostream& operator<<(std::ostream& os,
const ZoneVector<MachineType>* types) { const ZoneVector<MachineType>* types) {
// Print all the MachineTypes, separated by commas. // Print all the MachineTypes, separated by commas.
...@@ -798,6 +803,13 @@ const Operator* CommonOperatorBuilder::Phi(MachineRepresentation rep, ...@@ -798,6 +803,13 @@ const Operator* CommonOperatorBuilder::Phi(MachineRepresentation rep,
rep); // parameter rep); // parameter
} }
const Operator* CommonOperatorBuilder::TypeGuard(Type* type) {
return new (zone()) Operator1<Type*>( // --
IrOpcode::kTypeGuard, Operator::kPure, // opcode
"TypeGuard", // name
1, 0, 1, 1, 0, 0, // counts
type); // parameter
}
const Operator* CommonOperatorBuilder::EffectPhi(int effect_input_count) { const Operator* CommonOperatorBuilder::EffectPhi(int effect_input_count) {
DCHECK(effect_input_count > 0); // Disallow empty effect phis. DCHECK(effect_input_count > 0); // Disallow empty effect phis.
......
...@@ -169,6 +169,8 @@ RegionObservability RegionObservabilityOf(Operator const*) WARN_UNUSED_RESULT; ...@@ -169,6 +169,8 @@ RegionObservability RegionObservabilityOf(Operator const*) WARN_UNUSED_RESULT;
std::ostream& operator<<(std::ostream& os, std::ostream& operator<<(std::ostream& os,
const ZoneVector<MachineType>* types); const ZoneVector<MachineType>* types);
Type* TypeGuardTypeOf(Operator const*) WARN_UNUSED_RESULT;
// Interface for building common operators that can be used at any level of IR, // Interface for building common operators that can be used at any level of IR,
// including JavaScript, mid-level, and low-level. // including JavaScript, mid-level, and low-level.
class CommonOperatorBuilder final : public ZoneObject { class CommonOperatorBuilder final : public ZoneObject {
...@@ -235,6 +237,7 @@ class CommonOperatorBuilder final : public ZoneObject { ...@@ -235,6 +237,7 @@ class CommonOperatorBuilder final : public ZoneObject {
const Operator* TailCall(const CallDescriptor* descriptor); const Operator* TailCall(const CallDescriptor* descriptor);
const Operator* Projection(size_t index); const Operator* Projection(size_t index);
const Operator* Retain(); const Operator* Retain();
const Operator* TypeGuard(Type* type);
// Constructs a new merge or phi operator with the same opcode as {op}, but // Constructs a new merge or phi operator with the same opcode as {op}, but
// with {size} inputs. // with {size} inputs.
......
...@@ -369,10 +369,11 @@ void LoopVariableOptimizer::ChangeToInductionVariablePhis() { ...@@ -369,10 +369,11 @@ void LoopVariableOptimizer::ChangeToInductionVariablePhis() {
} }
} }
void LoopVariableOptimizer::ChangeFromInductionVariablePhis() { void LoopVariableOptimizer::ChangeToPhisAndInsertGuards() {
for (auto entry : induction_vars_) { for (auto entry : induction_vars_) {
InductionVariable* induction_var = entry.second; InductionVariable* induction_var = entry.second;
if (induction_var->phi()->opcode() == IrOpcode::kInductionVariablePhi) { if (induction_var->phi()->opcode() == IrOpcode::kInductionVariablePhi) {
// Turn the induction variable phi back to normal phi.
int value_count = 2; int value_count = 2;
Node* control = NodeProperties::GetControlInput(induction_var->phi()); Node* control = NodeProperties::GetControlInput(induction_var->phi());
DCHECK_EQ(value_count, control->op()->ControlInputCount()); DCHECK_EQ(value_count, control->op()->ControlInputCount());
...@@ -381,6 +382,19 @@ void LoopVariableOptimizer::ChangeFromInductionVariablePhis() { ...@@ -381,6 +382,19 @@ void LoopVariableOptimizer::ChangeFromInductionVariablePhis() {
NodeProperties::ChangeOp( NodeProperties::ChangeOp(
induction_var->phi(), induction_var->phi(),
common()->Phi(MachineRepresentation::kTagged, value_count)); common()->Phi(MachineRepresentation::kTagged, value_count));
// If the backedge is not a subtype of the phi's type, we insert a sigma
// to get the typing right.
Node* backedge_value = induction_var->phi()->InputAt(1);
Type* backedge_type = NodeProperties::GetType(backedge_value);
Type* phi_type = NodeProperties::GetType(induction_var->phi());
if (!backedge_type->Is(phi_type)) {
Node* backedge_control =
NodeProperties::GetControlInput(induction_var->phi())->InputAt(1);
Node* rename = graph()->NewNode(common()->TypeGuard(phi_type),
backedge_value, backedge_control);
induction_var->phi()->ReplaceInput(1, rename);
}
} }
} }
} }
......
...@@ -68,7 +68,7 @@ class LoopVariableOptimizer { ...@@ -68,7 +68,7 @@ class LoopVariableOptimizer {
} }
void ChangeToInductionVariablePhis(); void ChangeToInductionVariablePhis();
void ChangeFromInductionVariablePhis(); void ChangeToPhisAndInsertGuards();
private: private:
const int kAssumedLoopEntryIndex = 0; const int kAssumedLoopEntryIndex = 0;
......
...@@ -62,7 +62,8 @@ ...@@ -62,7 +62,8 @@
V(LoopExitValue) \ V(LoopExitValue) \
V(LoopExitEffect) \ V(LoopExitEffect) \
V(Projection) \ V(Projection) \
V(Retain) V(Retain) \
V(TypeGuard)
#define COMMON_OP_LIST(V) \ #define COMMON_OP_LIST(V) \
CONSTANT_OP_LIST(V) \ CONSTANT_OP_LIST(V) \
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
#include "src/compiler/operation-typer.h" #include "src/compiler/operation-typer.h"
#include "src/compiler/common-operator.h"
#include "src/factory.h" #include "src/factory.h"
#include "src/isolate.h" #include "src/isolate.h"
#include "src/type-cache.h" #include "src/type-cache.h"
...@@ -911,6 +912,10 @@ Type* OperationTyper::FalsifyUndefined(ComparisonOutcome outcome) { ...@@ -911,6 +912,10 @@ Type* OperationTyper::FalsifyUndefined(ComparisonOutcome outcome) {
return singleton_true(); return singleton_true();
} }
Type* OperationTyper::TypeTypeGuard(const Operator* sigma_op, Type* input) {
return Type::Intersect(input, TypeGuardTypeOf(sigma_op), zone());
}
} // namespace compiler } // namespace compiler
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
...@@ -19,6 +19,8 @@ class Zone; ...@@ -19,6 +19,8 @@ class Zone;
namespace compiler { namespace compiler {
class Operator;
class OperationTyper { class OperationTyper {
public: public:
OperationTyper(Isolate* isolate, Zone* zone); OperationTyper(Isolate* isolate, Zone* zone);
...@@ -43,6 +45,8 @@ class OperationTyper { ...@@ -43,6 +45,8 @@ class OperationTyper {
SIMPLIFIED_SPECULATIVE_NUMBER_BINOP_LIST(DECLARE_METHOD) SIMPLIFIED_SPECULATIVE_NUMBER_BINOP_LIST(DECLARE_METHOD)
#undef DECLARE_METHOD #undef DECLARE_METHOD
Type* TypeTypeGuard(const Operator* sigma_op, Type* input);
enum ComparisonOutcomeFlags { enum ComparisonOutcomeFlags {
kComparisonTrue = 1, kComparisonTrue = 1,
kComparisonFalse = 2, kComparisonFalse = 2,
......
...@@ -415,6 +415,12 @@ class RepresentationSelector { ...@@ -415,6 +415,12 @@ class RepresentationSelector {
break; break;
} }
case IrOpcode::kTypeGuard: {
new_type = op_typer_.TypeTypeGuard(node->op(),
FeedbackTypeOf(node->InputAt(0)));
break;
}
case IrOpcode::kSelect: { case IrOpcode::kSelect: {
new_type = TypeSelect(node); new_type = TypeSelect(node);
break; break;
...@@ -819,9 +825,12 @@ class RepresentationSelector { ...@@ -819,9 +825,12 @@ class RepresentationSelector {
} }
// Infer representation for phi-like nodes. // Infer representation for phi-like nodes.
MachineRepresentation GetOutputInfoForPhi(Node* node, Truncation use) { // The {node} parameter is only used to decide on the int64 representation.
// Once the type system supports an external pointer type, the {node}
// parameter can be removed.
MachineRepresentation GetOutputInfoForPhi(Node* node, Type* type,
Truncation use) {
// Compute the representation. // Compute the representation.
Type* type = TypeOf(node);
if (type->Is(Type::None())) { if (type->Is(Type::None())) {
return MachineRepresentation::kNone; return MachineRepresentation::kNone;
} else if (type->Is(Type::Signed32()) || type->Is(Type::Unsigned32())) { } else if (type->Is(Type::Signed32()) || type->Is(Type::Unsigned32())) {
...@@ -868,7 +877,8 @@ class RepresentationSelector { ...@@ -868,7 +877,8 @@ class RepresentationSelector {
SimplifiedLowering* lowering) { SimplifiedLowering* lowering) {
ProcessInput(node, 0, UseInfo::Bool()); ProcessInput(node, 0, UseInfo::Bool());
MachineRepresentation output = GetOutputInfoForPhi(node, truncation); MachineRepresentation output =
GetOutputInfoForPhi(node, TypeOf(node), truncation);
SetOutput(node, output); SetOutput(node, output);
if (lower()) { if (lower()) {
...@@ -889,7 +899,8 @@ class RepresentationSelector { ...@@ -889,7 +899,8 @@ class RepresentationSelector {
// Helper for handling phis. // Helper for handling phis.
void VisitPhi(Node* node, Truncation truncation, void VisitPhi(Node* node, Truncation truncation,
SimplifiedLowering* lowering) { SimplifiedLowering* lowering) {
MachineRepresentation output = GetOutputInfoForPhi(node, truncation); MachineRepresentation output =
GetOutputInfoForPhi(node, TypeOf(node), truncation);
// Only set the output representation if not running with type // Only set the output representation if not running with type
// feedback. (Feedback typing will set the representation.) // feedback. (Feedback typing will set the representation.)
SetOutput(node, output); SetOutput(node, output);
...@@ -903,7 +914,7 @@ class RepresentationSelector { ...@@ -903,7 +914,7 @@ class RepresentationSelector {
} }
// Convert inputs to the output representation of this phi, pass the // Convert inputs to the output representation of this phi, pass the
// truncation truncation along. // truncation along.
UseInfo input_use(output, truncation); UseInfo input_use(output, truncation);
for (int i = 0; i < node->InputCount(); i++) { for (int i = 0; i < node->InputCount(); i++) {
ProcessInput(node, i, i < values ? input_use : UseInfo::None()); ProcessInput(node, i, i < values ? input_use : UseInfo::None());
...@@ -2530,6 +2541,17 @@ class RepresentationSelector { ...@@ -2530,6 +2541,17 @@ class RepresentationSelector {
return VisitLeaf(node, MachineType::PointerRepresentation()); return VisitLeaf(node, MachineType::PointerRepresentation());
case IrOpcode::kStateValues: case IrOpcode::kStateValues:
return VisitStateValues(node); return VisitStateValues(node);
case IrOpcode::kTypeGuard: {
// We just get rid of the sigma here. In principle, it should be
// possible to refine the truncation and representation based on
// the sigma's type.
MachineRepresentation output =
GetOutputInfoForPhi(node, TypeOf(node->InputAt(0)), truncation);
VisitUnop(node, UseInfo(output, truncation), output);
if (lower()) DeferReplacement(node, node->InputAt(0));
return;
}
// The following opcodes are not produced before representation // The following opcodes are not produced before representation
// inference runs, so we do not have any real test coverage. // inference runs, so we do not have any real test coverage.
...@@ -2572,8 +2594,6 @@ class RepresentationSelector { ...@@ -2572,8 +2594,6 @@ class RepresentationSelector {
Node* control = NodeProperties::GetControlInput(node); Node* control = NodeProperties::GetControlInput(node);
Node* effect = NodeProperties::GetEffectInput(node); Node* effect = NodeProperties::GetEffectInput(node);
ReplaceEffectControlUses(node, effect, control); ReplaceEffectControlUses(node, effect, control);
} else {
DCHECK_EQ(0, node->op()->ControlInputCount());
} }
replacements_.push_back(node); replacements_.push_back(node);
......
...@@ -4,6 +4,8 @@ ...@@ -4,6 +4,8 @@
#include "src/compiler/typer.h" #include "src/compiler/typer.h"
#include <iomanip>
#include "src/base/flags.h" #include "src/base/flags.h"
#include "src/bootstrapper.h" #include "src/bootstrapper.h"
#include "src/compiler/common-operator.h" #include "src/compiler/common-operator.h"
...@@ -337,7 +339,7 @@ void Typer::Run(const NodeVector& roots, ...@@ -337,7 +339,7 @@ void Typer::Run(const NodeVector& roots,
graph_reducer.ReduceGraph(); graph_reducer.ReduceGraph();
if (induction_vars != nullptr) { if (induction_vars != nullptr) {
induction_vars->ChangeFromInductionVariablePhis(); induction_vars->ChangeToPhisAndInsertGuards();
} }
} }
...@@ -695,6 +697,7 @@ Type* Typer::Visitor::TypeInductionVariablePhi(Node* node) { ...@@ -695,6 +697,7 @@ Type* Typer::Visitor::TypeInductionVariablePhi(Node* node) {
} }
if (FLAG_trace_turbo_loop) { if (FLAG_trace_turbo_loop) {
OFStream os(stdout); OFStream os(stdout);
os << std::setprecision(10);
os << "Loop (" << NodeProperties::GetControlInput(node)->id() os << "Loop (" << NodeProperties::GetControlInput(node)->id()
<< ") variable bounds for phi " << node->id() << ": (" << min << ", " << ") variable bounds for phi " << node->id() << ": (" << min << ", "
<< max << ")\n"; << max << ")\n";
...@@ -765,6 +768,11 @@ Type* Typer::Visitor::TypeProjection(Node* node) { ...@@ -765,6 +768,11 @@ Type* Typer::Visitor::TypeProjection(Node* node) {
return Type::Any(); return Type::Any();
} }
Type* Typer::Visitor::TypeTypeGuard(Node* node) {
Type* const type = Operand(node, 0);
return typer_->operation_typer()->TypeTypeGuard(node->op(), type);
}
Type* Typer::Visitor::TypeDead(Node* node) { return Type::None(); } Type* Typer::Visitor::TypeDead(Node* node) { return Type::None(); }
// JS comparison operators. // JS comparison operators.
......
...@@ -1072,6 +1072,9 @@ void Verifier::Visitor::Check(Node* node) { ...@@ -1072,6 +1072,9 @@ void Verifier::Visitor::Check(Node* node) {
CheckValueInputIs(node, 0, Type::Number()); CheckValueInputIs(node, 0, Type::Number());
CheckUpperIs(node, Type::Number()); CheckUpperIs(node, Type::Number());
break; break;
case IrOpcode::kTypeGuard:
CheckUpperIs(node, TypeGuardTypeOf(node->op()));
break;
// Machine operators // Machine operators
// ----------------------- // -----------------------
......
// Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --turbo-loop-variable
(function() {
function f() {
for (var i = 0; i < 4294967295; i += 2) {
if (i === 10) break;
}
}
f();
})();
(function() {
function f() {
for (var i = 0; i < 4294967293; i += 2) {
if (i === 10) break;
}
}
f();
})();
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