| OLD | NEW |
| (Empty) | |
| 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. |
| 4 |
| 5 #include "src/compiler/pipeline.h" |
| 6 |
| 7 #include "src/base/platform/elapsed-timer.h" |
| 8 #include "src/compiler/ast-graph-builder.h" |
| 9 #include "src/compiler/code-generator.h" |
| 10 #include "src/compiler/graph-replay.h" |
| 11 #include "src/compiler/graph-visualizer.h" |
| 12 #include "src/compiler/instruction-selector.h" |
| 13 #include "src/compiler/js-context-specialization.h" |
| 14 #include "src/compiler/js-generic-lowering.h" |
| 15 #include "src/compiler/js-typed-lowering.h" |
| 16 #include "src/compiler/register-allocator.h" |
| 17 #include "src/compiler/schedule.h" |
| 18 #include "src/compiler/scheduler.h" |
| 19 #include "src/compiler/simplified-lowering.h" |
| 20 #include "src/compiler/typer.h" |
| 21 #include "src/compiler/verifier.h" |
| 22 #include "src/hydrogen.h" |
| 23 #include "src/ostreams.h" |
| 24 |
| 25 namespace v8 { |
| 26 namespace internal { |
| 27 namespace compiler { |
| 28 |
| 29 class PhaseStats { |
| 30 public: |
| 31 enum PhaseKind { |
| 32 CREATE_GRAPH, |
| 33 OPTIMIZATION, |
| 34 CODEGEN |
| 35 }; |
| 36 |
| 37 PhaseStats(CompilationInfo* info, PhaseKind kind, const char* name) |
| 38 : info_(info), kind_(kind), name_(name), |
| 39 size_(info->zone()->allocation_size()) { |
| 40 if (FLAG_turbo_stats) { |
| 41 timer_.Start(); |
| 42 } |
| 43 } |
| 44 |
| 45 ~PhaseStats() { |
| 46 if (FLAG_turbo_stats) { |
| 47 base::TimeDelta delta = timer_.Elapsed(); |
| 48 size_t bytes = info_->zone()->allocation_size() - size_; |
| 49 HStatistics* stats = info_->isolate()->GetTStatistics(); |
| 50 stats->SaveTiming(name_, delta, bytes); |
| 51 |
| 52 switch (kind_) { |
| 53 case CREATE_GRAPH: stats->IncrementCreateGraph(delta); break; |
| 54 case OPTIMIZATION: stats->IncrementOptimizeGraph(delta); break; |
| 55 case CODEGEN: stats->IncrementGenerateCode(delta); break; |
| 56 } |
| 57 } |
| 58 } |
| 59 |
| 60 private: |
| 61 CompilationInfo* info_; |
| 62 PhaseKind kind_; |
| 63 const char* name_; |
| 64 size_t size_; |
| 65 base::ElapsedTimer timer_; |
| 66 }; |
| 67 |
| 68 |
| 69 void Pipeline::VerifyAndPrintGraph(Graph* graph, const char* phase) { |
| 70 if (FLAG_trace_turbo) { |
| 71 OFStream os(stdout); |
| 72 os << "-- " << phase << " graph -----------------------------------\n" |
| 73 << AsDOT(*graph); |
| 74 } |
| 75 if (VerifyGraphs()) Verifier::Run(graph); |
| 76 } |
| 77 |
| 78 |
| 79 class AstGraphBuilderWithPositions: public AstGraphBuilder { |
| 80 public: |
| 81 explicit AstGraphBuilderWithPositions(CompilationInfo* info, JSGraph* jsgraph, |
| 82 SourcePositionTable* source_positions) |
| 83 : AstGraphBuilder(info, jsgraph, source_positions) {} |
| 84 |
| 85 #define DEF_VISIT(type) \ |
| 86 virtual void Visit##type(type* node) V8_OVERRIDE { \ |
| 87 SourcePositionTable::Scope pos(source_positions(), \ |
| 88 SourcePosition(node->position())); \ |
| 89 AstGraphBuilder::Visit##type(node); \ |
| 90 } |
| 91 AST_NODE_LIST(DEF_VISIT) |
| 92 #undef DEF_VISIT |
| 93 }; |
| 94 |
| 95 |
| 96 static void TraceSchedule(Schedule* schedule) { |
| 97 if (!FLAG_trace_turbo) return; |
| 98 OFStream os(stdout); |
| 99 os << "-- Schedule --------------------------------------\n" << *schedule; |
| 100 } |
| 101 |
| 102 |
| 103 Handle<Code> Pipeline::GenerateCode() { |
| 104 if (FLAG_turbo_stats) isolate()->GetTStatistics()->Initialize(info_); |
| 105 |
| 106 if (FLAG_trace_turbo) { |
| 107 OFStream os(stdout); |
| 108 os << "---------------------------------------------------\n" |
| 109 << "Begin compiling method " |
| 110 << info()->function()->debug_name()->ToCString().get() |
| 111 << " using Turbofan" << endl; |
| 112 } |
| 113 |
| 114 // Build the graph. |
| 115 Graph graph(zone()); |
| 116 SourcePositionTable source_positions(&graph); |
| 117 source_positions.AddDecorator(); |
| 118 // TODO(turbofan): there is no need to type anything during initial graph |
| 119 // construction. This is currently only needed for the node cache, which the |
| 120 // typer could sweep over later. |
| 121 Typer typer(zone()); |
| 122 CommonOperatorBuilder common(zone()); |
| 123 JSGraph jsgraph(&graph, &common, &typer); |
| 124 Node* context_node; |
| 125 { |
| 126 PhaseStats graph_builder_stats( |
| 127 info(), PhaseStats::CREATE_GRAPH, "graph builder"); |
| 128 AstGraphBuilderWithPositions graph_builder(info(), &jsgraph, |
| 129 &source_positions); |
| 130 graph_builder.CreateGraph(); |
| 131 context_node = graph_builder.GetFunctionContext(); |
| 132 } |
| 133 |
| 134 VerifyAndPrintGraph(&graph, "Initial untyped"); |
| 135 |
| 136 if (FLAG_context_specialization) { |
| 137 SourcePositionTable::Scope pos_(&source_positions, |
| 138 SourcePosition::Unknown()); |
| 139 // Specialize the code to the context as aggressively as possible. |
| 140 JSContextSpecializer spec(info(), &jsgraph, context_node); |
| 141 spec.SpecializeToContext(); |
| 142 VerifyAndPrintGraph(&graph, "Context specialized"); |
| 143 } |
| 144 |
| 145 // Print a replay of the initial graph. |
| 146 if (FLAG_print_turbo_replay) { |
| 147 GraphReplayPrinter::PrintReplay(&graph); |
| 148 } |
| 149 |
| 150 if (FLAG_turbo_types) { |
| 151 { |
| 152 // Type the graph. |
| 153 PhaseStats typer_stats(info(), PhaseStats::CREATE_GRAPH, "typer"); |
| 154 typer.Run(&graph, info()->context()); |
| 155 } |
| 156 // All new nodes must be typed. |
| 157 typer.DecorateGraph(&graph); |
| 158 { |
| 159 // Lower JSOperators where we can determine types. |
| 160 PhaseStats lowering_stats( |
| 161 info(), PhaseStats::CREATE_GRAPH, "typed lowering"); |
| 162 JSTypedLowering lowering(&jsgraph, &source_positions); |
| 163 lowering.LowerAllNodes(); |
| 164 |
| 165 VerifyAndPrintGraph(&graph, "Lowered typed"); |
| 166 } |
| 167 } |
| 168 |
| 169 { |
| 170 // Lower any remaining generic JSOperators. |
| 171 PhaseStats lowering_stats(info(), PhaseStats::CREATE_GRAPH, |
| 172 "generic lowering"); |
| 173 MachineOperatorBuilder machine(zone()); |
| 174 JSGenericLowering lowering(info(), &jsgraph, &machine, &source_positions); |
| 175 lowering.LowerAllNodes(); |
| 176 } |
| 177 |
| 178 // Compute a schedule. |
| 179 Schedule* schedule = ComputeSchedule(&graph); |
| 180 TraceSchedule(schedule); |
| 181 |
| 182 Handle<Code> code = Handle<Code>::null(); |
| 183 if (SupportedTarget()) { |
| 184 { |
| 185 // Generate optimized code. |
| 186 PhaseStats codegen_stats(info(), PhaseStats::CODEGEN, "codegen"); |
| 187 Linkage linkage(info()); |
| 188 code = GenerateCode(&linkage, &graph, schedule, &source_positions); |
| 189 info()->SetCode(code); |
| 190 } |
| 191 // Print optimized code. |
| 192 v8::internal::CodeGenerator::PrintCode(code, info()); |
| 193 } |
| 194 |
| 195 if (FLAG_trace_turbo) { |
| 196 OFStream os(stdout); |
| 197 os << "--------------------------------------------------\n" |
| 198 << "Finished compiling method " |
| 199 << info()->function()->debug_name()->ToCString().get() |
| 200 << " using Turbofan" << endl; |
| 201 } |
| 202 |
| 203 return code; |
| 204 } |
| 205 |
| 206 |
| 207 Schedule* Pipeline::ComputeSchedule(Graph* graph) { |
| 208 Scheduler scheduler(zone()); |
| 209 PhaseStats schedule_stats(info(), PhaseStats::CODEGEN, "scheduling"); |
| 210 return scheduler.NewSchedule(graph); |
| 211 } |
| 212 |
| 213 |
| 214 Handle<Code> Pipeline::GenerateCodeForMachineGraph(Linkage* linkage, |
| 215 Graph* graph, |
| 216 Schedule* schedule) { |
| 217 CHECK(SupportedTarget()); |
| 218 if (schedule == NULL) { |
| 219 VerifyAndPrintGraph(graph, "Machine"); |
| 220 schedule = ComputeSchedule(graph); |
| 221 } |
| 222 TraceSchedule(schedule); |
| 223 |
| 224 SourcePositionTable source_positions(graph); |
| 225 Handle<Code> code = GenerateCode(linkage, graph, schedule, &source_positions); |
| 226 #if ENABLE_DISASSEMBLER |
| 227 if (!code.is_null() && FLAG_print_opt_code) { |
| 228 CodeTracer::Scope tracing_scope(isolate()->GetCodeTracer()); |
| 229 OFStream os(tracing_scope.file()); |
| 230 code->Disassemble("test code", os); |
| 231 } |
| 232 #endif |
| 233 return code; |
| 234 } |
| 235 |
| 236 |
| 237 Handle<Code> Pipeline::GenerateCode(Linkage* linkage, Graph* graph, |
| 238 Schedule* schedule, |
| 239 SourcePositionTable* source_positions) { |
| 240 ASSERT_NOT_NULL(graph); |
| 241 ASSERT_NOT_NULL(linkage); |
| 242 ASSERT_NOT_NULL(schedule); |
| 243 ASSERT(SupportedTarget()); |
| 244 |
| 245 InstructionSequence sequence(linkage, graph, schedule); |
| 246 |
| 247 // Select and schedule instructions covering the scheduled graph. |
| 248 { |
| 249 InstructionSelector selector(&sequence, source_positions); |
| 250 selector.SelectInstructions(); |
| 251 } |
| 252 |
| 253 if (FLAG_trace_turbo) { |
| 254 OFStream os(stdout); |
| 255 os << "----- Instruction sequence before register allocation -----\n" |
| 256 << sequence; |
| 257 } |
| 258 |
| 259 // Allocate registers. |
| 260 { |
| 261 int node_count = graph->NodeCount(); |
| 262 if (node_count > UnallocatedOperand::kMaxVirtualRegisters) { |
| 263 linkage->info()->set_bailout_reason(kNotEnoughVirtualRegistersForValues); |
| 264 return Handle<Code>::null(); |
| 265 } |
| 266 RegisterAllocator allocator(&sequence); |
| 267 if (!allocator.Allocate()) { |
| 268 linkage->info()->set_bailout_reason(kNotEnoughVirtualRegistersRegalloc); |
| 269 return Handle<Code>::null(); |
| 270 } |
| 271 } |
| 272 |
| 273 if (FLAG_trace_turbo) { |
| 274 OFStream os(stdout); |
| 275 os << "----- Instruction sequence after register allocation -----\n" |
| 276 << sequence; |
| 277 } |
| 278 |
| 279 // Generate native sequence. |
| 280 CodeGenerator generator(&sequence); |
| 281 return generator.GenerateCode(); |
| 282 } |
| 283 |
| 284 } // namespace compiler |
| 285 } // namespace internal |
| 286 } // namespace v8 |
| OLD | NEW |