comparison llvm/unittests/Analysis/IRSimilarityIdentifierTest.cpp @ 236:c4bab56944e8 llvm-original

LLVM 16
author kono
date Wed, 09 Nov 2022 17:45:10 +0900
parents 79ff65ed7e25
children
comparison
equal deleted inserted replaced
232:70dce7da266c 236:c4bab56944e8
39 } 39 }
40 40
41 void getSimilarities( 41 void getSimilarities(
42 Module &M, 42 Module &M,
43 std::vector<std::vector<IRSimilarityCandidate>> &SimilarityCandidates) { 43 std::vector<std::vector<IRSimilarityCandidate>> &SimilarityCandidates) {
44 IRSimilarityIdentifier Identifier; 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);
45 SimilarityCandidates = Identifier.findSimilarity(M); 47 SimilarityCandidates = Identifier.findSimilarity(M);
46 } 48 }
47 49
48 // Checks that different opcodes are mapped to different values 50 // Checks that different opcodes are mapped to different values
49 TEST(IRInstructionMapper, OpcodeDifferentiation) { 51 TEST(IRInstructionMapper, OpcodeDifferentiation) {
722 getVectors(*M, Mapper, InstrList, UnsignedVec); 724 getVectors(*M, Mapper, InstrList, UnsignedVec);
723 725
724 ASSERT_TRUE(InstrList.size() == UnsignedVec.size()); 726 ASSERT_TRUE(InstrList.size() == UnsignedVec.size());
725 ASSERT_TRUE(UnsignedVec.size() == 3); 727 ASSERT_TRUE(UnsignedVec.size() == 3);
726 ASSERT_TRUE(UnsignedVec[0] != UnsignedVec[1]); 728 ASSERT_TRUE(UnsignedVec[0] != UnsignedVec[1]);
729 }
730
731 // Checks that the branch is mapped to legal when the option is set.
732 TEST(IRInstructionMapper, BranchLegal) {
733 StringRef ModuleString = R"(
734 define i32 @f(i32 %a, i32 %b) {
735 bb0:
736 %0 = icmp slt i32 %a, %b
737 br i1 %0, label %bb0, label %bb1
738 bb1:
739 ret i32 0
740 })";
741 LLVMContext Context;
742 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
743
744 std::vector<IRInstructionData *> InstrList;
745 std::vector<unsigned> UnsignedVec;
746
747 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
748 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
749 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
750 Mapper.InstClassifier.EnableBranches = true;
751 Mapper.initializeForBBs(*M);
752 getVectors(*M, Mapper, InstrList, UnsignedVec);
753
754 ASSERT_EQ(InstrList.size(), UnsignedVec.size());
755 ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(3));
756 ASSERT_TRUE(UnsignedVec[1] > UnsignedVec[0]);
757 ASSERT_TRUE(UnsignedVec[1] < UnsignedVec[2]);
758 }
759
760 // Checks that a PHINode is mapped to be legal.
761 TEST(IRInstructionMapper, PhiLegal) {
762 StringRef ModuleString = R"(
763 define i32 @f(i32 %a, i32 %b) {
764 bb0:
765 %0 = phi i1 [ 0, %bb0 ], [ %0, %bb1 ]
766 %1 = add i32 %a, %b
767 ret i32 0
768 bb1:
769 ret i32 1
770 })";
771 LLVMContext Context;
772 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
773
774 std::vector<IRInstructionData *> InstrList;
775 std::vector<unsigned> UnsignedVec;
776
777 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
778 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
779 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
780 Mapper.InstClassifier.EnableBranches = true;
781 Mapper.initializeForBBs(*M);
782 getVectors(*M, Mapper, InstrList, UnsignedVec);
783
784 ASSERT_EQ(InstrList.size(), UnsignedVec.size());
785 ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(3));
786 }
787
788 // Checks that a PHINode is mapped to be legal.
789 TEST(IRInstructionMapper, PhiIllegal) {
790 StringRef ModuleString = R"(
791 define i32 @f(i32 %a, i32 %b) {
792 bb0:
793 %0 = phi i1 [ 0, %bb0 ], [ %0, %bb1 ]
794 %1 = add i32 %a, %b
795 ret i32 0
796 bb1:
797 ret i32 1
798 })";
799 LLVMContext Context;
800 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
801
802 std::vector<IRInstructionData *> InstrList;
803 std::vector<unsigned> UnsignedVec;
804
805 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
806 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
807 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
808 Mapper.initializeForBBs(*M);
809 getVectors(*M, Mapper, InstrList, UnsignedVec);
810
811 ASSERT_EQ(InstrList.size(), UnsignedVec.size());
812 ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(3));
813 ASSERT_GT(UnsignedVec[0], Mapper.IllegalInstrNumber);
727 } 814 }
728 815
729 // In most cases, the illegal instructions we are collecting don't require any 816 // 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, 817 // 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. 818 // and the mapper will create 0 length vectors, and we can check that.
736 // instruction that comes after. So to check that we have an illegal 823 // instruction that comes after. So to check that we have an illegal
737 // instruction, we place a legal instruction after an illegal instruction, and 824 // instruction, we place a legal instruction after an illegal instruction, and
738 // check that the illegal unsigned integer is greater than the unsigned integer 825 // check that the illegal unsigned integer is greater than the unsigned integer
739 // of the legal instruction. 826 // of the legal instruction.
740 827
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. 828 // Checks that an alloca instruction is mapped to be illegal.
796 TEST(IRInstructionMapper, AllocaIllegal) { 829 TEST(IRInstructionMapper, AllocaIllegal) {
797 StringRef ModuleString = R"( 830 StringRef ModuleString = R"(
798 define i32 @f(i32 %a, i32 %b) { 831 define i32 @f(i32 %a, i32 %b) {
799 bb0: 832 bb0:
810 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator; 843 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
811 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator); 844 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
812 getVectors(*M, Mapper, InstrList, UnsignedVec); 845 getVectors(*M, Mapper, InstrList, UnsignedVec);
813 846
814 ASSERT_EQ(InstrList.size(), UnsignedVec.size()); 847 ASSERT_EQ(InstrList.size(), UnsignedVec.size());
815 ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(0)); 848 ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(1));
849 ASSERT_GT(UnsignedVec[0], Mapper.IllegalInstrNumber);
816 } 850 }
817 851
818 // Checks that an getelementptr instruction is mapped to be legal. And that 852 // Checks that an getelementptr instruction is mapped to be legal. And that
819 // the operands in getelementpointer instructions are the exact same after the 853 // the operands in getelementpointer instructions are the exact same after the
820 // first element operand, which only requires the same type. 854 // first element operand, which only requires the same type.
927 ASSERT_EQ(InstrList.size(), UnsignedVec.size()); 961 ASSERT_EQ(InstrList.size(), UnsignedVec.size());
928 ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(3)); 962 ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(3));
929 ASSERT_NE(UnsignedVec[0], UnsignedVec[1]); 963 ASSERT_NE(UnsignedVec[0], UnsignedVec[1]);
930 } 964 }
931 965
932 // Checks that indirect call instructions are mapped to be illegal since we 966 // Checks that indirect call instructions are mapped to be illegal when it is
933 // cannot guarantee the same function in two different cases. 967 // specified to disallow them.
934 TEST(IRInstructionMapper, CallsIllegalIndirect) { 968 TEST(IRInstructionMapper, CallsIllegalIndirect) {
935 StringRef ModuleString = R"( 969 StringRef ModuleString = R"(
936 define i32 @f(void()* %func) { 970 define i32 @f(void()* %func) {
937 bb0: 971 bb0:
938 call void %func() 972 call void %func()
945 std::vector<unsigned> UnsignedVec; 979 std::vector<unsigned> UnsignedVec;
946 980
947 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator; 981 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
948 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator; 982 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
949 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator); 983 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
950 getVectors(*M, Mapper, InstrList, UnsignedVec); 984 Mapper.InstClassifier.EnableIndirectCalls = false;
951 985 getVectors(*M, Mapper, InstrList, UnsignedVec);
952 ASSERT_EQ(InstrList.size(), UnsignedVec.size()); 986
953 ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(0)); 987 ASSERT_EQ(InstrList.size(), UnsignedVec.size());
988 ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(1));
989 ASSERT_GT(UnsignedVec[0], Mapper.IllegalInstrNumber);
990 }
991
992 // Checks that indirect call instructions are mapped to be legal when it is not
993 // specified to disallow them.
994 TEST(IRInstructionMapper, CallsLegalIndirect) {
995 StringRef ModuleString = R"(
996 define i32 @f(void()* %func) {
997 bb0:
998 call void %func()
999 call void %func()
1000 ret i32 0
1001 })";
1002 LLVMContext Context;
1003 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
1004
1005 std::vector<IRInstructionData *> InstrList;
1006 std::vector<unsigned> UnsignedVec;
1007
1008 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
1009 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
1010 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
1011 Mapper.InstClassifier.EnableIndirectCalls = true;
1012 getVectors(*M, Mapper, InstrList, UnsignedVec);
1013
1014 ASSERT_EQ(InstrList.size(), UnsignedVec.size());
1015 ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(3));
954 } 1016 }
955 1017
956 // Checks that a call instruction is mapped to be legal. Here we check that 1018 // 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 1019 // a call with the same name, and same types are mapped to the same
958 // value. 1020 // value.
980 ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(3)); 1042 ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(3));
981 ASSERT_EQ(UnsignedVec[0], UnsignedVec[1]); 1043 ASSERT_EQ(UnsignedVec[0], UnsignedVec[1]);
982 } 1044 }
983 1045
984 // Here we check that a calls with different names, but the same arguments types 1046 // Here we check that a calls with different names, but the same arguments types
985 // are mapped to different value. 1047 // are mapped to different value when specified that the name must match.
986 TEST(IRInstructionMapper, CallsSameArgTypeDifferentName) { 1048 TEST(IRInstructionMapper, CallsSameArgTypeDifferentNameDisallowed) {
987 StringRef ModuleString = R"( 1049 StringRef ModuleString = R"(
988 declare i32 @f1(i32, i32) 1050 declare i32 @f1(i32, i32)
989 declare i32 @f2(i32, i32) 1051 declare i32 @f2(i32, i32)
990 define i32 @f(i32 %a, i32 %b) { 1052 define i32 @f(i32 %a, i32 %b) {
991 bb0: 1053 bb0:
1000 std::vector<unsigned> UnsignedVec; 1062 std::vector<unsigned> UnsignedVec;
1001 1063
1002 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator; 1064 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
1003 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator; 1065 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
1004 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator); 1066 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
1067 Mapper.EnableMatchCallsByName = true;
1005 getVectors(*M, Mapper, InstrList, UnsignedVec); 1068 getVectors(*M, Mapper, InstrList, UnsignedVec);
1006 1069
1007 ASSERT_EQ(InstrList.size(), UnsignedVec.size()); 1070 ASSERT_EQ(InstrList.size(), UnsignedVec.size());
1008 ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(3)); 1071 ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(3));
1009 ASSERT_NE(UnsignedVec[0], UnsignedVec[1]); 1072 ASSERT_NE(UnsignedVec[0], UnsignedVec[1]);
1073 }
1074
1075 // Here we check that a calls with different names, but the same arguments types
1076 // are mapped to the same value when it is not specifed that they must match.
1077 TEST(IRInstructionMapper, CallsSameArgTypeDifferentName) {
1078 StringRef ModuleString = R"(
1079 declare i32 @f1(i32, i32)
1080 declare i32 @f2(i32, i32)
1081 define i32 @f(i32 %a, i32 %b) {
1082 bb0:
1083 %0 = call i32 @f1(i32 %a, i32 %b)
1084 %1 = call i32 @f2(i32 %a, i32 %b)
1085 ret i32 0
1086 })";
1087 LLVMContext Context;
1088 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
1089
1090 std::vector<IRInstructionData *> InstrList;
1091 std::vector<unsigned> UnsignedVec;
1092
1093 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
1094 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
1095 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
1096 Mapper.EnableMatchCallsByName = false;
1097 getVectors(*M, Mapper, InstrList, UnsignedVec);
1098
1099 ASSERT_EQ(InstrList.size(), UnsignedVec.size());
1100 ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(3));
1101 ASSERT_EQ(UnsignedVec[0], UnsignedVec[1]);
1010 } 1102 }
1011 1103
1012 // Here we check that a calls with different names, and different arguments 1104 // Here we check that a calls with different names, and different arguments
1013 // types are mapped to different value. 1105 // types are mapped to different value.
1014 TEST(IRInstructionMapper, CallsDifferentArgTypeDifferentName) { 1106 TEST(IRInstructionMapper, CallsDifferentArgTypeDifferentName) {
1174 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator; 1266 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
1175 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator); 1267 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
1176 getVectors(*M, Mapper, InstrList, UnsignedVec); 1268 getVectors(*M, Mapper, InstrList, UnsignedVec);
1177 1269
1178 ASSERT_EQ(InstrList.size(), UnsignedVec.size()); 1270 ASSERT_EQ(InstrList.size(), UnsignedVec.size());
1179 ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(0)); 1271 ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(1));
1272 ASSERT_GT(UnsignedVec[0], Mapper.IllegalInstrNumber);
1180 } 1273 }
1181 1274
1182 // Checks that an callbr instructions are considered to be illegal. Callbr 1275 // Checks that an callbr instructions are considered to be illegal. Callbr
1183 // instructions are considered to be illegal because of the change in the 1276 // instructions are considered to be illegal because of the change in the
1184 // control flow that is currently not recognized. 1277 // control flow that is currently not recognized.
1207 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator; 1300 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
1208 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator); 1301 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
1209 getVectors(*M, Mapper, InstrList, UnsignedVec); 1302 getVectors(*M, Mapper, InstrList, UnsignedVec);
1210 1303
1211 ASSERT_EQ(InstrList.size(), UnsignedVec.size()); 1304 ASSERT_EQ(InstrList.size(), UnsignedVec.size());
1212 ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(0)); 1305 ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(1));
1306 ASSERT_GT(UnsignedVec[0], Mapper.IllegalInstrNumber);
1213 } 1307 }
1214 1308
1215 // Checks that an debuginfo intrinsics are mapped to be invisible. Since they 1309 // 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. 1310 // do not semantically change the program, they can be recognized as similar.
1217 TEST(IRInstructionMapper, DebugInfoInvisible) { 1311 TEST(IRInstructionMapper, DebugInfoInvisible) {
1265 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator; 1359 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
1266 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator); 1360 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
1267 getVectors(*M, Mapper, InstrList, UnsignedVec); 1361 getVectors(*M, Mapper, InstrList, UnsignedVec);
1268 1362
1269 ASSERT_EQ(InstrList.size(), UnsignedVec.size()); 1363 ASSERT_EQ(InstrList.size(), UnsignedVec.size());
1270 ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(0)); 1364 ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(1));
1365 ASSERT_GT(UnsignedVec[0], Mapper.IllegalInstrNumber);
1271 } 1366 }
1272 1367
1273 // Checks that an eh.exceptioncode intrinsic is mapped to be illegal. 1368 // Checks that an eh.exceptioncode intrinsic is mapped to be illegal.
1274 TEST(IRInstructionMapper, ExceptionHandlingExceptionCodeIllegal) { 1369 TEST(IRInstructionMapper, ExceptionHandlingExceptionCodeIllegal) {
1275 StringRef ModuleString = R"( 1370 StringRef ModuleString = R"(
1297 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator; 1392 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
1298 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator); 1393 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
1299 getVectors(*M, Mapper, InstrList, UnsignedVec); 1394 getVectors(*M, Mapper, InstrList, UnsignedVec);
1300 1395
1301 ASSERT_EQ(InstrList.size(), UnsignedVec.size()); 1396 ASSERT_EQ(InstrList.size(), UnsignedVec.size());
1302 ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(0)); 1397 ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(1));
1398 ASSERT_GT(UnsignedVec[0], Mapper.IllegalInstrNumber);
1303 } 1399 }
1304 1400
1305 // Checks that an eh.unwind intrinsic is mapped to be illegal. 1401 // Checks that an eh.unwind intrinsic is mapped to be illegal.
1306 TEST(IRInstructionMapper, ExceptionHandlingUnwindIllegal) { 1402 TEST(IRInstructionMapper, ExceptionHandlingUnwindIllegal) {
1307 StringRef ModuleString = R"( 1403 StringRef ModuleString = R"(
1322 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator; 1418 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
1323 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator); 1419 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
1324 getVectors(*M, Mapper, InstrList, UnsignedVec); 1420 getVectors(*M, Mapper, InstrList, UnsignedVec);
1325 1421
1326 ASSERT_EQ(InstrList.size(), UnsignedVec.size()); 1422 ASSERT_EQ(InstrList.size(), UnsignedVec.size());
1327 ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(0)); 1423 ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(1));
1424 ASSERT_GT(UnsignedVec[0], Mapper.IllegalInstrNumber);
1328 } 1425 }
1329 1426
1330 // Checks that an eh.exceptionpointer intrinsic is mapped to be illegal. 1427 // Checks that an eh.exceptionpointer intrinsic is mapped to be illegal.
1331 TEST(IRInstructionMapper, ExceptionHandlingExceptionPointerIllegal) { 1428 TEST(IRInstructionMapper, ExceptionHandlingExceptionPointerIllegal) {
1332 StringRef ModuleString = R"( 1429 StringRef ModuleString = R"(
1347 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator; 1444 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
1348 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator); 1445 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
1349 getVectors(*M, Mapper, InstrList, UnsignedVec); 1446 getVectors(*M, Mapper, InstrList, UnsignedVec);
1350 1447
1351 ASSERT_EQ(InstrList.size(), UnsignedVec.size()); 1448 ASSERT_EQ(InstrList.size(), UnsignedVec.size());
1352 ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(0)); 1449 ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(1));
1450 ASSERT_GT(UnsignedVec[0], Mapper.IllegalInstrNumber);
1353 } 1451 }
1354 1452
1355 // Checks that a catchpad instruction is mapped to an illegal value. 1453 // Checks that a catchpad instruction is mapped to an illegal value.
1356 TEST(IRInstructionMapper, CatchpadIllegal) { 1454 TEST(IRInstructionMapper, CatchpadIllegal) {
1357 StringRef ModuleString = R"( 1455 StringRef ModuleString = R"(
1378 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator; 1476 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
1379 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator); 1477 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
1380 getVectors(*M, Mapper, InstrList, UnsignedVec); 1478 getVectors(*M, Mapper, InstrList, UnsignedVec);
1381 1479
1382 ASSERT_EQ(InstrList.size(), UnsignedVec.size()); 1480 ASSERT_EQ(InstrList.size(), UnsignedVec.size());
1383 ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(0)); 1481 ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(1));
1482 ASSERT_GT(UnsignedVec[0], Mapper.IllegalInstrNumber);
1384 } 1483 }
1385 1484
1386 // Checks that a cleanuppad instruction is mapped to an illegal value. 1485 // Checks that a cleanuppad instruction is mapped to an illegal value.
1387 TEST(IRInstructionMapper, CleanuppadIllegal) { 1486 TEST(IRInstructionMapper, CleanuppadIllegal) {
1388 StringRef ModuleString = R"( 1487 StringRef ModuleString = R"(
1409 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator; 1508 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
1410 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator); 1509 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
1411 getVectors(*M, Mapper, InstrList, UnsignedVec); 1510 getVectors(*M, Mapper, InstrList, UnsignedVec);
1412 1511
1413 ASSERT_EQ(InstrList.size(), UnsignedVec.size()); 1512 ASSERT_EQ(InstrList.size(), UnsignedVec.size());
1414 ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(0)); 1513 ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(1));
1514 ASSERT_GT(UnsignedVec[0], Mapper.IllegalInstrNumber);
1415 } 1515 }
1416 1516
1417 // The following three instructions are memory transfer and setting based, which 1517 // The following three instructions are memory transfer and setting based, which
1418 // are considered illegal since is extra checking needed to handle the address 1518 // are considered illegal since is extra checking needed to handle the address
1419 // space checking. 1519 // space checking.
1420 1520
1421 // Checks that a memset instruction is mapped to an illegal value. 1521 // Checks that a memset instruction is mapped to an illegal value when
1522 // specified.
1422 TEST(IRInstructionMapper, MemSetIllegal) { 1523 TEST(IRInstructionMapper, MemSetIllegal) {
1423 StringRef ModuleString = R"( 1524 StringRef ModuleString = R"(
1424 declare void @llvm.memset.p0i8.i64(i8* nocapture writeonly, i8, i64, i32, i1) 1525 declare void @llvm.memset.p0i8.i64(i8* nocapture writeonly, i8, i64, i32, i1)
1425 1526
1426 define i64 @function(i64 %x, i64 %z, i64 %n) { 1527 define i64 @function(i64 %x, i64 %z, i64 %n) {
1440 std::vector<unsigned> UnsignedVec; 1541 std::vector<unsigned> UnsignedVec;
1441 1542
1442 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator; 1543 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
1443 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator; 1544 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
1444 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator); 1545 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
1445 getVectors(*M, Mapper, InstrList, UnsignedVec); 1546 Mapper.InstClassifier.EnableIntrinsics = false;
1446 1547 getVectors(*M, Mapper, InstrList, UnsignedVec);
1447 ASSERT_EQ(InstrList.size(), UnsignedVec.size()); 1548
1448 ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(6)); 1549 ASSERT_EQ(InstrList.size(), UnsignedVec.size());
1449 ASSERT_TRUE(UnsignedVec[2] < UnsignedVec[1]); 1550 ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(7));
1450 } 1551 ASSERT_TRUE(UnsignedVec[2] < UnsignedVec[0]);
1451 1552 }
1452 // Checks that a memcpy instruction is mapped to an illegal value. 1553
1554 // Checks that a memcpy instruction is mapped to an illegal value when
1555 // specified.
1453 TEST(IRInstructionMapper, MemCpyIllegal) { 1556 TEST(IRInstructionMapper, MemCpyIllegal) {
1454 StringRef ModuleString = R"( 1557 StringRef ModuleString = R"(
1455 declare void @llvm.memcpy.p0i8.i64(i8* nocapture writeonly, i8, i64, i32, i1) 1558 declare void @llvm.memcpy.p0i8.i64(i8* nocapture writeonly, i8, i64, i32, i1)
1456 1559
1457 define i64 @function(i64 %x, i64 %z, i64 %n) { 1560 define i64 @function(i64 %x, i64 %z, i64 %n) {
1471 std::vector<unsigned> UnsignedVec; 1574 std::vector<unsigned> UnsignedVec;
1472 1575
1473 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator; 1576 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
1474 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator; 1577 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
1475 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator); 1578 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
1476 getVectors(*M, Mapper, InstrList, UnsignedVec); 1579 Mapper.InstClassifier.EnableIntrinsics = false;
1477 1580 getVectors(*M, Mapper, InstrList, UnsignedVec);
1478 ASSERT_EQ(InstrList.size(), UnsignedVec.size()); 1581
1479 ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(6)); 1582 ASSERT_EQ(InstrList.size(), UnsignedVec.size());
1480 ASSERT_TRUE(UnsignedVec[2] < UnsignedVec[1]); 1583 ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(7));
1481 } 1584 ASSERT_GT(UnsignedVec[2], UnsignedVec[3]);
1482 1585 ASSERT_LT(UnsignedVec[2], UnsignedVec[0]);
1483 // Checks that a memmove instruction is mapped to an illegal value. 1586 }
1587
1588 // Checks that a memmove instruction is mapped to an illegal value when
1589 // specified.
1484 TEST(IRInstructionMapper, MemMoveIllegal) { 1590 TEST(IRInstructionMapper, MemMoveIllegal) {
1485 StringRef ModuleString = R"( 1591 StringRef ModuleString = R"(
1486 declare void @llvm.memmove.p0i8.i64(i8* nocapture writeonly, i8, i64, i32, i1) 1592 declare void @llvm.memmove.p0i8.i64(i8* nocapture writeonly, i8, i64, i32, i1)
1487 1593
1488 define i64 @function(i64 %x, i64 %z, i64 %n) { 1594 define i64 @function(i64 %x, i64 %z, i64 %n) {
1502 std::vector<unsigned> UnsignedVec; 1608 std::vector<unsigned> UnsignedVec;
1503 1609
1504 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator; 1610 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
1505 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator; 1611 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
1506 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator); 1612 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
1507 getVectors(*M, Mapper, InstrList, UnsignedVec); 1613 Mapper.InstClassifier.EnableIntrinsics = false;
1508 1614 getVectors(*M, Mapper, InstrList, UnsignedVec);
1509 ASSERT_EQ(InstrList.size(), UnsignedVec.size()); 1615
1510 ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(6)); 1616 ASSERT_EQ(InstrList.size(), UnsignedVec.size());
1511 ASSERT_TRUE(UnsignedVec[2] < UnsignedVec[1]); 1617 ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(7));
1618 ASSERT_LT(UnsignedVec[2], UnsignedVec[0]);
1619 }
1620
1621 // Checks that mem* instructions are mapped to an legal value when not
1622 // specified, and that all the intrinsics are marked differently.
1623 TEST(IRInstructionMapper, MemOpsLegal) {
1624 StringRef ModuleString = R"(
1625 declare void @llvm.memmove.p0i8.i64(i8* nocapture writeonly, i8, i64, i32, i1)
1626 declare void @llvm.memcpy.p0i8.i64(i8* nocapture writeonly, i8, i64, i32, i1)
1627 declare void @llvm.memset.p0i8.i64(i8* nocapture writeonly, i8, i64, i32, i1)
1628
1629 define i64 @function(i64 %x, i64 %z, i64 %n) {
1630 entry:
1631 %pool = alloca [59 x i64], align 4
1632 %tmp = bitcast [59 x i64]* %pool to i8*
1633 call void @llvm.memmove.p0i8.i64(i8* nonnull %tmp, i8 0, i64 236, i32 4, i1 false)
1634 call void @llvm.memcpy.p0i8.i64(i8* nonnull %tmp, i8 0, i64 236, i32 4, i1 false)
1635 call void @llvm.memset.p0i8.i64(i8* nonnull %tmp, i8 0, i64 236, i32 4, i1 false)
1636 %cmp3 = icmp eq i64 %n, 0
1637 %a = add i64 %x, %z
1638 %c = add i64 %x, %z
1639 ret i64 0
1640 })";
1641 LLVMContext Context;
1642 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
1643
1644 std::vector<IRInstructionData *> InstrList;
1645 std::vector<unsigned> UnsignedVec;
1646
1647 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
1648 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
1649 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
1650 Mapper.InstClassifier.EnableIntrinsics = true;
1651 getVectors(*M, Mapper, InstrList, UnsignedVec);
1652
1653 ASSERT_EQ(InstrList.size(), UnsignedVec.size());
1654 ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(9));
1655 ASSERT_LT(UnsignedVec[2], UnsignedVec[3]);
1656 ASSERT_LT(UnsignedVec[3], UnsignedVec[4]);
1657 ASSERT_LT(UnsignedVec[4], UnsignedVec[5]);
1512 } 1658 }
1513 1659
1514 // Checks that a variable argument instructions are mapped to an illegal value. 1660 // Checks that a variable argument instructions are mapped to an illegal value.
1515 // We exclude variable argument instructions since variable arguments 1661 // We exclude variable argument instructions since variable arguments
1516 // requires extra checking of the argument list. 1662 // requires extra checking of the argument list.
1550 std::vector<unsigned> UnsignedVec; 1696 std::vector<unsigned> UnsignedVec;
1551 1697
1552 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator; 1698 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
1553 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator; 1699 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
1554 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator); 1700 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
1555 getVectors(*M, Mapper, InstrList, UnsignedVec); 1701 Mapper.InstClassifier.EnableIntrinsics = false;
1556 1702 getVectors(*M, Mapper, InstrList, UnsignedVec);
1557 ASSERT_EQ(InstrList.size(), UnsignedVec.size()); 1703
1558 ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(16)); 1704 ASSERT_EQ(InstrList.size(), UnsignedVec.size());
1559 ASSERT_TRUE(UnsignedVec[4] < UnsignedVec[3]); 1705 ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(17));
1560 ASSERT_TRUE(UnsignedVec[7] < UnsignedVec[6]); 1706 ASSERT_TRUE(UnsignedVec[7] < UnsignedVec[0]);
1561 ASSERT_TRUE(UnsignedVec[10] < UnsignedVec[9]); 1707 ASSERT_TRUE(UnsignedVec[13] < UnsignedVec[10]);
1562 ASSERT_TRUE(UnsignedVec[13] < UnsignedVec[12]); 1708 ASSERT_TRUE(UnsignedVec[16] < UnsignedVec[13]);
1563 } 1709 }
1564 1710
1565 // Check the length of adding two illegal instructions one after th other. We 1711 // 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. 1712 // should find that only one element is added for each illegal range.
1567 TEST(IRInstructionMapper, RepeatedIllegalLength) { 1713 TEST(IRInstructionMapper, RepeatedIllegalLength) {
1597 1743
1598 // A helper function that accepts an instruction list from a module made up of 1744 // 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 1745 // two blocks of two legal instructions and terminator, and checks them for
1600 // instruction similarity. 1746 // instruction similarity.
1601 static bool longSimCandCompare(std::vector<IRInstructionData *> &InstrList, 1747 static bool longSimCandCompare(std::vector<IRInstructionData *> &InstrList,
1602 bool Structure = false) { 1748 bool Structure = false, unsigned Length = 2,
1749 unsigned StartIdxOne = 0,
1750 unsigned StartIdxTwo = 3) {
1603 std::vector<IRInstructionData *>::iterator Start, End; 1751 std::vector<IRInstructionData *>::iterator Start, End;
1604 1752
1605 Start = InstrList.begin(); 1753 Start = InstrList.begin();
1606 End = InstrList.begin(); 1754 End = InstrList.begin();
1607 1755
1608 std::advance(End, 1); 1756 std::advance(End, StartIdxOne + Length - 1);
1609 IRSimilarityCandidate Cand1(0, 2, *Start, *End); 1757 IRSimilarityCandidate Cand1(StartIdxOne, Length, *Start, *End);
1610 1758
1611 Start = InstrList.begin(); 1759 Start = InstrList.begin();
1612 End = InstrList.begin(); 1760 End = InstrList.begin();
1613 1761
1614 std::advance(Start, 3); 1762 std::advance(Start, StartIdxTwo);
1615 std::advance(End, 4); 1763 std::advance(End, StartIdxTwo + Length - 1);
1616 IRSimilarityCandidate Cand2(3, 2, *Start, *End); 1764 IRSimilarityCandidate Cand2(StartIdxTwo, Length, *Start, *End);
1617 if (Structure) 1765 if (Structure)
1618 return IRSimilarityCandidate::compareStructure(Cand1, Cand2); 1766 return IRSimilarityCandidate::compareStructure(Cand1, Cand2);
1619 return IRSimilarityCandidate::isSimilar(Cand1, Cand2); 1767 return IRSimilarityCandidate::isSimilar(Cand1, Cand2);
1620 } 1768 }
1621 1769
1984 ASSERT_TRUE(InstrList.size() == UnsignedVec.size()); 2132 ASSERT_TRUE(InstrList.size() == UnsignedVec.size());
1985 2133
1986 ASSERT_TRUE(longSimCandCompare(InstrList, true)); 2134 ASSERT_TRUE(longSimCandCompare(InstrList, true));
1987 } 2135 }
1988 2136
2137 // Checks that the canonical numbering between two candidates matches the found
2138 // mapping between two candidates.
2139 TEST(IRSimilarityCandidate, CanonicalNumbering) {
2140 StringRef ModuleString = R"(
2141 define i32 @f(i32 %a, i32 %b) {
2142 bb0:
2143 %0 = add i32 %a, %b
2144 %1 = sub i32 %b, %a
2145 ret i32 0
2146 bb1:
2147 %2 = add i32 %a, %b
2148 %3 = sub i32 %b, %a
2149 ret i32 0
2150 })";
2151 LLVMContext Context;
2152 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
2153
2154 std::vector<IRInstructionData *> InstrList;
2155 std::vector<unsigned> UnsignedVec;
2156
2157 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
2158 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
2159 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
2160 getVectors(*M, Mapper, InstrList, UnsignedVec);
2161
2162 // Check to make sure that we have a long enough region.
2163 ASSERT_EQ(InstrList.size(), static_cast<unsigned>(6));
2164 // Check that the instructions were added correctly to both vectors.
2165 ASSERT_EQ(InstrList.size(), UnsignedVec.size());
2166
2167 std::vector<IRInstructionData *>::iterator Start, End;
2168
2169 Start = InstrList.begin();
2170 End = InstrList.begin();
2171
2172 std::advance(End, 1);
2173 IRSimilarityCandidate Cand1(0, 2, *Start, *End);
2174
2175 Start = InstrList.begin();
2176 End = InstrList.begin();
2177
2178 std::advance(Start, 3);
2179 std::advance(End, 4);
2180 IRSimilarityCandidate Cand2(3, 2, *Start, *End);
2181 DenseMap<unsigned, DenseSet<unsigned>> Mapping1;
2182 DenseMap<unsigned, DenseSet<unsigned>> Mapping2;
2183 ASSERT_TRUE(IRSimilarityCandidate::compareStructure(Cand1, Cand2, Mapping1,
2184 Mapping2));
2185 IRSimilarityCandidate::createCanonicalMappingFor(Cand1);
2186 Cand2.createCanonicalRelationFrom(Cand1, Mapping1, Mapping2);
2187
2188 for (std::pair<unsigned, DenseSet<unsigned>> &P : Mapping2) {
2189 unsigned Source = P.first;
2190
2191 ASSERT_TRUE(Cand2.getCanonicalNum(Source).has_value());
2192 unsigned Canon = *Cand2.getCanonicalNum(Source);
2193 ASSERT_TRUE(Cand1.fromCanonicalNum(Canon).has_value());
2194 unsigned Dest = *Cand1.fromCanonicalNum(Canon);
2195
2196 DenseSet<unsigned>::iterator It = P.second.find(Dest);
2197 ASSERT_NE(It, P.second.end());
2198 }
2199 }
2200
1989 // Checks that the same structure is recognized between two candidates. While 2201 // Checks that the same structure is recognized between two candidates. While
1990 // the input names are reversed, they still perform the same overall operation. 2202 // the input names are reversed, they still perform the same overall operation.
1991 TEST(IRSimilarityCandidate, DifferentNameSameStructure) { 2203 TEST(IRSimilarityCandidate, DifferentNameSameStructure) {
1992 StringRef ModuleString = R"( 2204 StringRef ModuleString = R"(
1993 define i32 @f(i32 %a, i32 %b) { 2205 define i32 @f(i32 %a, i32 %b) {
2015 ASSERT_EQ(InstrList.size(), static_cast<unsigned>(6)); 2227 ASSERT_EQ(InstrList.size(), static_cast<unsigned>(6));
2016 // Check that the instructions were added correctly to both vectors. 2228 // Check that the instructions were added correctly to both vectors.
2017 ASSERT_TRUE(InstrList.size() == UnsignedVec.size()); 2229 ASSERT_TRUE(InstrList.size() == UnsignedVec.size());
2018 2230
2019 ASSERT_TRUE(longSimCandCompare(InstrList, true)); 2231 ASSERT_TRUE(longSimCandCompare(InstrList, true));
2232 }
2233
2234 // Checks that the same structure is recognized between two candidates when
2235 // the branches target other blocks inside the same region, the relative
2236 // distance between the blocks must be the same.
2237 TEST(IRSimilarityCandidate, SameBranchStructureInternal) {
2238 StringRef ModuleString = R"(
2239 define i32 @f(i32 %a, i32 %b) {
2240 bb0:
2241 %0 = add i32 %a, %b
2242 %1 = add i32 %b, %a
2243 br label %bb1
2244 bb1:
2245 %2 = add i32 %b, %a
2246 %3 = add i32 %a, %b
2247 ret i32 0
2248 }
2249
2250 define i32 @f2(i32 %a, i32 %b) {
2251 bb0:
2252 %0 = add i32 %a, %b
2253 %1 = add i32 %b, %a
2254 br label %bb1
2255 bb1:
2256 %2 = add i32 %b, %a
2257 %3 = add i32 %a, %b
2258 ret i32 0
2259 })";
2260 LLVMContext Context;
2261 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
2262
2263 std::vector<IRInstructionData *> InstrList;
2264 std::vector<unsigned> UnsignedVec;
2265
2266 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
2267 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
2268 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
2269 Mapper.InstClassifier.EnableBranches = true;
2270 Mapper.initializeForBBs(*M);
2271 getVectors(*M, Mapper, InstrList, UnsignedVec);
2272
2273 // Check to make sure that we have a long enough region.
2274 ASSERT_EQ(InstrList.size(), static_cast<unsigned>(12));
2275 // Check that the instructions were added correctly to both vectors.
2276 ASSERT_TRUE(InstrList.size() == UnsignedVec.size());
2277
2278 ASSERT_TRUE(longSimCandCompare(InstrList, true, 5, 0, 6));
2279 }
2280
2281 // Checks that the different structure is recognized between two candidates,
2282 // when the branches target other blocks inside the same region, the relative
2283 // distance between the blocks must be the same.
2284 TEST(IRSimilarityCandidate, DifferentBranchStructureInternal) {
2285 StringRef ModuleString = R"(
2286 define i32 @f(i32 %a, i32 %b) {
2287 bb0:
2288 %0 = add i32 %a, %b
2289 %1 = add i32 %b, %a
2290 br label %bb2
2291 bb1:
2292 %2 = add i32 %b, %a
2293 %3 = add i32 %a, %b
2294 br label %bb2
2295 bb2:
2296 %4 = add i32 %b, %a
2297 %5 = add i32 %a, %b
2298 ret i32 0
2299 }
2300
2301 define i32 @f2(i32 %a, i32 %b) {
2302 bb0:
2303 %0 = add i32 %a, %b
2304 %1 = add i32 %b, %a
2305 br label %bb1
2306 bb1:
2307 %2 = add i32 %b, %a
2308 %3 = add i32 %a, %b
2309 br label %bb2
2310 bb2:
2311 %4 = add i32 %b, %a
2312 %5 = add i32 %a, %b
2313 ret i32 0
2314 })";
2315 LLVMContext Context;
2316 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
2317
2318 std::vector<IRInstructionData *> InstrList;
2319 std::vector<unsigned> UnsignedVec;
2320
2321 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
2322 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
2323 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
2324 Mapper.InstClassifier.EnableBranches = true;
2325 Mapper.initializeForBBs(*M);
2326 getVectors(*M, Mapper, InstrList, UnsignedVec);
2327
2328 // Check to make sure that we have a long enough region.
2329 ASSERT_EQ(InstrList.size(), static_cast<unsigned>(18));
2330 // Check that the instructions were added correctly to both vectors.
2331 ASSERT_TRUE(InstrList.size() == UnsignedVec.size());
2332
2333 ASSERT_FALSE(longSimCandCompare(InstrList, true, 6, 0, 9));
2334 }
2335
2336 // Checks that the same structure is recognized between two candidates, when
2337 // the branches target other blocks outside region, the relative distance
2338 // does not need to be the same.
2339 TEST(IRSimilarityCandidate, SameBranchStructureOutside) {
2340 StringRef ModuleString = R"(
2341 define i32 @f(i32 %a, i32 %b) {
2342 bb0:
2343 %0 = add i32 %a, %b
2344 %1 = add i32 %b, %a
2345 br label %bb1
2346 bb1:
2347 %2 = add i32 %b, %a
2348 %3 = add i32 %a, %b
2349 ret i32 0
2350 }
2351
2352 define i32 @f2(i32 %a, i32 %b) {
2353 bb0:
2354 %0 = add i32 %a, %b
2355 %1 = add i32 %b, %a
2356 br label %bb1
2357 bb1:
2358 %2 = add i32 %b, %a
2359 %3 = add i32 %a, %b
2360 ret i32 0
2361 })";
2362 LLVMContext Context;
2363 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
2364
2365 std::vector<IRInstructionData *> InstrList;
2366 std::vector<unsigned> UnsignedVec;
2367
2368 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
2369 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
2370 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
2371 Mapper.InstClassifier.EnableBranches = true;
2372 Mapper.initializeForBBs(*M);
2373 getVectors(*M, Mapper, InstrList, UnsignedVec);
2374
2375 // Check to make sure that we have a long enough region.
2376 ASSERT_EQ(InstrList.size(), static_cast<unsigned>(12));
2377 // Check that the instructions were added correctly to both vectors.
2378 ASSERT_TRUE(InstrList.size() == UnsignedVec.size());
2379
2380 ASSERT_TRUE(longSimCandCompare(InstrList, true, 3, 0, 6));
2381 }
2382
2383 // Checks that the same structure is recognized between two candidates, when
2384 // the branches target other blocks outside region, the relative distance
2385 // does not need to be the same.
2386 TEST(IRSimilarityCandidate, DifferentBranchStructureOutside) {
2387 StringRef ModuleString = R"(
2388 define i32 @f(i32 %a, i32 %b) {
2389 bb0:
2390 %0 = add i32 %a, %b
2391 %1 = add i32 %b, %a
2392 br label %bb1
2393 bb1:
2394 %2 = add i32 %b, %a
2395 %3 = add i32 %a, %b
2396 ret i32 0
2397 }
2398
2399 define i32 @f2(i32 %a, i32 %b) {
2400 bb0:
2401 %0 = add i32 %a, %b
2402 %1 = add i32 %b, %a
2403 br label %bb2
2404 bb1:
2405 %2 = add i32 %b, %a
2406 %3 = add i32 %a, %b
2407 br label %bb2
2408 bb2:
2409 %4 = add i32 %b, %a
2410 %5 = add i32 %a, %b
2411 ret i32 0
2412 })";
2413 LLVMContext Context;
2414 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
2415
2416 std::vector<IRInstructionData *> InstrList;
2417 std::vector<unsigned> UnsignedVec;
2418
2419 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
2420 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
2421 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
2422 Mapper.InstClassifier.EnableBranches = true;
2423 Mapper.initializeForBBs(*M);
2424 getVectors(*M, Mapper, InstrList, UnsignedVec);
2425
2426 // Check to make sure that we have a long enough region.
2427 ASSERT_EQ(InstrList.size(), static_cast<unsigned>(15));
2428 // Check that the instructions were added correctly to both vectors.
2429 ASSERT_TRUE(InstrList.size() == UnsignedVec.size());
2430
2431 ASSERT_TRUE(longSimCandCompare(InstrList, true, 3, 0, 6));
2432 }
2433
2434 // Checks that the same structure is recognized between two candidates,
2435 // when the phi predecessor are other blocks inside the same region,
2436 // the relative distance between the blocks must be the same.
2437 TEST(IRSimilarityCandidate, SamePHIStructureInternal) {
2438 StringRef ModuleString = R"(
2439 define i32 @f(i32 %a, i32 %b) {
2440 bb0:
2441 br label %bb2
2442 bb1:
2443 br label %bb2
2444 bb2:
2445 %0 = phi i32 [ %a, %bb0 ], [ %b, %bb1 ]
2446 %1 = add i32 %b, %a
2447 %2 = add i32 %a, %b
2448 ret i32 0
2449 }
2450
2451 define i32 @f2(i32 %a, i32 %b) {
2452 bb0:
2453 br label %bb2
2454 bb1:
2455 br label %bb2
2456 bb2:
2457 %0 = phi i32 [ %a, %bb0 ], [ %b, %bb1 ]
2458 %1 = add i32 %b, %a
2459 %2 = add i32 %a, %b
2460 ret i32 0
2461 })";
2462 LLVMContext Context;
2463 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
2464
2465 std::vector<IRInstructionData *> InstrList;
2466 std::vector<unsigned> UnsignedVec;
2467
2468 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
2469 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
2470 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
2471 Mapper.InstClassifier.EnableBranches = true;
2472 Mapper.initializeForBBs(*M);
2473 getVectors(*M, Mapper, InstrList, UnsignedVec);
2474
2475 // Check to make sure that we have a long enough region.
2476 ASSERT_EQ(InstrList.size(), static_cast<unsigned>(12));
2477 // Check that the instructions were added correctly to both vectors.
2478 ASSERT_TRUE(InstrList.size() == UnsignedVec.size());
2479
2480 ASSERT_TRUE(longSimCandCompare(InstrList, true, 4, 0, 6));
2481 }
2482
2483 // Checks that the different structure is recognized between two candidates,
2484 // when the phi predecessor are other blocks inside the same region,
2485 // the relative distance between the blocks must be the same.
2486 TEST(IRSimilarityCandidate, DifferentPHIStructureInternal) {
2487 StringRef ModuleString = R"(
2488 define i32 @f(i32 %a, i32 %b) {
2489 bb0:
2490 br label %bb2
2491 bb1:
2492 br label %bb2
2493 bb3:
2494 br label %bb2
2495 bb2:
2496 %0 = phi i32 [ %a, %bb0 ], [ %b, %bb1 ]
2497 %1 = add i32 %b, %a
2498 %2 = add i32 %a, %b
2499 ret i32 0
2500 }
2501
2502 define i32 @f2(i32 %a, i32 %b) {
2503 bb0:
2504 br label %bb2
2505 bb1:
2506 br label %bb2
2507 bb3:
2508 br label %bb2
2509 bb2:
2510 %0 = phi i32 [ %a, %bb0 ], [ %b, %bb3 ]
2511 %1 = add i32 %b, %a
2512 %2 = add i32 %a, %b
2513 ret i32 0
2514 })";
2515 LLVMContext Context;
2516 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
2517
2518 std::vector<IRInstructionData *> InstrList;
2519 std::vector<unsigned> UnsignedVec;
2520
2521 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
2522 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
2523 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
2524 Mapper.InstClassifier.EnableBranches = true;
2525 Mapper.initializeForBBs(*M);
2526 getVectors(*M, Mapper, InstrList, UnsignedVec);
2527
2528 // Check to make sure that we have a long enough region.
2529 ASSERT_EQ(InstrList.size(), static_cast<unsigned>(14));
2530 // Check that the instructions were added correctly to both vectors.
2531 ASSERT_TRUE(InstrList.size() == UnsignedVec.size());
2532
2533 ASSERT_FALSE(longSimCandCompare(InstrList, true, 5, 0, 7));
2020 } 2534 }
2021 2535
2022 // Checks that two sets of identical instructions are found to be the same. 2536 // Checks that two sets of identical instructions are found to be the same.
2023 // Both sequences of adds have the same operand ordering, and the same 2537 // Both sequences of adds have the same operand ordering, and the same
2024 // instructions, making them strcturally equivalent. 2538 // instructions, making them strcturally equivalent.
2103 InstIdx += 3; 2617 InstIdx += 3;
2104 } 2618 }
2105 } 2619 }
2106 } 2620 }
2107 2621
2622 // This test ensures that when the first instruction in a sequence is
2623 // a commutative instruction with the same value (mcomm_inst_same_val), but the
2624 // corresponding instruction (comm_inst_diff_val) is not, we mark the regions
2625 // and not similar.
2626 TEST(IRSimilarityIdentifier, CommutativeSameValueFirstMisMatch) {
2627 StringRef ModuleString = R"(
2628 define void @v_1_0(i64 %v_33) {
2629 entry:
2630 %comm_inst_same_val = mul i64 undef, undef
2631 %add = add i64 %comm_inst_same_val, %v_33
2632 %comm_inst_diff_val = mul i64 0, undef
2633 %mul.i = add i64 %comm_inst_diff_val, %comm_inst_diff_val
2634 unreachable
2635 })";
2636 LLVMContext Context;
2637 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
2638
2639 std::vector<std::vector<IRSimilarityCandidate>> SimilarityCandidates;
2640 getSimilarities(*M, SimilarityCandidates);
2641
2642 ASSERT_TRUE(SimilarityCandidates.size() == 0);
2643 }
2644
2645 // This test makes sure that intrinsic functions that are marked commutative
2646 // are still treated as non-commutative since they are function calls.
2647 TEST(IRSimilarityIdentifier, IntrinsicCommutative) {
2648 // If treated as commutative, we will fail to find a valid mapping, causing
2649 // an assertion error.
2650 StringRef ModuleString = R"(
2651 define void @foo() {
2652 entry:
2653 %0 = call i16 @llvm.smul.fix.i16(i16 16384, i16 16384, i32 15)
2654 store i16 %0, i16* undef, align 1
2655 %1 = icmp eq i16 undef, 8192
2656 call void @bar()
2657 %2 = call i16 @llvm.smul.fix.i16(i16 -16384, i16 16384, i32 15)
2658 store i16 %2, i16* undef, align 1
2659 %3 = icmp eq i16 undef, -8192
2660 call void @bar()
2661 %4 = call i16 @llvm.smul.fix.i16(i16 -16384, i16 -16384, i32 15)
2662 ret void
2663 }
2664
2665 declare void @bar()
2666
2667 ; Function Attrs: nofree nosync nounwind readnone speculatable willreturn
2668 declare i16 @llvm.smul.fix.i16(i16, i16, i32 immarg))";
2669 LLVMContext Context;
2670 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
2671
2672 std::vector<std::vector<IRSimilarityCandidate>> SimilarityCandidates;
2673 getSimilarities(*M, SimilarityCandidates);
2674
2675 ASSERT_TRUE(SimilarityCandidates.size() == 0);
2676 }
2677
2108 // This test checks to see whether we can detect different structure in 2678 // This test checks to see whether we can detect different structure in
2109 // commutative instructions. In this case, the second operand in the second 2679 // commutative instructions. In this case, the second operand in the second
2110 // add is different. 2680 // add is different.
2111 TEST(IRSimilarityIdentifier, NoCommutativeSimilarity) { 2681 TEST(IRSimilarityIdentifier, NoCommutativeSimilarity) {
2112 StringRef ModuleString = R"( 2682 StringRef ModuleString = R"(