#include "llvm/Analysis/IRSimilarityIdentifier.h"
#include "llvm/AsmParser/Parser.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "llvm/Support/Allocator.h"
#include "llvm/Support/SourceMgr.h"
#include "gtest/gtest.h"
using namespace llvm;
using namespace IRSimilarity;
static std::unique_ptr<Module> makeLLVMModule(LLVMContext &Context,
StringRef ModuleStr) {
SMDiagnostic Err;
std::unique_ptr<Module> M = parseAssemblyString(ModuleStr, Err, Context);
assert(M && "Bad LLVM IR?");
return M;
}
void getVectors(Module &M, IRInstructionMapper &Mapper,
std::vector<IRInstructionData *> &InstrList,
std::vector<unsigned> &UnsignedVec) {
for (Function &F : M)
for (BasicBlock &BB : F)
Mapper.convertToUnsignedVec(BB, InstrList, UnsignedVec);
}
void getSimilarities(
Module &M,
std::vector<std::vector<IRSimilarityCandidate>> &SimilarityCandidates) {
IRSimilarityIdentifier Identifier(false);
SimilarityCandidates = Identifier.findSimilarity(M);
}
TEST(IRInstructionMapper, OpcodeDifferentiation) {
StringRef ModuleString = R"(
define i32 @f(i32 %a, i32 %b) {
bb0:
%0 = add i32 %a, %b
%1 = mul i32 %a, %b
ret i32 0
})";
LLVMContext Context;
std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
std::vector<IRInstructionData *> InstrList;
std::vector<unsigned> UnsignedVec;
SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
getVectors(*M, Mapper, InstrList, UnsignedVec);
ASSERT_TRUE(InstrList.size() == UnsignedVec.size());
ASSERT_TRUE(UnsignedVec.size() == 3);
ASSERT_TRUE(UnsignedVec[0] != UnsignedVec[1]);
}
TEST(IRInstructionMapper, OpcodeTypeSimilarity) {
StringRef ModuleString = R"(
define i32 @f(i32 %a, i32 %b) {
bb0:
%0 = add i32 %a, %b
%1 = add i32 %b, %a
ret i32 0
})";
LLVMContext Context;
std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
std::vector<IRInstructionData *> InstrList;
std::vector<unsigned> UnsignedVec;
SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
getVectors(*M, Mapper, InstrList, UnsignedVec);
ASSERT_TRUE(InstrList.size() == UnsignedVec.size());
ASSERT_TRUE(UnsignedVec.size() == 3);
ASSERT_TRUE(UnsignedVec[0] == UnsignedVec[1]);
}
TEST(IRInstructionMapper, TypeDifferentiation) {
StringRef ModuleString = R"(
define i32 @f(i32 %a, i32 %b, i64 %c, i64 %d) {
bb0:
%0 = add i32 %a, %b
%1 = add i64 %c, %d
ret i32 0
})";
LLVMContext Context;
std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
std::vector<IRInstructionData *> InstrList;
std::vector<unsigned> UnsignedVec;
SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
getVectors(*M, Mapper, InstrList, UnsignedVec);
ASSERT_TRUE(InstrList.size() == UnsignedVec.size());
ASSERT_TRUE(UnsignedVec.size() == 3);
ASSERT_TRUE(UnsignedVec[0] != UnsignedVec[1]);
}
TEST(IRInstructionMapper, PredicateDifferentiation) {
StringRef ModuleString = R"(
define i32 @f(i32 %a, i32 %b) {
bb0:
%0 = icmp sge i32 %b, %a
%1 = icmp slt i32 %a, %b
ret i32 0
})";
LLVMContext Context;
std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
std::vector<IRInstructionData *> InstrList;
std::vector<unsigned> UnsignedVec;
SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
getVectors(*M, Mapper, InstrList, UnsignedVec);
ASSERT_TRUE(InstrList.size() == UnsignedVec.size());
ASSERT_TRUE(UnsignedVec.size() == 3);
ASSERT_TRUE(UnsignedVec[0] != UnsignedVec[1]);
}
TEST(IRInstructionMapper, PredicateIsomorphism) {
StringRef ModuleString = R"(
define i32 @f(i32 %a, i32 %b) {
bb0:
%0 = icmp sgt i32 %a, %b
%1 = icmp slt i32 %b, %a
ret i32 0
})";
LLVMContext Context;
std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
std::vector<IRInstructionData *> InstrList;
std::vector<unsigned> UnsignedVec;
SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
getVectors(*M, Mapper, InstrList, UnsignedVec);
ASSERT_TRUE(InstrList.size() == UnsignedVec.size());
ASSERT_TRUE(UnsignedVec.size() == 3);
ASSERT_TRUE(UnsignedVec[0] == UnsignedVec[1]);
}
TEST(IRInstructionMapper, PredicateSimilarity) {
StringRef ModuleString = R"(
define i32 @f(i32 %a, i32 %b) {
bb0:
%0 = icmp slt i32 %a, %b
%1 = icmp slt i32 %b, %a
ret i32 0
})";
LLVMContext Context;
std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
std::vector<IRInstructionData *> InstrList;
std::vector<unsigned> UnsignedVec;
SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
getVectors(*M, Mapper, InstrList, UnsignedVec);
ASSERT_TRUE(InstrList.size() == UnsignedVec.size());
ASSERT_TRUE(UnsignedVec.size() == 3);
ASSERT_TRUE(UnsignedVec[0] == UnsignedVec[1]);
}
TEST(IRInstructionMapper, FPPredicateSimilarity) {
StringRef ModuleString = R"(
define i32 @f(double %a, double %b) {
bb0:
%0 = fcmp olt double %a, %b
%1 = fcmp olt double %b, %a
ret i32 0
})";
LLVMContext Context;
std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
std::vector<IRInstructionData *> InstrList;
std::vector<unsigned> UnsignedVec;
SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
getVectors(*M, Mapper, InstrList, UnsignedVec);
ASSERT_TRUE(InstrList.size() == UnsignedVec.size());
ASSERT_TRUE(UnsignedVec.size() == 3);
ASSERT_TRUE(UnsignedVec[0] == UnsignedVec[1]);
}
TEST(IRInstructionMapper, FPPredicatDifference) {
StringRef ModuleString = R"(
define i32 @f(double %a, double %b) {
bb0:
%0 = fcmp olt double %a, %b
%1 = fcmp oge double %b, %a
ret i32 0
})";
LLVMContext Context;
std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
std::vector<IRInstructionData *> InstrList;
std::vector<unsigned> UnsignedVec;
SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
getVectors(*M, Mapper, InstrList, UnsignedVec);
ASSERT_TRUE(InstrList.size() == UnsignedVec.size());
ASSERT_TRUE(UnsignedVec.size() == 3);
ASSERT_TRUE(UnsignedVec[0] != UnsignedVec[1]);
}
TEST(IRInstructionMapper, ZextTypeSimilarity) {
StringRef ModuleString = R"(
define i32 @f(i32 %a) {
bb0:
%0 = zext i32 %a to i64
%1 = zext i32 %a to i64
ret i32 0
})";
LLVMContext Context;
std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
std::vector<IRInstructionData *> InstrList;
std::vector<unsigned> UnsignedVec;
SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
getVectors(*M, Mapper, InstrList, UnsignedVec);
ASSERT_TRUE(InstrList.size() == UnsignedVec.size());
ASSERT_TRUE(UnsignedVec.size() == 3);
ASSERT_TRUE(UnsignedVec[0] == UnsignedVec[1]);
}
TEST(IRInstructionMapper, SextTypeSimilarity) {
StringRef ModuleString = R"(
define i32 @f(i32 %a) {
bb0:
%0 = sext i32 %a to i64
%1 = sext i32 %a to i64
ret i32 0
})";
LLVMContext Context;
std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
std::vector<IRInstructionData *> InstrList;
std::vector<unsigned> UnsignedVec;
SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
getVectors(*M, Mapper, InstrList, UnsignedVec);
ASSERT_TRUE(InstrList.size() == UnsignedVec.size());
ASSERT_TRUE(UnsignedVec.size() == 3);
ASSERT_TRUE(UnsignedVec[0] == UnsignedVec[1]);
}
TEST(IRInstructionMapper, ZextTypeDifference) {
StringRef ModuleString = R"(
define i32 @f(i32 %a, i8 %b) {
bb0:
%0 = zext i32 %a to i64
%1 = zext i8 %b to i32
ret i32 0
})";
LLVMContext Context;
std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
std::vector<IRInstructionData *> InstrList;
std::vector<unsigned> UnsignedVec;
SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
getVectors(*M, Mapper, InstrList, UnsignedVec);
ASSERT_TRUE(InstrList.size() == UnsignedVec.size());
ASSERT_TRUE(UnsignedVec.size() == 3);
ASSERT_TRUE(UnsignedVec[0] != UnsignedVec[1]);
}
TEST(IRInstructionMapper, SextTypeDifference) {
StringRef ModuleString = R"(
define i32 @f(i32 %a, i8 %b) {
bb0:
%0 = sext i32 %a to i64
%1 = sext i8 %b to i32
ret i32 0
})";
LLVMContext Context;
std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
std::vector<IRInstructionData *> InstrList;
std::vector<unsigned> UnsignedVec;
SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
getVectors(*M, Mapper, InstrList, UnsignedVec);
ASSERT_TRUE(InstrList.size() == UnsignedVec.size());
ASSERT_TRUE(UnsignedVec.size() == 3);
ASSERT_TRUE(UnsignedVec[0] != UnsignedVec[1]);
}
TEST(IRInstructionMapper, LoadSimilarType) {
StringRef ModuleString = R"(
define i32 @f(i32* %a, i32* %b) {
bb0:
%0 = load i32, i32* %a
%1 = load i32, i32* %b
ret i32 0
})";
LLVMContext Context;
std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
std::vector<IRInstructionData *> InstrList;
std::vector<unsigned> UnsignedVec;
SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
getVectors(*M, Mapper, InstrList, UnsignedVec);
ASSERT_TRUE(InstrList.size() == UnsignedVec.size());
ASSERT_TRUE(UnsignedVec.size() == 3);
ASSERT_TRUE(UnsignedVec[0] == UnsignedVec[1]);
}
TEST(IRInstructionMapper, LoadDifferentType) {
StringRef ModuleString = R"(
define i32 @f(i32* %a, i64* %b) {
bb0:
%0 = load i32, i32* %a
%1 = load i64, i64* %b
ret i32 0
})";
LLVMContext Context;
std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
std::vector<IRInstructionData *> InstrList;
std::vector<unsigned> UnsignedVec;
SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
getVectors(*M, Mapper, InstrList, UnsignedVec);
ASSERT_TRUE(InstrList.size() == UnsignedVec.size());
ASSERT_TRUE(UnsignedVec.size() == 3);
ASSERT_TRUE(UnsignedVec[0] != UnsignedVec[1]);
}
TEST(IRInstructionMapper, LoadDifferentAlign) {
StringRef ModuleString = R"(
define i32 @f(i32* %a, i32* %b) {
bb0:
%0 = load i32, i32* %a, align 4
%1 = load i32, i32* %b, align 8
ret i32 0
})";
LLVMContext Context;
std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
std::vector<IRInstructionData *> InstrList;
std::vector<unsigned> UnsignedVec;
SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
getVectors(*M, Mapper, InstrList, UnsignedVec);
ASSERT_TRUE(InstrList.size() == UnsignedVec.size());
ASSERT_TRUE(UnsignedVec.size() == 3);
ASSERT_TRUE(UnsignedVec[0] != UnsignedVec[1]);
}
TEST(IRInstructionMapper, LoadDifferentVolatile) {
StringRef ModuleString = R"(
define i32 @f(i32* %a, i32* %b) {
bb0:
%0 = load volatile i32, i32* %a
%1 = load i32, i32* %b
ret i32 0
})";
LLVMContext Context;
std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
std::vector<IRInstructionData *> InstrList;
std::vector<unsigned> UnsignedVec;
SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
getVectors(*M, Mapper, InstrList, UnsignedVec);
ASSERT_TRUE(InstrList.size() == UnsignedVec.size());
ASSERT_TRUE(UnsignedVec.size() == 3);
ASSERT_TRUE(UnsignedVec[0] != UnsignedVec[1]);
}
TEST(IRInstructionMapper, LoadSameVolatile) {
StringRef ModuleString = R"(
define i32 @f(i32* %a, i32* %b) {
bb0:
%0 = load volatile i32, i32* %a
%1 = load volatile i32, i32* %b
ret i32 0
})";
LLVMContext Context;
std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
std::vector<IRInstructionData *> InstrList;
std::vector<unsigned> UnsignedVec;
SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
getVectors(*M, Mapper, InstrList, UnsignedVec);
ASSERT_TRUE(InstrList.size() == UnsignedVec.size());
ASSERT_TRUE(UnsignedVec.size() == 3);
ASSERT_TRUE(UnsignedVec[0] == UnsignedVec[1]);
}
TEST(IRInstructionMapper, LoadDifferentAtomic) {
StringRef ModuleString = R"(
define i32 @f(i32* %a, i32* %b) {
bb0:
%0 = load atomic i32, i32* %a unordered, align 4
%1 = load atomic i32, i32* %b monotonic, align 4
ret i32 0
})";
LLVMContext Context;
std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
std::vector<IRInstructionData *> InstrList;
std::vector<unsigned> UnsignedVec;
SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
getVectors(*M, Mapper, InstrList, UnsignedVec);
ASSERT_TRUE(InstrList.size() == UnsignedVec.size());
ASSERT_TRUE(UnsignedVec.size() == 3);
ASSERT_TRUE(UnsignedVec[0] != UnsignedVec[1]);
}
TEST(IRInstructionMapper, LoadSameAtomic) {
StringRef ModuleString = R"(
define i32 @f(i32* %a, i32* %b) {
bb0:
%0 = load atomic i32, i32* %a unordered, align 4
%1 = load atomic i32, i32* %b unordered, align 4
ret i32 0
})";
LLVMContext Context;
std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
std::vector<IRInstructionData *> InstrList;
std::vector<unsigned> UnsignedVec;
SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
getVectors(*M, Mapper, InstrList, UnsignedVec);
ASSERT_TRUE(InstrList.size() == UnsignedVec.size());
ASSERT_TRUE(UnsignedVec.size() == 3);
ASSERT_TRUE(UnsignedVec[0] == UnsignedVec[1]);
}
TEST(IRInstructionMapper, StoreSimilarType) {
StringRef ModuleString = R"(
define i32 @f(i32* %a, i32* %b) {
bb0:
store i32 1, i32* %a
store i32 2, i32* %a
ret i32 0
})";
LLVMContext Context;
std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
std::vector<IRInstructionData *> InstrList;
std::vector<unsigned> UnsignedVec;
SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
getVectors(*M, Mapper, InstrList, UnsignedVec);
ASSERT_TRUE(InstrList.size() == UnsignedVec.size());
ASSERT_TRUE(UnsignedVec.size() == 3);
ASSERT_TRUE(UnsignedVec[0] == UnsignedVec[1]);
}
TEST(IRInstructionMapper, StoreDifferentType) {
StringRef ModuleString = R"(
define i32 @f(i32* %a, i64* %b) {
bb0:
store i32 1, i32* %a
store i64 1, i64* %b
ret i32 0
})";
LLVMContext Context;
std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
std::vector<IRInstructionData *> InstrList;
std::vector<unsigned> UnsignedVec;
SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
getVectors(*M, Mapper, InstrList, UnsignedVec);
ASSERT_TRUE(InstrList.size() == UnsignedVec.size());
ASSERT_TRUE(UnsignedVec.size() == 3);
ASSERT_TRUE(UnsignedVec[0] != UnsignedVec[1]);
}
TEST(IRInstructionMapper, StoreDifferentAlign) {
StringRef ModuleString = R"(
define i32 @f(i32* %a, i32* %b) {
bb0:
store i32 1, i32* %a, align 4
store i32 1, i32* %b, align 8
ret i32 0
})";
LLVMContext Context;
std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
std::vector<IRInstructionData *> InstrList;
std::vector<unsigned> UnsignedVec;
SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
getVectors(*M, Mapper, InstrList, UnsignedVec);
ASSERT_TRUE(InstrList.size() == UnsignedVec.size());
ASSERT_TRUE(UnsignedVec.size() == 3);
ASSERT_TRUE(UnsignedVec[0] != UnsignedVec[1]);
}
TEST(IRInstructionMapper, StoreDifferentVolatile) {
StringRef ModuleString = R"(
define i32 @f(i32* %a, i32* %b) {
bb0:
store volatile i32 1, i32* %a
store i32 1, i32* %b
ret i32 0
})";
LLVMContext Context;
std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
std::vector<IRInstructionData *> InstrList;
std::vector<unsigned> UnsignedVec;
SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
getVectors(*M, Mapper, InstrList, UnsignedVec);
ASSERT_TRUE(InstrList.size() == UnsignedVec.size());
ASSERT_TRUE(UnsignedVec.size() == 3);
ASSERT_TRUE(UnsignedVec[0] != UnsignedVec[1]);
}
TEST(IRInstructionMapper, StoreSameVolatile) {
StringRef ModuleString = R"(
define i32 @f(i32* %a, i32* %b) {
bb0:
store volatile i32 1, i32* %a
store volatile i32 1, i32* %b
ret i32 0
})";
LLVMContext Context;
std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
std::vector<IRInstructionData *> InstrList;
std::vector<unsigned> UnsignedVec;
SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
getVectors(*M, Mapper, InstrList, UnsignedVec);
ASSERT_TRUE(InstrList.size() == UnsignedVec.size());
ASSERT_TRUE(UnsignedVec.size() == 3);
ASSERT_TRUE(UnsignedVec[0] == UnsignedVec[1]);
}
TEST(IRInstructionMapper, StoreSameAtomic) {
StringRef ModuleString = R"(
define i32 @f(i32* %a, i32* %b) {
bb0:
store atomic i32 1, i32* %a unordered, align 4
store atomic i32 1, i32* %b unordered, align 4
ret i32 0
})";
LLVMContext Context;
std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
std::vector<IRInstructionData *> InstrList;
std::vector<unsigned> UnsignedVec;
SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
getVectors(*M, Mapper, InstrList, UnsignedVec);
ASSERT_TRUE(InstrList.size() == UnsignedVec.size());
ASSERT_TRUE(UnsignedVec.size() == 3);
ASSERT_TRUE(UnsignedVec[0] == UnsignedVec[1]);
}
TEST(IRInstructionMapper, StoreDifferentAtomic) {
StringRef ModuleString = R"(
define i32 @f(i32* %a, i32* %b) {
bb0:
store atomic i32 1, i32* %a unordered, align 4
store atomic i32 1, i32* %b monotonic, align 4
ret i32 0
})";
LLVMContext Context;
std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
std::vector<IRInstructionData *> InstrList;
std::vector<unsigned> UnsignedVec;
SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
getVectors(*M, Mapper, InstrList, UnsignedVec);
ASSERT_TRUE(InstrList.size() == UnsignedVec.size());
ASSERT_TRUE(UnsignedVec.size() == 3);
ASSERT_TRUE(UnsignedVec[0] != UnsignedVec[1]);
}
TEST(IRInstructionMapper, BranchLegal) {
StringRef ModuleString = R"(
define i32 @f(i32 %a, i32 %b) {
bb0:
%0 = icmp slt i32 %a, %b
br i1 %0, label %bb0, label %bb1
bb1:
ret i32 0
})";
LLVMContext Context;
std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
std::vector<IRInstructionData *> InstrList;
std::vector<unsigned> UnsignedVec;
SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
Mapper.InstClassifier.EnableBranches = true;
Mapper.initializeForBBs(*M);
getVectors(*M, Mapper, InstrList, UnsignedVec);
ASSERT_EQ(InstrList.size(), UnsignedVec.size());
ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(3));
ASSERT_TRUE(UnsignedVec[1] > UnsignedVec[0]);
ASSERT_TRUE(UnsignedVec[1] < UnsignedVec[2]);
}
TEST(IRInstructionMapper, PhiLegal) {
StringRef ModuleString = R"(
define i32 @f(i32 %a, i32 %b) {
bb0:
%0 = phi i1 [ 0, %bb0 ], [ %0, %bb1 ]
%1 = add i32 %a, %b
ret i32 0
bb1:
ret i32 1
})";
LLVMContext Context;
std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
std::vector<IRInstructionData *> InstrList;
std::vector<unsigned> UnsignedVec;
SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
Mapper.InstClassifier.EnableBranches = true;
Mapper.initializeForBBs(*M);
getVectors(*M, Mapper, InstrList, UnsignedVec);
ASSERT_EQ(InstrList.size(), UnsignedVec.size());
ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(3));
}
TEST(IRInstructionMapper, PhiIllegal) {
StringRef ModuleString = R"(
define i32 @f(i32 %a, i32 %b) {
bb0:
%0 = phi i1 [ 0, %bb0 ], [ %0, %bb1 ]
%1 = add i32 %a, %b
ret i32 0
bb1:
ret i32 1
})";
LLVMContext Context;
std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
std::vector<IRInstructionData *> InstrList;
std::vector<unsigned> UnsignedVec;
SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
Mapper.initializeForBBs(*M);
getVectors(*M, Mapper, InstrList, UnsignedVec);
ASSERT_EQ(InstrList.size(), UnsignedVec.size());
ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(3));
ASSERT_GT(UnsignedVec[0], Mapper.IllegalInstrNumber);
}
TEST(IRInstructionMapper, AllocaIllegal) {
StringRef ModuleString = R"(
define i32 @f(i32 %a, i32 %b) {
bb0:
%0 = alloca i32
ret i32 0
})";
LLVMContext Context;
std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
std::vector<IRInstructionData *> InstrList;
std::vector<unsigned> UnsignedVec;
SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
getVectors(*M, Mapper, InstrList, UnsignedVec);
ASSERT_EQ(InstrList.size(), UnsignedVec.size());
ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(1));
ASSERT_GT(UnsignedVec[0], Mapper.IllegalInstrNumber);
}
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, 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 0
ret i32 0
})";
LLVMContext Context;
std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
std::vector<IRInstructionData *> InstrList;
std::vector<unsigned> UnsignedVec;
SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
getVectors(*M, Mapper, InstrList, UnsignedVec);
ASSERT_EQ(InstrList.size(), UnsignedVec.size());
ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(3));
ASSERT_EQ(UnsignedVec[0], UnsignedVec[1]);
}
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<Module> M = makeLLVMModule(Context, ModuleString);
std::vector<IRInstructionData *> InstrList;
std::vector<unsigned> UnsignedVec;
SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
getVectors(*M, Mapper, InstrList, UnsignedVec);
ASSERT_EQ(InstrList.size(), UnsignedVec.size());
ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(3));
ASSERT_NE(UnsignedVec[0], UnsignedVec[1]);
}
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<Module> M = makeLLVMModule(Context, ModuleString);
std::vector<IRInstructionData *> InstrList;
std::vector<unsigned> UnsignedVec;
SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
getVectors(*M, Mapper, InstrList, UnsignedVec);
ASSERT_EQ(InstrList.size(), UnsignedVec.size());
ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(3));
ASSERT_NE(UnsignedVec[0], UnsignedVec[1]);
}
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<Module> M = makeLLVMModule(Context, ModuleString);
std::vector<IRInstructionData *> InstrList;
std::vector<unsigned> UnsignedVec;
SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
getVectors(*M, Mapper, InstrList, UnsignedVec);
ASSERT_EQ(InstrList.size(), UnsignedVec.size());
ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(3));
ASSERT_NE(UnsignedVec[0], UnsignedVec[1]);
}
TEST(IRInstructionMapper, CallsIllegalIndirect) {
StringRef ModuleString = R"(
define i32 @f(void()* %func) {
bb0:
call void %func()
ret i32 0
})";
LLVMContext Context;
std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
std::vector<IRInstructionData *> InstrList;
std::vector<unsigned> UnsignedVec;
SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
Mapper.InstClassifier.EnableIndirectCalls = false;
getVectors(*M, Mapper, InstrList, UnsignedVec);
ASSERT_EQ(InstrList.size(), UnsignedVec.size());
ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(1));
ASSERT_GT(UnsignedVec[0], Mapper.IllegalInstrNumber);
}
TEST(IRInstructionMapper, CallsLegalIndirect) {
StringRef ModuleString = R"(
define i32 @f(void()* %func) {
bb0:
call void %func()
call void %func()
ret i32 0
})";
LLVMContext Context;
std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
std::vector<IRInstructionData *> InstrList;
std::vector<unsigned> UnsignedVec;
SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
Mapper.InstClassifier.EnableIndirectCalls = true;
getVectors(*M, Mapper, InstrList, UnsignedVec);
ASSERT_EQ(InstrList.size(), UnsignedVec.size());
ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(3));
}
TEST(IRInstructionMapper, CallsSameTypeSameName) {
StringRef ModuleString = R"(
declare i32 @f1(i32, i32)
define i32 @f(i32 %a, i32 %b) {
bb0:
%0 = call i32 @f1(i32 %a, i32 %b)
%1 = call i32 @f1(i32 %a, i32 %b)
ret i32 0
})";
LLVMContext Context;
std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
std::vector<IRInstructionData *> InstrList;
std::vector<unsigned> UnsignedVec;
SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
getVectors(*M, Mapper, InstrList, UnsignedVec);
ASSERT_EQ(InstrList.size(), UnsignedVec.size());
ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(3));
ASSERT_EQ(UnsignedVec[0], UnsignedVec[1]);
}
TEST(IRInstructionMapper, CallsSameArgTypeDifferentNameDisallowed) {
StringRef ModuleString = R"(
declare i32 @f1(i32, i32)
declare i32 @f2(i32, i32)
define i32 @f(i32 %a, i32 %b) {
bb0:
%0 = call i32 @f1(i32 %a, i32 %b)
%1 = call i32 @f2(i32 %a, i32 %b)
ret i32 0
})";
LLVMContext Context;
std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
std::vector<IRInstructionData *> InstrList;
std::vector<unsigned> UnsignedVec;
SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
Mapper.EnableMatchCallsByName = true;
getVectors(*M, Mapper, InstrList, UnsignedVec);
ASSERT_EQ(InstrList.size(), UnsignedVec.size());
ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(3));
ASSERT_NE(UnsignedVec[0], UnsignedVec[1]);
}
TEST(IRInstructionMapper, CallsSameArgTypeDifferentName) {
StringRef ModuleString = R"(
declare i32 @f1(i32, i32)
declare i32 @f2(i32, i32)
define i32 @f(i32 %a, i32 %b) {
bb0:
%0 = call i32 @f1(i32 %a, i32 %b)
%1 = call i32 @f2(i32 %a, i32 %b)
ret i32 0
})";
LLVMContext Context;
std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
std::vector<IRInstructionData *> InstrList;
std::vector<unsigned> UnsignedVec;
SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
Mapper.EnableMatchCallsByName = false;
getVectors(*M, Mapper, InstrList, UnsignedVec);
ASSERT_EQ(InstrList.size(), UnsignedVec.size());
ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(3));
ASSERT_EQ(UnsignedVec[0], UnsignedVec[1]);
}
TEST(IRInstructionMapper, CallsDifferentArgTypeDifferentName) {
StringRef ModuleString = R"(
declare i32 @f1(i32, i32)
declare i32 @f2(i32)
define i32 @f(i32 %a, i32 %b) {
bb0:
%0 = call i32 @f1(i32 %a, i32 %b)
%1 = call i32 @f2(i32 %a)
ret i32 0
})";
LLVMContext Context;
std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
std::vector<IRInstructionData *> InstrList;
std::vector<unsigned> UnsignedVec;
SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
getVectors(*M, Mapper, InstrList, UnsignedVec);
ASSERT_EQ(InstrList.size(), UnsignedVec.size());
ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(3));
ASSERT_NE(UnsignedVec[0], UnsignedVec[1]);
}
TEST(IRInstructionMapper, CallsDifferentReturnTypeDifferentName) {
StringRef ModuleString = R"(
declare i64 @f1(i32, i32)
declare i32 @f2(i32, i32)
define i32 @f(i32 %a, i32 %b) {
bb0:
%0 = call i64 @f1(i32 %a, i32 %b)
%1 = call i32 @f2(i32 %a, i32 %b)
ret i32 0
})";
LLVMContext Context;
std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
std::vector<IRInstructionData *> InstrList;
std::vector<unsigned> UnsignedVec;
SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
getVectors(*M, Mapper, InstrList, UnsignedVec);
ASSERT_EQ(InstrList.size(), UnsignedVec.size());
ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(3));
ASSERT_NE(UnsignedVec[0], UnsignedVec[1]);
}
TEST(IRInstructionMapper, CallsSameParameters) {
StringRef ModuleString = R"(
declare i32 @f1(i32, i32)
define i32 @f(i32 %a, i32 %b) {
bb0:
%0 = tail call fastcc i32 @f1(i32 %a, i32 %b)
%1 = tail call fastcc i32 @f1(i32 %a, i32 %b)
ret i32 0
})";
LLVMContext Context;
std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
std::vector<IRInstructionData *> InstrList;
std::vector<unsigned> UnsignedVec;
SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
getVectors(*M, Mapper, InstrList, UnsignedVec);
ASSERT_EQ(InstrList.size(), UnsignedVec.size());
ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(3));
ASSERT_EQ(UnsignedVec[0], UnsignedVec[1]);
}
TEST(IRInstructionMapper, CallsDifferentTails) {
StringRef ModuleString = R"(
declare i32 @f1(i32, i32)
define i32 @f(i32 %a, i32 %b) {
bb0:
%0 = tail call i32 @f1(i32 %a, i32 %b)
%1 = call i32 @f1(i32 %a, i32 %b)
ret i32 0
})";
LLVMContext Context;
std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
std::vector<IRInstructionData *> InstrList;
std::vector<unsigned> UnsignedVec;
SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
getVectors(*M, Mapper, InstrList, UnsignedVec);
ASSERT_EQ(InstrList.size(), UnsignedVec.size());
ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(3));
ASSERT_NE(UnsignedVec[0], UnsignedVec[1]);
}
TEST(IRInstructionMapper, CallsDifferentCallingConventions) {
StringRef ModuleString = R"(
declare i32 @f1(i32, i32)
define i32 @f(i32 %a, i32 %b) {
bb0:
%0 = call fastcc i32 @f1(i32 %a, i32 %b)
%1 = call i32 @f1(i32 %a, i32 %b)
ret i32 0
})";
LLVMContext Context;
std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
std::vector<IRInstructionData *> InstrList;
std::vector<unsigned> UnsignedVec;
SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
getVectors(*M, Mapper, InstrList, UnsignedVec);
ASSERT_EQ(InstrList.size(), UnsignedVec.size());
ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(3));
ASSERT_NE(UnsignedVec[0], UnsignedVec[1]);
}
TEST(IRInstructionMapper, InvokeIllegal) {
StringRef ModuleString = R"(
define i32 @f(i8 *%gep1, i32 %b) {
then:
invoke i32 undef(i8* undef)
to label %invoke unwind label %lpad
invoke:
unreachable
lpad:
landingpad { i8*, i32 }
catch i8* null
unreachable
})";
LLVMContext Context;
std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
std::vector<IRInstructionData *> InstrList;
std::vector<unsigned> UnsignedVec;
SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
getVectors(*M, Mapper, InstrList, UnsignedVec);
ASSERT_EQ(InstrList.size(), UnsignedVec.size());
ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(1));
ASSERT_GT(UnsignedVec[0], Mapper.IllegalInstrNumber);
}
TEST(IRInstructionMapper, CallBrInstIllegal) {
StringRef ModuleString = R"(
define void @test() {
fail:
ret void
}
define i32 @f(i32 %a, i32 %b) {
bb0:
callbr void asm "xorl $0, $0; jmp ${1:l}", "r,X,~{dirflag},~{fpsr},~{flags}"(i32 %a, i8* blockaddress(@test, %fail)) to label %normal [label %fail]
fail:
ret i32 0
normal:
ret i32 0
})";
LLVMContext Context;
std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
std::vector<IRInstructionData *> InstrList;
std::vector<unsigned> UnsignedVec;
SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
getVectors(*M, Mapper, InstrList, UnsignedVec);
ASSERT_EQ(InstrList.size(), UnsignedVec.size());
ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(1));
ASSERT_GT(UnsignedVec[0], Mapper.IllegalInstrNumber);
}
TEST(IRInstructionMapper, DebugInfoInvisible) {
StringRef ModuleString = R"(
define i32 @f(i32 %a, i32 %b) {
then:
%0 = add i32 %a, %b
call void @llvm.dbg.value(metadata !0)
%1 = add i32 %a, %b
ret i32 0
}
declare void @llvm.dbg.value(metadata)
!0 = distinct !{!"test\00", i32 10})";
LLVMContext Context;
std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
std::vector<IRInstructionData *> InstrList;
std::vector<unsigned> UnsignedVec;
SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
getVectors(*M, Mapper, InstrList, UnsignedVec);
ASSERT_EQ(InstrList.size(), UnsignedVec.size());
ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(3));
}
TEST(IRInstructionMapper, ExceptionHandlingTypeIdIllegal) {
StringRef ModuleString = R"(
@_ZTIi = external constant i8*
define i32 @f() {
then:
%0 = call i32 @llvm.eh.typeid.for(i8* bitcast (i8** @_ZTIi to i8*))
ret i32 0
}
declare i32 @llvm.eh.typeid.for(i8*))";
LLVMContext Context;
std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
std::vector<IRInstructionData *> InstrList;
std::vector<unsigned> UnsignedVec;
SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
getVectors(*M, Mapper, InstrList, UnsignedVec);
ASSERT_EQ(InstrList.size(), UnsignedVec.size());
ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(1));
ASSERT_GT(UnsignedVec[0], Mapper.IllegalInstrNumber);
}
TEST(IRInstructionMapper, ExceptionHandlingExceptionCodeIllegal) {
StringRef ModuleString = R"(
define i32 @f(i32 %a, i32 %b) {
entry:
%0 = catchswitch within none [label %__except] unwind to caller
__except:
%1 = catchpad within %0 [i8* null]
catchret from %1 to label %__except
then:
%2 = call i32 @llvm.eh.exceptioncode(token %1)
ret i32 0
}
declare i32 @llvm.eh.exceptioncode(token))";
LLVMContext Context;
std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
std::vector<IRInstructionData *> InstrList;
std::vector<unsigned> UnsignedVec;
SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
getVectors(*M, Mapper, InstrList, UnsignedVec);
ASSERT_EQ(InstrList.size(), UnsignedVec.size());
ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(1));
ASSERT_GT(UnsignedVec[0], Mapper.IllegalInstrNumber);
}
TEST(IRInstructionMapper, ExceptionHandlingUnwindIllegal) {
StringRef ModuleString = R"(
define i32 @f(i32 %a, i32 %b) {
entry:
call void @llvm.eh.unwind.init()
ret i32 0
}
declare void @llvm.eh.unwind.init())";
LLVMContext Context;
std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
std::vector<IRInstructionData *> InstrList;
std::vector<unsigned> UnsignedVec;
SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
getVectors(*M, Mapper, InstrList, UnsignedVec);
ASSERT_EQ(InstrList.size(), UnsignedVec.size());
ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(1));
ASSERT_GT(UnsignedVec[0], Mapper.IllegalInstrNumber);
}
TEST(IRInstructionMapper, ExceptionHandlingExceptionPointerIllegal) {
StringRef ModuleString = R"(
define i32 @f(i32 %a, i32 %b) {
entry:
%0 = call i8* @llvm.eh.exceptionpointer.p0i8(i32 0)
ret i32 0
}
declare i8* @llvm.eh.exceptionpointer.p0i8(i32))";
LLVMContext Context;
std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
std::vector<IRInstructionData *> InstrList;
std::vector<unsigned> UnsignedVec;
SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
getVectors(*M, Mapper, InstrList, UnsignedVec);
ASSERT_EQ(InstrList.size(), UnsignedVec.size());
ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(1));
ASSERT_GT(UnsignedVec[0], Mapper.IllegalInstrNumber);
}
TEST(IRInstructionMapper, CatchpadIllegal) {
StringRef ModuleString = R"(
declare void @llvm.donothing() nounwind readnone
define void @function() personality i8 3 {
entry:
invoke void @llvm.donothing() to label %normal unwind label %exception
exception:
%cs1 = catchswitch within none [label %catchpad1] unwind to caller
catchpad1:
catchpad within %cs1 []
br label %normal
normal:
ret void
})";
LLVMContext Context;
std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
std::vector<IRInstructionData *> InstrList;
std::vector<unsigned> UnsignedVec;
SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
getVectors(*M, Mapper, InstrList, UnsignedVec);
ASSERT_EQ(InstrList.size(), UnsignedVec.size());
ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(1));
ASSERT_GT(UnsignedVec[0], Mapper.IllegalInstrNumber);
}
TEST(IRInstructionMapper, CleanuppadIllegal) {
StringRef ModuleString = R"(
declare void @llvm.donothing() nounwind readnone
define void @function() personality i8 3 {
entry:
invoke void @llvm.donothing() to label %normal unwind label %exception
exception:
%cs1 = catchswitch within none [label %catchpad1] unwind to caller
catchpad1:
%clean = cleanuppad within none []
br label %normal
normal:
ret void
})";
LLVMContext Context;
std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
std::vector<IRInstructionData *> InstrList;
std::vector<unsigned> UnsignedVec;
SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
getVectors(*M, Mapper, InstrList, UnsignedVec);
ASSERT_EQ(InstrList.size(), UnsignedVec.size());
ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(1));
ASSERT_GT(UnsignedVec[0], Mapper.IllegalInstrNumber);
}
TEST(IRInstructionMapper, MemSetIllegal) {
StringRef ModuleString = R"(
declare void @llvm.memset.p0i8.i64(i8* nocapture writeonly, i8, i64, i32, i1)
define i64 @function(i64 %x, i64 %z, i64 %n) {
entry:
%pool = alloca [59 x i64], align 4
%tmp = bitcast [59 x i64]* %pool to i8*
call void @llvm.memset.p0i8.i64(i8* nonnull %tmp, i8 0, i64 236, i32 4, i1 false)
%cmp3 = icmp eq i64 %n, 0
%a = add i64 %x, %z
%c = add i64 %x, %z
ret i64 0
})";
LLVMContext Context;
std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
std::vector<IRInstructionData *> InstrList;
std::vector<unsigned> UnsignedVec;
SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
Mapper.InstClassifier.EnableIntrinsics = false;
getVectors(*M, Mapper, InstrList, UnsignedVec);
ASSERT_EQ(InstrList.size(), UnsignedVec.size());
ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(7));
ASSERT_TRUE(UnsignedVec[2] < UnsignedVec[0]);
}
TEST(IRInstructionMapper, MemCpyIllegal) {
StringRef ModuleString = R"(
declare void @llvm.memcpy.p0i8.i64(i8* nocapture writeonly, i8, i64, i32, i1)
define i64 @function(i64 %x, i64 %z, i64 %n) {
entry:
%pool = alloca [59 x i64], align 4
%tmp = bitcast [59 x i64]* %pool to i8*
call void @llvm.memcpy.p0i8.i64(i8* nonnull %tmp, i8 0, i64 236, i32 4, i1 false)
%cmp3 = icmp eq i64 %n, 0
%a = add i64 %x, %z
%c = add i64 %x, %z
ret i64 0
})";
LLVMContext Context;
std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
std::vector<IRInstructionData *> InstrList;
std::vector<unsigned> UnsignedVec;
SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
Mapper.InstClassifier.EnableIntrinsics = false;
getVectors(*M, Mapper, InstrList, UnsignedVec);
ASSERT_EQ(InstrList.size(), UnsignedVec.size());
ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(7));
ASSERT_GT(UnsignedVec[2], UnsignedVec[3]);
ASSERT_LT(UnsignedVec[2], UnsignedVec[0]);
}
TEST(IRInstructionMapper, MemMoveIllegal) {
StringRef ModuleString = R"(
declare void @llvm.memmove.p0i8.i64(i8* nocapture writeonly, i8, i64, i32, i1)
define i64 @function(i64 %x, i64 %z, i64 %n) {
entry:
%pool = alloca [59 x i64], align 4
%tmp = bitcast [59 x i64]* %pool to i8*
call void @llvm.memmove.p0i8.i64(i8* nonnull %tmp, i8 0, i64 236, i32 4, i1 false)
%cmp3 = icmp eq i64 %n, 0
%a = add i64 %x, %z
%c = add i64 %x, %z
ret i64 0
})";
LLVMContext Context;
std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
std::vector<IRInstructionData *> InstrList;
std::vector<unsigned> UnsignedVec;
SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
Mapper.InstClassifier.EnableIntrinsics = false;
getVectors(*M, Mapper, InstrList, UnsignedVec);
ASSERT_EQ(InstrList.size(), UnsignedVec.size());
ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(7));
ASSERT_LT(UnsignedVec[2], UnsignedVec[0]);
}
TEST(IRInstructionMapper, MemOpsLegal) {
StringRef ModuleString = R"(
declare void @llvm.memmove.p0i8.i64(i8* nocapture writeonly, i8, i64, i32, i1)
declare void @llvm.memcpy.p0i8.i64(i8* nocapture writeonly, i8, i64, i32, i1)
declare void @llvm.memset.p0i8.i64(i8* nocapture writeonly, i8, i64, i32, i1)
define i64 @function(i64 %x, i64 %z, i64 %n) {
entry:
%pool = alloca [59 x i64], align 4
%tmp = bitcast [59 x i64]* %pool to i8*
call void @llvm.memmove.p0i8.i64(i8* nonnull %tmp, i8 0, i64 236, i32 4, i1 false)
call void @llvm.memcpy.p0i8.i64(i8* nonnull %tmp, i8 0, i64 236, i32 4, i1 false)
call void @llvm.memset.p0i8.i64(i8* nonnull %tmp, i8 0, i64 236, i32 4, i1 false)
%cmp3 = icmp eq i64 %n, 0
%a = add i64 %x, %z
%c = add i64 %x, %z
ret i64 0
})";
LLVMContext Context;
std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
std::vector<IRInstructionData *> InstrList;
std::vector<unsigned> UnsignedVec;
SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
Mapper.InstClassifier.EnableIntrinsics = true;
getVectors(*M, Mapper, InstrList, UnsignedVec);
ASSERT_EQ(InstrList.size(), UnsignedVec.size());
ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(9));
ASSERT_LT(UnsignedVec[2], UnsignedVec[3]);
ASSERT_LT(UnsignedVec[3], UnsignedVec[4]);
ASSERT_LT(UnsignedVec[4], UnsignedVec[5]);
}
TEST(IRInstructionMapper, VarArgsIllegal) {
StringRef ModuleString = R"(
declare void @llvm.va_start(i8*)
declare void @llvm.va_copy(i8*, i8*)
declare void @llvm.va_end(i8*)
define i32 @func1(i32 %a, double %b, i8* %v, ...) nounwind {
entry:
%a.addr = alloca i32, align 4
%b.addr = alloca double, align 8
%ap = alloca i8*, align 4
%c = alloca i32, align 4
store i32 %a, i32* %a.addr, align 4
store double %b, double* %b.addr, align 8
%ap1 = bitcast i8** %ap to i8*
call void @llvm.va_start(i8* %ap1)
store double %b, double* %b.addr, align 8
store double %b, double* %b.addr, align 8
%0 = va_arg i8** %ap, i32
store double %b, double* %b.addr, align 8
store double %b, double* %b.addr, align 8
call void @llvm.va_copy(i8* %v, i8* %ap1)
store double %b, double* %b.addr, align 8
store double %b, double* %b.addr, align 8
call void @llvm.va_end(i8* %ap1)
store i32 %0, i32* %c, align 4
%tmp = load i32, i32* %c, align 4
ret i32 %tmp
})";
LLVMContext Context;
std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
std::vector<IRInstructionData *> InstrList;
std::vector<unsigned> UnsignedVec;
SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
Mapper.InstClassifier.EnableIntrinsics = false;
getVectors(*M, Mapper, InstrList, UnsignedVec);
ASSERT_EQ(InstrList.size(), UnsignedVec.size());
ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(17));
ASSERT_TRUE(UnsignedVec[7] < UnsignedVec[0]);
ASSERT_TRUE(UnsignedVec[13] < UnsignedVec[10]);
ASSERT_TRUE(UnsignedVec[16] < UnsignedVec[13]);
}
TEST(IRInstructionMapper, RepeatedIllegalLength) {
StringRef ModuleString = R"(
define i32 @f(i32 %a, i32 %b) {
bb0:
%0 = add i32 %a, %b
%1 = mul i32 %a, %b
%2 = alloca i32
%3 = alloca i32
%4 = add i32 %a, %b
%5 = mul i32 %a, %b
ret i32 0
})";
LLVMContext Context;
std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
std::vector<IRInstructionData *> InstrList;
std::vector<unsigned> UnsignedVec;
SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
getVectors(*M, Mapper, InstrList, UnsignedVec);
ASSERT_TRUE(InstrList.size() == UnsignedVec.size());
ASSERT_TRUE(UnsignedVec.size() == 6);
}
static bool longSimCandCompare(std::vector<IRInstructionData *> &InstrList,
bool Structure = false, unsigned Length = 2,
unsigned StartIdxOne = 0,
unsigned StartIdxTwo = 3) {
std::vector<IRInstructionData *>::iterator Start, End;
Start = InstrList.begin();
End = InstrList.begin();
std::advance(End, StartIdxOne + Length - 1);
IRSimilarityCandidate Cand1(StartIdxOne, Length, *Start, *End);
Start = InstrList.begin();
End = InstrList.begin();
std::advance(Start, StartIdxTwo);
std::advance(End, StartIdxTwo + Length - 1);
IRSimilarityCandidate Cand2(StartIdxTwo, Length, *Start, *End);
if (Structure)
return IRSimilarityCandidate::compareStructure(Cand1, Cand2);
return IRSimilarityCandidate::isSimilar(Cand1, Cand2);
}
TEST(IRSimilarityCandidate, CheckIdenticalInstructions) {
StringRef ModuleString = R"(
define i32 @f(i32 %a, i32 %b) {
bb0:
%0 = add i32 %a, %b
%1 = add i32 %b, %a
ret i32 0
})";
LLVMContext Context;
std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
std::vector<IRInstructionData *> InstrList;
std::vector<unsigned> UnsignedVec;
SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
getVectors(*M, Mapper, InstrList, UnsignedVec);
ASSERT_EQ(InstrList.size(), static_cast<unsigned>(3));
ASSERT_TRUE(InstrList.size() == UnsignedVec.size());
std::vector<IRInstructionData *>::iterator Start, End;
Start = InstrList.begin();
End = InstrList.begin();
std::advance(End, 1);
IRSimilarityCandidate Cand1(0, 2, *Start, *End);
IRSimilarityCandidate Cand2(0, 2, *Start, *End);
ASSERT_TRUE(IRSimilarityCandidate::isSimilar(Cand1, Cand2));
}
TEST(IRSimilarityCandidate, PredicateIsomorphism) {
StringRef ModuleString = R"(
define i32 @f(i32 %a, i32 %b) {
bb0:
%0 = icmp sgt i32 %a, %b
%1 = add i32 %b, %a
br label %bb1
bb1:
%2 = icmp slt i32 %a, %b
%3 = add i32 %a, %b
ret i32 0
})";
LLVMContext Context;
std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
std::vector<IRInstructionData *> InstrList;
std::vector<unsigned> UnsignedVec;
SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
getVectors(*M, Mapper, InstrList, UnsignedVec);
ASSERT_TRUE(InstrList.size() > 5);
ASSERT_TRUE(InstrList.size() == UnsignedVec.size());
std::vector<IRInstructionData *>::iterator Start, End;
Start = InstrList.begin();
End = InstrList.begin();
std::advance(End, 1);
IRSimilarityCandidate Cand1(0, 2, *Start, *End);
Start = InstrList.begin();
End = InstrList.begin();
std::advance(Start, 3);
std::advance(End, 4);
IRSimilarityCandidate Cand2(3, 2, *Start, *End);
ASSERT_TRUE(IRSimilarityCandidate::isSimilar(Cand1, Cand2));
}
TEST(IRSimilarityCandidate, CheckRegionsDifferentInstruction) {
StringRef ModuleString = R"(
define i32 @f(i32 %a, i32 %b) {
bb0:
%0 = add i32 %a, %b
%1 = add i32 %b, %a
ret i32 0
bb1:
%2 = sub i32 %a, %b
%3 = add i32 %b, %a
ret i32 0
})";
LLVMContext Context;
std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
std::vector<IRInstructionData *> InstrList;
std::vector<unsigned> UnsignedVec;
SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
getVectors(*M, Mapper, InstrList, UnsignedVec);
ASSERT_EQ(InstrList.size(), static_cast<unsigned>(6));
ASSERT_TRUE(InstrList.size() == UnsignedVec.size());
ASSERT_FALSE(longSimCandCompare(InstrList));
}
TEST(IRSimilarityCandidate, CheckRegionsDifferentTypes) {
StringRef ModuleString = R"(
define i32 @f(i32 %a, i32 %b, i64 %c, i64 %d) {
bb0:
%0 = add i32 %a, %b
%1 = add i32 %b, %a
ret i32 0
bb1:
%2 = add i64 %c, %d
%3 = add i64 %d, %c
ret i32 0
})";
LLVMContext Context;
std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
std::vector<IRInstructionData *> InstrList;
std::vector<unsigned> UnsignedVec;
SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
getVectors(*M, Mapper, InstrList, UnsignedVec);
ASSERT_EQ(InstrList.size(), static_cast<unsigned>(6));
ASSERT_TRUE(InstrList.size() == UnsignedVec.size());
ASSERT_FALSE(longSimCandCompare(InstrList));
}
TEST(IRSimilarityCandidate, IdenticalWithDebug) {
StringRef ModuleString = R"(
define i32 @f(i32 %a, i32 %b) {
bb0:
%0 = add i32 %a, %b
call void @llvm.dbg.value(metadata !0)
%1 = add i32 %b, %a
ret i32 0
bb1:
%2 = add i32 %a, %b
call void @llvm.dbg.value(metadata !1)
%3 = add i32 %b, %a
ret i32 0
bb2:
%4 = add i32 %a, %b
%5 = add i32 %b, %a
ret i32 0
}
declare void @llvm.dbg.value(metadata)
!0 = distinct !{!"test\00", i32 10}
!1 = distinct !{!"test\00", i32 11})";
LLVMContext Context;
std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
std::vector<IRInstructionData *> InstrList;
std::vector<unsigned> UnsignedVec;
SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
getVectors(*M, Mapper, InstrList, UnsignedVec);
ASSERT_EQ(InstrList.size(), static_cast<unsigned>(9));
ASSERT_TRUE(InstrList.size() == UnsignedVec.size());
ASSERT_TRUE(longSimCandCompare(InstrList));
}
TEST(IRSimilarityCandidate, IllegalInCandidate) {
StringRef ModuleString = R"(
define i32 @f(i32 %a, i32 %b) {
bb0:
%0 = add i32 %a, %b
%1 = add i32 %a, %b
%2 = alloca i32
ret i32 0
bb1:
%3 = add i32 %a, %b
%4 = add i32 %a, %b
%5 = alloca i32
ret i32 0
})";
LLVMContext Context;
std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
std::vector<IRInstructionData *> InstrList;
std::vector<unsigned> UnsignedVec;
SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
getVectors(*M, Mapper, InstrList, UnsignedVec);
ASSERT_EQ(InstrList.size(), static_cast<unsigned>(6));
ASSERT_TRUE(InstrList.size() == UnsignedVec.size());
std::vector<IRInstructionData *>::iterator Start, End;
Start = InstrList.begin();
End = InstrList.begin();
std::advance(End, 2);
IRSimilarityCandidate Cand1(0, 3, *Start, *End);
Start = InstrList.begin();
End = InstrList.begin();
std::advance(Start, 3);
std::advance(End, 5);
IRSimilarityCandidate Cand2(3, 3, *Start, *End);
ASSERT_FALSE(IRSimilarityCandidate::isSimilar(Cand1, Cand2));
}
TEST(IRSimilarityCandidate, DifferentStructure) {
StringRef ModuleString = R"(
define i32 @f(i32 %a, i32 %b) {
bb0:
%0 = add i32 %a, %b
%1 = add i32 %b, %a
ret i32 0
bb1:
%2 = add i32 %a, %b
%3 = add i32 %b, %0
ret i32 0
})";
LLVMContext Context;
std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
std::vector<IRInstructionData *> InstrList;
std::vector<unsigned> UnsignedVec;
SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
getVectors(*M, Mapper, InstrList, UnsignedVec);
ASSERT_EQ(InstrList.size(), static_cast<unsigned>(6));
ASSERT_TRUE(InstrList.size() == UnsignedVec.size());
ASSERT_FALSE(longSimCandCompare(InstrList, true));
}
TEST(IRSimilarityCandidate, PredicateIsomorphismStructure) {
StringRef ModuleString = R"(
define i32 @f(i32 %a, i32 %b) {
bb0:
%0 = icmp sgt i32 %a, %b
%1 = add i32 %a, %b
br label %bb1
bb1:
%2 = icmp slt i32 %b, %a
%3 = add i32 %a, %b
ret i32 0
})";
LLVMContext Context;
std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
std::vector<IRInstructionData *> InstrList;
std::vector<unsigned> UnsignedVec;
SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
getVectors(*M, Mapper, InstrList, UnsignedVec);
ASSERT_TRUE(InstrList.size() > 5);
ASSERT_TRUE(InstrList.size() == UnsignedVec.size());
ASSERT_TRUE(longSimCandCompare(InstrList, true));
}
TEST(IRSimilarityCandidate, PredicateDifference) {
StringRef ModuleString = R"(
define i32 @f(i32 %a, i32 %b) {
bb0:
%0 = icmp sge i32 %a, %b
%1 = add i32 %b, %a
br label %bb1
bb1:
%2 = icmp slt i32 %b, %a
%3 = add i32 %a, %b
ret i32 0
})";
LLVMContext Context;
std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
std::vector<IRInstructionData *> InstrList;
std::vector<unsigned> UnsignedVec;
SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
getVectors(*M, Mapper, InstrList, UnsignedVec);
ASSERT_TRUE(InstrList.size() > 5);
ASSERT_TRUE(InstrList.size() == UnsignedVec.size());
ASSERT_FALSE(longSimCandCompare(InstrList));
}
TEST(IRSimilarityCandidate, SameStructure) {
StringRef ModuleString = R"(
define i32 @f(i32 %a, i32 %b) {
bb0:
%0 = add i32 %a, %b
%1 = sub i32 %b, %a
ret i32 0
bb1:
%2 = add i32 %a, %b
%3 = sub i32 %b, %a
ret i32 0
})";
LLVMContext Context;
std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
std::vector<IRInstructionData *> InstrList;
std::vector<unsigned> UnsignedVec;
SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
getVectors(*M, Mapper, InstrList, UnsignedVec);
ASSERT_EQ(InstrList.size(), static_cast<unsigned>(6));
ASSERT_TRUE(InstrList.size() == UnsignedVec.size());
ASSERT_TRUE(longSimCandCompare(InstrList, true));
}
TEST(IRSimilarityCandidate, CanonicalNumbering) {
StringRef ModuleString = R"(
define i32 @f(i32 %a, i32 %b) {
bb0:
%0 = add i32 %a, %b
%1 = sub i32 %b, %a
ret i32 0
bb1:
%2 = add i32 %a, %b
%3 = sub i32 %b, %a
ret i32 0
})";
LLVMContext Context;
std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
std::vector<IRInstructionData *> InstrList;
std::vector<unsigned> UnsignedVec;
SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
getVectors(*M, Mapper, InstrList, UnsignedVec);
ASSERT_EQ(InstrList.size(), static_cast<unsigned>(6));
ASSERT_EQ(InstrList.size(), UnsignedVec.size());
std::vector<IRInstructionData *>::iterator Start, End;
Start = InstrList.begin();
End = InstrList.begin();
std::advance(End, 1);
IRSimilarityCandidate Cand1(0, 2, *Start, *End);
Start = InstrList.begin();
End = InstrList.begin();
std::advance(Start, 3);
std::advance(End, 4);
IRSimilarityCandidate Cand2(3, 2, *Start, *End);
DenseMap<unsigned, DenseSet<unsigned>> Mapping1;
DenseMap<unsigned, DenseSet<unsigned>> Mapping2;
ASSERT_TRUE(IRSimilarityCandidate::compareStructure(Cand1, Cand2, Mapping1,
Mapping2));
IRSimilarityCandidate::createCanonicalMappingFor(Cand1);
Cand2.createCanonicalRelationFrom(Cand1, Mapping1, Mapping2);
for (std::pair<unsigned, DenseSet<unsigned>> &P : Mapping2) {
unsigned Source = P.first;
ASSERT_TRUE(Cand2.getCanonicalNum(Source).has_value());
unsigned Canon = *Cand2.getCanonicalNum(Source);
ASSERT_TRUE(Cand1.fromCanonicalNum(Canon).has_value());
unsigned Dest = *Cand1.fromCanonicalNum(Canon);
DenseSet<unsigned>::iterator It = P.second.find(Dest);
ASSERT_NE(It, P.second.end());
}
}
TEST(IRSimilarityCandidate, DifferentNameSameStructure) {
StringRef ModuleString = R"(
define i32 @f(i32 %a, i32 %b) {
bb0:
%0 = add i32 %a, %b
%1 = add i32 %b, %a
ret i32 0
bb1:
%2 = add i32 %b, %a
%3 = add i32 %a, %b
ret i32 0
})";
LLVMContext Context;
std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
std::vector<IRInstructionData *> InstrList;
std::vector<unsigned> UnsignedVec;
SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
getVectors(*M, Mapper, InstrList, UnsignedVec);
ASSERT_EQ(InstrList.size(), static_cast<unsigned>(6));
ASSERT_TRUE(InstrList.size() == UnsignedVec.size());
ASSERT_TRUE(longSimCandCompare(InstrList, true));
}
TEST(IRSimilarityCandidate, SameBranchStructureInternal) {
StringRef ModuleString = R"(
define i32 @f(i32 %a, i32 %b) {
bb0:
%0 = add i32 %a, %b
%1 = add i32 %b, %a
br label %bb1
bb1:
%2 = add i32 %b, %a
%3 = add i32 %a, %b
ret i32 0
}
define i32 @f2(i32 %a, i32 %b) {
bb0:
%0 = add i32 %a, %b
%1 = add i32 %b, %a
br label %bb1
bb1:
%2 = add i32 %b, %a
%3 = add i32 %a, %b
ret i32 0
})";
LLVMContext Context;
std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
std::vector<IRInstructionData *> InstrList;
std::vector<unsigned> UnsignedVec;
SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
Mapper.InstClassifier.EnableBranches = true;
Mapper.initializeForBBs(*M);
getVectors(*M, Mapper, InstrList, UnsignedVec);
ASSERT_EQ(InstrList.size(), static_cast<unsigned>(12));
ASSERT_TRUE(InstrList.size() == UnsignedVec.size());
ASSERT_TRUE(longSimCandCompare(InstrList, true, 5, 0, 6));
}
TEST(IRSimilarityCandidate, DifferentBranchStructureInternal) {
StringRef ModuleString = R"(
define i32 @f(i32 %a, i32 %b) {
bb0:
%0 = add i32 %a, %b
%1 = add i32 %b, %a
br label %bb2
bb1:
%2 = add i32 %b, %a
%3 = add i32 %a, %b
br label %bb2
bb2:
%4 = add i32 %b, %a
%5 = add i32 %a, %b
ret i32 0
}
define i32 @f2(i32 %a, i32 %b) {
bb0:
%0 = add i32 %a, %b
%1 = add i32 %b, %a
br label %bb1
bb1:
%2 = add i32 %b, %a
%3 = add i32 %a, %b
br label %bb2
bb2:
%4 = add i32 %b, %a
%5 = add i32 %a, %b
ret i32 0
})";
LLVMContext Context;
std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
std::vector<IRInstructionData *> InstrList;
std::vector<unsigned> UnsignedVec;
SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
Mapper.InstClassifier.EnableBranches = true;
Mapper.initializeForBBs(*M);
getVectors(*M, Mapper, InstrList, UnsignedVec);
ASSERT_EQ(InstrList.size(), static_cast<unsigned>(18));
ASSERT_TRUE(InstrList.size() == UnsignedVec.size());
ASSERT_FALSE(longSimCandCompare(InstrList, true, 6, 0, 9));
}
TEST(IRSimilarityCandidate, SameBranchStructureOutside) {
StringRef ModuleString = R"(
define i32 @f(i32 %a, i32 %b) {
bb0:
%0 = add i32 %a, %b
%1 = add i32 %b, %a
br label %bb1
bb1:
%2 = add i32 %b, %a
%3 = add i32 %a, %b
ret i32 0
}
define i32 @f2(i32 %a, i32 %b) {
bb0:
%0 = add i32 %a, %b
%1 = add i32 %b, %a
br label %bb1
bb1:
%2 = add i32 %b, %a
%3 = add i32 %a, %b
ret i32 0
})";
LLVMContext Context;
std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
std::vector<IRInstructionData *> InstrList;
std::vector<unsigned> UnsignedVec;
SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
Mapper.InstClassifier.EnableBranches = true;
Mapper.initializeForBBs(*M);
getVectors(*M, Mapper, InstrList, UnsignedVec);
ASSERT_EQ(InstrList.size(), static_cast<unsigned>(12));
ASSERT_TRUE(InstrList.size() == UnsignedVec.size());
ASSERT_TRUE(longSimCandCompare(InstrList, true, 3, 0, 6));
}
TEST(IRSimilarityCandidate, DifferentBranchStructureOutside) {
StringRef ModuleString = R"(
define i32 @f(i32 %a, i32 %b) {
bb0:
%0 = add i32 %a, %b
%1 = add i32 %b, %a
br label %bb1
bb1:
%2 = add i32 %b, %a
%3 = add i32 %a, %b
ret i32 0
}
define i32 @f2(i32 %a, i32 %b) {
bb0:
%0 = add i32 %a, %b
%1 = add i32 %b, %a
br label %bb2
bb1:
%2 = add i32 %b, %a
%3 = add i32 %a, %b
br label %bb2
bb2:
%4 = add i32 %b, %a
%5 = add i32 %a, %b
ret i32 0
})";
LLVMContext Context;
std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
std::vector<IRInstructionData *> InstrList;
std::vector<unsigned> UnsignedVec;
SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
Mapper.InstClassifier.EnableBranches = true;
Mapper.initializeForBBs(*M);
getVectors(*M, Mapper, InstrList, UnsignedVec);
ASSERT_EQ(InstrList.size(), static_cast<unsigned>(15));
ASSERT_TRUE(InstrList.size() == UnsignedVec.size());
ASSERT_TRUE(longSimCandCompare(InstrList, true, 3, 0, 6));
}
TEST(IRSimilarityCandidate, SamePHIStructureInternal) {
StringRef ModuleString = R"(
define i32 @f(i32 %a, i32 %b) {
bb0:
br label %bb2
bb1:
br label %bb2
bb2:
%0 = phi i32 [ %a, %bb0 ], [ %b, %bb1 ]
%1 = add i32 %b, %a
%2 = add i32 %a, %b
ret i32 0
}
define i32 @f2(i32 %a, i32 %b) {
bb0:
br label %bb2
bb1:
br label %bb2
bb2:
%0 = phi i32 [ %a, %bb0 ], [ %b, %bb1 ]
%1 = add i32 %b, %a
%2 = add i32 %a, %b
ret i32 0
})";
LLVMContext Context;
std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
std::vector<IRInstructionData *> InstrList;
std::vector<unsigned> UnsignedVec;
SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
Mapper.InstClassifier.EnableBranches = true;
Mapper.initializeForBBs(*M);
getVectors(*M, Mapper, InstrList, UnsignedVec);
ASSERT_EQ(InstrList.size(), static_cast<unsigned>(12));
ASSERT_TRUE(InstrList.size() == UnsignedVec.size());
ASSERT_TRUE(longSimCandCompare(InstrList, true, 4, 0, 6));
}
TEST(IRSimilarityCandidate, DifferentPHIStructureInternal) {
StringRef ModuleString = R"(
define i32 @f(i32 %a, i32 %b) {
bb0:
br label %bb2
bb1:
br label %bb2
bb3:
br label %bb2
bb2:
%0 = phi i32 [ %a, %bb0 ], [ %b, %bb1 ]
%1 = add i32 %b, %a
%2 = add i32 %a, %b
ret i32 0
}
define i32 @f2(i32 %a, i32 %b) {
bb0:
br label %bb2
bb1:
br label %bb2
bb3:
br label %bb2
bb2:
%0 = phi i32 [ %a, %bb0 ], [ %b, %bb3 ]
%1 = add i32 %b, %a
%2 = add i32 %a, %b
ret i32 0
})";
LLVMContext Context;
std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
std::vector<IRInstructionData *> InstrList;
std::vector<unsigned> UnsignedVec;
SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
Mapper.InstClassifier.EnableBranches = true;
Mapper.initializeForBBs(*M);
getVectors(*M, Mapper, InstrList, UnsignedVec);
ASSERT_EQ(InstrList.size(), static_cast<unsigned>(14));
ASSERT_TRUE(InstrList.size() == UnsignedVec.size());
ASSERT_FALSE(longSimCandCompare(InstrList, true, 5, 0, 7));
}
TEST(IRSimilarityIdentifier, IdentitySimilarity) {
StringRef ModuleString = R"(
define i32 @f(i32 %a, i32 %b) {
bb0:
%0 = add i32 %a, %b
%1 = sub i32 %b, %a
br label %bb1
bb1:
%2 = add i32 %a, %b
%3 = sub i32 %b, %a
ret i32 0
})";
LLVMContext Context;
std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
std::vector<std::vector<IRSimilarityCandidate>> SimilarityCandidates;
getSimilarities(*M, SimilarityCandidates);
ASSERT_TRUE(SimilarityCandidates.size() == 1);
for (std::vector<IRSimilarityCandidate> &Cands : SimilarityCandidates) {
ASSERT_TRUE(Cands.size() == 2);
unsigned InstIdx = 0;
for (IRSimilarityCandidate &Cand : Cands) {
ASSERT_TRUE(Cand.getStartIdx() == InstIdx);
InstIdx += 3;
}
}
}
TEST(IRSimilarityIdentifier, InstructionDifference) {
StringRef ModuleString = R"(
define i32 @f(i32 %a, i32 %b, i32 %c, i32 %d) {
bb0:
%0 = sub i32 %a, %b
%1 = add i32 %b, %a
br label %bb1
bb1:
%2 = add i32 %c, %d
%3 = sub i32 %d, %c
ret i32 0
})";
LLVMContext Context;
std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
std::vector<std::vector<IRSimilarityCandidate>> SimilarityCandidates;
getSimilarities(*M, SimilarityCandidates);
ASSERT_TRUE(SimilarityCandidates.empty());
}
TEST(IRSimilarityIdentifier, CommutativeSimilarity) {
StringRef ModuleString = R"(
define i32 @f(i32 %a, i32 %b) {
bb0:
%0 = add i32 %a, %b
%1 = add i32 %b, %a
br label %bb1
bb1:
%2 = add i32 %a, %b
%3 = add i32 %a, %b
ret i32 0
})";
LLVMContext Context;
std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
std::vector<std::vector<IRSimilarityCandidate>> SimilarityCandidates;
getSimilarities(*M, SimilarityCandidates);
ASSERT_TRUE(SimilarityCandidates.size() == 1);
for (std::vector<IRSimilarityCandidate> &Cands : SimilarityCandidates) {
ASSERT_TRUE(Cands.size() == 2);
unsigned InstIdx = 0;
for (IRSimilarityCandidate &Cand : Cands) {
ASSERT_TRUE(Cand.getStartIdx() == InstIdx);
InstIdx += 3;
}
}
}
TEST(IRSimilarityIdentifier, CommutativeSameValueFirstMisMatch) {
StringRef ModuleString = R"(
define void @v_1_0(i64 %v_33) {
entry:
%comm_inst_same_val = mul i64 undef, undef
%add = add i64 %comm_inst_same_val, %v_33
%comm_inst_diff_val = mul i64 0, undef
%mul.i = add i64 %comm_inst_diff_val, %comm_inst_diff_val
unreachable
})";
LLVMContext Context;
std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
std::vector<std::vector<IRSimilarityCandidate>> SimilarityCandidates;
getSimilarities(*M, SimilarityCandidates);
ASSERT_TRUE(SimilarityCandidates.size() == 0);
}
TEST(IRSimilarityIdentifier, IntrinsicCommutative) {
StringRef ModuleString = R"(
define void @foo() {
entry:
%0 = call i16 @llvm.smul.fix.i16(i16 16384, i16 16384, i32 15)
store i16 %0, i16* undef, align 1
%1 = icmp eq i16 undef, 8192
call void @bar()
%2 = call i16 @llvm.smul.fix.i16(i16 -16384, i16 16384, i32 15)
store i16 %2, i16* undef, align 1
%3 = icmp eq i16 undef, -8192
call void @bar()
%4 = call i16 @llvm.smul.fix.i16(i16 -16384, i16 -16384, i32 15)
ret void
}
declare void @bar()
; Function Attrs: nofree nosync nounwind readnone speculatable willreturn
declare i16 @llvm.smul.fix.i16(i16, i16, i32 immarg))";
LLVMContext Context;
std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
std::vector<std::vector<IRSimilarityCandidate>> SimilarityCandidates;
getSimilarities(*M, SimilarityCandidates);
ASSERT_TRUE(SimilarityCandidates.size() == 0);
}
TEST(IRSimilarityIdentifier, NoCommutativeSimilarity) {
StringRef ModuleString = R"(
define i32 @f(i32 %a, i32 %b) {
bb0:
%0 = add i32 %a, %b
%1 = add i32 %1, %b
br label %bb1
bb1:
%2 = add i32 %a, %b
%3 = add i32 %2, %a
ret i32 0
})";
LLVMContext Context;
std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
std::vector<std::vector<IRSimilarityCandidate>> SimilarityCandidates;
getSimilarities(*M, SimilarityCandidates);
ASSERT_TRUE(SimilarityCandidates.size() == 0);
}
TEST(IRSimilarityIdentifier, NonCommutativeDifference) {
StringRef ModuleString = R"(
define i32 @f(i32 %a, i32 %b) {
bb0:
%0 = sub i32 %a, %b
%1 = sub i32 %b, %a
br label %bb1
bb1:
%2 = sub i32 %a, %b
%3 = sub i32 %a, %b
ret i32 0
})";
LLVMContext Context;
std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
std::vector<std::vector<IRSimilarityCandidate>> SimilarityCandidates;
getSimilarities(*M, SimilarityCandidates);
ASSERT_TRUE(SimilarityCandidates.empty());
}
TEST(IRSimilarityIdentifier, MappingSimilarity) {
StringRef ModuleString = R"(
define i32 @f(i32 %a, i32 %b, i32 %c, i32 %d) {
bb0:
%0 = add i32 %a, %b
%1 = sub i32 %b, %a
br label %bb1
bb1:
%2 = add i32 %c, %d
%3 = sub i32 %d, %c
ret i32 0
})";
LLVMContext Context;
std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
std::vector<std::vector<IRSimilarityCandidate>> SimilarityCandidates;
getSimilarities(*M, SimilarityCandidates);
ASSERT_TRUE(SimilarityCandidates.size() == 1);
for (std::vector<IRSimilarityCandidate> &Cands : SimilarityCandidates) {
ASSERT_TRUE(Cands.size() == 2);
unsigned InstIdx = 0;
for (IRSimilarityCandidate &Cand : Cands) {
ASSERT_TRUE(Cand.getStartIdx() == InstIdx);
InstIdx += 3;
}
}
}
TEST(IRSimilarityIdentifier, PredicateIsomorphism) {
StringRef ModuleString = R"(
define i32 @f(i32 %a, i32 %b) {
bb0:
%0 = add i32 %a, %b
%1 = icmp sgt i32 %b, %a
br label %bb1
bb1:
%2 = add i32 %a, %b
%3 = icmp slt i32 %a, %b
ret i32 0
})";
LLVMContext Context;
std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
std::vector<std::vector<IRSimilarityCandidate>> SimilarityCandidates;
getSimilarities(*M, SimilarityCandidates);
ASSERT_TRUE(SimilarityCandidates.size() == 1);
for (std::vector<IRSimilarityCandidate> &Cands : SimilarityCandidates) {
ASSERT_TRUE(Cands.size() == 2);
unsigned InstIdx = 0;
for (IRSimilarityCandidate &Cand : Cands) {
ASSERT_TRUE(Cand.getStartIdx() == InstIdx);
InstIdx += 3;
}
}
}
TEST(IRSimilarityIdentifier, ConstantMappingSimilarity) {
StringRef ModuleString = R"(
define i32 @f(i32 %a, i32 %b) {
bb0:
%0 = add i32 1, %b
%1 = icmp sgt i32 %b, 1
br label %bb1
bb1:
%2 = add i32 %a, %b
%3 = icmp sgt i32 %b, %a
ret i32 0
})";
LLVMContext Context;
std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
std::vector<std::vector<IRSimilarityCandidate>> SimilarityCandidates;
getSimilarities(*M, SimilarityCandidates);
ASSERT_TRUE(SimilarityCandidates.size() == 1);
for (std::vector<IRSimilarityCandidate> &Cands : SimilarityCandidates) {
ASSERT_TRUE(Cands.size() == 2);
unsigned InstIdx = 0;
for (IRSimilarityCandidate &Cand : Cands) {
ASSERT_TRUE(Cand.getStartIdx() == InstIdx);
InstIdx += 3;
}
}
}
TEST(IRSimilarityIdentifier, ConstantMappingDifference) {
StringRef ModuleString = R"(
define i32 @f(i32 %a, i32 %b) {
bb0:
%0 = add i32 1, %b
%1 = icmp sgt i32 %b, 2
br label %bb1
bb1:
%2 = add i32 %a, %b
%3 = icmp slt i32 %a, %b
ret i32 0
})";
LLVMContext Context;
std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
std::vector<std::vector<IRSimilarityCandidate>> SimilarityCandidates;
getSimilarities(*M, SimilarityCandidates);
ASSERT_TRUE(SimilarityCandidates.empty());
}