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 // In most cases, the illegal instructions we are collecting don't require any 761 // sort of setup. In these cases, we can just only have illegal instructions, 762 // and the mapper will create 0 length vectors, and we can check that. 763 764 // In cases where we have legal instructions needed to set up the illegal 765 // instruction, to check illegal instructions are assigned unsigned integers 766 // from the maximum value decreasing to 0, it will be greater than a legal 767 // instruction that comes after. So to check that we have an illegal 768 // instruction, we place a legal instruction after an illegal instruction, and 769 // check that the illegal unsigned integer is greater than the unsigned integer 770 // of the legal instruction. 771 772 // Checks that a PHINode is mapped to be illegal since there is extra checking 773 // needed to ensure that a branch in one region is bin an isomorphic 774 // location in a different region. 775 TEST(IRInstructionMapper, PhiIllegal) { 776 StringRef ModuleString = R"( 777 define i32 @f(i32 %a, i32 %b) { 778 bb0: 779 %0 = phi i1 [ 0, %bb0 ], [ %0, %bb1 ] 780 ret i32 0 781 bb1: 782 ret i32 1 783 })"; 784 LLVMContext Context; 785 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); 786 787 std::vector<IRInstructionData *> InstrList; 788 std::vector<unsigned> UnsignedVec; 789 790 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator; 791 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator; 792 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator); 793 getVectors(*M, Mapper, InstrList, UnsignedVec); 794 795 ASSERT_EQ(InstrList.size(), UnsignedVec.size()); 796 ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(0)); 797 } 798 799 // Checks that an alloca instruction is mapped to be illegal. 800 TEST(IRInstructionMapper, AllocaIllegal) { 801 StringRef ModuleString = R"( 802 define i32 @f(i32 %a, i32 %b) { 803 bb0: 804 %0 = alloca i32 805 ret i32 0 806 })"; 807 LLVMContext Context; 808 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); 809 810 std::vector<IRInstructionData *> InstrList; 811 std::vector<unsigned> UnsignedVec; 812 813 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator; 814 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator; 815 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator); 816 getVectors(*M, Mapper, InstrList, UnsignedVec); 817 818 ASSERT_EQ(InstrList.size(), UnsignedVec.size()); 819 ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(0)); 820 } 821 822 // Checks that an getelementptr instruction is mapped to be legal. And that 823 // the operands in getelementpointer instructions are the exact same after the 824 // first element operand, which only requires the same type. 825 TEST(IRInstructionMapper, GetElementPtrSameEndOperands) { 826 StringRef ModuleString = R"( 827 %struct.RT = type { i8, [10 x [20 x i32]], i8 } 828 %struct.ST = type { i32, double, %struct.RT } 829 define i32 @f(%struct.ST* %s, i64 %a, i64 %b) { 830 bb0: 831 %0 = getelementptr inbounds %struct.ST, %struct.ST* %s, i64 %a, i32 0 832 %1 = getelementptr inbounds %struct.ST, %struct.ST* %s, i64 %b, i32 0 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>(3)); 848 ASSERT_EQ(UnsignedVec[0], UnsignedVec[1]); 849 } 850 851 // Check that when the operands in getelementpointer instructions are not the 852 // exact same after the first element operand, the instructions are mapped to 853 // different values. 854 TEST(IRInstructionMapper, GetElementPtrDifferentEndOperands) { 855 StringRef ModuleString = R"( 856 %struct.RT = type { i8, [10 x [20 x i32]], i8 } 857 %struct.ST = type { i32, double, %struct.RT } 858 define i32 @f(%struct.ST* %s, i64 %a, i64 %b) { 859 bb0: 860 %0 = getelementptr inbounds %struct.ST, %struct.ST* %s, i64 %a, i32 0 861 %1 = getelementptr inbounds %struct.ST, %struct.ST* %s, i64 %b, i32 2 862 ret i32 0 863 })"; 864 LLVMContext Context; 865 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); 866 867 std::vector<IRInstructionData *> InstrList; 868 std::vector<unsigned> UnsignedVec; 869 870 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator; 871 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator; 872 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator); 873 getVectors(*M, Mapper, InstrList, UnsignedVec); 874 875 ASSERT_EQ(InstrList.size(), UnsignedVec.size()); 876 ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(3)); 877 ASSERT_NE(UnsignedVec[0], UnsignedVec[1]); 878 } 879 880 // Check that when the operands in getelementpointer instructions are not the 881 // same initial base type, each instruction is mapped to a different value. 882 TEST(IRInstructionMapper, GetElementPtrDifferentBaseType) { 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, %struct.RT* %r, i64 %a, i64 %b) { 887 bb0: 888 %0 = getelementptr inbounds %struct.ST, %struct.ST* %s, i64 %a 889 %1 = getelementptr inbounds %struct.RT, %struct.RT* %r, i64 %b 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 do not have 909 // the same inbounds modifier, they are not counted as the same. 910 TEST(IRInstructionMapper, GetElementPtrDifferentInBounds) { 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, i32 0 917 %1 = getelementptr %struct.ST, %struct.ST* %s, i64 %b, i32 0 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 // Checks that indirect call instructions are mapped to be illegal since we 937 // cannot guarantee the same function in two different cases. 938 TEST(IRInstructionMapper, CallsIllegalIndirect) { 939 StringRef ModuleString = R"( 940 define i32 @f(void()* %func) { 941 bb0: 942 call void %func() 943 ret i32 0 944 })"; 945 LLVMContext Context; 946 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); 947 948 std::vector<IRInstructionData *> InstrList; 949 std::vector<unsigned> UnsignedVec; 950 951 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator; 952 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator; 953 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator); 954 getVectors(*M, Mapper, InstrList, UnsignedVec); 955 956 ASSERT_EQ(InstrList.size(), UnsignedVec.size()); 957 ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(0)); 958 } 959 960 // Checks that a call instruction is mapped to be legal. Here we check that 961 // a call with the same name, and same types are mapped to the same 962 // value. 963 TEST(IRInstructionMapper, CallsSameTypeSameName) { 964 StringRef ModuleString = R"( 965 declare i32 @f1(i32, i32) 966 define i32 @f(i32 %a, i32 %b) { 967 bb0: 968 %0 = call i32 @f1(i32 %a, i32 %b) 969 %1 = call i32 @f1(i32 %a, i32 %b) 970 ret i32 0 971 })"; 972 LLVMContext Context; 973 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); 974 975 std::vector<IRInstructionData *> InstrList; 976 std::vector<unsigned> UnsignedVec; 977 978 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator; 979 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator; 980 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator); 981 getVectors(*M, Mapper, InstrList, UnsignedVec); 982 983 ASSERT_EQ(InstrList.size(), UnsignedVec.size()); 984 ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(3)); 985 ASSERT_EQ(UnsignedVec[0], UnsignedVec[1]); 986 } 987 988 // Here we check that a calls with different names, but the same arguments types 989 // are mapped to different value. 990 TEST(IRInstructionMapper, CallsSameArgTypeDifferentName) { 991 StringRef ModuleString = R"( 992 declare i32 @f1(i32, i32) 993 declare i32 @f2(i32, i32) 994 define i32 @f(i32 %a, i32 %b) { 995 bb0: 996 %0 = call i32 @f1(i32 %a, i32 %b) 997 %1 = call i32 @f2(i32 %a, i32 %b) 998 ret i32 0 999 })"; 1000 LLVMContext Context; 1001 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); 1002 1003 std::vector<IRInstructionData *> InstrList; 1004 std::vector<unsigned> UnsignedVec; 1005 1006 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator; 1007 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator; 1008 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator); 1009 getVectors(*M, Mapper, InstrList, UnsignedVec); 1010 1011 ASSERT_EQ(InstrList.size(), UnsignedVec.size()); 1012 ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(3)); 1013 ASSERT_NE(UnsignedVec[0], UnsignedVec[1]); 1014 } 1015 1016 // Here we check that a calls with different names, and different arguments 1017 // types are mapped to different value. 1018 TEST(IRInstructionMapper, CallsDifferentArgTypeDifferentName) { 1019 StringRef ModuleString = R"( 1020 declare i32 @f1(i32, i32) 1021 declare i32 @f2(i32) 1022 define i32 @f(i32 %a, i32 %b) { 1023 bb0: 1024 %0 = call i32 @f1(i32 %a, i32 %b) 1025 %1 = call i32 @f2(i32 %a) 1026 ret i32 0 1027 })"; 1028 LLVMContext Context; 1029 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); 1030 1031 std::vector<IRInstructionData *> InstrList; 1032 std::vector<unsigned> UnsignedVec; 1033 1034 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator; 1035 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator; 1036 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator); 1037 getVectors(*M, Mapper, InstrList, UnsignedVec); 1038 1039 ASSERT_EQ(InstrList.size(), UnsignedVec.size()); 1040 ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(3)); 1041 ASSERT_NE(UnsignedVec[0], UnsignedVec[1]); 1042 } 1043 1044 // Here we check that calls with different names, and different return 1045 // types are mapped to different value. 1046 TEST(IRInstructionMapper, CallsDifferentReturnTypeDifferentName) { 1047 StringRef ModuleString = R"( 1048 declare i64 @f1(i32, i32) 1049 declare i32 @f2(i32, i32) 1050 define i32 @f(i32 %a, i32 %b) { 1051 bb0: 1052 %0 = call i64 @f1(i32 %a, i32 %b) 1053 %1 = call i32 @f2(i32 %a, i32 %b) 1054 ret i32 0 1055 })"; 1056 LLVMContext Context; 1057 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); 1058 1059 std::vector<IRInstructionData *> InstrList; 1060 std::vector<unsigned> UnsignedVec; 1061 1062 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator; 1063 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator; 1064 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator); 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 calls with the same name, types, and parameters map to the 1073 // same unsigned integer. 1074 TEST(IRInstructionMapper, CallsSameParameters) { 1075 StringRef ModuleString = R"( 1076 declare i32 @f1(i32, i32) 1077 define i32 @f(i32 %a, i32 %b) { 1078 bb0: 1079 %0 = tail call fastcc i32 @f1(i32 %a, i32 %b) 1080 %1 = tail call fastcc i32 @f1(i32 %a, i32 %b) 1081 ret i32 0 1082 })"; 1083 LLVMContext Context; 1084 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); 1085 1086 std::vector<IRInstructionData *> InstrList; 1087 std::vector<unsigned> UnsignedVec; 1088 1089 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator; 1090 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator; 1091 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator); 1092 getVectors(*M, Mapper, InstrList, UnsignedVec); 1093 1094 ASSERT_EQ(InstrList.size(), UnsignedVec.size()); 1095 ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(3)); 1096 ASSERT_EQ(UnsignedVec[0], UnsignedVec[1]); 1097 } 1098 1099 // Here we check that calls with different tail call settings are mapped to 1100 // different values. 1101 TEST(IRInstructionMapper, CallsDifferentTails) { 1102 StringRef ModuleString = R"( 1103 declare i32 @f1(i32, i32) 1104 define i32 @f(i32 %a, i32 %b) { 1105 bb0: 1106 %0 = tail call i32 @f1(i32 %a, i32 %b) 1107 %1 = call i32 @f1(i32 %a, i32 %b) 1108 ret i32 0 1109 })"; 1110 LLVMContext Context; 1111 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); 1112 1113 std::vector<IRInstructionData *> InstrList; 1114 std::vector<unsigned> UnsignedVec; 1115 1116 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator; 1117 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator; 1118 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator); 1119 getVectors(*M, Mapper, InstrList, UnsignedVec); 1120 1121 ASSERT_EQ(InstrList.size(), UnsignedVec.size()); 1122 ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(3)); 1123 ASSERT_NE(UnsignedVec[0], UnsignedVec[1]); 1124 } 1125 1126 // Here we check that calls with different calling convention settings are 1127 // mapped to different values. 1128 TEST(IRInstructionMapper, CallsDifferentCallingConventions) { 1129 StringRef ModuleString = R"( 1130 declare i32 @f1(i32, i32) 1131 define i32 @f(i32 %a, i32 %b) { 1132 bb0: 1133 %0 = call fastcc i32 @f1(i32 %a, i32 %b) 1134 %1 = call i32 @f1(i32 %a, i32 %b) 1135 ret i32 0 1136 })"; 1137 LLVMContext Context; 1138 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); 1139 1140 std::vector<IRInstructionData *> InstrList; 1141 std::vector<unsigned> UnsignedVec; 1142 1143 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator; 1144 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator; 1145 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator); 1146 getVectors(*M, Mapper, InstrList, UnsignedVec); 1147 1148 ASSERT_EQ(InstrList.size(), UnsignedVec.size()); 1149 ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(3)); 1150 ASSERT_NE(UnsignedVec[0], UnsignedVec[1]); 1151 } 1152 1153 // Checks that an invoke instruction is mapped to be illegal. Invoke 1154 // instructions are considered to be illegal because of the change in the 1155 // control flow that is currently not recognized. 1156 TEST(IRInstructionMapper, InvokeIllegal) { 1157 StringRef ModuleString = R"( 1158 define i32 @f(i8 *%gep1, i32 %b) { 1159 then: 1160 invoke i32 undef(i8* undef) 1161 to label %invoke unwind label %lpad 1162 1163 invoke: 1164 unreachable 1165 1166 lpad: 1167 landingpad { i8*, i32 } 1168 catch i8* null 1169 unreachable 1170 })"; 1171 LLVMContext Context; 1172 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); 1173 1174 std::vector<IRInstructionData *> InstrList; 1175 std::vector<unsigned> UnsignedVec; 1176 1177 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator; 1178 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator; 1179 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator); 1180 getVectors(*M, Mapper, InstrList, UnsignedVec); 1181 1182 ASSERT_EQ(InstrList.size(), UnsignedVec.size()); 1183 ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(0)); 1184 } 1185 1186 // Checks that an callbr instructions are considered to be illegal. Callbr 1187 // instructions are considered to be illegal because of the change in the 1188 // control flow that is currently not recognized. 1189 TEST(IRInstructionMapper, CallBrInstIllegal) { 1190 StringRef ModuleString = R"( 1191 define void @test() { 1192 fail: 1193 ret void 1194 } 1195 1196 define i32 @f(i32 %a, i32 %b) { 1197 bb0: 1198 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] 1199 fail: 1200 ret i32 0 1201 normal: 1202 ret i32 0 1203 })"; 1204 LLVMContext Context; 1205 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); 1206 1207 std::vector<IRInstructionData *> InstrList; 1208 std::vector<unsigned> UnsignedVec; 1209 1210 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator; 1211 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator; 1212 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator); 1213 getVectors(*M, Mapper, InstrList, UnsignedVec); 1214 1215 ASSERT_EQ(InstrList.size(), UnsignedVec.size()); 1216 ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(0)); 1217 } 1218 1219 // Checks that an debuginfo intrinsics are mapped to be invisible. Since they 1220 // do not semantically change the program, they can be recognized as similar. 1221 TEST(IRInstructionMapper, DebugInfoInvisible) { 1222 StringRef ModuleString = R"( 1223 define i32 @f(i32 %a, i32 %b) { 1224 then: 1225 %0 = add i32 %a, %b 1226 call void @llvm.dbg.value(metadata !0) 1227 %1 = add i32 %a, %b 1228 ret i32 0 1229 } 1230 1231 declare void @llvm.dbg.value(metadata) 1232 !0 = distinct !{!"test\00", i32 10})"; 1233 LLVMContext Context; 1234 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); 1235 1236 std::vector<IRInstructionData *> InstrList; 1237 std::vector<unsigned> UnsignedVec; 1238 1239 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator; 1240 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator; 1241 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator); 1242 getVectors(*M, Mapper, InstrList, UnsignedVec); 1243 1244 ASSERT_EQ(InstrList.size(), UnsignedVec.size()); 1245 ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(3)); 1246 } 1247 1248 // The following are all exception handling intrinsics. We do not currently 1249 // handle these instruction because they are very context dependent. 1250 1251 // Checks that an eh.typeid.for intrinsic is mapped to be illegal. 1252 TEST(IRInstructionMapper, ExceptionHandlingTypeIdIllegal) { 1253 StringRef ModuleString = R"( 1254 @_ZTIi = external constant i8* 1255 define i32 @f() { 1256 then: 1257 %0 = call i32 @llvm.eh.typeid.for(i8* bitcast (i8** @_ZTIi to i8*)) 1258 ret i32 0 1259 } 1260 1261 declare i32 @llvm.eh.typeid.for(i8*))"; 1262 LLVMContext Context; 1263 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); 1264 1265 std::vector<IRInstructionData *> InstrList; 1266 std::vector<unsigned> UnsignedVec; 1267 1268 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator; 1269 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator; 1270 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator); 1271 getVectors(*M, Mapper, InstrList, UnsignedVec); 1272 1273 ASSERT_EQ(InstrList.size(), UnsignedVec.size()); 1274 ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(0)); 1275 } 1276 1277 // Checks that an eh.exceptioncode intrinsic is mapped to be illegal. 1278 TEST(IRInstructionMapper, ExceptionHandlingExceptionCodeIllegal) { 1279 StringRef ModuleString = R"( 1280 define i32 @f(i32 %a, i32 %b) { 1281 entry: 1282 %0 = catchswitch within none [label %__except] unwind to caller 1283 1284 __except: 1285 %1 = catchpad within %0 [i8* null] 1286 catchret from %1 to label %__except 1287 1288 then: 1289 %2 = call i32 @llvm.eh.exceptioncode(token %1) 1290 ret i32 0 1291 } 1292 1293 declare i32 @llvm.eh.exceptioncode(token))"; 1294 LLVMContext Context; 1295 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); 1296 1297 std::vector<IRInstructionData *> InstrList; 1298 std::vector<unsigned> UnsignedVec; 1299 1300 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator; 1301 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator; 1302 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator); 1303 getVectors(*M, Mapper, InstrList, UnsignedVec); 1304 1305 ASSERT_EQ(InstrList.size(), UnsignedVec.size()); 1306 ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(0)); 1307 } 1308 1309 // Checks that an eh.unwind intrinsic is mapped to be illegal. 1310 TEST(IRInstructionMapper, ExceptionHandlingUnwindIllegal) { 1311 StringRef ModuleString = R"( 1312 define i32 @f(i32 %a, i32 %b) { 1313 entry: 1314 call void @llvm.eh.unwind.init() 1315 ret i32 0 1316 } 1317 1318 declare void @llvm.eh.unwind.init())"; 1319 LLVMContext Context; 1320 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); 1321 1322 std::vector<IRInstructionData *> InstrList; 1323 std::vector<unsigned> UnsignedVec; 1324 1325 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator; 1326 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator; 1327 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator); 1328 getVectors(*M, Mapper, InstrList, UnsignedVec); 1329 1330 ASSERT_EQ(InstrList.size(), UnsignedVec.size()); 1331 ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(0)); 1332 } 1333 1334 // Checks that an eh.exceptionpointer intrinsic is mapped to be illegal. 1335 TEST(IRInstructionMapper, ExceptionHandlingExceptionPointerIllegal) { 1336 StringRef ModuleString = R"( 1337 define i32 @f(i32 %a, i32 %b) { 1338 entry: 1339 %0 = call i8* @llvm.eh.exceptionpointer.p0i8(i32 0) 1340 ret i32 0 1341 } 1342 1343 declare i8* @llvm.eh.exceptionpointer.p0i8(i32))"; 1344 LLVMContext Context; 1345 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); 1346 1347 std::vector<IRInstructionData *> InstrList; 1348 std::vector<unsigned> UnsignedVec; 1349 1350 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator; 1351 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator; 1352 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator); 1353 getVectors(*M, Mapper, InstrList, UnsignedVec); 1354 1355 ASSERT_EQ(InstrList.size(), UnsignedVec.size()); 1356 ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(0)); 1357 } 1358 1359 // Checks that a catchpad instruction is mapped to an illegal value. 1360 TEST(IRInstructionMapper, CatchpadIllegal) { 1361 StringRef ModuleString = R"( 1362 declare void @llvm.donothing() nounwind readnone 1363 1364 define void @function() personality i8 3 { 1365 entry: 1366 invoke void @llvm.donothing() to label %normal unwind label %exception 1367 exception: 1368 %cs1 = catchswitch within none [label %catchpad1] unwind to caller 1369 catchpad1: 1370 catchpad within %cs1 [] 1371 br label %normal 1372 normal: 1373 ret void 1374 })"; 1375 LLVMContext Context; 1376 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); 1377 1378 std::vector<IRInstructionData *> InstrList; 1379 std::vector<unsigned> UnsignedVec; 1380 1381 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator; 1382 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator; 1383 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator); 1384 getVectors(*M, Mapper, InstrList, UnsignedVec); 1385 1386 ASSERT_EQ(InstrList.size(), UnsignedVec.size()); 1387 ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(0)); 1388 } 1389 1390 // Checks that a cleanuppad instruction is mapped to an illegal value. 1391 TEST(IRInstructionMapper, CleanuppadIllegal) { 1392 StringRef ModuleString = R"( 1393 declare void @llvm.donothing() nounwind readnone 1394 1395 define void @function() personality i8 3 { 1396 entry: 1397 invoke void @llvm.donothing() to label %normal unwind label %exception 1398 exception: 1399 %cs1 = catchswitch within none [label %catchpad1] unwind to caller 1400 catchpad1: 1401 %clean = cleanuppad within none [] 1402 br label %normal 1403 normal: 1404 ret void 1405 })"; 1406 LLVMContext Context; 1407 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); 1408 1409 std::vector<IRInstructionData *> InstrList; 1410 std::vector<unsigned> UnsignedVec; 1411 1412 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator; 1413 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator; 1414 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator); 1415 getVectors(*M, Mapper, InstrList, UnsignedVec); 1416 1417 ASSERT_EQ(InstrList.size(), UnsignedVec.size()); 1418 ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(0)); 1419 } 1420 1421 // The following three instructions are memory transfer and setting based, which 1422 // are considered illegal since is extra checking needed to handle the address 1423 // space checking. 1424 1425 // Checks that a memset instruction is mapped to an illegal value. 1426 TEST(IRInstructionMapper, MemSetIllegal) { 1427 StringRef ModuleString = R"( 1428 declare void @llvm.memset.p0i8.i64(i8* nocapture writeonly, i8, i64, i32, i1) 1429 1430 define i64 @function(i64 %x, i64 %z, i64 %n) { 1431 entry: 1432 %pool = alloca [59 x i64], align 4 1433 %tmp = bitcast [59 x i64]* %pool to i8* 1434 call void @llvm.memset.p0i8.i64(i8* nonnull %tmp, i8 0, i64 236, i32 4, i1 false) 1435 %cmp3 = icmp eq i64 %n, 0 1436 %a = add i64 %x, %z 1437 %c = add i64 %x, %z 1438 ret i64 0 1439 })"; 1440 LLVMContext Context; 1441 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); 1442 1443 std::vector<IRInstructionData *> InstrList; 1444 std::vector<unsigned> UnsignedVec; 1445 1446 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator; 1447 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator; 1448 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator); 1449 getVectors(*M, Mapper, InstrList, UnsignedVec); 1450 1451 ASSERT_EQ(InstrList.size(), UnsignedVec.size()); 1452 ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(7)); 1453 ASSERT_TRUE(UnsignedVec[2] < UnsignedVec[0]); 1454 } 1455 1456 // Checks that a memcpy instruction is mapped to an illegal value. 1457 TEST(IRInstructionMapper, MemCpyIllegal) { 1458 StringRef ModuleString = R"( 1459 declare void @llvm.memcpy.p0i8.i64(i8* nocapture writeonly, i8, i64, i32, i1) 1460 1461 define i64 @function(i64 %x, i64 %z, i64 %n) { 1462 entry: 1463 %pool = alloca [59 x i64], align 4 1464 %tmp = bitcast [59 x i64]* %pool to i8* 1465 call void @llvm.memcpy.p0i8.i64(i8* nonnull %tmp, i8 0, i64 236, i32 4, i1 false) 1466 %cmp3 = icmp eq i64 %n, 0 1467 %a = add i64 %x, %z 1468 %c = add i64 %x, %z 1469 ret i64 0 1470 })"; 1471 LLVMContext Context; 1472 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); 1473 1474 std::vector<IRInstructionData *> InstrList; 1475 std::vector<unsigned> UnsignedVec; 1476 1477 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator; 1478 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator; 1479 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator); 1480 getVectors(*M, Mapper, InstrList, UnsignedVec); 1481 1482 ASSERT_EQ(InstrList.size(), UnsignedVec.size()); 1483 ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(7)); 1484 ASSERT_GT(UnsignedVec[2], UnsignedVec[3]); 1485 ASSERT_LT(UnsignedVec[2], UnsignedVec[0]); 1486 } 1487 1488 // Checks that a memmove instruction is mapped to an illegal value. 1489 TEST(IRInstructionMapper, MemMoveIllegal) { 1490 StringRef ModuleString = R"( 1491 declare void @llvm.memmove.p0i8.i64(i8* nocapture writeonly, i8, i64, i32, i1) 1492 1493 define i64 @function(i64 %x, i64 %z, i64 %n) { 1494 entry: 1495 %pool = alloca [59 x i64], align 4 1496 %tmp = bitcast [59 x i64]* %pool to i8* 1497 call void @llvm.memmove.p0i8.i64(i8* nonnull %tmp, i8 0, i64 236, i32 4, i1 false) 1498 %cmp3 = icmp eq i64 %n, 0 1499 %a = add i64 %x, %z 1500 %c = add i64 %x, %z 1501 ret i64 0 1502 })"; 1503 LLVMContext Context; 1504 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); 1505 1506 std::vector<IRInstructionData *> InstrList; 1507 std::vector<unsigned> UnsignedVec; 1508 1509 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator; 1510 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator; 1511 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator); 1512 getVectors(*M, Mapper, InstrList, UnsignedVec); 1513 1514 ASSERT_EQ(InstrList.size(), UnsignedVec.size()); 1515 ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(7)); 1516 ASSERT_LT(UnsignedVec[2], UnsignedVec[0]); 1517 } 1518 1519 // Checks that a variable argument instructions are mapped to an illegal value. 1520 // We exclude variable argument instructions since variable arguments 1521 // requires extra checking of the argument list. 1522 TEST(IRInstructionMapper, VarArgsIllegal) { 1523 StringRef ModuleString = R"( 1524 declare void @llvm.va_start(i8*) 1525 declare void @llvm.va_copy(i8*, i8*) 1526 declare void @llvm.va_end(i8*) 1527 1528 define i32 @func1(i32 %a, double %b, i8* %v, ...) nounwind { 1529 entry: 1530 %a.addr = alloca i32, align 4 1531 %b.addr = alloca double, align 8 1532 %ap = alloca i8*, align 4 1533 %c = alloca i32, align 4 1534 store i32 %a, i32* %a.addr, align 4 1535 store double %b, double* %b.addr, align 8 1536 %ap1 = bitcast i8** %ap to i8* 1537 call void @llvm.va_start(i8* %ap1) 1538 store double %b, double* %b.addr, align 8 1539 store double %b, double* %b.addr, align 8 1540 %0 = va_arg i8** %ap, i32 1541 store double %b, double* %b.addr, align 8 1542 store double %b, double* %b.addr, align 8 1543 call void @llvm.va_copy(i8* %v, i8* %ap1) 1544 store double %b, double* %b.addr, align 8 1545 store double %b, double* %b.addr, align 8 1546 call void @llvm.va_end(i8* %ap1) 1547 store i32 %0, i32* %c, align 4 1548 %tmp = load i32, i32* %c, align 4 1549 ret i32 %tmp 1550 })"; 1551 LLVMContext Context; 1552 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); 1553 1554 std::vector<IRInstructionData *> InstrList; 1555 std::vector<unsigned> UnsignedVec; 1556 1557 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator; 1558 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator; 1559 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator); 1560 getVectors(*M, Mapper, InstrList, UnsignedVec); 1561 1562 ASSERT_EQ(InstrList.size(), UnsignedVec.size()); 1563 ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(17)); 1564 ASSERT_TRUE(UnsignedVec[7] < UnsignedVec[0]); 1565 ASSERT_TRUE(UnsignedVec[13] < UnsignedVec[10]); 1566 ASSERT_TRUE(UnsignedVec[16] < UnsignedVec[13]); 1567 } 1568 1569 // Check the length of adding two illegal instructions one after th other. We 1570 // should find that only one element is added for each illegal range. 1571 TEST(IRInstructionMapper, RepeatedIllegalLength) { 1572 StringRef ModuleString = R"( 1573 define i32 @f(i32 %a, i32 %b) { 1574 bb0: 1575 %0 = add i32 %a, %b 1576 %1 = mul i32 %a, %b 1577 %2 = alloca i32 1578 %3 = alloca i32 1579 %4 = add i32 %a, %b 1580 %5 = mul i32 %a, %b 1581 ret i32 0 1582 })"; 1583 LLVMContext Context; 1584 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); 1585 1586 std::vector<IRInstructionData *> InstrList; 1587 std::vector<unsigned> UnsignedVec; 1588 1589 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator; 1590 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator; 1591 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator); 1592 getVectors(*M, Mapper, InstrList, UnsignedVec); 1593 1594 // Check that the size of the unsigned vector and the instruction list are the 1595 // same as a safety check. 1596 ASSERT_TRUE(InstrList.size() == UnsignedVec.size()); 1597 1598 // Make sure that the unsigned vector is the expected size. 1599 ASSERT_TRUE(UnsignedVec.size() == 6); 1600 } 1601 1602 // A helper function that accepts an instruction list from a module made up of 1603 // two blocks of two legal instructions and terminator, and checks them for 1604 // instruction similarity. 1605 static bool longSimCandCompare(std::vector<IRInstructionData *> &InstrList, 1606 bool Structure = false, unsigned Length = 2, 1607 unsigned StartIdxOne = 0, 1608 unsigned StartIdxTwo = 3) { 1609 std::vector<IRInstructionData *>::iterator Start, End; 1610 1611 Start = InstrList.begin(); 1612 End = InstrList.begin(); 1613 1614 std::advance(End, StartIdxOne + Length - 1); 1615 IRSimilarityCandidate Cand1(StartIdxOne, Length, *Start, *End); 1616 1617 Start = InstrList.begin(); 1618 End = InstrList.begin(); 1619 1620 std::advance(Start, StartIdxTwo); 1621 std::advance(End, StartIdxTwo + Length - 1); 1622 IRSimilarityCandidate Cand2(StartIdxTwo, Length, *Start, *End); 1623 if (Structure) 1624 return IRSimilarityCandidate::compareStructure(Cand1, Cand2); 1625 return IRSimilarityCandidate::isSimilar(Cand1, Cand2); 1626 } 1627 1628 // Checks that two adds with commuted operands are considered to be the same 1629 // instructions. 1630 TEST(IRSimilarityCandidate, CheckIdenticalInstructions) { 1631 StringRef ModuleString = R"( 1632 define i32 @f(i32 %a, i32 %b) { 1633 bb0: 1634 %0 = add i32 %a, %b 1635 %1 = add i32 %b, %a 1636 ret i32 0 1637 })"; 1638 LLVMContext Context; 1639 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); 1640 1641 std::vector<IRInstructionData *> InstrList; 1642 std::vector<unsigned> UnsignedVec; 1643 1644 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator; 1645 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator; 1646 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator); 1647 getVectors(*M, Mapper, InstrList, UnsignedVec); 1648 1649 // Check to make sure that we have a long enough region. 1650 ASSERT_EQ(InstrList.size(), static_cast<unsigned>(3)); 1651 // Check that the instructions were added correctly to both vectors. 1652 ASSERT_TRUE(InstrList.size() == UnsignedVec.size()); 1653 1654 std::vector<IRInstructionData *>::iterator Start, End; 1655 Start = InstrList.begin(); 1656 End = InstrList.begin(); 1657 std::advance(End, 1); 1658 IRSimilarityCandidate Cand1(0, 2, *Start, *End); 1659 IRSimilarityCandidate Cand2(0, 2, *Start, *End); 1660 1661 ASSERT_TRUE(IRSimilarityCandidate::isSimilar(Cand1, Cand2)); 1662 } 1663 1664 // Checks that comparison instructions are found to be similar instructions 1665 // when the operands are flipped and the predicate is also swapped. 1666 TEST(IRSimilarityCandidate, PredicateIsomorphism) { 1667 StringRef ModuleString = R"( 1668 define i32 @f(i32 %a, i32 %b) { 1669 bb0: 1670 %0 = icmp sgt i32 %a, %b 1671 %1 = add i32 %b, %a 1672 br label %bb1 1673 bb1: 1674 %2 = icmp slt i32 %a, %b 1675 %3 = add i32 %a, %b 1676 ret i32 0 1677 })"; 1678 LLVMContext Context; 1679 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); 1680 1681 std::vector<IRInstructionData *> InstrList; 1682 std::vector<unsigned> UnsignedVec; 1683 1684 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator; 1685 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator; 1686 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator); 1687 getVectors(*M, Mapper, InstrList, UnsignedVec); 1688 1689 ASSERT_TRUE(InstrList.size() > 5); 1690 ASSERT_TRUE(InstrList.size() == UnsignedVec.size()); 1691 1692 std::vector<IRInstructionData *>::iterator Start, End; 1693 Start = InstrList.begin(); 1694 End = InstrList.begin(); 1695 1696 std::advance(End, 1); 1697 IRSimilarityCandidate Cand1(0, 2, *Start, *End); 1698 1699 Start = InstrList.begin(); 1700 End = InstrList.begin(); 1701 1702 std::advance(Start, 3); 1703 std::advance(End, 4); 1704 IRSimilarityCandidate Cand2(3, 2, *Start, *End); 1705 1706 ASSERT_TRUE(IRSimilarityCandidate::isSimilar(Cand1, Cand2)); 1707 } 1708 1709 // Checks that IRSimilarityCandidates wrapping these two regions of instructions 1710 // are able to differentiate between instructions that have different opcodes. 1711 TEST(IRSimilarityCandidate, CheckRegionsDifferentInstruction) { 1712 StringRef ModuleString = R"( 1713 define i32 @f(i32 %a, i32 %b) { 1714 bb0: 1715 %0 = add i32 %a, %b 1716 %1 = add i32 %b, %a 1717 ret i32 0 1718 bb1: 1719 %2 = sub i32 %a, %b 1720 %3 = add i32 %b, %a 1721 ret i32 0 1722 })"; 1723 LLVMContext Context; 1724 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); 1725 1726 std::vector<IRInstructionData *> InstrList; 1727 std::vector<unsigned> UnsignedVec; 1728 1729 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator; 1730 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator; 1731 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator); 1732 getVectors(*M, Mapper, InstrList, UnsignedVec); 1733 1734 // Check to make sure that we have a long enough region. 1735 ASSERT_EQ(InstrList.size(), static_cast<unsigned>(6)); 1736 // Check that the instructions were added correctly to both vectors. 1737 ASSERT_TRUE(InstrList.size() == UnsignedVec.size()); 1738 1739 ASSERT_FALSE(longSimCandCompare(InstrList)); 1740 } 1741 1742 // Checks that IRSimilarityCandidates wrapping these two regions of instructions 1743 // are able to differentiate between instructions that have different types. 1744 TEST(IRSimilarityCandidate, CheckRegionsDifferentTypes) { 1745 StringRef ModuleString = R"( 1746 define i32 @f(i32 %a, i32 %b, i64 %c, i64 %d) { 1747 bb0: 1748 %0 = add i32 %a, %b 1749 %1 = add i32 %b, %a 1750 ret i32 0 1751 bb1: 1752 %2 = add i64 %c, %d 1753 %3 = add i64 %d, %c 1754 ret i32 0 1755 })"; 1756 LLVMContext Context; 1757 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); 1758 1759 std::vector<IRInstructionData *> InstrList; 1760 std::vector<unsigned> UnsignedVec; 1761 1762 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator; 1763 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator; 1764 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator); 1765 getVectors(*M, Mapper, InstrList, UnsignedVec); 1766 1767 // Check to make sure that we have a long enough region. 1768 ASSERT_EQ(InstrList.size(), static_cast<unsigned>(6)); 1769 // Check that the instructions were added correctly to both vectors. 1770 ASSERT_TRUE(InstrList.size() == UnsignedVec.size()); 1771 1772 ASSERT_FALSE(longSimCandCompare(InstrList)); 1773 } 1774 1775 // Check that debug instructions do not impact similarity. They are marked as 1776 // invisible. 1777 TEST(IRSimilarityCandidate, IdenticalWithDebug) { 1778 StringRef ModuleString = R"( 1779 define i32 @f(i32 %a, i32 %b) { 1780 bb0: 1781 %0 = add i32 %a, %b 1782 call void @llvm.dbg.value(metadata !0) 1783 %1 = add i32 %b, %a 1784 ret i32 0 1785 bb1: 1786 %2 = add i32 %a, %b 1787 call void @llvm.dbg.value(metadata !1) 1788 %3 = add i32 %b, %a 1789 ret i32 0 1790 bb2: 1791 %4 = add i32 %a, %b 1792 %5 = add i32 %b, %a 1793 ret i32 0 1794 } 1795 1796 declare void @llvm.dbg.value(metadata) 1797 !0 = distinct !{!"test\00", i32 10} 1798 !1 = distinct !{!"test\00", i32 11})"; 1799 LLVMContext Context; 1800 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); 1801 1802 std::vector<IRInstructionData *> InstrList; 1803 std::vector<unsigned> UnsignedVec; 1804 1805 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator; 1806 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator; 1807 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator); 1808 getVectors(*M, Mapper, InstrList, UnsignedVec); 1809 1810 // Check to make sure that we have a long enough region. 1811 ASSERT_EQ(InstrList.size(), static_cast<unsigned>(9)); 1812 // Check that the instructions were added correctly to both vectors. 1813 ASSERT_TRUE(InstrList.size() == UnsignedVec.size()); 1814 1815 ASSERT_TRUE(longSimCandCompare(InstrList)); 1816 } 1817 1818 // Checks that IRSimilarityCandidates that include illegal instructions, are not 1819 // considered to be the same set of instructions. In these sets of instructions 1820 // the allocas are illegal. 1821 TEST(IRSimilarityCandidate, IllegalInCandidate) { 1822 StringRef ModuleString = R"( 1823 define i32 @f(i32 %a, i32 %b) { 1824 bb0: 1825 %0 = add i32 %a, %b 1826 %1 = add i32 %a, %b 1827 %2 = alloca i32 1828 ret i32 0 1829 bb1: 1830 %3 = add i32 %a, %b 1831 %4 = add i32 %a, %b 1832 %5 = alloca i32 1833 ret i32 0 1834 })"; 1835 LLVMContext Context; 1836 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); 1837 1838 std::vector<IRInstructionData *> InstrList; 1839 std::vector<unsigned> UnsignedVec; 1840 1841 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator; 1842 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator; 1843 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator); 1844 getVectors(*M, Mapper, InstrList, UnsignedVec); 1845 1846 // Check to make sure that we have a long enough region. 1847 ASSERT_EQ(InstrList.size(), static_cast<unsigned>(6)); 1848 // Check that the instructions were added correctly to both vectors. 1849 ASSERT_TRUE(InstrList.size() == UnsignedVec.size()); 1850 1851 std::vector<IRInstructionData *>::iterator Start, End; 1852 1853 Start = InstrList.begin(); 1854 End = InstrList.begin(); 1855 1856 std::advance(End, 2); 1857 IRSimilarityCandidate Cand1(0, 3, *Start, *End); 1858 1859 Start = InstrList.begin(); 1860 End = InstrList.begin(); 1861 1862 std::advance(Start, 3); 1863 std::advance(End, 5); 1864 IRSimilarityCandidate Cand2(3, 3, *Start, *End); 1865 ASSERT_FALSE(IRSimilarityCandidate::isSimilar(Cand1, Cand2)); 1866 } 1867 1868 // Checks that different structure, in this case, where we introduce a new 1869 // needed input in one region, is recognized as different. 1870 TEST(IRSimilarityCandidate, DifferentStructure) { 1871 StringRef ModuleString = R"( 1872 define i32 @f(i32 %a, i32 %b) { 1873 bb0: 1874 %0 = add i32 %a, %b 1875 %1 = add i32 %b, %a 1876 ret i32 0 1877 bb1: 1878 %2 = add i32 %a, %b 1879 %3 = add i32 %b, %0 1880 ret i32 0 1881 })"; 1882 LLVMContext Context; 1883 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); 1884 1885 std::vector<IRInstructionData *> InstrList; 1886 std::vector<unsigned> UnsignedVec; 1887 1888 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator; 1889 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator; 1890 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator); 1891 getVectors(*M, Mapper, InstrList, UnsignedVec); 1892 1893 // Check to make sure that we have a long enough region. 1894 ASSERT_EQ(InstrList.size(), static_cast<unsigned>(6)); 1895 // Check that the instructions were added correctly to both vectors. 1896 ASSERT_TRUE(InstrList.size() == UnsignedVec.size()); 1897 1898 ASSERT_FALSE(longSimCandCompare(InstrList, true)); 1899 } 1900 1901 // Checks that comparison instructions are found to have the same structure 1902 // when the operands are flipped and the predicate is also swapped. 1903 TEST(IRSimilarityCandidate, PredicateIsomorphismStructure) { 1904 StringRef ModuleString = R"( 1905 define i32 @f(i32 %a, i32 %b) { 1906 bb0: 1907 %0 = icmp sgt i32 %a, %b 1908 %1 = add i32 %a, %b 1909 br label %bb1 1910 bb1: 1911 %2 = icmp slt i32 %b, %a 1912 %3 = add i32 %a, %b 1913 ret i32 0 1914 })"; 1915 LLVMContext Context; 1916 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); 1917 1918 std::vector<IRInstructionData *> InstrList; 1919 std::vector<unsigned> UnsignedVec; 1920 1921 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator; 1922 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator; 1923 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator); 1924 getVectors(*M, Mapper, InstrList, UnsignedVec); 1925 1926 ASSERT_TRUE(InstrList.size() > 5); 1927 ASSERT_TRUE(InstrList.size() == UnsignedVec.size()); 1928 1929 ASSERT_TRUE(longSimCandCompare(InstrList, true)); 1930 } 1931 1932 // Checks that different predicates are counted as diferent. 1933 TEST(IRSimilarityCandidate, PredicateDifference) { 1934 StringRef ModuleString = R"( 1935 define i32 @f(i32 %a, i32 %b) { 1936 bb0: 1937 %0 = icmp sge i32 %a, %b 1938 %1 = add i32 %b, %a 1939 br label %bb1 1940 bb1: 1941 %2 = icmp slt i32 %b, %a 1942 %3 = add i32 %a, %b 1943 ret i32 0 1944 })"; 1945 LLVMContext Context; 1946 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); 1947 1948 std::vector<IRInstructionData *> InstrList; 1949 std::vector<unsigned> UnsignedVec; 1950 1951 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator; 1952 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator; 1953 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator); 1954 getVectors(*M, Mapper, InstrList, UnsignedVec); 1955 1956 ASSERT_TRUE(InstrList.size() > 5); 1957 ASSERT_TRUE(InstrList.size() == UnsignedVec.size()); 1958 1959 ASSERT_FALSE(longSimCandCompare(InstrList)); 1960 } 1961 1962 // Checks that the same structure is recognized between two candidates. The 1963 // items %a and %b are used in the same way in both sets of instructions. 1964 TEST(IRSimilarityCandidate, SameStructure) { 1965 StringRef ModuleString = R"( 1966 define i32 @f(i32 %a, i32 %b) { 1967 bb0: 1968 %0 = add i32 %a, %b 1969 %1 = sub i32 %b, %a 1970 ret i32 0 1971 bb1: 1972 %2 = add i32 %a, %b 1973 %3 = sub i32 %b, %a 1974 ret i32 0 1975 })"; 1976 LLVMContext Context; 1977 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); 1978 1979 std::vector<IRInstructionData *> InstrList; 1980 std::vector<unsigned> UnsignedVec; 1981 1982 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator; 1983 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator; 1984 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator); 1985 getVectors(*M, Mapper, InstrList, UnsignedVec); 1986 1987 // Check to make sure that we have a long enough region. 1988 ASSERT_EQ(InstrList.size(), static_cast<unsigned>(6)); 1989 // Check that the instructions were added correctly to both vectors. 1990 ASSERT_TRUE(InstrList.size() == UnsignedVec.size()); 1991 1992 ASSERT_TRUE(longSimCandCompare(InstrList, true)); 1993 } 1994 1995 // Checks that the canonical numbering between two candidates matches the found 1996 // mapping between two candidates. 1997 TEST(IRSimilarityCandidate, CanonicalNumbering) { 1998 StringRef ModuleString = R"( 1999 define i32 @f(i32 %a, i32 %b) { 2000 bb0: 2001 %0 = add i32 %a, %b 2002 %1 = sub i32 %b, %a 2003 ret i32 0 2004 bb1: 2005 %2 = add i32 %a, %b 2006 %3 = sub i32 %b, %a 2007 ret i32 0 2008 })"; 2009 LLVMContext Context; 2010 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); 2011 2012 std::vector<IRInstructionData *> InstrList; 2013 std::vector<unsigned> UnsignedVec; 2014 2015 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator; 2016 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator; 2017 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator); 2018 getVectors(*M, Mapper, InstrList, UnsignedVec); 2019 2020 // Check to make sure that we have a long enough region. 2021 ASSERT_EQ(InstrList.size(), static_cast<unsigned>(6)); 2022 // Check that the instructions were added correctly to both vectors. 2023 ASSERT_EQ(InstrList.size(), UnsignedVec.size()); 2024 2025 std::vector<IRInstructionData *>::iterator Start, End; 2026 2027 Start = InstrList.begin(); 2028 End = InstrList.begin(); 2029 2030 std::advance(End, 1); 2031 IRSimilarityCandidate Cand1(0, 2, *Start, *End); 2032 2033 Start = InstrList.begin(); 2034 End = InstrList.begin(); 2035 2036 std::advance(Start, 3); 2037 std::advance(End, 4); 2038 IRSimilarityCandidate Cand2(3, 2, *Start, *End); 2039 DenseMap<unsigned, DenseSet<unsigned>> Mapping1; 2040 DenseMap<unsigned, DenseSet<unsigned>> Mapping2; 2041 ASSERT_TRUE(IRSimilarityCandidate::compareStructure(Cand1, Cand2, Mapping1, 2042 Mapping2)); 2043 IRSimilarityCandidate::createCanonicalMappingFor(Cand1); 2044 Cand2.createCanonicalRelationFrom(Cand1, Mapping1, Mapping2); 2045 2046 for (std::pair<unsigned, DenseSet<unsigned>> &P : Mapping2) { 2047 unsigned Source = P.first; 2048 2049 ASSERT_TRUE(Cand2.getCanonicalNum(Source).hasValue()); 2050 unsigned Canon = *Cand2.getCanonicalNum(Source); 2051 ASSERT_TRUE(Cand1.fromCanonicalNum(Canon).hasValue()); 2052 unsigned Dest = *Cand1.fromCanonicalNum(Canon); 2053 2054 DenseSet<unsigned>::iterator It = P.second.find(Dest); 2055 ASSERT_NE(It, P.second.end()); 2056 } 2057 } 2058 2059 // Checks that the same structure is recognized between two candidates. While 2060 // the input names are reversed, they still perform the same overall operation. 2061 TEST(IRSimilarityCandidate, DifferentNameSameStructure) { 2062 StringRef ModuleString = R"( 2063 define i32 @f(i32 %a, i32 %b) { 2064 bb0: 2065 %0 = add i32 %a, %b 2066 %1 = add i32 %b, %a 2067 ret i32 0 2068 bb1: 2069 %2 = add i32 %b, %a 2070 %3 = add i32 %a, %b 2071 ret i32 0 2072 })"; 2073 LLVMContext Context; 2074 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); 2075 2076 std::vector<IRInstructionData *> InstrList; 2077 std::vector<unsigned> UnsignedVec; 2078 2079 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator; 2080 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator; 2081 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator); 2082 getVectors(*M, Mapper, InstrList, UnsignedVec); 2083 2084 // Check to make sure that we have a long enough region. 2085 ASSERT_EQ(InstrList.size(), static_cast<unsigned>(6)); 2086 // Check that the instructions were added correctly to both vectors. 2087 ASSERT_TRUE(InstrList.size() == UnsignedVec.size()); 2088 2089 ASSERT_TRUE(longSimCandCompare(InstrList, true)); 2090 } 2091 2092 // Checks that the same structure is recognized between two candidates when 2093 // the branches target other blocks inside the same region, the relative 2094 // distance between the blocks must be the same. 2095 TEST(IRSimilarityCandidate, SameBranchStructureInternal) { 2096 StringRef ModuleString = R"( 2097 define i32 @f(i32 %a, i32 %b) { 2098 bb0: 2099 %0 = add i32 %a, %b 2100 %1 = add i32 %b, %a 2101 br label %bb1 2102 bb1: 2103 %2 = add i32 %b, %a 2104 %3 = add i32 %a, %b 2105 ret i32 0 2106 } 2107 2108 define i32 @f2(i32 %a, i32 %b) { 2109 bb0: 2110 %0 = add i32 %a, %b 2111 %1 = add i32 %b, %a 2112 br label %bb1 2113 bb1: 2114 %2 = add i32 %b, %a 2115 %3 = add i32 %a, %b 2116 ret i32 0 2117 })"; 2118 LLVMContext Context; 2119 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); 2120 2121 std::vector<IRInstructionData *> InstrList; 2122 std::vector<unsigned> UnsignedVec; 2123 2124 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator; 2125 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator; 2126 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator); 2127 Mapper.InstClassifier.EnableBranches = true; 2128 Mapper.initializeForBBs(*M); 2129 getVectors(*M, Mapper, InstrList, UnsignedVec); 2130 2131 // Check to make sure that we have a long enough region. 2132 ASSERT_EQ(InstrList.size(), static_cast<unsigned>(12)); 2133 // Check that the instructions were added correctly to both vectors. 2134 ASSERT_TRUE(InstrList.size() == UnsignedVec.size()); 2135 2136 ASSERT_TRUE(longSimCandCompare(InstrList, true, 5, 0, 6)); 2137 } 2138 2139 // Checks that the different structure is recognized between two candidates, 2140 // when the branches target other blocks inside the same region, the relative 2141 // distance between the blocks must be the same. 2142 TEST(IRSimilarityCandidate, DifferentBranchStructureInternal) { 2143 StringRef ModuleString = R"( 2144 define i32 @f(i32 %a, i32 %b) { 2145 bb0: 2146 %0 = add i32 %a, %b 2147 %1 = add i32 %b, %a 2148 br label %bb2 2149 bb1: 2150 %2 = add i32 %b, %a 2151 %3 = add i32 %a, %b 2152 br label %bb2 2153 bb2: 2154 %4 = add i32 %b, %a 2155 %5 = add i32 %a, %b 2156 ret i32 0 2157 } 2158 2159 define i32 @f2(i32 %a, i32 %b) { 2160 bb0: 2161 %0 = add i32 %a, %b 2162 %1 = add i32 %b, %a 2163 br label %bb1 2164 bb1: 2165 %2 = add i32 %b, %a 2166 %3 = add i32 %a, %b 2167 br label %bb2 2168 bb2: 2169 %4 = add i32 %b, %a 2170 %5 = add i32 %a, %b 2171 ret i32 0 2172 })"; 2173 LLVMContext Context; 2174 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); 2175 2176 std::vector<IRInstructionData *> InstrList; 2177 std::vector<unsigned> UnsignedVec; 2178 2179 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator; 2180 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator; 2181 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator); 2182 Mapper.InstClassifier.EnableBranches = true; 2183 Mapper.initializeForBBs(*M); 2184 getVectors(*M, Mapper, InstrList, UnsignedVec); 2185 2186 // Check to make sure that we have a long enough region. 2187 ASSERT_EQ(InstrList.size(), static_cast<unsigned>(18)); 2188 // Check that the instructions were added correctly to both vectors. 2189 ASSERT_TRUE(InstrList.size() == UnsignedVec.size()); 2190 2191 ASSERT_FALSE(longSimCandCompare(InstrList, true, 6, 0, 9)); 2192 } 2193 2194 // Checks that the same structure is recognized between two candidates, when 2195 // the branches target other blocks outside region, the relative distance 2196 // does not need to be the same. 2197 TEST(IRSimilarityCandidate, SameBranchStructureOutside) { 2198 StringRef ModuleString = R"( 2199 define i32 @f(i32 %a, i32 %b) { 2200 bb0: 2201 %0 = add i32 %a, %b 2202 %1 = add i32 %b, %a 2203 br label %bb1 2204 bb1: 2205 %2 = add i32 %b, %a 2206 %3 = add i32 %a, %b 2207 ret i32 0 2208 } 2209 2210 define i32 @f2(i32 %a, i32 %b) { 2211 bb0: 2212 %0 = add i32 %a, %b 2213 %1 = add i32 %b, %a 2214 br label %bb1 2215 bb1: 2216 %2 = add i32 %b, %a 2217 %3 = add i32 %a, %b 2218 ret i32 0 2219 })"; 2220 LLVMContext Context; 2221 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); 2222 2223 std::vector<IRInstructionData *> InstrList; 2224 std::vector<unsigned> UnsignedVec; 2225 2226 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator; 2227 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator; 2228 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator); 2229 Mapper.InstClassifier.EnableBranches = true; 2230 Mapper.initializeForBBs(*M); 2231 getVectors(*M, Mapper, InstrList, UnsignedVec); 2232 2233 // Check to make sure that we have a long enough region. 2234 ASSERT_EQ(InstrList.size(), static_cast<unsigned>(12)); 2235 // Check that the instructions were added correctly to both vectors. 2236 ASSERT_TRUE(InstrList.size() == UnsignedVec.size()); 2237 2238 ASSERT_TRUE(longSimCandCompare(InstrList, true, 3, 0, 6)); 2239 } 2240 2241 // Checks that the same structure is recognized between two candidates, when 2242 // the branches target other blocks outside region, the relative distance 2243 // does not need to be the same. 2244 TEST(IRSimilarityCandidate, DifferentBranchStructureOutside) { 2245 StringRef ModuleString = R"( 2246 define i32 @f(i32 %a, i32 %b) { 2247 bb0: 2248 %0 = add i32 %a, %b 2249 %1 = add i32 %b, %a 2250 br label %bb1 2251 bb1: 2252 %2 = add i32 %b, %a 2253 %3 = add i32 %a, %b 2254 ret i32 0 2255 } 2256 2257 define i32 @f2(i32 %a, i32 %b) { 2258 bb0: 2259 %0 = add i32 %a, %b 2260 %1 = add i32 %b, %a 2261 br label %bb2 2262 bb1: 2263 %2 = add i32 %b, %a 2264 %3 = add i32 %a, %b 2265 br label %bb2 2266 bb2: 2267 %4 = add i32 %b, %a 2268 %5 = add i32 %a, %b 2269 ret i32 0 2270 })"; 2271 LLVMContext Context; 2272 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); 2273 2274 std::vector<IRInstructionData *> InstrList; 2275 std::vector<unsigned> UnsignedVec; 2276 2277 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator; 2278 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator; 2279 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator); 2280 Mapper.InstClassifier.EnableBranches = true; 2281 Mapper.initializeForBBs(*M); 2282 getVectors(*M, Mapper, InstrList, UnsignedVec); 2283 2284 // Check to make sure that we have a long enough region. 2285 ASSERT_EQ(InstrList.size(), static_cast<unsigned>(15)); 2286 // Check that the instructions were added correctly to both vectors. 2287 ASSERT_TRUE(InstrList.size() == UnsignedVec.size()); 2288 2289 ASSERT_TRUE(longSimCandCompare(InstrList, true, 3, 0, 6)); 2290 } 2291 2292 // Checks that two sets of identical instructions are found to be the same. 2293 // Both sequences of adds have the same operand ordering, and the same 2294 // instructions, making them strcturally equivalent. 2295 TEST(IRSimilarityIdentifier, IdentitySimilarity) { 2296 StringRef ModuleString = R"( 2297 define i32 @f(i32 %a, i32 %b) { 2298 bb0: 2299 %0 = add i32 %a, %b 2300 %1 = sub i32 %b, %a 2301 br label %bb1 2302 bb1: 2303 %2 = add i32 %a, %b 2304 %3 = sub i32 %b, %a 2305 ret i32 0 2306 })"; 2307 LLVMContext Context; 2308 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); 2309 2310 std::vector<std::vector<IRSimilarityCandidate>> SimilarityCandidates; 2311 getSimilarities(*M, SimilarityCandidates); 2312 2313 ASSERT_TRUE(SimilarityCandidates.size() == 1); 2314 for (std::vector<IRSimilarityCandidate> &Cands : SimilarityCandidates) { 2315 ASSERT_TRUE(Cands.size() == 2); 2316 unsigned InstIdx = 0; 2317 for (IRSimilarityCandidate &Cand : Cands) { 2318 ASSERT_TRUE(Cand.getStartIdx() == InstIdx); 2319 InstIdx += 3; 2320 } 2321 } 2322 } 2323 2324 // Checks that incorrect sequences are not found as similar. In this case, 2325 // we have different sequences of instructions. 2326 TEST(IRSimilarityIdentifier, InstructionDifference) { 2327 StringRef ModuleString = R"( 2328 define i32 @f(i32 %a, i32 %b, i32 %c, i32 %d) { 2329 bb0: 2330 %0 = sub i32 %a, %b 2331 %1 = add i32 %b, %a 2332 br label %bb1 2333 bb1: 2334 %2 = add i32 %c, %d 2335 %3 = sub i32 %d, %c 2336 ret i32 0 2337 })"; 2338 LLVMContext Context; 2339 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); 2340 2341 std::vector<std::vector<IRSimilarityCandidate>> SimilarityCandidates; 2342 getSimilarities(*M, SimilarityCandidates); 2343 2344 ASSERT_TRUE(SimilarityCandidates.empty()); 2345 } 2346 2347 // This test checks to see whether we can detect similarity for commutative 2348 // instructions where the operands have been reversed. 2349 TEST(IRSimilarityIdentifier, CommutativeSimilarity) { 2350 StringRef ModuleString = R"( 2351 define i32 @f(i32 %a, i32 %b) { 2352 bb0: 2353 %0 = add i32 %a, %b 2354 %1 = add i32 %b, %a 2355 br label %bb1 2356 bb1: 2357 %2 = add i32 %a, %b 2358 %3 = add i32 %a, %b 2359 ret i32 0 2360 })"; 2361 LLVMContext Context; 2362 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); 2363 2364 std::vector<std::vector<IRSimilarityCandidate>> SimilarityCandidates; 2365 getSimilarities(*M, SimilarityCandidates); 2366 2367 ASSERT_TRUE(SimilarityCandidates.size() == 1); 2368 for (std::vector<IRSimilarityCandidate> &Cands : SimilarityCandidates) { 2369 ASSERT_TRUE(Cands.size() == 2); 2370 unsigned InstIdx = 0; 2371 for (IRSimilarityCandidate &Cand : Cands) { 2372 ASSERT_TRUE(Cand.getStartIdx() == InstIdx); 2373 InstIdx += 3; 2374 } 2375 } 2376 } 2377 2378 // This test checks to see whether we can detect different structure in 2379 // commutative instructions. In this case, the second operand in the second 2380 // add is different. 2381 TEST(IRSimilarityIdentifier, NoCommutativeSimilarity) { 2382 StringRef ModuleString = R"( 2383 define i32 @f(i32 %a, i32 %b) { 2384 bb0: 2385 %0 = add i32 %a, %b 2386 %1 = add i32 %1, %b 2387 br label %bb1 2388 bb1: 2389 %2 = add i32 %a, %b 2390 %3 = add i32 %2, %a 2391 ret i32 0 2392 })"; 2393 LLVMContext Context; 2394 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); 2395 2396 std::vector<std::vector<IRSimilarityCandidate>> SimilarityCandidates; 2397 getSimilarities(*M, SimilarityCandidates); 2398 2399 ASSERT_TRUE(SimilarityCandidates.size() == 0); 2400 } 2401 2402 // Check that we are not finding similarity in non commutative 2403 // instructions. That is, while the instruction and operands used are the same 2404 // in the two subtraction sequences, they are in a different order, and cannot 2405 // be counted as the same since a subtraction is not commutative. 2406 TEST(IRSimilarityIdentifier, NonCommutativeDifference) { 2407 StringRef ModuleString = R"( 2408 define i32 @f(i32 %a, i32 %b) { 2409 bb0: 2410 %0 = sub i32 %a, %b 2411 %1 = sub i32 %b, %a 2412 br label %bb1 2413 bb1: 2414 %2 = sub i32 %a, %b 2415 %3 = sub i32 %a, %b 2416 ret i32 0 2417 })"; 2418 LLVMContext Context; 2419 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); 2420 2421 std::vector<std::vector<IRSimilarityCandidate>> SimilarityCandidates; 2422 getSimilarities(*M, SimilarityCandidates); 2423 2424 ASSERT_TRUE(SimilarityCandidates.empty()); 2425 } 2426 2427 // Check that we find similarity despite changing the register names. 2428 TEST(IRSimilarityIdentifier, MappingSimilarity) { 2429 StringRef ModuleString = R"( 2430 define i32 @f(i32 %a, i32 %b, i32 %c, i32 %d) { 2431 bb0: 2432 %0 = add i32 %a, %b 2433 %1 = sub i32 %b, %a 2434 br label %bb1 2435 bb1: 2436 %2 = add i32 %c, %d 2437 %3 = sub i32 %d, %c 2438 ret i32 0 2439 })"; 2440 LLVMContext Context; 2441 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); 2442 2443 std::vector<std::vector<IRSimilarityCandidate>> SimilarityCandidates; 2444 getSimilarities(*M, SimilarityCandidates); 2445 2446 ASSERT_TRUE(SimilarityCandidates.size() == 1); 2447 for (std::vector<IRSimilarityCandidate> &Cands : SimilarityCandidates) { 2448 ASSERT_TRUE(Cands.size() == 2); 2449 unsigned InstIdx = 0; 2450 for (IRSimilarityCandidate &Cand : Cands) { 2451 ASSERT_TRUE(Cand.getStartIdx() == InstIdx); 2452 InstIdx += 3; 2453 } 2454 } 2455 } 2456 2457 // Check that we find instances of swapped predicate isomorphism. That is, 2458 // for predicates that can be flipped, e.g. greater than to less than, 2459 // we can identify that instances of these different literal predicates, but are 2460 // the same within a single swap can be found. 2461 TEST(IRSimilarityIdentifier, PredicateIsomorphism) { 2462 StringRef ModuleString = R"( 2463 define i32 @f(i32 %a, i32 %b) { 2464 bb0: 2465 %0 = add i32 %a, %b 2466 %1 = icmp sgt i32 %b, %a 2467 br label %bb1 2468 bb1: 2469 %2 = add i32 %a, %b 2470 %3 = icmp slt i32 %a, %b 2471 ret i32 0 2472 })"; 2473 LLVMContext Context; 2474 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); 2475 2476 std::vector<std::vector<IRSimilarityCandidate>> SimilarityCandidates; 2477 getSimilarities(*M, SimilarityCandidates); 2478 2479 ASSERT_TRUE(SimilarityCandidates.size() == 1); 2480 for (std::vector<IRSimilarityCandidate> &Cands : SimilarityCandidates) { 2481 ASSERT_TRUE(Cands.size() == 2); 2482 unsigned InstIdx = 0; 2483 for (IRSimilarityCandidate &Cand : Cands) { 2484 ASSERT_TRUE(Cand.getStartIdx() == InstIdx); 2485 InstIdx += 3; 2486 } 2487 } 2488 } 2489 2490 // Checks that constants are detected as the same operand in each use in the 2491 // sequences of instructions. Also checks that we can find structural 2492 // equivalence using constants. In this case the 1 has the same use pattern as 2493 // %a. 2494 TEST(IRSimilarityIdentifier, ConstantMappingSimilarity) { 2495 StringRef ModuleString = R"( 2496 define i32 @f(i32 %a, i32 %b) { 2497 bb0: 2498 %0 = add i32 1, %b 2499 %1 = icmp sgt i32 %b, 1 2500 br label %bb1 2501 bb1: 2502 %2 = add i32 %a, %b 2503 %3 = icmp sgt i32 %b, %a 2504 ret i32 0 2505 })"; 2506 LLVMContext Context; 2507 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); 2508 2509 std::vector<std::vector<IRSimilarityCandidate>> SimilarityCandidates; 2510 getSimilarities(*M, SimilarityCandidates); 2511 2512 ASSERT_TRUE(SimilarityCandidates.size() == 1); 2513 for (std::vector<IRSimilarityCandidate> &Cands : SimilarityCandidates) { 2514 ASSERT_TRUE(Cands.size() == 2); 2515 unsigned InstIdx = 0; 2516 for (IRSimilarityCandidate &Cand : Cands) { 2517 ASSERT_TRUE(Cand.getStartIdx() == InstIdx); 2518 InstIdx += 3; 2519 } 2520 } 2521 } 2522 2523 // Check that constants are uniquely identified. i.e. two different constants 2524 // are not considered the same. This means that this should not find any 2525 // structural similarity. 2526 TEST(IRSimilarityIdentifier, ConstantMappingDifference) { 2527 StringRef ModuleString = R"( 2528 define i32 @f(i32 %a, i32 %b) { 2529 bb0: 2530 %0 = add i32 1, %b 2531 %1 = icmp sgt i32 %b, 2 2532 br label %bb1 2533 bb1: 2534 %2 = add i32 %a, %b 2535 %3 = icmp slt i32 %a, %b 2536 ret i32 0 2537 })"; 2538 LLVMContext Context; 2539 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); 2540 2541 std::vector<std::vector<IRSimilarityCandidate>> SimilarityCandidates; 2542 getSimilarities(*M, SimilarityCandidates); 2543 2544 ASSERT_TRUE(SimilarityCandidates.empty()); 2545 } 2546