1 /** 2 * Copyright (c) 2021-2022 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16 #ifndef COMPILER_TOOLS_PAOC_PAOC_CLUSTERS_H 17 #define COMPILER_TOOLS_PAOC_PAOC_CLUSTERS_H 18 19 #include <unordered_map> 20 #include <string_view> 21 #include <string> 22 23 #include "utils/json_parser.h" 24 #include "utils/pandargs.h" 25 #include "utils/logger.h" 26 27 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) 28 #define LOG_PAOC_CLUSTERS(level) LOG(level, COMPILER) << "PAOC_CLUSTERS: " 29 30 namespace panda { 31 32 /** 33 * Implements `--paoc-clusters` option. 34 * Stores clusters themselves and "function:cluster" relations 35 */ 36 class PaocClusters { 37 using JsonObjPointer = JsonObject::JsonObjPointer; 38 using StringT = JsonObject::StringT; 39 using ArrayT = JsonObject::ArrayT; 40 using NumT = JsonObject::NumT; 41 using Key = JsonObject::Key; 42 43 public: 44 static constexpr std::string_view CLUSTERS_MAP_OBJ_NAME {"clusters_map"}; // Contains `method-clusters` relations 45 static constexpr std::string_view CLUSTERS_OBJ_NAME {"compiler_options"}; // Contains `cluster-options` relations 46 class OptionsCluster; 47 Find(const std::string & method)48 const std::vector<OptionsCluster *> *Find(const std::string &method) 49 { 50 auto iter = special_options_.find(method); 51 if (iter == special_options_.end()) { 52 return nullptr; 53 } 54 LOG_PAOC_CLUSTERS(INFO) << "Found clusters for method `" << method << "`"; 55 return &iter->second; 56 } 57 Init(const JsonObject & obj,PandArgParser * pa_parser)58 void Init(const JsonObject &obj, PandArgParser *pa_parser) 59 { 60 ASSERT(pa_parser != nullptr); 61 InitClusters(obj, pa_parser); 62 InitClustersMap(obj); 63 } 64 InitClusters(const JsonObject & main_obj,PandArgParser * pa_parser)65 void InitClusters(const JsonObject &main_obj, PandArgParser *pa_parser) 66 { 67 if (main_obj.GetValue<JsonObjPointer>(Key(CLUSTERS_OBJ_NAME)) == nullptr) { 68 LOG_PAOC_CLUSTERS(FATAL) << "Can't find `" << CLUSTERS_OBJ_NAME << "` object"; 69 } 70 const auto clusters_json = main_obj.GetValue<JsonObjPointer>(Key(CLUSTERS_OBJ_NAME))->get(); 71 72 // Fill clusters_ in order of presence in JSON-obj: 73 size_t n_clusters = clusters_json->GetSize(); 74 for (size_t idx = 0; idx < n_clusters; idx++) { 75 const auto cluster_json = clusters_json->GetValue<JsonObjPointer>(idx)->get(); 76 if (cluster_json == nullptr) { 77 LOG_PAOC_CLUSTERS(FATAL) << "Can't find a cluster (idx = " << idx << ")"; 78 } 79 clusters_.emplace_back(clusters_json->GetKeyByIndex(idx)); 80 81 // Fill current cluster: 82 const auto &options_json = cluster_json->GetUnorderedMap(); 83 // Add option-value pair: 84 for (const auto &p : options_json) { 85 const auto &option_name = p.first; 86 const auto *option_value = cluster_json->GetValueSourceString(option_name); 87 if (option_value == nullptr || option_value->empty()) { 88 LOG_PAOC_CLUSTERS(FATAL) 89 << "Can't find option's value (cluster `" << clusters_json->GetKeyByIndex(idx) << "`, option `" 90 << option_name << "`)"; 91 } 92 93 auto *option = pa_parser->GetPandArg(option_name); 94 if (option == nullptr) { 95 LOG_PAOC_CLUSTERS(FATAL) << "Unknown option: `" << option_name << "`"; 96 } 97 auto value = OptionsCluster::ParseOptionValue(*option_value, option, pa_parser); 98 clusters_.back().GetVector().emplace_back(option, std::move(value)); 99 } 100 } 101 } 102 InitClustersMap(const JsonObject & main_obj)103 void InitClustersMap(const JsonObject &main_obj) 104 { 105 if (main_obj.GetValue<JsonObjPointer>(Key(CLUSTERS_MAP_OBJ_NAME)) == nullptr) { 106 LOG_PAOC_CLUSTERS(FATAL) << "Can't find `" << CLUSTERS_MAP_OBJ_NAME << "` object"; 107 } 108 const auto clusters_map_json = main_obj.GetValue<JsonObjPointer>(Key(CLUSTERS_MAP_OBJ_NAME))->get(); 109 110 // Fill special_options_: 111 for (const auto &p : clusters_map_json->GetUnorderedMap()) { 112 const auto &method_name = p.first; 113 const auto &clusters_array = p.second; 114 const auto *cur_clusters_json = clusters_array.Get<ArrayT>(); 115 116 if (cur_clusters_json == nullptr) { 117 LOG_PAOC_CLUSTERS(FATAL) << "Can't get clusters array for method `" << method_name << "`"; 118 } 119 auto &cur_clusters = special_options_.try_emplace(method_name).first->second; 120 for (const auto &idx : *cur_clusters_json) { 121 // Cluster may be referenced by integer number (cluster's order) or string (cluster's name): 122 const auto *num_idx = idx.Get<NumT>(); 123 const auto *str_idx = idx.Get<StringT>(); 124 size_t cluster_idx = 0; 125 if (num_idx != nullptr) { 126 cluster_idx = static_cast<size_t>(*num_idx); 127 } else if (str_idx != nullptr) { 128 const auto clusters_json = main_obj.GetValue<JsonObjPointer>(Key(CLUSTERS_OBJ_NAME))->get(); 129 cluster_idx = static_cast<size_t>(clusters_json->GetIndexByKey(*str_idx)); 130 ASSERT(cluster_idx != static_cast<size_t>(-1)); 131 } else { 132 LOG_PAOC_CLUSTERS(FATAL) << "Incorrect reference to a cluster for `" << method_name << "`"; 133 UNREACHABLE(); 134 } 135 if (cluster_idx >= clusters_.size()) { 136 LOG_PAOC_CLUSTERS(FATAL) << "Cluster's index out of range for `" << method_name << "`"; 137 } 138 cur_clusters.push_back(&clusters_[cluster_idx]); 139 ASSERT(cur_clusters.back() != nullptr); 140 } 141 } 142 } 143 144 /** 145 * Implements a cluster and contains info related to it. 146 * (i.e. vector of "option:alternative_value" pairs) 147 */ 148 class OptionsCluster { 149 public: 150 // Variant of possible PandArg types: 151 using ValueVariant = std::variant<std::string, int, double, bool, arg_list_t, uint32_t, uint64_t>; 152 153 // NOLINTNEXTLINE(modernize-pass-by-value) OptionsCluster(const std::string & cluster_name)154 explicit OptionsCluster(const std::string &cluster_name) : cluster_name_(cluster_name) {} 155 Apply()156 void Apply() 157 { 158 for (auto &pair_option_value : cluster_) { 159 SwapValue(pair_option_value.first, &pair_option_value.second); 160 } 161 } Restore()162 void Restore() 163 { 164 for (auto &pair_option_value : cluster_) { 165 SwapValue(pair_option_value.first, &pair_option_value.second); 166 } 167 } 168 ParseOptionValue(const std::string_view & value_string,PandArgBase * option,PandArgParser * pa_parser)169 static ValueVariant ParseOptionValue(const std::string_view &value_string, PandArgBase *option, 170 PandArgParser *pa_parser) 171 { 172 switch (option->GetType()) { 173 case PandArgType::STRING: 174 return ParseOptionValue<std::string>(value_string, option, pa_parser); 175 176 case PandArgType::INTEGER: 177 return ParseOptionValue<int>(value_string, option, pa_parser); 178 179 case PandArgType::DOUBLE: 180 return ParseOptionValue<double>(value_string, option, pa_parser); 181 182 case PandArgType::BOOL: 183 return ParseOptionValue<bool>(value_string, option, pa_parser); 184 185 case PandArgType::LIST: 186 return ParseOptionValue<arg_list_t>(value_string, option, pa_parser); 187 188 case PandArgType::UINT32: 189 return ParseOptionValue<uint32_t>(value_string, option, pa_parser); 190 191 case PandArgType::UINT64: 192 return ParseOptionValue<uint64_t>(value_string, option, pa_parser); 193 194 case PandArgType::NOTYPE: 195 default: 196 UNREACHABLE(); 197 } 198 } 199 GetVector()200 std::vector<std::pair<PandArgBase *const, ValueVariant>> &GetVector() 201 { 202 return cluster_; 203 } 204 205 private: 206 template <typename T> ParseOptionValue(const std::string_view & value_string,PandArgBase * option_base,PandArgParser * pa_parser)207 static ValueVariant ParseOptionValue(const std::string_view &value_string, PandArgBase *option_base, 208 PandArgParser *pa_parser) 209 { 210 ASSERT(option_base != nullptr); 211 auto option = static_cast<PandArg<T> *>(option_base); 212 auto option_copy = *option; 213 pa_parser->ParseSingleArg(&option_copy, value_string); 214 return option_copy.GetValue(); 215 } 216 SwapValue(PandArgBase * option,ValueVariant * value)217 void SwapValue(PandArgBase *option, ValueVariant *value) 218 { 219 PandArgType type_id {static_cast<uint8_t>(value->index())}; 220 switch (type_id) { 221 case PandArgType::STRING: 222 SwapValue<std::string>(option, value); 223 return; 224 case PandArgType::INTEGER: 225 SwapValue<int>(option, value); 226 return; 227 case PandArgType::DOUBLE: 228 SwapValue<double>(option, value); 229 return; 230 case PandArgType::BOOL: 231 SwapValue<bool>(option, value); 232 return; 233 case PandArgType::LIST: 234 SwapValue<arg_list_t>(option, value); 235 return; 236 case PandArgType::UINT32: 237 SwapValue<uint32_t>(option, value); 238 return; 239 case PandArgType::UINT64: 240 SwapValue<uint64_t>(option, value); 241 return; 242 case PandArgType::NOTYPE: 243 default: 244 UNREACHABLE(); 245 } 246 } 247 248 template <typename T> SwapValue(PandArgBase * option_base,ValueVariant * value)249 void SwapValue(PandArgBase *option_base, ValueVariant *value) 250 { 251 auto *option = static_cast<PandArg<T> *>(option_base); 252 T temp(option->GetValue()); 253 ASSERT(std::holds_alternative<T>(*value)); 254 option->template SetValue<false>(*std::get_if<T>(value)); 255 *value = std::move(temp); 256 } 257 258 private: 259 std::string cluster_name_; 260 std::vector<std::pair<PandArgBase *const, ValueVariant>> cluster_; 261 }; 262 263 /** 264 * Searches for a cluster for the specified method in @param clusters_info and applies it to the compiler. 265 * On destruction, restores previously applied options. 266 */ 267 class ScopedApplySpecialOptions { 268 public: 269 NO_COPY_SEMANTIC(ScopedApplySpecialOptions); 270 NO_MOVE_SEMANTIC(ScopedApplySpecialOptions); 271 ScopedApplySpecialOptions(const std::string & method,PaocClusters * clusters_info)272 explicit ScopedApplySpecialOptions(const std::string &method, PaocClusters *clusters_info) 273 { 274 // Find clusters for required method: 275 current_clusters_ = clusters_info->Find(method); 276 if (current_clusters_ == nullptr) { 277 return; 278 } 279 // Apply clusters: 280 for (auto cluster : *current_clusters_) { 281 cluster->Apply(); 282 } 283 } ~ScopedApplySpecialOptions()284 ~ScopedApplySpecialOptions() 285 { 286 if (current_clusters_ != nullptr) { 287 for (auto cluster : *current_clusters_) { 288 cluster->Restore(); 289 } 290 } 291 } 292 293 private: 294 const std::vector<OptionsCluster *> *current_clusters_ {nullptr}; 295 }; 296 297 private: 298 std::vector<OptionsCluster> clusters_; 299 std::unordered_map<std::string, std::vector<OptionsCluster *>> special_options_; 300 }; 301 302 #undef LOG_PAOC_CLUSTERS 303 304 } // namespace panda 305 306 #endif // COMPILER_TOOLS_PAOC_CLUSTERS_H 307