Commit 3864c961 authored by Nico Hartmann's avatar Nico Hartmann Committed by V8 LUCI CQ

[turbofan] Print an additional Turbolizer phase for SLVerifier

To make the existing mechanism for printing JSON for turbolizer able to
print types other than the ones stored in the nodes (so the verifier can
print its own types here), this CL restructures the printing mechanism
into a single non-private class that can be inherited to override
certain parts of the printing. In this CL only GetType is made virtual
to allow verifier to override it, but additional parts can be made
overridable whenever necessary.

Bug: v8:12619
Change-Id: Idf31f8cdb49eb6c3204c6abfbb74fc981330d6d2
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3571818Reviewed-by: 's avatarTobias Tebbi <tebbi@chromium.org>
Commit-Queue: Nico Hartmann <nicohartmann@chromium.org>
Cr-Commit-Position: refs/heads/main@{#79909}
parent 818fa541
......@@ -268,153 +268,139 @@ static const char* SafeMnemonic(Node* node) {
return node == nullptr ? "null" : node->op()->mnemonic();
}
class JSONGraphNodeWriter {
public:
JSONGraphNodeWriter(std::ostream& os, Zone* zone, const Graph* graph,
const SourcePositionTable* positions,
const NodeOriginTable* origins)
: os_(os),
all_(zone, graph, false),
live_(zone, graph, true),
positions_(positions),
origins_(origins),
first_node_(true) {}
JSONGraphNodeWriter(const JSONGraphNodeWriter&) = delete;
JSONGraphNodeWriter& operator=(const JSONGraphNodeWriter&) = delete;
void Print() {
for (Node* const node : all_.reachable) PrintNode(node);
os_ << "\n";
}
JSONGraphWriter::JSONGraphWriter(std::ostream& os, const Graph* graph,
const SourcePositionTable* positions,
const NodeOriginTable* origins)
: os_(os),
zone_(nullptr),
graph_(graph),
positions_(positions),
origins_(origins),
first_node_(true),
first_edge_(true) {}
void JSONGraphWriter::PrintPhase(const char* phase_name) {
os_ << "{\"name\":\"" << phase_name << "\",\"type\":\"graph\",\"data\":";
Print();
os_ << "},\n";
}
void PrintNode(Node* node) {
if (first_node_) {
first_node_ = false;
} else {
os_ << ",\n";
}
std::ostringstream label, title, properties;
node->op()->PrintTo(label, Operator::PrintVerbosity::kSilent);
node->op()->PrintTo(title, Operator::PrintVerbosity::kVerbose);
node->op()->PrintPropsTo(properties);
os_ << "{\"id\":" << SafeId(node) << ",\"label\":\"" << JSONEscaped(label)
<< "\""
<< ",\"title\":\"" << JSONEscaped(title) << "\""
<< ",\"live\": " << (live_.IsLive(node) ? "true" : "false")
<< ",\"properties\":\"" << JSONEscaped(properties) << "\"";
IrOpcode::Value opcode = node->opcode();
if (IrOpcode::IsPhiOpcode(opcode)) {
os_ << ",\"rankInputs\":[0," << NodeProperties::FirstControlIndex(node)
<< "]";
os_ << ",\"rankWithInput\":[" << NodeProperties::FirstControlIndex(node)
<< "]";
} else if (opcode == IrOpcode::kIfTrue || opcode == IrOpcode::kIfFalse ||
opcode == IrOpcode::kLoop) {
os_ << ",\"rankInputs\":[" << NodeProperties::FirstControlIndex(node)
<< "]";
}
if (opcode == IrOpcode::kBranch) {
os_ << ",\"rankInputs\":[0]";
}
if (positions_ != nullptr) {
SourcePosition position = positions_->GetSourcePosition(node);
if (position.IsKnown()) {
os_ << ", \"sourcePosition\" : " << AsJSON(position);
}
}
if (origins_) {
NodeOrigin origin = origins_->GetNodeOrigin(node);
if (origin.IsKnown()) {
os_ << ", \"origin\" : " << AsJSON(origin);
}
void JSONGraphWriter::Print() {
AccountingAllocator allocator;
Zone tmp_zone(&allocator, ZONE_NAME);
zone_ = &tmp_zone;
AllNodes all(zone_, graph_, false);
AllNodes live(zone_, graph_, true);
os_ << "{\n\"nodes\":[";
for (Node* const node : all.reachable) PrintNode(node, live.IsLive(node));
os_ << "\n";
os_ << "],\n\"edges\":[";
for (Node* const node : all.reachable) PrintEdges(node);
os_ << "\n";
os_ << "]}";
zone_ = nullptr;
}
void JSONGraphWriter::PrintNode(Node* node, bool is_live) {
if (first_node_) {
first_node_ = false;
} else {
os_ << ",\n";
}
std::ostringstream label, title, properties;
node->op()->PrintTo(label, Operator::PrintVerbosity::kSilent);
node->op()->PrintTo(title, Operator::PrintVerbosity::kVerbose);
node->op()->PrintPropsTo(properties);
os_ << "{\"id\":" << SafeId(node) << ",\"label\":\"" << JSONEscaped(label)
<< "\""
<< ",\"title\":\"" << JSONEscaped(title) << "\""
<< ",\"live\": " << (is_live ? "true" : "false") << ",\"properties\":\""
<< JSONEscaped(properties) << "\"";
IrOpcode::Value opcode = node->opcode();
if (IrOpcode::IsPhiOpcode(opcode)) {
os_ << ",\"rankInputs\":[0," << NodeProperties::FirstControlIndex(node)
<< "]";
os_ << ",\"rankWithInput\":[" << NodeProperties::FirstControlIndex(node)
<< "]";
} else if (opcode == IrOpcode::kIfTrue || opcode == IrOpcode::kIfFalse ||
opcode == IrOpcode::kLoop) {
os_ << ",\"rankInputs\":[" << NodeProperties::FirstControlIndex(node)
<< "]";
}
if (opcode == IrOpcode::kBranch) {
os_ << ",\"rankInputs\":[0]";
}
if (positions_ != nullptr) {
SourcePosition position = positions_->GetSourcePosition(node);
if (position.IsKnown()) {
os_ << ", \"sourcePosition\" : " << AsJSON(position);
}
os_ << ",\"opcode\":\"" << IrOpcode::Mnemonic(node->opcode()) << "\"";
os_ << ",\"control\":" << (NodeProperties::IsControl(node) ? "true"
: "false");
os_ << ",\"opinfo\":\"" << node->op()->ValueInputCount() << " v "
<< node->op()->EffectInputCount() << " eff "
<< node->op()->ControlInputCount() << " ctrl in, "
<< node->op()->ValueOutputCount() << " v "
<< node->op()->EffectOutputCount() << " eff "
<< node->op()->ControlOutputCount() << " ctrl out\"";
if (NodeProperties::IsTyped(node)) {
Type type = NodeProperties::GetType(node);
std::ostringstream type_out;
type.PrintTo(type_out);
os_ << ",\"type\":\"" << JSONEscaped(type_out) << "\"";
}
if (origins_) {
NodeOrigin origin = origins_->GetNodeOrigin(node);
if (origin.IsKnown()) {
os_ << ", \"origin\" : " << AsJSON(origin);
}
os_ << "}";
}
private:
std::ostream& os_;
AllNodes all_;
AllNodes live_;
const SourcePositionTable* positions_;
const NodeOriginTable* origins_;
bool first_node_;
};
class JSONGraphEdgeWriter {
public:
JSONGraphEdgeWriter(std::ostream& os, Zone* zone, const Graph* graph)
: os_(os), all_(zone, graph, false), first_edge_(true) {}
JSONGraphEdgeWriter(const JSONGraphEdgeWriter&) = delete;
JSONGraphEdgeWriter& operator=(const JSONGraphEdgeWriter&) = delete;
void Print() {
for (Node* const node : all_.reachable) PrintEdges(node);
os_ << "\n";
os_ << ",\"opcode\":\"" << IrOpcode::Mnemonic(node->opcode()) << "\"";
os_ << ",\"control\":"
<< (NodeProperties::IsControl(node) ? "true" : "false");
os_ << ",\"opinfo\":\"" << node->op()->ValueInputCount() << " v "
<< node->op()->EffectInputCount() << " eff "
<< node->op()->ControlInputCount() << " ctrl in, "
<< node->op()->ValueOutputCount() << " v "
<< node->op()->EffectOutputCount() << " eff "
<< node->op()->ControlOutputCount() << " ctrl out\"";
if (auto type_opt = GetType(node)) {
std::ostringstream type_out;
type_opt->PrintTo(type_out);
os_ << ",\"type\":\"" << JSONEscaped(type_out) << "\"";
}
os_ << "}";
}
void PrintEdges(Node* node) {
for (int i = 0; i < node->InputCount(); i++) {
Node* input = node->InputAt(i);
if (input == nullptr) continue;
PrintEdge(node, i, input);
}
void JSONGraphWriter::PrintEdges(Node* node) {
for (int i = 0; i < node->InputCount(); i++) {
Node* input = node->InputAt(i);
if (input == nullptr) continue;
PrintEdge(node, i, input);
}
}
void PrintEdge(Node* from, int index, Node* to) {
if (first_edge_) {
first_edge_ = false;
} else {
os_ << ",\n";
}
const char* edge_type = nullptr;
if (index < NodeProperties::FirstValueIndex(from)) {
edge_type = "unknown";
} else if (index < NodeProperties::FirstContextIndex(from)) {
edge_type = "value";
} else if (index < NodeProperties::FirstFrameStateIndex(from)) {
edge_type = "context";
} else if (index < NodeProperties::FirstEffectIndex(from)) {
edge_type = "frame-state";
} else if (index < NodeProperties::FirstControlIndex(from)) {
edge_type = "effect";
} else {
edge_type = "control";
}
os_ << "{\"source\":" << SafeId(to) << ",\"target\":" << SafeId(from)
<< ",\"index\":" << index << ",\"type\":\"" << edge_type << "\"}";
void JSONGraphWriter::PrintEdge(Node* from, int index, Node* to) {
if (first_edge_) {
first_edge_ = false;
} else {
os_ << ",\n";
}
const char* edge_type = nullptr;
if (index < NodeProperties::FirstValueIndex(from)) {
edge_type = "unknown";
} else if (index < NodeProperties::FirstContextIndex(from)) {
edge_type = "value";
} else if (index < NodeProperties::FirstFrameStateIndex(from)) {
edge_type = "context";
} else if (index < NodeProperties::FirstEffectIndex(from)) {
edge_type = "frame-state";
} else if (index < NodeProperties::FirstControlIndex(from)) {
edge_type = "effect";
} else {
edge_type = "control";
}
os_ << "{\"source\":" << SafeId(to) << ",\"target\":" << SafeId(from)
<< ",\"index\":" << index << ",\"type\":\"" << edge_type << "\"}";
}
private:
std::ostream& os_;
AllNodes all_;
bool first_edge_;
};
base::Optional<Type> JSONGraphWriter::GetType(Node* node) {
if (!NodeProperties::IsTyped(node)) return base::nullopt;
return NodeProperties::GetType(node);
}
std::ostream& operator<<(std::ostream& os, const GraphAsJSON& ad) {
AccountingAllocator allocator;
Zone tmp_zone(&allocator, ZONE_NAME);
os << "{\n\"nodes\":[";
JSONGraphNodeWriter(os, &tmp_zone, &ad.graph, ad.positions, ad.origins)
.Print();
os << "],\n\"edges\":[";
JSONGraphEdgeWriter(os, &tmp_zone, &ad.graph).Print();
os << "]}";
JSONGraphWriter writer(os, &ad.graph, ad.positions, ad.origins);
writer.Print();
return os;
}
......
......@@ -29,11 +29,13 @@ class Instruction;
class InstructionBlock;
class InstructionOperand;
class InstructionSequence;
class Node;
class NodeOrigin;
class NodeOriginTable;
class RegisterAllocationData;
class Schedule;
class SourcePositionTable;
class Type;
struct TurboJsonFile : public std::ofstream {
TurboJsonFile(OptimizedCompilationInfo* info, std::ios_base::openmode mode);
......@@ -95,6 +97,34 @@ std::unique_ptr<char[]> GetVisualizerLogFileName(OptimizedCompilationInfo* info,
const char* phase,
const char* suffix);
class JSONGraphWriter {
public:
JSONGraphWriter(std::ostream& os, const Graph* graph,
const SourcePositionTable* positions,
const NodeOriginTable* origins);
JSONGraphWriter(const JSONGraphWriter&) = delete;
JSONGraphWriter& operator=(const JSONGraphWriter&) = delete;
void PrintPhase(const char* phase_name);
void Print();
protected:
void PrintNode(Node* node, bool is_live);
void PrintEdges(Node* node);
void PrintEdge(Node* from, int index, Node* to);
virtual base::Optional<Type> GetType(Node* node);
protected:
std::ostream& os_;
Zone* zone_;
const Graph* graph_;
const SourcePositionTable* positions_;
const NodeOriginTable* origins_;
bool first_node_;
bool first_edge_;
};
struct GraphAsJSON {
GraphAsJSON(const Graph& g, SourcePositionTable* p, NodeOriginTable* o)
: graph(g), positions(p), origins(o) {}
......
......@@ -1583,7 +1583,7 @@ struct SimplifiedLoweringPhase {
SimplifiedLowering lowering(data->jsgraph(), data->broker(), temp_zone,
data->source_positions(), data->node_origins(),
&data->info()->tick_counter(), linkage,
data->observe_node_manager());
data->info(), data->observe_node_manager());
// RepresentationChanger accesses the heap.
UnparkedScopeIfNeeded scope(data->broker());
......
......@@ -16,7 +16,7 @@ class OperationTyper;
class SimplifiedLoweringVerifier final {
public:
struct PerNodeData {
Type type = Type::None();
base::Optional<Type> type = base::nullopt;
Truncation truncation = Truncation::Any(IdentifyZeros::kDistinguishZeros);
};
......@@ -31,6 +31,18 @@ class SimplifiedLoweringVerifier final {
}
const ZoneVector<Node*>& inserted_hints() const { return hints_; }
base::Optional<Type> GetType(Node* node) const {
if (NodeProperties::IsTyped(node)) {
return NodeProperties::GetType(node);
}
// For nodes that have not been typed before SL, we use the type that has
// been inferred by the verifier.
if (node->id() < data_.size()) {
return data_[node->id()].type;
}
return base::nullopt;
}
private:
void ResizeDataIfNecessary(Node* node) {
if (data_.size() <= node->id()) {
......@@ -54,10 +66,11 @@ class SimplifiedLoweringVerifier final {
}
// For nodes that have not been typed before SL, we use the type that has
// been inferred by the verifier.
base::Optional<Type> type_opt;
if (input->id() < data_.size()) {
return data_[input->id()].type;
type_opt = data_[input->id()].type;
}
return Type::None();
return type_opt.has_value() ? *type_opt : Type::None();
}
void SetTruncation(Node* node, const Truncation& truncation) {
......
......@@ -16,6 +16,8 @@
#include "src/compiler/common-operator.h"
#include "src/compiler/compiler-source-position-table.h"
#include "src/compiler/diamond.h"
#include "src/compiler/graph-visualizer.h"
#include "src/compiler/js-heap-broker.h"
#include "src/compiler/linkage.h"
#include "src/compiler/node-matchers.h"
#include "src/compiler/node-observer.h"
......@@ -222,6 +224,23 @@ bool IsSomePositiveOrderedNumber(Type type) {
return type.Is(Type::OrderedNumber()) && (type.IsNone() || type.Min() > 0);
}
class JSONGraphWriterWithVerifierTypes : public JSONGraphWriter {
public:
JSONGraphWriterWithVerifierTypes(std::ostream& os, const Graph* graph,
const SourcePositionTable* positions,
const NodeOriginTable* origins,
SimplifiedLoweringVerifier* verifier)
: JSONGraphWriter(os, graph, positions, origins), verifier_(verifier) {}
protected:
base::Optional<Type> GetType(Node* node) override {
return verifier_->GetType(node);
}
private:
SimplifiedLoweringVerifier* verifier_;
};
} // namespace
#ifdef DEBUG
......@@ -316,6 +335,7 @@ class RepresentationSelector {
ObserveNodeManager* observe_node_manager,
SimplifiedLoweringVerifier* verifier)
: jsgraph_(jsgraph),
broker_(broker),
zone_(zone),
might_need_revisit_(zone),
count_(jsgraph->graph()->NodeCount()),
......@@ -721,7 +741,7 @@ class RepresentationSelector {
}
}
void RunVerifyPhase() {
void RunVerifyPhase(OptimizedCompilationInfo* info) {
DCHECK_NOT_NULL(verifier_);
TRACE("--{Verify Phase}--\n");
......@@ -741,6 +761,17 @@ class RepresentationSelector {
// Verify all nodes.
for (Node* node : traversal_nodes_) verifier_->VisitNode(node, op_typer_);
// Print graph.
if (info != nullptr && info->trace_turbo_json()) {
UnparkedScopeIfNeeded scope(broker_);
AllowHandleDereference allow_deref;
TurboJsonFile json_of(info, std::ios_base::app);
JSONGraphWriterWithVerifierTypes writer(
json_of, graph(), source_positions_, node_origins_, verifier_);
writer.PrintPhase("V8.TFSimplifiedLoweringVerifier");
}
// Eliminate all introduced hints.
for (Node* node : verifier_->inserted_hints()) {
Node* input = node->InputAt(0);
......@@ -756,7 +787,7 @@ class RepresentationSelector {
RunLowerPhase(lowering);
if (verification_enabled()) {
RunVerifyPhase();
RunVerifyPhase(lowering->info_);
}
}
......@@ -4128,6 +4159,7 @@ class RepresentationSelector {
}
JSGraph* jsgraph_;
JSHeapBroker* broker_;
Zone* zone_; // Temporary zone.
// Map from node to its uses that might need to be revisited.
ZoneMap<Node*, ZoneVector<Node*>> might_need_revisit_;
......@@ -4323,13 +4355,11 @@ void RepresentationSelector::InsertUnreachableIfNecessary<LOWER>(Node* node) {
}
}
SimplifiedLowering::SimplifiedLowering(JSGraph* jsgraph, JSHeapBroker* broker,
Zone* zone,
SourcePositionTable* source_positions,
NodeOriginTable* node_origins,
TickCounter* tick_counter,
Linkage* linkage,
ObserveNodeManager* observe_node_manager)
SimplifiedLowering::SimplifiedLowering(
JSGraph* jsgraph, JSHeapBroker* broker, Zone* zone,
SourcePositionTable* source_positions, NodeOriginTable* node_origins,
TickCounter* tick_counter, Linkage* linkage, OptimizedCompilationInfo* info,
ObserveNodeManager* observe_node_manager)
: jsgraph_(jsgraph),
broker_(broker),
zone_(zone),
......@@ -4338,6 +4368,7 @@ SimplifiedLowering::SimplifiedLowering(JSGraph* jsgraph, JSHeapBroker* broker,
node_origins_(node_origins),
tick_counter_(tick_counter),
linkage_(linkage),
info_(info),
observe_node_manager_(observe_node_manager) {}
void SimplifiedLowering::LowerAllNodes() {
......
......@@ -30,8 +30,8 @@ class V8_EXPORT_PRIVATE SimplifiedLowering final {
public:
SimplifiedLowering(JSGraph* jsgraph, JSHeapBroker* broker, Zone* zone,
SourcePositionTable* source_position,
NodeOriginTable* node_origins,
TickCounter* tick_counter, Linkage* linkage,
NodeOriginTable* node_origins, TickCounter* tick_counter,
Linkage* linkage, OptimizedCompilationInfo* info,
ObserveNodeManager* observe_node_manager = nullptr);
~SimplifiedLowering() = default;
......@@ -84,6 +84,7 @@ class V8_EXPORT_PRIVATE SimplifiedLowering final {
TickCounter* const tick_counter_;
Linkage* const linkage_;
OptimizedCompilationInfo* info_;
ObserveNodeManager* const observe_node_manager_;
......
......@@ -50,7 +50,8 @@ class SimplifiedLoweringTest : public GraphTest {
Linkage* linkage = zone()->New<Linkage>(Linkage::GetJSCallDescriptor(
zone(), false, num_parameters_ + 1, CallDescriptor::kCanUseRoots));
SimplifiedLowering lowering(jsgraph(), broker(), zone(), source_positions(),
node_origins(), tick_counter(), linkage);
node_origins(), tick_counter(), linkage,
nullptr);
lowering.LowerAllNodes();
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment