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