Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2014 the V8 project authors. All rights reserved. | 1 // Copyright 2014 the V8 project authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "src/compiler/verifier.h" | 5 #include "src/compiler/verifier.h" |
| 6 | 6 |
| 7 #include <deque> | 7 #include <deque> |
| 8 #include <queue> | 8 #include <queue> |
| 9 | 9 |
| 10 #include "src/compiler/generic-algorithm.h" | 10 #include "src/compiler/generic-algorithm.h" |
| 11 #include "src/compiler/generic-node-inl.h" | 11 #include "src/compiler/generic-node-inl.h" |
| 12 #include "src/compiler/generic-node.h" | 12 #include "src/compiler/generic-node.h" |
| 13 #include "src/compiler/graph-inl.h" | 13 #include "src/compiler/graph-inl.h" |
| 14 #include "src/compiler/graph.h" | 14 #include "src/compiler/graph.h" |
| 15 #include "src/compiler/node.h" | 15 #include "src/compiler/node.h" |
| 16 #include "src/compiler/node-properties-inl.h" | 16 #include "src/compiler/node-properties-inl.h" |
| 17 #include "src/compiler/node-properties.h" | 17 #include "src/compiler/node-properties.h" |
| 18 #include "src/compiler/opcodes.h" | 18 #include "src/compiler/opcodes.h" |
| 19 #include "src/compiler/operator.h" | 19 #include "src/compiler/operator.h" |
| 20 #include "src/compiler/schedule.h" | 20 #include "src/compiler/schedule.h" |
| 21 #include "src/compiler/simplified-operator.h" | |
| 21 #include "src/data-flow.h" | 22 #include "src/data-flow.h" |
| 22 | 23 |
| 23 namespace v8 { | 24 namespace v8 { |
| 24 namespace internal { | 25 namespace internal { |
| 25 namespace compiler { | 26 namespace compiler { |
| 26 | 27 |
| 27 | 28 |
| 28 static bool IsDefUseChainLinkPresent(Node* def, Node* use) { | 29 static bool IsDefUseChainLinkPresent(Node* def, Node* use) { |
| 29 Node::Uses uses = def->uses(); | 30 Node::Uses uses = def->uses(); |
| 30 for (Node::Uses::iterator it = uses.begin(); it != uses.end(); ++it) { | 31 for (Node::Uses::iterator it = uses.begin(); it != uses.end(); ++it) { |
| 31 if (*it == use) return true; | 32 if (*it == use) return true; |
| 32 } | 33 } |
| 33 return false; | 34 return false; |
| 34 } | 35 } |
| 35 | 36 |
| 36 | 37 |
| 37 static bool IsUseDefChainLinkPresent(Node* def, Node* use) { | 38 static bool IsUseDefChainLinkPresent(Node* def, Node* use) { |
| 38 Node::Inputs inputs = use->inputs(); | 39 Node::Inputs inputs = use->inputs(); |
| 39 for (Node::Inputs::iterator it = inputs.begin(); it != inputs.end(); ++it) { | 40 for (Node::Inputs::iterator it = inputs.begin(); it != inputs.end(); ++it) { |
| 40 if (*it == def) return true; | 41 if (*it == def) return true; |
| 41 } | 42 } |
| 42 return false; | 43 return false; |
| 43 } | 44 } |
| 44 | 45 |
| 45 | 46 |
| 46 class Verifier::Visitor : public NullNodeVisitor { | 47 class Verifier::Visitor : public NullNodeVisitor { |
| 47 public: | 48 public: |
| 48 explicit Visitor(Zone* zone) | 49 Visitor(Zone* z, Typing typed) : zone(z), typing(typed) {} |
| 49 : reached_from_start(NodeSet::key_compare(), | |
| 50 NodeSet::allocator_type(zone)), | |
| 51 reached_from_end(NodeSet::key_compare(), | |
| 52 NodeSet::allocator_type(zone)) {} | |
| 53 | 50 |
| 54 // Fulfills the PreNodeCallback interface. | 51 // Fulfills the PreNodeCallback interface. |
| 55 GenericGraphVisit::Control Pre(Node* node); | 52 GenericGraphVisit::Control Pre(Node* node); |
| 56 | 53 |
| 57 bool from_start; | 54 Zone* zone; |
| 58 NodeSet reached_from_start; | 55 Typing typing; |
| 59 NodeSet reached_from_end; | 56 |
| 57 private: | |
| 58 // TODO(rossberg): Get rid of these once we got rid of NodeProperties. | |
| 59 Bounds bounds(Node* node) { | |
|
titzer
2014/10/14 16:13:22
There is a method for this now, yes?
| |
| 60 return NodeProperties::GetBounds(node); | |
| 61 } | |
| 62 Node* Operand(Node* node, int i = 0) { | |
| 63 return NodeProperties::GetValueInput(node, i); | |
| 64 } | |
| 65 FieldAccess Field(Node* node) { | |
| 66 DCHECK(node->opcode() == IrOpcode::kLoadField || | |
| 67 node->opcode() == IrOpcode::kStoreField); | |
| 68 return OpParameter<FieldAccess>(node); | |
| 69 } | |
| 70 ElementAccess Element(Node* node) { | |
| 71 DCHECK(node->opcode() == IrOpcode::kLoadElement || | |
| 72 node->opcode() == IrOpcode::kStoreElement); | |
| 73 return OpParameter<ElementAccess>(node); | |
| 74 } | |
| 60 }; | 75 }; |
| 61 | 76 |
| 62 | 77 |
| 63 GenericGraphVisit::Control Verifier::Visitor::Pre(Node* node) { | 78 GenericGraphVisit::Control Verifier::Visitor::Pre(Node* node) { |
| 64 int value_count = OperatorProperties::GetValueInputCount(node->op()); | 79 int value_count = OperatorProperties::GetValueInputCount(node->op()); |
| 65 int context_count = OperatorProperties::GetContextInputCount(node->op()); | 80 int context_count = OperatorProperties::GetContextInputCount(node->op()); |
| 66 int frame_state_count = | 81 int frame_state_count = |
| 67 OperatorProperties::GetFrameStateInputCount(node->op()); | 82 OperatorProperties::GetFrameStateInputCount(node->op()); |
| 68 int effect_count = OperatorProperties::GetEffectInputCount(node->op()); | 83 int effect_count = OperatorProperties::GetEffectInputCount(node->op()); |
| 69 int control_count = OperatorProperties::GetControlInputCount(node->op()); | 84 int control_count = OperatorProperties::GetControlInputCount(node->op()); |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 119 // Verify all successors are projections if multiple value outputs exist. | 134 // Verify all successors are projections if multiple value outputs exist. |
| 120 if (OperatorProperties::GetValueOutputCount(node->op()) > 1) { | 135 if (OperatorProperties::GetValueOutputCount(node->op()) > 1) { |
| 121 Node::Uses uses = node->uses(); | 136 Node::Uses uses = node->uses(); |
| 122 for (Node::Uses::iterator it = uses.begin(); it != uses.end(); ++it) { | 137 for (Node::Uses::iterator it = uses.begin(); it != uses.end(); ++it) { |
| 123 CHECK(!NodeProperties::IsValueEdge(it.edge()) || | 138 CHECK(!NodeProperties::IsValueEdge(it.edge()) || |
| 124 (*it)->opcode() == IrOpcode::kProjection || | 139 (*it)->opcode() == IrOpcode::kProjection || |
| 125 (*it)->opcode() == IrOpcode::kParameter); | 140 (*it)->opcode() == IrOpcode::kParameter); |
| 126 } | 141 } |
| 127 } | 142 } |
| 128 | 143 |
| 129 switch (node->opcode()) { | 144 if (typing == TYPED) { |
| 130 case IrOpcode::kStart: | 145 switch (node->opcode()) { |
| 131 // Start has no inputs. | 146 // Control operators |
| 132 CHECK_EQ(0, input_count); | 147 // ----------------- |
| 133 break; | 148 case IrOpcode::kStart: |
| 134 case IrOpcode::kEnd: | 149 // Start has no inputs. |
| 135 // End has no outputs. | 150 CHECK_EQ(0, input_count); |
| 136 CHECK(!OperatorProperties::HasValueOutput(node->op())); | 151 // Type is a tuple. |
| 137 CHECK(!OperatorProperties::HasEffectOutput(node->op())); | 152 // TODO(rossberg): Multiple outputs are currently typed as Internal. |
| 138 CHECK(!OperatorProperties::HasControlOutput(node->op())); | 153 CHECK(bounds(node).upper->Is(Type::Internal())); |
| 139 break; | 154 break; |
| 140 case IrOpcode::kDead: | 155 case IrOpcode::kEnd: |
| 141 // Dead is never connected to the graph. | 156 // End has no outputs. |
| 142 UNREACHABLE(); | 157 CHECK(!OperatorProperties::HasValueOutput(node->op())); |
| 143 case IrOpcode::kBranch: { | 158 CHECK(!OperatorProperties::HasEffectOutput(node->op())); |
| 144 // Branch uses are IfTrue and IfFalse. | 159 CHECK(!OperatorProperties::HasControlOutput(node->op())); |
| 145 Node::Uses uses = node->uses(); | 160 // Type is empty. |
| 146 bool got_true = false, got_false = false; | 161 CHECK(!NodeProperties::IsTyped(node)); |
| 147 for (Node::Uses::iterator it = uses.begin(); it != uses.end(); ++it) { | 162 break; |
| 148 CHECK(((*it)->opcode() == IrOpcode::kIfTrue && !got_true) || | 163 case IrOpcode::kDead: |
| 149 ((*it)->opcode() == IrOpcode::kIfFalse && !got_false)); | 164 // Dead is never connected to the graph. |
| 150 if ((*it)->opcode() == IrOpcode::kIfTrue) got_true = true; | 165 UNREACHABLE(); |
| 151 if ((*it)->opcode() == IrOpcode::kIfFalse) got_false = true; | 166 case IrOpcode::kBranch: { |
| 152 } | 167 // Branch uses are IfTrue and IfFalse. |
| 153 // TODO(rossberg): Currently fails for various tests. | 168 Node::Uses uses = node->uses(); |
| 154 // CHECK(got_true && got_false); | 169 bool count_true = 0, count_false = 0; |
| 155 break; | 170 for (Node::Uses::iterator it = uses.begin(); it != uses.end(); ++it) { |
| 171 CHECK((*it)->opcode() == IrOpcode::kIfTrue || | |
| 172 (*it)->opcode() == IrOpcode::kIfFalse); | |
| 173 if ((*it)->opcode() == IrOpcode::kIfTrue) ++count_true; | |
| 174 if ((*it)->opcode() == IrOpcode::kIfFalse) ++count_false; | |
| 175 } | |
| 176 CHECK(count_true == 1 && count_false == 1); | |
| 177 // Type is empty. | |
| 178 CHECK(!NodeProperties::IsTyped(node)); | |
| 179 break; | |
| 180 } | |
| 181 case IrOpcode::kIfTrue: | |
| 182 case IrOpcode::kIfFalse: | |
| 183 CHECK_EQ(IrOpcode::kBranch, | |
| 184 NodeProperties::GetControlInput(node, 0)->opcode()); | |
| 185 // Type is empty. | |
| 186 CHECK(!NodeProperties::IsTyped(node)); | |
| 187 break; | |
| 188 case IrOpcode::kLoop: | |
| 189 case IrOpcode::kMerge: | |
| 190 // Type is empty. | |
| 191 CHECK(!NodeProperties::IsTyped(node)); | |
| 192 break; | |
| 193 case IrOpcode::kReturn: | |
| 194 // TODO(rossberg): check successor is End | |
| 195 // Type is empty. | |
| 196 CHECK(!NodeProperties::IsTyped(node)); | |
| 197 break; | |
| 198 case IrOpcode::kThrow: | |
| 199 // TODO(rossberg): what are the constraints on these? | |
| 200 // Type is empty. | |
| 201 CHECK(!NodeProperties::IsTyped(node)); | |
| 202 break; | |
| 203 | |
| 204 // Common operators | |
| 205 // ---------------- | |
| 206 case IrOpcode::kParameter: { | |
| 207 // Parameters have the start node as inputs. | |
| 208 CHECK_EQ(1, input_count); | |
| 209 CHECK_EQ(IrOpcode::kStart, | |
| 210 NodeProperties::GetValueInput(node, 0)->opcode()); | |
| 211 // Parameter has an input that produces enough values. | |
| 212 int index = OpParameter<int>(node); | |
| 213 Node* input = NodeProperties::GetValueInput(node, 0); | |
| 214 // Currently, parameter indices start at -1 instead of 0. | |
| 215 CHECK_GT( | |
| 216 OperatorProperties::GetValueOutputCount(input->op()), index + 1); | |
| 217 // Type can be anything. | |
| 218 CHECK(bounds(node).upper->Is(Type::Any())); | |
| 219 break; | |
| 220 } | |
| 221 case IrOpcode::kInt32Constant: // TODO(rossberg): rename Word32Constant? | |
| 222 // Constants have no inputs. | |
| 223 CHECK_EQ(0, input_count); | |
| 224 // Type is a 32 bit integer, signed or unsigned. | |
| 225 CHECK(bounds(node).upper->Is(Type::Integral32())); | |
| 226 break; | |
| 227 case IrOpcode::kInt64Constant: // Close enough... | |
| 228 case IrOpcode::kFloat32Constant: | |
| 229 case IrOpcode::kFloat64Constant: | |
| 230 case IrOpcode::kNumberConstant: | |
| 231 // Constants have no inputs. | |
| 232 CHECK_EQ(0, input_count); | |
| 233 // Type is a number. | |
| 234 CHECK(bounds(node).upper->Is(Type::Number())); | |
| 235 break; | |
| 236 case IrOpcode::kHeapConstant: | |
| 237 // Constants have no inputs. | |
| 238 CHECK_EQ(0, input_count); | |
| 239 // Type can be anything represented as a heap pointer. | |
| 240 CHECK(bounds(node).upper->Is(Type::TaggedPtr())); | |
| 241 break; | |
| 242 case IrOpcode::kExternalConstant: | |
| 243 // Constants have no inputs. | |
| 244 CHECK_EQ(0, input_count); | |
| 245 // Type is considered internal. | |
| 246 CHECK(bounds(node).upper->Is(Type::Internal())); | |
| 247 break; | |
| 248 case IrOpcode::kProjection: { | |
| 249 // Projection has an input that produces enough values. | |
| 250 int index = OpParameter<int>(node->op()); | |
| 251 Node* input = NodeProperties::GetValueInput(node, 0); | |
| 252 CHECK_GT(OperatorProperties::GetValueOutputCount(input->op()), index); | |
| 253 // Type can be anything. | |
| 254 // TODO(rossberg): Introduce tuple types for this. | |
| 255 CHECK(bounds(node).upper->Is(Type::Any())); | |
| 256 break; | |
| 257 } | |
| 258 case IrOpcode::kPhi: { | |
| 259 // Phi input count matches parent control node. | |
| 260 CHECK_EQ(1, control_count); | |
| 261 Node* control = NodeProperties::GetControlInput(node, 0); | |
| 262 CHECK_EQ(value_count, | |
| 263 OperatorProperties::GetControlInputCount(control->op())); | |
| 264 // Type must be subsumed by all input types. | |
| 265 // TODO(rossberg): for now at least, narrowing does not really hold. | |
| 266 /* | |
| 267 for (int i = 0; i < value_count; ++i) { | |
| 268 // TODO(rossberg, jarin): Figure out what to do about lower bounds. | |
| 269 // CHECK(bounds(node).lower->Is(bounds(Operand(node, i)).lower)); | |
| 270 CHECK(bounds(Operand(node, i)).upper->Is(bounds(node).upper)); | |
| 271 } | |
| 272 */ | |
| 273 break; | |
| 274 } | |
| 275 case IrOpcode::kEffectPhi: { | |
| 276 // EffectPhi input count matches parent control node. | |
| 277 CHECK_EQ(1, control_count); | |
| 278 Node* control = NodeProperties::GetControlInput(node, 0); | |
| 279 CHECK_EQ(effect_count, | |
| 280 OperatorProperties::GetControlInputCount(control->op())); | |
| 281 break; | |
| 282 } | |
| 283 case IrOpcode::kValueEffect: | |
| 284 // TODO(rossberg): what are the constraints on these? | |
| 285 break; | |
| 286 case IrOpcode::kFinish: { | |
| 287 // TODO(rossberg): what are the constraints on these? | |
| 288 // Type must be subsumed by input type. | |
| 289 CHECK(bounds(Operand(node)).lower->Is(bounds(node).lower)); | |
| 290 CHECK(bounds(Operand(node)).upper->Is(bounds(node).upper)); | |
| 291 break; | |
| 292 } | |
| 293 case IrOpcode::kFrameState: | |
| 294 // TODO(jarin): what are the constraints on these? | |
| 295 break; | |
| 296 case IrOpcode::kStateValues: | |
| 297 // TODO(jarin): what are the constraints on these? | |
| 298 break; | |
| 299 case IrOpcode::kCall: | |
| 300 // TODO(rossberg): what are the constraints on these? | |
| 301 break; | |
| 302 | |
| 303 // JavaScript operators | |
| 304 // -------------------- | |
| 305 case IrOpcode::kJSEqual: | |
| 306 case IrOpcode::kJSNotEqual: | |
| 307 case IrOpcode::kJSStrictEqual: | |
| 308 case IrOpcode::kJSStrictNotEqual: | |
| 309 case IrOpcode::kJSLessThan: | |
| 310 case IrOpcode::kJSGreaterThan: | |
| 311 case IrOpcode::kJSLessThanOrEqual: | |
| 312 case IrOpcode::kJSGreaterThanOrEqual: | |
| 313 case IrOpcode::kJSUnaryNot: | |
| 314 // Type is Boolean. | |
| 315 CHECK(bounds(node).upper->Is(Type::Boolean())); | |
| 316 break; | |
| 317 | |
| 318 case IrOpcode::kJSBitwiseOr: | |
| 319 case IrOpcode::kJSBitwiseXor: | |
| 320 case IrOpcode::kJSBitwiseAnd: | |
| 321 case IrOpcode::kJSShiftLeft: | |
| 322 case IrOpcode::kJSShiftRight: | |
| 323 case IrOpcode::kJSShiftRightLogical: | |
| 324 // Type is 32 bit integral. | |
| 325 CHECK(bounds(node).upper->Is(Type::Integral32())); | |
| 326 break; | |
| 327 case IrOpcode::kJSAdd: | |
| 328 // Type is Number or String. | |
| 329 CHECK(bounds(node).upper->Is(Type::NumberOrString())); | |
| 330 break; | |
| 331 case IrOpcode::kJSSubtract: | |
| 332 case IrOpcode::kJSMultiply: | |
| 333 case IrOpcode::kJSDivide: | |
| 334 case IrOpcode::kJSModulus: | |
| 335 // Type is Number. | |
| 336 CHECK(bounds(node).upper->Is(Type::Number())); | |
| 337 break; | |
| 338 | |
| 339 case IrOpcode::kJSToBoolean: | |
| 340 // Type is Boolean. | |
| 341 CHECK(bounds(node).upper->Is(Type::Boolean())); | |
| 342 break; | |
| 343 case IrOpcode::kJSToNumber: | |
| 344 // Type is Number. | |
| 345 CHECK(bounds(node).upper->Is(Type::Number())); | |
| 346 break; | |
| 347 case IrOpcode::kJSToString: | |
| 348 // Type is String. | |
| 349 CHECK(bounds(node).upper->Is(Type::String())); | |
| 350 break; | |
| 351 case IrOpcode::kJSToName: | |
| 352 // Type is Name. | |
| 353 CHECK(bounds(node).upper->Is(Type::Name())); | |
| 354 break; | |
| 355 case IrOpcode::kJSToObject: | |
| 356 // Type is Receiver. | |
| 357 CHECK(bounds(node).upper->Is(Type::Receiver())); | |
| 358 break; | |
| 359 | |
| 360 case IrOpcode::kJSCreate: | |
| 361 // Type is Object. | |
| 362 CHECK(bounds(node).upper->Is(Type::Object())); | |
| 363 break; | |
| 364 case IrOpcode::kJSLoadProperty: | |
| 365 case IrOpcode::kJSLoadNamed: | |
| 366 // Type can be anything. | |
| 367 CHECK(bounds(node).upper->Is(Type::Any())); | |
| 368 break; | |
| 369 case IrOpcode::kJSStoreProperty: | |
| 370 case IrOpcode::kJSStoreNamed: | |
| 371 // Type is empty. | |
| 372 CHECK(!NodeProperties::IsTyped(node)); | |
| 373 break; | |
| 374 case IrOpcode::kJSDeleteProperty: | |
| 375 case IrOpcode::kJSHasProperty: | |
| 376 case IrOpcode::kJSInstanceOf: | |
| 377 // Type is Boolean. | |
| 378 CHECK(bounds(node).upper->Is(Type::Boolean())); | |
| 379 break; | |
| 380 case IrOpcode::kJSTypeOf: | |
| 381 // Type is String. | |
| 382 CHECK(bounds(node).upper->Is(Type::String())); | |
| 383 break; | |
| 384 | |
| 385 case IrOpcode::kJSLoadContext: | |
| 386 // Type can be anything. | |
| 387 CHECK(bounds(node).upper->Is(Type::Any())); | |
| 388 break; | |
| 389 case IrOpcode::kJSStoreContext: | |
| 390 // Type is empty. | |
| 391 CHECK(!NodeProperties::IsTyped(node)); | |
| 392 break; | |
| 393 case IrOpcode::kJSCreateFunctionContext: | |
| 394 case IrOpcode::kJSCreateCatchContext: | |
| 395 case IrOpcode::kJSCreateWithContext: | |
| 396 case IrOpcode::kJSCreateBlockContext: | |
| 397 case IrOpcode::kJSCreateModuleContext: | |
| 398 case IrOpcode::kJSCreateGlobalContext: { | |
| 399 // Type is Context, and operand is Internal. | |
| 400 Bounds outer = bounds(NodeProperties::GetContextInput(node)); | |
| 401 // TODO(rossberg): This should really be Is(Internal), but the typer | |
| 402 // currently can't do backwards propagation. | |
| 403 CHECK(outer.upper->Maybe(Type::Internal())); | |
| 404 CHECK(bounds(node).upper->IsContext()); | |
| 405 break; | |
| 406 } | |
| 407 | |
| 408 case IrOpcode::kJSCallConstruct: | |
| 409 // Type is Receiver. | |
| 410 CHECK(bounds(node).upper->Is(Type::Receiver())); | |
| 411 break; | |
| 412 case IrOpcode::kJSCallFunction: | |
| 413 case IrOpcode::kJSCallRuntime: | |
| 414 case IrOpcode::kJSYield: | |
| 415 case IrOpcode::kJSDebugger: | |
| 416 // Type can be anything. | |
| 417 CHECK(bounds(node).upper->Is(Type::Any())); | |
| 418 break; | |
| 419 | |
| 420 // Simplified operators | |
| 421 // ------------------------------- | |
| 422 case IrOpcode::kBooleanNot: | |
| 423 // Boolean -> Boolean | |
| 424 CHECK(bounds(Operand(node)).upper->Is(Type::Boolean())); | |
| 425 CHECK(bounds(node).upper->Is(Type::Boolean())); | |
| 426 break; | |
| 427 case IrOpcode::kBooleanToNumber: | |
| 428 // Boolean -> Number | |
| 429 CHECK(bounds(Operand(node)).upper->Is(Type::Boolean())); | |
| 430 CHECK(bounds(node).upper->Is(Type::Number())); | |
| 431 break; | |
| 432 case IrOpcode::kNumberEqual: | |
| 433 case IrOpcode::kNumberLessThan: | |
| 434 case IrOpcode::kNumberLessThanOrEqual: | |
| 435 // (Number, Number) -> Boolean | |
| 436 CHECK(bounds(Operand(node, 0)).upper->Is(Type::Number())); | |
| 437 CHECK(bounds(Operand(node, 1)).upper->Is(Type::Number())); | |
| 438 CHECK(bounds(node).upper->Is(Type::Boolean())); | |
| 439 break; | |
| 440 case IrOpcode::kNumberAdd: | |
| 441 case IrOpcode::kNumberSubtract: | |
| 442 case IrOpcode::kNumberMultiply: | |
| 443 case IrOpcode::kNumberDivide: | |
| 444 case IrOpcode::kNumberModulus: | |
| 445 // (Number, Number) -> Number | |
| 446 CHECK(bounds(Operand(node, 0)).upper->Is(Type::Number())); | |
| 447 CHECK(bounds(Operand(node, 1)).upper->Is(Type::Number())); | |
| 448 // TODO(rossberg): activate once we retype after opcode changes. | |
| 449 // CHECK(bounds(node).upper->Is(Type::Number())); | |
| 450 break; | |
| 451 case IrOpcode::kNumberToInt32: | |
| 452 // Number -> Signed32 | |
| 453 CHECK(bounds(Operand(node)).upper->Is(Type::Number())); | |
| 454 CHECK(bounds(node).upper->Is(Type::Signed32())); | |
| 455 break; | |
| 456 case IrOpcode::kNumberToUint32: | |
| 457 // Number -> Unsigned32 | |
| 458 CHECK(bounds(Operand(node)).upper->Is(Type::Number())); | |
| 459 CHECK(bounds(node).upper->Is(Type::Unsigned32())); | |
| 460 break; | |
| 461 case IrOpcode::kStringEqual: | |
| 462 case IrOpcode::kStringLessThan: | |
| 463 case IrOpcode::kStringLessThanOrEqual: | |
| 464 // (String, String) -> Boolean | |
| 465 CHECK(bounds(Operand(node, 0)).upper->Is(Type::String())); | |
| 466 CHECK(bounds(Operand(node, 1)).upper->Is(Type::String())); | |
| 467 CHECK(bounds(node).upper->Is(Type::Boolean())); | |
| 468 break; | |
| 469 case IrOpcode::kStringAdd: | |
| 470 // (String, String) -> String | |
| 471 CHECK(bounds(Operand(node, 0)).upper->Is(Type::String())); | |
| 472 CHECK(bounds(Operand(node, 1)).upper->Is(Type::String())); | |
| 473 CHECK(bounds(node).upper->Is(Type::String())); | |
| 474 break; | |
| 475 case IrOpcode::kReferenceEqual: { | |
| 476 // (Unique, Any) -> Boolean and | |
| 477 // (Any, Unique) -> Boolean | |
| 478 CHECK(bounds(Operand(node, 0)).upper->Is(Type::Unique()) || | |
| 479 bounds(Operand(node, 1)).upper->Is(Type::Unique())); | |
| 480 CHECK(bounds(node).upper->Is(Type::Boolean())); | |
| 481 break; | |
| 482 } | |
| 483 | |
| 484 case IrOpcode::kChangeTaggedToInt32: { | |
| 485 // Signed32 /\ Tagged -> Signed32 /\ UntaggedInt32 | |
| 486 // TODO(neis): Activate once ChangeRepresentation works in typer. | |
| 487 // Type* from = Type::Intersect(Type::Signed32(), Type::Tagged()); | |
| 488 // Type* to = Type::Intersect(Type::Signed32(), Type::UntaggedInt32()); | |
| 489 // CHECK(bounds(Operand(node)).upper->Is(from)); | |
| 490 // CHECK(bounds(node).upper->Is(to)); | |
| 491 break; | |
| 492 } | |
| 493 case IrOpcode::kChangeTaggedToUint32: { | |
| 494 // Unsigned32 /\ Tagged -> Unsigned32 /\ UntaggedInt32 | |
| 495 // TODO(neis): Activate once ChangeRepresentation works in typer. | |
| 496 // Type* from = Type::Intersect(Type::Unsigned32(), Type::Tagged()); | |
| 497 // Type* to = Type::Intersect(Type::Unsigned32(), Type::UntaggedInt32()) ; | |
| 498 // CHECK(bounds(Operand(node)).upper->Is(from)); | |
| 499 // CHECK(bounds(node).upper->Is(to)); | |
| 500 break; | |
| 501 } | |
| 502 case IrOpcode::kChangeTaggedToFloat64: { | |
| 503 // Number /\ Tagged -> Number /\ UntaggedFloat64 | |
| 504 // TODO(neis): Activate once ChangeRepresentation works in typer. | |
| 505 // Type* from = Type::Intersect(Type::Number(), Type::Tagged()); | |
| 506 // Type* to = Type::Intersect(Type::Number(), Type::UntaggedFloat64()); | |
| 507 // CHECK(bounds(Operand(node)).upper->Is(from)); | |
| 508 // CHECK(bounds(node).upper->Is(to)); | |
| 509 break; | |
| 510 } | |
| 511 case IrOpcode::kChangeInt32ToTagged: { | |
| 512 // Signed32 /\ UntaggedInt32 -> Signed32 /\ Tagged | |
| 513 // TODO(neis): Activate once ChangeRepresentation works in typer. | |
| 514 // Type* from = Type::Intersect(Type::Signed32(), Type::UntaggedInt32()) ; | |
| 515 // Type* to = Type::Intersect(Type::Signed32(), Type::Tagged()); | |
| 516 // CHECK(bounds(Operand(node)).upper->Is(from)); | |
| 517 // CHECK(bounds(node).upper->Is(to)); | |
| 518 break; | |
| 519 } | |
| 520 case IrOpcode::kChangeUint32ToTagged: { | |
| 521 // Unsigned32 /\ UntaggedInt32 -> Unsigned32 /\ Tagged | |
| 522 // TODO(neis): Activate once ChangeRepresentation works in typer. | |
| 523 // Type* from = Type::Intersect(Type::Unsigned32(), Type::UntaggedInt32( )); | |
| 524 // Type* to = Type::Intersect(Type::Unsigned32(), Type::Tagged()); | |
| 525 // CHECK(bounds(Operand(node)).upper->Is(from)); | |
| 526 // CHECK(bounds(node).upper->Is(to)); | |
| 527 break; | |
| 528 } | |
| 529 case IrOpcode::kChangeFloat64ToTagged: { | |
| 530 // Number /\ UntaggedFloat64 -> Number /\ Tagged | |
| 531 // TODO(neis): Activate once ChangeRepresentation works in typer. | |
| 532 // Type* from = Type::Intersect(Type::Number(), Type::UntaggedFloat64()) ; | |
| 533 // Type* to = Type::Intersect(Type::Number(), Type::Tagged()); | |
| 534 // CHECK(bounds(Operand(node)).upper->Is(from)); | |
| 535 // CHECK(bounds(node).upper->Is(to)); | |
| 536 break; | |
| 537 } | |
| 538 case IrOpcode::kChangeBoolToBit: { | |
| 539 // Boolean /\ TaggedPtr -> Boolean /\ UntaggedInt1 | |
| 540 // TODO(neis): Activate once ChangeRepresentation works in typer. | |
| 541 // Type* from = Type::Intersect(Type::Boolean(), Type::TaggedPtr()); | |
| 542 // Type* to = Type::Intersect(Type::Boolean(), Type::UntaggedInt1()); | |
| 543 // CHECK(bounds(Operand(node)).upper->Is(from)); | |
| 544 // CHECK(bounds(node).upper->Is(to)); | |
| 545 break; | |
| 546 } | |
| 547 case IrOpcode::kChangeBitToBool: { | |
| 548 // Boolean /\ UntaggedInt1 -> Boolean /\ TaggedPtr | |
| 549 // TODO(neis): Activate once ChangeRepresentation works in typer. | |
| 550 // Type* from = Type::Intersect(Type::Boolean(), Type::UntaggedInt1()); | |
| 551 // Type* to = Type::Intersect(Type::Boolean(), Type::TaggedPtr()); | |
| 552 // CHECK(bounds(Operand(node)).upper->Is(from)); | |
| 553 // CHECK(bounds(node).upper->Is(to)); | |
| 554 break; | |
| 555 } | |
| 556 | |
| 557 case IrOpcode::kLoadField: | |
| 558 // Object -> fieldtype | |
| 559 // TODO(rossberg): activate once machine ops are typed. | |
| 560 // CHECK(bounds(Operand(node)).upper->Is(Type::Object())); | |
| 561 // CHECK(bounds(node).upper->Is(Field(node).type)); | |
| 562 break; | |
| 563 case IrOpcode::kLoadElement: | |
| 564 // Object -> elementtype | |
| 565 // TODO(rossberg): activate once machine ops are typed. | |
| 566 // CHECK(bounds(Operand(node)).upper->Is(Type::Object())); | |
| 567 // CHECK(bounds(node).upper->Is(Element(node).type)); | |
| 568 break; | |
| 569 case IrOpcode::kStoreField: | |
| 570 // (Object, fieldtype) -> _|_ | |
| 571 // TODO(rossberg): activate once machine ops are typed. | |
| 572 // CHECK(bounds(Operand(node, 0)).upper->Is(Type::Object())); | |
| 573 // CHECK(bounds(Operand(node, 1)).upper->Is(Field(node).type)); | |
| 574 CHECK(!NodeProperties::IsTyped(node)); | |
| 575 break; | |
| 576 case IrOpcode::kStoreElement: | |
| 577 // (Object, elementtype) -> _|_ | |
| 578 // TODO(rossberg): activate once machine ops are typed. | |
| 579 // CHECK(bounds(Operand(node, 0)).upper->Is(Type::Object())); | |
| 580 // CHECK(bounds(Operand(node, 1)).upper->Is(Element(node).type)); | |
| 581 CHECK(!NodeProperties::IsTyped(node)); | |
| 582 break; | |
| 583 | |
| 584 // Machine operators | |
| 585 // ----------------------- | |
| 586 case IrOpcode::kLoad: | |
| 587 case IrOpcode::kStore: | |
| 588 case IrOpcode::kWord32And: | |
| 589 case IrOpcode::kWord32Or: | |
| 590 case IrOpcode::kWord32Xor: | |
| 591 case IrOpcode::kWord32Shl: | |
| 592 case IrOpcode::kWord32Shr: | |
| 593 case IrOpcode::kWord32Sar: | |
| 594 case IrOpcode::kWord32Ror: | |
| 595 case IrOpcode::kWord32Equal: | |
| 596 case IrOpcode::kWord64And: | |
| 597 case IrOpcode::kWord64Or: | |
| 598 case IrOpcode::kWord64Xor: | |
| 599 case IrOpcode::kWord64Shl: | |
| 600 case IrOpcode::kWord64Shr: | |
| 601 case IrOpcode::kWord64Sar: | |
| 602 case IrOpcode::kWord64Ror: | |
| 603 case IrOpcode::kWord64Equal: | |
| 604 case IrOpcode::kInt32Add: | |
| 605 case IrOpcode::kInt32AddWithOverflow: | |
| 606 case IrOpcode::kInt32Sub: | |
| 607 case IrOpcode::kInt32SubWithOverflow: | |
| 608 case IrOpcode::kInt32Mul: | |
| 609 case IrOpcode::kInt32MulHigh: | |
| 610 case IrOpcode::kInt32Div: | |
| 611 case IrOpcode::kInt32Mod: | |
| 612 case IrOpcode::kInt32LessThan: | |
| 613 case IrOpcode::kInt32LessThanOrEqual: | |
| 614 case IrOpcode::kUint32Div: | |
| 615 case IrOpcode::kUint32Mod: | |
| 616 case IrOpcode::kUint32LessThan: | |
| 617 case IrOpcode::kUint32LessThanOrEqual: | |
| 618 case IrOpcode::kInt64Add: | |
| 619 case IrOpcode::kInt64Sub: | |
| 620 case IrOpcode::kInt64Mul: | |
| 621 case IrOpcode::kInt64Div: | |
| 622 case IrOpcode::kInt64Mod: | |
| 623 case IrOpcode::kInt64LessThan: | |
| 624 case IrOpcode::kInt64LessThanOrEqual: | |
| 625 case IrOpcode::kUint64Div: | |
| 626 case IrOpcode::kUint64Mod: | |
| 627 case IrOpcode::kUint64LessThan: | |
| 628 case IrOpcode::kFloat64Add: | |
| 629 case IrOpcode::kFloat64Sub: | |
| 630 case IrOpcode::kFloat64Mul: | |
| 631 case IrOpcode::kFloat64Div: | |
| 632 case IrOpcode::kFloat64Mod: | |
| 633 case IrOpcode::kFloat64Sqrt: | |
| 634 case IrOpcode::kFloat64Equal: | |
| 635 case IrOpcode::kFloat64LessThan: | |
| 636 case IrOpcode::kFloat64LessThanOrEqual: | |
| 637 case IrOpcode::kTruncateInt64ToInt32: | |
| 638 case IrOpcode::kTruncateFloat64ToFloat32: | |
| 639 case IrOpcode::kTruncateFloat64ToInt32: | |
| 640 case IrOpcode::kChangeInt32ToInt64: | |
| 641 case IrOpcode::kChangeUint32ToUint64: | |
| 642 case IrOpcode::kChangeInt32ToFloat64: | |
| 643 case IrOpcode::kChangeUint32ToFloat64: | |
| 644 case IrOpcode::kChangeFloat32ToFloat64: | |
| 645 case IrOpcode::kChangeFloat64ToInt32: | |
| 646 case IrOpcode::kChangeFloat64ToUint32: | |
| 647 case IrOpcode::kLoadStackPointer: | |
| 648 // TODO(rossberg): Check. | |
| 649 break; | |
| 156 } | 650 } |
| 157 case IrOpcode::kIfTrue: | |
| 158 case IrOpcode::kIfFalse: | |
| 159 CHECK_EQ(IrOpcode::kBranch, | |
| 160 NodeProperties::GetControlInput(node, 0)->opcode()); | |
| 161 break; | |
| 162 case IrOpcode::kLoop: | |
| 163 case IrOpcode::kMerge: | |
| 164 break; | |
| 165 case IrOpcode::kReturn: | |
| 166 // TODO(rossberg): check successor is End | |
| 167 break; | |
| 168 case IrOpcode::kThrow: | |
| 169 // TODO(rossberg): what are the constraints on these? | |
| 170 break; | |
| 171 case IrOpcode::kParameter: { | |
| 172 // Parameters have the start node as inputs. | |
| 173 CHECK_EQ(1, input_count); | |
| 174 CHECK_EQ(IrOpcode::kStart, | |
| 175 NodeProperties::GetValueInput(node, 0)->opcode()); | |
| 176 // Parameter has an input that produces enough values. | |
| 177 int index = OpParameter<int>(node); | |
| 178 Node* input = NodeProperties::GetValueInput(node, 0); | |
| 179 // Currently, parameter indices start at -1 instead of 0. | |
| 180 CHECK_GT(OperatorProperties::GetValueOutputCount(input->op()), index + 1); | |
| 181 break; | |
| 182 } | |
| 183 case IrOpcode::kInt32Constant: | |
| 184 case IrOpcode::kInt64Constant: | |
| 185 case IrOpcode::kFloat64Constant: | |
| 186 case IrOpcode::kExternalConstant: | |
| 187 case IrOpcode::kNumberConstant: | |
| 188 case IrOpcode::kHeapConstant: | |
| 189 // Constants have no inputs. | |
| 190 CHECK_EQ(0, input_count); | |
| 191 break; | |
| 192 case IrOpcode::kPhi: { | |
| 193 // Phi input count matches parent control node. | |
| 194 CHECK_EQ(1, control_count); | |
| 195 Node* control = NodeProperties::GetControlInput(node, 0); | |
| 196 CHECK_EQ(value_count, | |
| 197 OperatorProperties::GetControlInputCount(control->op())); | |
| 198 break; | |
| 199 } | |
| 200 case IrOpcode::kEffectPhi: { | |
| 201 // EffectPhi input count matches parent control node. | |
| 202 CHECK_EQ(1, control_count); | |
| 203 Node* control = NodeProperties::GetControlInput(node, 0); | |
| 204 CHECK_EQ(effect_count, | |
| 205 OperatorProperties::GetControlInputCount(control->op())); | |
| 206 break; | |
| 207 } | |
| 208 case IrOpcode::kFrameState: | |
| 209 // TODO(jarin): what are the constraints on these? | |
| 210 break; | |
| 211 case IrOpcode::kCall: | |
| 212 // TODO(rossberg): what are the constraints on these? | |
| 213 break; | |
| 214 case IrOpcode::kProjection: { | |
| 215 // Projection has an input that produces enough values. | |
| 216 size_t index = OpParameter<size_t>(node); | |
| 217 Node* input = NodeProperties::GetValueInput(node, 0); | |
| 218 CHECK_GT(OperatorProperties::GetValueOutputCount(input->op()), | |
| 219 static_cast<int>(index)); | |
| 220 break; | |
| 221 } | |
| 222 default: | |
| 223 // TODO(rossberg): Check other node kinds. | |
| 224 break; | |
| 225 } | |
| 226 | |
| 227 if (from_start) { | |
| 228 reached_from_start.insert(node); | |
| 229 } else { | |
| 230 reached_from_end.insert(node); | |
| 231 } | 651 } |
| 232 | 652 |
| 233 return GenericGraphVisit::CONTINUE; | 653 return GenericGraphVisit::CONTINUE; |
| 234 } | 654 } |
| 235 | 655 |
| 236 | 656 |
| 237 void Verifier::Run(Graph* graph) { | 657 void Verifier::Run(Graph* graph, Typing typing) { |
| 238 Visitor visitor(graph->zone()); | 658 Visitor visitor(graph->zone(), typing); |
| 239 | |
| 240 CHECK_NE(NULL, graph->start()); | 659 CHECK_NE(NULL, graph->start()); |
| 241 visitor.from_start = true; | |
| 242 graph->VisitNodeUsesFromStart(&visitor); | |
| 243 CHECK_NE(NULL, graph->end()); | 660 CHECK_NE(NULL, graph->end()); |
| 244 visitor.from_start = false; | |
| 245 graph->VisitNodeInputsFromEnd(&visitor); | 661 graph->VisitNodeInputsFromEnd(&visitor); |
| 246 | |
| 247 // All control nodes reachable from end are reachable from start. | |
| 248 for (NodeSet::iterator it = visitor.reached_from_end.begin(); | |
| 249 it != visitor.reached_from_end.end(); ++it) { | |
| 250 CHECK(!NodeProperties::IsControl(*it) || | |
| 251 visitor.reached_from_start.count(*it)); | |
| 252 } | |
| 253 } | 662 } |
| 254 | 663 |
| 255 | 664 |
| 665 // ----------------------------------------------------------------------------- | |
| 666 | |
| 256 static bool HasDominatingDef(Schedule* schedule, Node* node, | 667 static bool HasDominatingDef(Schedule* schedule, Node* node, |
| 257 BasicBlock* container, BasicBlock* use_block, | 668 BasicBlock* container, BasicBlock* use_block, |
| 258 int use_pos) { | 669 int use_pos) { |
| 259 BasicBlock* block = use_block; | 670 BasicBlock* block = use_block; |
| 260 while (true) { | 671 while (true) { |
| 261 while (use_pos >= 0) { | 672 while (use_pos >= 0) { |
| 262 if (block->NodeAt(use_pos) == node) return true; | 673 if (block->NodeAt(use_pos) == node) return true; |
| 263 use_pos--; | 674 use_pos--; |
| 264 } | 675 } |
| 265 block = block->dominator(); | 676 block = block->dominator(); |
| (...skipping 208 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 474 // Check inputs for all nodes in the block. | 885 // Check inputs for all nodes in the block. |
| 475 for (size_t i = 0; i < block->NodeCount(); i++) { | 886 for (size_t i = 0; i < block->NodeCount(); i++) { |
| 476 Node* node = block->NodeAt(i); | 887 Node* node = block->NodeAt(i); |
| 477 CheckInputsDominate(schedule, block, node, static_cast<int>(i) - 1); | 888 CheckInputsDominate(schedule, block, node, static_cast<int>(i) - 1); |
| 478 } | 889 } |
| 479 } | 890 } |
| 480 } | 891 } |
| 481 } | 892 } |
| 482 } | 893 } |
| 483 } // namespace v8::internal::compiler | 894 } // namespace v8::internal::compiler |
| OLD | NEW |