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