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