blob: 537ceb665e9bcce416e4762e0b59bc2413d847ff [file] [log] [blame]
James C Scott4f596682014-05-01 05:52:04 -07001/*
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#ifndef ART_COMPILER_DEX_PASS_DRIVER_ME_H_
18#define ART_COMPILER_DEX_PASS_DRIVER_ME_H_
19
Razvan A Lupusorubd25d4b2014-07-02 18:16:51 -070020#include <cstdlib>
21#include <cstring>
James C Scott4f596682014-05-01 05:52:04 -070022#include "bb_optimizations.h"
Jean Christophe Beyler2469e602014-05-06 20:36:55 -070023#include "dataflow_iterator.h"
24#include "dataflow_iterator-inl.h"
James C Scott4f596682014-05-01 05:52:04 -070025#include "pass_driver.h"
26#include "pass_me.h"
27
28namespace art {
29
Jean Christophe Beyler2469e602014-05-06 20:36:55 -070030template <typename PassDriverType>
31class PassDriverME: public PassDriver<PassDriverType> {
James C Scott4f596682014-05-01 05:52:04 -070032 public:
Jean Christophe Beyler2469e602014-05-06 20:36:55 -070033 explicit PassDriverME(CompilationUnit* cu)
34 : pass_me_data_holder_(), dump_cfg_folder_("/sdcard/") {
35 pass_me_data_holder_.bb = nullptr;
36 pass_me_data_holder_.c_unit = cu;
37 }
38
39 ~PassDriverME() {
40 }
41
42 void DispatchPass(const Pass* pass) {
43 VLOG(compiler) << "Dispatching " << pass->GetName();
44 const PassME* me_pass = down_cast<const PassME*>(pass);
45
46 DataFlowAnalysisMode mode = me_pass->GetTraversal();
47
48 switch (mode) {
49 case kPreOrderDFSTraversal:
50 DoWalkBasicBlocks<PreOrderDfsIterator>(&pass_me_data_holder_, me_pass);
51 break;
52 case kRepeatingPreOrderDFSTraversal:
53 DoWalkBasicBlocks<RepeatingPreOrderDfsIterator>(&pass_me_data_holder_, me_pass);
54 break;
55 case kRepeatingPostOrderDFSTraversal:
56 DoWalkBasicBlocks<RepeatingPostOrderDfsIterator>(&pass_me_data_holder_, me_pass);
57 break;
58 case kReversePostOrderDFSTraversal:
59 DoWalkBasicBlocks<ReversePostOrderDfsIterator>(&pass_me_data_holder_, me_pass);
60 break;
61 case kRepeatingReversePostOrderDFSTraversal:
62 DoWalkBasicBlocks<RepeatingReversePostOrderDfsIterator>(&pass_me_data_holder_, me_pass);
63 break;
64 case kPostOrderDOMTraversal:
65 DoWalkBasicBlocks<PostOrderDOMIterator>(&pass_me_data_holder_, me_pass);
66 break;
Vladimir Marko622bdbe2014-06-19 14:59:05 +010067 case kTopologicalSortTraversal:
68 DoWalkBasicBlocks<TopologicalSortIterator>(&pass_me_data_holder_, me_pass);
69 break;
70 case kRepeatingTopologicalSortTraversal:
71 DoWalkBasicBlocks<RepeatingTopologicalSortIterator>(&pass_me_data_holder_, me_pass);
72 break;
Vladimir Marko55fff042014-07-10 12:42:52 +010073 case kLoopRepeatingTopologicalSortTraversal:
74 DoWalkBasicBlocks<LoopRepeatingTopologicalSortIterator>(&pass_me_data_holder_, me_pass);
75 break;
Jean Christophe Beyler2469e602014-05-06 20:36:55 -070076 case kAllNodes:
77 DoWalkBasicBlocks<AllNodesIterator>(&pass_me_data_holder_, me_pass);
78 break;
79 case kNoNodes:
80 break;
81 default:
82 LOG(FATAL) << "Iterator mode not handled in dispatcher: " << mode;
83 break;
84 }
85 }
86
87 bool RunPass(const Pass* pass, bool time_split) {
88 // Paranoid: c_unit and pass cannot be nullptr, and the pass should have a name
89 DCHECK(pass != nullptr);
90 DCHECK(pass->GetName() != nullptr && pass->GetName()[0] != 0);
91 CompilationUnit* c_unit = pass_me_data_holder_.c_unit;
92 DCHECK(c_unit != nullptr);
93
94 // Do we perform a time split
95 if (time_split) {
96 c_unit->NewTimingSplit(pass->GetName());
97 }
98
Razvan A Lupusorubd25d4b2014-07-02 18:16:51 -070099 // First, work on determining pass verbosity.
100 bool old_print_pass = c_unit->print_pass;
101 c_unit->print_pass = PassDriver<PassDriverType>::default_print_passes_;
102 const char* print_pass_list = PassDriver<PassDriverType>::print_pass_list_.c_str();
103 if (print_pass_list != nullptr && strstr(print_pass_list, pass->GetName()) != nullptr) {
104 c_unit->print_pass = true;
105 }
106
107 // Next, check if there are any overridden settings for the pass that change default configuration.
108 c_unit->overridden_pass_options.clear();
109 FillOverriddenPassSettings(pass->GetName(), c_unit->overridden_pass_options);
110 if (c_unit->print_pass) {
111 for (auto setting_it : c_unit->overridden_pass_options) {
112 LOG(INFO) << "Overridden option \"" << setting_it.first << ":"
113 << setting_it.second << "\" for pass \"" << pass->GetName() << "\"";
114 }
115 }
116
Jean Christophe Beyler2469e602014-05-06 20:36:55 -0700117 // Check the pass gate first.
118 bool should_apply_pass = pass->Gate(&pass_me_data_holder_);
119 if (should_apply_pass) {
Jean Christophe Beyler2469e602014-05-06 20:36:55 -0700120 // Applying the pass: first start, doWork, and end calls.
121 this->ApplyPass(&pass_me_data_holder_, pass);
122
123 bool should_dump = ((c_unit->enable_debug & (1 << kDebugDumpCFG)) != 0);
124
125 const char* dump_pass_list = PassDriver<PassDriverType>::dump_pass_list_.c_str();
126
127 if (dump_pass_list != nullptr) {
128 bool found = strstr(dump_pass_list, pass->GetName());
129 should_dump = (should_dump || found);
130 }
131
132 if (should_dump) {
133 // Do we want to log it?
134 if ((c_unit->enable_debug& (1 << kDebugDumpCFG)) != 0) {
135 // Do we have a pass folder?
136 const PassME* me_pass = (down_cast<const PassME*>(pass));
137 const char* passFolder = me_pass->GetDumpCFGFolder();
138 DCHECK(passFolder != nullptr);
139
140 if (passFolder[0] != 0) {
141 // Create directory prefix.
142 std::string prefix = GetDumpCFGFolder();
143 prefix += passFolder;
144 prefix += "/";
145
146 c_unit->mir_graph->DumpCFG(prefix.c_str(), false);
147 }
148 }
149 }
Jean Christophe Beyler2469e602014-05-06 20:36:55 -0700150 }
151
Razvan A Lupusorubd25d4b2014-07-02 18:16:51 -0700152 // Before wrapping up with this pass, restore old pass verbosity flag.
153 c_unit->print_pass = old_print_pass;
154
Jean Christophe Beyler2469e602014-05-06 20:36:55 -0700155 // If the pass gate passed, we can declare success.
156 return should_apply_pass;
157 }
158
159 const char* GetDumpCFGFolder() const {
160 return dump_cfg_folder_;
161 }
162
Razvan A Lupusorubd25d4b2014-07-02 18:16:51 -0700163 static void PrintPassOptions() {
164 for (auto pass : PassDriver<PassDriverType>::g_default_pass_list) {
165 const PassME* me_pass = down_cast<const PassME*>(pass);
166 if (me_pass->HasOptions()) {
167 LOG(INFO) << "Pass options for \"" << me_pass->GetName() << "\" are:";
168 SafeMap<const std::string, int> overridden_settings;
169 FillOverriddenPassSettings(me_pass->GetName(), overridden_settings);
170 me_pass->PrintPassOptions(overridden_settings);
171 }
172 }
173 }
174
James C Scott4f596682014-05-01 05:52:04 -0700175 protected:
176 /** @brief The data holder that contains data needed for the PassDriverME. */
177 PassMEDataHolder pass_me_data_holder_;
178
179 /** @brief Dump CFG base folder: where is the base folder for dumping CFGs. */
180 const char* dump_cfg_folder_;
James C Scott4f596682014-05-01 05:52:04 -0700181
Jean Christophe Beyler2469e602014-05-06 20:36:55 -0700182 static void DoWalkBasicBlocks(PassMEDataHolder* data, const PassME* pass,
183 DataflowIterator* iterator) {
184 // Paranoid: Check the iterator before walking the BasicBlocks.
185 DCHECK(iterator != nullptr);
186 bool change = false;
187 for (BasicBlock* bb = iterator->Next(change); bb != nullptr; bb = iterator->Next(change)) {
188 data->bb = bb;
189 change = pass->Worker(data);
190 }
191 }
192
193 template <typename Iterator>
194 inline static void DoWalkBasicBlocks(PassMEDataHolder* data, const PassME* pass) {
195 DCHECK(data != nullptr);
196 CompilationUnit* c_unit = data->c_unit;
197 DCHECK(c_unit != nullptr);
198 Iterator iterator(c_unit->mir_graph.get());
199 DoWalkBasicBlocks(data, pass, &iterator);
200 }
Razvan A Lupusorubd25d4b2014-07-02 18:16:51 -0700201
202 /**
203 * @brief Fills the settings_to_fill by finding all of the applicable options in the overridden_pass_options_list_.
204 * @param pass_name The pass name for which to fill settings.
205 * @param settings_to_fill Fills the options to contain the mapping of name of option to the new configuration.
206 */
207 static void FillOverriddenPassSettings(const char* pass_name, SafeMap<const std::string, int>& settings_to_fill) {
208 const std::string& settings = PassDriver<PassDriverType>::overridden_pass_options_list_;
209 const size_t settings_len = settings.size();
210
211 // Before anything, check if we care about anything right now.
212 if (settings_len == 0) {
213 return;
214 }
215
216 const size_t pass_name_len = strlen(pass_name);
217 const size_t min_setting_size = 4; // 2 delimiters, 1 setting name, 1 setting
218 size_t search_pos = 0;
219
220 // If there is no room for pass options, exit early.
221 if (settings_len < pass_name_len + min_setting_size) {
222 return;
223 }
224
225 do {
226 search_pos = settings.find(pass_name, search_pos);
227
228 // Check if we found this pass name in rest of string.
229 if (search_pos == std::string::npos) {
230 // No more settings for this pass.
231 break;
232 }
233
234 // The string contains the pass name. Now check that there is
235 // room for the settings: at least one char for setting name,
236 // two chars for two delimiter, and at least one char for setting.
237 if (search_pos + pass_name_len + min_setting_size >= settings_len) {
238 // No more settings for this pass.
239 break;
240 }
241
242 // Update the current search position to not include the pass name.
243 search_pos += pass_name_len;
244
245 // The format must be "PassName:SettingName:#" where # is the setting.
246 // Thus look for the first ":" which must exist.
247 if (settings[search_pos] != ':') {
248 // Missing delimiter right after pass name.
249 continue;
250 } else {
251 search_pos += 1;
252 }
253
254 // Now look for the actual setting by finding the next ":" delimiter.
255 const size_t setting_name_pos = search_pos;
256 size_t setting_pos = settings.find(':', setting_name_pos);
257
258 if (setting_pos == std::string::npos) {
259 // Missing a delimiter that would capture where setting starts.
260 continue;
261 } else if (setting_pos == setting_name_pos) {
262 // Missing setting thus did not move from setting name
263 continue;
264 } else {
265 // Skip the delimiter.
266 setting_pos += 1;
267 }
268
269 // Look for the terminating delimiter which must be a comma.
270 size_t next_configuration_separator = settings.find(',', setting_pos);
271 if (next_configuration_separator == std::string::npos) {
272 next_configuration_separator = settings_len;
273 }
274
275 // Prevent end of string errors.
276 if (next_configuration_separator == setting_pos) {
277 continue;
278 }
279
280 // Get the actual setting itself. Strtol is being used to convert because it is
281 // exception safe. If the input is not sane, it will set a setting of 0.
282 std::string setting_string = settings.substr(setting_pos, next_configuration_separator - setting_pos);
283 int setting = std::strtol(setting_string.c_str(), 0, 0);
284
285 std::string setting_name = settings.substr(setting_name_pos, setting_pos - setting_name_pos - 1);
286
287 settings_to_fill.Put(setting_name, setting);
288
289 search_pos = next_configuration_separator;
290 } while (true);
291 }
Jean Christophe Beyler2469e602014-05-06 20:36:55 -0700292};
James C Scott4f596682014-05-01 05:52:04 -0700293} // namespace art
294#endif // ART_COMPILER_DEX_PASS_DRIVER_ME_H_
Jean Christophe Beyler2469e602014-05-06 20:36:55 -0700295