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