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