Index: llvm/tools/llvm-diff/CMakeLists.txt =================================================================== --- llvm/tools/llvm-diff/CMakeLists.txt +++ llvm/tools/llvm-diff/CMakeLists.txt @@ -1,6 +1,8 @@ set(LLVM_LINK_COMPONENTS + Analysis Core IRReader + Passes Support ) Index: llvm/tools/llvm-diff/llvm-diff.cpp =================================================================== --- llvm/tools/llvm-diff/llvm-diff.cpp +++ llvm/tools/llvm-diff/llvm-diff.cpp @@ -13,6 +13,7 @@ #include "DiffLog.h" #include "DifferenceEngine.h" #include "llvm/ADT/StringRef.h" +#include "llvm/IR/ChangeReporters.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Module.h" #include "llvm/IR/Type.h" @@ -26,6 +27,12 @@ using namespace llvm; +using namespace cr; + +static cl::opt DotCfgDiff( + "dot-cfg", + cl::desc("Generate dot files into specified directory to show differences"), + cl::NotHidden, cl::init("")); /// Reads a module from a file. On error, messages are written to stderr /// and null is returned. @@ -38,21 +45,31 @@ return M; } -static void diffGlobal(DifferenceEngine &Engine, Module &L, Module &R, - StringRef Name) { +static std::pair getFuncs(Module &L, Module &R, + StringRef Name) { // Drop leading sigils from the global name. if (Name.startswith("@")) Name = Name.substr(1); Function *LFn = L.getFunction(Name); Function *RFn = R.getFunction(Name); if (LFn && RFn) - Engine.diff(LFn, RFn); - else if (!LFn && !RFn) + return {LFn, RFn}; + if (!LFn && !RFn) errs() << "No function named @" << Name << " in either module\n"; else if (!LFn) errs() << "No function named @" << Name << " in left module\n"; else errs() << "No function named @" << Name << " in right module\n"; + return {nullptr, nullptr}; +} + +static void diffGlobal(DifferenceEngine &Engine, Module &L, Module &R, + StringRef Name) { + Function *LFn = nullptr; + Function *RFn = nullptr; + std::tie(LFn, RFn) = getFuncs(L, R, Name); + if (LFn && RFn) + Engine.diff(LFn, RFn); } static cl::opt LeftFilename(cl::Positional, @@ -74,6 +91,57 @@ std::unique_ptr RModule = readModule(Context, RightFilename); if (!LModule || !RModule) return 1; + if (DotCfgDiff != "") { + std::error_code EC; + llvm::raw_fd_ostream HTML(DotCfgDiff + "/dot-cfg-diffs.html", EC); + if (EC) { + errs() << "Error: " << EC.message() << "\n"; + return 1; + } + + HTML << "dot-cfg-diffs.html\n" + << ""; + + // If any global names were given, just diff those. + if (!GlobalsToCompare.empty()) { + for (unsigned I = 0, E = GlobalsToCompare.size(); I != E; ++I) { + Function *LFn = nullptr; + Function *RFn = nullptr; + std::tie(LFn, RFn) = getFuncs(*LModule, *RModule, GlobalsToCompare[I]); + if (LFn && RFn) { + Any LAny((const Function *)LFn); + BlockSuccessorsIRData Before; + CFGDotComparer::analyzeIR(LAny, Before); + Any RAny((const Function *)RFn); + BlockSuccessorsIRData After; + CFGDotComparer::analyzeIR(RAny, After); + + // Create diff for function. + CFGDotComparer CDC(HTML, I, DotCfgDiff, Before, After); + CDC.compare(LAny, "", "", LFn->getName()); + } + } + } else { + // Otherwise, diff everything in the module. + Any LAny(&(const Module &)((*LModule))); + BlockSuccessorsIRData Before; + CFGDotComparer::analyzeIR(LAny, Before); + Any RAny(&(const Module &)((*RModule))); + BlockSuccessorsIRData After; + CFGDotComparer::analyzeIR(RAny, After); + + CFGDotComparer CDC(HTML, 0, DotCfgDiff, Before, After); + CDC.compare(RAny, "", "", ""); + } + + HTML << "\n"; + HTML.flush(); + HTML.close(); + + return 0; + } + DiffConsumer Consumer; DifferenceEngine Engine(Consumer);