diff --git a/llvm/include/llvm/Analysis/IRSimilarityIdentifier.h b/llvm/include/llvm/Analysis/IRSimilarityIdentifier.h --- a/llvm/include/llvm/Analysis/IRSimilarityIdentifier.h +++ b/llvm/include/llvm/Analysis/IRSimilarityIdentifier.h @@ -52,6 +52,8 @@ #include "llvm/IR/InstVisitor.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/Module.h" +#include "llvm/IR/PassManager.h" +#include "llvm/Pass.h" #include "llvm/Support/Allocator.h" namespace llvm { @@ -695,6 +697,50 @@ }; } // end namespace IRSimilarity + +/// An analysis pass based on legacy pass manager that runs and returns +/// IRSimilarityIdentifier run on the Module. +class IRSimilarityIdentifierWrapperPass : public ModulePass { + std::unique_ptr IRSI; + +public: + static char ID; + IRSimilarityIdentifierWrapperPass(); + + IRSimilarity::IRSimilarityIdentifier &getIRSI() { return *IRSI; } + const IRSimilarity::IRSimilarityIdentifier &getIRSI() const { return *IRSI; } + + bool doInitialization(Module &M) override; + bool doFinalization(Module &M) override; + bool runOnModule(Module &M) override; + void getAnalysisUsage(AnalysisUsage &AU) const override { + AU.setPreservesAll(); + } +}; + +/// An analysis pass that runs and returns the IRSimilarityIdentifier run on the +/// Module. +class IRSimilarityAnalysis : public AnalysisInfoMixin { +public: + typedef IRSimilarity::IRSimilarityIdentifier Result; + + Result run(Module &M, ModuleAnalysisManager &); + +private: + friend AnalysisInfoMixin; + static AnalysisKey Key; +}; + +/// Printer pass that uses \c IRSimilarityAnalysis. +class IRSimilarityAnalysisPrinterPass + : public PassInfoMixin { + raw_ostream &OS; + +public: + explicit IRSimilarityAnalysisPrinterPass(raw_ostream &OS) : OS(OS) {} + PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM); +}; + } // end namespace llvm #endif // LLVM_ANALYSIS_IRSIMILARITYIDENTIFIER_H diff --git a/llvm/include/llvm/InitializePasses.h b/llvm/include/llvm/InitializePasses.h --- a/llvm/include/llvm/InitializePasses.h +++ b/llvm/include/llvm/InitializePasses.h @@ -181,6 +181,7 @@ void initializeHWAddressSanitizerLegacyPassPass(PassRegistry &); void initializeIPSCCPLegacyPassPass(PassRegistry&); void initializeIRCELegacyPassPass(PassRegistry&); +void initializeIRSimilarityIdentifierWrapperPassPass(PassRegistry&); void initializeIRTranslatorPass(PassRegistry&); void initializeIVUsersWrapperPassPass(PassRegistry&); void initializeIfConverterPass(PassRegistry&); diff --git a/llvm/lib/Analysis/Analysis.cpp b/llvm/lib/Analysis/Analysis.cpp --- a/llvm/lib/Analysis/Analysis.cpp +++ b/llvm/lib/Analysis/Analysis.cpp @@ -52,6 +52,7 @@ initializeIVUsersWrapperPassPass(Registry); initializeInstCountLegacyPassPass(Registry); initializeIntervalPartitionPass(Registry); + initializeIRSimilarityIdentifierWrapperPassPass(Registry); initializeLazyBranchProbabilityInfoPassPass(Registry); initializeLazyBlockFrequencyInfoPassPass(Registry); initializeLazyValueInfoWrapperPassPass(Registry); diff --git a/llvm/lib/Analysis/IRSimilarityIdentifier.cpp b/llvm/lib/Analysis/IRSimilarityIdentifier.cpp --- a/llvm/lib/Analysis/IRSimilarityIdentifier.cpp +++ b/llvm/lib/Analysis/IRSimilarityIdentifier.cpp @@ -16,6 +16,7 @@ #include "llvm/ADT/DenseMap.h" #include "llvm/IR/Intrinsics.h" #include "llvm/IR/User.h" +#include "llvm/InitializePasses.h" #include "llvm/Support/SuffixTree.h" using namespace llvm; @@ -639,3 +640,58 @@ return SimilarityCandidates.getValue(); } + +INITIALIZE_PASS(IRSimilarityIdentifierWrapperPass, "ir-similarity-identifier", + "ir-similarity-identifier", false, true) + +IRSimilarityIdentifierWrapperPass::IRSimilarityIdentifierWrapperPass() + : ModulePass(ID) { + initializeIRSimilarityIdentifierWrapperPassPass( + *PassRegistry::getPassRegistry()); +} + +bool IRSimilarityIdentifierWrapperPass::doInitialization(Module &M) { + IRSI.reset(new IRSimilarityIdentifier(M)); + return false; +} + +bool IRSimilarityIdentifierWrapperPass::doFinalization(Module &M) { + IRSI.reset(); + return false; +} + +bool IRSimilarityIdentifierWrapperPass::runOnModule(Module &M) { + // All the real work is done in the constructor for the pass. + IRSI.reset(new IRSimilarityIdentifier(M)); + return false; +} + +AnalysisKey IRSimilarityAnalysis::Key; +IRSimilarityIdentifier IRSimilarityAnalysis::run(Module &M, + ModuleAnalysisManager &) { + + return IRSimilarityIdentifier(M); +} + +PreservedAnalyses +IRSimilarityAnalysisPrinterPass::run(Module &M, ModuleAnalysisManager &AM) { + IRSimilarityIdentifier &IRSI = AM.getResult(M); + Optional &SimilarityCandidatesOpt = IRSI.getSimilarity(); + + for (std::vector &CandVec : *SimilarityCandidatesOpt) { + OS << CandVec.size() << " candidates of length " + << CandVec.begin()->getLength() << ". Found in: \n"; + for (IRSimilarityCandidate &Cand : CandVec) { + OS << " Function: " << Cand.front()->Inst->getFunction()->getName().str() + << ", Basic Block: "; + if (Cand.front()->Inst->getParent()->getName().str() == "") + OS << "(unnamed)\n"; + else + OS << Cand.front()->Inst->getParent()->getName().str() << "\n"; + } + } + + return PreservedAnalyses::all(); +} + +char IRSimilarityIdentifierWrapperPass::ID = 0; diff --git a/llvm/lib/Passes/PassBuilder.cpp b/llvm/lib/Passes/PassBuilder.cpp --- a/llvm/lib/Passes/PassBuilder.cpp +++ b/llvm/lib/Passes/PassBuilder.cpp @@ -35,6 +35,7 @@ #include "llvm/Analysis/DominanceFrontier.h" #include "llvm/Analysis/FunctionPropertiesAnalysis.h" #include "llvm/Analysis/GlobalsModRef.h" +#include "llvm/Analysis/IRSimilarityIdentifier.h" #include "llvm/Analysis/IVUsers.h" #include "llvm/Analysis/InlineAdvisor.h" #include "llvm/Analysis/InlineSizeEstimatorAnalysis.h" diff --git a/llvm/lib/Passes/PassRegistry.def b/llvm/lib/Passes/PassRegistry.def --- a/llvm/lib/Passes/PassRegistry.def +++ b/llvm/lib/Passes/PassRegistry.def @@ -28,6 +28,7 @@ MODULE_ANALYSIS("pass-instrumentation", PassInstrumentationAnalysis(PIC)) MODULE_ANALYSIS("asan-globals-md", ASanGlobalsMetadataAnalysis()) MODULE_ANALYSIS("inline-advisor", InlineAdvisorAnalysis()) +MODULE_ANALYSIS("ir-similarity", IRSimilarityAnalysis()) #ifndef MODULE_ALIAS_ANALYSIS #define MODULE_ALIAS_ANALYSIS(NAME, CREATE_PASS) \ @@ -65,6 +66,7 @@ MODULE_PASS("internalize", InternalizePass()) MODULE_PASS("invalidate", InvalidateAllAnalysesPass()) MODULE_PASS("ipsccp", IPSCCPPass()) +MODULE_PASS("print-ir-similarity", IRSimilarityAnalysisPrinterPass(dbgs())) MODULE_PASS("lowertypetests", LowerTypeTestsPass(nullptr, nullptr)) MODULE_PASS("mergefunc", MergeFunctionsPass()) MODULE_PASS("name-anon-globals", NameAnonGlobalPass()) diff --git a/llvm/test/Analysis/IRSimilarityIdentifier/basic.ll b/llvm/test/Analysis/IRSimilarityIdentifier/basic.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Analysis/IRSimilarityIdentifier/basic.ll @@ -0,0 +1,97 @@ +; RUN: opt -disable-output -S -passes=print-ir-similarity < %s 2>&1 | FileCheck %s + +; This is a simple test to make sure the IRSimilarityIdentifier and +; IRSimilarityPrinterPass is working. + +; CHECK: 4 candidates of length 2. Found in: +; CHECK-NEXT: Function: cat, Basic Block: entry +; CHECK-NEXT: Function: fish, Basic Block: entry +; CHECK-NEXT: Function: dog, Basic Block: entry +; CHECK-NEXT: Function: turtle, Basic Block: (unnamed) +; CHECK-NEXT: 4 candidates of length 3. Found in: +; CHECK-NEXT: Function: cat, Basic Block: entry +; CHECK-NEXT: Function: fish, Basic Block: entry +; CHECK-NEXT: Function: dog, Basic Block: entry +; CHECK-NEXT: Function: turtle, Basic Block: (unnamed) +; CHECK-NEXT: 4 candidates of length 4. Found in: +; CHECK-NEXT: Function: cat, Basic Block: entry +; CHECK-NEXT: Function: fish, Basic Block: entry +; CHECK-NEXT: Function: dog, Basic Block: entry +; CHECK-NEXT: Function: turtle, Basic Block: (unnamed) +; CHECK-NEXT: 4 candidates of length 5. Found in: +; CHECK-NEXT: Function: cat, Basic Block: entry +; CHECK-NEXT: Function: fish, Basic Block: entry +; CHECK-NEXT: Function: dog, Basic Block: entry +; CHECK-NEXT: Function: turtle, Basic Block: (unnamed) +; CHECK-NEXT: 4 candidates of length 6. Found in: +; CHECK-NEXT: Function: cat, Basic Block: entry +; CHECK-NEXT: Function: fish, Basic Block: entry +; CHECK-NEXT: Function: dog, Basic Block: entry +; CHECK-NEXT: Function: turtle, Basic Block: (unnamed) + +define linkonce_odr void @fish() { +entry: + %0 = alloca i32, align 4 + %1 = alloca i32, align 4 + %2 = alloca i32, align 4 + %3 = alloca i32, align 4 + %4 = alloca i32, align 4 + %5 = alloca i32, align 4 + store i32 6, i32* %0, align 4 + store i32 1, i32* %1, align 4 + store i32 2, i32* %2, align 4 + store i32 3, i32* %3, align 4 + store i32 4, i32* %4, align 4 + store i32 5, i32* %5, align 4 + ret void +} + +define void @turtle() { + %1 = alloca i32, align 4 + %2 = alloca i32, align 4 + %3 = alloca i32, align 4 + %4 = alloca i32, align 4 + %5 = alloca i32, align 4 + %6 = alloca i32, align 4 + store i32 1, i32* %1, align 4 + store i32 2, i32* %2, align 4 + store i32 3, i32* %3, align 4 + store i32 4, i32* %4, align 4 + store i32 5, i32* %5, align 4 + store i32 6, i32* %6, align 4 + ret void +} + +define void @cat() { +entry: + %0 = alloca i32, align 4 + %1 = alloca i32, align 4 + %2 = alloca i32, align 4 + %3 = alloca i32, align 4 + %4 = alloca i32, align 4 + %5 = alloca i32, align 4 + store i32 6, i32* %0, align 4 + store i32 1, i32* %1, align 4 + store i32 2, i32* %2, align 4 + store i32 3, i32* %3, align 4 + store i32 4, i32* %4, align 4 + store i32 5, i32* %5, align 4 + ret void +} + +define void @dog() { +entry: + %0 = alloca i32, align 4 + %1 = alloca i32, align 4 + %2 = alloca i32, align 4 + %3 = alloca i32, align 4 + %4 = alloca i32, align 4 + %5 = alloca i32, align 4 + store i32 6, i32* %0, align 4 + store i32 1, i32* %1, align 4 + store i32 2, i32* %2, align 4 + store i32 3, i32* %3, align 4 + store i32 4, i32* %4, align 4 + store i32 5, i32* %5, align 4 + ret void +} diff --git a/llvm/test/Analysis/IRSimilarityIdentifier/different.ll b/llvm/test/Analysis/IRSimilarityIdentifier/different.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Analysis/IRSimilarityIdentifier/different.ll @@ -0,0 +1,37 @@ +; RUN: opt -disable-output -S -passes=print-ir-similarity < %s 2>&1 | FileCheck --allow-empty %s + +; Check to make sure that the IRSimilarityIdentifier and IRSimilarityPrinterPass +; return items only within the same function when there are different sets of +; instructions in functions. + +; CHECK: 2 candidates of length 3. Found in: +; CHECK-NEXT: Function: turtle, Basic Block: (unnamed) +; CHECK-NEXT: Function: turtle, Basic Block: (unnamed) +; CHECK-NEXT: 2 candidates of length 5. Found in: +; CHECK-NEXT: Function: fish, Basic Block: entry +; CHECK-NEXT: Function: fish, Basic Block: entry + +define linkonce_odr void @fish() { +entry: + %0 = alloca i32, align 4 + %1 = alloca i32, align 4 + %2 = alloca i32, align 4 + %3 = alloca i32, align 4 + %4 = alloca i32, align 4 + %5 = alloca i32, align 4 + store i32 6, i32* %0, align 4 + store i32 1, i32* %1, align 4 + store i32 2, i32* %2, align 4 + store i32 3, i32* %3, align 4 + store i32 4, i32* %4, align 4 + store i32 5, i32* %5, align 4 + ret void +} + +define void @turtle(i32* %0, i32* %1, i32* %2, i32* %3) { + %a = load i32, i32* %0 + %b = load i32, i32* %1 + %c = load i32, i32* %2 + %d = load i32, i32* %3 + ret void +} diff --git a/llvm/test/Analysis/IRSimilarityIdentifier/nothing.ll b/llvm/test/Analysis/IRSimilarityIdentifier/nothing.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Analysis/IRSimilarityIdentifier/nothing.ll @@ -0,0 +1,11 @@ +; RUN: opt -disable-output -S -passes=print-ir-similarity < %s 2>&1 | FileCheck --allow-empty %s + +; This is a simple test to make sure the IRSimilarityPrinterPass returns +; nothing when there is nothing to analyze. + +; CHECK-NOT: Found in + +define linkonce_odr void @fish() { +entry: + ret void +}