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