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       case IrOpcode::kCallWithCallerSavedRegisters: {
65         auto call_descriptor = CallDescriptorOf(input->op());
66         return call_descriptor->GetReturnType(index).representation();
67       }
68       default:
69         return MachineRepresentation::kNone;
70     }
71   }
72 
PromoteRepresentation(MachineRepresentation rep)73   MachineRepresentation PromoteRepresentation(MachineRepresentation rep) {
74     switch (rep) {
75       case MachineRepresentation::kWord8:
76       case MachineRepresentation::kWord16:
77       case MachineRepresentation::kWord32:
78         return MachineRepresentation::kWord32;
79       default:
80         break;
81     }
82     return rep;
83   }
84 
Run()85   void Run() {
86     auto blocks = schedule_->all_blocks();
87     for (BasicBlock* block : *blocks) {
88       current_block_ = block;
89       for (size_t i = 0; i <= block->NodeCount(); ++i) {
90         Node const* node =
91             i < block->NodeCount() ? block->NodeAt(i) : block->control_input();
92         if (node == nullptr) {
93           DCHECK_EQ(block->NodeCount(), i);
94           break;
95         }
96         switch (node->opcode()) {
97           case IrOpcode::kParameter:
98             representation_vector_[node->id()] =
99                 linkage_->GetParameterType(ParameterIndexOf(node->op()))
100                     .representation();
101             break;
102           case IrOpcode::kReturn: {
103             representation_vector_[node->id()] = PromoteRepresentation(
104                 linkage_->GetReturnType().representation());
105             break;
106           }
107           case IrOpcode::kProjection: {
108             representation_vector_[node->id()] = GetProjectionType(node);
109           } break;
110           case IrOpcode::kTypedStateValues:
111             representation_vector_[node->id()] = MachineRepresentation::kNone;
112             break;
113           case IrOpcode::kWord32AtomicLoad:
114           case IrOpcode::kLoad:
115           case IrOpcode::kProtectedLoad:
116           case IrOpcode::kPoisonedLoad:
117             representation_vector_[node->id()] = PromoteRepresentation(
118                 LoadRepresentationOf(node->op()).representation());
119             break;
120           case IrOpcode::kLoadStackPointer:
121           case IrOpcode::kLoadFramePointer:
122           case IrOpcode::kLoadParentFramePointer:
123             representation_vector_[node->id()] =
124                 MachineType::PointerRepresentation();
125             break;
126           case IrOpcode::kUnalignedLoad:
127             representation_vector_[node->id()] = PromoteRepresentation(
128                 LoadRepresentationOf(node->op()).representation());
129             break;
130           case IrOpcode::kPhi:
131             representation_vector_[node->id()] =
132                 PhiRepresentationOf(node->op());
133             break;
134           case IrOpcode::kCall:
135           case IrOpcode::kCallWithCallerSavedRegisters: {
136             auto call_descriptor = CallDescriptorOf(node->op());
137             if (call_descriptor->ReturnCount() > 0) {
138               representation_vector_[node->id()] =
139                   call_descriptor->GetReturnType(0).representation();
140             } else {
141               representation_vector_[node->id()] =
142                   MachineRepresentation::kTagged;
143             }
144             break;
145           }
146           case IrOpcode::kWord32AtomicStore:
147             representation_vector_[node->id()] =
148                 PromoteRepresentation(AtomicStoreRepresentationOf(node->op()));
149             break;
150           case IrOpcode::kWord32AtomicExchange:
151           case IrOpcode::kWord32AtomicCompareExchange:
152           case IrOpcode::kWord32AtomicAdd:
153           case IrOpcode::kWord32AtomicSub:
154           case IrOpcode::kWord32AtomicAnd:
155           case IrOpcode::kWord32AtomicOr:
156           case IrOpcode::kWord32AtomicXor:
157             representation_vector_[node->id()] = PromoteRepresentation(
158                 AtomicOpType(node->op()).representation());
159             break;
160           case IrOpcode::kStore:
161           case IrOpcode::kProtectedStore:
162             representation_vector_[node->id()] = PromoteRepresentation(
163                 StoreRepresentationOf(node->op()).representation());
164             break;
165           case IrOpcode::kUnalignedStore:
166             representation_vector_[node->id()] = PromoteRepresentation(
167                 UnalignedStoreRepresentationOf(node->op()));
168             break;
169           case IrOpcode::kHeapConstant:
170           case IrOpcode::kNumberConstant:
171           case IrOpcode::kChangeBitToTagged:
172           case IrOpcode::kIfException:
173           case IrOpcode::kOsrValue:
174           case IrOpcode::kChangeInt32ToTagged:
175           case IrOpcode::kChangeUint32ToTagged:
176           case IrOpcode::kBitcastWordToTagged:
177           case IrOpcode::kTaggedPoisonOnSpeculation:
178             representation_vector_[node->id()] = MachineRepresentation::kTagged;
179             break;
180           case IrOpcode::kWord32PoisonOnSpeculation:
181             representation_vector_[node->id()] = MachineRepresentation::kWord32;
182             break;
183           case IrOpcode::kWord64PoisonOnSpeculation:
184             representation_vector_[node->id()] = MachineRepresentation::kWord64;
185             break;
186           case IrOpcode::kExternalConstant:
187             representation_vector_[node->id()] =
188                 MachineType::PointerRepresentation();
189             break;
190           case IrOpcode::kBitcastTaggedToWord:
191             representation_vector_[node->id()] =
192                 MachineType::PointerRepresentation();
193             break;
194           case IrOpcode::kBitcastWordToTaggedSigned:
195             representation_vector_[node->id()] =
196                 MachineRepresentation::kTaggedSigned;
197             break;
198           case IrOpcode::kWord32Equal:
199           case IrOpcode::kInt32LessThan:
200           case IrOpcode::kInt32LessThanOrEqual:
201           case IrOpcode::kUint32LessThan:
202           case IrOpcode::kUint32LessThanOrEqual:
203           case IrOpcode::kWord64Equal:
204           case IrOpcode::kInt64LessThan:
205           case IrOpcode::kInt64LessThanOrEqual:
206           case IrOpcode::kUint64LessThan:
207           case IrOpcode::kUint64LessThanOrEqual:
208           case IrOpcode::kFloat32Equal:
209           case IrOpcode::kFloat32LessThan:
210           case IrOpcode::kFloat32LessThanOrEqual:
211           case IrOpcode::kFloat64Equal:
212           case IrOpcode::kFloat64LessThan:
213           case IrOpcode::kFloat64LessThanOrEqual:
214           case IrOpcode::kChangeTaggedToBit:
215             representation_vector_[node->id()] = MachineRepresentation::kBit;
216             break;
217 #define LABEL(opcode) case IrOpcode::k##opcode:
218           case IrOpcode::kTruncateInt64ToInt32:
219           case IrOpcode::kTruncateFloat32ToInt32:
220           case IrOpcode::kTruncateFloat32ToUint32:
221           case IrOpcode::kBitcastFloat32ToInt32:
222           case IrOpcode::kI32x4ExtractLane:
223           case IrOpcode::kI16x8ExtractLane:
224           case IrOpcode::kI8x16ExtractLane:
225           case IrOpcode::kInt32Constant:
226           case IrOpcode::kRelocatableInt32Constant:
227           case IrOpcode::kTruncateFloat64ToWord32:
228           case IrOpcode::kTruncateFloat64ToUint32:
229           case IrOpcode::kChangeFloat64ToInt32:
230           case IrOpcode::kChangeFloat64ToUint32:
231           case IrOpcode::kRoundFloat64ToInt32:
232           case IrOpcode::kFloat64ExtractLowWord32:
233           case IrOpcode::kFloat64ExtractHighWord32:
234             MACHINE_UNOP_32_LIST(LABEL)
235             MACHINE_BINOP_32_LIST(LABEL) {
236               representation_vector_[node->id()] =
237                   MachineRepresentation::kWord32;
238             }
239             break;
240           case IrOpcode::kChangeInt32ToInt64:
241           case IrOpcode::kChangeUint32ToUint64:
242           case IrOpcode::kInt64Constant:
243           case IrOpcode::kRelocatableInt64Constant:
244           case IrOpcode::kBitcastFloat64ToInt64:
245           case IrOpcode::kChangeFloat64ToUint64:
246             MACHINE_BINOP_64_LIST(LABEL) {
247               representation_vector_[node->id()] =
248                   MachineRepresentation::kWord64;
249             }
250             break;
251           case IrOpcode::kRoundInt32ToFloat32:
252           case IrOpcode::kRoundUint32ToFloat32:
253           case IrOpcode::kRoundInt64ToFloat32:
254           case IrOpcode::kRoundUint64ToFloat32:
255           case IrOpcode::kBitcastInt32ToFloat32:
256           case IrOpcode::kFloat32Constant:
257           case IrOpcode::kTruncateFloat64ToFloat32:
258             MACHINE_FLOAT32_BINOP_LIST(LABEL)
259             MACHINE_FLOAT32_UNOP_LIST(LABEL) {
260               representation_vector_[node->id()] =
261                   MachineRepresentation::kFloat32;
262             }
263             break;
264           case IrOpcode::kRoundInt64ToFloat64:
265           case IrOpcode::kRoundUint64ToFloat64:
266           case IrOpcode::kChangeFloat32ToFloat64:
267           case IrOpcode::kChangeInt32ToFloat64:
268           case IrOpcode::kChangeUint32ToFloat64:
269           case IrOpcode::kFloat64InsertLowWord32:
270           case IrOpcode::kFloat64InsertHighWord32:
271           case IrOpcode::kFloat64Constant:
272           case IrOpcode::kFloat64SilenceNaN:
273             MACHINE_FLOAT64_BINOP_LIST(LABEL)
274             MACHINE_FLOAT64_UNOP_LIST(LABEL) {
275               representation_vector_[node->id()] =
276                   MachineRepresentation::kFloat64;
277             }
278             break;
279           case IrOpcode::kI32x4ReplaceLane:
280           case IrOpcode::kI32x4Splat:
281             representation_vector_[node->id()] =
282                 MachineRepresentation::kSimd128;
283             break;
284 #undef LABEL
285           default:
286             break;
287         }
288       }
289     }
290   }
291 
292   Schedule const* const schedule_;
293   Linkage const* const linkage_;
294   ZoneVector<MachineRepresentation> representation_vector_;
295   BasicBlock* current_block_;
296 };
297 
298 class MachineRepresentationChecker {
299  public:
MachineRepresentationChecker(Schedule const * const schedule,MachineRepresentationInferrer const * const inferrer,bool is_stub,const char * name)300   MachineRepresentationChecker(
301       Schedule const* const schedule,
302       MachineRepresentationInferrer const* const inferrer, bool is_stub,
303       const char* name)
304       : schedule_(schedule),
305         inferrer_(inferrer),
306         is_stub_(is_stub),
307         name_(name),
308         current_block_(nullptr) {}
309 
Run()310   void Run() {
311     BasicBlockVector const* blocks = schedule_->all_blocks();
312     for (BasicBlock* block : *blocks) {
313       current_block_ = block;
314       for (size_t i = 0; i <= block->NodeCount(); ++i) {
315         Node const* node =
316             i < block->NodeCount() ? block->NodeAt(i) : block->control_input();
317         if (node == nullptr) {
318           DCHECK_EQ(block->NodeCount(), i);
319           break;
320         }
321         switch (node->opcode()) {
322           case IrOpcode::kCall:
323           case IrOpcode::kCallWithCallerSavedRegisters:
324           case IrOpcode::kTailCall:
325             CheckCallInputs(node);
326             break;
327           case IrOpcode::kChangeBitToTagged:
328             CHECK_EQ(MachineRepresentation::kBit,
329                      inferrer_->GetRepresentation(node->InputAt(0)));
330             break;
331           case IrOpcode::kChangeTaggedToBit:
332             CHECK_EQ(MachineRepresentation::kTagged,
333                      inferrer_->GetRepresentation(node->InputAt(0)));
334             break;
335           case IrOpcode::kRoundInt64ToFloat64:
336           case IrOpcode::kRoundUint64ToFloat64:
337           case IrOpcode::kRoundInt64ToFloat32:
338           case IrOpcode::kRoundUint64ToFloat32:
339           case IrOpcode::kTruncateInt64ToInt32:
340             CheckValueInputForInt64Op(node, 0);
341             break;
342           case IrOpcode::kBitcastWordToTagged:
343           case IrOpcode::kBitcastWordToTaggedSigned:
344             CheckValueInputRepresentationIs(
345                 node, 0, MachineType::PointerRepresentation());
346             break;
347           case IrOpcode::kWord32PoisonOnSpeculation:
348             CheckValueInputRepresentationIs(node, 0,
349                                             MachineRepresentation::kWord32);
350             break;
351           case IrOpcode::kWord64PoisonOnSpeculation:
352             CheckValueInputRepresentationIs(node, 0,
353                                             MachineRepresentation::kWord64);
354             break;
355           case IrOpcode::kBitcastTaggedToWord:
356           case IrOpcode::kTaggedPoisonOnSpeculation:
357             CheckValueInputIsTagged(node, 0);
358             break;
359           case IrOpcode::kTruncateFloat64ToWord32:
360           case IrOpcode::kTruncateFloat64ToUint32:
361           case IrOpcode::kTruncateFloat64ToFloat32:
362           case IrOpcode::kChangeFloat64ToInt32:
363           case IrOpcode::kChangeFloat64ToUint32:
364           case IrOpcode::kRoundFloat64ToInt32:
365           case IrOpcode::kFloat64ExtractLowWord32:
366           case IrOpcode::kFloat64ExtractHighWord32:
367           case IrOpcode::kBitcastFloat64ToInt64:
368           case IrOpcode::kTryTruncateFloat64ToInt64:
369             CheckValueInputForFloat64Op(node, 0);
370             break;
371           case IrOpcode::kWord64Equal:
372             if (Is64()) {
373               CheckValueInputIsTaggedOrPointer(node, 0);
374               CheckValueInputIsTaggedOrPointer(node, 1);
375               if (!is_stub_) {
376                 CheckValueInputRepresentationIs(
377                     node, 1, inferrer_->GetRepresentation(node->InputAt(0)));
378               }
379             } else {
380               CheckValueInputForInt64Op(node, 0);
381               CheckValueInputForInt64Op(node, 1);
382             }
383             break;
384           case IrOpcode::kInt64LessThan:
385           case IrOpcode::kInt64LessThanOrEqual:
386           case IrOpcode::kUint64LessThan:
387           case IrOpcode::kUint64LessThanOrEqual:
388             CheckValueInputForInt64Op(node, 0);
389             CheckValueInputForInt64Op(node, 1);
390             break;
391           case IrOpcode::kI32x4ExtractLane:
392           case IrOpcode::kI16x8ExtractLane:
393           case IrOpcode::kI8x16ExtractLane:
394             CheckValueInputRepresentationIs(node, 0,
395                                             MachineRepresentation::kSimd128);
396             break;
397           case IrOpcode::kI32x4ReplaceLane:
398             CheckValueInputRepresentationIs(node, 0,
399                                             MachineRepresentation::kSimd128);
400             CheckValueInputForInt32Op(node, 1);
401             break;
402           case IrOpcode::kI32x4Splat:
403             CheckValueInputForInt32Op(node, 0);
404             break;
405 #define LABEL(opcode) case IrOpcode::k##opcode:
406           case IrOpcode::kChangeInt32ToTagged:
407           case IrOpcode::kChangeUint32ToTagged:
408           case IrOpcode::kChangeInt32ToFloat64:
409           case IrOpcode::kChangeUint32ToFloat64:
410           case IrOpcode::kRoundInt32ToFloat32:
411           case IrOpcode::kRoundUint32ToFloat32:
412           case IrOpcode::kBitcastInt32ToFloat32:
413           case IrOpcode::kChangeInt32ToInt64:
414           case IrOpcode::kChangeUint32ToUint64:
415             MACHINE_UNOP_32_LIST(LABEL) { CheckValueInputForInt32Op(node, 0); }
416             break;
417           case IrOpcode::kWord32Equal:
418             if (Is32()) {
419               CheckValueInputIsTaggedOrPointer(node, 0);
420               CheckValueInputIsTaggedOrPointer(node, 1);
421               if (!is_stub_) {
422                 CheckValueInputRepresentationIs(
423                     node, 1, inferrer_->GetRepresentation(node->InputAt(0)));
424               }
425             } else {
426               CheckValueInputForInt32Op(node, 0);
427               CheckValueInputForInt32Op(node, 1);
428             }
429             break;
430 
431           case IrOpcode::kInt32LessThan:
432           case IrOpcode::kInt32LessThanOrEqual:
433           case IrOpcode::kUint32LessThan:
434           case IrOpcode::kUint32LessThanOrEqual:
435             MACHINE_BINOP_32_LIST(LABEL) {
436               CheckValueInputForInt32Op(node, 0);
437               CheckValueInputForInt32Op(node, 1);
438             }
439             break;
440             MACHINE_BINOP_64_LIST(LABEL) {
441               CheckValueInputForInt64Op(node, 0);
442               CheckValueInputForInt64Op(node, 1);
443             }
444             break;
445           case IrOpcode::kFloat32Equal:
446           case IrOpcode::kFloat32LessThan:
447           case IrOpcode::kFloat32LessThanOrEqual:
448             MACHINE_FLOAT32_BINOP_LIST(LABEL) {
449               CheckValueInputForFloat32Op(node, 0);
450               CheckValueInputForFloat32Op(node, 1);
451             }
452             break;
453           case IrOpcode::kChangeFloat32ToFloat64:
454           case IrOpcode::kTruncateFloat32ToInt32:
455           case IrOpcode::kTruncateFloat32ToUint32:
456           case IrOpcode::kBitcastFloat32ToInt32:
457             MACHINE_FLOAT32_UNOP_LIST(LABEL) {
458               CheckValueInputForFloat32Op(node, 0);
459             }
460             break;
461           case IrOpcode::kFloat64Equal:
462           case IrOpcode::kFloat64LessThan:
463           case IrOpcode::kFloat64LessThanOrEqual:
464             MACHINE_FLOAT64_BINOP_LIST(LABEL) {
465               CheckValueInputForFloat64Op(node, 0);
466               CheckValueInputForFloat64Op(node, 1);
467             }
468             break;
469           case IrOpcode::kFloat64SilenceNaN:
470           case IrOpcode::kChangeFloat64ToUint64:
471             MACHINE_FLOAT64_UNOP_LIST(LABEL) {
472               CheckValueInputForFloat64Op(node, 0);
473             }
474             break;
475 #undef LABEL
476           case IrOpcode::kFloat64InsertLowWord32:
477           case IrOpcode::kFloat64InsertHighWord32:
478             CheckValueInputForFloat64Op(node, 0);
479             CheckValueInputForInt32Op(node, 1);
480             break;
481           case IrOpcode::kParameter:
482           case IrOpcode::kProjection:
483             break;
484           case IrOpcode::kDebugAbort:
485             CheckValueInputIsTagged(node, 0);
486             break;
487           case IrOpcode::kLoad:
488           case IrOpcode::kWord32AtomicLoad:
489           case IrOpcode::kPoisonedLoad:
490             CheckValueInputIsTaggedOrPointer(node, 0);
491             CheckValueInputRepresentationIs(
492                 node, 1, MachineType::PointerRepresentation());
493             break;
494           case IrOpcode::kStore:
495           case IrOpcode::kWord32AtomicStore:
496           case IrOpcode::kWord32AtomicExchange:
497           case IrOpcode::kWord32AtomicAdd:
498           case IrOpcode::kWord32AtomicSub:
499           case IrOpcode::kWord32AtomicAnd:
500           case IrOpcode::kWord32AtomicOr:
501           case IrOpcode::kWord32AtomicXor:
502             CheckValueInputIsTaggedOrPointer(node, 0);
503             CheckValueInputRepresentationIs(
504                 node, 1, MachineType::PointerRepresentation());
505             switch (inferrer_->GetRepresentation(node)) {
506               case MachineRepresentation::kTagged:
507               case MachineRepresentation::kTaggedPointer:
508               case MachineRepresentation::kTaggedSigned:
509                 CheckValueInputIsTagged(node, 2);
510                 break;
511               default:
512                 CheckValueInputRepresentationIs(
513                     node, 2, inferrer_->GetRepresentation(node));
514             }
515             break;
516           case IrOpcode::kWord32AtomicCompareExchange:
517             CheckValueInputIsTaggedOrPointer(node, 0);
518             CheckValueInputRepresentationIs(
519                 node, 1, MachineType::PointerRepresentation());
520             switch (inferrer_->GetRepresentation(node)) {
521               case MachineRepresentation::kTagged:
522               case MachineRepresentation::kTaggedPointer:
523               case MachineRepresentation::kTaggedSigned:
524                 CheckValueInputIsTagged(node, 2);
525                 CheckValueInputIsTagged(node, 3);
526                 break;
527               default:
528                 CheckValueInputRepresentationIs(
529                     node, 2, inferrer_->GetRepresentation(node));
530                 CheckValueInputRepresentationIs(
531                     node, 3, inferrer_->GetRepresentation(node));
532             }
533             break;
534           case IrOpcode::kPhi:
535             switch (inferrer_->GetRepresentation(node)) {
536               case MachineRepresentation::kTagged:
537               case MachineRepresentation::kTaggedPointer:
538               case MachineRepresentation::kTaggedSigned:
539                 for (int i = 0; i < node->op()->ValueInputCount(); ++i) {
540                   CheckValueInputIsTagged(node, i);
541                 }
542                 break;
543               case MachineRepresentation::kWord32:
544                 for (int i = 0; i < node->op()->ValueInputCount(); ++i) {
545                   CheckValueInputForInt32Op(node, i);
546                 }
547                 break;
548               default:
549                 for (int i = 0; i < node->op()->ValueInputCount(); ++i) {
550                   CheckValueInputRepresentationIs(
551                       node, i, inferrer_->GetRepresentation(node));
552                 }
553                 break;
554             }
555             break;
556           case IrOpcode::kBranch:
557           case IrOpcode::kSwitch:
558             CheckValueInputForInt32Op(node, 0);
559             break;
560           case IrOpcode::kReturn: {
561             // TODO(ishell): enable once the pop count parameter type becomes
562             // MachineType::PointerRepresentation(). Currently it's int32 or
563             // word-size.
564             // CheckValueInputRepresentationIs(
565             //     node, 0, MachineType::PointerRepresentation());  // Pop count
566             size_t return_count = inferrer_->call_descriptor()->ReturnCount();
567             for (size_t i = 0; i < return_count; i++) {
568               MachineType type = inferrer_->call_descriptor()->GetReturnType(i);
569               int input_index = static_cast<int>(i + 1);
570               switch (type.representation()) {
571                 case MachineRepresentation::kTagged:
572                 case MachineRepresentation::kTaggedPointer:
573                 case MachineRepresentation::kTaggedSigned:
574                   CheckValueInputIsTagged(node, input_index);
575                   break;
576                 case MachineRepresentation::kWord32:
577                   CheckValueInputForInt32Op(node, input_index);
578                   break;
579                 default:
580                   CheckValueInputRepresentationIs(node, input_index,
581                                                   type.representation());
582                   break;
583               }
584             }
585             break;
586           }
587           case IrOpcode::kThrow:
588           case IrOpcode::kTypedStateValues:
589           case IrOpcode::kFrameState:
590             break;
591           default:
592             if (node->op()->ValueInputCount() != 0) {
593               std::stringstream str;
594               str << "Node #" << node->id() << ":" << *node->op()
595                   << " in the machine graph is not being checked.";
596               PrintDebugHelp(str, node);
597               FATAL("%s", str.str().c_str());
598             }
599             break;
600         }
601       }
602     }
603   }
604 
605  private:
Is32()606   static bool Is32() {
607     return MachineType::PointerRepresentation() ==
608            MachineRepresentation::kWord32;
609   }
Is64()610   static bool Is64() {
611     return MachineType::PointerRepresentation() ==
612            MachineRepresentation::kWord64;
613   }
614 
CheckValueInputRepresentationIs(Node const * node,int index,MachineRepresentation representation)615   void CheckValueInputRepresentationIs(Node const* node, int index,
616                                        MachineRepresentation representation) {
617     Node const* input = node->InputAt(index);
618     MachineRepresentation input_representation =
619         inferrer_->GetRepresentation(input);
620     if (input_representation != representation) {
621       std::stringstream str;
622       str << "TypeError: node #" << node->id() << ":" << *node->op()
623           << " uses node #" << input->id() << ":" << *input->op() << ":"
624           << input_representation << " which doesn't have a " << representation
625           << " representation.";
626       PrintDebugHelp(str, node);
627       FATAL("%s", str.str().c_str());
628     }
629   }
630 
CheckValueInputIsTagged(Node const * node,int index)631   void CheckValueInputIsTagged(Node const* node, int index) {
632     Node const* input = node->InputAt(index);
633     switch (inferrer_->GetRepresentation(input)) {
634       case MachineRepresentation::kTagged:
635       case MachineRepresentation::kTaggedPointer:
636       case MachineRepresentation::kTaggedSigned:
637         return;
638       default:
639         break;
640     }
641     std::ostringstream str;
642     str << "TypeError: node #" << node->id() << ":" << *node->op()
643         << " uses node #" << input->id() << ":" << *input->op()
644         << " which doesn't have a tagged representation.";
645     PrintDebugHelp(str, node);
646     FATAL("%s", str.str().c_str());
647   }
648 
CheckValueInputIsTaggedOrPointer(Node const * node,int index)649   void CheckValueInputIsTaggedOrPointer(Node const* node, int index) {
650     Node const* input = node->InputAt(index);
651     switch (inferrer_->GetRepresentation(input)) {
652       case MachineRepresentation::kTagged:
653       case MachineRepresentation::kTaggedPointer:
654       case MachineRepresentation::kTaggedSigned:
655         return;
656       case MachineRepresentation::kBit:
657       case MachineRepresentation::kWord8:
658       case MachineRepresentation::kWord16:
659       case MachineRepresentation::kWord32:
660         if (Is32()) {
661           return;
662         }
663         break;
664       case MachineRepresentation::kWord64:
665         if (Is64()) {
666           return;
667         }
668         break;
669       default:
670         break;
671     }
672     if (inferrer_->GetRepresentation(input) !=
673         MachineType::PointerRepresentation()) {
674       std::ostringstream str;
675       str << "TypeError: node #" << node->id() << ":" << *node->op()
676           << " uses node #" << input->id() << ":" << *input->op()
677           << " which doesn't have a tagged or pointer representation.";
678       PrintDebugHelp(str, node);
679       FATAL("%s", str.str().c_str());
680     }
681   }
682 
CheckValueInputForInt32Op(Node const * node,int index)683   void CheckValueInputForInt32Op(Node const* node, int index) {
684     Node const* input = node->InputAt(index);
685     switch (inferrer_->GetRepresentation(input)) {
686       case MachineRepresentation::kBit:
687       case MachineRepresentation::kWord8:
688       case MachineRepresentation::kWord16:
689       case MachineRepresentation::kWord32:
690         return;
691       case MachineRepresentation::kNone: {
692         std::ostringstream str;
693         str << "TypeError: node #" << input->id() << ":" << *input->op()
694             << " is untyped.";
695         PrintDebugHelp(str, node);
696         FATAL("%s", str.str().c_str());
697         break;
698       }
699       default:
700         break;
701     }
702     std::ostringstream str;
703     str << "TypeError: node #" << node->id() << ":" << *node->op()
704         << " uses node #" << input->id() << ":" << *input->op()
705         << " which doesn't have an int32-compatible representation.";
706     PrintDebugHelp(str, node);
707     FATAL("%s", str.str().c_str());
708   }
709 
CheckValueInputForInt64Op(Node const * node,int index)710   void CheckValueInputForInt64Op(Node const* node, int index) {
711     Node const* input = node->InputAt(index);
712     MachineRepresentation input_representation =
713         inferrer_->GetRepresentation(input);
714     switch (input_representation) {
715       case MachineRepresentation::kWord64:
716         return;
717       case MachineRepresentation::kNone: {
718         std::ostringstream str;
719         str << "TypeError: node #" << input->id() << ":" << *input->op()
720             << " is untyped.";
721         PrintDebugHelp(str, node);
722         FATAL("%s", str.str().c_str());
723         break;
724       }
725 
726       default:
727         break;
728     }
729     std::ostringstream str;
730     str << "TypeError: node #" << node->id() << ":" << *node->op()
731         << " uses node #" << input->id() << ":" << *input->op() << ":"
732         << input_representation
733         << " which doesn't have a kWord64 representation.";
734     PrintDebugHelp(str, node);
735     FATAL("%s", str.str().c_str());
736   }
737 
CheckValueInputForFloat32Op(Node const * node,int index)738   void CheckValueInputForFloat32Op(Node const* node, int index) {
739     Node const* input = node->InputAt(index);
740     if (MachineRepresentation::kFloat32 ==
741         inferrer_->GetRepresentation(input)) {
742       return;
743     }
744     std::ostringstream str;
745     str << "TypeError: node #" << node->id() << ":" << *node->op()
746         << " uses node #" << input->id() << ":" << *input->op()
747         << " which doesn't have a kFloat32 representation.";
748     PrintDebugHelp(str, node);
749     FATAL("%s", str.str().c_str());
750   }
751 
CheckValueInputForFloat64Op(Node const * node,int index)752   void CheckValueInputForFloat64Op(Node const* node, int index) {
753     Node const* input = node->InputAt(index);
754     if (MachineRepresentation::kFloat64 ==
755         inferrer_->GetRepresentation(input)) {
756       return;
757     }
758     std::ostringstream str;
759     str << "TypeError: node #" << node->id() << ":" << *node->op()
760         << " uses node #" << input->id() << ":" << *input->op()
761         << " which doesn't have a kFloat64 representation.";
762     PrintDebugHelp(str, node);
763     FATAL("%s", str.str().c_str());
764   }
765 
CheckCallInputs(Node const * node)766   void CheckCallInputs(Node const* node) {
767     auto call_descriptor = CallDescriptorOf(node->op());
768     std::ostringstream str;
769     bool should_log_error = false;
770     for (size_t i = 0; i < call_descriptor->InputCount(); ++i) {
771       Node const* input = node->InputAt(static_cast<int>(i));
772       MachineRepresentation const input_type =
773           inferrer_->GetRepresentation(input);
774       MachineRepresentation const expected_input_type =
775           call_descriptor->GetInputType(i).representation();
776       if (!IsCompatible(expected_input_type, input_type)) {
777         if (!should_log_error) {
778           should_log_error = true;
779           str << "TypeError: node #" << node->id() << ":" << *node->op()
780               << " has wrong type for:" << std::endl;
781         } else {
782           str << std::endl;
783         }
784         str << " * input " << i << " (" << input->id() << ":" << *input->op()
785             << ") has a " << input_type
786             << " representation (expected: " << expected_input_type << ").";
787       }
788     }
789     if (should_log_error) {
790       PrintDebugHelp(str, node);
791       FATAL("%s", str.str().c_str());
792     }
793   }
794 
Intersect(MachineRepresentation lhs,MachineRepresentation rhs)795   bool Intersect(MachineRepresentation lhs, MachineRepresentation rhs) {
796     return (GetRepresentationProperties(lhs) &
797             GetRepresentationProperties(rhs)) != 0;
798   }
799 
800   enum RepresentationProperties { kIsPointer = 1, kIsTagged = 2 };
801 
GetRepresentationProperties(MachineRepresentation representation)802   int GetRepresentationProperties(MachineRepresentation representation) {
803     switch (representation) {
804       case MachineRepresentation::kTagged:
805       case MachineRepresentation::kTaggedPointer:
806         return kIsPointer | kIsTagged;
807       case MachineRepresentation::kTaggedSigned:
808         return kIsTagged;
809       case MachineRepresentation::kWord32:
810         return MachineRepresentation::kWord32 ==
811                        MachineType::PointerRepresentation()
812                    ? kIsPointer
813                    : 0;
814       case MachineRepresentation::kWord64:
815         return MachineRepresentation::kWord64 ==
816                        MachineType::PointerRepresentation()
817                    ? kIsPointer
818                    : 0;
819       default:
820         return 0;
821     }
822   }
823 
IsCompatible(MachineRepresentation expected,MachineRepresentation actual)824   bool IsCompatible(MachineRepresentation expected,
825                     MachineRepresentation actual) {
826     switch (expected) {
827       case MachineRepresentation::kTagged:
828         return (actual == MachineRepresentation::kTagged ||
829                 actual == MachineRepresentation::kTaggedSigned ||
830                 actual == MachineRepresentation::kTaggedPointer);
831       case MachineRepresentation::kTaggedSigned:
832       case MachineRepresentation::kTaggedPointer:
833       case MachineRepresentation::kFloat32:
834       case MachineRepresentation::kFloat64:
835       case MachineRepresentation::kSimd128:
836       case MachineRepresentation::kBit:
837       case MachineRepresentation::kWord8:
838       case MachineRepresentation::kWord16:
839       case MachineRepresentation::kWord64:
840         return expected == actual;
841         break;
842       case MachineRepresentation::kWord32:
843         return (actual == MachineRepresentation::kBit ||
844                 actual == MachineRepresentation::kWord8 ||
845                 actual == MachineRepresentation::kWord16 ||
846                 actual == MachineRepresentation::kWord32);
847       case MachineRepresentation::kNone:
848         UNREACHABLE();
849     }
850     return false;
851   }
852 
PrintDebugHelp(std::ostream & out,Node const * node)853   void PrintDebugHelp(std::ostream& out, Node const* node) {
854     if (DEBUG_BOOL) {
855       out << "\n#     Current block: " << *current_block_;
856       out << "\n#\n#     Specify option --csa-trap-on-node=" << name_ << ","
857           << node->id() << " for debugging.";
858     }
859   }
860 
861   Schedule const* const schedule_;
862   MachineRepresentationInferrer const* const inferrer_;
863   bool is_stub_;
864   const char* name_;
865   BasicBlock* current_block_;
866 };
867 
868 }  // namespace
869 
Run(Graph * graph,Schedule const * const schedule,Linkage * linkage,bool is_stub,const char * name,Zone * temp_zone)870 void MachineGraphVerifier::Run(Graph* graph, Schedule const* const schedule,
871                                Linkage* linkage, bool is_stub, const char* name,
872                                Zone* temp_zone) {
873   MachineRepresentationInferrer representation_inferrer(schedule, graph,
874                                                         linkage, temp_zone);
875   MachineRepresentationChecker checker(schedule, &representation_inferrer,
876                                        is_stub, name);
877   checker.Run();
878 }
879 
880 }  // namespace compiler
881 }  // namespace internal
882 }  // namespace v8
883