[maglev] Simple Graph verifier

It currently only checks if the node inputs are expected to be
tagged or untagged.

Bug: v8:7700
Change-Id: Ibf068098dfb08c28b2744cb321fa857572998948
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3578804
Reviewed-by: Leszek Swirski <leszeks@chromium.org>
Commit-Queue: Victor Gomes <victorgomes@chromium.org>
Auto-Submit: Victor Gomes <victorgomes@chromium.org>
Cr-Commit-Position: refs/heads/main@{#79945}
This commit is contained in:
Victor Gomes 2022-04-12 18:16:34 +02:00 committed by V8 LUCI CQ
parent 74178a4304
commit 1b456ebbe8
3 changed files with 152 additions and 0 deletions

View File

@ -3484,6 +3484,7 @@ v8_header_set("v8_internal_headers") {
"src/maglev/maglev-graph-labeller.h",
"src/maglev/maglev-graph-printer.h",
"src/maglev/maglev-graph-processor.h",
"src/maglev/maglev-graph-verifier.h",
"src/maglev/maglev-graph.h",
"src/maglev/maglev-interpreter-frame-state.h",
"src/maglev/maglev-ir.h",

View File

@ -31,6 +31,7 @@
#include "src/maglev/maglev-graph-labeller.h"
#include "src/maglev/maglev-graph-printer.h"
#include "src/maglev/maglev-graph-processor.h"
#include "src/maglev/maglev-graph-verifier.h"
#include "src/maglev/maglev-graph.h"
#include "src/maglev/maglev-interpreter-frame-state.h"
#include "src/maglev/maglev-ir.h"
@ -174,6 +175,13 @@ void MaglevCompiler::Compile() {
PrintGraph(std::cout, toplevel_compilation_unit_, graph_builder.graph());
}
#ifdef DEBUG
{
GraphProcessor<MaglevGraphVerifier> verifier(toplevel_compilation_unit_);
verifier.ProcessGraph(graph_builder.graph());
}
#endif
{
GraphMultiProcessor<NumberingProcessor, UseMarkingProcessor,
MaglevVregAllocator>

View File

@ -0,0 +1,143 @@
// Copyright 2022 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.
#ifndef V8_MAGLEV_MAGLEV_GRAPH_VERIFIER_H_
#define V8_MAGLEV_MAGLEV_GRAPH_VERIFIER_H_
#include "src/maglev/maglev-graph-labeller.h"
#include "src/maglev/maglev-ir.h"
namespace v8 {
namespace internal {
namespace maglev {
std::ostream& operator<<(std::ostream& os, const ValueRepresentation& repr) {
switch (repr) {
case ValueRepresentation::kTagged:
os << "TaggedValue";
break;
case ValueRepresentation::kUntagged:
os << "UntaggedValue";
break;
}
return os;
}
class Graph;
// TODO(victorgomes): Currently it only verifies the inputs for all ValueNodes
// are expected to be tagged/untagged. Add more verification later.
class MaglevGraphVerifier {
public:
void PreProcessGraph(MaglevCompilationUnit* compilation_unit, Graph* graph) {
if (compilation_unit->has_graph_labeller()) {
graph_labeller_ = compilation_unit->graph_labeller();
}
}
void PostProcessGraph(MaglevCompilationUnit*, Graph* graph) {}
void PreProcessBasicBlock(MaglevCompilationUnit*, BasicBlock* block) {}
void CheckValueInputIs(NodeBase* node, int i, ValueRepresentation repr) {
ValueNode* input = node->input(i).node();
if (input->value_representation() != repr) {
std::ostringstream str;
str << "Type representation error: node ";
if (graph_labeller_) {
str << "#" << graph_labeller_->NodeId(node) << " : ";
}
str << node->opcode() << " (input @" << i << " = " << input->opcode()
<< ") type " << input->value_representation() << " is not " << repr;
FATAL("%s", str.str().c_str());
}
}
void Process(NodeBase* node, const ProcessingState& state) {
switch (node->opcode()) {
case Opcode::kConstant:
case Opcode::kSmiConstant:
case Opcode::kInt32Constant:
case Opcode::kRootConstant:
case Opcode::kInitialValue:
case Opcode::kRegisterInput:
case Opcode::kGapMove:
case Opcode::kEagerDeopt:
case Opcode::kJump:
case Opcode::kJumpLoop:
// No input.
DCHECK_EQ(node->input_count(), 0);
break;
case Opcode::kGenericNegate:
case Opcode::kGenericIncrement:
case Opcode::kGenericDecrement:
case Opcode::kCheckedSmiUntag:
case Opcode::kLoadField:
case Opcode::kLoadGlobal:
// TODO(victorgomes): Can we check that the input is actually a map?
case Opcode::kCheckMaps:
// TODO(victorgomes): Can we check that the input is Boolean?
case Opcode::kBranchIfTrue:
case Opcode::kBranchIfToBooleanTrue:
case Opcode::kReturn:
// Generic tagged unary operations.
DCHECK_EQ(node->input_count(), 1);
CheckValueInputIs(node, 0, ValueRepresentation::kTagged);
break;
case Opcode::kCheckedSmiTag:
// Untagged unary operations.
CheckValueInputIs(node, 0, ValueRepresentation::kUntagged);
break;
case Opcode::kGenericAdd:
case Opcode::kGenericSubtract:
case Opcode::kGenericMultiply:
case Opcode::kGenericDivide:
case Opcode::kGenericModulus:
case Opcode::kGenericExponentiate:
case Opcode::kGenericBitwiseAnd:
case Opcode::kGenericBitwiseOr:
case Opcode::kGenericBitwiseXor:
case Opcode::kGenericShiftLeft:
case Opcode::kGenericShiftRight:
case Opcode::kGenericShiftRightLogical:
case Opcode::kGenericBitwiseNot:
// TODO(victorgomes): Can we use the fact that these nodes return a
// Boolean?
case Opcode::kGenericEqual:
case Opcode::kGenericStrictEqual:
case Opcode::kGenericLessThan:
case Opcode::kGenericLessThanOrEqual:
case Opcode::kGenericGreaterThan:
case Opcode::kGenericGreaterThanOrEqual:
// TODO(victorgomes): Can we check that first input is an Object?
case Opcode::kStoreField:
case Opcode::kLoadNamedGeneric:
// Generic tagged binary operations.
DCHECK_EQ(node->input_count(), 2);
CheckValueInputIs(node, 0, ValueRepresentation::kTagged);
CheckValueInputIs(node, 1, ValueRepresentation::kTagged);
break;
case Opcode::kInt32AddWithOverflow:
// Untagged binary operations.
CheckValueInputIs(node, 0, ValueRepresentation::kUntagged);
CheckValueInputIs(node, 1, ValueRepresentation::kUntagged);
break;
case Opcode::kCall:
case Opcode::kPhi:
// All inputs should be tagged.
for (int i = 0; i < node->input_count(); i++) {
CheckValueInputIs(node, i, ValueRepresentation::kTagged);
}
break;
}
}
private:
MaglevGraphLabeller* graph_labeller_ = nullptr;
};
} // namespace maglev
} // namespace internal
} // namespace v8
#endif // V8_MAGLEV_MAGLEV_GRAPH_VERIFIER_H_