blob: 5eeb5dc2486be4efabdccfc046204a92886f623e [file] [log] [blame]
// Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/compiler/machine-graph-verifier.h"
#include "src/compiler/common-operator.h"
#include "src/compiler/graph.h"
#include "src/compiler/linkage.h"
#include "src/compiler/machine-operator.h"
#include "src/compiler/node-properties.h"
#include "src/compiler/node.h"
#include "src/compiler/schedule.h"
#include "src/zone/zone.h"
namespace v8 {
namespace internal {
namespace compiler {
namespace {
class MachineRepresentationInferrer {
public:
MachineRepresentationInferrer(Schedule const* schedule, Graph const* graph,
Linkage* linkage, Zone* zone)
: schedule_(schedule),
linkage_(linkage),
representation_vector_(graph->NodeCount(), MachineRepresentation::kNone,
zone) {
Run();
}
CallDescriptor* call_descriptor() const {
return linkage_->GetIncomingDescriptor();
}
MachineRepresentation GetRepresentation(Node const* node) const {
return representation_vector_.at(node->id());
}
private:
MachineRepresentation GetProjectionType(Node const* projection) {
size_t index = ProjectionIndexOf(projection->op());
Node* input = projection->InputAt(0);
switch (input->opcode()) {
case IrOpcode::kInt32AddWithOverflow:
case IrOpcode::kInt32SubWithOverflow:
case IrOpcode::kInt32MulWithOverflow:
CHECK_LE(index, static_cast<size_t>(1));
return index == 0 ? MachineRepresentation::kWord32
: MachineRepresentation::kBit;
case IrOpcode::kInt64AddWithOverflow:
case IrOpcode::kInt64SubWithOverflow:
CHECK_LE(index, static_cast<size_t>(1));
return index == 0 ? MachineRepresentation::kWord64
: MachineRepresentation::kBit;
case IrOpcode::kTryTruncateFloat32ToInt64:
case IrOpcode::kTryTruncateFloat64ToInt64:
case IrOpcode::kTryTruncateFloat32ToUint64:
CHECK_LE(index, static_cast<size_t>(1));
return index == 0 ? MachineRepresentation::kWord64
: MachineRepresentation::kBit;
case IrOpcode::kCall: {
auto call_descriptor = CallDescriptorOf(input->op());
return call_descriptor->GetReturnType(index).representation();
}
case IrOpcode::kWord32AtomicPairLoad:
case IrOpcode::kWord32AtomicPairAdd:
case IrOpcode::kWord32AtomicPairSub:
case IrOpcode::kWord32AtomicPairAnd:
case IrOpcode::kWord32AtomicPairOr:
case IrOpcode::kWord32AtomicPairXor:
case IrOpcode::kWord32AtomicPairExchange:
case IrOpcode::kWord32AtomicPairCompareExchange:
CHECK_LE(index, static_cast<size_t>(1));
return MachineRepresentation::kWord32;
default:
return MachineRepresentation::kNone;
}
}
MachineRepresentation PromoteRepresentation(MachineRepresentation rep) {
switch (rep) {
case MachineRepresentation::kWord8:
case MachineRepresentation::kWord16:
case MachineRepresentation::kWord32:
return MachineRepresentation::kWord32;
default:
break;
}
return rep;
}
void Run() {
auto blocks = schedule_->all_blocks();
for (BasicBlock* block : *blocks) {
current_block_ = block;
for (size_t i = 0; i <= block->NodeCount(); ++i) {
Node const* node =
i < block->NodeCount() ? block->NodeAt(i) : block->control_input();
if (node == nullptr) {
DCHECK_EQ(block->NodeCount(), i);
break;
}
switch (node->opcode()) {
case IrOpcode::kParameter:
representation_vector_[node->id()] =
linkage_->GetParameterType(ParameterIndexOf(node->op()))
.representation();
break;
case IrOpcode::kReturn: {
representation_vector_[node->id()] = PromoteRepresentation(
linkage_->GetReturnType().representation());
break;
}
case IrOpcode::kProjection: {
representation_vector_[node->id()] = GetProjectionType(node);
} break;
case IrOpcode::kTypedStateValues:
representation_vector_[node->id()] = MachineRepresentation::kNone;
break;
case IrOpcode::kWord32AtomicLoad:
case IrOpcode::kWord64AtomicLoad:
case IrOpcode::kLoad:
case IrOpcode::kProtectedLoad:
case IrOpcode::kPoisonedLoad:
representation_vector_[node->id()] = PromoteRepresentation(
LoadRepresentationOf(node->op()).representation());
break;
case IrOpcode::kLoadFramePointer:
case IrOpcode::kLoadParentFramePointer:
representation_vector_[node->id()] =
MachineType::PointerRepresentation();
break;
case IrOpcode::kUnalignedLoad:
representation_vector_[node->id()] = PromoteRepresentation(
LoadRepresentationOf(node->op()).representation());
break;
case IrOpcode::kPhi:
representation_vector_[node->id()] =
PhiRepresentationOf(node->op());
break;
case IrOpcode::kCall: {
auto call_descriptor = CallDescriptorOf(node->op());
if (call_descriptor->ReturnCount() > 0) {
representation_vector_[node->id()] =
call_descriptor->GetReturnType(0).representation();
} else {
representation_vector_[node->id()] =
MachineRepresentation::kTagged;
}
break;
}
case IrOpcode::kWord32AtomicStore:
case IrOpcode::kWord64AtomicStore:
representation_vector_[node->id()] =
PromoteRepresentation(AtomicStoreRepresentationOf(node->op()));
break;
case IrOpcode::kWord32AtomicPairLoad:
case IrOpcode::kWord32AtomicPairStore:
case IrOpcode::kWord32AtomicPairAdd:
case IrOpcode::kWord32AtomicPairSub:
case IrOpcode::kWord32AtomicPairAnd:
case IrOpcode::kWord32AtomicPairOr:
case IrOpcode::kWord32AtomicPairXor:
case IrOpcode::kWord32AtomicPairExchange:
case IrOpcode::kWord32AtomicPairCompareExchange:
representation_vector_[node->id()] = MachineRepresentation::kWord32;
break;
case IrOpcode::kWord32AtomicExchange:
case IrOpcode::kWord32AtomicCompareExchange:
case IrOpcode::kWord32AtomicAdd:
case IrOpcode::kWord32AtomicSub:
case IrOpcode::kWord32AtomicAnd:
case IrOpcode::kWord32AtomicOr:
case IrOpcode::kWord32AtomicXor:
case IrOpcode::kWord64AtomicExchange:
case IrOpcode::kWord64AtomicCompareExchange:
case IrOpcode::kWord64AtomicAdd:
case IrOpcode::kWord64AtomicSub:
case IrOpcode::kWord64AtomicAnd:
case IrOpcode::kWord64AtomicOr:
case IrOpcode::kWord64AtomicXor:
representation_vector_[node->id()] = PromoteRepresentation(
AtomicOpType(node->op()).representation());
break;
case IrOpcode::kStore:
case IrOpcode::kProtectedStore:
representation_vector_[node->id()] = PromoteRepresentation(
StoreRepresentationOf(node->op()).representation());
break;
case IrOpcode::kUnalignedStore:
representation_vector_[node->id()] = PromoteRepresentation(
UnalignedStoreRepresentationOf(node->op()));
break;
case IrOpcode::kHeapConstant:
representation_vector_[node->id()] =
MachineRepresentation::kTaggedPointer;
break;
case IrOpcode::kNumberConstant:
case IrOpcode::kDelayedStringConstant:
case IrOpcode::kChangeBitToTagged:
case IrOpcode::kIfException:
case IrOpcode::kOsrValue:
case IrOpcode::kChangeInt32ToTagged:
case IrOpcode::kChangeUint32ToTagged:
case IrOpcode::kBitcastWordToTagged:
case IrOpcode::kTaggedPoisonOnSpeculation:
representation_vector_[node->id()] = MachineRepresentation::kTagged;
break;
case IrOpcode::kWord32PoisonOnSpeculation:
representation_vector_[node->id()] = MachineRepresentation::kWord32;
break;
case IrOpcode::kWord64PoisonOnSpeculation:
representation_vector_[node->id()] = MachineRepresentation::kWord64;
break;
case IrOpcode::kCompressedHeapConstant:
representation_vector_[node->id()] =
MachineRepresentation::kCompressedPointer;
break;
case IrOpcode::kExternalConstant:
representation_vector_[node->id()] =
MachineType::PointerRepresentation();
break;
case IrOpcode::kBitcastTaggedToWord:
case IrOpcode::kBitcastTaggedToWordForTagAndSmiBits:
representation_vector_[node->id()] =
MachineType::PointerRepresentation();
break;
case IrOpcode::kBitcastWordToTaggedSigned:
representation_vector_[node->id()] =
MachineRepresentation::kTaggedSigned;
break;
case IrOpcode::kWord32Equal:
case IrOpcode::kInt32LessThan:
case IrOpcode::kInt32LessThanOrEqual:
case IrOpcode::kUint32LessThan:
case IrOpcode::kUint32LessThanOrEqual:
case IrOpcode::kWord64Equal:
case IrOpcode::kInt64LessThan:
case IrOpcode::kInt64LessThanOrEqual:
case IrOpcode::kUint64LessThan:
case IrOpcode::kUint64LessThanOrEqual:
case IrOpcode::kFloat32Equal:
case IrOpcode::kFloat32LessThan:
case IrOpcode::kFloat32LessThanOrEqual:
case IrOpcode::kFloat64Equal:
case IrOpcode::kFloat64LessThan:
case IrOpcode::kFloat64LessThanOrEqual:
case IrOpcode::kChangeTaggedToBit:
case IrOpcode::kStackPointerGreaterThan:
representation_vector_[node->id()] = MachineRepresentation::kBit;
break;
#define LABEL(opcode) case IrOpcode::k##opcode:
case IrOpcode::kTruncateInt64ToInt32:
case IrOpcode::kTruncateFloat32ToInt32:
case IrOpcode::kTruncateFloat32ToUint32:
case IrOpcode::kBitcastFloat32ToInt32:
case IrOpcode::kI32x4ExtractLane:
case IrOpcode::kI16x8ExtractLaneU:
case IrOpcode::kI16x8ExtractLaneS:
case IrOpcode::kI8x16ExtractLaneU:
case IrOpcode::kI8x16ExtractLaneS:
case IrOpcode::kInt32Constant:
case IrOpcode::kRelocatableInt32Constant:
case IrOpcode::kTruncateFloat64ToWord32:
case IrOpcode::kTruncateFloat64ToUint32:
case IrOpcode::kChangeFloat64ToInt32:
case IrOpcode::kChangeFloat64ToUint32:
case IrOpcode::kRoundFloat64ToInt32:
case IrOpcode::kFloat64ExtractLowWord32:
case IrOpcode::kFloat64ExtractHighWord32:
MACHINE_UNOP_32_LIST(LABEL)
MACHINE_BINOP_32_LIST(LABEL) {
representation_vector_[node->id()] =
MachineRepresentation::kWord32;
}
break;
case IrOpcode::kChangeInt32ToInt64:
case IrOpcode::kChangeUint32ToUint64:
case IrOpcode::kInt64Constant:
case IrOpcode::kRelocatableInt64Constant:
case IrOpcode::kBitcastFloat64ToInt64:
case IrOpcode::kChangeFloat64ToInt64:
case IrOpcode::kChangeFloat64ToUint64:
MACHINE_BINOP_64_LIST(LABEL) {
representation_vector_[node->id()] =
MachineRepresentation::kWord64;
}
break;
case IrOpcode::kRoundInt32ToFloat32:
case IrOpcode::kRoundUint32ToFloat32:
case IrOpcode::kRoundInt64ToFloat32:
case IrOpcode::kRoundUint64ToFloat32:
case IrOpcode::kBitcastInt32ToFloat32:
case IrOpcode::kFloat32Constant:
case IrOpcode::kTruncateFloat64ToFloat32:
MACHINE_FLOAT32_BINOP_LIST(LABEL)
MACHINE_FLOAT32_UNOP_LIST(LABEL) {
representation_vector_[node->id()] =
MachineRepresentation::kFloat32;
}
break;
case IrOpcode::kRoundInt64ToFloat64:
case IrOpcode::kRoundUint64ToFloat64:
case IrOpcode::kChangeFloat32ToFloat64:
case IrOpcode::kChangeInt32ToFloat64:
case IrOpcode::kChangeUint32ToFloat64:
case IrOpcode::kFloat64InsertLowWord32:
case IrOpcode::kFloat64InsertHighWord32:
case IrOpcode::kFloat64Constant:
case IrOpcode::kFloat64SilenceNaN:
MACHINE_FLOAT64_BINOP_LIST(LABEL)
MACHINE_FLOAT64_UNOP_LIST(LABEL) {
representation_vector_[node->id()] =
MachineRepresentation::kFloat64;
}
break;
case IrOpcode::kI32x4ReplaceLane:
case IrOpcode::kI32x4Splat:
representation_vector_[node->id()] =
MachineRepresentation::kSimd128;
break;
#undef LABEL
default:
break;
}
}
}
}
Schedule const* const schedule_;
Linkage const* const linkage_;
ZoneVector<MachineRepresentation> representation_vector_;
BasicBlock* current_block_;
};
class MachineRepresentationChecker {
public:
MachineRepresentationChecker(
Schedule const* const schedule,
MachineRepresentationInferrer const* const inferrer, bool is_stub,
const char* name)
: schedule_(schedule),
inferrer_(inferrer),
is_stub_(is_stub),
name_(name),
current_block_(nullptr) {}
void Run() {
BasicBlockVector const* blocks = schedule_->all_blocks();
for (BasicBlock* block : *blocks) {
current_block_ = block;
for (size_t i = 0; i <= block->NodeCount(); ++i) {
Node const* node =
i < block->NodeCount() ? block->NodeAt(i) : block->control_input();
if (node == nullptr) {
DCHECK_EQ(block->NodeCount(), i);
break;
}
switch (node->opcode()) {
case IrOpcode::kCall:
case IrOpcode::kTailCall:
CheckCallInputs(node);
break;
case IrOpcode::kChangeBitToTagged:
CHECK_EQ(MachineRepresentation::kBit,
inferrer_->GetRepresentation(node->InputAt(0)));
break;
case IrOpcode::kChangeTaggedToBit:
CHECK_EQ(MachineRepresentation::kTagged,
inferrer_->GetRepresentation(node->InputAt(0)));
break;
case IrOpcode::kRoundInt64ToFloat64:
case IrOpcode::kRoundUint64ToFloat64:
case IrOpcode::kRoundInt64ToFloat32:
case IrOpcode::kRoundUint64ToFloat32:
case IrOpcode::kTruncateInt64ToInt32:
CheckValueInputForInt64Op(node, 0);
break;
case IrOpcode::kBitcastWordToTagged:
case IrOpcode::kBitcastWordToTaggedSigned:
CheckValueInputRepresentationIs(
node, 0, MachineType::PointerRepresentation());
break;
case IrOpcode::kWord32PoisonOnSpeculation:
CheckValueInputRepresentationIs(node, 0,
MachineRepresentation::kWord32);
break;
case IrOpcode::kWord64PoisonOnSpeculation:
CheckValueInputRepresentationIs(node, 0,
MachineRepresentation::kWord64);
break;
case IrOpcode::kBitcastTaggedToWord:
case IrOpcode::kBitcastTaggedToWordForTagAndSmiBits:
if (COMPRESS_POINTERS_BOOL) {
CheckValueInputIsCompressedOrTagged(node, 0);
} else {
CheckValueInputIsTagged(node, 0);
}
break;
case IrOpcode::kTaggedPoisonOnSpeculation:
CheckValueInputIsTagged(node, 0);
break;
case IrOpcode::kTruncateFloat64ToWord32:
case IrOpcode::kTruncateFloat64ToUint32:
case IrOpcode::kTruncateFloat64ToFloat32:
case IrOpcode::kChangeFloat64ToInt32:
case IrOpcode::kChangeFloat64ToUint32:
case IrOpcode::kRoundFloat64ToInt32:
case IrOpcode::kFloat64ExtractLowWord32:
case IrOpcode::kFloat64ExtractHighWord32:
case IrOpcode::kBitcastFloat64ToInt64:
case IrOpcode::kTryTruncateFloat64ToInt64:
CheckValueInputForFloat64Op(node, 0);
break;
case IrOpcode::kWord64Equal:
if (Is64() && !COMPRESS_POINTERS_BOOL) {
CheckValueInputIsTaggedOrPointer(node, 0);
CheckValueInputIsTaggedOrPointer(node, 1);
if (!is_stub_) {
CheckValueInputRepresentationIs(
node, 1, inferrer_->GetRepresentation(node->InputAt(0)));
}
} else {
CheckValueInputForInt64Op(node, 0);
CheckValueInputForInt64Op(node, 1);
}
break;
case IrOpcode::kInt64LessThan:
case IrOpcode::kInt64LessThanOrEqual:
case IrOpcode::kUint64LessThan:
case IrOpcode::kUint64LessThanOrEqual:
CheckValueInputForInt64Op(node, 0);
CheckValueInputForInt64Op(node, 1);
break;
case IrOpcode::kI32x4ExtractLane:
case IrOpcode::kI16x8ExtractLaneU:
case IrOpcode::kI16x8ExtractLaneS:
case IrOpcode::kI8x16ExtractLaneU:
case IrOpcode::kI8x16ExtractLaneS:
CheckValueInputRepresentationIs(node, 0,
MachineRepresentation::kSimd128);
break;
case IrOpcode::kI32x4ReplaceLane:
CheckValueInputRepresentationIs(node, 0,
MachineRepresentation::kSimd128);
CheckValueInputForInt32Op(node, 1);
break;
case IrOpcode::kI32x4Splat:
CheckValueInputForInt32Op(node, 0);
break;
#define LABEL(opcode) case IrOpcode::k##opcode:
case IrOpcode::kChangeInt32ToTagged:
case IrOpcode::kChangeUint32ToTagged:
case IrOpcode::kChangeInt32ToFloat64:
case IrOpcode::kChangeUint32ToFloat64:
case IrOpcode::kRoundInt32ToFloat32:
case IrOpcode::kRoundUint32ToFloat32:
case IrOpcode::kBitcastInt32ToFloat32:
case IrOpcode::kBitcastWord32ToWord64:
case IrOpcode::kChangeInt32ToInt64:
case IrOpcode::kChangeUint32ToUint64:
MACHINE_UNOP_32_LIST(LABEL) { CheckValueInputForInt32Op(node, 0); }
break;
case IrOpcode::kWord32Equal:
if (Is32()) {
CheckValueInputIsTaggedOrPointer(node, 0);
CheckValueInputIsTaggedOrPointer(node, 1);
if (!is_stub_) {
CheckValueInputRepresentationIs(
node, 1, inferrer_->GetRepresentation(node->InputAt(0)));
}
} else {
if (COMPRESS_POINTERS_BOOL) {
CheckValueInputIsCompressedOrTaggedOrInt32(node, 0);
CheckValueInputIsCompressedOrTaggedOrInt32(node, 1);
} else {
CheckValueIsTaggedOrInt32(node, 0);
CheckValueIsTaggedOrInt32(node, 1);
}
}
break;
case IrOpcode::kInt32LessThan:
case IrOpcode::kInt32LessThanOrEqual:
case IrOpcode::kUint32LessThan:
case IrOpcode::kUint32LessThanOrEqual:
MACHINE_BINOP_32_LIST(LABEL) {
CheckValueInputForInt32Op(node, 0);
CheckValueInputForInt32Op(node, 1);
}
break;
MACHINE_BINOP_64_LIST(LABEL) {
CheckValueInputForInt64Op(node, 0);
CheckValueInputForInt64Op(node, 1);
}
break;
case IrOpcode::kFloat32Equal:
case IrOpcode::kFloat32LessThan:
case IrOpcode::kFloat32LessThanOrEqual:
MACHINE_FLOAT32_BINOP_LIST(LABEL) {
CheckValueInputForFloat32Op(node, 0);
CheckValueInputForFloat32Op(node, 1);
}
break;
case IrOpcode::kChangeFloat32ToFloat64:
case IrOpcode::kTruncateFloat32ToInt32:
case IrOpcode::kTruncateFloat32ToUint32:
case IrOpcode::kBitcastFloat32ToInt32:
MACHINE_FLOAT32_UNOP_LIST(LABEL) {
CheckValueInputForFloat32Op(node, 0);
}
break;
case IrOpcode::kFloat64Equal:
case IrOpcode::kFloat64LessThan:
case IrOpcode::kFloat64LessThanOrEqual:
MACHINE_FLOAT64_BINOP_LIST(LABEL) {
CheckValueInputForFloat64Op(node, 0);
CheckValueInputForFloat64Op(node, 1);
}
break;
case IrOpcode::kFloat64SilenceNaN:
case IrOpcode::kChangeFloat64ToInt64:
case IrOpcode::kChangeFloat64ToUint64:
MACHINE_FLOAT64_UNOP_LIST(LABEL) {
CheckValueInputForFloat64Op(node, 0);
}
break;
#undef LABEL
case IrOpcode::kFloat64InsertLowWord32:
case IrOpcode::kFloat64InsertHighWord32:
CheckValueInputForFloat64Op(node, 0);
CheckValueInputForInt32Op(node, 1);
break;
case IrOpcode::kParameter:
case IrOpcode::kProjection:
break;
case IrOpcode::kAbortCSAAssert:
CheckValueInputIsTagged(node, 0);
break;
case IrOpcode::kLoad:
case IrOpcode::kWord32AtomicLoad:
case IrOpcode::kWord32AtomicPairLoad:
case IrOpcode::kWord64AtomicLoad:
case IrOpcode::kPoisonedLoad:
CheckValueInputIsTaggedOrPointer(node, 0);
CheckValueInputRepresentationIs(
node, 1, MachineType::PointerRepresentation());
break;
case IrOpcode::kWord32AtomicPairAdd:
case IrOpcode::kWord32AtomicPairSub:
case IrOpcode::kWord32AtomicPairAnd:
case IrOpcode::kWord32AtomicPairOr:
case IrOpcode::kWord32AtomicPairXor:
case IrOpcode::kWord32AtomicPairStore:
case IrOpcode::kWord32AtomicPairExchange:
CheckValueInputRepresentationIs(node, 3,
MachineRepresentation::kWord32);
V8_FALLTHROUGH;
case IrOpcode::kStore:
case IrOpcode::kWord32AtomicStore:
case IrOpcode::kWord32AtomicExchange:
case IrOpcode::kWord32AtomicAdd:
case IrOpcode::kWord32AtomicSub:
case IrOpcode::kWord32AtomicAnd:
case IrOpcode::kWord32AtomicOr:
case IrOpcode::kWord32AtomicXor:
case IrOpcode::kWord64AtomicStore:
case IrOpcode::kWord64AtomicExchange:
case IrOpcode::kWord64AtomicAdd:
case IrOpcode::kWord64AtomicSub:
case IrOpcode::kWord64AtomicAnd:
case IrOpcode::kWord64AtomicOr:
case IrOpcode::kWord64AtomicXor:
CheckValueInputIsTaggedOrPointer(node, 0);
CheckValueInputRepresentationIs(
node, 1, MachineType::PointerRepresentation());
switch (inferrer_->GetRepresentation(node)) {
case MachineRepresentation::kTagged:
case MachineRepresentation::kTaggedPointer:
case MachineRepresentation::kTaggedSigned:
if (COMPRESS_POINTERS_BOOL &&
node->opcode() == IrOpcode::kStore &&
CanBeTaggedPointer(
StoreRepresentationOf(node->op()).representation())) {
CheckValueInputIsCompressedOrTagged(node, 2);
} else {
CheckValueInputIsTagged(node, 2);
}
break;
default:
CheckValueInputRepresentationIs(
node, 2, inferrer_->GetRepresentation(node));
}
break;
case IrOpcode::kWord32AtomicPairCompareExchange:
CheckValueInputRepresentationIs(node, 4,
MachineRepresentation::kWord32);
CheckValueInputRepresentationIs(node, 5,
MachineRepresentation::kWord32);
V8_FALLTHROUGH;
case IrOpcode::kWord32AtomicCompareExchange:
case IrOpcode::kWord64AtomicCompareExchange:
CheckValueInputIsTaggedOrPointer(node, 0);
CheckValueInputRepresentationIs(
node, 1, MachineType::PointerRepresentation());
switch (inferrer_->GetRepresentation(node)) {
case MachineRepresentation::kTagged:
case MachineRepresentation::kTaggedPointer:
case MachineRepresentation::kTaggedSigned:
CheckValueInputIsTagged(node, 2);
CheckValueInputIsTagged(node, 3);
break;
default:
CheckValueInputRepresentationIs(
node, 2, inferrer_->GetRepresentation(node));
CheckValueInputRepresentationIs(
node, 3, inferrer_->GetRepresentation(node));
}
break;
case IrOpcode::kPhi:
switch (inferrer_->GetRepresentation(node)) {
case MachineRepresentation::kTagged:
case MachineRepresentation::kTaggedPointer:
for (int i = 0; i < node->op()->ValueInputCount(); ++i) {
CheckValueInputIsTagged(node, i);
}
break;
case MachineRepresentation::kTaggedSigned:
for (int i = 0; i < node->op()->ValueInputCount(); ++i) {
if (COMPRESS_POINTERS_BOOL) {
CheckValueInputIsCompressedOrTagged(node, i);
} else {
CheckValueInputIsTagged(node, i);
}
}
break;
case MachineRepresentation::kCompressed:
case MachineRepresentation::kCompressedPointer:
for (int i = 0; i < node->op()->ValueInputCount(); ++i) {
CheckValueInputIsCompressedOrTagged(node, i);
}
break;
case MachineRepresentation::kWord32:
for (int i = 0; i < node->op()->ValueInputCount(); ++i) {
CheckValueInputForInt32Op(node, i);
}
break;
default:
for (int i = 0; i < node->op()->ValueInputCount(); ++i) {
CheckValueInputRepresentationIs(
node, i, inferrer_->GetRepresentation(node));
}
break;
}
break;
case IrOpcode::kBranch:
case IrOpcode::kSwitch:
CheckValueInputForInt32Op(node, 0);
break;
case IrOpcode::kReturn: {
// TODO(ishell): enable once the pop count parameter type becomes
// MachineType::PointerRepresentation(). Currently it's int32 or
// word-size.
// CheckValueInputRepresentationIs(
// node, 0, MachineType::PointerRepresentation()); // Pop count
size_t return_count = inferrer_->call_descriptor()->ReturnCount();
for (size_t i = 0; i < return_count; i++) {
MachineType type = inferrer_->call_descriptor()->GetReturnType(i);
int input_index = static_cast<int>(i + 1);
switch (type.representation()) {
case MachineRepresentation::kTagged:
case MachineRepresentation::kTaggedPointer:
case MachineRepresentation::kTaggedSigned:
CheckValueInputIsTagged(node, input_index);
break;
case MachineRepresentation::kWord32:
CheckValueInputForInt32Op(node, input_index);
break;
default:
CheckValueInputRepresentationIs(node, input_index,
type.representation());
break;
}
}
break;
}
case IrOpcode::kStackPointerGreaterThan:
CheckValueInputRepresentationIs(
node, 0, MachineType::PointerRepresentation());
break;
case IrOpcode::kThrow:
case IrOpcode::kTypedStateValues:
case IrOpcode::kFrameState:
case IrOpcode::kStaticAssert:
break;
default:
if (node->op()->ValueInputCount() != 0) {
std::stringstream str;
str << "Node #" << node->id() << ":" << *node->op()
<< " in the machine graph is not being checked.";
PrintDebugHelp(str, node);
FATAL("%s", str.str().c_str());
}
break;
}
}
}
}
private:
static bool Is32() {
return MachineType::PointerRepresentation() ==
MachineRepresentation::kWord32;
}
static bool Is64() {
return MachineType::PointerRepresentation() ==
MachineRepresentation::kWord64;
}
void CheckValueInputRepresentationIs(Node const* node, int index,
MachineRepresentation representation) {
Node const* input = node->InputAt(index);
MachineRepresentation input_representation =
inferrer_->GetRepresentation(input);
if (input_representation != representation) {
std::stringstream str;
str << "TypeError: node #" << node->id() << ":" << *node->op()
<< " uses node #" << input->id() << ":" << *input->op() << ":"
<< input_representation << " which doesn't have a " << representation
<< " representation.";
PrintDebugHelp(str, node);
FATAL("%s", str.str().c_str());
}
}
void CheckValueInputIsTagged(Node const* node, int index) {
Node const* input = node->InputAt(index);
switch (inferrer_->GetRepresentation(input)) {
case MachineRepresentation::kTagged:
case MachineRepresentation::kTaggedPointer:
case MachineRepresentation::kTaggedSigned:
return;
default:
break;
}
std::ostringstream str;
str << "TypeError: node #" << node->id() << ":" << *node->op()
<< " uses node #" << input->id() << ":" << *input->op()
<< " which doesn't have a tagged representation.";
PrintDebugHelp(str, node);
FATAL("%s", str.str().c_str());
}
void CheckValueInputIsCompressedOrTagged(Node const* node, int index) {
Node const* input = node->InputAt(index);
switch (inferrer_->GetRepresentation(input)) {
case MachineRepresentation::kCompressed:
case MachineRepresentation::kCompressedPointer:
case MachineRepresentation::kTagged:
case MachineRepresentation::kTaggedPointer:
case MachineRepresentation::kTaggedSigned:
return;
default:
break;
}
std::ostringstream str;
str << "TypeError: node #" << node->id() << ":" << *node->op()
<< " uses node #" << input->id() << ":" << *input->op()
<< " which doesn't have a compressed or tagged representation.";
PrintDebugHelp(str, node);
FATAL("%s", str.str().c_str());
}
void CheckValueInputIsCompressedOrTaggedOrInt32(Node const* node, int index) {
Node const* input = node->InputAt(index);
switch (inferrer_->GetRepresentation(input)) {
case MachineRepresentation::kCompressed:
case MachineRepresentation::kCompressedPointer:
return;
case MachineRepresentation::kTagged:
case MachineRepresentation::kTaggedPointer:
case MachineRepresentation::kTaggedSigned:
return;
case MachineRepresentation::kBit:
case MachineRepresentation::kWord8:
case MachineRepresentation::kWord16:
case MachineRepresentation::kWord32:
return;
default:
break;
}
std::ostringstream str;
str << "TypeError: node #" << node->id() << ":" << *node->op()
<< " uses node #" << input->id() << ":" << *input->op()
<< " which doesn't have a compressed, tagged, or int32 representation.";
PrintDebugHelp(str, node);
FATAL("%s", str.str().c_str());
}
void CheckValueInputIsTaggedOrPointer(Node const* node, int index) {
Node const* input = node->InputAt(index);
switch (inferrer_->GetRepresentation(input)) {
case MachineRepresentation::kTagged:
case MachineRepresentation::kTaggedPointer:
case MachineRepresentation::kTaggedSigned:
return;
case MachineRepresentation::kBit:
case MachineRepresentation::kWord8:
case MachineRepresentation::kWord16:
case MachineRepresentation::kWord32:
if (Is32()) {
return;
}
break;
case MachineRepresentation::kWord64:
if (Is64()) {
return;
}
break;
default:
break;
}
if (inferrer_->GetRepresentation(input) !=
MachineType::PointerRepresentation()) {
std::ostringstream str;
str << "TypeError: node #" << node->id() << ":" << *node->op()
<< " uses node #" << input->id() << ":" << *input->op()
<< " which doesn't have a tagged or pointer representation.";
PrintDebugHelp(str, node);
FATAL("%s", str.str().c_str());
}
}
void CheckValueInputForInt32Op(Node const* node, int index) {
Node const* input = node->InputAt(index);
switch (inferrer_->GetRepresentation(input)) {
case MachineRepresentation::kBit:
case MachineRepresentation::kWord8:
case MachineRepresentation::kWord16:
case MachineRepresentation::kWord32:
return;
case MachineRepresentation::kNone: {
std::ostringstream str;
str << "TypeError: node #" << input->id() << ":" << *input->op()
<< " is untyped.";
PrintDebugHelp(str, node);
FATAL("%s", str.str().c_str());
break;
}
default:
break;
}
std::ostringstream str;
str << "TypeError: node #" << node->id() << ":" << *node->op()
<< " uses node #" << input->id() << ":" << *input->op()
<< " which doesn't have an int32-compatible representation.";
PrintDebugHelp(str, node);
FATAL("%s", str.str().c_str());
}
void CheckValueIsTaggedOrInt32(Node const* node, int index) {
Node const* input = node->InputAt(index);
switch (inferrer_->GetRepresentation(input)) {
case MachineRepresentation::kBit:
case MachineRepresentation::kWord8:
case MachineRepresentation::kWord16:
case MachineRepresentation::kWord32:
return;
case MachineRepresentation::kTagged:
case MachineRepresentation::kTaggedPointer:
return;
default:
break;
}
std::ostringstream str;
str << "TypeError: node #" << node->id() << ":" << *node->op()
<< " uses node #" << input->id() << ":" << *input->op()
<< " which doesn't have a tagged or int32-compatible "
"representation.";
PrintDebugHelp(str, node);
FATAL("%s", str.str().c_str());
}
void CheckValueInputForInt64Op(Node const* node, int index) {
Node const* input = node->InputAt(index);
MachineRepresentation input_representation =
inferrer_->GetRepresentation(input);
switch (input_representation) {
case MachineRepresentation::kWord64:
return;
case MachineRepresentation::kNone: {
std::ostringstream str;
str << "TypeError: node #" << input->id() << ":" << *input->op()
<< " is untyped.";
PrintDebugHelp(str, node);
FATAL("%s", str.str().c_str());
break;
}
default:
break;
}
std::ostringstream str;
str << "TypeError: node #" << node->id() << ":" << *node->op()
<< " uses node #" << input->id() << ":" << *input->op() << ":"
<< input_representation
<< " which doesn't have a kWord64 representation.";
PrintDebugHelp(str, node);
FATAL("%s", str.str().c_str());
}
void CheckValueInputForFloat32Op(Node const* node, int index) {
Node const* input = node->InputAt(index);
if (MachineRepresentation::kFloat32 ==
inferrer_->GetRepresentation(input)) {
return;
}
std::ostringstream str;
str << "TypeError: node #" << node->id() << ":" << *node->op()
<< " uses node #" << input->id() << ":" << *input->op()
<< " which doesn't have a kFloat32 representation.";
PrintDebugHelp(str, node);
FATAL("%s", str.str().c_str());
}
void CheckValueInputForFloat64Op(Node const* node, int index) {
Node const* input = node->InputAt(index);
if (MachineRepresentation::kFloat64 ==
inferrer_->GetRepresentation(input)) {
return;
}
std::ostringstream str;
str << "TypeError: node #" << node->id() << ":" << *node->op()
<< " uses node #" << input->id() << ":" << *input->op()
<< " which doesn't have a kFloat64 representation.";
PrintDebugHelp(str, node);
FATAL("%s", str.str().c_str());
}
void CheckCallInputs(Node const* node) {
auto call_descriptor = CallDescriptorOf(node->op());
std::ostringstream str;
bool should_log_error = false;
for (size_t i = 0; i < call_descriptor->InputCount(); ++i) {
Node const* input = node->InputAt(static_cast<int>(i));
MachineRepresentation const input_type =
inferrer_->GetRepresentation(input);
MachineRepresentation const expected_input_type =
call_descriptor->GetInputType(i).representation();
if (!IsCompatible(expected_input_type, input_type)) {
if (!should_log_error) {
should_log_error = true;
str << "TypeError: node #" << node->id() << ":" << *node->op()
<< " has wrong type for:" << std::endl;
} else {
str << std::endl;
}
str << " * input " << i << " (" << input->id() << ":" << *input->op()
<< ") has a " << input_type
<< " representation (expected: " << expected_input_type << ").";
}
}
if (should_log_error) {
PrintDebugHelp(str, node);
FATAL("%s", str.str().c_str());
}
}
bool IsCompatible(MachineRepresentation expected,
MachineRepresentation actual) {
switch (expected) {
case MachineRepresentation::kTagged:
return IsAnyTagged(actual);
case MachineRepresentation::kCompressed:
return IsAnyCompressed(actual);
case MachineRepresentation::kTaggedSigned:
case MachineRepresentation::kTaggedPointer:
// TODO(tebbi): At the moment, the machine graph doesn't contain
// reliable information if a node is kTaggedSigned, kTaggedPointer or
// kTagged, and often this is context-dependent. We should at least
// check for obvious violations: kTaggedSigned where we expect
// kTaggedPointer and the other way around, but at the moment, this
// happens in dead code.
return IsAnyTagged(actual);
case MachineRepresentation::kCompressedPointer:
case MachineRepresentation::kFloat32:
case MachineRepresentation::kFloat64:
case MachineRepresentation::kSimd128:
case MachineRepresentation::kBit:
case MachineRepresentation::kWord8:
case MachineRepresentation::kWord16:
case MachineRepresentation::kWord64:
return expected == actual;
break;
case MachineRepresentation::kWord32:
return (actual == MachineRepresentation::kBit ||
actual == MachineRepresentation::kWord8 ||
actual == MachineRepresentation::kWord16 ||
actual == MachineRepresentation::kWord32);
case MachineRepresentation::kNone:
UNREACHABLE();
}
return false;
}
void PrintDebugHelp(std::ostream& out, Node const* node) {
if (DEBUG_BOOL) {
out << "\n# Current block: " << *current_block_;
out << "\n#\n# Specify option --csa-trap-on-node=" << name_ << ","
<< node->id() << " for debugging.";
}
}
Schedule const* const schedule_;
MachineRepresentationInferrer const* const inferrer_;
bool is_stub_;
const char* name_;
BasicBlock* current_block_;
};
} // namespace
void MachineGraphVerifier::Run(Graph* graph, Schedule const* const schedule,
Linkage* linkage, bool is_stub, const char* name,
Zone* temp_zone) {
MachineRepresentationInferrer representation_inferrer(schedule, graph,
linkage, temp_zone);
MachineRepresentationChecker checker(schedule, &representation_inferrer,
is_stub, name);
checker.Run();
}
} // namespace compiler
} // namespace internal
} // namespace v8