Line data Source code
1 : // Copyright 2013 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/graph-visualizer.h"
6 :
7 : #include <memory>
8 : #include <sstream>
9 : #include <string>
10 :
11 : #include "src/code-stubs.h"
12 : #include "src/compilation-info.h"
13 : #include "src/compiler/all-nodes.h"
14 : #include "src/compiler/compiler-source-position-table.h"
15 : #include "src/compiler/graph.h"
16 : #include "src/compiler/node-properties.h"
17 : #include "src/compiler/node.h"
18 : #include "src/compiler/opcodes.h"
19 : #include "src/compiler/operator-properties.h"
20 : #include "src/compiler/operator.h"
21 : #include "src/compiler/register-allocator.h"
22 : #include "src/compiler/schedule.h"
23 : #include "src/compiler/scheduler.h"
24 : #include "src/interpreter/bytecodes.h"
25 : #include "src/objects/script-inl.h"
26 : #include "src/ostreams.h"
27 :
28 : namespace v8 {
29 : namespace internal {
30 : namespace compiler {
31 :
32 0 : std::unique_ptr<char[]> GetVisualizerLogFileName(CompilationInfo* info,
33 : const char* phase,
34 : const char* suffix) {
35 : EmbeddedVector<char, 256> filename(0);
36 0 : std::unique_ptr<char[]> debug_name = info->GetDebugName();
37 0 : int optimization_id = info->IsOptimizing() ? info->optimization_id() : 0;
38 0 : if (strlen(debug_name.get()) > 0) {
39 0 : SNPrintF(filename, "turbo-%s-%i", debug_name.get(), optimization_id);
40 0 : } else if (info->has_shared_info()) {
41 : SNPrintF(filename, "turbo-%p-%i",
42 0 : static_cast<void*>(info->shared_info()->address()),
43 0 : optimization_id);
44 : } else {
45 0 : SNPrintF(filename, "turbo-none-%i", optimization_id);
46 : }
47 : EmbeddedVector<char, 256> source_file(0);
48 : bool source_available = false;
49 0 : if (FLAG_trace_file_names && info->has_shared_info() &&
50 : info->shared_info()->script()->IsScript()) {
51 : Object* source_name = Script::cast(info->shared_info()->script())->name();
52 0 : if (source_name->IsString()) {
53 : String* str = String::cast(source_name);
54 0 : if (str->length() > 0) {
55 0 : SNPrintF(source_file, "%s", str->ToCString().get());
56 : std::replace(source_file.start(),
57 0 : source_file.start() + source_file.length(), '/', '_');
58 : source_available = true;
59 : }
60 : }
61 : }
62 0 : std::replace(filename.start(), filename.start() + filename.length(), ' ',
63 0 : '_');
64 :
65 : EmbeddedVector<char, 256> full_filename;
66 0 : if (phase == nullptr && !source_available) {
67 0 : SNPrintF(full_filename, "%s.%s", filename.start(), suffix);
68 0 : } else if (phase != nullptr && !source_available) {
69 0 : SNPrintF(full_filename, "%s-%s.%s", filename.start(), phase, suffix);
70 0 : } else if (phase == nullptr && source_available) {
71 : SNPrintF(full_filename, "%s_%s.%s", filename.start(), source_file.start(),
72 0 : suffix);
73 : } else {
74 : SNPrintF(full_filename, "%s_%s-%s.%s", filename.start(),
75 0 : source_file.start(), phase, suffix);
76 : }
77 :
78 0 : char* buffer = new char[full_filename.length() + 1];
79 0 : memcpy(buffer, full_filename.start(), full_filename.length());
80 0 : buffer[full_filename.length()] = '\0';
81 0 : return std::unique_ptr<char[]>(buffer);
82 : }
83 :
84 :
85 600 : static int SafeId(Node* node) { return node == nullptr ? -1 : node->id(); }
86 0 : static const char* SafeMnemonic(Node* node) {
87 0 : return node == nullptr ? "null" : node->op()->mnemonic();
88 : }
89 :
90 : class JSONEscaped {
91 : public:
92 : explicit JSONEscaped(const std::ostringstream& os) : str_(os.str()) {}
93 :
94 360 : friend std::ostream& operator<<(std::ostream& os, const JSONEscaped& e) {
95 4728 : for (char c : e.str_) PipeCharacter(os, c);
96 360 : return os;
97 : }
98 :
99 : private:
100 4008 : static std::ostream& PipeCharacter(std::ostream& os, char c) {
101 4008 : if (c == '"') return os << "\\\"";
102 4008 : if (c == '\\') return os << "\\\\";
103 4008 : if (c == '\b') return os << "\\b";
104 4008 : if (c == '\f') return os << "\\f";
105 4008 : if (c == '\n') return os << "\\n";
106 4008 : if (c == '\r') return os << "\\r";
107 4008 : if (c == '\t') return os << "\\t";
108 4008 : return os << c;
109 : }
110 :
111 : const std::string str_;
112 : };
113 :
114 : class JSONGraphNodeWriter {
115 : public:
116 30 : JSONGraphNodeWriter(std::ostream& os, Zone* zone, const Graph* graph,
117 : const SourcePositionTable* positions)
118 : : os_(os),
119 : all_(zone, graph, false),
120 : live_(zone, graph, true),
121 : positions_(positions),
122 30 : first_node_(true) {}
123 :
124 30 : void Print() {
125 180 : for (Node* const node : all_.reachable) PrintNode(node);
126 30 : os_ << "\n";
127 30 : }
128 :
129 840 : void PrintNode(Node* node) {
130 120 : if (first_node_) {
131 30 : first_node_ = false;
132 : } else {
133 90 : os_ << ",\n";
134 : }
135 240 : std::ostringstream label, title, properties;
136 : node->op()->PrintTo(label, Operator::PrintVerbosity::kSilent);
137 : node->op()->PrintTo(title, Operator::PrintVerbosity::kVerbose);
138 120 : node->op()->PrintPropsTo(properties);
139 240 : os_ << "{\"id\":" << SafeId(node) << ",\"label\":\"" << JSONEscaped(label)
140 120 : << "\""
141 240 : << ",\"title\":\"" << JSONEscaped(title) << "\""
142 240 : << ",\"live\": " << (live_.IsLive(node) ? "true" : "false")
143 240 : << ",\"properties\":\"" << JSONEscaped(properties) << "\"";
144 : IrOpcode::Value opcode = node->opcode();
145 120 : if (IrOpcode::IsPhiOpcode(opcode)) {
146 18 : os_ << ",\"rankInputs\":[0," << NodeProperties::FirstControlIndex(node)
147 18 : << "]";
148 18 : os_ << ",\"rankWithInput\":[" << NodeProperties::FirstControlIndex(node)
149 18 : << "]";
150 204 : } else if (opcode == IrOpcode::kIfTrue || opcode == IrOpcode::kIfFalse ||
151 102 : opcode == IrOpcode::kLoop) {
152 0 : os_ << ",\"rankInputs\":[" << NodeProperties::FirstControlIndex(node)
153 0 : << "]";
154 : }
155 120 : if (opcode == IrOpcode::kBranch) {
156 0 : os_ << ",\"rankInputs\":[0]";
157 : }
158 120 : SourcePosition position = positions_->GetSourcePosition(node);
159 120 : if (position.IsKnown()) {
160 0 : os_ << ",\"pos\":" << position.ScriptOffset();
161 : }
162 120 : os_ << ",\"opcode\":\"" << IrOpcode::Mnemonic(node->opcode()) << "\"";
163 120 : os_ << ",\"control\":" << (NodeProperties::IsControl(node) ? "true"
164 240 : : "false");
165 240 : os_ << ",\"opinfo\":\"" << node->op()->ValueInputCount() << " v "
166 240 : << node->op()->EffectInputCount() << " eff "
167 240 : << node->op()->ControlInputCount() << " ctrl in, "
168 240 : << node->op()->ValueOutputCount() << " v "
169 240 : << node->op()->EffectOutputCount() << " eff "
170 240 : << node->op()->ControlOutputCount() << " ctrl out\"";
171 120 : if (NodeProperties::IsTyped(node)) {
172 : Type* type = NodeProperties::GetType(node);
173 0 : std::ostringstream type_out;
174 0 : type->PrintTo(type_out);
175 0 : os_ << ",\"type\":\"" << JSONEscaped(type_out) << "\"";
176 : }
177 240 : os_ << "}";
178 120 : }
179 :
180 : private:
181 : std::ostream& os_;
182 : AllNodes all_;
183 : AllNodes live_;
184 : const SourcePositionTable* positions_;
185 : bool first_node_;
186 :
187 : DISALLOW_COPY_AND_ASSIGN(JSONGraphNodeWriter);
188 : };
189 :
190 :
191 : class JSONGraphEdgeWriter {
192 : public:
193 : JSONGraphEdgeWriter(std::ostream& os, Zone* zone, const Graph* graph)
194 30 : : os_(os), all_(zone, graph, false), first_edge_(true) {}
195 :
196 30 : void Print() {
197 180 : for (Node* const node : all_.reachable) PrintEdges(node);
198 30 : os_ << "\n";
199 30 : }
200 :
201 120 : void PrintEdges(Node* node) {
202 528 : for (int i = 0; i < node->InputCount(); i++) {
203 : Node* input = node->InputAt(i);
204 144 : if (input == nullptr) continue;
205 120 : PrintEdge(node, i, input);
206 : }
207 120 : }
208 :
209 120 : void PrintEdge(Node* from, int index, Node* to) {
210 120 : if (first_edge_) {
211 30 : first_edge_ = false;
212 : } else {
213 90 : os_ << ",\n";
214 : }
215 : const char* edge_type = nullptr;
216 120 : if (index < NodeProperties::FirstValueIndex(from)) {
217 : edge_type = "unknown";
218 120 : } else if (index < NodeProperties::FirstContextIndex(from)) {
219 : edge_type = "value";
220 18 : } else if (index < NodeProperties::FirstFrameStateIndex(from)) {
221 : edge_type = "context";
222 18 : } else if (index < NodeProperties::FirstEffectIndex(from)) {
223 : edge_type = "frame-state";
224 18 : } else if (index < NodeProperties::FirstControlIndex(from)) {
225 : edge_type = "effect";
226 : } else {
227 : edge_type = "control";
228 : }
229 120 : os_ << "{\"source\":" << SafeId(to) << ",\"target\":" << SafeId(from)
230 120 : << ",\"index\":" << index << ",\"type\":\"" << edge_type << "\"}";
231 120 : }
232 :
233 : private:
234 : std::ostream& os_;
235 : AllNodes all_;
236 : bool first_edge_;
237 :
238 : DISALLOW_COPY_AND_ASSIGN(JSONGraphEdgeWriter);
239 : };
240 :
241 :
242 30 : std::ostream& operator<<(std::ostream& os, const AsJSON& ad) {
243 30 : AccountingAllocator allocator;
244 60 : Zone tmp_zone(&allocator, ZONE_NAME);
245 30 : os << "{\n\"nodes\":[";
246 30 : JSONGraphNodeWriter(os, &tmp_zone, &ad.graph, ad.positions).Print();
247 30 : os << "],\n\"edges\":[";
248 60 : JSONGraphEdgeWriter(os, &tmp_zone, &ad.graph).Print();
249 30 : os << "]}";
250 30 : return os;
251 : }
252 :
253 :
254 : class GraphC1Visualizer {
255 : public:
256 : GraphC1Visualizer(std::ostream& os, Zone* zone); // NOLINT
257 :
258 : void PrintCompilation(const CompilationInfo* info);
259 : void PrintSchedule(const char* phase, const Schedule* schedule,
260 : const SourcePositionTable* positions,
261 : const InstructionSequence* instructions);
262 : void PrintLiveRanges(const char* phase, const RegisterAllocationData* data);
263 : Zone* zone() const { return zone_; }
264 :
265 : private:
266 : void PrintIndent();
267 : void PrintStringProperty(const char* name, const char* value);
268 : void PrintLongProperty(const char* name, int64_t value);
269 : void PrintIntProperty(const char* name, int value);
270 : void PrintBlockProperty(const char* name, int rpo_number);
271 : void PrintNodeId(Node* n);
272 : void PrintNode(Node* n);
273 : void PrintInputs(Node* n);
274 : template <typename InputIterator>
275 : void PrintInputs(InputIterator* i, int count, const char* prefix);
276 : void PrintType(Node* node);
277 :
278 : void PrintLiveRange(const LiveRange* range, const char* type, int vreg);
279 : void PrintLiveRangeChain(const TopLevelLiveRange* range, const char* type);
280 :
281 : class Tag final BASE_EMBEDDED {
282 : public:
283 0 : Tag(GraphC1Visualizer* visualizer, const char* name) {
284 0 : name_ = name;
285 0 : visualizer_ = visualizer;
286 : visualizer->PrintIndent();
287 0 : visualizer_->os_ << "begin_" << name << "\n";
288 0 : visualizer->indent_++;
289 0 : }
290 :
291 0 : ~Tag() {
292 0 : visualizer_->indent_--;
293 0 : visualizer_->PrintIndent();
294 0 : visualizer_->os_ << "end_" << name_ << "\n";
295 : DCHECK_LE(0, visualizer_->indent_);
296 0 : }
297 :
298 : private:
299 : GraphC1Visualizer* visualizer_;
300 : const char* name_;
301 : };
302 :
303 : std::ostream& os_;
304 : int indent_;
305 : Zone* zone_;
306 :
307 : DISALLOW_COPY_AND_ASSIGN(GraphC1Visualizer);
308 : };
309 :
310 :
311 0 : void GraphC1Visualizer::PrintIndent() {
312 0 : for (int i = 0; i < indent_; i++) {
313 0 : os_ << " ";
314 : }
315 0 : }
316 :
317 :
318 0 : GraphC1Visualizer::GraphC1Visualizer(std::ostream& os, Zone* zone)
319 0 : : os_(os), indent_(0), zone_(zone) {}
320 :
321 :
322 0 : void GraphC1Visualizer::PrintStringProperty(const char* name,
323 : const char* value) {
324 : PrintIndent();
325 0 : os_ << name << " \"" << value << "\"\n";
326 0 : }
327 :
328 :
329 0 : void GraphC1Visualizer::PrintLongProperty(const char* name, int64_t value) {
330 : PrintIndent();
331 0 : os_ << name << " " << static_cast<int>(value / 1000) << "\n";
332 0 : }
333 :
334 :
335 0 : void GraphC1Visualizer::PrintBlockProperty(const char* name, int rpo_number) {
336 : PrintIndent();
337 0 : os_ << name << " \"B" << rpo_number << "\"\n";
338 0 : }
339 :
340 :
341 0 : void GraphC1Visualizer::PrintIntProperty(const char* name, int value) {
342 : PrintIndent();
343 0 : os_ << name << " " << value << "\n";
344 0 : }
345 :
346 :
347 0 : void GraphC1Visualizer::PrintCompilation(const CompilationInfo* info) {
348 0 : Tag tag(this, "compilation");
349 0 : std::unique_ptr<char[]> name = info->GetDebugName();
350 0 : if (info->IsOptimizing()) {
351 0 : PrintStringProperty("name", name.get());
352 : PrintIndent();
353 0 : os_ << "method \"" << name.get() << ":" << info->optimization_id()
354 0 : << "\"\n";
355 : } else {
356 0 : PrintStringProperty("name", name.get());
357 0 : PrintStringProperty("method", "stub");
358 : }
359 : PrintLongProperty(
360 : "date",
361 0 : static_cast<int64_t>(V8::GetCurrentPlatform()->CurrentClockTimeMillis()));
362 0 : }
363 :
364 :
365 0 : void GraphC1Visualizer::PrintNodeId(Node* n) { os_ << "n" << SafeId(n); }
366 :
367 :
368 0 : void GraphC1Visualizer::PrintNode(Node* n) {
369 0 : PrintNodeId(n);
370 0 : os_ << " " << *n->op() << " ";
371 0 : PrintInputs(n);
372 0 : }
373 :
374 :
375 : template <typename InputIterator>
376 0 : void GraphC1Visualizer::PrintInputs(InputIterator* i, int count,
377 : const char* prefix) {
378 0 : if (count > 0) {
379 0 : os_ << prefix;
380 : }
381 0 : while (count > 0) {
382 0 : os_ << " ";
383 0 : PrintNodeId(**i);
384 : ++(*i);
385 0 : count--;
386 : }
387 0 : }
388 :
389 :
390 0 : void GraphC1Visualizer::PrintInputs(Node* node) {
391 : auto i = node->inputs().begin();
392 0 : PrintInputs(&i, node->op()->ValueInputCount(), " ");
393 : PrintInputs(&i, OperatorProperties::GetContextInputCount(node->op()),
394 0 : " Ctx:");
395 : PrintInputs(&i, OperatorProperties::GetFrameStateInputCount(node->op()),
396 0 : " FS:");
397 0 : PrintInputs(&i, node->op()->EffectInputCount(), " Eff:");
398 0 : PrintInputs(&i, node->op()->ControlInputCount(), " Ctrl:");
399 0 : }
400 :
401 :
402 0 : void GraphC1Visualizer::PrintType(Node* node) {
403 0 : if (NodeProperties::IsTyped(node)) {
404 : Type* type = NodeProperties::GetType(node);
405 0 : os_ << " type:";
406 0 : type->PrintTo(os_);
407 : }
408 0 : }
409 :
410 :
411 0 : void GraphC1Visualizer::PrintSchedule(const char* phase,
412 : const Schedule* schedule,
413 : const SourcePositionTable* positions,
414 0 : const InstructionSequence* instructions) {
415 0 : Tag tag(this, "cfg");
416 0 : PrintStringProperty("name", phase);
417 : const BasicBlockVector* rpo = schedule->rpo_order();
418 0 : for (size_t i = 0; i < rpo->size(); i++) {
419 0 : BasicBlock* current = (*rpo)[i];
420 0 : Tag block_tag(this, "block");
421 0 : PrintBlockProperty("name", current->rpo_number());
422 0 : PrintIntProperty("from_bci", -1);
423 0 : PrintIntProperty("to_bci", -1);
424 :
425 : PrintIndent();
426 0 : os_ << "predecessors";
427 0 : for (BasicBlock* predecessor : current->predecessors()) {
428 0 : os_ << " \"B" << predecessor->rpo_number() << "\"";
429 : }
430 0 : os_ << "\n";
431 :
432 : PrintIndent();
433 0 : os_ << "successors";
434 0 : for (BasicBlock* successor : current->successors()) {
435 0 : os_ << " \"B" << successor->rpo_number() << "\"";
436 : }
437 0 : os_ << "\n";
438 :
439 : PrintIndent();
440 0 : os_ << "xhandlers\n";
441 :
442 : PrintIndent();
443 0 : os_ << "flags\n";
444 :
445 0 : if (current->dominator() != nullptr) {
446 0 : PrintBlockProperty("dominator", current->dominator()->rpo_number());
447 : }
448 :
449 0 : PrintIntProperty("loop_depth", current->loop_depth());
450 :
451 0 : const InstructionBlock* instruction_block =
452 : instructions->InstructionBlockAt(
453 0 : RpoNumber::FromInt(current->rpo_number()));
454 0 : if (instruction_block->code_start() >= 0) {
455 : int first_index = instruction_block->first_instruction_index();
456 : int last_index = instruction_block->last_instruction_index();
457 : PrintIntProperty(
458 : "first_lir_id",
459 0 : LifetimePosition::GapFromInstructionIndex(first_index).value());
460 : PrintIntProperty("last_lir_id",
461 : LifetimePosition::InstructionFromInstructionIndex(
462 0 : last_index).value());
463 : }
464 :
465 : {
466 0 : Tag states_tag(this, "states");
467 0 : Tag locals_tag(this, "locals");
468 : int total = 0;
469 0 : for (BasicBlock::const_iterator i = current->begin(); i != current->end();
470 : ++i) {
471 0 : if ((*i)->opcode() == IrOpcode::kPhi) total++;
472 : }
473 0 : PrintIntProperty("size", total);
474 0 : PrintStringProperty("method", "None");
475 : int index = 0;
476 0 : for (BasicBlock::const_iterator i = current->begin(); i != current->end();
477 : ++i) {
478 0 : if ((*i)->opcode() != IrOpcode::kPhi) continue;
479 : PrintIndent();
480 0 : os_ << index << " ";
481 0 : PrintNodeId(*i);
482 0 : os_ << " [";
483 0 : PrintInputs(*i);
484 0 : os_ << "]\n";
485 0 : index++;
486 0 : }
487 : }
488 :
489 : {
490 0 : Tag HIR_tag(this, "HIR");
491 0 : for (BasicBlock::const_iterator i = current->begin(); i != current->end();
492 : ++i) {
493 0 : Node* node = *i;
494 0 : if (node->opcode() == IrOpcode::kPhi) continue;
495 0 : int uses = node->UseCount();
496 : PrintIndent();
497 0 : os_ << "0 " << uses << " ";
498 0 : PrintNode(node);
499 0 : if (FLAG_trace_turbo_types) {
500 0 : os_ << " ";
501 0 : PrintType(node);
502 : }
503 0 : if (positions != nullptr) {
504 0 : SourcePosition position = positions->GetSourcePosition(node);
505 0 : if (position.IsKnown()) {
506 0 : os_ << " pos:";
507 0 : if (position.isInlined()) {
508 0 : os_ << "inlining(" << position.InliningId() << "),";
509 : }
510 0 : os_ << position.ScriptOffset();
511 : }
512 : }
513 0 : os_ << " <|@\n";
514 : }
515 :
516 : BasicBlock::Control control = current->control();
517 0 : if (control != BasicBlock::kNone) {
518 : PrintIndent();
519 0 : os_ << "0 0 ";
520 0 : if (current->control_input() != nullptr) {
521 0 : PrintNode(current->control_input());
522 : } else {
523 0 : os_ << -1 - current->rpo_number() << " Goto";
524 : }
525 0 : os_ << " ->";
526 0 : for (BasicBlock* successor : current->successors()) {
527 0 : os_ << " B" << successor->rpo_number();
528 : }
529 0 : if (FLAG_trace_turbo_types && current->control_input() != nullptr) {
530 0 : os_ << " ";
531 0 : PrintType(current->control_input());
532 : }
533 0 : os_ << " <|@\n";
534 0 : }
535 : }
536 :
537 0 : if (instructions != nullptr) {
538 0 : Tag LIR_tag(this, "LIR");
539 0 : for (int j = instruction_block->first_instruction_index();
540 : j <= instruction_block->last_instruction_index(); j++) {
541 : PrintIndent();
542 0 : PrintableInstruction printable = {RegisterConfiguration::Default(),
543 0 : instructions->InstructionAt(j)};
544 0 : os_ << j << " " << printable << " <|@\n";
545 0 : }
546 : }
547 0 : }
548 0 : }
549 :
550 :
551 0 : void GraphC1Visualizer::PrintLiveRanges(const char* phase,
552 : const RegisterAllocationData* data) {
553 0 : Tag tag(this, "intervals");
554 0 : PrintStringProperty("name", phase);
555 :
556 0 : for (const TopLevelLiveRange* range : data->fixed_double_live_ranges()) {
557 0 : PrintLiveRangeChain(range, "fixed");
558 : }
559 :
560 0 : for (const TopLevelLiveRange* range : data->fixed_live_ranges()) {
561 0 : PrintLiveRangeChain(range, "fixed");
562 : }
563 :
564 0 : for (const TopLevelLiveRange* range : data->live_ranges()) {
565 0 : PrintLiveRangeChain(range, "object");
566 0 : }
567 0 : }
568 :
569 0 : void GraphC1Visualizer::PrintLiveRangeChain(const TopLevelLiveRange* range,
570 : const char* type) {
571 0 : if (range == nullptr || range->IsEmpty()) return;
572 : int vreg = range->vreg();
573 0 : for (const LiveRange* child = range; child != nullptr;
574 : child = child->next()) {
575 0 : PrintLiveRange(child, type, vreg);
576 : }
577 : }
578 :
579 0 : void GraphC1Visualizer::PrintLiveRange(const LiveRange* range, const char* type,
580 : int vreg) {
581 0 : if (range != nullptr && !range->IsEmpty()) {
582 : PrintIndent();
583 0 : os_ << vreg << ":" << range->relative_id() << " " << type;
584 0 : if (range->HasRegisterAssigned()) {
585 0 : AllocatedOperand op = AllocatedOperand::cast(range->GetAssignedOperand());
586 0 : const auto config = RegisterConfiguration::Default();
587 0 : if (op.IsRegister()) {
588 0 : os_ << " \"" << config->GetGeneralRegisterName(op.register_code())
589 0 : << "\"";
590 0 : } else if (op.IsDoubleRegister()) {
591 0 : os_ << " \"" << config->GetDoubleRegisterName(op.register_code())
592 0 : << "\"";
593 : } else {
594 : DCHECK(op.IsFloatRegister());
595 0 : os_ << " \"" << config->GetFloatRegisterName(op.register_code())
596 0 : << "\"";
597 : }
598 0 : } else if (range->spilled()) {
599 0 : const TopLevelLiveRange* top = range->TopLevel();
600 : int index = -1;
601 0 : if (top->HasSpillRange()) {
602 : index = kMaxInt; // This hasn't been set yet.
603 0 : } else if (top->GetSpillOperand()->IsConstant()) {
604 0 : os_ << " \"const(nostack):"
605 0 : << ConstantOperand::cast(top->GetSpillOperand())->virtual_register()
606 0 : << "\"";
607 : } else {
608 : index = AllocatedOperand::cast(top->GetSpillOperand())->index();
609 0 : if (IsFloatingPoint(top->representation())) {
610 0 : os_ << " \"fp_stack:" << index << "\"";
611 : } else {
612 0 : os_ << " \"stack:" << index << "\"";
613 : }
614 : }
615 : }
616 :
617 0 : os_ << " " << vreg;
618 0 : for (const UseInterval* interval = range->first_interval();
619 : interval != nullptr; interval = interval->next()) {
620 0 : os_ << " [" << interval->start().value() << ", "
621 0 : << interval->end().value() << "[";
622 : }
623 :
624 0 : UsePosition* current_pos = range->first_pos();
625 0 : while (current_pos != nullptr) {
626 0 : if (current_pos->RegisterIsBeneficial() || FLAG_trace_all_uses) {
627 0 : os_ << " " << current_pos->pos().value() << " M";
628 : }
629 : current_pos = current_pos->next();
630 : }
631 :
632 0 : os_ << " \"\"\n";
633 : }
634 0 : }
635 :
636 :
637 0 : std::ostream& operator<<(std::ostream& os, const AsC1VCompilation& ac) {
638 0 : AccountingAllocator allocator;
639 0 : Zone tmp_zone(&allocator, ZONE_NAME);
640 0 : GraphC1Visualizer(os, &tmp_zone).PrintCompilation(ac.info_);
641 0 : return os;
642 : }
643 :
644 :
645 0 : std::ostream& operator<<(std::ostream& os, const AsC1V& ac) {
646 0 : AccountingAllocator allocator;
647 0 : Zone tmp_zone(&allocator, ZONE_NAME);
648 : GraphC1Visualizer(os, &tmp_zone)
649 0 : .PrintSchedule(ac.phase_, ac.schedule_, ac.positions_, ac.instructions_);
650 0 : return os;
651 : }
652 :
653 :
654 0 : std::ostream& operator<<(std::ostream& os,
655 : const AsC1VRegisterAllocationData& ac) {
656 0 : AccountingAllocator allocator;
657 0 : Zone tmp_zone(&allocator, ZONE_NAME);
658 0 : GraphC1Visualizer(os, &tmp_zone).PrintLiveRanges(ac.phase_, ac.data_);
659 0 : return os;
660 : }
661 :
662 : const int kUnvisited = 0;
663 : const int kOnStack = 1;
664 : const int kVisited = 2;
665 :
666 0 : std::ostream& operator<<(std::ostream& os, const AsRPO& ar) {
667 0 : AccountingAllocator allocator;
668 0 : Zone local_zone(&allocator, ZONE_NAME);
669 :
670 : // Do a post-order depth-first search on the RPO graph. For every node,
671 : // print:
672 : //
673 : // - the node id
674 : // - the operator mnemonic
675 : // - in square brackets its parameter (if present)
676 : // - in parentheses the list of argument ids and their mnemonics
677 : // - the node type (if it is typed)
678 :
679 : // Post-order guarantees that all inputs of a node will be printed before
680 : // the node itself, if there are no cycles. Any cycles are broken
681 : // arbitrarily.
682 :
683 0 : ZoneVector<byte> state(ar.graph.NodeCount(), kUnvisited, &local_zone);
684 0 : ZoneStack<Node*> stack(&local_zone);
685 :
686 0 : stack.push(ar.graph.end());
687 0 : state[ar.graph.end()->id()] = kOnStack;
688 0 : while (!stack.empty()) {
689 0 : Node* n = stack.top();
690 : bool pop = true;
691 0 : for (Node* const i : n->inputs()) {
692 0 : if (state[i->id()] == kUnvisited) {
693 0 : state[i->id()] = kOnStack;
694 : stack.push(i);
695 : pop = false;
696 0 : break;
697 : }
698 : }
699 0 : if (pop) {
700 0 : state[n->id()] = kVisited;
701 : stack.pop();
702 0 : os << "#" << n->id() << ":" << *n->op() << "(";
703 : // Print the inputs.
704 : int j = 0;
705 0 : for (Node* const i : n->inputs()) {
706 0 : if (j++ > 0) os << ", ";
707 0 : os << "#" << SafeId(i) << ":" << SafeMnemonic(i);
708 : }
709 0 : os << ")";
710 : // Print the node type, if any.
711 0 : if (NodeProperties::IsTyped(n)) {
712 0 : os << " [Type: ";
713 0 : NodeProperties::GetType(n)->PrintTo(os);
714 0 : os << "]";
715 : }
716 : os << std::endl;
717 : }
718 : }
719 0 : return os;
720 : }
721 :
722 : namespace {
723 :
724 0 : void PrintIndent(std::ostream& os, int indent) {
725 0 : os << " ";
726 0 : for (int i = 0; i < indent; i++) {
727 0 : os << ". ";
728 : }
729 0 : }
730 :
731 0 : void PrintScheduledNode(std::ostream& os, int indent, Node* n) {
732 0 : PrintIndent(os, indent);
733 0 : os << "#" << n->id() << ":" << *n->op() << "(";
734 : // Print the inputs.
735 : int j = 0;
736 0 : for (Node* const i : n->inputs()) {
737 0 : if (j++ > 0) os << ", ";
738 0 : os << "#" << SafeId(i) << ":" << SafeMnemonic(i);
739 : }
740 0 : os << ")";
741 : // Print the node type, if any.
742 0 : if (NodeProperties::IsTyped(n)) {
743 0 : os << " [Type: ";
744 0 : NodeProperties::GetType(n)->PrintTo(os);
745 0 : os << "]";
746 : }
747 0 : }
748 :
749 0 : void PrintScheduledGraph(std::ostream& os, const Schedule* schedule) {
750 : const BasicBlockVector* rpo = schedule->rpo_order();
751 0 : for (size_t i = 0; i < rpo->size(); i++) {
752 0 : BasicBlock* current = (*rpo)[i];
753 : int indent = current->loop_depth();
754 :
755 0 : os << " + Block B" << current->rpo_number() << " (pred:";
756 0 : for (BasicBlock* predecessor : current->predecessors()) {
757 0 : os << " B" << predecessor->rpo_number();
758 : }
759 0 : if (current->IsLoopHeader()) {
760 0 : os << ", loop until B" << current->loop_end()->rpo_number();
761 0 : } else if (current->loop_header()) {
762 0 : os << ", in loop B" << current->loop_header()->rpo_number();
763 : }
764 0 : os << ")" << std::endl;
765 :
766 0 : for (BasicBlock::const_iterator i = current->begin(); i != current->end();
767 : ++i) {
768 0 : Node* node = *i;
769 0 : PrintScheduledNode(os, indent, node);
770 : os << std::endl;
771 : }
772 :
773 0 : if (current->SuccessorCount() > 0) {
774 0 : if (current->control_input() != nullptr) {
775 0 : PrintScheduledNode(os, indent, current->control_input());
776 : } else {
777 0 : PrintIndent(os, indent);
778 0 : os << "Goto";
779 : }
780 0 : os << " ->";
781 :
782 : bool isFirst = true;
783 0 : for (BasicBlock* successor : current->successors()) {
784 0 : if (isFirst) {
785 : isFirst = false;
786 : } else {
787 0 : os << ",";
788 : }
789 0 : os << " B" << successor->rpo_number();
790 : }
791 : os << std::endl;
792 : } else {
793 : DCHECK_NULL(current->control_input());
794 : }
795 : }
796 0 : }
797 :
798 : } // namespace
799 :
800 0 : std::ostream& operator<<(std::ostream& os, const AsScheduledGraph& scheduled) {
801 0 : PrintScheduledGraph(os, scheduled.schedule);
802 0 : return os;
803 : }
804 :
805 : } // namespace compiler
806 : } // namespace internal
807 : } // namespace v8
|