1 // Copyright 2014 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.
5 #include "src/compiler/pipeline.h"
7 #include "src/base/platform/elapsed-timer.h"
8 #include "src/compiler/ast-graph-builder.h"
9 #include "src/compiler/change-lowering.h"
10 #include "src/compiler/code-generator.h"
11 #include "src/compiler/graph-replay.h"
12 #include "src/compiler/graph-visualizer.h"
13 #include "src/compiler/instruction.h"
14 #include "src/compiler/instruction-selector.h"
15 #include "src/compiler/js-context-specialization.h"
16 #include "src/compiler/js-generic-lowering.h"
17 #include "src/compiler/js-inlining.h"
18 #include "src/compiler/js-typed-lowering.h"
19 #include "src/compiler/machine-operator-reducer.h"
20 #include "src/compiler/phi-reducer.h"
21 #include "src/compiler/register-allocator.h"
22 #include "src/compiler/schedule.h"
23 #include "src/compiler/scheduler.h"
24 #include "src/compiler/simplified-lowering.h"
25 #include "src/compiler/simplified-operator-reducer.h"
26 #include "src/compiler/typer.h"
27 #include "src/compiler/value-numbering-reducer.h"
28 #include "src/compiler/verifier.h"
29 #include "src/hydrogen.h"
30 #include "src/ostreams.h"
31 #include "src/utils.h"
39 enum PhaseKind { CREATE_GRAPH, OPTIMIZATION, CODEGEN };
41 PhaseStats(CompilationInfo* info, PhaseKind kind, const char* name)
45 size_(info->zone()->allocation_size()) {
46 if (FLAG_turbo_stats) {
52 if (FLAG_turbo_stats) {
53 base::TimeDelta delta = timer_.Elapsed();
54 size_t bytes = info_->zone()->allocation_size() - size_;
55 HStatistics* stats = info_->isolate()->GetTStatistics();
56 stats->SaveTiming(name_, delta, static_cast<int>(bytes));
60 stats->IncrementCreateGraph(delta);
63 stats->IncrementOptimizeGraph(delta);
66 stats->IncrementGenerateCode(delta);
73 CompilationInfo* info_;
77 base::ElapsedTimer timer_;
81 static inline bool VerifyGraphs() {
85 return FLAG_turbo_verify;
90 void Pipeline::VerifyAndPrintGraph(Graph* graph, const char* phase) {
91 if (FLAG_trace_turbo) {
93 Vector<char> filename(buffer, sizeof(buffer));
94 if (!info_->shared_info().is_null()) {
95 SmartArrayPointer<char> functionname =
96 info_->shared_info()->DebugName()->ToCString();
97 if (strlen(functionname.get()) > 0) {
98 SNPrintF(filename, "turbo-%s-%s.dot", functionname.get(), phase);
100 SNPrintF(filename, "turbo-%p-%s.dot", static_cast<void*>(info_), phase);
103 SNPrintF(filename, "turbo-none-%s.dot", phase);
105 std::replace(filename.start(), filename.start() + filename.length(), ' ',
107 FILE* file = base::OS::FOpen(filename.start(), "w+");
113 os << "-- " << phase << " graph printed to file " << filename.start()
116 if (VerifyGraphs()) Verifier::Run(graph);
120 class AstGraphBuilderWithPositions : public AstGraphBuilder {
122 explicit AstGraphBuilderWithPositions(CompilationInfo* info, JSGraph* jsgraph,
123 SourcePositionTable* source_positions)
124 : AstGraphBuilder(info, jsgraph), source_positions_(source_positions) {}
127 SourcePositionTable::Scope pos(source_positions_,
128 SourcePosition::Unknown());
129 return AstGraphBuilder::CreateGraph();
132 #define DEF_VISIT(type) \
133 virtual void Visit##type(type* node) OVERRIDE { \
134 SourcePositionTable::Scope pos(source_positions_, \
135 SourcePosition(node->position())); \
136 AstGraphBuilder::Visit##type(node); \
138 AST_NODE_LIST(DEF_VISIT)
142 SourcePositionTable* source_positions_;
146 static void TraceSchedule(Schedule* schedule) {
147 if (!FLAG_trace_turbo) return;
149 os << "-- Schedule --------------------------------------\n" << *schedule;
153 Handle<Code> Pipeline::GenerateCode() {
154 if (info()->function()->dont_optimize_reason() == kTryCatchStatement ||
155 info()->function()->dont_optimize_reason() == kTryFinallyStatement ||
156 // TODO(turbofan): Make ES6 for-of work and remove this bailout.
157 info()->function()->dont_optimize_reason() == kForOfStatement ||
158 // TODO(turbofan): Make super work and remove this bailout.
159 info()->function()->dont_optimize_reason() == kSuperReference ||
160 // TODO(turbofan): Make OSR work and remove this bailout.
162 return Handle<Code>::null();
165 if (FLAG_turbo_stats) isolate()->GetTStatistics()->Initialize(info_);
167 if (FLAG_trace_turbo) {
169 os << "---------------------------------------------------\n"
170 << "Begin compiling method "
171 << info()->function()->debug_name()->ToCString().get()
172 << " using Turbofan" << endl;
177 SourcePositionTable source_positions(&graph);
178 source_positions.AddDecorator();
179 // TODO(turbofan): there is no need to type anything during initial graph
180 // construction. This is currently only needed for the node cache, which the
181 // typer could sweep over later.
183 MachineOperatorBuilder machine;
184 CommonOperatorBuilder common(zone());
185 JSOperatorBuilder javascript(zone());
186 JSGraph jsgraph(&graph, &common, &javascript, &typer, &machine);
189 PhaseStats graph_builder_stats(info(), PhaseStats::CREATE_GRAPH,
191 AstGraphBuilderWithPositions graph_builder(info(), &jsgraph,
193 graph_builder.CreateGraph();
194 context_node = graph_builder.GetFunctionContext();
197 PhaseStats phi_reducer_stats(info(), PhaseStats::CREATE_GRAPH,
199 PhiReducer phi_reducer;
200 GraphReducer graph_reducer(&graph);
201 graph_reducer.AddReducer(&phi_reducer);
202 graph_reducer.ReduceGraph();
203 // TODO(mstarzinger): Running reducer once ought to be enough for everyone.
204 graph_reducer.ReduceGraph();
205 graph_reducer.ReduceGraph();
208 VerifyAndPrintGraph(&graph, "Initial untyped");
210 if (info()->is_context_specializing()) {
211 SourcePositionTable::Scope pos(&source_positions,
212 SourcePosition::Unknown());
213 // Specialize the code to the context as aggressively as possible.
214 JSContextSpecializer spec(info(), &jsgraph, context_node);
215 spec.SpecializeToContext();
216 VerifyAndPrintGraph(&graph, "Context specialized");
219 if (info()->is_inlining_enabled()) {
220 SourcePositionTable::Scope pos(&source_positions,
221 SourcePosition::Unknown());
222 JSInliner inliner(info(), &jsgraph);
224 VerifyAndPrintGraph(&graph, "Inlined");
227 // Print a replay of the initial graph.
228 if (FLAG_print_turbo_replay) {
229 GraphReplayPrinter::PrintReplay(&graph);
232 if (info()->is_typing_enabled()) {
235 PhaseStats typer_stats(info(), PhaseStats::CREATE_GRAPH, "typer");
236 typer.Run(&graph, info()->context());
237 VerifyAndPrintGraph(&graph, "Typed");
239 // All new nodes must be typed.
240 typer.DecorateGraph(&graph);
242 // Lower JSOperators where we can determine types.
243 PhaseStats lowering_stats(info(), PhaseStats::CREATE_GRAPH,
245 SourcePositionTable::Scope pos(&source_positions,
246 SourcePosition::Unknown());
247 JSTypedLowering lowering(&jsgraph);
248 GraphReducer graph_reducer(&graph);
249 graph_reducer.AddReducer(&lowering);
250 graph_reducer.ReduceGraph();
252 VerifyAndPrintGraph(&graph, "Lowered typed");
255 // Lower simplified operators and insert changes.
256 PhaseStats lowering_stats(info(), PhaseStats::CREATE_GRAPH,
257 "simplified lowering");
258 SourcePositionTable::Scope pos(&source_positions,
259 SourcePosition::Unknown());
260 SimplifiedLowering lowering(&jsgraph);
261 lowering.LowerAllNodes();
263 VerifyAndPrintGraph(&graph, "Lowered simplified");
266 // Lower changes that have been inserted before.
267 PhaseStats lowering_stats(info(), PhaseStats::OPTIMIZATION,
269 SourcePositionTable::Scope pos(&source_positions,
270 SourcePosition::Unknown());
271 Linkage linkage(info());
272 // TODO(turbofan): Value numbering disabled for now.
273 // ValueNumberingReducer vn_reducer(zone());
274 SimplifiedOperatorReducer simple_reducer(&jsgraph);
275 ChangeLowering lowering(&jsgraph, &linkage);
276 MachineOperatorReducer mach_reducer(&jsgraph);
277 GraphReducer graph_reducer(&graph);
278 // TODO(titzer): Figure out if we should run all reducers at once here.
279 // graph_reducer.AddReducer(&vn_reducer);
280 graph_reducer.AddReducer(&simple_reducer);
281 graph_reducer.AddReducer(&lowering);
282 graph_reducer.AddReducer(&mach_reducer);
283 graph_reducer.ReduceGraph();
285 VerifyAndPrintGraph(&graph, "Lowered changes");
289 Handle<Code> code = Handle<Code>::null();
290 if (SupportedTarget()) {
292 // Lower any remaining generic JSOperators.
293 PhaseStats lowering_stats(info(), PhaseStats::CREATE_GRAPH,
295 SourcePositionTable::Scope pos(&source_positions,
296 SourcePosition::Unknown());
297 JSGenericLowering lowering(info(), &jsgraph);
298 GraphReducer graph_reducer(&graph);
299 graph_reducer.AddReducer(&lowering);
300 graph_reducer.ReduceGraph();
302 VerifyAndPrintGraph(&graph, "Lowered generic");
306 // Compute a schedule.
307 Schedule* schedule = ComputeSchedule(&graph);
308 // Generate optimized code.
309 PhaseStats codegen_stats(info(), PhaseStats::CODEGEN, "codegen");
310 Linkage linkage(info());
311 code = GenerateCode(&linkage, &graph, schedule, &source_positions);
312 info()->SetCode(code);
315 // Print optimized code.
316 v8::internal::CodeGenerator::PrintCode(code, info());
319 if (FLAG_trace_turbo) {
321 os << "--------------------------------------------------\n"
322 << "Finished compiling method "
323 << info()->function()->debug_name()->ToCString().get()
324 << " using Turbofan" << endl;
331 Schedule* Pipeline::ComputeSchedule(Graph* graph) {
332 PhaseStats schedule_stats(info(), PhaseStats::CODEGEN, "scheduling");
333 Schedule* schedule = Scheduler::ComputeSchedule(graph);
334 TraceSchedule(schedule);
335 if (VerifyGraphs()) ScheduleVerifier::Run(schedule);
340 Handle<Code> Pipeline::GenerateCodeForMachineGraph(Linkage* linkage,
342 Schedule* schedule) {
343 CHECK(SupportedBackend());
344 if (schedule == NULL) {
345 VerifyAndPrintGraph(graph, "Machine");
346 schedule = ComputeSchedule(graph);
348 TraceSchedule(schedule);
350 SourcePositionTable source_positions(graph);
351 Handle<Code> code = GenerateCode(linkage, graph, schedule, &source_positions);
352 #if ENABLE_DISASSEMBLER
353 if (!code.is_null() && FLAG_print_opt_code) {
354 CodeTracer::Scope tracing_scope(isolate()->GetCodeTracer());
355 OFStream os(tracing_scope.file());
356 code->Disassemble("test code", os);
363 Handle<Code> Pipeline::GenerateCode(Linkage* linkage, Graph* graph,
365 SourcePositionTable* source_positions) {
366 DCHECK_NOT_NULL(graph);
367 DCHECK_NOT_NULL(linkage);
368 DCHECK_NOT_NULL(schedule);
369 CHECK(SupportedBackend());
371 InstructionSequence sequence(linkage, graph, schedule);
373 // Select and schedule instructions covering the scheduled graph.
375 InstructionSelector selector(&sequence, source_positions);
376 selector.SelectInstructions();
379 if (FLAG_trace_turbo) {
381 os << "----- Instruction sequence before register allocation -----\n"
385 // Allocate registers.
387 int node_count = graph->NodeCount();
388 if (node_count > UnallocatedOperand::kMaxVirtualRegisters) {
389 linkage->info()->AbortOptimization(kNotEnoughVirtualRegistersForValues);
390 return Handle<Code>::null();
392 RegisterAllocator allocator(&sequence);
393 if (!allocator.Allocate()) {
394 linkage->info()->AbortOptimization(kNotEnoughVirtualRegistersRegalloc);
395 return Handle<Code>::null();
399 if (FLAG_trace_turbo) {
401 os << "----- Instruction sequence after register allocation -----\n"
405 // Generate native sequence.
406 CodeGenerator generator(&sequence);
407 return generator.GenerateCode();
411 void Pipeline::SetUp() {
412 InstructionOperand::SetUpCaches();
416 void Pipeline::TearDown() {
417 InstructionOperand::TearDownCaches();
420 } // namespace compiler
421 } // namespace internal