1 /* 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 20 #include <cstdlib> 21 #include <cstring> 22 23 #include "bb_optimizations.h" 24 #include "dataflow_iterator.h" 25 #include "dataflow_iterator-inl.h" 26 #include "dex_flags.h" 27 #include "pass_driver.h" 28 #include "pass_manager.h" 29 #include "pass_me.h" 30 #include "safe_map.h" 31 32 namespace art { 33 34 class PassManager; 35 class PassManagerOptions; 36 37 class PassDriverME: public PassDriver { 38 public: PassDriverME(const PassManager * const pass_manager,CompilationUnit * cu)39 explicit PassDriverME(const PassManager* const pass_manager, CompilationUnit* cu) 40 : PassDriver(pass_manager), pass_me_data_holder_(), dump_cfg_folder_("/sdcard/") { 41 pass_me_data_holder_.bb = nullptr; 42 pass_me_data_holder_.c_unit = cu; 43 } 44 ~PassDriverME()45 ~PassDriverME() { 46 } 47 DispatchPass(const Pass * pass)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; 73 case kTopologicalSortTraversal: 74 DoWalkBasicBlocks<TopologicalSortIterator>(&pass_me_data_holder_, me_pass); 75 break; 76 case kLoopRepeatingTopologicalSortTraversal: 77 DoWalkBasicBlocks<LoopRepeatingTopologicalSortIterator>(&pass_me_data_holder_, me_pass); 78 break; 79 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 RunPass(const Pass * pass,bool time_split)90 bool RunPass(const Pass* pass, bool time_split) OVERRIDE { 91 // Paranoid: c_unit and pass cannot be null, 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 102 // First, work on determining pass verbosity. 103 bool old_print_pass = c_unit->print_pass; 104 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) { 108 c_unit->print_pass = true; 109 } 110 111 // Next, check if there are any overridden settings for the pass that change default 112 // configuration. 113 c_unit->overridden_pass_options.clear(); 114 FillOverriddenPassSettings(options, pass->GetName(), c_unit->overridden_pass_options); 115 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 122 // Check the pass gate first. 123 bool should_apply_pass = pass->Gate(&pass_me_data_holder_); 124 if (should_apply_pass) { 125 // Applying the pass: first start, doWork, and end calls. 126 this->ApplyPass(&pass_me_data_holder_, pass); 127 128 bool should_dump = (c_unit->enable_debug & (1 << kDebugDumpCFG)) != 0; 129 130 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; 134 } 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 } 154 } 155 156 // Before wrapping up with this pass, restore old pass verbosity flag. 157 c_unit->print_pass = old_print_pass; 158 159 // If the pass gate passed, we can declare success. 160 return should_apply_pass; 161 } 162 PrintPassOptions(PassManager * manager)163 static void PrintPassOptions(PassManager* manager) { 164 for (const auto* pass : *manager->GetDefaultPassList()) { 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, const OptionContent> overridden_settings; 169 FillOverriddenPassSettings(&manager->GetOptions(), me_pass->GetName(), 170 overridden_settings); 171 me_pass->PrintPassOptions(overridden_settings); 172 } 173 } 174 } 175 GetDumpCFGFolder()176 const char* GetDumpCFGFolder() const { 177 return dump_cfg_folder_; 178 } 179 180 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_; 186 DoWalkBasicBlocks(PassMEDataHolder * data,const PassME * pass,DataflowIterator * iterator)187 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> DoWalkBasicBlocks(PassMEDataHolder * data,const PassME * pass)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 } 206 207 /** 208 * @brief Fills the settings_to_fill by finding all of the applicable options in the 209 * overridden_pass_options_list_. 210 * @param pass_name The pass name for which to fill settings. 211 * @param settings_to_fill Fills the options to contain the mapping of name of option to the new 212 * configuration. 213 */ FillOverriddenPassSettings(const PassManagerOptions * options,const char * pass_name,SafeMap<const std::string,const OptionContent> & settings_to_fill)214 static void FillOverriddenPassSettings( 215 const PassManagerOptions* options, const char* pass_name, 216 SafeMap<const std::string, const OptionContent>& settings_to_fill) { 217 const std::string& settings = options->GetOverriddenPassOptions(); 218 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 289 // Get the actual setting itself. 290 std::string setting_string = 291 settings.substr(setting_pos, next_configuration_separator - setting_pos); 292 293 std::string setting_name = 294 settings.substr(setting_name_pos, setting_pos - setting_name_pos - 1); 295 296 // 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. 303 304 // 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 } 311 search_pos = next_configuration_separator; 312 } while (true); 313 } 314 }; 315 } // namespace art 316 #endif // ART_COMPILER_DEX_PASS_DRIVER_ME_H_ 317 318