blob: d0af71c061dc1200b174a669fa023c7b59ce56cc [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>
Mathieu Chartier5bdab122015-01-26 18:30:19 -080022
James C Scott4f596682014-05-01 05:52:04 -070023#include "bb_optimizations.h"
Jean Christophe Beyler2469e602014-05-06 20:36:55 -070024#include "dataflow_iterator.h"
25#include "dataflow_iterator-inl.h"
Andreas Gampe0b9203e2015-01-22 20:39:27 -080026#include "dex_flags.h"
James C Scott4f596682014-05-01 05:52:04 -070027#include "pass_driver.h"
Mathieu Chartier5bdab122015-01-26 18:30:19 -080028#include "pass_manager.h"
James C Scott4f596682014-05-01 05:52:04 -070029#include "pass_me.h"
Mathieu Chartier5bdab122015-01-26 18:30:19 -080030#include "safe_map.h"
James C Scott4f596682014-05-01 05:52:04 -070031
32namespace art {
33
Mathieu Chartier5bdab122015-01-26 18:30:19 -080034class PassManager;
35class PassManagerOptions;
36
37class PassDriverME: public PassDriver {
James C Scott4f596682014-05-01 05:52:04 -070038 public:
Roland Levillain3887c462015-08-12 18:15:42 +010039 PassDriverME(const PassManager* const pass_manager, CompilationUnit* cu)
Mathieu Chartier5bdab122015-01-26 18:30:19 -080040 : PassDriver(pass_manager), pass_me_data_holder_(), dump_cfg_folder_("/sdcard/") {
Jean Christophe Beyler2469e602014-05-06 20:36:55 -070041 pass_me_data_holder_.bb = nullptr;
42 pass_me_data_holder_.c_unit = cu;
43 }
44
45 ~PassDriverME() {
46 }
47
48 void DispatchPass(const Pass* pass) {
49 VLOG(compiler) << "Dispatching " << pass->GetName();
50 const PassME* me_pass = down_cast<const PassME*>(pass);
51
52 DataFlowAnalysisMode mode = me_pass->GetTraversal();
53
54 switch (mode) {
55 case kPreOrderDFSTraversal:
56 DoWalkBasicBlocks<PreOrderDfsIterator>(&pass_me_data_holder_, me_pass);
57 break;
58 case kRepeatingPreOrderDFSTraversal:
59 DoWalkBasicBlocks<RepeatingPreOrderDfsIterator>(&pass_me_data_holder_, me_pass);
60 break;
61 case kRepeatingPostOrderDFSTraversal:
62 DoWalkBasicBlocks<RepeatingPostOrderDfsIterator>(&pass_me_data_holder_, me_pass);
63 break;
64 case kReversePostOrderDFSTraversal:
65 DoWalkBasicBlocks<ReversePostOrderDfsIterator>(&pass_me_data_holder_, me_pass);
66 break;
67 case kRepeatingReversePostOrderDFSTraversal:
68 DoWalkBasicBlocks<RepeatingReversePostOrderDfsIterator>(&pass_me_data_holder_, me_pass);
69 break;
70 case kPostOrderDOMTraversal:
71 DoWalkBasicBlocks<PostOrderDOMIterator>(&pass_me_data_holder_, me_pass);
72 break;
Vladimir Marko622bdbe2014-06-19 14:59:05 +010073 case kTopologicalSortTraversal:
74 DoWalkBasicBlocks<TopologicalSortIterator>(&pass_me_data_holder_, me_pass);
75 break;
Vladimir Marko55fff042014-07-10 12:42:52 +010076 case kLoopRepeatingTopologicalSortTraversal:
77 DoWalkBasicBlocks<LoopRepeatingTopologicalSortIterator>(&pass_me_data_holder_, me_pass);
78 break;
Jean Christophe Beyler2469e602014-05-06 20:36:55 -070079 case kAllNodes:
80 DoWalkBasicBlocks<AllNodesIterator>(&pass_me_data_holder_, me_pass);
81 break;
82 case kNoNodes:
83 break;
84 default:
85 LOG(FATAL) << "Iterator mode not handled in dispatcher: " << mode;
86 break;
87 }
88 }
89
Mathieu Chartier5bdab122015-01-26 18:30:19 -080090 bool RunPass(const Pass* pass, bool time_split) OVERRIDE {
Mathieu Chartier2cebb242015-04-21 16:50:40 -070091 // Paranoid: c_unit and pass cannot be null, and the pass should have a name.
Jean Christophe Beyler2469e602014-05-06 20:36:55 -070092 DCHECK(pass != nullptr);
93 DCHECK(pass->GetName() != nullptr && pass->GetName()[0] != 0);
94 CompilationUnit* c_unit = pass_me_data_holder_.c_unit;
95 DCHECK(c_unit != nullptr);
96
97 // Do we perform a time split
98 if (time_split) {
99 c_unit->NewTimingSplit(pass->GetName());
100 }
101
Razvan A Lupusorubd25d4b2014-07-02 18:16:51 -0700102 // First, work on determining pass verbosity.
103 bool old_print_pass = c_unit->print_pass;
Mathieu Chartier5bdab122015-01-26 18:30:19 -0800104 c_unit->print_pass = pass_manager_->GetOptions().GetPrintAllPasses();
105 auto* const options = &pass_manager_->GetOptions();
106 const std::string& print_pass_list = options->GetPrintPassList();
107 if (!print_pass_list.empty() && strstr(print_pass_list.c_str(), pass->GetName()) != nullptr) {
Razvan A Lupusorubd25d4b2014-07-02 18:16:51 -0700108 c_unit->print_pass = true;
109 }
110
Mathieu Chartier5bdab122015-01-26 18:30:19 -0800111 // Next, check if there are any overridden settings for the pass that change default
112 // configuration.
Razvan A Lupusorubd25d4b2014-07-02 18:16:51 -0700113 c_unit->overridden_pass_options.clear();
Mathieu Chartier5bdab122015-01-26 18:30:19 -0800114 FillOverriddenPassSettings(options, pass->GetName(), c_unit->overridden_pass_options);
Razvan A Lupusorubd25d4b2014-07-02 18:16:51 -0700115 if (c_unit->print_pass) {
116 for (auto setting_it : c_unit->overridden_pass_options) {
117 LOG(INFO) << "Overridden option \"" << setting_it.first << ":"
118 << setting_it.second << "\" for pass \"" << pass->GetName() << "\"";
119 }
120 }
121
Jean Christophe Beyler2469e602014-05-06 20:36:55 -0700122 // Check the pass gate first.
123 bool should_apply_pass = pass->Gate(&pass_me_data_holder_);
124 if (should_apply_pass) {
Jean Christophe Beyler2469e602014-05-06 20:36:55 -0700125 // Applying the pass: first start, doWork, and end calls.
126 this->ApplyPass(&pass_me_data_holder_, pass);
127
Mathieu Chartier5bdab122015-01-26 18:30:19 -0800128 bool should_dump = (c_unit->enable_debug & (1 << kDebugDumpCFG)) != 0;
Jean Christophe Beyler2469e602014-05-06 20:36:55 -0700129
Mathieu Chartier5bdab122015-01-26 18:30:19 -0800130 const std::string& dump_pass_list = pass_manager_->GetOptions().GetDumpPassList();
131 if (!dump_pass_list.empty()) {
132 const bool found = strstr(dump_pass_list.c_str(), pass->GetName());
133 should_dump = should_dump || found;
Jean Christophe Beyler2469e602014-05-06 20:36:55 -0700134 }
135
136 if (should_dump) {
137 // Do we want to log it?
138 if ((c_unit->enable_debug& (1 << kDebugDumpCFG)) != 0) {
139 // Do we have a pass folder?
140 const PassME* me_pass = (down_cast<const PassME*>(pass));
141 const char* passFolder = me_pass->GetDumpCFGFolder();
142 DCHECK(passFolder != nullptr);
143
144 if (passFolder[0] != 0) {
145 // Create directory prefix.
146 std::string prefix = GetDumpCFGFolder();
147 prefix += passFolder;
148 prefix += "/";
149
150 c_unit->mir_graph->DumpCFG(prefix.c_str(), false);
151 }
152 }
153 }
Jean Christophe Beyler2469e602014-05-06 20:36:55 -0700154 }
155
Razvan A Lupusorubd25d4b2014-07-02 18:16:51 -0700156 // Before wrapping up with this pass, restore old pass verbosity flag.
157 c_unit->print_pass = old_print_pass;
158
Jean Christophe Beyler2469e602014-05-06 20:36:55 -0700159 // If the pass gate passed, we can declare success.
160 return should_apply_pass;
161 }
162
Mathieu Chartier5bdab122015-01-26 18:30:19 -0800163 static void PrintPassOptions(PassManager* manager) {
164 for (const auto* pass : *manager->GetDefaultPassList()) {
Razvan A Lupusorubd25d4b2014-07-02 18:16:51 -0700165 const PassME* me_pass = down_cast<const PassME*>(pass);
166 if (me_pass->HasOptions()) {
167 LOG(INFO) << "Pass options for \"" << me_pass->GetName() << "\" are:";
Jean-Philippe Halimi98a26e12015-01-20 10:52:43 +0100168 SafeMap<const std::string, const OptionContent> overridden_settings;
Mathieu Chartier5bdab122015-01-26 18:30:19 -0800169 FillOverriddenPassSettings(&manager->GetOptions(), me_pass->GetName(),
170 overridden_settings);
Razvan A Lupusorubd25d4b2014-07-02 18:16:51 -0700171 me_pass->PrintPassOptions(overridden_settings);
172 }
173 }
174 }
175
Mathieu Chartier5bdab122015-01-26 18:30:19 -0800176 const char* GetDumpCFGFolder() const {
177 return dump_cfg_folder_;
178 }
179
James C Scott4f596682014-05-01 05:52:04 -0700180 protected:
181 /** @brief The data holder that contains data needed for the PassDriverME. */
182 PassMEDataHolder pass_me_data_holder_;
183
184 /** @brief Dump CFG base folder: where is the base folder for dumping CFGs. */
185 const char* dump_cfg_folder_;
James C Scott4f596682014-05-01 05:52:04 -0700186
Jean Christophe Beyler2469e602014-05-06 20:36:55 -0700187 static void DoWalkBasicBlocks(PassMEDataHolder* data, const PassME* pass,
188 DataflowIterator* iterator) {
189 // Paranoid: Check the iterator before walking the BasicBlocks.
190 DCHECK(iterator != nullptr);
191 bool change = false;
192 for (BasicBlock* bb = iterator->Next(change); bb != nullptr; bb = iterator->Next(change)) {
193 data->bb = bb;
194 change = pass->Worker(data);
195 }
196 }
197
198 template <typename Iterator>
199 inline static void DoWalkBasicBlocks(PassMEDataHolder* data, const PassME* pass) {
200 DCHECK(data != nullptr);
201 CompilationUnit* c_unit = data->c_unit;
202 DCHECK(c_unit != nullptr);
203 Iterator iterator(c_unit->mir_graph.get());
204 DoWalkBasicBlocks(data, pass, &iterator);
205 }
Razvan A Lupusorubd25d4b2014-07-02 18:16:51 -0700206
207 /**
Mathieu Chartier5bdab122015-01-26 18:30:19 -0800208 * @brief Fills the settings_to_fill by finding all of the applicable options in the
209 * overridden_pass_options_list_.
Razvan A Lupusorubd25d4b2014-07-02 18:16:51 -0700210 * @param pass_name The pass name for which to fill settings.
Mathieu Chartier5bdab122015-01-26 18:30:19 -0800211 * @param settings_to_fill Fills the options to contain the mapping of name of option to the new
212 * configuration.
Razvan A Lupusorubd25d4b2014-07-02 18:16:51 -0700213 */
Mathieu Chartier2cebb242015-04-21 16:50:40 -0700214 static void FillOverriddenPassSettings(
215 const PassManagerOptions* options, const char* pass_name,
216 SafeMap<const std::string, const OptionContent>& settings_to_fill) {
Mathieu Chartier5bdab122015-01-26 18:30:19 -0800217 const std::string& settings = options->GetOverriddenPassOptions();
Razvan A Lupusorubd25d4b2014-07-02 18:16:51 -0700218 const size_t settings_len = settings.size();
219
220 // Before anything, check if we care about anything right now.
221 if (settings_len == 0) {
222 return;
223 }
224
225 const size_t pass_name_len = strlen(pass_name);
226 const size_t min_setting_size = 4; // 2 delimiters, 1 setting name, 1 setting
227 size_t search_pos = 0;
228
229 // If there is no room for pass options, exit early.
230 if (settings_len < pass_name_len + min_setting_size) {
231 return;
232 }
233
234 do {
235 search_pos = settings.find(pass_name, search_pos);
236
237 // Check if we found this pass name in rest of string.
238 if (search_pos == std::string::npos) {
239 // No more settings for this pass.
240 break;
241 }
242
243 // The string contains the pass name. Now check that there is
244 // room for the settings: at least one char for setting name,
245 // two chars for two delimiter, and at least one char for setting.
246 if (search_pos + pass_name_len + min_setting_size >= settings_len) {
247 // No more settings for this pass.
248 break;
249 }
250
251 // Update the current search position to not include the pass name.
252 search_pos += pass_name_len;
253
254 // The format must be "PassName:SettingName:#" where # is the setting.
255 // Thus look for the first ":" which must exist.
256 if (settings[search_pos] != ':') {
257 // Missing delimiter right after pass name.
258 continue;
259 } else {
260 search_pos += 1;
261 }
262
263 // Now look for the actual setting by finding the next ":" delimiter.
264 const size_t setting_name_pos = search_pos;
265 size_t setting_pos = settings.find(':', setting_name_pos);
266
267 if (setting_pos == std::string::npos) {
268 // Missing a delimiter that would capture where setting starts.
269 continue;
270 } else if (setting_pos == setting_name_pos) {
271 // Missing setting thus did not move from setting name
272 continue;
273 } else {
274 // Skip the delimiter.
275 setting_pos += 1;
276 }
277
278 // Look for the terminating delimiter which must be a comma.
279 size_t next_configuration_separator = settings.find(',', setting_pos);
280 if (next_configuration_separator == std::string::npos) {
281 next_configuration_separator = settings_len;
282 }
283
284 // Prevent end of string errors.
285 if (next_configuration_separator == setting_pos) {
286 continue;
287 }
288
Jean-Philippe Halimi98a26e12015-01-20 10:52:43 +0100289 // Get the actual setting itself.
Mathieu Chartier5bdab122015-01-26 18:30:19 -0800290 std::string setting_string =
291 settings.substr(setting_pos, next_configuration_separator - setting_pos);
Razvan A Lupusorubd25d4b2014-07-02 18:16:51 -0700292
Mathieu Chartier5bdab122015-01-26 18:30:19 -0800293 std::string setting_name =
294 settings.substr(setting_name_pos, setting_pos - setting_name_pos - 1);
Razvan A Lupusorubd25d4b2014-07-02 18:16:51 -0700295
Jean-Philippe Halimi98a26e12015-01-20 10:52:43 +0100296 // We attempt to convert the option value to integer. Strtoll is being used to
297 // convert because it is exception safe.
298 char* end_ptr = nullptr;
299 const char* setting_ptr = setting_string.c_str();
300 DCHECK(setting_ptr != nullptr); // Paranoid: setting_ptr must be a valid pointer.
301 int64_t int_value = strtoll(setting_ptr, &end_ptr, 0);
302 DCHECK(end_ptr != nullptr); // Paranoid: end_ptr must be set by the strtoll call.
Razvan A Lupusorubd25d4b2014-07-02 18:16:51 -0700303
Jean-Philippe Halimi98a26e12015-01-20 10:52:43 +0100304 // If strtoll call succeeded, the option is now considered as integer.
305 if (*setting_ptr != '\0' && end_ptr != setting_ptr && *end_ptr == '\0') {
306 settings_to_fill.Put(setting_name, OptionContent(int_value));
307 } else {
308 // Otherwise, it is considered as a string.
309 settings_to_fill.Put(setting_name, OptionContent(setting_string.c_str()));
310 }
Razvan A Lupusorubd25d4b2014-07-02 18:16:51 -0700311 search_pos = next_configuration_separator;
312 } while (true);
313 }
Jean Christophe Beyler2469e602014-05-06 20:36:55 -0700314};
James C Scott4f596682014-05-01 05:52:04 -0700315} // namespace art
316#endif // ART_COMPILER_DEX_PASS_DRIVER_ME_H_