Commit f843327e authored by titzer@chromium.org's avatar titzer@chromium.org

Cleanups to Verifier.

This CL broadens the checks done by the verifier in untyped mode and introduces some subroutines to shorten the code a bit.

Introduce routines CheckUpperIs() CheckUpperMaybe() and CheckValueInputIs() that are called unconditionally by the verifier. If the typing mode is untyped, then don't check anything.

Also added a couple checks for Merge and Loop nodes that catch bugs where the operator and the node disagree on input counts (a bug encountered today).

R=mstarzinger@chromium.org, rossberg@chromium.org
BUG=

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

git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@24809 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent db000e30
......@@ -6,6 +6,8 @@
#include <deque>
#include <queue>
#include <sstream>
#include <string>
#include "src/compiler/generic-algorithm.h"
#include "src/compiler/generic-node-inl.h"
......@@ -20,6 +22,7 @@
#include "src/compiler/schedule.h"
#include "src/compiler/simplified-operator.h"
#include "src/data-flow.h"
#include "src/ostreams.h"
namespace v8 {
namespace internal {
......@@ -56,10 +59,8 @@ class Verifier::Visitor : public NullNodeVisitor {
private:
// TODO(rossberg): Get rid of these once we got rid of NodeProperties.
Bounds bounds(Node* node) {
return NodeProperties::GetBounds(node);
}
Node* Operand(Node* node, int i = 0) {
Bounds bounds(Node* node) { return NodeProperties::GetBounds(node); }
Node* ValueInput(Node* node, int i = 0) {
return NodeProperties::GetValueInput(node, i);
}
FieldAccess Field(Node* node) {
......@@ -72,6 +73,50 @@ class Verifier::Visitor : public NullNodeVisitor {
node->opcode() == IrOpcode::kStoreElement);
return OpParameter<ElementAccess>(node);
}
void CheckNotTyped(Node* node) {
if (NodeProperties::IsTyped(node)) {
std::ostringstream str;
str << "TypeError: node #" << node->opcode() << ":"
<< node->op()->mnemonic() << " should never have a type";
V8_Fatal(__FILE__, __LINE__, str.str().c_str());
}
}
void CheckUpperIs(Node* node, Type* type) {
if (typing == TYPED && !bounds(node).upper->Is(type)) {
std::ostringstream str;
str << "TypeError: node #" << node->opcode() << ":"
<< node->op()->mnemonic() << " upper bound ";
bounds(node).upper->PrintTo(str);
str << " is not ";
type->PrintTo(str);
V8_Fatal(__FILE__, __LINE__, str.str().c_str());
}
}
void CheckUpperMaybe(Node* node, Type* type) {
if (typing == TYPED && !bounds(node).upper->Maybe(type)) {
std::ostringstream str;
str << "TypeError: node #" << node->opcode() << ":"
<< node->op()->mnemonic() << " upper bound ";
bounds(node).upper->PrintTo(str);
str << " must intersect ";
type->PrintTo(str);
V8_Fatal(__FILE__, __LINE__, str.str().c_str());
}
}
void CheckValueInputIs(Node* node, int i, Type* type) {
Node* input = ValueInput(node, i);
if (typing == TYPED && !bounds(input).upper->Is(type)) {
std::ostringstream str;
str << "TypeError: node #" << node->opcode() << ":"
<< node->op()->mnemonic() << "(input @" << i << " = "
<< input->opcode() << ":" << input->op()->mnemonic()
<< ") upper bound ";
bounds(input).upper->PrintTo(str);
str << " is not ";
type->PrintTo(str);
V8_Fatal(__FILE__, __LINE__, str.str().c_str());
}
}
};
......@@ -141,527 +186,532 @@ GenericGraphVisit::Control Verifier::Visitor::Pre(Node* node) {
}
}
if (typing == TYPED) {
switch (node->opcode()) {
// Control operators
// -----------------
case IrOpcode::kStart:
// Start has no inputs.
CHECK_EQ(0, input_count);
// Type is a tuple.
// TODO(rossberg): Multiple outputs are currently typed as Internal.
CHECK(bounds(node).upper->Is(Type::Internal()));
break;
case IrOpcode::kEnd:
// End has no outputs.
CHECK(!OperatorProperties::HasValueOutput(node->op()));
CHECK(!OperatorProperties::HasEffectOutput(node->op()));
CHECK(!OperatorProperties::HasControlOutput(node->op()));
// Type is empty.
CHECK(!NodeProperties::IsTyped(node));
break;
case IrOpcode::kDead:
// Dead is never connected to the graph.
UNREACHABLE();
case IrOpcode::kBranch: {
// Branch uses are IfTrue and IfFalse.
Node::Uses uses = node->uses();
int count_true = 0, count_false = 0;
for (Node::Uses::iterator it = uses.begin(); it != uses.end(); ++it) {
CHECK((*it)->opcode() == IrOpcode::kIfTrue ||
(*it)->opcode() == IrOpcode::kIfFalse);
if ((*it)->opcode() == IrOpcode::kIfTrue) ++count_true;
if ((*it)->opcode() == IrOpcode::kIfFalse) ++count_false;
}
CHECK(count_true == 1 && count_false == 1);
// Type is empty.
CHECK(!NodeProperties::IsTyped(node));
break;
switch (node->opcode()) {
case IrOpcode::kStart:
// Start has no inputs.
CHECK_EQ(0, input_count);
// Type is a tuple.
// TODO(rossberg): Multiple outputs are currently typed as Internal.
CheckUpperIs(node, Type::Internal());
break;
case IrOpcode::kEnd:
// End has no outputs.
CHECK(!OperatorProperties::HasValueOutput(node->op()));
CHECK(!OperatorProperties::HasEffectOutput(node->op()));
CHECK(!OperatorProperties::HasControlOutput(node->op()));
// Type is empty.
CheckNotTyped(node);
break;
case IrOpcode::kDead:
// Dead is never connected to the graph.
UNREACHABLE();
case IrOpcode::kBranch: {
// Branch uses are IfTrue and IfFalse.
Node::Uses uses = node->uses();
int count_true = 0, count_false = 0;
for (Node::Uses::iterator it = uses.begin(); it != uses.end(); ++it) {
CHECK((*it)->opcode() == IrOpcode::kIfTrue ||
(*it)->opcode() == IrOpcode::kIfFalse);
if ((*it)->opcode() == IrOpcode::kIfTrue) ++count_true;
if ((*it)->opcode() == IrOpcode::kIfFalse) ++count_false;
}
case IrOpcode::kIfTrue:
case IrOpcode::kIfFalse:
CHECK_EQ(IrOpcode::kBranch,
NodeProperties::GetControlInput(node, 0)->opcode());
// Type is empty.
CHECK(!NodeProperties::IsTyped(node));
break;
case IrOpcode::kLoop:
case IrOpcode::kMerge:
// Type is empty.
CHECK(!NodeProperties::IsTyped(node));
break;
case IrOpcode::kReturn:
// TODO(rossberg): check successor is End
// Type is empty.
CHECK(!NodeProperties::IsTyped(node));
break;
case IrOpcode::kThrow:
// TODO(rossberg): what are the constraints on these?
// Type is empty.
CHECK(!NodeProperties::IsTyped(node));
break;
// Common operators
// ----------------
case IrOpcode::kParameter: {
// Parameters have the start node as inputs.
CHECK_EQ(1, input_count);
CHECK_EQ(IrOpcode::kStart,
NodeProperties::GetValueInput(node, 0)->opcode());
// Parameter has an input that produces enough values.
int index = OpParameter<int>(node);
Node* input = NodeProperties::GetValueInput(node, 0);
// Currently, parameter indices start at -1 instead of 0.
CHECK_GT(
OperatorProperties::GetValueOutputCount(input->op()), index + 1);
// Type can be anything.
CHECK(bounds(node).upper->Is(Type::Any()));
break;
}
case IrOpcode::kInt32Constant: // TODO(rossberg): rename Word32Constant?
// Constants have no inputs.
CHECK_EQ(0, input_count);
// Type is a 32 bit integer, signed or unsigned.
CHECK(bounds(node).upper->Is(Type::Integral32()));
break;
case IrOpcode::kInt64Constant:
// Constants have no inputs.
CHECK_EQ(0, input_count);
// Type is internal.
// TODO(rossberg): Introduce proper Int64 type.
CHECK(bounds(node).upper->Is(Type::Internal()));
break;
case IrOpcode::kFloat32Constant:
case IrOpcode::kFloat64Constant:
case IrOpcode::kNumberConstant:
// Constants have no inputs.
CHECK_EQ(0, input_count);
// Type is a number.
CHECK(bounds(node).upper->Is(Type::Number()));
break;
case IrOpcode::kHeapConstant:
// Constants have no inputs.
CHECK_EQ(0, input_count);
// Type can be anything represented as a heap pointer.
CHECK(bounds(node).upper->Is(Type::TaggedPtr()));
break;
case IrOpcode::kExternalConstant:
// Constants have no inputs.
CHECK_EQ(0, input_count);
// Type is considered internal.
CHECK(bounds(node).upper->Is(Type::Internal()));
break;
case IrOpcode::kProjection: {
// Projection has an input that produces enough values.
int index = OpParameter<int>(node->op());
Node* input = NodeProperties::GetValueInput(node, 0);
CHECK_GT(OperatorProperties::GetValueOutputCount(input->op()), index);
// Type can be anything.
// TODO(rossberg): Introduce tuple types for this.
CHECK(bounds(node).upper->Is(Type::Any()));
break;
}
case IrOpcode::kPhi: {
// Phi input count matches parent control node.
CHECK_EQ(1, control_count);
Node* control = NodeProperties::GetControlInput(node, 0);
CHECK_EQ(value_count,
OperatorProperties::GetControlInputCount(control->op()));
// Type must be subsumed by all input types.
// TODO(rossberg): for now at least, narrowing does not really hold.
/*
for (int i = 0; i < value_count; ++i) {
// TODO(rossberg, jarin): Figure out what to do about lower bounds.
// CHECK(bounds(node).lower->Is(bounds(Operand(node, i)).lower));
CHECK(bounds(Operand(node, i)).upper->Is(bounds(node).upper));
}
*/
break;
}
case IrOpcode::kEffectPhi: {
// EffectPhi input count matches parent control node.
CHECK_EQ(1, control_count);
Node* control = NodeProperties::GetControlInput(node, 0);
CHECK_EQ(effect_count,
OperatorProperties::GetControlInputCount(control->op()));
break;
}
case IrOpcode::kValueEffect:
// TODO(rossberg): what are the constraints on these?
break;
case IrOpcode::kFinish: {
// TODO(rossberg): what are the constraints on these?
// Type must be subsumed by input type.
CHECK(bounds(Operand(node)).lower->Is(bounds(node).lower));
CHECK(bounds(Operand(node)).upper->Is(bounds(node).upper));
break;
CHECK(count_true == 1 && count_false == 1);
// Type is empty.
CheckNotTyped(node);
break;
}
case IrOpcode::kIfTrue:
case IrOpcode::kIfFalse:
CHECK_EQ(IrOpcode::kBranch,
NodeProperties::GetControlInput(node, 0)->opcode());
// Type is empty.
CheckNotTyped(node);
break;
case IrOpcode::kLoop:
case IrOpcode::kMerge:
CHECK_EQ(control_count, input_count);
// Type is empty.
CheckNotTyped(node);
break;
case IrOpcode::kReturn:
// TODO(rossberg): check successor is End
// Type is empty.
CheckNotTyped(node);
break;
case IrOpcode::kThrow:
// TODO(rossberg): what are the constraints on these?
// Type is empty.
CheckNotTyped(node);
break;
// Common operators
// ----------------
case IrOpcode::kParameter: {
// Parameters have the start node as inputs.
CHECK_EQ(1, input_count);
CHECK_EQ(IrOpcode::kStart,
NodeProperties::GetValueInput(node, 0)->opcode());
// Parameter has an input that produces enough values.
int index = OpParameter<int>(node);
Node* input = NodeProperties::GetValueInput(node, 0);
// Currently, parameter indices start at -1 instead of 0.
CHECK_GT(OperatorProperties::GetValueOutputCount(input->op()), index + 1);
// Type can be anything.
CheckUpperIs(node, Type::Any());
break;
}
case IrOpcode::kInt32Constant: // TODO(rossberg): rename Word32Constant?
// Constants have no inputs.
CHECK_EQ(0, input_count);
// Type is a 32 bit integer, signed or unsigned.
CheckUpperIs(node, Type::Integral32());
break;
case IrOpcode::kInt64Constant:
// Constants have no inputs.
CHECK_EQ(0, input_count);
// Type is internal.
// TODO(rossberg): Introduce proper Int64 type.
CheckUpperIs(node, Type::Internal());
break;
case IrOpcode::kFloat32Constant:
case IrOpcode::kFloat64Constant:
case IrOpcode::kNumberConstant:
// Constants have no inputs.
CHECK_EQ(0, input_count);
// Type is a number.
CheckUpperIs(node, Type::Number());
break;
case IrOpcode::kHeapConstant:
// Constants have no inputs.
CHECK_EQ(0, input_count);
// Type can be anything represented as a heap pointer.
CheckUpperIs(node, Type::TaggedPtr());
break;
case IrOpcode::kExternalConstant:
// Constants have no inputs.
CHECK_EQ(0, input_count);
// Type is considered internal.
CheckUpperIs(node, Type::Internal());
break;
case IrOpcode::kProjection: {
// Projection has an input that produces enough values.
int index = OpParameter<int>(node->op());
Node* input = NodeProperties::GetValueInput(node, 0);
CHECK_GT(OperatorProperties::GetValueOutputCount(input->op()), index);
// Type can be anything.
// TODO(rossberg): Introduce tuple types for this.
// TODO(titzer): Convince rossberg not to.
CheckUpperIs(node, Type::Any());
break;
}
case IrOpcode::kPhi: {
// Phi input count matches parent control node.
CHECK_EQ(0, effect_count);
CHECK_EQ(1, control_count);
Node* control = NodeProperties::GetControlInput(node, 0);
CHECK_EQ(value_count,
OperatorProperties::GetControlInputCount(control->op()));
CHECK_EQ(input_count, 1 + value_count);
// Type must be subsumed by all input types.
// TODO(rossberg): for now at least, narrowing does not really hold.
/*
for (int i = 0; i < value_count; ++i) {
// TODO(rossberg, jarin): Figure out what to do about lower bounds.
// CHECK(bounds(node).lower->Is(bounds(ValueInput(node, i)).lower));
CHECK(bounds(ValueInput(node, i)).upper->Is(bounds(node).upper));
}
case IrOpcode::kFrameState:
// TODO(jarin): what are the constraints on these?
break;
case IrOpcode::kStateValues:
// TODO(jarin): what are the constraints on these?
break;
case IrOpcode::kCall:
// TODO(rossberg): what are the constraints on these?
break;
// JavaScript operators
// --------------------
case IrOpcode::kJSEqual:
case IrOpcode::kJSNotEqual:
case IrOpcode::kJSStrictEqual:
case IrOpcode::kJSStrictNotEqual:
case IrOpcode::kJSLessThan:
case IrOpcode::kJSGreaterThan:
case IrOpcode::kJSLessThanOrEqual:
case IrOpcode::kJSGreaterThanOrEqual:
case IrOpcode::kJSUnaryNot:
// Type is Boolean.
CHECK(bounds(node).upper->Is(Type::Boolean()));
break;
case IrOpcode::kJSBitwiseOr:
case IrOpcode::kJSBitwiseXor:
case IrOpcode::kJSBitwiseAnd:
case IrOpcode::kJSShiftLeft:
case IrOpcode::kJSShiftRight:
case IrOpcode::kJSShiftRightLogical:
// Type is 32 bit integral.
CHECK(bounds(node).upper->Is(Type::Integral32()));
break;
case IrOpcode::kJSAdd:
// Type is Number or String.
CHECK(bounds(node).upper->Is(Type::NumberOrString()));
break;
case IrOpcode::kJSSubtract:
case IrOpcode::kJSMultiply:
case IrOpcode::kJSDivide:
case IrOpcode::kJSModulus:
// Type is Number.
CHECK(bounds(node).upper->Is(Type::Number()));
break;
case IrOpcode::kJSToBoolean:
// Type is Boolean.
CHECK(bounds(node).upper->Is(Type::Boolean()));
break;
case IrOpcode::kJSToNumber:
// Type is Number.
CHECK(bounds(node).upper->Is(Type::Number()));
break;
case IrOpcode::kJSToString:
// Type is String.
CHECK(bounds(node).upper->Is(Type::String()));
break;
case IrOpcode::kJSToName:
// Type is Name.
CHECK(bounds(node).upper->Is(Type::Name()));
break;
case IrOpcode::kJSToObject:
// Type is Receiver.
CHECK(bounds(node).upper->Is(Type::Receiver()));
break;
case IrOpcode::kJSCreate:
// Type is Object.
CHECK(bounds(node).upper->Is(Type::Object()));
break;
case IrOpcode::kJSLoadProperty:
case IrOpcode::kJSLoadNamed:
// Type can be anything.
CHECK(bounds(node).upper->Is(Type::Any()));
break;
case IrOpcode::kJSStoreProperty:
case IrOpcode::kJSStoreNamed:
// Type is empty.
CHECK(!NodeProperties::IsTyped(node));
break;
case IrOpcode::kJSDeleteProperty:
case IrOpcode::kJSHasProperty:
case IrOpcode::kJSInstanceOf:
// Type is Boolean.
CHECK(bounds(node).upper->Is(Type::Boolean()));
break;
case IrOpcode::kJSTypeOf:
// Type is String.
CHECK(bounds(node).upper->Is(Type::String()));
break;
case IrOpcode::kJSLoadContext:
// Type can be anything.
CHECK(bounds(node).upper->Is(Type::Any()));
break;
case IrOpcode::kJSStoreContext:
// Type is empty.
CHECK(!NodeProperties::IsTyped(node));
break;
case IrOpcode::kJSCreateFunctionContext:
case IrOpcode::kJSCreateCatchContext:
case IrOpcode::kJSCreateWithContext:
case IrOpcode::kJSCreateBlockContext:
case IrOpcode::kJSCreateModuleContext:
case IrOpcode::kJSCreateGlobalContext: {
// Type is Context, and operand is Internal.
Bounds outer = bounds(NodeProperties::GetContextInput(node));
// TODO(rossberg): This should really be Is(Internal), but the typer
// currently can't do backwards propagation.
CHECK(outer.upper->Maybe(Type::Internal()));
CHECK(bounds(node).upper->IsContext());
break;
*/
break;
}
case IrOpcode::kEffectPhi: {
// EffectPhi input count matches parent control node.
CHECK_EQ(0, value_count);
CHECK_EQ(1, control_count);
Node* control = NodeProperties::GetControlInput(node, 0);
CHECK_EQ(effect_count,
OperatorProperties::GetControlInputCount(control->op()));
CHECK_EQ(input_count, 1 + effect_count);
break;
}
case IrOpcode::kValueEffect:
// TODO(rossberg): what are the constraints on these?
break;
case IrOpcode::kFinish: {
// TODO(rossberg): what are the constraints on these?
// Type must be subsumed by input type.
if (typing == TYPED) {
CHECK(bounds(ValueInput(node)).lower->Is(bounds(node).lower));
CHECK(bounds(ValueInput(node)).upper->Is(bounds(node).upper));
}
break;
}
case IrOpcode::kFrameState:
// TODO(jarin): what are the constraints on these?
break;
case IrOpcode::kStateValues:
// TODO(jarin): what are the constraints on these?
break;
case IrOpcode::kCall:
// TODO(rossberg): what are the constraints on these?
break;
// JavaScript operators
// --------------------
case IrOpcode::kJSEqual:
case IrOpcode::kJSNotEqual:
case IrOpcode::kJSStrictEqual:
case IrOpcode::kJSStrictNotEqual:
case IrOpcode::kJSLessThan:
case IrOpcode::kJSGreaterThan:
case IrOpcode::kJSLessThanOrEqual:
case IrOpcode::kJSGreaterThanOrEqual:
case IrOpcode::kJSUnaryNot:
// Type is Boolean.
CheckUpperIs(node, Type::Boolean());
break;
case IrOpcode::kJSBitwiseOr:
case IrOpcode::kJSBitwiseXor:
case IrOpcode::kJSBitwiseAnd:
case IrOpcode::kJSShiftLeft:
case IrOpcode::kJSShiftRight:
case IrOpcode::kJSShiftRightLogical:
// Type is 32 bit integral.
CheckUpperIs(node, Type::Integral32());
break;
case IrOpcode::kJSAdd:
// Type is Number or String.
CheckUpperIs(node, Type::NumberOrString());
break;
case IrOpcode::kJSSubtract:
case IrOpcode::kJSMultiply:
case IrOpcode::kJSDivide:
case IrOpcode::kJSModulus:
// Type is Number.
CheckUpperIs(node, Type::Number());
break;
case IrOpcode::kJSToBoolean:
// Type is Boolean.
CheckUpperIs(node, Type::Boolean());
break;
case IrOpcode::kJSToNumber:
// Type is Number.
CheckUpperIs(node, Type::Number());
break;
case IrOpcode::kJSToString:
// Type is String.
CheckUpperIs(node, Type::String());
break;
case IrOpcode::kJSToName:
// Type is Name.
CheckUpperIs(node, Type::Name());
break;
case IrOpcode::kJSToObject:
// Type is Receiver.
CheckUpperIs(node, Type::Receiver());
break;
case IrOpcode::kJSCreate:
// Type is Object.
CheckUpperIs(node, Type::Object());
break;
case IrOpcode::kJSLoadProperty:
case IrOpcode::kJSLoadNamed:
// Type can be anything.
CheckUpperIs(node, Type::Any());
break;
case IrOpcode::kJSStoreProperty:
case IrOpcode::kJSStoreNamed:
// Type is empty.
CheckNotTyped(node);
break;
case IrOpcode::kJSDeleteProperty:
case IrOpcode::kJSHasProperty:
case IrOpcode::kJSInstanceOf:
// Type is Boolean.
CheckUpperIs(node, Type::Boolean());
break;
case IrOpcode::kJSTypeOf:
// Type is String.
CheckUpperIs(node, Type::String());
break;
case IrOpcode::kJSLoadContext:
// Type can be anything.
CheckUpperIs(node, Type::Any());
break;
case IrOpcode::kJSStoreContext:
// Type is empty.
CheckNotTyped(node);
break;
case IrOpcode::kJSCreateFunctionContext:
case IrOpcode::kJSCreateCatchContext:
case IrOpcode::kJSCreateWithContext:
case IrOpcode::kJSCreateBlockContext:
case IrOpcode::kJSCreateModuleContext:
case IrOpcode::kJSCreateGlobalContext: {
// Type is Context, and operand is Internal.
Node* context = NodeProperties::GetContextInput(node);
// TODO(rossberg): This should really be Is(Internal), but the typer
// currently can't do backwards propagation.
CheckUpperMaybe(context, Type::Internal());
if (typing == TYPED) CHECK(bounds(node).upper->IsContext());
break;
}
case IrOpcode::kJSCallConstruct:
// Type is Receiver.
CHECK(bounds(node).upper->Is(Type::Receiver()));
break;
case IrOpcode::kJSCallFunction:
case IrOpcode::kJSCallRuntime:
case IrOpcode::kJSYield:
case IrOpcode::kJSDebugger:
// Type can be anything.
CHECK(bounds(node).upper->Is(Type::Any()));
break;
// Simplified operators
// -------------------------------
case IrOpcode::kBooleanNot:
// Boolean -> Boolean
CHECK(bounds(Operand(node)).upper->Is(Type::Boolean()));
CHECK(bounds(node).upper->Is(Type::Boolean()));
break;
case IrOpcode::kBooleanToNumber:
// Boolean -> Number
CHECK(bounds(Operand(node)).upper->Is(Type::Boolean()));
CHECK(bounds(node).upper->Is(Type::Number()));
break;
case IrOpcode::kNumberEqual:
case IrOpcode::kNumberLessThan:
case IrOpcode::kNumberLessThanOrEqual:
// (Number, Number) -> Boolean
CHECK(bounds(Operand(node, 0)).upper->Is(Type::Number()));
CHECK(bounds(Operand(node, 1)).upper->Is(Type::Number()));
CHECK(bounds(node).upper->Is(Type::Boolean()));
break;
case IrOpcode::kNumberAdd:
case IrOpcode::kNumberSubtract:
case IrOpcode::kNumberMultiply:
case IrOpcode::kNumberDivide:
case IrOpcode::kNumberModulus:
// (Number, Number) -> Number
CHECK(bounds(Operand(node, 0)).upper->Is(Type::Number()));
CHECK(bounds(Operand(node, 1)).upper->Is(Type::Number()));
// TODO(rossberg): activate once we retype after opcode changes.
// CHECK(bounds(node).upper->Is(Type::Number()));
break;
case IrOpcode::kNumberToInt32:
// Number -> Signed32
CHECK(bounds(Operand(node)).upper->Is(Type::Number()));
CHECK(bounds(node).upper->Is(Type::Signed32()));
break;
case IrOpcode::kNumberToUint32:
// Number -> Unsigned32
CHECK(bounds(Operand(node)).upper->Is(Type::Number()));
CHECK(bounds(node).upper->Is(Type::Unsigned32()));
break;
case IrOpcode::kStringEqual:
case IrOpcode::kStringLessThan:
case IrOpcode::kStringLessThanOrEqual:
// (String, String) -> Boolean
CHECK(bounds(Operand(node, 0)).upper->Is(Type::String()));
CHECK(bounds(Operand(node, 1)).upper->Is(Type::String()));
CHECK(bounds(node).upper->Is(Type::Boolean()));
break;
case IrOpcode::kStringAdd:
// (String, String) -> String
CHECK(bounds(Operand(node, 0)).upper->Is(Type::String()));
CHECK(bounds(Operand(node, 1)).upper->Is(Type::String()));
CHECK(bounds(node).upper->Is(Type::String()));
break;
case IrOpcode::kReferenceEqual: {
// (Unique, Any) -> Boolean and
// (Any, Unique) -> Boolean
CHECK(bounds(Operand(node, 0)).upper->Is(Type::Unique()) ||
bounds(Operand(node, 1)).upper->Is(Type::Unique()));
CHECK(bounds(node).upper->Is(Type::Boolean()));
break;
}
case IrOpcode::kObjectIsSmi:
CHECK(bounds(Operand(node)).upper->Is(Type::Any()));
CHECK(bounds(node).upper->Is(Type::Boolean()));
break;
case IrOpcode::kObjectIsNonNegativeSmi:
CHECK(bounds(Operand(node)).upper->Is(Type::Any()));
CHECK(bounds(node).upper->Is(Type::Boolean()));
break;
case IrOpcode::kChangeTaggedToInt32: {
// Signed32 /\ Tagged -> Signed32 /\ UntaggedInt32
// TODO(neis): Activate once ChangeRepresentation works in typer.
// Type* from = Type::Intersect(Type::Signed32(), Type::Tagged());
// Type* to = Type::Intersect(Type::Signed32(), Type::UntaggedInt32());
// CHECK(bounds(Operand(node)).upper->Is(from));
// CHECK(bounds(node).upper->Is(to));
break;
}
case IrOpcode::kChangeTaggedToUint32: {
// Unsigned32 /\ Tagged -> Unsigned32 /\ UntaggedInt32
// TODO(neis): Activate once ChangeRepresentation works in typer.
// Type* from = Type::Intersect(Type::Unsigned32(), Type::Tagged());
// Type* to =Type::Intersect(Type::Unsigned32(), Type::UntaggedInt32());
// CHECK(bounds(Operand(node)).upper->Is(from));
// CHECK(bounds(node).upper->Is(to));
break;
}
case IrOpcode::kChangeTaggedToFloat64: {
// Number /\ Tagged -> Number /\ UntaggedFloat64
// TODO(neis): Activate once ChangeRepresentation works in typer.
// Type* from = Type::Intersect(Type::Number(), Type::Tagged());
// Type* to = Type::Intersect(Type::Number(), Type::UntaggedFloat64());
// CHECK(bounds(Operand(node)).upper->Is(from));
// CHECK(bounds(node).upper->Is(to));
break;
}
case IrOpcode::kChangeInt32ToTagged: {
// Signed32 /\ UntaggedInt32 -> Signed32 /\ Tagged
// TODO(neis): Activate once ChangeRepresentation works in typer.
// Type* from =Type::Intersect(Type::Signed32(), Type::UntaggedInt32());
// Type* to = Type::Intersect(Type::Signed32(), Type::Tagged());
// CHECK(bounds(Operand(node)).upper->Is(from));
// CHECK(bounds(node).upper->Is(to));
break;
}
case IrOpcode::kChangeUint32ToTagged: {
// Unsigned32 /\ UntaggedInt32 -> Unsigned32 /\ Tagged
// TODO(neis): Activate once ChangeRepresentation works in typer.
// Type* from=Type::Intersect(Type::Unsigned32(),Type::UntaggedInt32());
// Type* to = Type::Intersect(Type::Unsigned32(), Type::Tagged());
// CHECK(bounds(Operand(node)).upper->Is(from));
// CHECK(bounds(node).upper->Is(to));
break;
}
case IrOpcode::kChangeFloat64ToTagged: {
// Number /\ UntaggedFloat64 -> Number /\ Tagged
// TODO(neis): Activate once ChangeRepresentation works in typer.
// Type* from =Type::Intersect(Type::Number(), Type::UntaggedFloat64());
// Type* to = Type::Intersect(Type::Number(), Type::Tagged());
// CHECK(bounds(Operand(node)).upper->Is(from));
// CHECK(bounds(node).upper->Is(to));
break;
}
case IrOpcode::kChangeBoolToBit: {
// Boolean /\ TaggedPtr -> Boolean /\ UntaggedInt1
// TODO(neis): Activate once ChangeRepresentation works in typer.
// Type* from = Type::Intersect(Type::Boolean(), Type::TaggedPtr());
// Type* to = Type::Intersect(Type::Boolean(), Type::UntaggedInt1());
// CHECK(bounds(Operand(node)).upper->Is(from));
// CHECK(bounds(node).upper->Is(to));
break;
}
case IrOpcode::kChangeBitToBool: {
// Boolean /\ UntaggedInt1 -> Boolean /\ TaggedPtr
// TODO(neis): Activate once ChangeRepresentation works in typer.
// Type* from = Type::Intersect(Type::Boolean(), Type::UntaggedInt1());
// Type* to = Type::Intersect(Type::Boolean(), Type::TaggedPtr());
// CHECK(bounds(Operand(node)).upper->Is(from));
// CHECK(bounds(node).upper->Is(to));
break;
case IrOpcode::kJSCallConstruct:
// Type is Receiver.
CheckUpperIs(node, Type::Receiver());
break;
case IrOpcode::kJSCallFunction:
case IrOpcode::kJSCallRuntime:
case IrOpcode::kJSYield:
case IrOpcode::kJSDebugger:
// Type can be anything.
CheckUpperIs(node, Type::Any());
break;
// Simplified operators
// -------------------------------
case IrOpcode::kBooleanNot:
// Boolean -> Boolean
CheckValueInputIs(node, 0, Type::Boolean());
CheckUpperIs(node, Type::Boolean());
break;
case IrOpcode::kBooleanToNumber:
// Boolean -> Number
CheckValueInputIs(node, 0, Type::Boolean());
CheckUpperIs(node, Type::Number());
break;
case IrOpcode::kNumberEqual:
case IrOpcode::kNumberLessThan:
case IrOpcode::kNumberLessThanOrEqual:
// (Number, Number) -> Boolean
CheckValueInputIs(node, 0, Type::Number());
CheckValueInputIs(node, 1, Type::Number());
CheckUpperIs(node, Type::Boolean());
break;
case IrOpcode::kNumberAdd:
case IrOpcode::kNumberSubtract:
case IrOpcode::kNumberMultiply:
case IrOpcode::kNumberDivide:
case IrOpcode::kNumberModulus:
// (Number, Number) -> Number
CheckValueInputIs(node, 0, Type::Number());
CheckValueInputIs(node, 1, Type::Number());
// TODO(rossberg): activate once we retype after opcode changes.
// CheckUpperIs(node, Type::Number());
break;
case IrOpcode::kNumberToInt32:
// Number -> Signed32
CheckValueInputIs(node, 0, Type::Number());
CheckUpperIs(node, Type::Signed32());
break;
case IrOpcode::kNumberToUint32:
// Number -> Unsigned32
CheckValueInputIs(node, 0, Type::Number());
CheckUpperIs(node, Type::Unsigned32());
break;
case IrOpcode::kStringEqual:
case IrOpcode::kStringLessThan:
case IrOpcode::kStringLessThanOrEqual:
// (String, String) -> Boolean
CheckValueInputIs(node, 0, Type::String());
CheckValueInputIs(node, 1, Type::String());
CheckUpperIs(node, Type::Boolean());
break;
case IrOpcode::kStringAdd:
// (String, String) -> String
CheckValueInputIs(node, 0, Type::String());
CheckValueInputIs(node, 1, Type::String());
CheckUpperIs(node, Type::String());
break;
case IrOpcode::kReferenceEqual: {
// (Unique, Any) -> Boolean and
// (Any, Unique) -> Boolean
if (typing == TYPED) {
CHECK(bounds(ValueInput(node, 0)).upper->Is(Type::Unique()) ||
bounds(ValueInput(node, 1)).upper->Is(Type::Unique()));
}
case IrOpcode::kLoadField:
// Object -> fieldtype
// TODO(rossberg): activate once machine ops are typed.
// CHECK(bounds(Operand(node)).upper->Is(Type::Object()));
// CHECK(bounds(node).upper->Is(Field(node).type));
break;
case IrOpcode::kLoadElement:
// Object -> elementtype
// TODO(rossberg): activate once machine ops are typed.
// CHECK(bounds(Operand(node)).upper->Is(Type::Object()));
// CHECK(bounds(node).upper->Is(Element(node).type));
break;
case IrOpcode::kStoreField:
// (Object, fieldtype) -> _|_
// TODO(rossberg): activate once machine ops are typed.
// CHECK(bounds(Operand(node, 0)).upper->Is(Type::Object()));
// CHECK(bounds(Operand(node, 1)).upper->Is(Field(node).type));
CHECK(!NodeProperties::IsTyped(node));
break;
case IrOpcode::kStoreElement:
// (Object, elementtype) -> _|_
// TODO(rossberg): activate once machine ops are typed.
// CHECK(bounds(Operand(node, 0)).upper->Is(Type::Object()));
// CHECK(bounds(Operand(node, 1)).upper->Is(Element(node).type));
CHECK(!NodeProperties::IsTyped(node));
break;
// Machine operators
// -----------------------
case IrOpcode::kLoad:
case IrOpcode::kStore:
case IrOpcode::kWord32And:
case IrOpcode::kWord32Or:
case IrOpcode::kWord32Xor:
case IrOpcode::kWord32Shl:
case IrOpcode::kWord32Shr:
case IrOpcode::kWord32Sar:
case IrOpcode::kWord32Ror:
case IrOpcode::kWord32Equal:
case IrOpcode::kWord64And:
case IrOpcode::kWord64Or:
case IrOpcode::kWord64Xor:
case IrOpcode::kWord64Shl:
case IrOpcode::kWord64Shr:
case IrOpcode::kWord64Sar:
case IrOpcode::kWord64Ror:
case IrOpcode::kWord64Equal:
case IrOpcode::kInt32Add:
case IrOpcode::kInt32AddWithOverflow:
case IrOpcode::kInt32Sub:
case IrOpcode::kInt32SubWithOverflow:
case IrOpcode::kInt32Mul:
case IrOpcode::kInt32MulHigh:
case IrOpcode::kInt32Div:
case IrOpcode::kInt32Mod:
case IrOpcode::kInt32LessThan:
case IrOpcode::kInt32LessThanOrEqual:
case IrOpcode::kUint32Div:
case IrOpcode::kUint32Mod:
case IrOpcode::kUint32LessThan:
case IrOpcode::kUint32LessThanOrEqual:
case IrOpcode::kInt64Add:
case IrOpcode::kInt64Sub:
case IrOpcode::kInt64Mul:
case IrOpcode::kInt64Div:
case IrOpcode::kInt64Mod:
case IrOpcode::kInt64LessThan:
case IrOpcode::kInt64LessThanOrEqual:
case IrOpcode::kUint64Div:
case IrOpcode::kUint64Mod:
case IrOpcode::kUint64LessThan:
case IrOpcode::kFloat64Add:
case IrOpcode::kFloat64Sub:
case IrOpcode::kFloat64Mul:
case IrOpcode::kFloat64Div:
case IrOpcode::kFloat64Mod:
case IrOpcode::kFloat64Sqrt:
case IrOpcode::kFloat64Equal:
case IrOpcode::kFloat64LessThan:
case IrOpcode::kFloat64LessThanOrEqual:
case IrOpcode::kTruncateInt64ToInt32:
case IrOpcode::kTruncateFloat64ToFloat32:
case IrOpcode::kTruncateFloat64ToInt32:
case IrOpcode::kChangeInt32ToInt64:
case IrOpcode::kChangeUint32ToUint64:
case IrOpcode::kChangeInt32ToFloat64:
case IrOpcode::kChangeUint32ToFloat64:
case IrOpcode::kChangeFloat32ToFloat64:
case IrOpcode::kChangeFloat64ToInt32:
case IrOpcode::kChangeFloat64ToUint32:
case IrOpcode::kLoadStackPointer:
// TODO(rossberg): Check.
break;
CheckUpperIs(node, Type::Boolean());
break;
}
case IrOpcode::kObjectIsSmi:
CheckValueInputIs(node, 0, Type::Any());
CheckUpperIs(node, Type::Boolean());
break;
case IrOpcode::kObjectIsNonNegativeSmi:
CheckValueInputIs(node, 0, Type::Any());
CheckUpperIs(node, Type::Boolean());
break;
case IrOpcode::kChangeTaggedToInt32: {
// Signed32 /\ Tagged -> Signed32 /\ UntaggedInt32
// TODO(neis): Activate once ChangeRepresentation works in typer.
// Type* from = Type::Intersect(Type::Signed32(), Type::Tagged());
// Type* to = Type::Intersect(Type::Signed32(), Type::UntaggedInt32());
// CheckValueInputIs(node, 0, from));
// CheckUpperIs(node, to));
break;
}
case IrOpcode::kChangeTaggedToUint32: {
// Unsigned32 /\ Tagged -> Unsigned32 /\ UntaggedInt32
// TODO(neis): Activate once ChangeRepresentation works in typer.
// Type* from = Type::Intersect(Type::Unsigned32(), Type::Tagged());
// Type* to =Type::Intersect(Type::Unsigned32(), Type::UntaggedInt32());
// CheckValueInputIs(node, 0, from));
// CheckUpperIs(node, to));
break;
}
case IrOpcode::kChangeTaggedToFloat64: {
// Number /\ Tagged -> Number /\ UntaggedFloat64
// TODO(neis): Activate once ChangeRepresentation works in typer.
// Type* from = Type::Intersect(Type::Number(), Type::Tagged());
// Type* to = Type::Intersect(Type::Number(), Type::UntaggedFloat64());
// CheckValueInputIs(node, 0, from));
// CheckUpperIs(node, to));
break;
}
case IrOpcode::kChangeInt32ToTagged: {
// Signed32 /\ UntaggedInt32 -> Signed32 /\ Tagged
// TODO(neis): Activate once ChangeRepresentation works in typer.
// Type* from =Type::Intersect(Type::Signed32(), Type::UntaggedInt32());
// Type* to = Type::Intersect(Type::Signed32(), Type::Tagged());
// CheckValueInputIs(node, 0, from));
// CheckUpperIs(node, to));
break;
}
case IrOpcode::kChangeUint32ToTagged: {
// Unsigned32 /\ UntaggedInt32 -> Unsigned32 /\ Tagged
// TODO(neis): Activate once ChangeRepresentation works in typer.
// Type* from=Type::Intersect(Type::Unsigned32(),Type::UntaggedInt32());
// Type* to = Type::Intersect(Type::Unsigned32(), Type::Tagged());
// CheckValueInputIs(node, 0, from));
// CheckUpperIs(node, to));
break;
}
case IrOpcode::kChangeFloat64ToTagged: {
// Number /\ UntaggedFloat64 -> Number /\ Tagged
// TODO(neis): Activate once ChangeRepresentation works in typer.
// Type* from =Type::Intersect(Type::Number(), Type::UntaggedFloat64());
// Type* to = Type::Intersect(Type::Number(), Type::Tagged());
// CheckValueInputIs(node, 0, from));
// CheckUpperIs(node, to));
break;
}
case IrOpcode::kChangeBoolToBit: {
// Boolean /\ TaggedPtr -> Boolean /\ UntaggedInt1
// TODO(neis): Activate once ChangeRepresentation works in typer.
// Type* from = Type::Intersect(Type::Boolean(), Type::TaggedPtr());
// Type* to = Type::Intersect(Type::Boolean(), Type::UntaggedInt1());
// CheckValueInputIs(node, 0, from));
// CheckUpperIs(node, to));
break;
}
case IrOpcode::kChangeBitToBool: {
// Boolean /\ UntaggedInt1 -> Boolean /\ TaggedPtr
// TODO(neis): Activate once ChangeRepresentation works in typer.
// Type* from = Type::Intersect(Type::Boolean(), Type::UntaggedInt1());
// Type* to = Type::Intersect(Type::Boolean(), Type::TaggedPtr());
// CheckValueInputIs(node, 0, from));
// CheckUpperIs(node, to));
break;
}
case IrOpcode::kLoadField:
// Object -> fieldtype
// TODO(rossberg): activate once machine ops are typed.
// CheckValueInputIs(node, 0, Type::Object());
// CheckUpperIs(node, Field(node).type));
break;
case IrOpcode::kLoadElement:
// Object -> elementtype
// TODO(rossberg): activate once machine ops are typed.
// CheckValueInputIs(node, 0, Type::Object());
// CheckUpperIs(node, Element(node).type));
break;
case IrOpcode::kStoreField:
// (Object, fieldtype) -> _|_
// TODO(rossberg): activate once machine ops are typed.
// CheckValueInputIs(node, 0, Type::Object());
// CheckValueInputIs(node, 1, Field(node).type));
CheckNotTyped(node);
break;
case IrOpcode::kStoreElement:
// (Object, elementtype) -> _|_
// TODO(rossberg): activate once machine ops are typed.
// CheckValueInputIs(node, 0, Type::Object());
// CheckValueInputIs(node, 1, Element(node).type));
CheckNotTyped(node);
break;
// Machine operators
// -----------------------
case IrOpcode::kLoad:
case IrOpcode::kStore:
case IrOpcode::kWord32And:
case IrOpcode::kWord32Or:
case IrOpcode::kWord32Xor:
case IrOpcode::kWord32Shl:
case IrOpcode::kWord32Shr:
case IrOpcode::kWord32Sar:
case IrOpcode::kWord32Ror:
case IrOpcode::kWord32Equal:
case IrOpcode::kWord64And:
case IrOpcode::kWord64Or:
case IrOpcode::kWord64Xor:
case IrOpcode::kWord64Shl:
case IrOpcode::kWord64Shr:
case IrOpcode::kWord64Sar:
case IrOpcode::kWord64Ror:
case IrOpcode::kWord64Equal:
case IrOpcode::kInt32Add:
case IrOpcode::kInt32AddWithOverflow:
case IrOpcode::kInt32Sub:
case IrOpcode::kInt32SubWithOverflow:
case IrOpcode::kInt32Mul:
case IrOpcode::kInt32MulHigh:
case IrOpcode::kInt32Div:
case IrOpcode::kInt32Mod:
case IrOpcode::kInt32LessThan:
case IrOpcode::kInt32LessThanOrEqual:
case IrOpcode::kUint32Div:
case IrOpcode::kUint32Mod:
case IrOpcode::kUint32LessThan:
case IrOpcode::kUint32LessThanOrEqual:
case IrOpcode::kInt64Add:
case IrOpcode::kInt64Sub:
case IrOpcode::kInt64Mul:
case IrOpcode::kInt64Div:
case IrOpcode::kInt64Mod:
case IrOpcode::kInt64LessThan:
case IrOpcode::kInt64LessThanOrEqual:
case IrOpcode::kUint64Div:
case IrOpcode::kUint64Mod:
case IrOpcode::kUint64LessThan:
case IrOpcode::kFloat64Add:
case IrOpcode::kFloat64Sub:
case IrOpcode::kFloat64Mul:
case IrOpcode::kFloat64Div:
case IrOpcode::kFloat64Mod:
case IrOpcode::kFloat64Sqrt:
case IrOpcode::kFloat64Equal:
case IrOpcode::kFloat64LessThan:
case IrOpcode::kFloat64LessThanOrEqual:
case IrOpcode::kTruncateInt64ToInt32:
case IrOpcode::kTruncateFloat64ToFloat32:
case IrOpcode::kTruncateFloat64ToInt32:
case IrOpcode::kChangeInt32ToInt64:
case IrOpcode::kChangeUint32ToUint64:
case IrOpcode::kChangeInt32ToFloat64:
case IrOpcode::kChangeUint32ToFloat64:
case IrOpcode::kChangeFloat32ToFloat64:
case IrOpcode::kChangeFloat64ToInt32:
case IrOpcode::kChangeFloat64ToUint32:
case IrOpcode::kLoadStackPointer:
// TODO(rossberg): Check.
break;
}
return GenericGraphVisit::CONTINUE;
......
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