1// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
2// for details. All rights reserved. Use of this source code is governed by a
3// BSD-style license that can be found in the LICENSE file.
4
5#ifndef RUNTIME_VM_COMPILER_COMPILER_PASS_H_
6#define RUNTIME_VM_COMPILER_COMPILER_PASS_H_
7
8#if defined(DART_PRECOMPILED_RUNTIME)
9#error "AOT runtime should not use compiler sources (including header files)"
10#endif // defined(DART_PRECOMPILED_RUNTIME)
11
12#include <initializer_list>
13
14#include "vm/growable_array.h"
15#include "vm/token_position.h"
16#include "vm/zone.h"
17
18namespace dart {
19
20#define COMPILER_PASS_LIST(V) \
21 V(AllocateRegisters) \
22 V(AllocateRegistersForGraphIntrinsic) \
23 V(AllocationSinking_DetachMaterializations) \
24 V(AllocationSinking_Sink) \
25 V(ApplyClassIds) \
26 V(ApplyICData) \
27 V(BranchSimplify) \
28 V(CSE) \
29 V(Canonicalize) \
30 V(ComputeSSA) \
31 V(ConstantPropagation) \
32 V(DCE) \
33 V(DelayAllocations) \
34 V(DSE) \
35 V(EliminateDeadPhis) \
36 V(EliminateEnvironments) \
37 V(EliminateStackOverflowChecks) \
38 V(FinalizeGraph) \
39 V(IfConvert) \
40 V(Inlining) \
41 V(LICM) \
42 V(OptimisticallySpecializeSmiPhis) \
43 V(OptimizeBranches) \
44 V(OptimizeTypedDataAccesses) \
45 V(RangeAnalysis) \
46 V(ReorderBlocks) \
47 V(RoundTripSerialization) \
48 V(SelectRepresentations) \
49 V(SerializeGraph) \
50 V(SetOuterInliningId) \
51 V(TryCatchOptimization) \
52 V(TryOptimizePatterns) \
53 V(TypePropagation) \
54 V(UseTableDispatch) \
55 V(WidenSmiToInt32) \
56 V(EliminateWriteBarriers)
57
58class AllocationSinking;
59class BlockScheduler;
60class CallSpecializer;
61class FlowGraph;
62class Function;
63class Precompiler;
64class SpeculativeInliningPolicy;
65class TimelineStream;
66class Thread;
67
68struct CompilerPassState {
69 CompilerPassState(Thread* thread,
70 FlowGraph* flow_graph,
71 SpeculativeInliningPolicy* speculative_policy,
72 Precompiler* precompiler = NULL)
73 : thread(thread),
74 precompiler(precompiler),
75 inlining_depth(0),
76 sinking(NULL),
77 call_specializer(NULL),
78 speculative_policy(speculative_policy),
79 reorder_blocks(false),
80 sticky_flags(0),
81 flow_graph_(flow_graph) {}
82
83 FlowGraph* flow_graph() const { return flow_graph_; }
84
85 void set_flow_graph(FlowGraph* flow_graph);
86
87 Thread* const thread;
88 Precompiler* const precompiler;
89 int inlining_depth;
90 AllocationSinking* sinking;
91
92 // Maps inline_id_to_function[inline_id] -> function. Top scope
93 // function has inline_id 0. The map is populated by the inliner.
94 GrowableArray<const Function*> inline_id_to_function;
95 // Token position where inlining occured.
96 GrowableArray<TokenPosition> inline_id_to_token_pos;
97 // For a given inlining-id(index) specifies the caller's inlining-id.
98 GrowableArray<intptr_t> caller_inline_id;
99
100 CallSpecializer* call_specializer;
101
102 SpeculativeInliningPolicy* speculative_policy;
103
104 bool reorder_blocks;
105
106 intptr_t sticky_flags;
107
108 private:
109 FlowGraph* flow_graph_;
110};
111
112class CompilerPass {
113 public:
114 enum Id {
115#define DEF(name) k##name,
116 COMPILER_PASS_LIST(DEF)
117#undef DEF
118 };
119
120#define ADD_ONE(name) +1
121 static constexpr intptr_t kNumPasses = 0 COMPILER_PASS_LIST(ADD_ONE);
122#undef ADD_ONE
123
124 CompilerPass(Id id, const char* name) : name_(name), flags_(0) {
125 ASSERT(passes_[id] == NULL);
126 passes_[id] = this;
127
128 // By default print the final flow-graph after the register allocation.
129 if (id == kAllocateRegisters) {
130 flags_ = kTraceAfter;
131 }
132 }
133 virtual ~CompilerPass() {}
134
135 enum Flag {
136 kDisabled = 1 << 0,
137 kTraceBefore = 1 << 1,
138 kTraceAfter = 1 << 2,
139 kSticky = 1 << 3,
140 kTraceBeforeOrAfter = kTraceBefore | kTraceAfter,
141 };
142
143 void Run(CompilerPassState* state) const;
144
145 intptr_t flags() const { return flags_; }
146 const char* name() const { return name_; }
147
148 bool IsFlagSet(Flag flag) const { return (flags() & flag) != 0; }
149
150 static CompilerPass* Get(Id id) { return passes_[id]; }
151
152 static void ParseFilters(const char* filter);
153
154 enum PipelineMode { kJIT, kAOT };
155
156 static void RunGraphIntrinsicPipeline(CompilerPassState* state);
157
158 static void RunInliningPipeline(PipelineMode mode, CompilerPassState* state);
159
160 // RunPipeline(WithPasses) may have the side effect of changing the FlowGraph
161 // stored in the CompilerPassState. However, existing callers may depend on
162 // the old invariant that the FlowGraph stored in the CompilerPassState was
163 // always updated, never entirely replaced.
164 //
165 // To make sure callers are updated properly, these methods also return
166 // the final FlowGraph and we add a check that callers use this result.
167 DART_WARN_UNUSED_RESULT
168 static FlowGraph* RunPipeline(PipelineMode mode, CompilerPassState* state);
169 DART_WARN_UNUSED_RESULT
170 static FlowGraph* RunPipelineWithPasses(
171 CompilerPassState* state,
172 std::initializer_list<CompilerPass::Id> passes);
173
174 // Pipeline which is used for "force-optimized" functions.
175 //
176 // Must not include speculative or inter-procedural optimizations.
177 DART_WARN_UNUSED_RESULT
178 static FlowGraph* RunForceOptimizedPipeline(PipelineMode mode,
179 CompilerPassState* state);
180
181 protected:
182 // This function executes the pass. If it returns true then
183 // we will run Canonicalize on the graph and execute the pass
184 // again.
185 virtual bool DoBody(CompilerPassState* state) const = 0;
186
187 private:
188 static CompilerPass* FindPassByName(const char* name) {
189 for (intptr_t i = 0; i < kNumPasses; i++) {
190 if ((passes_[i] != NULL) && (strcmp(passes_[i]->name_, name) == 0)) {
191 return passes_[i];
192 }
193 }
194 return NULL;
195 }
196
197 void PrintGraph(CompilerPassState* state, Flag mask, intptr_t round) const;
198
199 static CompilerPass* passes_[];
200
201 const char* name_;
202 intptr_t flags_;
203};
204
205} // namespace dart
206
207#endif // RUNTIME_VM_COMPILER_COMPILER_PASS_H_
208