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