| 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
|
|
|