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 
16 namespace v8 {
17 namespace internal {
18 namespace compiler {
19 
20 namespace {
21 
22 class MachineRepresentationInferrer {
23  public:
MachineRepresentationInferrer(Schedule const* schedule, Graph const* graph, Linkage* linkage, Zone* zone)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 
call_descriptor() const33   CallDescriptor* call_descriptor() const {
34     return linkage_->GetIncomingDescriptor();
35   }
36 
GetRepresentation(Node const* node) const37   MachineRepresentation GetRepresentation(Node const* node) const {
38     return representation_vector_.at(node->id());
39   }
40 
41  private:
GetProjectionType(Node const* projection)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 
PromoteRepresentation(MachineRepresentation rep)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 
Run()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 
347 class MachineRepresentationChecker {
348  public:
MachineRepresentationChecker( Schedule const* const schedule, MachineRepresentationInferrer const* const inferrer, bool is_stub, const char* name)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 
Run()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:
Is32()729   static bool Is32() {
730     return MachineType::PointerRepresentation() ==
731            MachineRepresentation::kWord32;
732   }
Is64()733   static bool Is64() {
734     return MachineType::PointerRepresentation() ==
735            MachineRepresentation::kWord64;
736   }
737 
CheckValueInputRepresentationIs(Node const* node, int index, MachineRepresentation representation)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 
CheckValueInputIsTagged(Node const* node, int index)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 
CheckValueInputIsCompressedOrTagged(Node const* node, int index)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 
CheckValueInputIsCompressedOrTaggedOrInt32(Node const* node, int index)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 
CheckValueInputIsTaggedOrPointer(Node const* node, int index)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 
CheckValueInputForInt32Op(Node const* node, int index)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 
CheckValueIsTaggedOrInt32(Node const* node, int index)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 
CheckValueInputForInt64Op(Node const* node, int index)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 
CheckValueInputForFloat32Op(Node const* node, int index)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 
CheckValueInputForFloat64Op(Node const* node, int index)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 
CheckCallInputs(Node const* node)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 
IsCompatible(MachineRepresentation expected, MachineRepresentation actual)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 
PrintDebugHelp(std::ostream& out, Node const* node)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 
Run(Graph* graph, Schedule const* const schedule, Linkage* linkage, bool is_stub, const char* name, Zone* temp_zone)1040 void 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