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