• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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