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