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