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