Mercurial > hg > CbC > CbC_llvm
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"( |