Index: llvm/include/llvm/Analysis/IRSimilarityIdentifier.h =================================================================== --- llvm/include/llvm/Analysis/IRSimilarityIdentifier.h +++ llvm/include/llvm/Analysis/IRSimilarityIdentifier.h @@ -341,10 +341,6 @@ // analyzed for similarity as it has no bearing on the outcome of the // program. InstrType visitDbgInfoIntrinsic(DbgInfoIntrinsic &DII) { return Invisible; } - // TODO: Handle GetElementPtrInsts - InstrType visitGetElementPtrInst(GetElementPtrInst &GEPI) { - return Illegal; - } // TODO: Handle specific intrinsics. InstrType visitIntrinsicInst(IntrinsicInst &II) { return Illegal; } // TODO: Handle CallInsts. Index: llvm/lib/Analysis/IRSimilarityIdentifier.cpp =================================================================== --- llvm/lib/Analysis/IRSimilarityIdentifier.cpp +++ llvm/lib/Analysis/IRSimilarityIdentifier.cpp @@ -41,6 +41,33 @@ if (!A.Inst->isSameOperationAs(B.Inst)) return false; + // Since any GEP Instruction operands after the first operand cannot be + // defined by a register, we must make sure that the operands after the first + // are the same in the two instructions + if (GetElementPtrInst *GEP = dyn_cast(A.Inst)) { + GetElementPtrInst *OtherGEP = cast(B.Inst); + + // If the instructions do not have the same inbounds restrictions, we do + // not consider them the same. + if (GEP->isInBounds() != OtherGEP->isInBounds()) + return false; + + detail::zippy, + iterator_range> + ZippedOperands = zip(GEP->indices(), OtherGEP->indices()); + + detail::zippy, + iterator_range>::iterator ZIt = ZippedOperands.begin(); + + // We increment here since we do not care about the first instruction, + // we only care about the following operands since they must be the + // exact same to be considered similar. + return std::all_of(++ZIt, ZippedOperands.end(), + [](std::tuple R) { + return std::get<0>(R) == std::get<1>(R); + }); + } + return true; } Index: llvm/unittests/Analysis/IRSimilarityIdentifierTest.cpp =================================================================== --- llvm/unittests/Analysis/IRSimilarityIdentifierTest.cpp +++ llvm/unittests/Analysis/IRSimilarityIdentifierTest.cpp @@ -729,16 +729,17 @@ ASSERT_EQ(UnsignedVec.size(), static_cast(0)); } -// Checks that an getelementptr instruction is mapped to be illegal. There is -// extra checking required for the parameters if a getelementptr has more than -// two operands. -TEST(IRInstructionMapper, GetElementPtrIllegal) { +// Checks that an getelementptr instruction is mapped to be legal. And that +// the operands in getelementpointer instructions are the exact same after the +// first element operand, which only requires the same type. +TEST(IRInstructionMapper, GetElementPtrSameEndOperands) { StringRef ModuleString = R"( %struct.RT = type { i8, [10 x [20 x i32]], i8 } %struct.ST = type { i32, double, %struct.RT } - define i32 @f(%struct.ST* %s, i32 %a, i32 %b) { + define i32 @f(%struct.ST* %s, i64 %a, i64 %b) { bb0: - %0 = getelementptr inbounds %struct.ST, %struct.ST* %s, i64 1 + %0 = getelementptr inbounds %struct.ST, %struct.ST* %s, i64 %a, i32 0 + %1 = getelementptr inbounds %struct.ST, %struct.ST* %s, i64 %b, i32 0 ret i32 0 })"; LLVMContext Context; @@ -750,7 +751,84 @@ getVectors(*M, InstrList, UnsignedVec); ASSERT_EQ(InstrList.size(), UnsignedVec.size()); - ASSERT_EQ(UnsignedVec.size(), static_cast(0)); + ASSERT_EQ(UnsignedVec.size(), static_cast(3)); + ASSERT_EQ(UnsignedVec[0], UnsignedVec[1]); +} + +// Check that when the operands in getelementpointer instructions are not the +// exact same after the first element operand, the instructions are mapped to +// different values. +TEST(IRInstructionMapper, GetElementPtrDifferentEndOperands) { + StringRef ModuleString = R"( + %struct.RT = type { i8, [10 x [20 x i32]], i8 } + %struct.ST = type { i32, double, %struct.RT } + define i32 @f(%struct.ST* %s, i64 %a, i64 %b) { + bb0: + %0 = getelementptr inbounds %struct.ST, %struct.ST* %s, i64 %a, i32 0 + %1 = getelementptr inbounds %struct.ST, %struct.ST* %s, i64 %b, i32 2 + ret i32 0 + })"; + LLVMContext Context; + std::unique_ptr M = makeLLVMModule(Context, ModuleString); + + std::vector InstrList; + std::vector UnsignedVec; + + getVectors(*M, InstrList, UnsignedVec); + + ASSERT_EQ(InstrList.size(), UnsignedVec.size()); + ASSERT_EQ(UnsignedVec.size(), static_cast(3)); + ASSERT_NE(UnsignedVec[0], UnsignedVec[1]); +} + +// Check that when the operands in getelementpointer instructions are not the +// same initial base type, each instruction is mapped to a different value. +TEST(IRInstructionMapper, GetElementPtrDifferentBaseType) { + StringRef ModuleString = R"( + %struct.RT = type { i8, [10 x [20 x i32]], i8 } + %struct.ST = type { i32, double, %struct.RT } + define i32 @f(%struct.ST* %s, %struct.RT* %r, i64 %a, i64 %b) { + bb0: + %0 = getelementptr inbounds %struct.ST, %struct.ST* %s, i64 %a + %1 = getelementptr inbounds %struct.RT, %struct.RT* %r, i64 %b + ret i32 0 + })"; + LLVMContext Context; + std::unique_ptr M = makeLLVMModule(Context, ModuleString); + + std::vector InstrList; + std::vector UnsignedVec; + + getVectors(*M, InstrList, UnsignedVec); + + ASSERT_EQ(InstrList.size(), UnsignedVec.size()); + ASSERT_EQ(UnsignedVec.size(), static_cast(3)); + ASSERT_NE(UnsignedVec[0], UnsignedVec[1]); +} + +// Check that when the operands in getelementpointer instructions do not have +// the same inbounds modifier, they are not counted as the same. +TEST(IRInstructionMapper, GetElementPtrDifferentInBounds) { + StringRef ModuleString = R"( + %struct.RT = type { i8, [10 x [20 x i32]], i8 } + %struct.ST = type { i32, double, %struct.RT } + define i32 @f(%struct.ST* %s, %struct.RT* %r, i64 %a, i64 %b) { + bb0: + %0 = getelementptr inbounds %struct.ST, %struct.ST* %s, i64 %a, i32 0 + %1 = getelementptr %struct.ST, %struct.ST* %s, i64 %b, i32 0 + ret i32 0 + })"; + LLVMContext Context; + std::unique_ptr M = makeLLVMModule(Context, ModuleString); + + std::vector InstrList; + std::vector UnsignedVec; + + getVectors(*M, InstrList, UnsignedVec); + + ASSERT_EQ(InstrList.size(), UnsignedVec.size()); + ASSERT_EQ(UnsignedVec.size(), static_cast(3)); + ASSERT_NE(UnsignedVec[0], UnsignedVec[1]); } // Checks that a call instruction is mapped to be illegal. We have to perform