| Index: src/compiler/verifier.cc
|
| diff --git a/src/compiler/verifier.cc b/src/compiler/verifier.cc
|
| index 9b06e3140eab4c6af39b54dddbffc00ce8bb6ac7..c4d99f6c4a1cdc32f8dc2b5798ba1331f024d084 100644
|
| --- a/src/compiler/verifier.cc
|
| +++ b/src/compiler/verifier.cc
|
| @@ -18,6 +18,7 @@
|
| #include "src/compiler/opcodes.h"
|
| #include "src/compiler/operator.h"
|
| #include "src/compiler/schedule.h"
|
| +#include "src/compiler/simplified-operator.h"
|
| #include "src/data-flow.h"
|
|
|
| namespace v8 {
|
| @@ -45,18 +46,41 @@ static bool IsUseDefChainLinkPresent(Node* def, Node* use) {
|
|
|
| class Verifier::Visitor : public NullNodeVisitor {
|
| public:
|
| - explicit Visitor(Zone* zone)
|
| - : reached_from_start(NodeSet::key_compare(),
|
| - NodeSet::allocator_type(zone)),
|
| + Visitor(Zone* z, Typing typed)
|
| + : zone(z),
|
| + typing(typed),
|
| + reached_from_start(NodeSet::key_compare(),
|
| + NodeSet::allocator_type(z)),
|
| reached_from_end(NodeSet::key_compare(),
|
| - NodeSet::allocator_type(zone)) {}
|
| + NodeSet::allocator_type(z)) {}
|
|
|
| // Fulfills the PreNodeCallback interface.
|
| GenericGraphVisit::Control Pre(Node* node);
|
|
|
| + Zone* zone;
|
| + Typing typing;
|
| bool from_start;
|
| NodeSet reached_from_start;
|
| NodeSet reached_from_end;
|
| +
|
| + 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) {
|
| + return NodeProperties::GetValueInput(node, i);
|
| + }
|
| + FieldAccess field(Node* node) {
|
| + DCHECK(node->opcode() == IrOpcode::kLoadField ||
|
| + node->opcode() == IrOpcode::kStoreField);
|
| + return static_cast<Operator1<FieldAccess>*>(node->op())->parameter();
|
| + }
|
| + ElementAccess element(Node* node) {
|
| + DCHECK(node->opcode() == IrOpcode::kLoadElement ||
|
| + node->opcode() == IrOpcode::kStoreElement);
|
| + return static_cast<Operator1<ElementAccess>*>(node->op())->parameter();
|
| + }
|
| };
|
|
|
|
|
| @@ -115,110 +139,488 @@ GenericGraphVisit::Control Verifier::Visitor::Pre(Node* node) {
|
| }
|
| }
|
|
|
| - switch (node->opcode()) {
|
| - case IrOpcode::kStart:
|
| - // Start has no inputs.
|
| - CHECK_EQ(0, input_count);
|
| - break;
|
| - case IrOpcode::kEnd:
|
| - // End has no outputs.
|
| - CHECK(!OperatorProperties::HasValueOutput(node->op()));
|
| - CHECK(!OperatorProperties::HasEffectOutput(node->op()));
|
| - CHECK(!OperatorProperties::HasControlOutput(node->op()));
|
| - 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();
|
| - bool got_true = false, got_false = false;
|
| - for (Node::Uses::iterator it = uses.begin(); it != uses.end(); ++it) {
|
| - CHECK(((*it)->opcode() == IrOpcode::kIfTrue && !got_true) ||
|
| - ((*it)->opcode() == IrOpcode::kIfFalse && !got_false));
|
| - if ((*it)->opcode() == IrOpcode::kIfTrue) got_true = true;
|
| - if ((*it)->opcode() == IrOpcode::kIfFalse) got_false = true;
|
| - }
|
| - // TODO(rossberg): Currently fails for various tests.
|
| - // CHECK(got_true && got_false);
|
| - break;
|
| - }
|
| - case IrOpcode::kIfTrue:
|
| - case IrOpcode::kIfFalse:
|
| - CHECK_EQ(IrOpcode::kBranch,
|
| - NodeProperties::GetControlInput(node, 0)->opcode());
|
| - break;
|
| - case IrOpcode::kLoop:
|
| - case IrOpcode::kMerge:
|
| - break;
|
| - case IrOpcode::kReturn:
|
| - // TODO(rossberg): check successor is End
|
| - break;
|
| - case IrOpcode::kThrow:
|
| - // TODO(rossberg): what are the constraints on these?
|
| - break;
|
| - 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 = static_cast<Operator1<int>*>(node->op())->parameter();
|
| - Node* input = NodeProperties::GetValueInput(node, 0);
|
| - // Currently, parameter indices start at -1 instead of 0.
|
| - CHECK_GT(OperatorProperties::GetValueOutputCount(input->op()), index + 1);
|
| - break;
|
| - }
|
| - case IrOpcode::kInt32Constant:
|
| - case IrOpcode::kInt64Constant:
|
| - case IrOpcode::kFloat64Constant:
|
| - case IrOpcode::kExternalConstant:
|
| - case IrOpcode::kNumberConstant:
|
| - case IrOpcode::kHeapConstant:
|
| - // Constants have no inputs.
|
| - CHECK_EQ(0, input_count);
|
| - 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()));
|
| - break;
|
| + if (typing == TYPED) {
|
| + // Multiple value outputs are currently typed as Internal.
|
| + // TODO(rossberg): Introduce tuple types.
|
| + if (OperatorProperties::GetValueOutputCount(node->op()) > 1) {
|
| + CHECK(bounds(node).upper->Is(Type::Internal()));
|
| }
|
| - 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::kLazyDeoptimization:
|
| - // TODO(jarin): what are the constraints on these?
|
| - break;
|
| - case IrOpcode::kDeoptimize:
|
| - // TODO(jarin): what are the constraints on these?
|
| - break;
|
| - case IrOpcode::kFrameState:
|
| - // TODO(jarin): what are the constraints on these?
|
| - break;
|
| - case IrOpcode::kCall:
|
| - // TODO(rossberg): what are the constraints on these?
|
| - break;
|
| - case IrOpcode::kContinuation:
|
| - // TODO(jarin): what are the constraints on these?
|
| - break;
|
| - case IrOpcode::kProjection: {
|
| - // Projection has an input that produces enough values.
|
| - int index = static_cast<Operator1<int>*>(node->op())->parameter();
|
| - Node* input = NodeProperties::GetValueInput(node, 0);
|
| - CHECK_GT(OperatorProperties::GetValueOutputCount(input->op()), index);
|
| - break;
|
| +
|
| + switch (node->opcode()) {
|
| + // Control operators
|
| + // -----------------
|
| + case IrOpcode::kStart:
|
| + // Start has no inputs.
|
| + CHECK_EQ(0, input_count);
|
| + // Type is 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()));
|
| + break;
|
| + case IrOpcode::kDead:
|
| + // Dead is never connected to the graph.
|
| + UNREACHABLE();
|
| + case IrOpcode::kBranch: {
|
| + // Ignore dead branches, because they may violate well-formedness.
|
| + // TODO(rossberg): Can we avoid this?
|
| + Node* parent = NodeProperties::GetControlInput(node, 0);
|
| + if (parent->opcode() == IrOpcode::kDead) break;
|
| + // Branch uses are IfTrue and IfFalse.
|
| + Node::Uses uses = node->uses();
|
| + bool 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);
|
| + break;
|
| + }
|
| + case IrOpcode::kIfTrue:
|
| + case IrOpcode::kIfFalse:
|
| + CHECK_EQ(IrOpcode::kBranch,
|
| + NodeProperties::GetControlInput(node, 0)->opcode());
|
| + break;
|
| + case IrOpcode::kLoop:
|
| + case IrOpcode::kMerge:
|
| + break;
|
| + case IrOpcode::kReturn:
|
| + // TODO(rossberg): check successor is End
|
| + break;
|
| + case IrOpcode::kThrow:
|
| + // TODO(rossberg): what are the constraints on these?
|
| + 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 = static_cast<Operator1<int>*>(node->op())->parameter();
|
| + 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: // Close enough...
|
| + 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 = static_cast<Operator1<int>*>(node->op())->parameter();
|
| + 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.
|
| + for (int i = 0; i < value_count; ++i) {
|
| + 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::kControlEffect:
|
| + 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;
|
| + }
|
| + case IrOpcode::kLazyDeoptimization:
|
| + // TODO(jarin): what are the constraints on these?
|
| + break;
|
| + case IrOpcode::kDeoptimize:
|
| + // TODO(jarin): what are the constraints on these?
|
| + 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;
|
| + case IrOpcode::kContinuation:
|
| + // TODO(jarin): 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:
|
| + 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(bounds(node).upper->Is(Type::None()));
|
| + 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(bounds(node).upper->Is(Type::None()));
|
| + 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->Is(Type::Context(outer.upper, zone)));
|
| + CHECK(bounds(node).lower->Is(Type::Context(outer.lower, zone)));
|
| + 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::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()));
|
| + 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, Unique) -> Boolean
|
| + CHECK(bounds(operand(node, 0)).upper->Is(Type::Unique()));
|
| + CHECK(bounds(operand(node, 1)).upper->Is(Type::Unique()));
|
| + CHECK(bounds(node).upper->Is(Type::Boolean()));
|
| + break;
|
| + }
|
| +
|
| + case IrOpcode::kChangeTaggedToInt32: {
|
| + // Signed32 /\ Tagged -> Signed32 /\ UntaggedInt32
|
| + 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
|
| + 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
|
| + 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
|
| + 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
|
| + 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
|
| + 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
|
| + 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
|
| + 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::kLoadField:
|
| + // Object -> fieldtype
|
| + CHECK(bounds(operand(node)).upper->Is(Type::Object()));
|
| + CHECK(bounds(node).upper->Is(field(node).type));
|
| + break;
|
| + case IrOpcode::kLoadElement:
|
| + // Object -> elementtype
|
| + CHECK(bounds(operand(node)).upper->Is(Type::Object()));
|
| + CHECK(bounds(node).upper->Is(element(node).type));
|
| + break;
|
| + case IrOpcode::kStoreField:
|
| + // (Object, fieldtype) -> _|_
|
| + CHECK(bounds(operand(node, 0)).upper->Is(Type::Object()));
|
| + CHECK(bounds(operand(node, 1)).upper->Is(field(node).type));
|
| + CHECK(bounds(node).upper->Is(Type::None()));
|
| + break;
|
| + case IrOpcode::kStoreElement:
|
| + // (Object, elementtype) -> _|_
|
| + CHECK(bounds(operand(node, 0)).upper->Is(Type::Object()));
|
| + CHECK(bounds(operand(node, 1)).upper->Is(element(node).type));
|
| + CHECK(bounds(node).upper->Is(Type::None()));
|
| + 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::kInt32Div:
|
| + case IrOpcode::kInt32UDiv:
|
| + case IrOpcode::kInt32Mod:
|
| + case IrOpcode::kInt32UMod:
|
| + case IrOpcode::kInt32LessThan:
|
| + case IrOpcode::kInt32LessThanOrEqual:
|
| + case IrOpcode::kUint32LessThan:
|
| + case IrOpcode::kUint32LessThanOrEqual:
|
| + case IrOpcode::kInt64Add:
|
| + case IrOpcode::kInt64Sub:
|
| + case IrOpcode::kInt64Mul:
|
| + case IrOpcode::kInt64Div:
|
| + case IrOpcode::kInt64UDiv:
|
| + case IrOpcode::kInt64Mod:
|
| + case IrOpcode::kInt64UMod:
|
| + case IrOpcode::kInt64LessThan:
|
| + case IrOpcode::kInt64LessThanOrEqual:
|
| + case IrOpcode::kFloat64Add:
|
| + case IrOpcode::kFloat64Sub:
|
| + case IrOpcode::kFloat64Mul:
|
| + case IrOpcode::kFloat64Div:
|
| + case IrOpcode::kFloat64Mod:
|
| + case IrOpcode::kFloat64Equal:
|
| + case IrOpcode::kFloat64LessThan:
|
| + case IrOpcode::kFloat64LessThanOrEqual:
|
| + case IrOpcode::kTruncateInt64ToInt32:
|
| + case IrOpcode::kTruncateFloat64ToInt32:
|
| + case IrOpcode::kChangeInt32ToInt64:
|
| + case IrOpcode::kChangeUint32ToUint64:
|
| + case IrOpcode::kChangeInt32ToFloat64:
|
| + case IrOpcode::kChangeUint32ToFloat64:
|
| + case IrOpcode::kChangeFloat64ToInt32:
|
| + case IrOpcode::kChangeFloat64ToUint32:
|
| + // TODO(rossberg): Check.
|
| + break;
|
| }
|
| - default:
|
| - // TODO(rossberg): Check other node kinds.
|
| - break;
|
| }
|
|
|
| if (from_start) {
|
| @@ -231,8 +633,8 @@ GenericGraphVisit::Control Verifier::Visitor::Pre(Node* node) {
|
| }
|
|
|
|
|
| -void Verifier::Run(Graph* graph) {
|
| - Visitor visitor(graph->zone());
|
| +void Verifier::Run(Graph* graph, Typing typing) {
|
| + Visitor visitor(graph->zone(), typing);
|
|
|
| CHECK_NE(NULL, graph->start());
|
| visitor.from_start = true;
|
| @@ -250,6 +652,8 @@ void Verifier::Run(Graph* graph) {
|
| }
|
|
|
|
|
| +// -----------------------------------------------------------------------------
|
| +
|
| static bool HasDominatingDef(Schedule* schedule, Node* node,
|
| BasicBlock* container, BasicBlock* use_block,
|
| int use_pos) {
|
|
|