blob: 7bfaf820ddf611b2f902ddab506bb59717f8905a [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;
Vladimir Marko55fff042014-07-10 12:42:52 +010070 case kLoopRepeatingTopologicalSortTraversal:
71 DoWalkBasicBlocks<LoopRepeatingTopologicalSortIterator>(&pass_me_data_holder_, me_pass);
72 break;
Jean Christophe Beyler2469e602014-05-06 20:36:55 -070073 case kAllNodes:
74 DoWalkBasicBlocks<AllNodesIterator>(&pass_me_data_holder_, me_pass);
75 break;
76 case kNoNodes:
77 break;
78 default:
79 LOG(FATAL) << "Iterator mode not handled in dispatcher: " << mode;
80 break;
81 }
82 }
83
84 bool RunPass(const Pass* pass, bool time_split) {
85 // Paranoid: c_unit and pass cannot be nullptr, and the pass should have a name
86 DCHECK(pass != nullptr);
87 DCHECK(pass->GetName() != nullptr && pass->GetName()[0] != 0);
88 CompilationUnit* c_unit = pass_me_data_holder_.c_unit;
89 DCHECK(c_unit != nullptr);
90
91 // Do we perform a time split
92 if (time_split) {
93 c_unit->NewTimingSplit(pass->GetName());
94 }
95
Razvan A Lupusorubd25d4b2014-07-02 18:16:51 -070096 // First, work on determining pass verbosity.
97 bool old_print_pass = c_unit->print_pass;
98 c_unit->print_pass = PassDriver<PassDriverType>::default_print_passes_;
99 const char* print_pass_list = PassDriver<PassDriverType>::print_pass_list_.c_str();
100 if (print_pass_list != nullptr && strstr(print_pass_list, pass->GetName()) != nullptr) {
101 c_unit->print_pass = true;
102 }
103
104 // Next, check if there are any overridden settings for the pass that change default configuration.
105 c_unit->overridden_pass_options.clear();
106 FillOverriddenPassSettings(pass->GetName(), c_unit->overridden_pass_options);
107 if (c_unit->print_pass) {
108 for (auto setting_it : c_unit->overridden_pass_options) {
109 LOG(INFO) << "Overridden option \"" << setting_it.first << ":"
110 << setting_it.second << "\" for pass \"" << pass->GetName() << "\"";
111 }
112 }
113
Jean Christophe Beyler2469e602014-05-06 20:36:55 -0700114 // Check the pass gate first.
115 bool should_apply_pass = pass->Gate(&pass_me_data_holder_);
116 if (should_apply_pass) {
Jean Christophe Beyler2469e602014-05-06 20:36:55 -0700117 // Applying the pass: first start, doWork, and end calls.
118 this->ApplyPass(&pass_me_data_holder_, pass);
119
120 bool should_dump = ((c_unit->enable_debug & (1 << kDebugDumpCFG)) != 0);
121
122 const char* dump_pass_list = PassDriver<PassDriverType>::dump_pass_list_.c_str();
123
124 if (dump_pass_list != nullptr) {
125 bool found = strstr(dump_pass_list, pass->GetName());
126 should_dump = (should_dump || found);
127 }
128
129 if (should_dump) {
130 // Do we want to log it?
131 if ((c_unit->enable_debug& (1 << kDebugDumpCFG)) != 0) {
132 // Do we have a pass folder?
133 const PassME* me_pass = (down_cast<const PassME*>(pass));
134 const char* passFolder = me_pass->GetDumpCFGFolder();
135 DCHECK(passFolder != nullptr);
136
137 if (passFolder[0] != 0) {
138 // Create directory prefix.
139 std::string prefix = GetDumpCFGFolder();
140 prefix += passFolder;
141 prefix += "/";
142
143 c_unit->mir_graph->DumpCFG(prefix.c_str(), false);
144 }
145 }
146 }
Jean Christophe Beyler2469e602014-05-06 20:36:55 -0700147 }
148
Razvan A Lupusorubd25d4b2014-07-02 18:16:51 -0700149 // Before wrapping up with this pass, restore old pass verbosity flag.
150 c_unit->print_pass = old_print_pass;
151
Jean Christophe Beyler2469e602014-05-06 20:36:55 -0700152 // If the pass gate passed, we can declare success.
153 return should_apply_pass;
154 }
155
156 const char* GetDumpCFGFolder() const {
157 return dump_cfg_folder_;
158 }
159
Razvan A Lupusorubd25d4b2014-07-02 18:16:51 -0700160 static void PrintPassOptions() {
161 for (auto pass : PassDriver<PassDriverType>::g_default_pass_list) {
162 const PassME* me_pass = down_cast<const PassME*>(pass);
163 if (me_pass->HasOptions()) {
164 LOG(INFO) << "Pass options for \"" << me_pass->GetName() << "\" are:";
165 SafeMap<const std::string, int> overridden_settings;
166 FillOverriddenPassSettings(me_pass->GetName(), overridden_settings);
167 me_pass->PrintPassOptions(overridden_settings);
168 }
169 }
170 }
171
James C Scott4f596682014-05-01 05:52:04 -0700172 protected:
173 /** @brief The data holder that contains data needed for the PassDriverME. */
174 PassMEDataHolder pass_me_data_holder_;
175
176 /** @brief Dump CFG base folder: where is the base folder for dumping CFGs. */
177 const char* dump_cfg_folder_;
James C Scott4f596682014-05-01 05:52:04 -0700178
Jean Christophe Beyler2469e602014-05-06 20:36:55 -0700179 static void DoWalkBasicBlocks(PassMEDataHolder* data, const PassME* pass,
180 DataflowIterator* iterator) {
181 // Paranoid: Check the iterator before walking the BasicBlocks.
182 DCHECK(iterator != nullptr);
183 bool change = false;
184 for (BasicBlock* bb = iterator->Next(change); bb != nullptr; bb = iterator->Next(change)) {
185 data->bb = bb;
186 change = pass->Worker(data);
187 }
188 }
189
190 template <typename Iterator>
191 inline static void DoWalkBasicBlocks(PassMEDataHolder* data, const PassME* pass) {
192 DCHECK(data != nullptr);
193 CompilationUnit* c_unit = data->c_unit;
194 DCHECK(c_unit != nullptr);
195 Iterator iterator(c_unit->mir_graph.get());
196 DoWalkBasicBlocks(data, pass, &iterator);
197 }
Razvan A Lupusorubd25d4b2014-07-02 18:16:51 -0700198
199 /**
200 * @brief Fills the settings_to_fill by finding all of the applicable options in the overridden_pass_options_list_.
201 * @param pass_name The pass name for which to fill settings.
202 * @param settings_to_fill Fills the options to contain the mapping of name of option to the new configuration.
203 */
204 static void FillOverriddenPassSettings(const char* pass_name, SafeMap<const std::string, int>& settings_to_fill) {
205 const std::string& settings = PassDriver<PassDriverType>::overridden_pass_options_list_;
206 const size_t settings_len = settings.size();
207
208 // Before anything, check if we care about anything right now.
209 if (settings_len == 0) {
210 return;
211 }
212
213 const size_t pass_name_len = strlen(pass_name);
214 const size_t min_setting_size = 4; // 2 delimiters, 1 setting name, 1 setting
215 size_t search_pos = 0;
216
217 // If there is no room for pass options, exit early.
218 if (settings_len < pass_name_len + min_setting_size) {
219 return;
220 }
221
222 do {
223 search_pos = settings.find(pass_name, search_pos);
224
225 // Check if we found this pass name in rest of string.
226 if (search_pos == std::string::npos) {
227 // No more settings for this pass.
228 break;
229 }
230
231 // The string contains the pass name. Now check that there is
232 // room for the settings: at least one char for setting name,
233 // two chars for two delimiter, and at least one char for setting.
234 if (search_pos + pass_name_len + min_setting_size >= settings_len) {
235 // No more settings for this pass.
236 break;
237 }
238
239 // Update the current search position to not include the pass name.
240 search_pos += pass_name_len;
241
242 // The format must be "PassName:SettingName:#" where # is the setting.
243 // Thus look for the first ":" which must exist.
244 if (settings[search_pos] != ':') {
245 // Missing delimiter right after pass name.
246 continue;
247 } else {
248 search_pos += 1;
249 }
250
251 // Now look for the actual setting by finding the next ":" delimiter.
252 const size_t setting_name_pos = search_pos;
253 size_t setting_pos = settings.find(':', setting_name_pos);
254
255 if (setting_pos == std::string::npos) {
256 // Missing a delimiter that would capture where setting starts.
257 continue;
258 } else if (setting_pos == setting_name_pos) {
259 // Missing setting thus did not move from setting name
260 continue;
261 } else {
262 // Skip the delimiter.
263 setting_pos += 1;
264 }
265
266 // Look for the terminating delimiter which must be a comma.
267 size_t next_configuration_separator = settings.find(',', setting_pos);
268 if (next_configuration_separator == std::string::npos) {
269 next_configuration_separator = settings_len;
270 }
271
272 // Prevent end of string errors.
273 if (next_configuration_separator == setting_pos) {
274 continue;
275 }
276
277 // Get the actual setting itself. Strtol is being used to convert because it is
278 // exception safe. If the input is not sane, it will set a setting of 0.
279 std::string setting_string = settings.substr(setting_pos, next_configuration_separator - setting_pos);
280 int setting = std::strtol(setting_string.c_str(), 0, 0);
281
282 std::string setting_name = settings.substr(setting_name_pos, setting_pos - setting_name_pos - 1);
283
284 settings_to_fill.Put(setting_name, setting);
285
286 search_pos = next_configuration_separator;
287 } while (true);
288 }
Jean Christophe Beyler2469e602014-05-06 20:36:55 -0700289};
James C Scott4f596682014-05-01 05:52:04 -0700290} // namespace art
291#endif // ART_COMPILER_DEX_PASS_DRIVER_ME_H_
Jean Christophe Beyler2469e602014-05-06 20:36:55 -0700292