1 //===- IRSimilarityIdentifierTest.cpp - IRSimilarityIdentifier unit tests -===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // Tests for components for finding similarity such as the instruction mapper, 10 // suffix tree usage, and structural analysis. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #include "llvm/Analysis/IRSimilarityIdentifier.h" 15 #include "llvm/AsmParser/Parser.h" 16 #include "llvm/IR/LLVMContext.h" 17 #include "llvm/IR/Module.h" 18 #include "llvm/Support/Allocator.h" 19 #include "llvm/Support/SourceMgr.h" 20 #include "gtest/gtest.h" 21 22 using namespace llvm; 23 using namespace IRSimilarity; 24 25 static std::unique_ptr<Module> makeLLVMModule(LLVMContext &Context, 26 StringRef ModuleStr) { 27 SMDiagnostic Err; 28 std::unique_ptr<Module> M = parseAssemblyString(ModuleStr, Err, Context); 29 assert(M && "Bad LLVM IR?"); 30 return M; 31 } 32 33 void getVectors(Module &M, IRInstructionMapper &Mapper, 34 std::vector<IRInstructionData *> &InstrList, 35 std::vector<unsigned> &UnsignedVec) { 36 for (Function &F : M) 37 for (BasicBlock &BB : F) 38 Mapper.convertToUnsignedVec(BB, InstrList, UnsignedVec); 39 } 40 41 void getSimilarities( 42 Module &M, 43 std::vector<std::vector<IRSimilarityCandidate>> &SimilarityCandidates) { 44 // In order to keep the size of the tests from becoming too large, we do not 45 // recognize similarity for branches unless explicitly needed. 46 IRSimilarityIdentifier Identifier(/*EnableBranchMatching = */false); 47 SimilarityCandidates = Identifier.findSimilarity(M); 48 } 49 50 // Checks that different opcodes are mapped to different values 51 TEST(IRInstructionMapper, OpcodeDifferentiation) { 52 StringRef ModuleString = R"( 53 define i32 @f(i32 %a, i32 %b) { 54 bb0: 55 %0 = add i32 %a, %b 56 %1 = mul i32 %a, %b 57 ret i32 0 58 })"; 59 LLVMContext Context; 60 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); 61 62 std::vector<IRInstructionData *> InstrList; 63 std::vector<unsigned> UnsignedVec; 64 65 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator; 66 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator; 67 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator); 68 getVectors(*M, Mapper, InstrList, UnsignedVec); 69 70 // Check that the size of the unsigned vector and the instruction list are the 71 // same as a safety check. 72 ASSERT_TRUE(InstrList.size() == UnsignedVec.size()); 73 74 // Make sure that the unsigned vector is the expected size. 75 ASSERT_TRUE(UnsignedVec.size() == 3); 76 77 // Check whether the instructions are not mapped to the same value. 78 ASSERT_TRUE(UnsignedVec[0] != UnsignedVec[1]); 79 } 80 81 // Checks that the same opcodes and types are mapped to the same values. 82 TEST(IRInstructionMapper, OpcodeTypeSimilarity) { 83 StringRef ModuleString = R"( 84 define i32 @f(i32 %a, i32 %b) { 85 bb0: 86 %0 = add i32 %a, %b 87 %1 = add i32 %b, %a 88 ret i32 0 89 })"; 90 LLVMContext Context; 91 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); 92 93 std::vector<IRInstructionData *> InstrList; 94 std::vector<unsigned> UnsignedVec; 95 96 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator; 97 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator; 98 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator); 99 getVectors(*M, Mapper, InstrList, UnsignedVec); 100 101 ASSERT_TRUE(InstrList.size() == UnsignedVec.size()); 102 ASSERT_TRUE(UnsignedVec.size() == 3); 103 104 // Check whether the instructions are mapped to the same value. 105 ASSERT_TRUE(UnsignedVec[0] == UnsignedVec[1]); 106 } 107 108 // Checks that the same opcode and different types are mapped to different 109 // values. 110 TEST(IRInstructionMapper, TypeDifferentiation) { 111 StringRef ModuleString = R"( 112 define i32 @f(i32 %a, i32 %b, i64 %c, i64 %d) { 113 bb0: 114 %0 = add i32 %a, %b 115 %1 = add i64 %c, %d 116 ret i32 0 117 })"; 118 LLVMContext Context; 119 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); 120 121 std::vector<IRInstructionData *> InstrList; 122 std::vector<unsigned> UnsignedVec; 123 124 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator; 125 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator; 126 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator); 127 getVectors(*M, Mapper, InstrList, UnsignedVec); 128 129 ASSERT_TRUE(InstrList.size() == UnsignedVec.size()); 130 ASSERT_TRUE(UnsignedVec.size() == 3); 131 ASSERT_TRUE(UnsignedVec[0] != UnsignedVec[1]); 132 } 133 134 // Checks that different predicates map to different values. 135 TEST(IRInstructionMapper, PredicateDifferentiation) { 136 StringRef ModuleString = R"( 137 define i32 @f(i32 %a, i32 %b) { 138 bb0: 139 %0 = icmp sge i32 %b, %a 140 %1 = icmp slt i32 %a, %b 141 ret i32 0 142 })"; 143 LLVMContext Context; 144 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); 145 146 std::vector<IRInstructionData *> InstrList; 147 std::vector<unsigned> UnsignedVec; 148 149 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator; 150 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator; 151 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator); 152 getVectors(*M, Mapper, InstrList, UnsignedVec); 153 154 ASSERT_TRUE(InstrList.size() == UnsignedVec.size()); 155 ASSERT_TRUE(UnsignedVec.size() == 3); 156 ASSERT_TRUE(UnsignedVec[0] != UnsignedVec[1]); 157 } 158 159 // Checks that predicates where that can be considered the same when the 160 // operands are swapped, i.e. greater than to less than are mapped to the same 161 // unsigned integer. 162 TEST(IRInstructionMapper, PredicateIsomorphism) { 163 StringRef ModuleString = R"( 164 define i32 @f(i32 %a, i32 %b) { 165 bb0: 166 %0 = icmp sgt i32 %a, %b 167 %1 = icmp slt i32 %b, %a 168 ret i32 0 169 })"; 170 LLVMContext Context; 171 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); 172 173 std::vector<IRInstructionData *> InstrList; 174 std::vector<unsigned> UnsignedVec; 175 176 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator; 177 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator; 178 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator); 179 getVectors(*M, Mapper, InstrList, UnsignedVec); 180 181 ASSERT_TRUE(InstrList.size() == UnsignedVec.size()); 182 ASSERT_TRUE(UnsignedVec.size() == 3); 183 ASSERT_TRUE(UnsignedVec[0] == UnsignedVec[1]); 184 } 185 186 // Checks that the same predicate maps to the same value. 187 TEST(IRInstructionMapper, PredicateSimilarity) { 188 StringRef ModuleString = R"( 189 define i32 @f(i32 %a, i32 %b) { 190 bb0: 191 %0 = icmp slt i32 %a, %b 192 %1 = icmp slt i32 %b, %a 193 ret i32 0 194 })"; 195 LLVMContext Context; 196 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); 197 198 std::vector<IRInstructionData *> InstrList; 199 std::vector<unsigned> UnsignedVec; 200 201 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator; 202 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator; 203 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator); 204 getVectors(*M, Mapper, InstrList, UnsignedVec); 205 206 ASSERT_TRUE(InstrList.size() == UnsignedVec.size()); 207 ASSERT_TRUE(UnsignedVec.size() == 3); 208 ASSERT_TRUE(UnsignedVec[0] == UnsignedVec[1]); 209 } 210 211 // Checks that the same predicate maps to the same value for floating point 212 // CmpInsts. 213 TEST(IRInstructionMapper, FPPredicateSimilarity) { 214 StringRef ModuleString = R"( 215 define i32 @f(double %a, double %b) { 216 bb0: 217 %0 = fcmp olt double %a, %b 218 %1 = fcmp olt double %b, %a 219 ret i32 0 220 })"; 221 LLVMContext Context; 222 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); 223 224 std::vector<IRInstructionData *> InstrList; 225 std::vector<unsigned> UnsignedVec; 226 227 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator; 228 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator; 229 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator); 230 getVectors(*M, Mapper, InstrList, UnsignedVec); 231 232 ASSERT_TRUE(InstrList.size() == UnsignedVec.size()); 233 ASSERT_TRUE(UnsignedVec.size() == 3); 234 ASSERT_TRUE(UnsignedVec[0] == UnsignedVec[1]); 235 } 236 237 // Checks that the different predicate maps to a different value for floating 238 // point CmpInsts. 239 TEST(IRInstructionMapper, FPPredicatDifference) { 240 StringRef ModuleString = R"( 241 define i32 @f(double %a, double %b) { 242 bb0: 243 %0 = fcmp olt double %a, %b 244 %1 = fcmp oge double %b, %a 245 ret i32 0 246 })"; 247 LLVMContext Context; 248 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); 249 250 std::vector<IRInstructionData *> InstrList; 251 std::vector<unsigned> UnsignedVec; 252 253 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator; 254 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator; 255 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator); 256 getVectors(*M, Mapper, InstrList, UnsignedVec); 257 258 ASSERT_TRUE(InstrList.size() == UnsignedVec.size()); 259 ASSERT_TRUE(UnsignedVec.size() == 3); 260 ASSERT_TRUE(UnsignedVec[0] != UnsignedVec[1]); 261 } 262 263 // Checks that the zexts that have the same type parameters map to the same 264 // unsigned integer. 265 TEST(IRInstructionMapper, ZextTypeSimilarity) { 266 StringRef ModuleString = R"( 267 define i32 @f(i32 %a) { 268 bb0: 269 %0 = zext i32 %a to i64 270 %1 = zext i32 %a to i64 271 ret i32 0 272 })"; 273 LLVMContext Context; 274 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); 275 276 std::vector<IRInstructionData *> InstrList; 277 std::vector<unsigned> UnsignedVec; 278 279 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator; 280 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator; 281 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator); 282 getVectors(*M, Mapper, InstrList, UnsignedVec); 283 284 ASSERT_TRUE(InstrList.size() == UnsignedVec.size()); 285 ASSERT_TRUE(UnsignedVec.size() == 3); 286 ASSERT_TRUE(UnsignedVec[0] == UnsignedVec[1]); 287 } 288 289 // Checks that the sexts that have the same type parameters map to the same 290 // unsigned integer. 291 TEST(IRInstructionMapper, SextTypeSimilarity) { 292 StringRef ModuleString = R"( 293 define i32 @f(i32 %a) { 294 bb0: 295 %0 = sext i32 %a to i64 296 %1 = sext i32 %a to i64 297 ret i32 0 298 })"; 299 LLVMContext Context; 300 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); 301 302 std::vector<IRInstructionData *> InstrList; 303 std::vector<unsigned> UnsignedVec; 304 305 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator; 306 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator; 307 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator); 308 getVectors(*M, Mapper, InstrList, UnsignedVec); 309 310 ASSERT_TRUE(InstrList.size() == UnsignedVec.size()); 311 ASSERT_TRUE(UnsignedVec.size() == 3); 312 ASSERT_TRUE(UnsignedVec[0] == UnsignedVec[1]); 313 } 314 315 // Checks that the zexts that have the different type parameters map to the 316 // different unsigned integers. 317 TEST(IRInstructionMapper, ZextTypeDifference) { 318 StringRef ModuleString = R"( 319 define i32 @f(i32 %a, i8 %b) { 320 bb0: 321 %0 = zext i32 %a to i64 322 %1 = zext i8 %b to i32 323 ret i32 0 324 })"; 325 LLVMContext Context; 326 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); 327 328 std::vector<IRInstructionData *> InstrList; 329 std::vector<unsigned> UnsignedVec; 330 331 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator; 332 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator; 333 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator); 334 getVectors(*M, Mapper, InstrList, UnsignedVec); 335 336 ASSERT_TRUE(InstrList.size() == UnsignedVec.size()); 337 ASSERT_TRUE(UnsignedVec.size() == 3); 338 ASSERT_TRUE(UnsignedVec[0] != UnsignedVec[1]); 339 } 340 341 // Checks that the sexts that have the different type parameters map to the 342 // different unsigned integers. 343 TEST(IRInstructionMapper, SextTypeDifference) { 344 StringRef ModuleString = R"( 345 define i32 @f(i32 %a, i8 %b) { 346 bb0: 347 %0 = sext i32 %a to i64 348 %1 = sext i8 %b to i32 349 ret i32 0 350 })"; 351 LLVMContext Context; 352 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); 353 354 std::vector<IRInstructionData *> InstrList; 355 std::vector<unsigned> UnsignedVec; 356 357 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator; 358 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator; 359 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator); 360 getVectors(*M, Mapper, InstrList, UnsignedVec); 361 362 ASSERT_TRUE(InstrList.size() == UnsignedVec.size()); 363 ASSERT_TRUE(UnsignedVec.size() == 3); 364 ASSERT_TRUE(UnsignedVec[0] != UnsignedVec[1]); 365 } 366 367 // Checks that loads that have the same type are mapped to the same unsigned 368 // integer. 369 TEST(IRInstructionMapper, LoadSimilarType) { 370 StringRef ModuleString = R"( 371 define i32 @f(i32* %a, i32* %b) { 372 bb0: 373 %0 = load i32, i32* %a 374 %1 = load i32, i32* %b 375 ret i32 0 376 })"; 377 LLVMContext Context; 378 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); 379 380 std::vector<IRInstructionData *> InstrList; 381 std::vector<unsigned> UnsignedVec; 382 383 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator; 384 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator; 385 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator); 386 getVectors(*M, Mapper, InstrList, UnsignedVec); 387 388 ASSERT_TRUE(InstrList.size() == UnsignedVec.size()); 389 ASSERT_TRUE(UnsignedVec.size() == 3); 390 ASSERT_TRUE(UnsignedVec[0] == UnsignedVec[1]); 391 } 392 393 // Checks that loads that have the different types are mapped to 394 // different unsigned integers. 395 TEST(IRInstructionMapper, LoadDifferentType) { 396 StringRef ModuleString = R"( 397 define i32 @f(i32* %a, i64* %b) { 398 bb0: 399 %0 = load i32, i32* %a 400 %1 = load i64, i64* %b 401 ret i32 0 402 })"; 403 LLVMContext Context; 404 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); 405 406 std::vector<IRInstructionData *> InstrList; 407 std::vector<unsigned> UnsignedVec; 408 409 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator; 410 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator; 411 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator); 412 getVectors(*M, Mapper, InstrList, UnsignedVec); 413 414 ASSERT_TRUE(InstrList.size() == UnsignedVec.size()); 415 ASSERT_TRUE(UnsignedVec.size() == 3); 416 ASSERT_TRUE(UnsignedVec[0] != UnsignedVec[1]); 417 } 418 419 // Checks that loads that have the different aligns are mapped to different 420 // unsigned integers. 421 TEST(IRInstructionMapper, LoadDifferentAlign) { 422 StringRef ModuleString = R"( 423 define i32 @f(i32* %a, i32* %b) { 424 bb0: 425 %0 = load i32, i32* %a, align 4 426 %1 = load i32, i32* %b, align 8 427 ret i32 0 428 })"; 429 LLVMContext Context; 430 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); 431 432 std::vector<IRInstructionData *> InstrList; 433 std::vector<unsigned> UnsignedVec; 434 435 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator; 436 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator; 437 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator); 438 getVectors(*M, Mapper, InstrList, UnsignedVec); 439 440 ASSERT_TRUE(InstrList.size() == UnsignedVec.size()); 441 ASSERT_TRUE(UnsignedVec.size() == 3); 442 ASSERT_TRUE(UnsignedVec[0] != UnsignedVec[1]); 443 } 444 445 // Checks that loads that have the different volatile settings are mapped to 446 // different unsigned integers. 447 TEST(IRInstructionMapper, LoadDifferentVolatile) { 448 StringRef ModuleString = R"( 449 define i32 @f(i32* %a, i32* %b) { 450 bb0: 451 %0 = load volatile i32, i32* %a 452 %1 = load i32, i32* %b 453 ret i32 0 454 })"; 455 LLVMContext Context; 456 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); 457 458 std::vector<IRInstructionData *> InstrList; 459 std::vector<unsigned> UnsignedVec; 460 461 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator; 462 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator; 463 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator); 464 getVectors(*M, Mapper, InstrList, UnsignedVec); 465 466 ASSERT_TRUE(InstrList.size() == UnsignedVec.size()); 467 ASSERT_TRUE(UnsignedVec.size() == 3); 468 ASSERT_TRUE(UnsignedVec[0] != UnsignedVec[1]); 469 } 470 471 // Checks that loads that have the same volatile settings are mapped to 472 // different unsigned integers. 473 TEST(IRInstructionMapper, LoadSameVolatile) { 474 StringRef ModuleString = R"( 475 define i32 @f(i32* %a, i32* %b) { 476 bb0: 477 %0 = load volatile i32, i32* %a 478 %1 = load volatile i32, i32* %b 479 ret i32 0 480 })"; 481 LLVMContext Context; 482 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); 483 484 std::vector<IRInstructionData *> InstrList; 485 std::vector<unsigned> UnsignedVec; 486 487 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator; 488 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator; 489 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator); 490 getVectors(*M, Mapper, InstrList, UnsignedVec); 491 492 ASSERT_TRUE(InstrList.size() == UnsignedVec.size()); 493 ASSERT_TRUE(UnsignedVec.size() == 3); 494 ASSERT_TRUE(UnsignedVec[0] == UnsignedVec[1]); 495 } 496 497 // Checks that loads that have the different atomicity settings are mapped to 498 // different unsigned integers. 499 TEST(IRInstructionMapper, LoadDifferentAtomic) { 500 StringRef ModuleString = R"( 501 define i32 @f(i32* %a, i32* %b) { 502 bb0: 503 %0 = load atomic i32, i32* %a unordered, align 4 504 %1 = load atomic i32, i32* %b monotonic, align 4 505 ret i32 0 506 })"; 507 LLVMContext Context; 508 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); 509 510 std::vector<IRInstructionData *> InstrList; 511 std::vector<unsigned> UnsignedVec; 512 513 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator; 514 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator; 515 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator); 516 getVectors(*M, Mapper, InstrList, UnsignedVec); 517 518 ASSERT_TRUE(InstrList.size() == UnsignedVec.size()); 519 ASSERT_TRUE(UnsignedVec.size() == 3); 520 ASSERT_TRUE(UnsignedVec[0] != UnsignedVec[1]); 521 } 522 523 // Checks that loads that have the same atomicity settings are mapped to 524 // different unsigned integers. 525 TEST(IRInstructionMapper, LoadSameAtomic) { 526 StringRef ModuleString = R"( 527 define i32 @f(i32* %a, i32* %b) { 528 bb0: 529 %0 = load atomic i32, i32* %a unordered, align 4 530 %1 = load atomic i32, i32* %b unordered, align 4 531 ret i32 0 532 })"; 533 LLVMContext Context; 534 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); 535 536 std::vector<IRInstructionData *> InstrList; 537 std::vector<unsigned> UnsignedVec; 538 539 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator; 540 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator; 541 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator); 542 getVectors(*M, Mapper, InstrList, UnsignedVec); 543 544 ASSERT_TRUE(InstrList.size() == UnsignedVec.size()); 545 ASSERT_TRUE(UnsignedVec.size() == 3); 546 ASSERT_TRUE(UnsignedVec[0] == UnsignedVec[1]); 547 } 548 549 // Checks that stores that have the same type are mapped to the same unsigned 550 // integer. 551 TEST(IRInstructionMapper, StoreSimilarType) { 552 StringRef ModuleString = R"( 553 define i32 @f(i32* %a, i32* %b) { 554 bb0: 555 store i32 1, i32* %a 556 store i32 2, i32* %a 557 ret i32 0 558 })"; 559 LLVMContext Context; 560 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); 561 562 std::vector<IRInstructionData *> InstrList; 563 std::vector<unsigned> UnsignedVec; 564 565 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator; 566 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator; 567 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator); 568 getVectors(*M, Mapper, InstrList, UnsignedVec); 569 570 ASSERT_TRUE(InstrList.size() == UnsignedVec.size()); 571 ASSERT_TRUE(UnsignedVec.size() == 3); 572 ASSERT_TRUE(UnsignedVec[0] == UnsignedVec[1]); 573 } 574 575 // Checks that stores that have the different types are mapped to 576 // different unsigned integers. 577 TEST(IRInstructionMapper, StoreDifferentType) { 578 StringRef ModuleString = R"( 579 define i32 @f(i32* %a, i64* %b) { 580 bb0: 581 store i32 1, i32* %a 582 store i64 1, i64* %b 583 ret i32 0 584 })"; 585 LLVMContext Context; 586 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); 587 588 std::vector<IRInstructionData *> InstrList; 589 std::vector<unsigned> UnsignedVec; 590 591 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator; 592 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator; 593 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator); 594 getVectors(*M, Mapper, InstrList, UnsignedVec); 595 596 ASSERT_TRUE(InstrList.size() == UnsignedVec.size()); 597 ASSERT_TRUE(UnsignedVec.size() == 3); 598 ASSERT_TRUE(UnsignedVec[0] != UnsignedVec[1]); 599 } 600 601 // Checks that stores that have the different aligns are mapped to different 602 // unsigned integers. 603 TEST(IRInstructionMapper, StoreDifferentAlign) { 604 StringRef ModuleString = R"( 605 define i32 @f(i32* %a, i32* %b) { 606 bb0: 607 store i32 1, i32* %a, align 4 608 store i32 1, i32* %b, align 8 609 ret i32 0 610 })"; 611 LLVMContext Context; 612 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); 613 614 std::vector<IRInstructionData *> InstrList; 615 std::vector<unsigned> UnsignedVec; 616 617 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator; 618 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator; 619 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator); 620 getVectors(*M, Mapper, InstrList, UnsignedVec); 621 622 ASSERT_TRUE(InstrList.size() == UnsignedVec.size()); 623 ASSERT_TRUE(UnsignedVec.size() == 3); 624 ASSERT_TRUE(UnsignedVec[0] != UnsignedVec[1]); 625 } 626 627 // Checks that stores that have the different volatile settings are mapped to 628 // different unsigned integers. 629 TEST(IRInstructionMapper, StoreDifferentVolatile) { 630 StringRef ModuleString = R"( 631 define i32 @f(i32* %a, i32* %b) { 632 bb0: 633 store volatile i32 1, i32* %a 634 store i32 1, i32* %b 635 ret i32 0 636 })"; 637 LLVMContext Context; 638 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); 639 640 std::vector<IRInstructionData *> InstrList; 641 std::vector<unsigned> UnsignedVec; 642 643 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator; 644 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator; 645 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator); 646 getVectors(*M, Mapper, InstrList, UnsignedVec); 647 648 ASSERT_TRUE(InstrList.size() == UnsignedVec.size()); 649 ASSERT_TRUE(UnsignedVec.size() == 3); 650 ASSERT_TRUE(UnsignedVec[0] != UnsignedVec[1]); 651 } 652 653 // Checks that stores that have the same volatile settings are mapped to 654 // different unsigned integers. 655 TEST(IRInstructionMapper, StoreSameVolatile) { 656 StringRef ModuleString = R"( 657 define i32 @f(i32* %a, i32* %b) { 658 bb0: 659 store volatile i32 1, i32* %a 660 store volatile i32 1, i32* %b 661 ret i32 0 662 })"; 663 LLVMContext Context; 664 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); 665 666 std::vector<IRInstructionData *> InstrList; 667 std::vector<unsigned> UnsignedVec; 668 669 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator; 670 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator; 671 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator); 672 getVectors(*M, Mapper, InstrList, UnsignedVec); 673 674 ASSERT_TRUE(InstrList.size() == UnsignedVec.size()); 675 ASSERT_TRUE(UnsignedVec.size() == 3); 676 ASSERT_TRUE(UnsignedVec[0] == UnsignedVec[1]); 677 } 678 679 // Checks that loads that have the same atomicity settings are mapped to 680 // different unsigned integers. 681 TEST(IRInstructionMapper, StoreSameAtomic) { 682 StringRef ModuleString = R"( 683 define i32 @f(i32* %a, i32* %b) { 684 bb0: 685 store atomic i32 1, i32* %a unordered, align 4 686 store atomic i32 1, i32* %b unordered, align 4 687 ret i32 0 688 })"; 689 LLVMContext Context; 690 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); 691 692 std::vector<IRInstructionData *> InstrList; 693 std::vector<unsigned> UnsignedVec; 694 695 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator; 696 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator; 697 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator); 698 getVectors(*M, Mapper, InstrList, UnsignedVec); 699 700 ASSERT_TRUE(InstrList.size() == UnsignedVec.size()); 701 ASSERT_TRUE(UnsignedVec.size() == 3); 702 ASSERT_TRUE(UnsignedVec[0] == UnsignedVec[1]); 703 } 704 705 // Checks that loads that have the different atomicity settings are mapped to 706 // different unsigned integers. 707 TEST(IRInstructionMapper, StoreDifferentAtomic) { 708 StringRef ModuleString = R"( 709 define i32 @f(i32* %a, i32* %b) { 710 bb0: 711 store atomic i32 1, i32* %a unordered, align 4 712 store atomic i32 1, i32* %b monotonic, align 4 713 ret i32 0 714 })"; 715 LLVMContext Context; 716 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); 717 718 std::vector<IRInstructionData *> InstrList; 719 std::vector<unsigned> UnsignedVec; 720 721 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator; 722 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator; 723 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator); 724 getVectors(*M, Mapper, InstrList, UnsignedVec); 725 726 ASSERT_TRUE(InstrList.size() == UnsignedVec.size()); 727 ASSERT_TRUE(UnsignedVec.size() == 3); 728 ASSERT_TRUE(UnsignedVec[0] != UnsignedVec[1]); 729 } 730 731 // Checks that the branch is mapped to legal when the option is set. 732 TEST(IRInstructionMapper, BranchLegal) { 733 StringRef ModuleString = R"( 734 define i32 @f(i32 %a, i32 %b) { 735 bb0: 736 %0 = icmp slt i32 %a, %b 737 br i1 %0, label %bb0, label %bb1 738 bb1: 739 ret i32 0 740 })"; 741 LLVMContext Context; 742 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); 743 744 std::vector<IRInstructionData *> InstrList; 745 std::vector<unsigned> UnsignedVec; 746 747 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator; 748 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator; 749 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator); 750 Mapper.InstClassifier.EnableBranches = true; 751 Mapper.initializeForBBs(*M); 752 getVectors(*M, Mapper, InstrList, UnsignedVec); 753 754 ASSERT_EQ(InstrList.size(), UnsignedVec.size()); 755 ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(3)); 756 ASSERT_TRUE(UnsignedVec[1] > UnsignedVec[0]); 757 ASSERT_TRUE(UnsignedVec[1] < UnsignedVec[2]); 758 } 759 760 // Checks that a PHINode is mapped to be legal. 761 TEST(IRInstructionMapper, PhiLegal) { 762 StringRef ModuleString = R"( 763 define i32 @f(i32 %a, i32 %b) { 764 bb0: 765 %0 = phi i1 [ 0, %bb0 ], [ %0, %bb1 ] 766 %1 = add i32 %a, %b 767 ret i32 0 768 bb1: 769 ret i32 1 770 })"; 771 LLVMContext Context; 772 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); 773 774 std::vector<IRInstructionData *> InstrList; 775 std::vector<unsigned> UnsignedVec; 776 777 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator; 778 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator; 779 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator); 780 Mapper.InstClassifier.EnableBranches = true; 781 Mapper.initializeForBBs(*M); 782 getVectors(*M, Mapper, InstrList, UnsignedVec); 783 784 ASSERT_EQ(InstrList.size(), UnsignedVec.size()); 785 ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(3)); 786 } 787 788 // Checks that a PHINode is mapped to be legal. 789 TEST(IRInstructionMapper, PhiIllegal) { 790 StringRef ModuleString = R"( 791 define i32 @f(i32 %a, i32 %b) { 792 bb0: 793 %0 = phi i1 [ 0, %bb0 ], [ %0, %bb1 ] 794 %1 = add i32 %a, %b 795 ret i32 0 796 bb1: 797 ret i32 1 798 })"; 799 LLVMContext Context; 800 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); 801 802 std::vector<IRInstructionData *> InstrList; 803 std::vector<unsigned> UnsignedVec; 804 805 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator; 806 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator; 807 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator); 808 Mapper.initializeForBBs(*M); 809 getVectors(*M, Mapper, InstrList, UnsignedVec); 810 811 ASSERT_EQ(InstrList.size(), UnsignedVec.size()); 812 ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(0)); 813 } 814 815 // In most cases, the illegal instructions we are collecting don't require any 816 // sort of setup. In these cases, we can just only have illegal instructions, 817 // and the mapper will create 0 length vectors, and we can check that. 818 819 // In cases where we have legal instructions needed to set up the illegal 820 // instruction, to check illegal instructions are assigned unsigned integers 821 // from the maximum value decreasing to 0, it will be greater than a legal 822 // instruction that comes after. So to check that we have an illegal 823 // instruction, we place a legal instruction after an illegal instruction, and 824 // check that the illegal unsigned integer is greater than the unsigned integer 825 // of the legal instruction. 826 827 // Checks that an alloca instruction is mapped to be illegal. 828 TEST(IRInstructionMapper, AllocaIllegal) { 829 StringRef ModuleString = R"( 830 define i32 @f(i32 %a, i32 %b) { 831 bb0: 832 %0 = alloca i32 833 ret i32 0 834 })"; 835 LLVMContext Context; 836 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); 837 838 std::vector<IRInstructionData *> InstrList; 839 std::vector<unsigned> UnsignedVec; 840 841 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator; 842 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator; 843 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator); 844 getVectors(*M, Mapper, InstrList, UnsignedVec); 845 846 ASSERT_EQ(InstrList.size(), UnsignedVec.size()); 847 ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(0)); 848 } 849 850 // Checks that an getelementptr instruction is mapped to be legal. And that 851 // the operands in getelementpointer instructions are the exact same after the 852 // first element operand, which only requires the same type. 853 TEST(IRInstructionMapper, GetElementPtrSameEndOperands) { 854 StringRef ModuleString = R"( 855 %struct.RT = type { i8, [10 x [20 x i32]], i8 } 856 %struct.ST = type { i32, double, %struct.RT } 857 define i32 @f(%struct.ST* %s, i64 %a, i64 %b) { 858 bb0: 859 %0 = getelementptr inbounds %struct.ST, %struct.ST* %s, i64 %a, i32 0 860 %1 = getelementptr inbounds %struct.ST, %struct.ST* %s, i64 %b, i32 0 861 ret i32 0 862 })"; 863 LLVMContext Context; 864 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); 865 866 std::vector<IRInstructionData *> InstrList; 867 std::vector<unsigned> UnsignedVec; 868 869 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator; 870 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator; 871 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator); 872 getVectors(*M, Mapper, InstrList, UnsignedVec); 873 874 ASSERT_EQ(InstrList.size(), UnsignedVec.size()); 875 ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(3)); 876 ASSERT_EQ(UnsignedVec[0], UnsignedVec[1]); 877 } 878 879 // Check that when the operands in getelementpointer instructions are not the 880 // exact same after the first element operand, the instructions are mapped to 881 // different values. 882 TEST(IRInstructionMapper, GetElementPtrDifferentEndOperands) { 883 StringRef ModuleString = R"( 884 %struct.RT = type { i8, [10 x [20 x i32]], i8 } 885 %struct.ST = type { i32, double, %struct.RT } 886 define i32 @f(%struct.ST* %s, i64 %a, i64 %b) { 887 bb0: 888 %0 = getelementptr inbounds %struct.ST, %struct.ST* %s, i64 %a, i32 0 889 %1 = getelementptr inbounds %struct.ST, %struct.ST* %s, i64 %b, i32 2 890 ret i32 0 891 })"; 892 LLVMContext Context; 893 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); 894 895 std::vector<IRInstructionData *> InstrList; 896 std::vector<unsigned> UnsignedVec; 897 898 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator; 899 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator; 900 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator); 901 getVectors(*M, Mapper, InstrList, UnsignedVec); 902 903 ASSERT_EQ(InstrList.size(), UnsignedVec.size()); 904 ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(3)); 905 ASSERT_NE(UnsignedVec[0], UnsignedVec[1]); 906 } 907 908 // Check that when the operands in getelementpointer instructions are not the 909 // same initial base type, each instruction is mapped to a different value. 910 TEST(IRInstructionMapper, GetElementPtrDifferentBaseType) { 911 StringRef ModuleString = R"( 912 %struct.RT = type { i8, [10 x [20 x i32]], i8 } 913 %struct.ST = type { i32, double, %struct.RT } 914 define i32 @f(%struct.ST* %s, %struct.RT* %r, i64 %a, i64 %b) { 915 bb0: 916 %0 = getelementptr inbounds %struct.ST, %struct.ST* %s, i64 %a 917 %1 = getelementptr inbounds %struct.RT, %struct.RT* %r, i64 %b 918 ret i32 0 919 })"; 920 LLVMContext Context; 921 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); 922 923 std::vector<IRInstructionData *> InstrList; 924 std::vector<unsigned> UnsignedVec; 925 926 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator; 927 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator; 928 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator); 929 getVectors(*M, Mapper, InstrList, UnsignedVec); 930 931 ASSERT_EQ(InstrList.size(), UnsignedVec.size()); 932 ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(3)); 933 ASSERT_NE(UnsignedVec[0], UnsignedVec[1]); 934 } 935 936 // Check that when the operands in getelementpointer instructions do not have 937 // the same inbounds modifier, they are not counted as the same. 938 TEST(IRInstructionMapper, GetElementPtrDifferentInBounds) { 939 StringRef ModuleString = R"( 940 %struct.RT = type { i8, [10 x [20 x i32]], i8 } 941 %struct.ST = type { i32, double, %struct.RT } 942 define i32 @f(%struct.ST* %s, %struct.RT* %r, i64 %a, i64 %b) { 943 bb0: 944 %0 = getelementptr inbounds %struct.ST, %struct.ST* %s, i64 %a, i32 0 945 %1 = getelementptr %struct.ST, %struct.ST* %s, i64 %b, i32 0 946 ret i32 0 947 })"; 948 LLVMContext Context; 949 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); 950 951 std::vector<IRInstructionData *> InstrList; 952 std::vector<unsigned> UnsignedVec; 953 954 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator; 955 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator; 956 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator); 957 getVectors(*M, Mapper, InstrList, UnsignedVec); 958 959 ASSERT_EQ(InstrList.size(), UnsignedVec.size()); 960 ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(3)); 961 ASSERT_NE(UnsignedVec[0], UnsignedVec[1]); 962 } 963 964 // Checks that indirect call instructions are mapped to be illegal when it is 965 // specified to disallow them. 966 TEST(IRInstructionMapper, CallsIllegalIndirect) { 967 StringRef ModuleString = R"( 968 define i32 @f(void()* %func) { 969 bb0: 970 call void %func() 971 ret i32 0 972 })"; 973 LLVMContext Context; 974 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); 975 976 std::vector<IRInstructionData *> InstrList; 977 std::vector<unsigned> UnsignedVec; 978 979 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator; 980 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator; 981 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator); 982 Mapper.InstClassifier.EnableIndirectCalls = false; 983 getVectors(*M, Mapper, InstrList, UnsignedVec); 984 985 ASSERT_EQ(InstrList.size(), UnsignedVec.size()); 986 ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(0)); 987 } 988 989 // Checks that indirect call instructions are mapped to be legal when it is not 990 // specified to disallow them. 991 TEST(IRInstructionMapper, CallsLegalIndirect) { 992 StringRef ModuleString = R"( 993 define i32 @f(void()* %func) { 994 bb0: 995 call void %func() 996 call void %func() 997 ret i32 0 998 })"; 999 LLVMContext Context; 1000 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); 1001 1002 std::vector<IRInstructionData *> InstrList; 1003 std::vector<unsigned> UnsignedVec; 1004 1005 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator; 1006 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator; 1007 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator); 1008 Mapper.InstClassifier.EnableIndirectCalls = true; 1009 getVectors(*M, Mapper, InstrList, UnsignedVec); 1010 1011 ASSERT_EQ(InstrList.size(), UnsignedVec.size()); 1012 ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(3)); 1013 } 1014 1015 // Checks that a call instruction is mapped to be legal. Here we check that 1016 // a call with the same name, and same types are mapped to the same 1017 // value. 1018 TEST(IRInstructionMapper, CallsSameTypeSameName) { 1019 StringRef ModuleString = R"( 1020 declare i32 @f1(i32, i32) 1021 define i32 @f(i32 %a, i32 %b) { 1022 bb0: 1023 %0 = call i32 @f1(i32 %a, i32 %b) 1024 %1 = call i32 @f1(i32 %a, i32 %b) 1025 ret i32 0 1026 })"; 1027 LLVMContext Context; 1028 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); 1029 1030 std::vector<IRInstructionData *> InstrList; 1031 std::vector<unsigned> UnsignedVec; 1032 1033 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator; 1034 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator; 1035 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator); 1036 getVectors(*M, Mapper, InstrList, UnsignedVec); 1037 1038 ASSERT_EQ(InstrList.size(), UnsignedVec.size()); 1039 ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(3)); 1040 ASSERT_EQ(UnsignedVec[0], UnsignedVec[1]); 1041 } 1042 1043 // Here we check that a calls with different names, but the same arguments types 1044 // are mapped to different value when specified that the name must match. 1045 TEST(IRInstructionMapper, CallsSameArgTypeDifferentNameDisallowed) { 1046 StringRef ModuleString = R"( 1047 declare i32 @f1(i32, i32) 1048 declare i32 @f2(i32, i32) 1049 define i32 @f(i32 %a, i32 %b) { 1050 bb0: 1051 %0 = call i32 @f1(i32 %a, i32 %b) 1052 %1 = call i32 @f2(i32 %a, i32 %b) 1053 ret i32 0 1054 })"; 1055 LLVMContext Context; 1056 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); 1057 1058 std::vector<IRInstructionData *> InstrList; 1059 std::vector<unsigned> UnsignedVec; 1060 1061 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator; 1062 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator; 1063 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator); 1064 Mapper.EnableMatchCallsByName = true; 1065 getVectors(*M, Mapper, InstrList, UnsignedVec); 1066 1067 ASSERT_EQ(InstrList.size(), UnsignedVec.size()); 1068 ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(3)); 1069 ASSERT_NE(UnsignedVec[0], UnsignedVec[1]); 1070 } 1071 1072 // Here we check that a calls with different names, but the same arguments types 1073 // are mapped to the same value when it is not specifed that they must match. 1074 TEST(IRInstructionMapper, CallsSameArgTypeDifferentName) { 1075 StringRef ModuleString = R"( 1076 declare i32 @f1(i32, i32) 1077 declare i32 @f2(i32, i32) 1078 define i32 @f(i32 %a, i32 %b) { 1079 bb0: 1080 %0 = call i32 @f1(i32 %a, i32 %b) 1081 %1 = call i32 @f2(i32 %a, i32 %b) 1082 ret i32 0 1083 })"; 1084 LLVMContext Context; 1085 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); 1086 1087 std::vector<IRInstructionData *> InstrList; 1088 std::vector<unsigned> UnsignedVec; 1089 1090 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator; 1091 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator; 1092 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator); 1093 Mapper.EnableMatchCallsByName = false; 1094 getVectors(*M, Mapper, InstrList, UnsignedVec); 1095 1096 ASSERT_EQ(InstrList.size(), UnsignedVec.size()); 1097 ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(3)); 1098 ASSERT_EQ(UnsignedVec[0], UnsignedVec[1]); 1099 } 1100 1101 // Here we check that a calls with different names, and different arguments 1102 // types are mapped to different value. 1103 TEST(IRInstructionMapper, CallsDifferentArgTypeDifferentName) { 1104 StringRef ModuleString = R"( 1105 declare i32 @f1(i32, i32) 1106 declare i32 @f2(i32) 1107 define i32 @f(i32 %a, i32 %b) { 1108 bb0: 1109 %0 = call i32 @f1(i32 %a, i32 %b) 1110 %1 = call i32 @f2(i32 %a) 1111 ret i32 0 1112 })"; 1113 LLVMContext Context; 1114 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); 1115 1116 std::vector<IRInstructionData *> InstrList; 1117 std::vector<unsigned> UnsignedVec; 1118 1119 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator; 1120 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator; 1121 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator); 1122 getVectors(*M, Mapper, InstrList, UnsignedVec); 1123 1124 ASSERT_EQ(InstrList.size(), UnsignedVec.size()); 1125 ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(3)); 1126 ASSERT_NE(UnsignedVec[0], UnsignedVec[1]); 1127 } 1128 1129 // Here we check that calls with different names, and different return 1130 // types are mapped to different value. 1131 TEST(IRInstructionMapper, CallsDifferentReturnTypeDifferentName) { 1132 StringRef ModuleString = R"( 1133 declare i64 @f1(i32, i32) 1134 declare i32 @f2(i32, i32) 1135 define i32 @f(i32 %a, i32 %b) { 1136 bb0: 1137 %0 = call i64 @f1(i32 %a, i32 %b) 1138 %1 = call i32 @f2(i32 %a, i32 %b) 1139 ret i32 0 1140 })"; 1141 LLVMContext Context; 1142 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); 1143 1144 std::vector<IRInstructionData *> InstrList; 1145 std::vector<unsigned> UnsignedVec; 1146 1147 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator; 1148 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator; 1149 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator); 1150 getVectors(*M, Mapper, InstrList, UnsignedVec); 1151 1152 ASSERT_EQ(InstrList.size(), UnsignedVec.size()); 1153 ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(3)); 1154 ASSERT_NE(UnsignedVec[0], UnsignedVec[1]); 1155 } 1156 1157 // Here we check that calls with the same name, types, and parameters map to the 1158 // same unsigned integer. 1159 TEST(IRInstructionMapper, CallsSameParameters) { 1160 StringRef ModuleString = R"( 1161 declare i32 @f1(i32, i32) 1162 define i32 @f(i32 %a, i32 %b) { 1163 bb0: 1164 %0 = tail call fastcc i32 @f1(i32 %a, i32 %b) 1165 %1 = tail call fastcc i32 @f1(i32 %a, i32 %b) 1166 ret i32 0 1167 })"; 1168 LLVMContext Context; 1169 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); 1170 1171 std::vector<IRInstructionData *> InstrList; 1172 std::vector<unsigned> UnsignedVec; 1173 1174 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator; 1175 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator; 1176 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator); 1177 getVectors(*M, Mapper, InstrList, UnsignedVec); 1178 1179 ASSERT_EQ(InstrList.size(), UnsignedVec.size()); 1180 ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(3)); 1181 ASSERT_EQ(UnsignedVec[0], UnsignedVec[1]); 1182 } 1183 1184 // Here we check that calls with different tail call settings are mapped to 1185 // different values. 1186 TEST(IRInstructionMapper, CallsDifferentTails) { 1187 StringRef ModuleString = R"( 1188 declare i32 @f1(i32, i32) 1189 define i32 @f(i32 %a, i32 %b) { 1190 bb0: 1191 %0 = tail call i32 @f1(i32 %a, i32 %b) 1192 %1 = call i32 @f1(i32 %a, i32 %b) 1193 ret i32 0 1194 })"; 1195 LLVMContext Context; 1196 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); 1197 1198 std::vector<IRInstructionData *> InstrList; 1199 std::vector<unsigned> UnsignedVec; 1200 1201 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator; 1202 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator; 1203 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator); 1204 getVectors(*M, Mapper, InstrList, UnsignedVec); 1205 1206 ASSERT_EQ(InstrList.size(), UnsignedVec.size()); 1207 ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(3)); 1208 ASSERT_NE(UnsignedVec[0], UnsignedVec[1]); 1209 } 1210 1211 // Here we check that calls with different calling convention settings are 1212 // mapped to different values. 1213 TEST(IRInstructionMapper, CallsDifferentCallingConventions) { 1214 StringRef ModuleString = R"( 1215 declare i32 @f1(i32, i32) 1216 define i32 @f(i32 %a, i32 %b) { 1217 bb0: 1218 %0 = call fastcc i32 @f1(i32 %a, i32 %b) 1219 %1 = call i32 @f1(i32 %a, i32 %b) 1220 ret i32 0 1221 })"; 1222 LLVMContext Context; 1223 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); 1224 1225 std::vector<IRInstructionData *> InstrList; 1226 std::vector<unsigned> UnsignedVec; 1227 1228 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator; 1229 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator; 1230 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator); 1231 getVectors(*M, Mapper, InstrList, UnsignedVec); 1232 1233 ASSERT_EQ(InstrList.size(), UnsignedVec.size()); 1234 ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(3)); 1235 ASSERT_NE(UnsignedVec[0], UnsignedVec[1]); 1236 } 1237 1238 // Checks that an invoke instruction is mapped to be illegal. Invoke 1239 // instructions are considered to be illegal because of the change in the 1240 // control flow that is currently not recognized. 1241 TEST(IRInstructionMapper, InvokeIllegal) { 1242 StringRef ModuleString = R"( 1243 define i32 @f(i8 *%gep1, i32 %b) { 1244 then: 1245 invoke i32 undef(i8* undef) 1246 to label %invoke unwind label %lpad 1247 1248 invoke: 1249 unreachable 1250 1251 lpad: 1252 landingpad { i8*, i32 } 1253 catch i8* null 1254 unreachable 1255 })"; 1256 LLVMContext Context; 1257 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); 1258 1259 std::vector<IRInstructionData *> InstrList; 1260 std::vector<unsigned> UnsignedVec; 1261 1262 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator; 1263 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator; 1264 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator); 1265 getVectors(*M, Mapper, InstrList, UnsignedVec); 1266 1267 ASSERT_EQ(InstrList.size(), UnsignedVec.size()); 1268 ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(0)); 1269 } 1270 1271 // Checks that an callbr instructions are considered to be illegal. Callbr 1272 // instructions are considered to be illegal because of the change in the 1273 // control flow that is currently not recognized. 1274 TEST(IRInstructionMapper, CallBrInstIllegal) { 1275 StringRef ModuleString = R"( 1276 define void @test() { 1277 fail: 1278 ret void 1279 } 1280 1281 define i32 @f(i32 %a, i32 %b) { 1282 bb0: 1283 callbr void asm "xorl $0, $0; jmp ${1:l}", "r,X,~{dirflag},~{fpsr},~{flags}"(i32 %a, i8* blockaddress(@test, %fail)) to label %normal [label %fail] 1284 fail: 1285 ret i32 0 1286 normal: 1287 ret i32 0 1288 })"; 1289 LLVMContext Context; 1290 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); 1291 1292 std::vector<IRInstructionData *> InstrList; 1293 std::vector<unsigned> UnsignedVec; 1294 1295 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator; 1296 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator; 1297 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator); 1298 getVectors(*M, Mapper, InstrList, UnsignedVec); 1299 1300 ASSERT_EQ(InstrList.size(), UnsignedVec.size()); 1301 ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(0)); 1302 } 1303 1304 // Checks that an debuginfo intrinsics are mapped to be invisible. Since they 1305 // do not semantically change the program, they can be recognized as similar. 1306 TEST(IRInstructionMapper, DebugInfoInvisible) { 1307 StringRef ModuleString = R"( 1308 define i32 @f(i32 %a, i32 %b) { 1309 then: 1310 %0 = add i32 %a, %b 1311 call void @llvm.dbg.value(metadata !0) 1312 %1 = add i32 %a, %b 1313 ret i32 0 1314 } 1315 1316 declare void @llvm.dbg.value(metadata) 1317 !0 = distinct !{!"test\00", i32 10})"; 1318 LLVMContext Context; 1319 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); 1320 1321 std::vector<IRInstructionData *> InstrList; 1322 std::vector<unsigned> UnsignedVec; 1323 1324 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator; 1325 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator; 1326 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator); 1327 getVectors(*M, Mapper, InstrList, UnsignedVec); 1328 1329 ASSERT_EQ(InstrList.size(), UnsignedVec.size()); 1330 ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(3)); 1331 } 1332 1333 // The following are all exception handling intrinsics. We do not currently 1334 // handle these instruction because they are very context dependent. 1335 1336 // Checks that an eh.typeid.for intrinsic is mapped to be illegal. 1337 TEST(IRInstructionMapper, ExceptionHandlingTypeIdIllegal) { 1338 StringRef ModuleString = R"( 1339 @_ZTIi = external constant i8* 1340 define i32 @f() { 1341 then: 1342 %0 = call i32 @llvm.eh.typeid.for(i8* bitcast (i8** @_ZTIi to i8*)) 1343 ret i32 0 1344 } 1345 1346 declare i32 @llvm.eh.typeid.for(i8*))"; 1347 LLVMContext Context; 1348 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); 1349 1350 std::vector<IRInstructionData *> InstrList; 1351 std::vector<unsigned> UnsignedVec; 1352 1353 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator; 1354 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator; 1355 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator); 1356 getVectors(*M, Mapper, InstrList, UnsignedVec); 1357 1358 ASSERT_EQ(InstrList.size(), UnsignedVec.size()); 1359 ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(0)); 1360 } 1361 1362 // Checks that an eh.exceptioncode intrinsic is mapped to be illegal. 1363 TEST(IRInstructionMapper, ExceptionHandlingExceptionCodeIllegal) { 1364 StringRef ModuleString = R"( 1365 define i32 @f(i32 %a, i32 %b) { 1366 entry: 1367 %0 = catchswitch within none [label %__except] unwind to caller 1368 1369 __except: 1370 %1 = catchpad within %0 [i8* null] 1371 catchret from %1 to label %__except 1372 1373 then: 1374 %2 = call i32 @llvm.eh.exceptioncode(token %1) 1375 ret i32 0 1376 } 1377 1378 declare i32 @llvm.eh.exceptioncode(token))"; 1379 LLVMContext Context; 1380 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); 1381 1382 std::vector<IRInstructionData *> InstrList; 1383 std::vector<unsigned> UnsignedVec; 1384 1385 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator; 1386 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator; 1387 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator); 1388 getVectors(*M, Mapper, InstrList, UnsignedVec); 1389 1390 ASSERT_EQ(InstrList.size(), UnsignedVec.size()); 1391 ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(0)); 1392 } 1393 1394 // Checks that an eh.unwind intrinsic is mapped to be illegal. 1395 TEST(IRInstructionMapper, ExceptionHandlingUnwindIllegal) { 1396 StringRef ModuleString = R"( 1397 define i32 @f(i32 %a, i32 %b) { 1398 entry: 1399 call void @llvm.eh.unwind.init() 1400 ret i32 0 1401 } 1402 1403 declare void @llvm.eh.unwind.init())"; 1404 LLVMContext Context; 1405 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); 1406 1407 std::vector<IRInstructionData *> InstrList; 1408 std::vector<unsigned> UnsignedVec; 1409 1410 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator; 1411 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator; 1412 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator); 1413 getVectors(*M, Mapper, InstrList, UnsignedVec); 1414 1415 ASSERT_EQ(InstrList.size(), UnsignedVec.size()); 1416 ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(0)); 1417 } 1418 1419 // Checks that an eh.exceptionpointer intrinsic is mapped to be illegal. 1420 TEST(IRInstructionMapper, ExceptionHandlingExceptionPointerIllegal) { 1421 StringRef ModuleString = R"( 1422 define i32 @f(i32 %a, i32 %b) { 1423 entry: 1424 %0 = call i8* @llvm.eh.exceptionpointer.p0i8(i32 0) 1425 ret i32 0 1426 } 1427 1428 declare i8* @llvm.eh.exceptionpointer.p0i8(i32))"; 1429 LLVMContext Context; 1430 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); 1431 1432 std::vector<IRInstructionData *> InstrList; 1433 std::vector<unsigned> UnsignedVec; 1434 1435 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator; 1436 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator; 1437 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator); 1438 getVectors(*M, Mapper, InstrList, UnsignedVec); 1439 1440 ASSERT_EQ(InstrList.size(), UnsignedVec.size()); 1441 ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(0)); 1442 } 1443 1444 // Checks that a catchpad instruction is mapped to an illegal value. 1445 TEST(IRInstructionMapper, CatchpadIllegal) { 1446 StringRef ModuleString = R"( 1447 declare void @llvm.donothing() nounwind readnone 1448 1449 define void @function() personality i8 3 { 1450 entry: 1451 invoke void @llvm.donothing() to label %normal unwind label %exception 1452 exception: 1453 %cs1 = catchswitch within none [label %catchpad1] unwind to caller 1454 catchpad1: 1455 catchpad within %cs1 [] 1456 br label %normal 1457 normal: 1458 ret void 1459 })"; 1460 LLVMContext Context; 1461 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); 1462 1463 std::vector<IRInstructionData *> InstrList; 1464 std::vector<unsigned> UnsignedVec; 1465 1466 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator; 1467 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator; 1468 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator); 1469 getVectors(*M, Mapper, InstrList, UnsignedVec); 1470 1471 ASSERT_EQ(InstrList.size(), UnsignedVec.size()); 1472 ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(0)); 1473 } 1474 1475 // Checks that a cleanuppad instruction is mapped to an illegal value. 1476 TEST(IRInstructionMapper, CleanuppadIllegal) { 1477 StringRef ModuleString = R"( 1478 declare void @llvm.donothing() nounwind readnone 1479 1480 define void @function() personality i8 3 { 1481 entry: 1482 invoke void @llvm.donothing() to label %normal unwind label %exception 1483 exception: 1484 %cs1 = catchswitch within none [label %catchpad1] unwind to caller 1485 catchpad1: 1486 %clean = cleanuppad within none [] 1487 br label %normal 1488 normal: 1489 ret void 1490 })"; 1491 LLVMContext Context; 1492 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); 1493 1494 std::vector<IRInstructionData *> InstrList; 1495 std::vector<unsigned> UnsignedVec; 1496 1497 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator; 1498 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator; 1499 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator); 1500 getVectors(*M, Mapper, InstrList, UnsignedVec); 1501 1502 ASSERT_EQ(InstrList.size(), UnsignedVec.size()); 1503 ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(0)); 1504 } 1505 1506 // The following three instructions are memory transfer and setting based, which 1507 // are considered illegal since is extra checking needed to handle the address 1508 // space checking. 1509 1510 // Checks that a memset instruction is mapped to an illegal value when 1511 // specified. 1512 TEST(IRInstructionMapper, MemSetIllegal) { 1513 StringRef ModuleString = R"( 1514 declare void @llvm.memset.p0i8.i64(i8* nocapture writeonly, i8, i64, i32, i1) 1515 1516 define i64 @function(i64 %x, i64 %z, i64 %n) { 1517 entry: 1518 %pool = alloca [59 x i64], align 4 1519 %tmp = bitcast [59 x i64]* %pool to i8* 1520 call void @llvm.memset.p0i8.i64(i8* nonnull %tmp, i8 0, i64 236, i32 4, i1 false) 1521 %cmp3 = icmp eq i64 %n, 0 1522 %a = add i64 %x, %z 1523 %c = add i64 %x, %z 1524 ret i64 0 1525 })"; 1526 LLVMContext Context; 1527 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); 1528 1529 std::vector<IRInstructionData *> InstrList; 1530 std::vector<unsigned> UnsignedVec; 1531 1532 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator; 1533 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator; 1534 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator); 1535 Mapper.InstClassifier.EnableIntrinsics = false; 1536 getVectors(*M, Mapper, InstrList, UnsignedVec); 1537 1538 ASSERT_EQ(InstrList.size(), UnsignedVec.size()); 1539 ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(7)); 1540 ASSERT_TRUE(UnsignedVec[2] < UnsignedVec[0]); 1541 } 1542 1543 // Checks that a memcpy instruction is mapped to an illegal value when 1544 // specified. 1545 TEST(IRInstructionMapper, MemCpyIllegal) { 1546 StringRef ModuleString = R"( 1547 declare void @llvm.memcpy.p0i8.i64(i8* nocapture writeonly, i8, i64, i32, i1) 1548 1549 define i64 @function(i64 %x, i64 %z, i64 %n) { 1550 entry: 1551 %pool = alloca [59 x i64], align 4 1552 %tmp = bitcast [59 x i64]* %pool to i8* 1553 call void @llvm.memcpy.p0i8.i64(i8* nonnull %tmp, i8 0, i64 236, i32 4, i1 false) 1554 %cmp3 = icmp eq i64 %n, 0 1555 %a = add i64 %x, %z 1556 %c = add i64 %x, %z 1557 ret i64 0 1558 })"; 1559 LLVMContext Context; 1560 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); 1561 1562 std::vector<IRInstructionData *> InstrList; 1563 std::vector<unsigned> UnsignedVec; 1564 1565 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator; 1566 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator; 1567 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator); 1568 Mapper.InstClassifier.EnableIntrinsics = false; 1569 getVectors(*M, Mapper, InstrList, UnsignedVec); 1570 1571 ASSERT_EQ(InstrList.size(), UnsignedVec.size()); 1572 ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(7)); 1573 ASSERT_GT(UnsignedVec[2], UnsignedVec[3]); 1574 ASSERT_LT(UnsignedVec[2], UnsignedVec[0]); 1575 } 1576 1577 // Checks that a memmove instruction is mapped to an illegal value when 1578 // specified. 1579 TEST(IRInstructionMapper, MemMoveIllegal) { 1580 StringRef ModuleString = R"( 1581 declare void @llvm.memmove.p0i8.i64(i8* nocapture writeonly, i8, i64, i32, i1) 1582 1583 define i64 @function(i64 %x, i64 %z, i64 %n) { 1584 entry: 1585 %pool = alloca [59 x i64], align 4 1586 %tmp = bitcast [59 x i64]* %pool to i8* 1587 call void @llvm.memmove.p0i8.i64(i8* nonnull %tmp, i8 0, i64 236, i32 4, i1 false) 1588 %cmp3 = icmp eq i64 %n, 0 1589 %a = add i64 %x, %z 1590 %c = add i64 %x, %z 1591 ret i64 0 1592 })"; 1593 LLVMContext Context; 1594 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); 1595 1596 std::vector<IRInstructionData *> InstrList; 1597 std::vector<unsigned> UnsignedVec; 1598 1599 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator; 1600 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator; 1601 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator); 1602 Mapper.InstClassifier.EnableIntrinsics = false; 1603 getVectors(*M, Mapper, InstrList, UnsignedVec); 1604 1605 ASSERT_EQ(InstrList.size(), UnsignedVec.size()); 1606 ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(7)); 1607 ASSERT_LT(UnsignedVec[2], UnsignedVec[0]); 1608 } 1609 1610 // Checks that mem* instructions are mapped to an legal value when not 1611 // specified, and that all the intrinsics are marked differently. 1612 TEST(IRInstructionMapper, MemOpsLegal) { 1613 StringRef ModuleString = R"( 1614 declare void @llvm.memmove.p0i8.i64(i8* nocapture writeonly, i8, i64, i32, i1) 1615 declare void @llvm.memcpy.p0i8.i64(i8* nocapture writeonly, i8, i64, i32, i1) 1616 declare void @llvm.memset.p0i8.i64(i8* nocapture writeonly, i8, i64, i32, i1) 1617 1618 define i64 @function(i64 %x, i64 %z, i64 %n) { 1619 entry: 1620 %pool = alloca [59 x i64], align 4 1621 %tmp = bitcast [59 x i64]* %pool to i8* 1622 call void @llvm.memmove.p0i8.i64(i8* nonnull %tmp, i8 0, i64 236, i32 4, i1 false) 1623 call void @llvm.memcpy.p0i8.i64(i8* nonnull %tmp, i8 0, i64 236, i32 4, i1 false) 1624 call void @llvm.memset.p0i8.i64(i8* nonnull %tmp, i8 0, i64 236, i32 4, i1 false) 1625 %cmp3 = icmp eq i64 %n, 0 1626 %a = add i64 %x, %z 1627 %c = add i64 %x, %z 1628 ret i64 0 1629 })"; 1630 LLVMContext Context; 1631 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); 1632 1633 std::vector<IRInstructionData *> InstrList; 1634 std::vector<unsigned> UnsignedVec; 1635 1636 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator; 1637 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator; 1638 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator); 1639 Mapper.InstClassifier.EnableIntrinsics = true; 1640 getVectors(*M, Mapper, InstrList, UnsignedVec); 1641 1642 ASSERT_EQ(InstrList.size(), UnsignedVec.size()); 1643 ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(9)); 1644 ASSERT_LT(UnsignedVec[2], UnsignedVec[3]); 1645 ASSERT_LT(UnsignedVec[3], UnsignedVec[4]); 1646 ASSERT_LT(UnsignedVec[4], UnsignedVec[5]); 1647 } 1648 1649 // Checks that a variable argument instructions are mapped to an illegal value. 1650 // We exclude variable argument instructions since variable arguments 1651 // requires extra checking of the argument list. 1652 TEST(IRInstructionMapper, VarArgsIllegal) { 1653 StringRef ModuleString = R"( 1654 declare void @llvm.va_start(i8*) 1655 declare void @llvm.va_copy(i8*, i8*) 1656 declare void @llvm.va_end(i8*) 1657 1658 define i32 @func1(i32 %a, double %b, i8* %v, ...) nounwind { 1659 entry: 1660 %a.addr = alloca i32, align 4 1661 %b.addr = alloca double, align 8 1662 %ap = alloca i8*, align 4 1663 %c = alloca i32, align 4 1664 store i32 %a, i32* %a.addr, align 4 1665 store double %b, double* %b.addr, align 8 1666 %ap1 = bitcast i8** %ap to i8* 1667 call void @llvm.va_start(i8* %ap1) 1668 store double %b, double* %b.addr, align 8 1669 store double %b, double* %b.addr, align 8 1670 %0 = va_arg i8** %ap, i32 1671 store double %b, double* %b.addr, align 8 1672 store double %b, double* %b.addr, align 8 1673 call void @llvm.va_copy(i8* %v, i8* %ap1) 1674 store double %b, double* %b.addr, align 8 1675 store double %b, double* %b.addr, align 8 1676 call void @llvm.va_end(i8* %ap1) 1677 store i32 %0, i32* %c, align 4 1678 %tmp = load i32, i32* %c, align 4 1679 ret i32 %tmp 1680 })"; 1681 LLVMContext Context; 1682 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); 1683 1684 std::vector<IRInstructionData *> InstrList; 1685 std::vector<unsigned> UnsignedVec; 1686 1687 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator; 1688 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator; 1689 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator); 1690 Mapper.InstClassifier.EnableIntrinsics = false; 1691 getVectors(*M, Mapper, InstrList, UnsignedVec); 1692 1693 ASSERT_EQ(InstrList.size(), UnsignedVec.size()); 1694 ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(17)); 1695 ASSERT_TRUE(UnsignedVec[7] < UnsignedVec[0]); 1696 ASSERT_TRUE(UnsignedVec[13] < UnsignedVec[10]); 1697 ASSERT_TRUE(UnsignedVec[16] < UnsignedVec[13]); 1698 } 1699 1700 // Check the length of adding two illegal instructions one after th other. We 1701 // should find that only one element is added for each illegal range. 1702 TEST(IRInstructionMapper, RepeatedIllegalLength) { 1703 StringRef ModuleString = R"( 1704 define i32 @f(i32 %a, i32 %b) { 1705 bb0: 1706 %0 = add i32 %a, %b 1707 %1 = mul i32 %a, %b 1708 %2 = alloca i32 1709 %3 = alloca i32 1710 %4 = add i32 %a, %b 1711 %5 = mul i32 %a, %b 1712 ret i32 0 1713 })"; 1714 LLVMContext Context; 1715 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); 1716 1717 std::vector<IRInstructionData *> InstrList; 1718 std::vector<unsigned> UnsignedVec; 1719 1720 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator; 1721 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator; 1722 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator); 1723 getVectors(*M, Mapper, InstrList, UnsignedVec); 1724 1725 // Check that the size of the unsigned vector and the instruction list are the 1726 // same as a safety check. 1727 ASSERT_TRUE(InstrList.size() == UnsignedVec.size()); 1728 1729 // Make sure that the unsigned vector is the expected size. 1730 ASSERT_TRUE(UnsignedVec.size() == 6); 1731 } 1732 1733 // A helper function that accepts an instruction list from a module made up of 1734 // two blocks of two legal instructions and terminator, and checks them for 1735 // instruction similarity. 1736 static bool longSimCandCompare(std::vector<IRInstructionData *> &InstrList, 1737 bool Structure = false, unsigned Length = 2, 1738 unsigned StartIdxOne = 0, 1739 unsigned StartIdxTwo = 3) { 1740 std::vector<IRInstructionData *>::iterator Start, End; 1741 1742 Start = InstrList.begin(); 1743 End = InstrList.begin(); 1744 1745 std::advance(End, StartIdxOne + Length - 1); 1746 IRSimilarityCandidate Cand1(StartIdxOne, Length, *Start, *End); 1747 1748 Start = InstrList.begin(); 1749 End = InstrList.begin(); 1750 1751 std::advance(Start, StartIdxTwo); 1752 std::advance(End, StartIdxTwo + Length - 1); 1753 IRSimilarityCandidate Cand2(StartIdxTwo, Length, *Start, *End); 1754 if (Structure) 1755 return IRSimilarityCandidate::compareStructure(Cand1, Cand2); 1756 return IRSimilarityCandidate::isSimilar(Cand1, Cand2); 1757 } 1758 1759 // Checks that two adds with commuted operands are considered to be the same 1760 // instructions. 1761 TEST(IRSimilarityCandidate, CheckIdenticalInstructions) { 1762 StringRef ModuleString = R"( 1763 define i32 @f(i32 %a, i32 %b) { 1764 bb0: 1765 %0 = add i32 %a, %b 1766 %1 = add i32 %b, %a 1767 ret i32 0 1768 })"; 1769 LLVMContext Context; 1770 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); 1771 1772 std::vector<IRInstructionData *> InstrList; 1773 std::vector<unsigned> UnsignedVec; 1774 1775 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator; 1776 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator; 1777 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator); 1778 getVectors(*M, Mapper, InstrList, UnsignedVec); 1779 1780 // Check to make sure that we have a long enough region. 1781 ASSERT_EQ(InstrList.size(), static_cast<unsigned>(3)); 1782 // Check that the instructions were added correctly to both vectors. 1783 ASSERT_TRUE(InstrList.size() == UnsignedVec.size()); 1784 1785 std::vector<IRInstructionData *>::iterator Start, End; 1786 Start = InstrList.begin(); 1787 End = InstrList.begin(); 1788 std::advance(End, 1); 1789 IRSimilarityCandidate Cand1(0, 2, *Start, *End); 1790 IRSimilarityCandidate Cand2(0, 2, *Start, *End); 1791 1792 ASSERT_TRUE(IRSimilarityCandidate::isSimilar(Cand1, Cand2)); 1793 } 1794 1795 // Checks that comparison instructions are found to be similar instructions 1796 // when the operands are flipped and the predicate is also swapped. 1797 TEST(IRSimilarityCandidate, PredicateIsomorphism) { 1798 StringRef ModuleString = R"( 1799 define i32 @f(i32 %a, i32 %b) { 1800 bb0: 1801 %0 = icmp sgt i32 %a, %b 1802 %1 = add i32 %b, %a 1803 br label %bb1 1804 bb1: 1805 %2 = icmp slt i32 %a, %b 1806 %3 = add i32 %a, %b 1807 ret i32 0 1808 })"; 1809 LLVMContext Context; 1810 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); 1811 1812 std::vector<IRInstructionData *> InstrList; 1813 std::vector<unsigned> UnsignedVec; 1814 1815 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator; 1816 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator; 1817 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator); 1818 getVectors(*M, Mapper, InstrList, UnsignedVec); 1819 1820 ASSERT_TRUE(InstrList.size() > 5); 1821 ASSERT_TRUE(InstrList.size() == UnsignedVec.size()); 1822 1823 std::vector<IRInstructionData *>::iterator Start, End; 1824 Start = InstrList.begin(); 1825 End = InstrList.begin(); 1826 1827 std::advance(End, 1); 1828 IRSimilarityCandidate Cand1(0, 2, *Start, *End); 1829 1830 Start = InstrList.begin(); 1831 End = InstrList.begin(); 1832 1833 std::advance(Start, 3); 1834 std::advance(End, 4); 1835 IRSimilarityCandidate Cand2(3, 2, *Start, *End); 1836 1837 ASSERT_TRUE(IRSimilarityCandidate::isSimilar(Cand1, Cand2)); 1838 } 1839 1840 // Checks that IRSimilarityCandidates wrapping these two regions of instructions 1841 // are able to differentiate between instructions that have different opcodes. 1842 TEST(IRSimilarityCandidate, CheckRegionsDifferentInstruction) { 1843 StringRef ModuleString = R"( 1844 define i32 @f(i32 %a, i32 %b) { 1845 bb0: 1846 %0 = add i32 %a, %b 1847 %1 = add i32 %b, %a 1848 ret i32 0 1849 bb1: 1850 %2 = sub i32 %a, %b 1851 %3 = add i32 %b, %a 1852 ret i32 0 1853 })"; 1854 LLVMContext Context; 1855 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); 1856 1857 std::vector<IRInstructionData *> InstrList; 1858 std::vector<unsigned> UnsignedVec; 1859 1860 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator; 1861 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator; 1862 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator); 1863 getVectors(*M, Mapper, InstrList, UnsignedVec); 1864 1865 // Check to make sure that we have a long enough region. 1866 ASSERT_EQ(InstrList.size(), static_cast<unsigned>(6)); 1867 // Check that the instructions were added correctly to both vectors. 1868 ASSERT_TRUE(InstrList.size() == UnsignedVec.size()); 1869 1870 ASSERT_FALSE(longSimCandCompare(InstrList)); 1871 } 1872 1873 // Checks that IRSimilarityCandidates wrapping these two regions of instructions 1874 // are able to differentiate between instructions that have different types. 1875 TEST(IRSimilarityCandidate, CheckRegionsDifferentTypes) { 1876 StringRef ModuleString = R"( 1877 define i32 @f(i32 %a, i32 %b, i64 %c, i64 %d) { 1878 bb0: 1879 %0 = add i32 %a, %b 1880 %1 = add i32 %b, %a 1881 ret i32 0 1882 bb1: 1883 %2 = add i64 %c, %d 1884 %3 = add i64 %d, %c 1885 ret i32 0 1886 })"; 1887 LLVMContext Context; 1888 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); 1889 1890 std::vector<IRInstructionData *> InstrList; 1891 std::vector<unsigned> UnsignedVec; 1892 1893 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator; 1894 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator; 1895 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator); 1896 getVectors(*M, Mapper, InstrList, UnsignedVec); 1897 1898 // Check to make sure that we have a long enough region. 1899 ASSERT_EQ(InstrList.size(), static_cast<unsigned>(6)); 1900 // Check that the instructions were added correctly to both vectors. 1901 ASSERT_TRUE(InstrList.size() == UnsignedVec.size()); 1902 1903 ASSERT_FALSE(longSimCandCompare(InstrList)); 1904 } 1905 1906 // Check that debug instructions do not impact similarity. They are marked as 1907 // invisible. 1908 TEST(IRSimilarityCandidate, IdenticalWithDebug) { 1909 StringRef ModuleString = R"( 1910 define i32 @f(i32 %a, i32 %b) { 1911 bb0: 1912 %0 = add i32 %a, %b 1913 call void @llvm.dbg.value(metadata !0) 1914 %1 = add i32 %b, %a 1915 ret i32 0 1916 bb1: 1917 %2 = add i32 %a, %b 1918 call void @llvm.dbg.value(metadata !1) 1919 %3 = add i32 %b, %a 1920 ret i32 0 1921 bb2: 1922 %4 = add i32 %a, %b 1923 %5 = add i32 %b, %a 1924 ret i32 0 1925 } 1926 1927 declare void @llvm.dbg.value(metadata) 1928 !0 = distinct !{!"test\00", i32 10} 1929 !1 = distinct !{!"test\00", i32 11})"; 1930 LLVMContext Context; 1931 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); 1932 1933 std::vector<IRInstructionData *> InstrList; 1934 std::vector<unsigned> UnsignedVec; 1935 1936 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator; 1937 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator; 1938 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator); 1939 getVectors(*M, Mapper, InstrList, UnsignedVec); 1940 1941 // Check to make sure that we have a long enough region. 1942 ASSERT_EQ(InstrList.size(), static_cast<unsigned>(9)); 1943 // Check that the instructions were added correctly to both vectors. 1944 ASSERT_TRUE(InstrList.size() == UnsignedVec.size()); 1945 1946 ASSERT_TRUE(longSimCandCompare(InstrList)); 1947 } 1948 1949 // Checks that IRSimilarityCandidates that include illegal instructions, are not 1950 // considered to be the same set of instructions. In these sets of instructions 1951 // the allocas are illegal. 1952 TEST(IRSimilarityCandidate, IllegalInCandidate) { 1953 StringRef ModuleString = R"( 1954 define i32 @f(i32 %a, i32 %b) { 1955 bb0: 1956 %0 = add i32 %a, %b 1957 %1 = add i32 %a, %b 1958 %2 = alloca i32 1959 ret i32 0 1960 bb1: 1961 %3 = add i32 %a, %b 1962 %4 = add i32 %a, %b 1963 %5 = alloca i32 1964 ret i32 0 1965 })"; 1966 LLVMContext Context; 1967 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); 1968 1969 std::vector<IRInstructionData *> InstrList; 1970 std::vector<unsigned> UnsignedVec; 1971 1972 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator; 1973 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator; 1974 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator); 1975 getVectors(*M, Mapper, InstrList, UnsignedVec); 1976 1977 // Check to make sure that we have a long enough region. 1978 ASSERT_EQ(InstrList.size(), static_cast<unsigned>(6)); 1979 // Check that the instructions were added correctly to both vectors. 1980 ASSERT_TRUE(InstrList.size() == UnsignedVec.size()); 1981 1982 std::vector<IRInstructionData *>::iterator Start, End; 1983 1984 Start = InstrList.begin(); 1985 End = InstrList.begin(); 1986 1987 std::advance(End, 2); 1988 IRSimilarityCandidate Cand1(0, 3, *Start, *End); 1989 1990 Start = InstrList.begin(); 1991 End = InstrList.begin(); 1992 1993 std::advance(Start, 3); 1994 std::advance(End, 5); 1995 IRSimilarityCandidate Cand2(3, 3, *Start, *End); 1996 ASSERT_FALSE(IRSimilarityCandidate::isSimilar(Cand1, Cand2)); 1997 } 1998 1999 // Checks that different structure, in this case, where we introduce a new 2000 // needed input in one region, is recognized as different. 2001 TEST(IRSimilarityCandidate, DifferentStructure) { 2002 StringRef ModuleString = R"( 2003 define i32 @f(i32 %a, i32 %b) { 2004 bb0: 2005 %0 = add i32 %a, %b 2006 %1 = add i32 %b, %a 2007 ret i32 0 2008 bb1: 2009 %2 = add i32 %a, %b 2010 %3 = add i32 %b, %0 2011 ret i32 0 2012 })"; 2013 LLVMContext Context; 2014 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); 2015 2016 std::vector<IRInstructionData *> InstrList; 2017 std::vector<unsigned> UnsignedVec; 2018 2019 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator; 2020 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator; 2021 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator); 2022 getVectors(*M, Mapper, InstrList, UnsignedVec); 2023 2024 // Check to make sure that we have a long enough region. 2025 ASSERT_EQ(InstrList.size(), static_cast<unsigned>(6)); 2026 // Check that the instructions were added correctly to both vectors. 2027 ASSERT_TRUE(InstrList.size() == UnsignedVec.size()); 2028 2029 ASSERT_FALSE(longSimCandCompare(InstrList, true)); 2030 } 2031 2032 // Checks that comparison instructions are found to have the same structure 2033 // when the operands are flipped and the predicate is also swapped. 2034 TEST(IRSimilarityCandidate, PredicateIsomorphismStructure) { 2035 StringRef ModuleString = R"( 2036 define i32 @f(i32 %a, i32 %b) { 2037 bb0: 2038 %0 = icmp sgt i32 %a, %b 2039 %1 = add i32 %a, %b 2040 br label %bb1 2041 bb1: 2042 %2 = icmp slt i32 %b, %a 2043 %3 = add i32 %a, %b 2044 ret i32 0 2045 })"; 2046 LLVMContext Context; 2047 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); 2048 2049 std::vector<IRInstructionData *> InstrList; 2050 std::vector<unsigned> UnsignedVec; 2051 2052 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator; 2053 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator; 2054 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator); 2055 getVectors(*M, Mapper, InstrList, UnsignedVec); 2056 2057 ASSERT_TRUE(InstrList.size() > 5); 2058 ASSERT_TRUE(InstrList.size() == UnsignedVec.size()); 2059 2060 ASSERT_TRUE(longSimCandCompare(InstrList, true)); 2061 } 2062 2063 // Checks that different predicates are counted as diferent. 2064 TEST(IRSimilarityCandidate, PredicateDifference) { 2065 StringRef ModuleString = R"( 2066 define i32 @f(i32 %a, i32 %b) { 2067 bb0: 2068 %0 = icmp sge i32 %a, %b 2069 %1 = add i32 %b, %a 2070 br label %bb1 2071 bb1: 2072 %2 = icmp slt i32 %b, %a 2073 %3 = add i32 %a, %b 2074 ret i32 0 2075 })"; 2076 LLVMContext Context; 2077 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); 2078 2079 std::vector<IRInstructionData *> InstrList; 2080 std::vector<unsigned> UnsignedVec; 2081 2082 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator; 2083 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator; 2084 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator); 2085 getVectors(*M, Mapper, InstrList, UnsignedVec); 2086 2087 ASSERT_TRUE(InstrList.size() > 5); 2088 ASSERT_TRUE(InstrList.size() == UnsignedVec.size()); 2089 2090 ASSERT_FALSE(longSimCandCompare(InstrList)); 2091 } 2092 2093 // Checks that the same structure is recognized between two candidates. The 2094 // items %a and %b are used in the same way in both sets of instructions. 2095 TEST(IRSimilarityCandidate, SameStructure) { 2096 StringRef ModuleString = R"( 2097 define i32 @f(i32 %a, i32 %b) { 2098 bb0: 2099 %0 = add i32 %a, %b 2100 %1 = sub i32 %b, %a 2101 ret i32 0 2102 bb1: 2103 %2 = add i32 %a, %b 2104 %3 = sub i32 %b, %a 2105 ret i32 0 2106 })"; 2107 LLVMContext Context; 2108 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); 2109 2110 std::vector<IRInstructionData *> InstrList; 2111 std::vector<unsigned> UnsignedVec; 2112 2113 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator; 2114 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator; 2115 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator); 2116 getVectors(*M, Mapper, InstrList, UnsignedVec); 2117 2118 // Check to make sure that we have a long enough region. 2119 ASSERT_EQ(InstrList.size(), static_cast<unsigned>(6)); 2120 // Check that the instructions were added correctly to both vectors. 2121 ASSERT_TRUE(InstrList.size() == UnsignedVec.size()); 2122 2123 ASSERT_TRUE(longSimCandCompare(InstrList, true)); 2124 } 2125 2126 // Checks that the canonical numbering between two candidates matches the found 2127 // mapping between two candidates. 2128 TEST(IRSimilarityCandidate, CanonicalNumbering) { 2129 StringRef ModuleString = R"( 2130 define i32 @f(i32 %a, i32 %b) { 2131 bb0: 2132 %0 = add i32 %a, %b 2133 %1 = sub i32 %b, %a 2134 ret i32 0 2135 bb1: 2136 %2 = add i32 %a, %b 2137 %3 = sub i32 %b, %a 2138 ret i32 0 2139 })"; 2140 LLVMContext Context; 2141 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); 2142 2143 std::vector<IRInstructionData *> InstrList; 2144 std::vector<unsigned> UnsignedVec; 2145 2146 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator; 2147 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator; 2148 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator); 2149 getVectors(*M, Mapper, InstrList, UnsignedVec); 2150 2151 // Check to make sure that we have a long enough region. 2152 ASSERT_EQ(InstrList.size(), static_cast<unsigned>(6)); 2153 // Check that the instructions were added correctly to both vectors. 2154 ASSERT_EQ(InstrList.size(), UnsignedVec.size()); 2155 2156 std::vector<IRInstructionData *>::iterator Start, End; 2157 2158 Start = InstrList.begin(); 2159 End = InstrList.begin(); 2160 2161 std::advance(End, 1); 2162 IRSimilarityCandidate Cand1(0, 2, *Start, *End); 2163 2164 Start = InstrList.begin(); 2165 End = InstrList.begin(); 2166 2167 std::advance(Start, 3); 2168 std::advance(End, 4); 2169 IRSimilarityCandidate Cand2(3, 2, *Start, *End); 2170 DenseMap<unsigned, DenseSet<unsigned>> Mapping1; 2171 DenseMap<unsigned, DenseSet<unsigned>> Mapping2; 2172 ASSERT_TRUE(IRSimilarityCandidate::compareStructure(Cand1, Cand2, Mapping1, 2173 Mapping2)); 2174 IRSimilarityCandidate::createCanonicalMappingFor(Cand1); 2175 Cand2.createCanonicalRelationFrom(Cand1, Mapping1, Mapping2); 2176 2177 for (std::pair<unsigned, DenseSet<unsigned>> &P : Mapping2) { 2178 unsigned Source = P.first; 2179 2180 ASSERT_TRUE(Cand2.getCanonicalNum(Source).hasValue()); 2181 unsigned Canon = *Cand2.getCanonicalNum(Source); 2182 ASSERT_TRUE(Cand1.fromCanonicalNum(Canon).hasValue()); 2183 unsigned Dest = *Cand1.fromCanonicalNum(Canon); 2184 2185 DenseSet<unsigned>::iterator It = P.second.find(Dest); 2186 ASSERT_NE(It, P.second.end()); 2187 } 2188 } 2189 2190 // Checks that the same structure is recognized between two candidates. While 2191 // the input names are reversed, they still perform the same overall operation. 2192 TEST(IRSimilarityCandidate, DifferentNameSameStructure) { 2193 StringRef ModuleString = R"( 2194 define i32 @f(i32 %a, i32 %b) { 2195 bb0: 2196 %0 = add i32 %a, %b 2197 %1 = add i32 %b, %a 2198 ret i32 0 2199 bb1: 2200 %2 = add i32 %b, %a 2201 %3 = add i32 %a, %b 2202 ret i32 0 2203 })"; 2204 LLVMContext Context; 2205 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); 2206 2207 std::vector<IRInstructionData *> InstrList; 2208 std::vector<unsigned> UnsignedVec; 2209 2210 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator; 2211 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator; 2212 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator); 2213 getVectors(*M, Mapper, InstrList, UnsignedVec); 2214 2215 // Check to make sure that we have a long enough region. 2216 ASSERT_EQ(InstrList.size(), static_cast<unsigned>(6)); 2217 // Check that the instructions were added correctly to both vectors. 2218 ASSERT_TRUE(InstrList.size() == UnsignedVec.size()); 2219 2220 ASSERT_TRUE(longSimCandCompare(InstrList, true)); 2221 } 2222 2223 // Checks that the same structure is recognized between two candidates when 2224 // the branches target other blocks inside the same region, the relative 2225 // distance between the blocks must be the same. 2226 TEST(IRSimilarityCandidate, SameBranchStructureInternal) { 2227 StringRef ModuleString = R"( 2228 define i32 @f(i32 %a, i32 %b) { 2229 bb0: 2230 %0 = add i32 %a, %b 2231 %1 = add i32 %b, %a 2232 br label %bb1 2233 bb1: 2234 %2 = add i32 %b, %a 2235 %3 = add i32 %a, %b 2236 ret i32 0 2237 } 2238 2239 define i32 @f2(i32 %a, i32 %b) { 2240 bb0: 2241 %0 = add i32 %a, %b 2242 %1 = add i32 %b, %a 2243 br label %bb1 2244 bb1: 2245 %2 = add i32 %b, %a 2246 %3 = add i32 %a, %b 2247 ret i32 0 2248 })"; 2249 LLVMContext Context; 2250 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); 2251 2252 std::vector<IRInstructionData *> InstrList; 2253 std::vector<unsigned> UnsignedVec; 2254 2255 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator; 2256 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator; 2257 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator); 2258 Mapper.InstClassifier.EnableBranches = true; 2259 Mapper.initializeForBBs(*M); 2260 getVectors(*M, Mapper, InstrList, UnsignedVec); 2261 2262 // Check to make sure that we have a long enough region. 2263 ASSERT_EQ(InstrList.size(), static_cast<unsigned>(12)); 2264 // Check that the instructions were added correctly to both vectors. 2265 ASSERT_TRUE(InstrList.size() == UnsignedVec.size()); 2266 2267 ASSERT_TRUE(longSimCandCompare(InstrList, true, 5, 0, 6)); 2268 } 2269 2270 // Checks that the different structure is recognized between two candidates, 2271 // when the branches target other blocks inside the same region, the relative 2272 // distance between the blocks must be the same. 2273 TEST(IRSimilarityCandidate, DifferentBranchStructureInternal) { 2274 StringRef ModuleString = R"( 2275 define i32 @f(i32 %a, i32 %b) { 2276 bb0: 2277 %0 = add i32 %a, %b 2278 %1 = add i32 %b, %a 2279 br label %bb2 2280 bb1: 2281 %2 = add i32 %b, %a 2282 %3 = add i32 %a, %b 2283 br label %bb2 2284 bb2: 2285 %4 = add i32 %b, %a 2286 %5 = add i32 %a, %b 2287 ret i32 0 2288 } 2289 2290 define i32 @f2(i32 %a, i32 %b) { 2291 bb0: 2292 %0 = add i32 %a, %b 2293 %1 = add i32 %b, %a 2294 br label %bb1 2295 bb1: 2296 %2 = add i32 %b, %a 2297 %3 = add i32 %a, %b 2298 br label %bb2 2299 bb2: 2300 %4 = add i32 %b, %a 2301 %5 = add i32 %a, %b 2302 ret i32 0 2303 })"; 2304 LLVMContext Context; 2305 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); 2306 2307 std::vector<IRInstructionData *> InstrList; 2308 std::vector<unsigned> UnsignedVec; 2309 2310 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator; 2311 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator; 2312 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator); 2313 Mapper.InstClassifier.EnableBranches = true; 2314 Mapper.initializeForBBs(*M); 2315 getVectors(*M, Mapper, InstrList, UnsignedVec); 2316 2317 // Check to make sure that we have a long enough region. 2318 ASSERT_EQ(InstrList.size(), static_cast<unsigned>(18)); 2319 // Check that the instructions were added correctly to both vectors. 2320 ASSERT_TRUE(InstrList.size() == UnsignedVec.size()); 2321 2322 ASSERT_FALSE(longSimCandCompare(InstrList, true, 6, 0, 9)); 2323 } 2324 2325 // Checks that the same structure is recognized between two candidates, when 2326 // the branches target other blocks outside region, the relative distance 2327 // does not need to be the same. 2328 TEST(IRSimilarityCandidate, SameBranchStructureOutside) { 2329 StringRef ModuleString = R"( 2330 define i32 @f(i32 %a, i32 %b) { 2331 bb0: 2332 %0 = add i32 %a, %b 2333 %1 = add i32 %b, %a 2334 br label %bb1 2335 bb1: 2336 %2 = add i32 %b, %a 2337 %3 = add i32 %a, %b 2338 ret i32 0 2339 } 2340 2341 define i32 @f2(i32 %a, i32 %b) { 2342 bb0: 2343 %0 = add i32 %a, %b 2344 %1 = add i32 %b, %a 2345 br label %bb1 2346 bb1: 2347 %2 = add i32 %b, %a 2348 %3 = add i32 %a, %b 2349 ret i32 0 2350 })"; 2351 LLVMContext Context; 2352 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); 2353 2354 std::vector<IRInstructionData *> InstrList; 2355 std::vector<unsigned> UnsignedVec; 2356 2357 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator; 2358 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator; 2359 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator); 2360 Mapper.InstClassifier.EnableBranches = true; 2361 Mapper.initializeForBBs(*M); 2362 getVectors(*M, Mapper, InstrList, UnsignedVec); 2363 2364 // Check to make sure that we have a long enough region. 2365 ASSERT_EQ(InstrList.size(), static_cast<unsigned>(12)); 2366 // Check that the instructions were added correctly to both vectors. 2367 ASSERT_TRUE(InstrList.size() == UnsignedVec.size()); 2368 2369 ASSERT_TRUE(longSimCandCompare(InstrList, true, 3, 0, 6)); 2370 } 2371 2372 // Checks that the same structure is recognized between two candidates, when 2373 // the branches target other blocks outside region, the relative distance 2374 // does not need to be the same. 2375 TEST(IRSimilarityCandidate, DifferentBranchStructureOutside) { 2376 StringRef ModuleString = R"( 2377 define i32 @f(i32 %a, i32 %b) { 2378 bb0: 2379 %0 = add i32 %a, %b 2380 %1 = add i32 %b, %a 2381 br label %bb1 2382 bb1: 2383 %2 = add i32 %b, %a 2384 %3 = add i32 %a, %b 2385 ret i32 0 2386 } 2387 2388 define i32 @f2(i32 %a, i32 %b) { 2389 bb0: 2390 %0 = add i32 %a, %b 2391 %1 = add i32 %b, %a 2392 br label %bb2 2393 bb1: 2394 %2 = add i32 %b, %a 2395 %3 = add i32 %a, %b 2396 br label %bb2 2397 bb2: 2398 %4 = add i32 %b, %a 2399 %5 = add i32 %a, %b 2400 ret i32 0 2401 })"; 2402 LLVMContext Context; 2403 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); 2404 2405 std::vector<IRInstructionData *> InstrList; 2406 std::vector<unsigned> UnsignedVec; 2407 2408 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator; 2409 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator; 2410 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator); 2411 Mapper.InstClassifier.EnableBranches = true; 2412 Mapper.initializeForBBs(*M); 2413 getVectors(*M, Mapper, InstrList, UnsignedVec); 2414 2415 // Check to make sure that we have a long enough region. 2416 ASSERT_EQ(InstrList.size(), static_cast<unsigned>(15)); 2417 // Check that the instructions were added correctly to both vectors. 2418 ASSERT_TRUE(InstrList.size() == UnsignedVec.size()); 2419 2420 ASSERT_TRUE(longSimCandCompare(InstrList, true, 3, 0, 6)); 2421 } 2422 2423 // Checks that the same structure is recognized between two candidates, 2424 // when the phi predecessor are other blocks inside the same region, 2425 // the relative distance between the blocks must be the same. 2426 TEST(IRSimilarityCandidate, SamePHIStructureInternal) { 2427 StringRef ModuleString = R"( 2428 define i32 @f(i32 %a, i32 %b) { 2429 bb0: 2430 br label %bb2 2431 bb1: 2432 br label %bb2 2433 bb2: 2434 %0 = phi i32 [ %a, %bb0 ], [ %b, %bb1 ] 2435 %1 = add i32 %b, %a 2436 %2 = add i32 %a, %b 2437 ret i32 0 2438 } 2439 2440 define i32 @f2(i32 %a, i32 %b) { 2441 bb0: 2442 br label %bb2 2443 bb1: 2444 br label %bb2 2445 bb2: 2446 %0 = phi i32 [ %a, %bb0 ], [ %b, %bb1 ] 2447 %1 = add i32 %b, %a 2448 %2 = add i32 %a, %b 2449 ret i32 0 2450 })"; 2451 LLVMContext Context; 2452 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); 2453 2454 std::vector<IRInstructionData *> InstrList; 2455 std::vector<unsigned> UnsignedVec; 2456 2457 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator; 2458 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator; 2459 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator); 2460 Mapper.InstClassifier.EnableBranches = true; 2461 Mapper.initializeForBBs(*M); 2462 getVectors(*M, Mapper, InstrList, UnsignedVec); 2463 2464 // Check to make sure that we have a long enough region. 2465 ASSERT_EQ(InstrList.size(), static_cast<unsigned>(11)); 2466 // Check that the instructions were added correctly to both vectors. 2467 ASSERT_TRUE(InstrList.size() == UnsignedVec.size()); 2468 2469 ASSERT_TRUE(longSimCandCompare(InstrList, true, 4, 0, 6)); 2470 } 2471 2472 // Checks that the different structure is recognized between two candidates, 2473 // when the phi predecessor are other blocks inside the same region, 2474 // the relative distance between the blocks must be the same. 2475 TEST(IRSimilarityCandidate, DifferentPHIStructureInternal) { 2476 StringRef ModuleString = R"( 2477 define i32 @f(i32 %a, i32 %b) { 2478 bb0: 2479 br label %bb2 2480 bb1: 2481 br label %bb2 2482 bb3: 2483 br label %bb2 2484 bb2: 2485 %0 = phi i32 [ %a, %bb0 ], [ %b, %bb1 ] 2486 %1 = add i32 %b, %a 2487 %2 = add i32 %a, %b 2488 ret i32 0 2489 } 2490 2491 define i32 @f2(i32 %a, i32 %b) { 2492 bb0: 2493 br label %bb2 2494 bb1: 2495 br label %bb2 2496 bb3: 2497 br label %bb2 2498 bb2: 2499 %0 = phi i32 [ %a, %bb0 ], [ %b, %bb3 ] 2500 %1 = add i32 %b, %a 2501 %2 = add i32 %a, %b 2502 ret i32 0 2503 })"; 2504 LLVMContext Context; 2505 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); 2506 2507 std::vector<IRInstructionData *> InstrList; 2508 std::vector<unsigned> UnsignedVec; 2509 2510 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator; 2511 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator; 2512 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator); 2513 Mapper.InstClassifier.EnableBranches = true; 2514 Mapper.initializeForBBs(*M); 2515 getVectors(*M, Mapper, InstrList, UnsignedVec); 2516 2517 // Check to make sure that we have a long enough region. 2518 ASSERT_EQ(InstrList.size(), static_cast<unsigned>(13)); 2519 // Check that the instructions were added correctly to both vectors. 2520 ASSERT_TRUE(InstrList.size() == UnsignedVec.size()); 2521 2522 ASSERT_FALSE(longSimCandCompare(InstrList, true, 5, 0, 7)); 2523 } 2524 2525 // Checks that two sets of identical instructions are found to be the same. 2526 // Both sequences of adds have the same operand ordering, and the same 2527 // instructions, making them strcturally equivalent. 2528 TEST(IRSimilarityIdentifier, IdentitySimilarity) { 2529 StringRef ModuleString = R"( 2530 define i32 @f(i32 %a, i32 %b) { 2531 bb0: 2532 %0 = add i32 %a, %b 2533 %1 = sub i32 %b, %a 2534 br label %bb1 2535 bb1: 2536 %2 = add i32 %a, %b 2537 %3 = sub i32 %b, %a 2538 ret i32 0 2539 })"; 2540 LLVMContext Context; 2541 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); 2542 2543 std::vector<std::vector<IRSimilarityCandidate>> SimilarityCandidates; 2544 getSimilarities(*M, SimilarityCandidates); 2545 2546 ASSERT_TRUE(SimilarityCandidates.size() == 1); 2547 for (std::vector<IRSimilarityCandidate> &Cands : SimilarityCandidates) { 2548 ASSERT_TRUE(Cands.size() == 2); 2549 unsigned InstIdx = 0; 2550 for (IRSimilarityCandidate &Cand : Cands) { 2551 ASSERT_TRUE(Cand.getStartIdx() == InstIdx); 2552 InstIdx += 3; 2553 } 2554 } 2555 } 2556 2557 // Checks that incorrect sequences are not found as similar. In this case, 2558 // we have different sequences of instructions. 2559 TEST(IRSimilarityIdentifier, InstructionDifference) { 2560 StringRef ModuleString = R"( 2561 define i32 @f(i32 %a, i32 %b, i32 %c, i32 %d) { 2562 bb0: 2563 %0 = sub i32 %a, %b 2564 %1 = add i32 %b, %a 2565 br label %bb1 2566 bb1: 2567 %2 = add i32 %c, %d 2568 %3 = sub i32 %d, %c 2569 ret i32 0 2570 })"; 2571 LLVMContext Context; 2572 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); 2573 2574 std::vector<std::vector<IRSimilarityCandidate>> SimilarityCandidates; 2575 getSimilarities(*M, SimilarityCandidates); 2576 2577 ASSERT_TRUE(SimilarityCandidates.empty()); 2578 } 2579 2580 // This test checks to see whether we can detect similarity for commutative 2581 // instructions where the operands have been reversed. 2582 TEST(IRSimilarityIdentifier, CommutativeSimilarity) { 2583 StringRef ModuleString = R"( 2584 define i32 @f(i32 %a, i32 %b) { 2585 bb0: 2586 %0 = add i32 %a, %b 2587 %1 = add i32 %b, %a 2588 br label %bb1 2589 bb1: 2590 %2 = add i32 %a, %b 2591 %3 = add i32 %a, %b 2592 ret i32 0 2593 })"; 2594 LLVMContext Context; 2595 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); 2596 2597 std::vector<std::vector<IRSimilarityCandidate>> SimilarityCandidates; 2598 getSimilarities(*M, SimilarityCandidates); 2599 2600 ASSERT_TRUE(SimilarityCandidates.size() == 1); 2601 for (std::vector<IRSimilarityCandidate> &Cands : SimilarityCandidates) { 2602 ASSERT_TRUE(Cands.size() == 2); 2603 unsigned InstIdx = 0; 2604 for (IRSimilarityCandidate &Cand : Cands) { 2605 ASSERT_TRUE(Cand.getStartIdx() == InstIdx); 2606 InstIdx += 3; 2607 } 2608 } 2609 } 2610 2611 // This test checks to see whether we can detect different structure in 2612 // commutative instructions. In this case, the second operand in the second 2613 // add is different. 2614 TEST(IRSimilarityIdentifier, NoCommutativeSimilarity) { 2615 StringRef ModuleString = R"( 2616 define i32 @f(i32 %a, i32 %b) { 2617 bb0: 2618 %0 = add i32 %a, %b 2619 %1 = add i32 %1, %b 2620 br label %bb1 2621 bb1: 2622 %2 = add i32 %a, %b 2623 %3 = add i32 %2, %a 2624 ret i32 0 2625 })"; 2626 LLVMContext Context; 2627 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); 2628 2629 std::vector<std::vector<IRSimilarityCandidate>> SimilarityCandidates; 2630 getSimilarities(*M, SimilarityCandidates); 2631 2632 ASSERT_TRUE(SimilarityCandidates.size() == 0); 2633 } 2634 2635 // Check that we are not finding similarity in non commutative 2636 // instructions. That is, while the instruction and operands used are the same 2637 // in the two subtraction sequences, they are in a different order, and cannot 2638 // be counted as the same since a subtraction is not commutative. 2639 TEST(IRSimilarityIdentifier, NonCommutativeDifference) { 2640 StringRef ModuleString = R"( 2641 define i32 @f(i32 %a, i32 %b) { 2642 bb0: 2643 %0 = sub i32 %a, %b 2644 %1 = sub i32 %b, %a 2645 br label %bb1 2646 bb1: 2647 %2 = sub i32 %a, %b 2648 %3 = sub i32 %a, %b 2649 ret i32 0 2650 })"; 2651 LLVMContext Context; 2652 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); 2653 2654 std::vector<std::vector<IRSimilarityCandidate>> SimilarityCandidates; 2655 getSimilarities(*M, SimilarityCandidates); 2656 2657 ASSERT_TRUE(SimilarityCandidates.empty()); 2658 } 2659 2660 // Check that we find similarity despite changing the register names. 2661 TEST(IRSimilarityIdentifier, MappingSimilarity) { 2662 StringRef ModuleString = R"( 2663 define i32 @f(i32 %a, i32 %b, i32 %c, i32 %d) { 2664 bb0: 2665 %0 = add i32 %a, %b 2666 %1 = sub i32 %b, %a 2667 br label %bb1 2668 bb1: 2669 %2 = add i32 %c, %d 2670 %3 = sub i32 %d, %c 2671 ret i32 0 2672 })"; 2673 LLVMContext Context; 2674 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); 2675 2676 std::vector<std::vector<IRSimilarityCandidate>> SimilarityCandidates; 2677 getSimilarities(*M, SimilarityCandidates); 2678 2679 ASSERT_TRUE(SimilarityCandidates.size() == 1); 2680 for (std::vector<IRSimilarityCandidate> &Cands : SimilarityCandidates) { 2681 ASSERT_TRUE(Cands.size() == 2); 2682 unsigned InstIdx = 0; 2683 for (IRSimilarityCandidate &Cand : Cands) { 2684 ASSERT_TRUE(Cand.getStartIdx() == InstIdx); 2685 InstIdx += 3; 2686 } 2687 } 2688 } 2689 2690 // Check that we find instances of swapped predicate isomorphism. That is, 2691 // for predicates that can be flipped, e.g. greater than to less than, 2692 // we can identify that instances of these different literal predicates, but are 2693 // the same within a single swap can be found. 2694 TEST(IRSimilarityIdentifier, PredicateIsomorphism) { 2695 StringRef ModuleString = R"( 2696 define i32 @f(i32 %a, i32 %b) { 2697 bb0: 2698 %0 = add i32 %a, %b 2699 %1 = icmp sgt i32 %b, %a 2700 br label %bb1 2701 bb1: 2702 %2 = add i32 %a, %b 2703 %3 = icmp slt i32 %a, %b 2704 ret i32 0 2705 })"; 2706 LLVMContext Context; 2707 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); 2708 2709 std::vector<std::vector<IRSimilarityCandidate>> SimilarityCandidates; 2710 getSimilarities(*M, SimilarityCandidates); 2711 2712 ASSERT_TRUE(SimilarityCandidates.size() == 1); 2713 for (std::vector<IRSimilarityCandidate> &Cands : SimilarityCandidates) { 2714 ASSERT_TRUE(Cands.size() == 2); 2715 unsigned InstIdx = 0; 2716 for (IRSimilarityCandidate &Cand : Cands) { 2717 ASSERT_TRUE(Cand.getStartIdx() == InstIdx); 2718 InstIdx += 3; 2719 } 2720 } 2721 } 2722 2723 // Checks that constants are detected as the same operand in each use in the 2724 // sequences of instructions. Also checks that we can find structural 2725 // equivalence using constants. In this case the 1 has the same use pattern as 2726 // %a. 2727 TEST(IRSimilarityIdentifier, ConstantMappingSimilarity) { 2728 StringRef ModuleString = R"( 2729 define i32 @f(i32 %a, i32 %b) { 2730 bb0: 2731 %0 = add i32 1, %b 2732 %1 = icmp sgt i32 %b, 1 2733 br label %bb1 2734 bb1: 2735 %2 = add i32 %a, %b 2736 %3 = icmp sgt i32 %b, %a 2737 ret i32 0 2738 })"; 2739 LLVMContext Context; 2740 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); 2741 2742 std::vector<std::vector<IRSimilarityCandidate>> SimilarityCandidates; 2743 getSimilarities(*M, SimilarityCandidates); 2744 2745 ASSERT_TRUE(SimilarityCandidates.size() == 1); 2746 for (std::vector<IRSimilarityCandidate> &Cands : SimilarityCandidates) { 2747 ASSERT_TRUE(Cands.size() == 2); 2748 unsigned InstIdx = 0; 2749 for (IRSimilarityCandidate &Cand : Cands) { 2750 ASSERT_TRUE(Cand.getStartIdx() == InstIdx); 2751 InstIdx += 3; 2752 } 2753 } 2754 } 2755 2756 // Check that constants are uniquely identified. i.e. two different constants 2757 // are not considered the same. This means that this should not find any 2758 // structural similarity. 2759 TEST(IRSimilarityIdentifier, ConstantMappingDifference) { 2760 StringRef ModuleString = R"( 2761 define i32 @f(i32 %a, i32 %b) { 2762 bb0: 2763 %0 = add i32 1, %b 2764 %1 = icmp sgt i32 %b, 2 2765 br label %bb1 2766 bb1: 2767 %2 = add i32 %a, %b 2768 %3 = icmp slt i32 %a, %b 2769 ret i32 0 2770 })"; 2771 LLVMContext Context; 2772 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); 2773 2774 std::vector<std::vector<IRSimilarityCandidate>> SimilarityCandidates; 2775 getSimilarities(*M, SimilarityCandidates); 2776 2777 ASSERT_TRUE(SimilarityCandidates.empty()); 2778 } 2779