• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2024 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 #ifndef LIBABCKIT_TESTS_HELPERS
16 #define LIBABCKIT_TESTS_HELPERS
17 
18 #include "libabckit/include/c/isa/isa_dynamic.h"
19 #include "libabckit/src/include_v2/c/isa/isa_static.h"
20 #include "libabckit/include/c/abckit.h"
21 #include "libabckit/include/c/metadata_core.h"
22 #include "libabckit/include/c/ir_core.h"
23 #include "libabckit/src/logger.h"
24 
25 #include <string>
26 #include <type_traits>
27 #include <vector>
28 #include <functional>
29 
30 #include <gtest/gtest.h>
31 
32 #ifndef ABCKIT_ABC_DIR
33 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
34 #define ABCKIT_ABC_DIR ""
35 #endif
36 
37 #ifndef ABCKIT_TEST_DIR
38 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
39 #define ABCKIT_TEST_DIR ""
40 #endif
41 
42 namespace libabckit::test::helpers {
43 
44 std::vector<AbckitBasicBlock *> BBgetPredBlocks(AbckitBasicBlock *bb);
45 std::vector<AbckitBasicBlock *> BBgetSuccBlocks(AbckitBasicBlock *bb);
46 std::vector<AbckitInst *> BBgetAllInsts(AbckitBasicBlock *bb);
47 
48 template <class T>
49 // NOLINTBEGIN(misc-non-private-member-variables-in-classes)
50 struct InstSchema {
InstSchemaInstSchema51     InstSchema(size_t id, T o, std::vector<size_t> i) : id(id), opcode(o), inputs(std::move(i)) {}
52     size_t id;
53     T opcode;
54     std::vector<size_t> inputs;
55 };
56 // NOLINTEND(misc-non-private-member-variables-in-classes)
57 template struct InstSchema<AbckitIsaApiStaticOpcode>;
58 template struct InstSchema<AbckitIsaApiDynamicOpcode>;
59 
60 template <class T>
61 // NOLINTBEGIN(misc-non-private-member-variables-in-classes)
62 struct BBSchema {
63     BBSchema(std::vector<size_t> p, std::vector<size_t> s, std::vector<InstSchema<T>> i)
64         : preds(std::move(p)), succs(std::move(s)), instSchemas(std::move(i))
65     {
66     }
67     std::vector<size_t> preds;
68     std::vector<size_t> succs;
69     std::vector<InstSchema<T>> instSchemas;
70 };
71 // NOLINTEND(misc-non-private-member-variables-in-classes)
72 template struct BBSchema<AbckitIsaApiStaticOpcode>;
73 template struct BBSchema<AbckitIsaApiDynamicOpcode>;
74 
75 inline static auto g_impl = AbckitGetApiImpl(ABCKIT_VERSION_RELEASE_1_0_0);
76 inline static auto g_implI = AbckitGetInspectApiImpl(ABCKIT_VERSION_RELEASE_1_0_0);
77 inline static auto g_implG = AbckitGetGraphApiImpl(ABCKIT_VERSION_RELEASE_1_0_0);
78 inline static auto g_gStat = AbckitGetIsaApiStaticImpl(ABCKIT_VERSION_RELEASE_1_0_0);
79 inline static auto g_gDyn = AbckitGetIsaApiDynamicImpl(ABCKIT_VERSION_RELEASE_1_0_0);
80 inline static auto g_implM = AbckitGetModifyApiImpl(ABCKIT_VERSION_RELEASE_1_0_0);
81 
82 template <class T>
83 static void VerifyBBPreds(AbckitBasicBlock *bb, const std::unordered_map<AbckitBasicBlock *, size_t> &bbToIdx,
84                           const BBSchema<T> &bbSchema)
85 {
86     // Verify bb predecessors
87     auto preds = BBgetPredBlocks(bb);
88     ASSERT_EQ(preds.size(), bbSchema.preds.size());
89     for (size_t predIdx = 0; predIdx < preds.size(); predIdx++) {
90         ASSERT_EQ(bbToIdx.at(preds[predIdx]), bbSchema.preds[predIdx]);
91     }
92 }
93 
94 template <class T>
95 static void VerifyBBSuccs(AbckitBasicBlock *bb, const std::unordered_map<AbckitBasicBlock *, size_t> &bbToIdx,
96                           const BBSchema<T> &bbSchema)
97 {
98     // Verify bb successors
99     auto succs = BBgetSuccBlocks(bb);
100     ASSERT_EQ(succs.size(), bbSchema.succs.size());
101     for (size_t succIdx = 0; succIdx < succs.size(); succIdx++) {
102         ASSERT_EQ(bbToIdx.at(succs[succIdx]), bbSchema.succs[succIdx]);
103     }
104 }
105 
106 template <typename T>
107 static void VerifyGraphInputs(uint32_t inputCount, const InstSchema<T> &instSchema,
108                               const std::unordered_map<size_t, size_t> &schemaIdToId, AbckitInst *inst)
109 {
110     // Verify inputs
111     ASSERT_EQ(inputCount, instSchema.inputs.size());
112     for (size_t inputNumber = 0; inputNumber < inputCount; inputNumber++) {
113         auto input = g_implG->iGetInput(inst, inputNumber);
114         auto inputId = g_implG->iGetId(input);
115         auto inputIdx = instSchema.inputs[inputNumber];
116         ASSERT_NE(schemaIdToId.find(inputIdx), schemaIdToId.end());
117         ASSERT_EQ(schemaIdToId.at(inputIdx), inputId);
118     }
119 }
120 
121 template <typename T>
122 static void VerifyInstSchema(const std::vector<AbckitBasicBlock *> &bbs, const std::vector<BBSchema<T>> &bbSchemas,
123                              const std::unordered_map<AbckitBasicBlock *, size_t> &bbToIdx)
124 {
125     std::unordered_map<size_t, size_t> schemaIdToId;  // Map from inst schema id to actual inst id
126     for (size_t bbIdx = 0; bbIdx < bbs.size(); bbIdx++) {
127         auto *bb = bbs[bbIdx];
128         auto &bbSchema = bbSchemas[bbIdx];
129 
130         VerifyBBPreds<T>(bb, bbToIdx, bbSchema);
131 
132         VerifyBBSuccs<T>(bb, bbToIdx, bbSchema);
133 
134         // Collect instructions
135         std::vector<AbckitInst *> insts = BBgetAllInsts(bb);
136 
137         // Verify instructions
138         auto &instSchemas = bbSchema.instSchemas;
139         std::unordered_map<size_t, AbckitInst *> idToInst;
140         ASSERT_EQ(insts.size(), instSchemas.size());
141         for (size_t instIdx = 0; instIdx < insts.size(); instIdx++) {
142             auto &instSchema = instSchemas[instIdx];
143             auto *inst = insts[instIdx];
144 
145             if constexpr (std::is_same<T, AbckitIsaApiDynamicOpcode>()) {
146                 ASSERT_EQ(g_gDyn->iGetOpcode(inst), instSchema.opcode);
147             } else if constexpr (std::is_same<T, AbckitIsaApiStaticOpcode>()) {
148                 ASSERT_EQ(g_gStat->iGetOpcode(inst), instSchema.opcode);
149             } else {
150                 LIBABCKIT_UNREACHABLE;
151             }
152 
153             auto instId = g_implG->iGetId(inst);
154             auto instSchemaId = instSchema.id;
155             schemaIdToId.insert({instSchemaId, instId});
156             idToInst.insert({instId, inst});
157 
158             VerifyGraphInputs(g_implG->iGetInputCount(inst), instSchema, schemaIdToId, inst);
159         }
160     }
161 }
162 
163 template <class T>
164 void VerifyGraph(AbckitGraph *graph, const std::vector<BBSchema<T>> &bbSchemas)
165 {
166     LIBABCKIT_LOG(DEBUG) << " Graph:\n";
167     LIBABCKIT_LOG_DUMP(g_implG->gDump(graph, 2U), DEBUG);
168     std::vector<AbckitBasicBlock *> bbs;
169 
170     // Collect basic blocks
171     g_implG->gVisitBlocksRpo(graph, &bbs, [](AbckitBasicBlock *bb, void *data) {
172         reinterpret_cast<std::vector<AbckitBasicBlock *> *>(data)->emplace_back(bb);
173         return true;
174     });
175 
176     // Construct maps bb->idx
177     std::unordered_map<AbckitBasicBlock *, size_t> bbToIdx;
178     ASSERT_EQ(bbs.size(), bbSchemas.size());
179     for (size_t bbIdx = 0; bbIdx < bbs.size(); bbIdx++) {
180         auto *bb = bbs[bbIdx];
181         bbToIdx.insert({bb, bbIdx});
182     }
183 
184     VerifyInstSchema(bbs, bbSchemas, bbToIdx);
185 }
186 
187 bool Match(const std::string &actual, const std::string &expected);
188 void TransformMethod(AbckitFile *file, const std::string &methodSignature,
189                      const std::function<void(AbckitFile *, AbckitCoreFunction *, AbckitGraph *)> &userTransformer);
190 void TransformMethod(const std::string &inputPath, const std::string &outputPath, const std::string &methodSignature,
191                      const std::function<void(AbckitFile *, AbckitCoreFunction *, AbckitGraph *)> &userTransformer);
192 void TransformMethod(const std::string &inputPath, const std::string &outputPath, const std::string &methodSignature,
193                      const std::function<void(AbckitFile *, AbckitCoreFunction *, AbckitGraph *)> &userTransformer,
194                      const std::function<void(AbckitGraph *)> &validateResult);
195 
196 void InspectMethod(AbckitFile *file, const std::string &methodSignature,
197                    const std::function<void(AbckitFile *, AbckitCoreFunction *, AbckitGraph *)> &userInspector);
198 void InspectMethod(const std::string &inputPath, const std::string &methodSignature,
199                    const std::function<void(AbckitFile *, AbckitCoreFunction *, AbckitGraph *)> &userInspector);
200 
201 AbckitInst *FindFirstInst(
202     AbckitGraph *graph, AbckitIsaApiStaticOpcode opcode,
203     const std::function<bool(AbckitInst *)> &findIf = [](AbckitInst *) { return true; });
204 AbckitInst *FindFirstInst(
205     AbckitGraph *graph, AbckitIsaApiDynamicOpcode opcode,
206     const std::function<bool(AbckitInst *)> &findIf = [](AbckitInst *) { return true; });
207 AbckitInst *FindLastInst(
208     AbckitGraph *graph, AbckitIsaApiDynamicOpcode opcode,
209     const std::function<bool(AbckitInst *)> &findIf = [](AbckitInst *) { return true; });
210 AbckitInst *FindLastInst(
211     AbckitGraph *graph, AbckitIsaApiStaticOpcode opcode,
212     const std::function<bool(AbckitInst *)> &findIf = [](AbckitInst *) { return true; });
213 void ReplaceInst(AbckitInst *what, AbckitInst *with);
214 void EnumerateAllMethods(AbckitFile *file, const std::function<void(AbckitCoreFunction *)> &cb);
215 
216 struct ModuleByNameContext {
217     AbckitCoreModule *module;
218     const char *name;
219 };
220 
221 struct ImportByAliasContext {
222     AbckitCoreImportDescriptor *id;
223     const char *name;
224 };
225 
226 struct ExportByAliasContext {
227     AbckitCoreExportDescriptor *ed;
228     const char *name;
229 };
230 
231 struct ClassByNameContext {
232     AbckitCoreClass *klass;
233     const char *name;
234 };
235 
236 struct MethodByNameContext {
237     AbckitCoreFunction *method = nullptr;
238     const char *name = "";
239     bool fullSign = false;
240 };
241 
242 struct NamepsaceByNameContext {
243     AbckitCoreNamespace *n;
244     const char *name;
245 };
246 
247 struct AnnotationInterfaceByNameContext {
248     AbckitCoreAnnotationInterface *ai;
249     const char *name;
250 };
251 
252 struct AnnotationByNameContext {
253     AbckitCoreAnnotation *anno;
254     const char *name;
255 };
256 
257 AbckitCoreFunction *FindMethodByName(AbckitFile *file, const std::string &name);
258 AbckitCoreNamespace *FindNamespaceByName(AbckitFile *file, const std::string &name);
259 bool ModuleByNameFinder(AbckitCoreModule *module, void *data);
260 bool ImportByAliasFinder(AbckitCoreImportDescriptor *id, void *data);
261 bool ExportByAliasFinder(AbckitCoreExportDescriptor *ed, void *data);
262 bool ClassByNameFinder(AbckitCoreClass *klass, void *data);
263 bool NamespaceByNameFinder(AbckitCoreNamespace *n, void *data);
264 bool MethodByNameFinder(AbckitCoreFunction *method, void *data);
265 bool AnnotationInterfaceByNameFinder(AbckitCoreAnnotationInterface *ai, void *data);
266 bool AnnotationByNameFinder(AbckitCoreAnnotation *anno, void *data);
267 bool NameToModuleCollector(AbckitCoreModule *module, void *data);
268 bool ModuleImportsCollector(AbckitCoreImportDescriptor *id, void *data);
269 bool ModuleExportsCollector(AbckitCoreExportDescriptor *ed, void *data);
270 
271 void AssertModuleVisitor(AbckitCoreModule *module, void *data);
272 void AssertImportVisitor(AbckitCoreImportDescriptor *id, void *data);
273 void AssertExportVisitor(AbckitCoreExportDescriptor *ed, void *data);
274 void AssertClassVisitor(AbckitCoreClass *klass, void *data);
275 void AssertMethodVisitor(AbckitCoreFunction *method, void *data);
276 void AssertOpenAbc(const char *fname, AbckitFile **file);
277 std::string_view AbckitStringToString(AbckitString *str);
278 std::string GetCropFuncName(const std::string &fullSig);
279 
280 }  // namespace libabckit::test::helpers
281 
282 #endif  // LIBABCKIT_TESTS_HELPERS
283