Chromium Code Reviews| Index: src/compiler/verifier.cc |
| diff --git a/src/compiler/verifier.cc b/src/compiler/verifier.cc |
| index 4c28f3521a9b93cee27bac6f98f744b6315587d5..ba9e0f53698c122c32853b42e468b33ae30312bc 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,32 @@ 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)), |
| - reached_from_end(NodeSet::key_compare(), |
| - NodeSet::allocator_type(zone)) {} |
| + Visitor(Zone* z, Typing typed) : zone(z), typing(typed) {} |
| // Fulfills the PreNodeCallback interface. |
| GenericGraphVisit::Control Pre(Node* node); |
| - bool from_start; |
| - NodeSet reached_from_start; |
| - NodeSet reached_from_end; |
| + Zone* zone; |
| + Typing typing; |
| + |
| + private: |
| + // TODO(rossberg): Get rid of these once we got rid of NodeProperties. |
| + Bounds bounds(Node* node) { |
|
titzer
2014/10/14 16:13:22
There is a method for this now, yes?
|
| + 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 OpParameter<FieldAccess>(node); |
| + } |
| + ElementAccess Element(Node* node) { |
| + DCHECK(node->opcode() == IrOpcode::kLoadElement || |
| + node->opcode() == IrOpcode::kStoreElement); |
| + return OpParameter<ElementAccess>(node); |
| + } |
| }; |
| @@ -126,133 +141,529 @@ 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; |
| + 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(); |
| + 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); |
| + // Type is empty. |
| + CHECK(!NodeProperties::IsTyped(node)); |
| + break; |
| + } |
| + 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: // Close enough... |
| + 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; |
| + } |
| + 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; |
| + } |
| + |
| + 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; |
| } |
| - // 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 = 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); |
| - 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; |
| - } |
| - 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::kFrameState: |
| - // TODO(jarin): what are the constraints on these? |
| - break; |
| - case IrOpcode::kCall: |
| - // TODO(rossberg): what are the constraints on these? |
| - break; |
| - case IrOpcode::kProjection: { |
| - // Projection has an input that produces enough values. |
| - size_t index = OpParameter<size_t>(node); |
| - Node* input = NodeProperties::GetValueInput(node, 0); |
| - CHECK_GT(OperatorProperties::GetValueOutputCount(input->op()), |
| - static_cast<int>(index)); |
| - break; |
| - } |
| - default: |
| - // TODO(rossberg): Check other node kinds. |
| - break; |
| - } |
| - if (from_start) { |
| - reached_from_start.insert(node); |
| - } else { |
| - reached_from_end.insert(node); |
| + 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::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; |
| + } |
| } |
| return GenericGraphVisit::CONTINUE; |
| } |
| -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; |
| - graph->VisitNodeUsesFromStart(&visitor); |
| CHECK_NE(NULL, graph->end()); |
| - visitor.from_start = false; |
| graph->VisitNodeInputsFromEnd(&visitor); |
| - |
| - // All control nodes reachable from end are reachable from start. |
| - for (NodeSet::iterator it = visitor.reached_from_end.begin(); |
| - it != visitor.reached_from_end.end(); ++it) { |
| - CHECK(!NodeProperties::IsControl(*it) || |
| - visitor.reached_from_start.count(*it)); |
| - } |
| } |
| +// ----------------------------------------------------------------------------- |
| + |
| static bool HasDominatingDef(Schedule* schedule, Node* node, |
| BasicBlock* container, BasicBlock* use_block, |
| int use_pos) { |