1 /* 2 * Copyright (c) 2021-2023 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 = specialOptions_.find(method); 51 if (iter == specialOptions_.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 * paParser)58 void Init(const JsonObject &obj, PandArgParser *paParser) 59 { 60 ASSERT(paParser != nullptr); 61 InitClusters(obj, paParser); 62 InitClustersMap(obj); 63 } 64 InitClusters(const JsonObject & mainObj,PandArgParser * paParser)65 void InitClusters(const JsonObject &mainObj, PandArgParser *paParser) 66 { 67 if (mainObj.GetValue<JsonObjPointer>(Key(CLUSTERS_OBJ_NAME)) == nullptr) { 68 LOG_PAOC_CLUSTERS(FATAL) << "Can't find `" << CLUSTERS_OBJ_NAME << "` object"; 69 } 70 const auto clustersJson = mainObj.GetValue<JsonObjPointer>(Key(CLUSTERS_OBJ_NAME))->get(); 71 72 // Fill clusters_ in order of presence in JSON-obj: 73 size_t nClusters = clustersJson->GetSize(); 74 for (size_t idx = 0; idx < nClusters; idx++) { 75 const auto clusterJson = clustersJson->GetValue<JsonObjPointer>(idx)->get(); 76 if (clusterJson == nullptr) { 77 LOG_PAOC_CLUSTERS(FATAL) << "Can't find a cluster (idx = " << idx << ")"; 78 } 79 clusters_.emplace_back(clustersJson->GetKeyByIndex(idx)); 80 81 // Fill current cluster: 82 const auto &optionsJson = clusterJson->GetUnorderedMap(); 83 // Add option-value pair: 84 for (const auto &p : optionsJson) { 85 const auto &optionName = p.first; 86 const auto *optionValue = clusterJson->GetValueSourceString(optionName); 87 if (optionValue == nullptr || optionValue->empty()) { 88 LOG_PAOC_CLUSTERS(FATAL) << "Can't find option's value (cluster `" 89 << clustersJson->GetKeyByIndex(idx) << "`, option `" << optionName << "`)"; 90 } 91 92 auto *option = paParser->GetPandArg(optionName); 93 if (option == nullptr) { 94 LOG_PAOC_CLUSTERS(FATAL) << "Unknown option: `" << optionName << "`"; 95 } 96 auto value = OptionsCluster::ParseOptionValue(*optionValue, option, paParser); 97 clusters_.back().GetVector().emplace_back(option, std::move(value)); 98 } 99 } 100 } 101 InitClustersMap(const JsonObject & mainObj)102 void InitClustersMap(const JsonObject &mainObj) 103 { 104 if (mainObj.GetValue<JsonObjPointer>(Key(CLUSTERS_MAP_OBJ_NAME)) == nullptr) { 105 LOG_PAOC_CLUSTERS(FATAL) << "Can't find `" << CLUSTERS_MAP_OBJ_NAME << "` object"; 106 } 107 const auto clustersMapJson = mainObj.GetValue<JsonObjPointer>(Key(CLUSTERS_MAP_OBJ_NAME))->get(); 108 109 // Fill special_options_: 110 for (const auto &p : clustersMapJson->GetUnorderedMap()) { 111 const auto &methodName = p.first; 112 const auto &clustersArray = p.second; 113 const auto *curClustersJson = clustersArray.Get<ArrayT>(); 114 115 if (curClustersJson == nullptr) { 116 LOG_PAOC_CLUSTERS(FATAL) << "Can't get clusters array for method `" << methodName << "`"; 117 } 118 auto &curClusters = specialOptions_.try_emplace(methodName).first->second; 119 for (const auto &idx : *curClustersJson) { 120 // Cluster may be referenced by integer number (cluster's order) or string (cluster's name): 121 const auto *numIdx = idx.Get<NumT>(); 122 const auto *strIdx = idx.Get<StringT>(); 123 size_t clusterIdx = 0; 124 if (numIdx != nullptr) { 125 clusterIdx = static_cast<size_t>(*numIdx); 126 } else if (strIdx != nullptr) { 127 const auto clustersJson = mainObj.GetValue<JsonObjPointer>(Key(CLUSTERS_OBJ_NAME))->get(); 128 clusterIdx = static_cast<size_t>(clustersJson->GetIndexByKey(*strIdx)); 129 ASSERT(clusterIdx != static_cast<size_t>(-1)); 130 } else { 131 LOG_PAOC_CLUSTERS(FATAL) << "Incorrect reference to a cluster for `" << methodName << "`"; 132 UNREACHABLE(); 133 } 134 if (clusterIdx >= clusters_.size()) { 135 LOG_PAOC_CLUSTERS(FATAL) << "Cluster's index out of range for `" << methodName << "`"; 136 } 137 curClusters.push_back(&clusters_[clusterIdx]); 138 ASSERT(curClusters.back() != nullptr); 139 } 140 } 141 } 142 143 /** 144 * Implements a cluster and contains info related to it. 145 * (i.e. vector of "option:alternative_value" pairs) 146 */ 147 class OptionsCluster { 148 public: 149 // Variant of possible PandArg types: 150 using ValueVariant = std::variant<std::string, int, double, bool, arg_list_t, uint32_t, uint64_t>; 151 152 // NOLINTNEXTLINE(modernize-pass-by-value) OptionsCluster(const std::string & clusterName)153 explicit OptionsCluster(const std::string &clusterName) : clusterName_(clusterName) {} 154 Apply()155 void Apply() 156 { 157 for (auto &pairOptionValue : cluster_) { 158 SwapValue(pairOptionValue.first, &pairOptionValue.second); 159 } 160 } Restore()161 void Restore() 162 { 163 for (auto &pairOptionValue : cluster_) { 164 SwapValue(pairOptionValue.first, &pairOptionValue.second); 165 } 166 } 167 ParseOptionValue(const std::string_view & valueString,PandArgBase * option,PandArgParser * paParser)168 static ValueVariant ParseOptionValue(const std::string_view &valueString, PandArgBase *option, 169 PandArgParser *paParser) 170 { 171 switch (option->GetType()) { 172 case PandArgType::STRING: 173 return ParseOptionValue<std::string>(valueString, option, paParser); 174 175 case PandArgType::INTEGER: 176 return ParseOptionValue<int>(valueString, option, paParser); 177 178 case PandArgType::DOUBLE: 179 return ParseOptionValue<double>(valueString, option, paParser); 180 181 case PandArgType::BOOL: 182 return ParseOptionValue<bool>(valueString, option, paParser); 183 184 case PandArgType::LIST: 185 return ParseOptionValue<arg_list_t>(valueString, option, paParser); 186 187 case PandArgType::UINT32: 188 return ParseOptionValue<uint32_t>(valueString, option, paParser); 189 190 case PandArgType::UINT64: 191 return ParseOptionValue<uint64_t>(valueString, option, paParser); 192 193 case PandArgType::NOTYPE: 194 default: 195 UNREACHABLE(); 196 } 197 } 198 GetVector()199 std::vector<std::pair<PandArgBase *const, ValueVariant>> &GetVector() 200 { 201 return cluster_; 202 } 203 204 private: 205 template <typename T> ParseOptionValue(const std::string_view & valueString,PandArgBase * optionBase,PandArgParser * paParser)206 static ValueVariant ParseOptionValue(const std::string_view &valueString, PandArgBase *optionBase, 207 PandArgParser *paParser) 208 { 209 ASSERT(optionBase != nullptr); 210 auto option = static_cast<PandArg<T> *>(optionBase); 211 auto optionCopy = *option; 212 paParser->ParseSingleArg(&optionCopy, valueString); 213 return optionCopy.GetValue(); 214 } 215 SwapValue(PandArgBase * option,ValueVariant * value)216 void SwapValue(PandArgBase *option, ValueVariant *value) 217 { 218 PandArgType typeId {static_cast<uint8_t>(value->index())}; 219 switch (typeId) { 220 case PandArgType::STRING: 221 SwapValue<std::string>(option, value); 222 return; 223 case PandArgType::INTEGER: 224 SwapValue<int>(option, value); 225 return; 226 case PandArgType::DOUBLE: 227 SwapValue<double>(option, value); 228 return; 229 case PandArgType::BOOL: 230 SwapValue<bool>(option, value); 231 return; 232 case PandArgType::LIST: 233 SwapValue<arg_list_t>(option, value); 234 return; 235 case PandArgType::UINT32: 236 SwapValue<uint32_t>(option, value); 237 return; 238 case PandArgType::UINT64: 239 SwapValue<uint64_t>(option, value); 240 return; 241 case PandArgType::NOTYPE: 242 default: 243 UNREACHABLE(); 244 } 245 } 246 247 template <typename T> SwapValue(PandArgBase * optionBase,ValueVariant * value)248 void SwapValue(PandArgBase *optionBase, ValueVariant *value) 249 { 250 auto *option = static_cast<PandArg<T> *>(optionBase); 251 T temp(option->GetValue()); 252 ASSERT(std::holds_alternative<T>(*value)); 253 option->template SetValue<false>(*std::get_if<T>(value)); 254 *value = std::move(temp); 255 } 256 257 private: 258 std::string clusterName_; 259 std::vector<std::pair<PandArgBase *const, ValueVariant>> cluster_; 260 }; 261 262 /** 263 * Searches for a cluster for the specified method in @param clusters_info and applies it to the compiler. 264 * On destruction, restores previously applied options. 265 */ 266 class ScopedApplySpecialOptions { 267 public: 268 NO_COPY_SEMANTIC(ScopedApplySpecialOptions); 269 NO_MOVE_SEMANTIC(ScopedApplySpecialOptions); 270 ScopedApplySpecialOptions(const std::string & method,PaocClusters * clustersInfo)271 explicit ScopedApplySpecialOptions(const std::string &method, PaocClusters *clustersInfo) 272 { 273 // Find clusters for required method: 274 currentClusters_ = clustersInfo->Find(method); 275 if (currentClusters_ == nullptr) { 276 return; 277 } 278 // Apply clusters: 279 for (auto cluster : *currentClusters_) { 280 cluster->Apply(); 281 } 282 } ~ScopedApplySpecialOptions()283 ~ScopedApplySpecialOptions() 284 { 285 if (currentClusters_ != nullptr) { 286 for (auto cluster : *currentClusters_) { 287 cluster->Restore(); 288 } 289 } 290 } 291 292 private: 293 const std::vector<OptionsCluster *> *currentClusters_ {nullptr}; 294 }; 295 296 private: 297 std::vector<OptionsCluster> clusters_; 298 std::unordered_map<std::string, std::vector<OptionsCluster *>> specialOptions_; 299 }; 300 301 #undef LOG_PAOC_CLUSTERS 302 303 } // namespace panda 304 305 #endif // COMPILER_TOOLS_PAOC_CLUSTERS_H 306