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