1// Copyright 2016 the V8 project authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "src/compiler/machine-graph-verifier.h" 6 7#include "src/compiler/common-operator.h" 8#include "src/compiler/graph.h" 9#include "src/compiler/linkage.h" 10#include "src/compiler/machine-operator.h" 11#include "src/compiler/node-properties.h" 12#include "src/compiler/node.h" 13#include "src/compiler/schedule.h" 14#include "src/zone/zone.h" 15 16namespace v8 { 17namespace internal { 18namespace compiler { 19 20namespace { 21 22class MachineRepresentationInferrer { 23 public: 24 MachineRepresentationInferrer(Schedule const* schedule, Graph const* graph, 25 Linkage* linkage, Zone* zone) 26 : schedule_(schedule), 27 linkage_(linkage), 28 representation_vector_(graph->NodeCount(), MachineRepresentation::kNone, 29 zone) { 30 Run(); 31 } 32 33 CallDescriptor* call_descriptor() const { 34 return linkage_->GetIncomingDescriptor(); 35 } 36 37 MachineRepresentation GetRepresentation(Node const* node) const { 38 return representation_vector_.at(node->id()); 39 } 40 41 private: 42 MachineRepresentation GetProjectionType(Node const* projection) { 43 size_t index = ProjectionIndexOf(projection->op()); 44 Node* input = projection->InputAt(0); 45 switch (input->opcode()) { 46 case IrOpcode::kInt32AddWithOverflow: 47 case IrOpcode::kInt32SubWithOverflow: 48 case IrOpcode::kInt32MulWithOverflow: 49 CHECK_LE(index, static_cast<size_t>(1)); 50 return index == 0 ? MachineRepresentation::kWord32 51 : MachineRepresentation::kBit; 52 case IrOpcode::kInt64AddWithOverflow: 53 case IrOpcode::kInt64SubWithOverflow: 54 CHECK_LE(index, static_cast<size_t>(1)); 55 return index == 0 ? MachineRepresentation::kWord64 56 : MachineRepresentation::kBit; 57 case IrOpcode::kTryTruncateFloat32ToInt64: 58 case IrOpcode::kTryTruncateFloat64ToInt64: 59 case IrOpcode::kTryTruncateFloat32ToUint64: 60 CHECK_LE(index, static_cast<size_t>(1)); 61 return index == 0 ? MachineRepresentation::kWord64 62 : MachineRepresentation::kBit; 63 case IrOpcode::kCall: { 64 auto call_descriptor = CallDescriptorOf(input->op()); 65 return call_descriptor->GetReturnType(index).representation(); 66 } 67 case IrOpcode::kWord32AtomicPairLoad: 68 case IrOpcode::kWord32AtomicPairAdd: 69 case IrOpcode::kWord32AtomicPairSub: 70 case IrOpcode::kWord32AtomicPairAnd: 71 case IrOpcode::kWord32AtomicPairOr: 72 case IrOpcode::kWord32AtomicPairXor: 73 case IrOpcode::kWord32AtomicPairExchange: 74 case IrOpcode::kWord32AtomicPairCompareExchange: 75 CHECK_LE(index, static_cast<size_t>(1)); 76 return MachineRepresentation::kWord32; 77 default: 78 return MachineRepresentation::kNone; 79 } 80 } 81 82 MachineRepresentation PromoteRepresentation(MachineRepresentation rep) { 83 switch (rep) { 84 case MachineRepresentation::kWord8: 85 case MachineRepresentation::kWord16: 86 case MachineRepresentation::kWord32: 87 return MachineRepresentation::kWord32; 88 case MachineRepresentation::kSandboxedPointer: 89 // A sandboxed pointer is a Word64 that uses an encoded representation 90 // when stored on the heap. 91 return MachineRepresentation::kWord64; 92 default: 93 break; 94 } 95 return rep; 96 } 97 98 void Run() { 99 auto blocks = schedule_->all_blocks(); 100 for (BasicBlock* block : *blocks) { 101 current_block_ = block; 102 for (size_t i = 0; i <= block->NodeCount(); ++i) { 103 Node const* node = 104 i < block->NodeCount() ? block->NodeAt(i) : block->control_input(); 105 if (node == nullptr) { 106 DCHECK_EQ(block->NodeCount(), i); 107 break; 108 } 109 switch (node->opcode()) { 110 case IrOpcode::kParameter: 111 representation_vector_[node->id()] = 112 linkage_->GetParameterType(ParameterIndexOf(node->op())) 113 .representation(); 114 break; 115 case IrOpcode::kReturn: { 116 representation_vector_[node->id()] = PromoteRepresentation( 117 linkage_->GetReturnType().representation()); 118 break; 119 } 120 case IrOpcode::kProjection: { 121 representation_vector_[node->id()] = GetProjectionType(node); 122 } break; 123 case IrOpcode::kTypedStateValues: 124 representation_vector_[node->id()] = MachineRepresentation::kNone; 125 break; 126 case IrOpcode::kWord32AtomicLoad: 127 case IrOpcode::kWord64AtomicLoad: 128 representation_vector_[node->id()] = 129 PromoteRepresentation(AtomicLoadParametersOf(node->op()) 130 .representation() 131 .representation()); 132 break; 133 case IrOpcode::kLoad: 134 case IrOpcode::kLoadImmutable: 135 case IrOpcode::kProtectedLoad: 136 representation_vector_[node->id()] = PromoteRepresentation( 137 LoadRepresentationOf(node->op()).representation()); 138 break; 139 case IrOpcode::kLoadFramePointer: 140 case IrOpcode::kLoadParentFramePointer: 141 representation_vector_[node->id()] = 142 MachineType::PointerRepresentation(); 143 break; 144 case IrOpcode::kUnalignedLoad: 145 representation_vector_[node->id()] = PromoteRepresentation( 146 LoadRepresentationOf(node->op()).representation()); 147 break; 148 case IrOpcode::kPhi: 149 representation_vector_[node->id()] = 150 PhiRepresentationOf(node->op()); 151 break; 152 case IrOpcode::kCall: { 153 auto call_descriptor = CallDescriptorOf(node->op()); 154 if (call_descriptor->ReturnCount() > 0) { 155 representation_vector_[node->id()] = 156 call_descriptor->GetReturnType(0).representation(); 157 } else { 158 representation_vector_[node->id()] = 159 MachineRepresentation::kTagged; 160 } 161 break; 162 } 163 case IrOpcode::kWord32AtomicStore: 164 case IrOpcode::kWord64AtomicStore: 165 representation_vector_[node->id()] = PromoteRepresentation( 166 AtomicStoreParametersOf(node->op()).representation()); 167 break; 168 case IrOpcode::kWord32AtomicPairLoad: 169 case IrOpcode::kWord32AtomicPairStore: 170 case IrOpcode::kWord32AtomicPairAdd: 171 case IrOpcode::kWord32AtomicPairSub: 172 case IrOpcode::kWord32AtomicPairAnd: 173 case IrOpcode::kWord32AtomicPairOr: 174 case IrOpcode::kWord32AtomicPairXor: 175 case IrOpcode::kWord32AtomicPairExchange: 176 case IrOpcode::kWord32AtomicPairCompareExchange: 177 representation_vector_[node->id()] = MachineRepresentation::kWord32; 178 break; 179 case IrOpcode::kWord32AtomicExchange: 180 case IrOpcode::kWord32AtomicCompareExchange: 181 case IrOpcode::kWord32AtomicAdd: 182 case IrOpcode::kWord32AtomicSub: 183 case IrOpcode::kWord32AtomicAnd: 184 case IrOpcode::kWord32AtomicOr: 185 case IrOpcode::kWord32AtomicXor: 186 case IrOpcode::kWord64AtomicExchange: 187 case IrOpcode::kWord64AtomicCompareExchange: 188 case IrOpcode::kWord64AtomicAdd: 189 case IrOpcode::kWord64AtomicSub: 190 case IrOpcode::kWord64AtomicAnd: 191 case IrOpcode::kWord64AtomicOr: 192 case IrOpcode::kWord64AtomicXor: 193 representation_vector_[node->id()] = PromoteRepresentation( 194 AtomicOpType(node->op()).representation()); 195 break; 196 case IrOpcode::kStore: 197 case IrOpcode::kProtectedStore: 198 representation_vector_[node->id()] = PromoteRepresentation( 199 StoreRepresentationOf(node->op()).representation()); 200 break; 201 case IrOpcode::kUnalignedStore: 202 representation_vector_[node->id()] = PromoteRepresentation( 203 UnalignedStoreRepresentationOf(node->op())); 204 break; 205 case IrOpcode::kHeapConstant: 206 representation_vector_[node->id()] = 207 MachineRepresentation::kTaggedPointer; 208 break; 209 case IrOpcode::kNumberConstant: 210 case IrOpcode::kDelayedStringConstant: 211 case IrOpcode::kChangeBitToTagged: 212 case IrOpcode::kIfException: 213 case IrOpcode::kOsrValue: 214 case IrOpcode::kChangeInt32ToTagged: 215 case IrOpcode::kChangeUint32ToTagged: 216 case IrOpcode::kBitcastWordToTagged: 217 representation_vector_[node->id()] = MachineRepresentation::kTagged; 218 break; 219 case IrOpcode::kCompressedHeapConstant: 220 representation_vector_[node->id()] = 221 MachineRepresentation::kCompressedPointer; 222 break; 223 case IrOpcode::kExternalConstant: 224 representation_vector_[node->id()] = 225 MachineType::PointerRepresentation(); 226 break; 227 case IrOpcode::kBitcastTaggedToWord: 228 case IrOpcode::kBitcastTaggedToWordForTagAndSmiBits: 229 representation_vector_[node->id()] = 230 MachineType::PointerRepresentation(); 231 break; 232 case IrOpcode::kBitcastWordToTaggedSigned: 233 representation_vector_[node->id()] = 234 MachineRepresentation::kTaggedSigned; 235 break; 236 case IrOpcode::kWord32Equal: 237 case IrOpcode::kInt32LessThan: 238 case IrOpcode::kInt32LessThanOrEqual: 239 case IrOpcode::kUint32LessThan: 240 case IrOpcode::kUint32LessThanOrEqual: 241 case IrOpcode::kWord64Equal: 242 case IrOpcode::kInt64LessThan: 243 case IrOpcode::kInt64LessThanOrEqual: 244 case IrOpcode::kUint64LessThan: 245 case IrOpcode::kUint64LessThanOrEqual: 246 case IrOpcode::kFloat32Equal: 247 case IrOpcode::kFloat32LessThan: 248 case IrOpcode::kFloat32LessThanOrEqual: 249 case IrOpcode::kFloat64Equal: 250 case IrOpcode::kFloat64LessThan: 251 case IrOpcode::kFloat64LessThanOrEqual: 252 case IrOpcode::kChangeTaggedToBit: 253 case IrOpcode::kStackPointerGreaterThan: 254 representation_vector_[node->id()] = MachineRepresentation::kBit; 255 break; 256#define LABEL(opcode) case IrOpcode::k##opcode: 257 case IrOpcode::kTruncateInt64ToInt32: 258 case IrOpcode::kTruncateFloat32ToInt32: 259 case IrOpcode::kTruncateFloat32ToUint32: 260 case IrOpcode::kBitcastFloat32ToInt32: 261 case IrOpcode::kI32x4ExtractLane: 262 case IrOpcode::kI16x8ExtractLaneU: 263 case IrOpcode::kI16x8ExtractLaneS: 264 case IrOpcode::kI8x16ExtractLaneU: 265 case IrOpcode::kI8x16ExtractLaneS: 266 case IrOpcode::kInt32Constant: 267 case IrOpcode::kRelocatableInt32Constant: 268 case IrOpcode::kTruncateFloat64ToWord32: 269 case IrOpcode::kTruncateFloat64ToUint32: 270 case IrOpcode::kChangeFloat64ToInt32: 271 case IrOpcode::kChangeFloat64ToUint32: 272 case IrOpcode::kRoundFloat64ToInt32: 273 case IrOpcode::kFloat64ExtractLowWord32: 274 case IrOpcode::kFloat64ExtractHighWord32: 275 case IrOpcode::kWord32Popcnt: 276 case IrOpcode::kI8x16BitMask: 277 MACHINE_UNOP_32_LIST(LABEL) 278 MACHINE_BINOP_32_LIST(LABEL) { 279 representation_vector_[node->id()] = 280 MachineRepresentation::kWord32; 281 } 282 break; 283 case IrOpcode::kChangeInt32ToInt64: 284 case IrOpcode::kChangeUint32ToUint64: 285 case IrOpcode::kInt64Constant: 286 case IrOpcode::kRelocatableInt64Constant: 287 case IrOpcode::kBitcastFloat64ToInt64: 288 case IrOpcode::kChangeFloat64ToInt64: 289 case IrOpcode::kChangeFloat64ToUint64: 290 case IrOpcode::kWord64Popcnt: 291 case IrOpcode::kWord64Ctz: 292 case IrOpcode::kWord64Clz: 293 MACHINE_BINOP_64_LIST(LABEL) { 294 representation_vector_[node->id()] = 295 MachineRepresentation::kWord64; 296 } 297 break; 298 case IrOpcode::kRoundInt32ToFloat32: 299 case IrOpcode::kRoundUint32ToFloat32: 300 case IrOpcode::kRoundInt64ToFloat32: 301 case IrOpcode::kRoundUint64ToFloat32: 302 case IrOpcode::kBitcastInt32ToFloat32: 303 case IrOpcode::kFloat32Constant: 304 case IrOpcode::kTruncateFloat64ToFloat32: 305 MACHINE_FLOAT32_BINOP_LIST(LABEL) 306 MACHINE_FLOAT32_UNOP_LIST(LABEL) { 307 representation_vector_[node->id()] = 308 MachineRepresentation::kFloat32; 309 } 310 break; 311 case IrOpcode::kRoundInt64ToFloat64: 312 case IrOpcode::kRoundUint64ToFloat64: 313 case IrOpcode::kChangeFloat32ToFloat64: 314 case IrOpcode::kChangeInt32ToFloat64: 315 case IrOpcode::kChangeUint32ToFloat64: 316 case IrOpcode::kFloat64InsertLowWord32: 317 case IrOpcode::kFloat64InsertHighWord32: 318 case IrOpcode::kFloat64Constant: 319 case IrOpcode::kFloat64SilenceNaN: 320 MACHINE_FLOAT64_BINOP_LIST(LABEL) 321 MACHINE_FLOAT64_UNOP_LIST(LABEL) { 322 representation_vector_[node->id()] = 323 MachineRepresentation::kFloat64; 324 } 325 break; 326 case IrOpcode::kI32x4ReplaceLane: 327 case IrOpcode::kI32x4Splat: 328 case IrOpcode::kI8x16Splat: 329 case IrOpcode::kI8x16Eq: 330 representation_vector_[node->id()] = 331 MachineRepresentation::kSimd128; 332 break; 333#undef LABEL 334 default: 335 break; 336 } 337 } 338 } 339 } 340 341 Schedule const* const schedule_; 342 Linkage const* const linkage_; 343 ZoneVector<MachineRepresentation> representation_vector_; 344 BasicBlock* current_block_; 345}; 346 347class MachineRepresentationChecker { 348 public: 349 MachineRepresentationChecker( 350 Schedule const* const schedule, 351 MachineRepresentationInferrer const* const inferrer, bool is_stub, 352 const char* name) 353 : schedule_(schedule), 354 inferrer_(inferrer), 355 is_stub_(is_stub), 356 name_(name), 357 current_block_(nullptr) {} 358 359 void Run() { 360 BasicBlockVector const* blocks = schedule_->all_blocks(); 361 for (BasicBlock* block : *blocks) { 362 current_block_ = block; 363 for (size_t i = 0; i <= block->NodeCount(); ++i) { 364 Node const* node = 365 i < block->NodeCount() ? block->NodeAt(i) : block->control_input(); 366 if (node == nullptr) { 367 DCHECK_EQ(block->NodeCount(), i); 368 break; 369 } 370 switch (node->opcode()) { 371 case IrOpcode::kCall: 372 case IrOpcode::kTailCall: 373 CheckCallInputs(node); 374 break; 375 case IrOpcode::kChangeBitToTagged: 376 CHECK_EQ(MachineRepresentation::kBit, 377 inferrer_->GetRepresentation(node->InputAt(0))); 378 break; 379 case IrOpcode::kChangeTaggedToBit: 380 CHECK_EQ(MachineRepresentation::kTagged, 381 inferrer_->GetRepresentation(node->InputAt(0))); 382 break; 383 case IrOpcode::kRoundInt64ToFloat64: 384 case IrOpcode::kRoundUint64ToFloat64: 385 case IrOpcode::kRoundInt64ToFloat32: 386 case IrOpcode::kRoundUint64ToFloat32: 387 case IrOpcode::kTruncateInt64ToInt32: 388 case IrOpcode::kWord64Ctz: 389 case IrOpcode::kWord64Clz: 390 case IrOpcode::kWord64Popcnt: 391 CheckValueInputForInt64Op(node, 0); 392 break; 393 case IrOpcode::kBitcastWordToTagged: 394 case IrOpcode::kBitcastWordToTaggedSigned: 395 CheckValueInputRepresentationIs( 396 node, 0, MachineType::PointerRepresentation()); 397 break; 398 case IrOpcode::kBitcastTaggedToWord: 399 case IrOpcode::kBitcastTaggedToWordForTagAndSmiBits: 400 if (COMPRESS_POINTERS_BOOL) { 401 CheckValueInputIsCompressedOrTagged(node, 0); 402 } else { 403 CheckValueInputIsTagged(node, 0); 404 } 405 break; 406 case IrOpcode::kTruncateFloat64ToWord32: 407 case IrOpcode::kTruncateFloat64ToUint32: 408 case IrOpcode::kTruncateFloat64ToFloat32: 409 case IrOpcode::kChangeFloat64ToInt32: 410 case IrOpcode::kChangeFloat64ToUint32: 411 case IrOpcode::kRoundFloat64ToInt32: 412 case IrOpcode::kFloat64ExtractLowWord32: 413 case IrOpcode::kFloat64ExtractHighWord32: 414 case IrOpcode::kBitcastFloat64ToInt64: 415 case IrOpcode::kTryTruncateFloat64ToInt64: 416 CheckValueInputForFloat64Op(node, 0); 417 break; 418 case IrOpcode::kWord64Equal: 419 if (Is64() && !COMPRESS_POINTERS_BOOL) { 420 CheckValueInputIsTaggedOrPointer(node, 0); 421 CheckValueInputIsTaggedOrPointer(node, 1); 422 if (!is_stub_) { 423 CheckValueInputRepresentationIs( 424 node, 1, inferrer_->GetRepresentation(node->InputAt(0))); 425 } 426 } else { 427 CheckValueInputForInt64Op(node, 0); 428 CheckValueInputForInt64Op(node, 1); 429 } 430 break; 431 case IrOpcode::kInt64LessThan: 432 case IrOpcode::kInt64LessThanOrEqual: 433 case IrOpcode::kUint64LessThan: 434 case IrOpcode::kUint64LessThanOrEqual: 435 CheckValueInputForInt64Op(node, 0); 436 CheckValueInputForInt64Op(node, 1); 437 break; 438 case IrOpcode::kI32x4ExtractLane: 439 case IrOpcode::kI16x8ExtractLaneU: 440 case IrOpcode::kI16x8ExtractLaneS: 441 case IrOpcode::kI8x16BitMask: 442 case IrOpcode::kI8x16ExtractLaneU: 443 case IrOpcode::kI8x16ExtractLaneS: 444 CheckValueInputRepresentationIs(node, 0, 445 MachineRepresentation::kSimd128); 446 break; 447 case IrOpcode::kI32x4ReplaceLane: 448 CheckValueInputRepresentationIs(node, 0, 449 MachineRepresentation::kSimd128); 450 CheckValueInputForInt32Op(node, 1); 451 break; 452 case IrOpcode::kI32x4Splat: 453 case IrOpcode::kI8x16Splat: 454 CheckValueInputForInt32Op(node, 0); 455 break; 456 case IrOpcode::kI8x16Eq: 457 CheckValueInputRepresentationIs(node, 0, 458 MachineRepresentation::kSimd128); 459 CheckValueInputRepresentationIs(node, 1, 460 MachineRepresentation::kSimd128); 461 break; 462 463#define LABEL(opcode) case IrOpcode::k##opcode: 464 case IrOpcode::kChangeInt32ToTagged: 465 case IrOpcode::kChangeUint32ToTagged: 466 case IrOpcode::kChangeInt32ToFloat64: 467 case IrOpcode::kChangeUint32ToFloat64: 468 case IrOpcode::kRoundInt32ToFloat32: 469 case IrOpcode::kRoundUint32ToFloat32: 470 case IrOpcode::kBitcastInt32ToFloat32: 471 case IrOpcode::kBitcastWord32ToWord64: 472 case IrOpcode::kChangeInt32ToInt64: 473 case IrOpcode::kChangeUint32ToUint64: 474 case IrOpcode::kWord32Popcnt: 475 MACHINE_UNOP_32_LIST(LABEL) { CheckValueInputForInt32Op(node, 0); } 476 break; 477 case IrOpcode::kWord32Equal: 478 if (Is32()) { 479 CheckValueInputIsTaggedOrPointer(node, 0); 480 CheckValueInputIsTaggedOrPointer(node, 1); 481 if (!is_stub_) { 482 CheckValueInputRepresentationIs( 483 node, 1, inferrer_->GetRepresentation(node->InputAt(0))); 484 } 485 } else { 486 if (COMPRESS_POINTERS_BOOL) { 487 CheckValueInputIsCompressedOrTaggedOrInt32(node, 0); 488 CheckValueInputIsCompressedOrTaggedOrInt32(node, 1); 489 } else { 490 CheckValueIsTaggedOrInt32(node, 0); 491 CheckValueIsTaggedOrInt32(node, 1); 492 } 493 } 494 break; 495 496 case IrOpcode::kInt32LessThan: 497 case IrOpcode::kInt32LessThanOrEqual: 498 case IrOpcode::kUint32LessThan: 499 case IrOpcode::kUint32LessThanOrEqual: 500 MACHINE_BINOP_32_LIST(LABEL) { 501 CheckValueInputForInt32Op(node, 0); 502 CheckValueInputForInt32Op(node, 1); 503 } 504 break; 505 MACHINE_BINOP_64_LIST(LABEL) { 506 CheckValueInputForInt64Op(node, 0); 507 CheckValueInputForInt64Op(node, 1); 508 } 509 break; 510 case IrOpcode::kFloat32Equal: 511 case IrOpcode::kFloat32LessThan: 512 case IrOpcode::kFloat32LessThanOrEqual: 513 MACHINE_FLOAT32_BINOP_LIST(LABEL) { 514 CheckValueInputForFloat32Op(node, 0); 515 CheckValueInputForFloat32Op(node, 1); 516 } 517 break; 518 case IrOpcode::kChangeFloat32ToFloat64: 519 case IrOpcode::kTruncateFloat32ToInt32: 520 case IrOpcode::kTruncateFloat32ToUint32: 521 case IrOpcode::kBitcastFloat32ToInt32: 522 MACHINE_FLOAT32_UNOP_LIST(LABEL) { 523 CheckValueInputForFloat32Op(node, 0); 524 } 525 break; 526 case IrOpcode::kFloat64Equal: 527 case IrOpcode::kFloat64LessThan: 528 case IrOpcode::kFloat64LessThanOrEqual: 529 MACHINE_FLOAT64_BINOP_LIST(LABEL) { 530 CheckValueInputForFloat64Op(node, 0); 531 CheckValueInputForFloat64Op(node, 1); 532 } 533 break; 534 case IrOpcode::kFloat64SilenceNaN: 535 case IrOpcode::kChangeFloat64ToInt64: 536 case IrOpcode::kChangeFloat64ToUint64: 537 MACHINE_FLOAT64_UNOP_LIST(LABEL) { 538 CheckValueInputForFloat64Op(node, 0); 539 } 540 break; 541#undef LABEL 542 case IrOpcode::kFloat64InsertLowWord32: 543 case IrOpcode::kFloat64InsertHighWord32: 544 CheckValueInputForFloat64Op(node, 0); 545 CheckValueInputForInt32Op(node, 1); 546 break; 547 case IrOpcode::kParameter: 548 case IrOpcode::kProjection: 549 break; 550 case IrOpcode::kAbortCSADcheck: 551 CheckValueInputIsTagged(node, 0); 552 break; 553 case IrOpcode::kLoad: 554 case IrOpcode::kUnalignedLoad: 555 case IrOpcode::kLoadImmutable: 556 case IrOpcode::kWord32AtomicLoad: 557 case IrOpcode::kWord32AtomicPairLoad: 558 case IrOpcode::kWord64AtomicLoad: 559 CheckValueInputIsTaggedOrPointer(node, 0); 560 CheckValueInputRepresentationIs( 561 node, 1, MachineType::PointerRepresentation()); 562 break; 563 case IrOpcode::kWord32AtomicPairAdd: 564 case IrOpcode::kWord32AtomicPairSub: 565 case IrOpcode::kWord32AtomicPairAnd: 566 case IrOpcode::kWord32AtomicPairOr: 567 case IrOpcode::kWord32AtomicPairXor: 568 case IrOpcode::kWord32AtomicPairStore: 569 case IrOpcode::kWord32AtomicPairExchange: 570 CheckValueInputRepresentationIs(node, 3, 571 MachineRepresentation::kWord32); 572 V8_FALLTHROUGH; 573 case IrOpcode::kStore: 574 case IrOpcode::kUnalignedStore: 575 case IrOpcode::kWord32AtomicStore: 576 case IrOpcode::kWord32AtomicExchange: 577 case IrOpcode::kWord32AtomicAdd: 578 case IrOpcode::kWord32AtomicSub: 579 case IrOpcode::kWord32AtomicAnd: 580 case IrOpcode::kWord32AtomicOr: 581 case IrOpcode::kWord32AtomicXor: 582 case IrOpcode::kWord64AtomicStore: 583 case IrOpcode::kWord64AtomicExchange: 584 case IrOpcode::kWord64AtomicAdd: 585 case IrOpcode::kWord64AtomicSub: 586 case IrOpcode::kWord64AtomicAnd: 587 case IrOpcode::kWord64AtomicOr: 588 case IrOpcode::kWord64AtomicXor: 589 CheckValueInputIsTaggedOrPointer(node, 0); 590 CheckValueInputRepresentationIs( 591 node, 1, MachineType::PointerRepresentation()); 592 switch (inferrer_->GetRepresentation(node)) { 593 case MachineRepresentation::kTagged: 594 case MachineRepresentation::kTaggedPointer: 595 case MachineRepresentation::kTaggedSigned: 596 if (COMPRESS_POINTERS_BOOL && 597 ((node->opcode() == IrOpcode::kStore && 598 IsAnyTagged(StoreRepresentationOf(node->op()) 599 .representation())) || 600 (node->opcode() == IrOpcode::kWord32AtomicStore && 601 IsAnyTagged(AtomicStoreParametersOf(node->op()) 602 .representation())))) { 603 CheckValueInputIsCompressedOrTagged(node, 2); 604 } else { 605 CheckValueInputIsTagged(node, 2); 606 } 607 break; 608 default: 609 CheckValueInputRepresentationIs( 610 node, 2, inferrer_->GetRepresentation(node)); 611 } 612 break; 613 case IrOpcode::kWord32AtomicPairCompareExchange: 614 CheckValueInputRepresentationIs(node, 4, 615 MachineRepresentation::kWord32); 616 CheckValueInputRepresentationIs(node, 5, 617 MachineRepresentation::kWord32); 618 V8_FALLTHROUGH; 619 case IrOpcode::kWord32AtomicCompareExchange: 620 case IrOpcode::kWord64AtomicCompareExchange: 621 CheckValueInputIsTaggedOrPointer(node, 0); 622 CheckValueInputRepresentationIs( 623 node, 1, MachineType::PointerRepresentation()); 624 switch (inferrer_->GetRepresentation(node)) { 625 case MachineRepresentation::kTagged: 626 case MachineRepresentation::kTaggedPointer: 627 case MachineRepresentation::kTaggedSigned: 628 CheckValueInputIsTagged(node, 2); 629 CheckValueInputIsTagged(node, 3); 630 break; 631 default: 632 CheckValueInputRepresentationIs( 633 node, 2, inferrer_->GetRepresentation(node)); 634 CheckValueInputRepresentationIs( 635 node, 3, inferrer_->GetRepresentation(node)); 636 } 637 break; 638 case IrOpcode::kPhi: 639 switch (inferrer_->GetRepresentation(node)) { 640 case MachineRepresentation::kTagged: 641 case MachineRepresentation::kTaggedPointer: 642 for (int j = 0; j < node->op()->ValueInputCount(); ++j) { 643 CheckValueInputIsTagged(node, j); 644 } 645 break; 646 case MachineRepresentation::kTaggedSigned: 647 for (int j = 0; j < node->op()->ValueInputCount(); ++j) { 648 if (COMPRESS_POINTERS_BOOL) { 649 CheckValueInputIsCompressedOrTagged(node, j); 650 } else { 651 CheckValueInputIsTagged(node, j); 652 } 653 } 654 break; 655 case MachineRepresentation::kCompressed: 656 case MachineRepresentation::kCompressedPointer: 657 for (int j = 0; j < node->op()->ValueInputCount(); ++j) { 658 CheckValueInputIsCompressedOrTagged(node, j); 659 } 660 break; 661 case MachineRepresentation::kWord32: 662 for (int j = 0; j < node->op()->ValueInputCount(); ++j) { 663 CheckValueInputForInt32Op(node, j); 664 } 665 break; 666 default: 667 for (int j = 0; j < node->op()->ValueInputCount(); ++j) { 668 CheckValueInputRepresentationIs( 669 node, j, inferrer_->GetRepresentation(node)); 670 } 671 break; 672 } 673 break; 674 case IrOpcode::kBranch: 675 case IrOpcode::kSwitch: 676 CheckValueInputForInt32Op(node, 0); 677 break; 678 case IrOpcode::kReturn: { 679 // TODO(ishell): enable once the pop count parameter type becomes 680 // MachineType::PointerRepresentation(). Currently it's int32 or 681 // word-size. 682 // CheckValueInputRepresentationIs( 683 // node, 0, MachineType::PointerRepresentation()); // Pop count 684 size_t return_count = inferrer_->call_descriptor()->ReturnCount(); 685 for (size_t j = 0; j < return_count; j++) { 686 MachineType type = inferrer_->call_descriptor()->GetReturnType(j); 687 int input_index = static_cast<int>(j + 1); 688 switch (type.representation()) { 689 case MachineRepresentation::kTagged: 690 case MachineRepresentation::kTaggedPointer: 691 case MachineRepresentation::kTaggedSigned: 692 CheckValueInputIsTagged(node, input_index); 693 break; 694 case MachineRepresentation::kWord32: 695 CheckValueInputForInt32Op(node, input_index); 696 break; 697 default: 698 CheckValueInputRepresentationIs(node, input_index, 699 type.representation()); 700 break; 701 } 702 } 703 break; 704 } 705 case IrOpcode::kStackPointerGreaterThan: 706 CheckValueInputRepresentationIs( 707 node, 0, MachineType::PointerRepresentation()); 708 break; 709 case IrOpcode::kThrow: 710 case IrOpcode::kTypedStateValues: 711 case IrOpcode::kFrameState: 712 case IrOpcode::kStaticAssert: 713 break; 714 default: 715 if (node->op()->ValueInputCount() != 0) { 716 std::stringstream str; 717 str << "Node #" << node->id() << ":" << *node->op() 718 << " in the machine graph is not being checked."; 719 PrintDebugHelp(str, node); 720 FATAL("%s", str.str().c_str()); 721 } 722 break; 723 } 724 } 725 } 726 } 727 728 private: 729 static bool Is32() { 730 return MachineType::PointerRepresentation() == 731 MachineRepresentation::kWord32; 732 } 733 static bool Is64() { 734 return MachineType::PointerRepresentation() == 735 MachineRepresentation::kWord64; 736 } 737 738 void CheckValueInputRepresentationIs(Node const* node, int index, 739 MachineRepresentation representation) { 740 Node const* input = node->InputAt(index); 741 MachineRepresentation input_representation = 742 inferrer_->GetRepresentation(input); 743 if (input_representation != representation) { 744 std::stringstream str; 745 str << "TypeError: node #" << node->id() << ":" << *node->op() 746 << " uses node #" << input->id() << ":" << *input->op() << ":" 747 << input_representation << " which doesn't have a " << representation 748 << " representation."; 749 PrintDebugHelp(str, node); 750 FATAL("%s", str.str().c_str()); 751 } 752 } 753 754 void CheckValueInputIsTagged(Node const* node, int index) { 755 Node const* input = node->InputAt(index); 756 switch (inferrer_->GetRepresentation(input)) { 757 case MachineRepresentation::kTagged: 758 case MachineRepresentation::kTaggedPointer: 759 case MachineRepresentation::kTaggedSigned: 760 return; 761 default: 762 break; 763 } 764 std::ostringstream str; 765 str << "TypeError: node #" << node->id() << ":" << *node->op() 766 << " uses node #" << input->id() << ":" << *input->op() 767 << " which doesn't have a tagged representation."; 768 PrintDebugHelp(str, node); 769 FATAL("%s", str.str().c_str()); 770 } 771 772 void CheckValueInputIsCompressedOrTagged(Node const* node, int index) { 773 Node const* input = node->InputAt(index); 774 switch (inferrer_->GetRepresentation(input)) { 775 case MachineRepresentation::kCompressed: 776 case MachineRepresentation::kCompressedPointer: 777 case MachineRepresentation::kTagged: 778 case MachineRepresentation::kTaggedPointer: 779 case MachineRepresentation::kTaggedSigned: 780 return; 781 default: 782 break; 783 } 784 std::ostringstream str; 785 str << "TypeError: node #" << node->id() << ":" << *node->op() 786 << " uses node #" << input->id() << ":" << *input->op() 787 << " which doesn't have a compressed or tagged representation."; 788 PrintDebugHelp(str, node); 789 FATAL("%s", str.str().c_str()); 790 } 791 792 void CheckValueInputIsCompressedOrTaggedOrInt32(Node const* node, int index) { 793 Node const* input = node->InputAt(index); 794 switch (inferrer_->GetRepresentation(input)) { 795 case MachineRepresentation::kCompressed: 796 case MachineRepresentation::kCompressedPointer: 797 return; 798 case MachineRepresentation::kTagged: 799 case MachineRepresentation::kTaggedPointer: 800 case MachineRepresentation::kTaggedSigned: 801 return; 802 case MachineRepresentation::kBit: 803 case MachineRepresentation::kWord8: 804 case MachineRepresentation::kWord16: 805 case MachineRepresentation::kWord32: 806 return; 807 default: 808 break; 809 } 810 std::ostringstream str; 811 str << "TypeError: node #" << node->id() << ":" << *node->op() 812 << " uses node #" << input->id() << ":" << *input->op() 813 << " which doesn't have a compressed, tagged, or int32 representation."; 814 PrintDebugHelp(str, node); 815 FATAL("%s", str.str().c_str()); 816 } 817 818 void CheckValueInputIsTaggedOrPointer(Node const* node, int index) { 819 Node const* input = node->InputAt(index); 820 switch (inferrer_->GetRepresentation(input)) { 821 case MachineRepresentation::kTagged: 822 case MachineRepresentation::kTaggedPointer: 823 case MachineRepresentation::kTaggedSigned: 824 return; 825 case MachineRepresentation::kBit: 826 case MachineRepresentation::kWord8: 827 case MachineRepresentation::kWord16: 828 case MachineRepresentation::kWord32: 829 if (Is32()) { 830 return; 831 } 832 break; 833 case MachineRepresentation::kWord64: 834 if (Is64()) { 835 return; 836 } 837 break; 838 default: 839 break; 840 } 841 if (inferrer_->GetRepresentation(input) != 842 MachineType::PointerRepresentation()) { 843 std::ostringstream str; 844 str << "TypeError: node #" << node->id() << ":" << *node->op() 845 << " uses node #" << input->id() << ":" << *input->op() 846 << " which doesn't have a tagged or pointer representation."; 847 PrintDebugHelp(str, node); 848 FATAL("%s", str.str().c_str()); 849 } 850 } 851 852 void CheckValueInputForInt32Op(Node const* node, int index) { 853 Node const* input = node->InputAt(index); 854 switch (inferrer_->GetRepresentation(input)) { 855 case MachineRepresentation::kBit: 856 case MachineRepresentation::kWord8: 857 case MachineRepresentation::kWord16: 858 case MachineRepresentation::kWord32: 859 return; 860 case MachineRepresentation::kNone: { 861 std::ostringstream str; 862 str << "TypeError: node #" << input->id() << ":" << *input->op() 863 << " is untyped."; 864 PrintDebugHelp(str, node); 865 FATAL("%s", str.str().c_str()); 866 } 867 default: 868 break; 869 } 870 std::ostringstream str; 871 str << "TypeError: node #" << node->id() << ":" << *node->op() 872 << " uses node #" << input->id() << ":" << *input->op() 873 << " which doesn't have an int32-compatible representation."; 874 PrintDebugHelp(str, node); 875 FATAL("%s", str.str().c_str()); 876 } 877 878 void CheckValueIsTaggedOrInt32(Node const* node, int index) { 879 Node const* input = node->InputAt(index); 880 switch (inferrer_->GetRepresentation(input)) { 881 case MachineRepresentation::kBit: 882 case MachineRepresentation::kWord8: 883 case MachineRepresentation::kWord16: 884 case MachineRepresentation::kWord32: 885 return; 886 case MachineRepresentation::kTagged: 887 case MachineRepresentation::kTaggedPointer: 888 return; 889 default: 890 break; 891 } 892 std::ostringstream str; 893 str << "TypeError: node #" << node->id() << ":" << *node->op() 894 << " uses node #" << input->id() << ":" << *input->op() 895 << " which doesn't have a tagged or int32-compatible " 896 "representation."; 897 PrintDebugHelp(str, node); 898 FATAL("%s", str.str().c_str()); 899 } 900 901 void CheckValueInputForInt64Op(Node const* node, int index) { 902 Node const* input = node->InputAt(index); 903 MachineRepresentation input_representation = 904 inferrer_->GetRepresentation(input); 905 switch (input_representation) { 906 case MachineRepresentation::kWord64: 907 return; 908 case MachineRepresentation::kNone: { 909 std::ostringstream str; 910 str << "TypeError: node #" << input->id() << ":" << *input->op() 911 << " is untyped."; 912 PrintDebugHelp(str, node); 913 FATAL("%s", str.str().c_str()); 914 } 915 916 default: 917 break; 918 } 919 std::ostringstream str; 920 str << "TypeError: node #" << node->id() << ":" << *node->op() 921 << " uses node #" << input->id() << ":" << *input->op() << ":" 922 << input_representation 923 << " which doesn't have a kWord64 representation."; 924 PrintDebugHelp(str, node); 925 FATAL("%s", str.str().c_str()); 926 } 927 928 void CheckValueInputForFloat32Op(Node const* node, int index) { 929 Node const* input = node->InputAt(index); 930 if (MachineRepresentation::kFloat32 == 931 inferrer_->GetRepresentation(input)) { 932 return; 933 } 934 std::ostringstream str; 935 str << "TypeError: node #" << node->id() << ":" << *node->op() 936 << " uses node #" << input->id() << ":" << *input->op() 937 << " which doesn't have a kFloat32 representation."; 938 PrintDebugHelp(str, node); 939 FATAL("%s", str.str().c_str()); 940 } 941 942 void CheckValueInputForFloat64Op(Node const* node, int index) { 943 Node const* input = node->InputAt(index); 944 if (MachineRepresentation::kFloat64 == 945 inferrer_->GetRepresentation(input)) { 946 return; 947 } 948 std::ostringstream str; 949 str << "TypeError: node #" << node->id() << ":" << *node->op() 950 << " uses node #" << input->id() << ":" << *input->op() 951 << " which doesn't have a kFloat64 representation."; 952 PrintDebugHelp(str, node); 953 FATAL("%s", str.str().c_str()); 954 } 955 956 void CheckCallInputs(Node const* node) { 957 auto call_descriptor = CallDescriptorOf(node->op()); 958 std::ostringstream str; 959 bool should_log_error = false; 960 for (size_t i = 0; i < call_descriptor->InputCount(); ++i) { 961 Node const* input = node->InputAt(static_cast<int>(i)); 962 MachineRepresentation const input_type = 963 inferrer_->GetRepresentation(input); 964 MachineRepresentation const expected_input_type = 965 call_descriptor->GetInputType(i).representation(); 966 if (!IsCompatible(expected_input_type, input_type)) { 967 if (!should_log_error) { 968 should_log_error = true; 969 str << "TypeError: node #" << node->id() << ":" << *node->op() 970 << " has wrong type for:" << std::endl; 971 } else { 972 str << std::endl; 973 } 974 str << " * input " << i << " (" << input->id() << ":" << *input->op() 975 << ") has a " << input_type 976 << " representation (expected: " << expected_input_type << ")."; 977 } 978 } 979 if (should_log_error) { 980 PrintDebugHelp(str, node); 981 FATAL("%s", str.str().c_str()); 982 } 983 } 984 985 bool IsCompatible(MachineRepresentation expected, 986 MachineRepresentation actual) { 987 switch (expected) { 988 case MachineRepresentation::kTagged: 989 return IsAnyTagged(actual); 990 case MachineRepresentation::kCompressed: 991 return IsAnyCompressed(actual); 992 case MachineRepresentation::kMapWord: 993 case MachineRepresentation::kTaggedSigned: 994 case MachineRepresentation::kTaggedPointer: 995 // TODO(turbofan): At the moment, the machine graph doesn't contain 996 // reliable information if a node is kTaggedSigned, kTaggedPointer or 997 // kTagged, and often this is context-dependent. We should at least 998 // check for obvious violations: kTaggedSigned where we expect 999 // kTaggedPointer and the other way around, but at the moment, this 1000 // happens in dead code. 1001 return IsAnyTagged(actual); 1002 case MachineRepresentation::kCompressedPointer: 1003 case MachineRepresentation::kSandboxedPointer: 1004 case MachineRepresentation::kFloat32: 1005 case MachineRepresentation::kFloat64: 1006 case MachineRepresentation::kSimd128: 1007 case MachineRepresentation::kBit: 1008 case MachineRepresentation::kWord8: 1009 case MachineRepresentation::kWord16: 1010 case MachineRepresentation::kWord64: 1011 return expected == actual; 1012 case MachineRepresentation::kWord32: 1013 return (actual == MachineRepresentation::kBit || 1014 actual == MachineRepresentation::kWord8 || 1015 actual == MachineRepresentation::kWord16 || 1016 actual == MachineRepresentation::kWord32); 1017 case MachineRepresentation::kNone: 1018 UNREACHABLE(); 1019 } 1020 return false; 1021 } 1022 1023 void PrintDebugHelp(std::ostream& out, Node const* node) { 1024 if (DEBUG_BOOL) { 1025 out << "\n# Current block: " << *current_block_; 1026 out << "\n#\n# Specify option --csa-trap-on-node=" << name_ << "," 1027 << node->id() << " for debugging."; 1028 } 1029 } 1030 1031 Schedule const* const schedule_; 1032 MachineRepresentationInferrer const* const inferrer_; 1033 bool is_stub_; 1034 const char* name_; 1035 BasicBlock* current_block_; 1036}; 1037 1038} // namespace 1039 1040void MachineGraphVerifier::Run(Graph* graph, Schedule const* const schedule, 1041 Linkage* linkage, bool is_stub, const char* name, 1042 Zone* temp_zone) { 1043 MachineRepresentationInferrer representation_inferrer(schedule, graph, 1044 linkage, temp_zone); 1045 MachineRepresentationChecker checker(schedule, &representation_inferrer, 1046 is_stub, name); 1047 checker.Run(); 1048} 1049 1050} // namespace compiler 1051} // namespace internal 1052} // namespace v8 1053