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) {
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,
const ZoneVector<MachineType>* types) {
// Print all the MachineTypes, separated by commas.
......@@ -798,6 +803,13 @@ const Operator* CommonOperatorBuilder::Phi(MachineRepresentation rep,
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) {
DCHECK(effect_input_count > 0); // Disallow empty effect phis.
......
......@@ -169,6 +169,8 @@ RegionObservability RegionObservabilityOf(Operator const*) WARN_UNUSED_RESULT;
std::ostream& operator<<(std::ostream& os,
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,
// including JavaScript, mid-level, and low-level.
class CommonOperatorBuilder final : public ZoneObject {
......@@ -235,6 +237,7 @@ class CommonOperatorBuilder final : public ZoneObject {
const Operator* TailCall(const CallDescriptor* descriptor);
const Operator* Projection(size_t index);
const Operator* Retain();
const Operator* TypeGuard(Type* type);
// Constructs a new merge or phi operator with the same opcode as {op}, but
// with {size} inputs.
......
......@@ -369,10 +369,11 @@ void LoopVariableOptimizer::ChangeToInductionVariablePhis() {
}
}
void LoopVariableOptimizer::ChangeFromInductionVariablePhis() {
void LoopVariableOptimizer::ChangeToPhisAndInsertGuards() {
for (auto entry : induction_vars_) {
InductionVariable* induction_var = entry.second;
if (induction_var->phi()->opcode() == IrOpcode::kInductionVariablePhi) {
// Turn the induction variable phi back to normal phi.
int value_count = 2;
Node* control = NodeProperties::GetControlInput(induction_var->phi());
DCHECK_EQ(value_count, control->op()->ControlInputCount());
......@@ -381,6 +382,19 @@ void LoopVariableOptimizer::ChangeFromInductionVariablePhis() {
NodeProperties::ChangeOp(
induction_var->phi(),
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 {
}
void ChangeToInductionVariablePhis();
void ChangeFromInductionVariablePhis();
void ChangeToPhisAndInsertGuards();
private:
const int kAssumedLoopEntryIndex = 0;
......
......@@ -62,7 +62,8 @@
V(LoopExitValue) \
V(LoopExitEffect) \
V(Projection) \
V(Retain)
V(Retain) \
V(TypeGuard)
#define COMMON_OP_LIST(V) \
CONSTANT_OP_LIST(V) \
......
......@@ -4,6 +4,7 @@
#include "src/compiler/operation-typer.h"
#include "src/compiler/common-operator.h"
#include "src/factory.h"
#include "src/isolate.h"
#include "src/type-cache.h"
......@@ -911,6 +912,10 @@ Type* OperationTyper::FalsifyUndefined(ComparisonOutcome outcome) {
return singleton_true();
}
Type* OperationTyper::TypeTypeGuard(const Operator* sigma_op, Type* input) {
return Type::Intersect(input, TypeGuardTypeOf(sigma_op), zone());
}
} // namespace compiler
} // namespace internal
} // namespace v8
......@@ -19,6 +19,8 @@ class Zone;
namespace compiler {
class Operator;
class OperationTyper {
public:
OperationTyper(Isolate* isolate, Zone* zone);
......@@ -43,6 +45,8 @@ class OperationTyper {
SIMPLIFIED_SPECULATIVE_NUMBER_BINOP_LIST(DECLARE_METHOD)
#undef DECLARE_METHOD
Type* TypeTypeGuard(const Operator* sigma_op, Type* input);
enum ComparisonOutcomeFlags {
kComparisonTrue = 1,
kComparisonFalse = 2,
......
......@@ -415,6 +415,12 @@ class RepresentationSelector {
break;
}
case IrOpcode::kTypeGuard: {
new_type = op_typer_.TypeTypeGuard(node->op(),
FeedbackTypeOf(node->InputAt(0)));
break;
}
case IrOpcode::kSelect: {
new_type = TypeSelect(node);
break;
......@@ -819,9 +825,12 @@ class RepresentationSelector {
}
// 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.
Type* type = TypeOf(node);
if (type->Is(Type::None())) {
return MachineRepresentation::kNone;
} else if (type->Is(Type::Signed32()) || type->Is(Type::Unsigned32())) {
......@@ -868,7 +877,8 @@ class RepresentationSelector {
SimplifiedLowering* lowering) {
ProcessInput(node, 0, UseInfo::Bool());
MachineRepresentation output = GetOutputInfoForPhi(node, truncation);
MachineRepresentation output =
GetOutputInfoForPhi(node, TypeOf(node), truncation);
SetOutput(node, output);
if (lower()) {
......@@ -889,7 +899,8 @@ class RepresentationSelector {
// Helper for handling phis.
void VisitPhi(Node* node, Truncation truncation,
SimplifiedLowering* lowering) {
MachineRepresentation output = GetOutputInfoForPhi(node, truncation);
MachineRepresentation output =
GetOutputInfoForPhi(node, TypeOf(node), truncation);
// Only set the output representation if not running with type
// feedback. (Feedback typing will set the representation.)
SetOutput(node, output);
......@@ -903,7 +914,7 @@ class RepresentationSelector {
}
// Convert inputs to the output representation of this phi, pass the
// truncation truncation along.
// truncation along.
UseInfo input_use(output, truncation);
for (int i = 0; i < node->InputCount(); i++) {
ProcessInput(node, i, i < values ? input_use : UseInfo::None());
......@@ -2530,6 +2541,17 @@ class RepresentationSelector {
return VisitLeaf(node, MachineType::PointerRepresentation());
case IrOpcode::kStateValues:
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
// inference runs, so we do not have any real test coverage.
......@@ -2572,8 +2594,6 @@ class RepresentationSelector {
Node* control = NodeProperties::GetControlInput(node);
Node* effect = NodeProperties::GetEffectInput(node);
ReplaceEffectControlUses(node, effect, control);
} else {
DCHECK_EQ(0, node->op()->ControlInputCount());
}
replacements_.push_back(node);
......
......@@ -4,6 +4,8 @@
#include "src/compiler/typer.h"
#include <iomanip>
#include "src/base/flags.h"
#include "src/bootstrapper.h"
#include "src/compiler/common-operator.h"
......@@ -337,7 +339,7 @@ void Typer::Run(const NodeVector& roots,
graph_reducer.ReduceGraph();
if (induction_vars != nullptr) {
induction_vars->ChangeFromInductionVariablePhis();
induction_vars->ChangeToPhisAndInsertGuards();
}
}
......@@ -695,6 +697,7 @@ Type* Typer::Visitor::TypeInductionVariablePhi(Node* node) {
}
if (FLAG_trace_turbo_loop) {
OFStream os(stdout);
os << std::setprecision(10);
os << "Loop (" << NodeProperties::GetControlInput(node)->id()
<< ") variable bounds for phi " << node->id() << ": (" << min << ", "
<< max << ")\n";
......@@ -765,6 +768,11 @@ Type* Typer::Visitor::TypeProjection(Node* node) {
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(); }
// JS comparison operators.
......
......@@ -1072,6 +1072,9 @@ void Verifier::Visitor::Check(Node* node) {
CheckValueInputIs(node, 0, Type::Number());
CheckUpperIs(node, Type::Number());
break;
case IrOpcode::kTypeGuard:
CheckUpperIs(node, TypeGuardTypeOf(node->op()));
break;
// 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