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