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