Index: src/compiler/pipeline.cc |
diff --git a/src/compiler/pipeline.cc b/src/compiler/pipeline.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..25f0063972b09708d00fad862b337e2f6d7f50a5 |
--- /dev/null |
+++ b/src/compiler/pipeline.cc |
@@ -0,0 +1,290 @@ |
+// Copyright 2014 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/pipeline.h" |
+ |
+#include "src/base/platform/elapsed-timer.h" |
+#include "src/compiler/ast-graph-builder.h" |
+#include "src/compiler/code-generator.h" |
+#include "src/compiler/graph-replay.h" |
+#include "src/compiler/graph-visualizer.h" |
+#include "src/compiler/instruction-selector.h" |
+#include "src/compiler/js-context-specialization.h" |
+#include "src/compiler/js-generic-lowering.h" |
+#include "src/compiler/js-typed-lowering.h" |
+#include "src/compiler/register-allocator.h" |
+#include "src/compiler/schedule.h" |
+#include "src/compiler/scheduler.h" |
+#include "src/compiler/simplified-lowering.h" |
+#include "src/compiler/typer.h" |
+#include "src/compiler/verifier.h" |
+#include "src/hydrogen.h" |
+#include "src/ostreams.h" |
+ |
+namespace v8 { |
+namespace internal { |
+namespace compiler { |
+ |
+class PhaseStats { |
+ public: |
+ enum PhaseKind { CREATE_GRAPH, OPTIMIZATION, CODEGEN }; |
+ |
+ PhaseStats(CompilationInfo* info, PhaseKind kind, const char* name) |
+ : info_(info), |
+ kind_(kind), |
+ name_(name), |
+ size_(info->zone()->allocation_size()) { |
+ if (FLAG_turbo_stats) { |
+ timer_.Start(); |
+ } |
+ } |
+ |
+ ~PhaseStats() { |
+ if (FLAG_turbo_stats) { |
+ base::TimeDelta delta = timer_.Elapsed(); |
+ size_t bytes = info_->zone()->allocation_size() - size_; |
+ HStatistics* stats = info_->isolate()->GetTStatistics(); |
+ stats->SaveTiming(name_, delta, bytes); |
+ |
+ switch (kind_) { |
+ case CREATE_GRAPH: |
+ stats->IncrementCreateGraph(delta); |
+ break; |
+ case OPTIMIZATION: |
+ stats->IncrementOptimizeGraph(delta); |
+ break; |
+ case CODEGEN: |
+ stats->IncrementGenerateCode(delta); |
+ break; |
+ } |
+ } |
+ } |
+ |
+ private: |
+ CompilationInfo* info_; |
+ PhaseKind kind_; |
+ const char* name_; |
+ size_t size_; |
+ base::ElapsedTimer timer_; |
+}; |
+ |
+ |
+void Pipeline::VerifyAndPrintGraph(Graph* graph, const char* phase) { |
+ if (FLAG_trace_turbo) { |
+ OFStream os(stdout); |
+ os << "-- " << phase << " graph -----------------------------------\n" |
+ << AsDOT(*graph); |
+ } |
+ if (VerifyGraphs()) Verifier::Run(graph); |
+} |
+ |
+ |
+class AstGraphBuilderWithPositions : public AstGraphBuilder { |
+ public: |
+ explicit AstGraphBuilderWithPositions(CompilationInfo* info, JSGraph* jsgraph, |
+ SourcePositionTable* source_positions) |
+ : AstGraphBuilder(info, jsgraph, source_positions) {} |
+ |
+#define DEF_VISIT(type) \ |
+ virtual void Visit##type(type* node) V8_OVERRIDE { \ |
+ SourcePositionTable::Scope pos(source_positions(), \ |
+ SourcePosition(node->position())); \ |
+ AstGraphBuilder::Visit##type(node); \ |
+ } |
+ AST_NODE_LIST(DEF_VISIT) |
+#undef DEF_VISIT |
+}; |
+ |
+ |
+static void TraceSchedule(Schedule* schedule) { |
+ if (!FLAG_trace_turbo) return; |
+ OFStream os(stdout); |
+ os << "-- Schedule --------------------------------------\n" << *schedule; |
+} |
+ |
+ |
+Handle<Code> Pipeline::GenerateCode() { |
+ if (FLAG_turbo_stats) isolate()->GetTStatistics()->Initialize(info_); |
+ |
+ if (FLAG_trace_turbo) { |
+ OFStream os(stdout); |
+ os << "---------------------------------------------------\n" |
+ << "Begin compiling method " |
+ << info()->function()->debug_name()->ToCString().get() |
+ << " using Turbofan" << endl; |
+ } |
+ |
+ // Build the graph. |
+ Graph graph(zone()); |
+ SourcePositionTable source_positions(&graph); |
+ source_positions.AddDecorator(); |
+ // TODO(turbofan): there is no need to type anything during initial graph |
+ // construction. This is currently only needed for the node cache, which the |
+ // typer could sweep over later. |
+ Typer typer(zone()); |
+ CommonOperatorBuilder common(zone()); |
+ JSGraph jsgraph(&graph, &common, &typer); |
+ Node* context_node; |
+ { |
+ PhaseStats graph_builder_stats(info(), PhaseStats::CREATE_GRAPH, |
+ "graph builder"); |
+ AstGraphBuilderWithPositions graph_builder(info(), &jsgraph, |
+ &source_positions); |
+ graph_builder.CreateGraph(); |
+ context_node = graph_builder.GetFunctionContext(); |
+ } |
+ |
+ VerifyAndPrintGraph(&graph, "Initial untyped"); |
+ |
+ if (FLAG_context_specialization) { |
+ SourcePositionTable::Scope pos_(&source_positions, |
+ SourcePosition::Unknown()); |
+ // Specialize the code to the context as aggressively as possible. |
+ JSContextSpecializer spec(info(), &jsgraph, context_node); |
+ spec.SpecializeToContext(); |
+ VerifyAndPrintGraph(&graph, "Context specialized"); |
+ } |
+ |
+ // Print a replay of the initial graph. |
+ if (FLAG_print_turbo_replay) { |
+ GraphReplayPrinter::PrintReplay(&graph); |
+ } |
+ |
+ if (FLAG_turbo_types) { |
+ { |
+ // Type the graph. |
+ PhaseStats typer_stats(info(), PhaseStats::CREATE_GRAPH, "typer"); |
+ typer.Run(&graph, info()->context()); |
+ } |
+ // All new nodes must be typed. |
+ typer.DecorateGraph(&graph); |
+ { |
+ // Lower JSOperators where we can determine types. |
+ PhaseStats lowering_stats(info(), PhaseStats::CREATE_GRAPH, |
+ "typed lowering"); |
+ JSTypedLowering lowering(&jsgraph, &source_positions); |
+ lowering.LowerAllNodes(); |
+ |
+ VerifyAndPrintGraph(&graph, "Lowered typed"); |
+ } |
+ } |
+ |
+ { |
+ // Lower any remaining generic JSOperators. |
+ PhaseStats lowering_stats(info(), PhaseStats::CREATE_GRAPH, |
+ "generic lowering"); |
+ MachineOperatorBuilder machine(zone()); |
+ JSGenericLowering lowering(info(), &jsgraph, &machine, &source_positions); |
+ lowering.LowerAllNodes(); |
+ } |
+ |
+ // Compute a schedule. |
+ Schedule* schedule = ComputeSchedule(&graph); |
+ TraceSchedule(schedule); |
+ |
+ Handle<Code> code = Handle<Code>::null(); |
+ if (SupportedTarget()) { |
+ { |
+ // Generate optimized code. |
+ PhaseStats codegen_stats(info(), PhaseStats::CODEGEN, "codegen"); |
+ Linkage linkage(info()); |
+ code = GenerateCode(&linkage, &graph, schedule, &source_positions); |
+ info()->SetCode(code); |
+ } |
+ // Print optimized code. |
+ v8::internal::CodeGenerator::PrintCode(code, info()); |
+ } |
+ |
+ if (FLAG_trace_turbo) { |
+ OFStream os(stdout); |
+ os << "--------------------------------------------------\n" |
+ << "Finished compiling method " |
+ << info()->function()->debug_name()->ToCString().get() |
+ << " using Turbofan" << endl; |
+ } |
+ |
+ return code; |
+} |
+ |
+ |
+Schedule* Pipeline::ComputeSchedule(Graph* graph) { |
+ Scheduler scheduler(zone()); |
+ PhaseStats schedule_stats(info(), PhaseStats::CODEGEN, "scheduling"); |
+ return scheduler.NewSchedule(graph); |
+} |
+ |
+ |
+Handle<Code> Pipeline::GenerateCodeForMachineGraph(Linkage* linkage, |
+ Graph* graph, |
+ Schedule* schedule) { |
+ CHECK(SupportedTarget()); |
+ if (schedule == NULL) { |
+ VerifyAndPrintGraph(graph, "Machine"); |
+ schedule = ComputeSchedule(graph); |
+ } |
+ TraceSchedule(schedule); |
+ |
+ SourcePositionTable source_positions(graph); |
+ Handle<Code> code = GenerateCode(linkage, graph, schedule, &source_positions); |
+#if ENABLE_DISASSEMBLER |
+ if (!code.is_null() && FLAG_print_opt_code) { |
+ CodeTracer::Scope tracing_scope(isolate()->GetCodeTracer()); |
+ OFStream os(tracing_scope.file()); |
+ code->Disassemble("test code", os); |
+ } |
+#endif |
+ return code; |
+} |
+ |
+ |
+Handle<Code> Pipeline::GenerateCode(Linkage* linkage, Graph* graph, |
+ Schedule* schedule, |
+ SourcePositionTable* source_positions) { |
+ ASSERT_NOT_NULL(graph); |
+ ASSERT_NOT_NULL(linkage); |
+ ASSERT_NOT_NULL(schedule); |
+ ASSERT(SupportedTarget()); |
+ |
+ InstructionSequence sequence(linkage, graph, schedule); |
+ |
+ // Select and schedule instructions covering the scheduled graph. |
+ { |
+ InstructionSelector selector(&sequence, source_positions); |
+ selector.SelectInstructions(); |
+ } |
+ |
+ if (FLAG_trace_turbo) { |
+ OFStream os(stdout); |
+ os << "----- Instruction sequence before register allocation -----\n" |
+ << sequence; |
+ } |
+ |
+ // Allocate registers. |
+ { |
+ int node_count = graph->NodeCount(); |
+ if (node_count > UnallocatedOperand::kMaxVirtualRegisters) { |
+ linkage->info()->set_bailout_reason(kNotEnoughVirtualRegistersForValues); |
+ return Handle<Code>::null(); |
+ } |
+ RegisterAllocator allocator(&sequence); |
+ if (!allocator.Allocate()) { |
+ linkage->info()->set_bailout_reason(kNotEnoughVirtualRegistersRegalloc); |
+ return Handle<Code>::null(); |
+ } |
+ } |
+ |
+ if (FLAG_trace_turbo) { |
+ OFStream os(stdout); |
+ os << "----- Instruction sequence after register allocation -----\n" |
+ << sequence; |
+ } |
+ |
+ // Generate native sequence. |
+ CodeGenerator generator(&sequence); |
+ return generator.GenerateCode(); |
+} |
+ |
+} // namespace compiler |
+} // namespace internal |
+} // namespace v8 |