blob: 99541acf995ffdad2c2bea6f8219d9d8d0c72100 [file] [log] [blame]
Jean Christophe Beyler4e97c532014-01-07 10:07:18 -08001/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <dlfcn.h>
18
19#include "bb_optimizations.h"
20#include "compiler_internals.h"
21#include "dataflow_iterator.h"
22#include "dataflow_iterator-inl.h"
23#include "pass.h"
24#include "pass_driver.h"
25
26namespace art {
27
28PassDriver::PassDriver(CompilationUnit* const cu, bool create_default_passes) : cu_(cu) {
29 dump_cfg_folder_ = "/sdcard/";
30
31 // If need be, create the default passes.
32 if (create_default_passes == true) {
33 CreatePasses();
34 }
35}
36
37PassDriver::~PassDriver() {
38 // Clear the map: done to remove any chance of having a pointer after freeing below
39 pass_map_.clear();
40}
41
42void PassDriver::InsertPass(Pass* new_pass, bool warn_override) {
43 assert(new_pass != 0);
44
45 // Get name here to not do it all over the method.
46 const std::string& name = new_pass->GetName();
47
48 // Do we want to warn the user about squashing a pass?
49 if (warn_override == false) {
50 SafeMap<std::string, Pass* >::iterator it = pass_map_.find(name);
51
52 if (it != pass_map_.end()) {
53 LOG(INFO) << "Pass name " << name << " already used, overwriting pass";
54 }
55 }
56
57 // Now add to map and list.
58 pass_map_.Put(name, new_pass);
59 pass_list_.push_back(new_pass);
60}
61
62void PassDriver::CreatePasses() {
63 /*
64 * Create the pass list:
65 * - These passes are immutable and are shared across the threads:
66 * - This is achieved via:
67 * - The UniquePtr used here.
68 * - DISALLOW_COPY_AND_ASSIGN in the base Pass class.
69 *
70 * Advantage is that there will be no race conditions here.
71 * Disadvantage is the passes can't change their internal states depending on CompilationUnit:
72 * - This is not yet an issue: no current pass would require it.
73 */
74 static UniquePtr<Pass> *passes[] = {
75 new UniquePtr<Pass>(new CodeLayout()),
76 new UniquePtr<Pass>(new SSATransformation()),
77 new UniquePtr<Pass>(new ConstantPropagation()),
78 new UniquePtr<Pass>(new InitRegLocations()),
79 new UniquePtr<Pass>(new MethodUseCount()),
80 new UniquePtr<Pass>(new NullCheckEliminationAndTypeInferenceInit()),
81 new UniquePtr<Pass>(new NullCheckEliminationAndTypeInference()),
82 new UniquePtr<Pass>(new BBCombine()),
83 new UniquePtr<Pass>(new BBOptimizations()),
84 };
85
86 // Get number of elements in the array.
87 unsigned int nbr = (sizeof(passes) / sizeof(passes[0]));
88
89 // Insert each pass into the map and into the list via the InsertPass method:
90 // - Map is used for the lookup
91 // - List is used for the pass walk
92 for (unsigned int i = 0; i < nbr; i++) {
93 InsertPass(passes[i]->get());
94 }
95}
96
97void PassDriver::HandlePassFlag(CompilationUnit* c_unit, Pass* pass) {
98 // Unused parameters for the moment.
99 UNUSED(c_unit);
100 UNUSED(pass);
101}
102
103void PassDriver::DispatchPass(CompilationUnit* c_unit, Pass* curPass) {
104 DataflowIterator* iterator = 0;
105
106 LOG(DEBUG) << "Dispatching " << curPass->GetName();
107
108 MIRGraph* mir_graph = c_unit->mir_graph.get();
109 ArenaAllocator *arena = &(c_unit->arena);
110
111 // Let us start by getting the right iterator.
112 DataFlowAnalysisMode mode = curPass->GetTraversal();
113
114 switch (mode) {
115 case kPreOrderDFSTraversal:
116 iterator = new (arena) PreOrderDfsIterator(mir_graph);
117 break;
118 case kRepeatingPreOrderDFSTraversal:
119 iterator = new (arena) RepeatingPreOrderDfsIterator(mir_graph);
120 break;
121 case kRepeatingPostOrderDFSTraversal:
122 iterator = new (arena) RepeatingPostOrderDfsIterator(mir_graph);
123 break;
124 case kReversePostOrderDFSTraversal:
125 iterator = new (arena) ReversePostOrderDfsIterator(mir_graph);
126 break;
127 case kRepeatingReversePostOrderDFSTraversal:
128 iterator = new (arena) RepeatingReversePostOrderDfsIterator(mir_graph);
129 break;
130 case kPostOrderDOMTraversal:
131 iterator = new (arena) PostOrderDOMIterator(mir_graph);
132 break;
133 case kAllNodes:
134 iterator = new (arena) AllNodesIterator(mir_graph);
135 break;
136 default:
137 LOG(DEBUG) << "Iterator mode not handled in dispatcher: " << mode;
138 return;
139 }
140
141 // Paranoid: Check the iterator before walking the BasicBlocks.
142 assert(iterator != 0);
143
144 bool change = false;
145 for (BasicBlock *bb = iterator->Next(change); bb != 0; bb = iterator->Next(change)) {
146 change = curPass->WalkBasicBlocks(c_unit, bb);
147 }
148}
149
150void PassDriver::ApplyPass(CompilationUnit* c_unit, Pass* curPass) {
151 curPass->Start(c_unit);
152 DispatchPass(c_unit, curPass);
153 curPass->End(c_unit);
154}
155
156bool PassDriver::RunPass(CompilationUnit* c_unit, Pass* curPass, bool time_split) {
157 // Paranoid: c_unit or curPass cannot be 0, and the pass should have a name.
158 if (c_unit == 0 || curPass == 0 || (strcmp(curPass->GetName(), "") == 0)) {
159 return false;
160 }
161
162 // Do we perform a time split
163 if (time_split == true) {
Nicolas Geoffraya3058e72014-01-15 11:44:38 +0000164 c_unit->NewTimingSplit(curPass->GetName());
Jean Christophe Beyler4e97c532014-01-07 10:07:18 -0800165 }
166
167 // Check the pass gate first.
168 bool shouldApplyPass = curPass->Gate(c_unit);
169
170 if (shouldApplyPass == true) {
171 // Applying the pass: first start, doWork, and end calls.
172 ApplyPass(c_unit, curPass);
173
174 // Clean up if need be.
175 HandlePassFlag(c_unit, curPass);
176
177 // Do we want to log it?
178 if ((c_unit->enable_debug& (1 << kDebugDumpCFG)) != 0) {
179 // Do we have a pass folder?
180 const std::string& passFolder = curPass->GetDumpCFGFolder();
181
182 if (passFolder != "") {
183 // Create directory prefix.
184 std::string prefix = GetDumpCFGFolder();
185 prefix += passFolder;
186 prefix += "/";
187
188 c_unit->mir_graph->DumpCFG(prefix.c_str(), false);
189 }
190 }
191 }
192
193 // If the pass gate passed, we can declare success.
194 return shouldApplyPass;
195}
196
197bool PassDriver::RunPass(CompilationUnit* c_unit, const std::string& pass_name) {
198 // Paranoid: c_unit cannot be 0 and we need a pass name.
199 if (c_unit == 0 || pass_name == "") {
200 return false;
201 }
202
203 Pass* curPass = GetPass(pass_name);
204
205 if (curPass != 0) {
206 return RunPass(c_unit, curPass);
207 }
208
209 // Return false, we did not find the pass.
210 return false;
211}
212
213void PassDriver::Launch() {
214 for (std::list<Pass* >::iterator it = pass_list_.begin(); it != pass_list_.end(); it++) {
215 Pass* curPass = *it;
216 RunPass(cu_, curPass, true);
217 }
218}
219
220void PassDriver::PrintPassNames() const {
221 LOG(INFO) << "Loop Passes are:";
222
223 for (std::list<Pass* >::const_iterator it = pass_list_.begin(); it != pass_list_.end(); it++) {
224 const Pass* curPass = *it;
225 LOG(INFO) << "\t-" << curPass->GetName();
226 }
227}
228
229Pass* PassDriver::GetPass(const std::string& name) const {
230 SafeMap<std::string, Pass*>::const_iterator it = pass_map_.find(name);
231
232 if (it != pass_map_.end()) {
233 return it->second;
234 }
235
236 return 0;
237}
238
239} // namespace art