blob: fed92be5c602243a6d549ca373db8799a0773cc1 [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:
Mathieu Chartier5bdab122015-01-26 18:30:19 -080039 explicit PassDriverME(const PassManager* const pass_manager, CompilationUnit* cu)
40 : 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 {
Jean Christophe Beyler2469e602014-05-06 20:36:55 -070091 // Paranoid: c_unit and pass cannot be nullptr, and the pass should have a name
92 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:";
168 SafeMap<const std::string, int> 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 Chartier5bdab122015-01-26 18:30:19 -0800214 static void FillOverriddenPassSettings(const PassManagerOptions* options, const char* pass_name,
215 SafeMap<const std::string, int>& settings_to_fill) {
216 const std::string& settings = options->GetOverriddenPassOptions();
Razvan A Lupusorubd25d4b2014-07-02 18:16:51 -0700217 const size_t settings_len = settings.size();
218
219 // Before anything, check if we care about anything right now.
220 if (settings_len == 0) {
221 return;
222 }
223
224 const size_t pass_name_len = strlen(pass_name);
225 const size_t min_setting_size = 4; // 2 delimiters, 1 setting name, 1 setting
226 size_t search_pos = 0;
227
228 // If there is no room for pass options, exit early.
229 if (settings_len < pass_name_len + min_setting_size) {
230 return;
231 }
232
233 do {
234 search_pos = settings.find(pass_name, search_pos);
235
236 // Check if we found this pass name in rest of string.
237 if (search_pos == std::string::npos) {
238 // No more settings for this pass.
239 break;
240 }
241
242 // The string contains the pass name. Now check that there is
243 // room for the settings: at least one char for setting name,
244 // two chars for two delimiter, and at least one char for setting.
245 if (search_pos + pass_name_len + min_setting_size >= settings_len) {
246 // No more settings for this pass.
247 break;
248 }
249
250 // Update the current search position to not include the pass name.
251 search_pos += pass_name_len;
252
253 // The format must be "PassName:SettingName:#" where # is the setting.
254 // Thus look for the first ":" which must exist.
255 if (settings[search_pos] != ':') {
256 // Missing delimiter right after pass name.
257 continue;
258 } else {
259 search_pos += 1;
260 }
261
262 // Now look for the actual setting by finding the next ":" delimiter.
263 const size_t setting_name_pos = search_pos;
264 size_t setting_pos = settings.find(':', setting_name_pos);
265
266 if (setting_pos == std::string::npos) {
267 // Missing a delimiter that would capture where setting starts.
268 continue;
269 } else if (setting_pos == setting_name_pos) {
270 // Missing setting thus did not move from setting name
271 continue;
272 } else {
273 // Skip the delimiter.
274 setting_pos += 1;
275 }
276
277 // Look for the terminating delimiter which must be a comma.
278 size_t next_configuration_separator = settings.find(',', setting_pos);
279 if (next_configuration_separator == std::string::npos) {
280 next_configuration_separator = settings_len;
281 }
282
283 // Prevent end of string errors.
284 if (next_configuration_separator == setting_pos) {
285 continue;
286 }
287
288 // Get the actual setting itself. Strtol is being used to convert because it is
289 // exception safe. If the input is not sane, it will set a setting of 0.
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 int setting = std::strtol(setting_string.c_str(), 0, 0);
293
Mathieu Chartier5bdab122015-01-26 18:30:19 -0800294 std::string setting_name =
295 settings.substr(setting_name_pos, setting_pos - setting_name_pos - 1);
Razvan A Lupusorubd25d4b2014-07-02 18:16:51 -0700296
297 settings_to_fill.Put(setting_name, setting);
298
299 search_pos = next_configuration_separator;
300 } while (true);
301 }
Jean Christophe Beyler2469e602014-05-06 20:36:55 -0700302};
James C Scott4f596682014-05-01 05:52:04 -0700303} // namespace art
304#endif // ART_COMPILER_DEX_PASS_DRIVER_ME_H_
Jean Christophe Beyler2469e602014-05-06 20:36:55 -0700305