161483f0eSJohn McCall //===-- llvm-diff.cpp - Module comparator command-line driver ---*- C++ -*-===//
261483f0eSJohn McCall //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
661483f0eSJohn McCall //
761483f0eSJohn McCall //===----------------------------------------------------------------------===//
861483f0eSJohn McCall //
961483f0eSJohn McCall // This file defines the command-line driver for the difference engine.
1061483f0eSJohn McCall //
1161483f0eSJohn McCall //===----------------------------------------------------------------------===//
1261483f0eSJohn McCall
134d293f21SBill Wendling #include "lib/DiffLog.h"
144d293f21SBill Wendling #include "lib/DifferenceEngine.h"
1561483f0eSJohn McCall #include "llvm/ADT/StringRef.h"
169fb823bbSChandler Carruth #include "llvm/IR/LLVMContext.h"
179fb823bbSChandler Carruth #include "llvm/IR/Module.h"
189fb823bbSChandler Carruth #include "llvm/IR/Type.h"
19e60e57beSChandler Carruth #include "llvm/IRReader/IRReader.h"
2061483f0eSJohn McCall #include "llvm/Support/CommandLine.h"
2161483f0eSJohn McCall #include "llvm/Support/MemoryBuffer.h"
2261483f0eSJohn McCall #include "llvm/Support/SourceMgr.h"
234d88a1c2SChandler Carruth #include "llvm/Support/raw_ostream.h"
24*75e164f6Sserge-sans-paille #include "llvm/Support/WithColor.h"
255e6a16d7SJohn McCall #include <string>
265e6a16d7SJohn McCall #include <utility>
275e6a16d7SJohn McCall
285e6a16d7SJohn McCall
295e6a16d7SJohn McCall using namespace llvm;
305e6a16d7SJohn McCall
3180e85e72SDan Gohman /// Reads a module from a file. On error, messages are written to stderr
3280e85e72SDan Gohman /// and null is returned.
readModule(LLVMContext & Context,StringRef Name)33d233b06aSRafael Espindola static std::unique_ptr<Module> readModule(LLVMContext &Context,
34d233b06aSRafael Espindola StringRef Name) {
355e6a16d7SJohn McCall SMDiagnostic Diag;
36d233b06aSRafael Espindola std::unique_ptr<Module> M = parseIRFile(Name, Diag, Context);
3780e85e72SDan Gohman if (!M)
38a3a06810SChris Lattner Diag.print("llvm-diff", errs());
3980e85e72SDan Gohman return M;
405e6a16d7SJohn McCall }
415e6a16d7SJohn McCall
diffGlobal(DifferenceEngine & Engine,Module & L,Module & R,StringRef Name)42d233b06aSRafael Espindola static void diffGlobal(DifferenceEngine &Engine, Module &L, Module &R,
4358c5088dSJohn McCall StringRef Name) {
4458c5088dSJohn McCall // Drop leading sigils from the global name.
4558c5088dSJohn McCall if (Name.startswith("@")) Name = Name.substr(1);
465e6a16d7SJohn McCall
47d233b06aSRafael Espindola Function *LFn = L.getFunction(Name);
48d233b06aSRafael Espindola Function *RFn = R.getFunction(Name);
4958c5088dSJohn McCall if (LFn && RFn)
5058c5088dSJohn McCall Engine.diff(LFn, RFn);
5158c5088dSJohn McCall else if (!LFn && !RFn)
5258c5088dSJohn McCall errs() << "No function named @" << Name << " in either module\n";
5358c5088dSJohn McCall else if (!LFn)
5458c5088dSJohn McCall errs() << "No function named @" << Name << " in left module\n";
5558c5088dSJohn McCall else
5658c5088dSJohn McCall errs() << "No function named @" << Name << " in right module\n";
5758c5088dSJohn McCall }
5858c5088dSJohn McCall
59669275f8STimm Bäder cl::OptionCategory DiffCategory("Diff Options");
60669275f8STimm Bäder
61accb015fSChris Lattner static cl::opt<std::string> LeftFilename(cl::Positional,
62669275f8STimm Bäder cl::desc("<first file>"), cl::Required,
63669275f8STimm Bäder cl::cat(DiffCategory));
64accb015fSChris Lattner static cl::opt<std::string> RightFilename(cl::Positional,
659ad943efSJohn McCall cl::desc("<second file>"),
66669275f8STimm Bäder cl::Required, cl::cat(DiffCategory));
67accb015fSChris Lattner static cl::list<std::string> GlobalsToCompare(cl::Positional,
68669275f8STimm Bäder cl::desc("<globals to compare>"),
69669275f8STimm Bäder cl::cat(DiffCategory));
7058c5088dSJohn McCall
main(int argc,char ** argv)7158c5088dSJohn McCall int main(int argc, char **argv) {
72669275f8STimm Bäder cl::HideUnrelatedOptions({&DiffCategory, &getColorCategory()});
7358c5088dSJohn McCall cl::ParseCommandLineOptions(argc, argv);
745e6a16d7SJohn McCall
755e6a16d7SJohn McCall LLVMContext Context;
765e6a16d7SJohn McCall
775e6a16d7SJohn McCall // Load both modules. Die if that fails.
78d233b06aSRafael Espindola std::unique_ptr<Module> LModule = readModule(Context, LeftFilename);
79d233b06aSRafael Espindola std::unique_ptr<Module> RModule = readModule(Context, RightFilename);
805e6a16d7SJohn McCall if (!LModule || !RModule) return 1;
815e6a16d7SJohn McCall
82628a39faSBenjamin Kramer DiffConsumer Consumer;
83628a39faSBenjamin Kramer DifferenceEngine Engine(Consumer);
845e6a16d7SJohn McCall
8558c5088dSJohn McCall // If any global names were given, just diff those.
8658c5088dSJohn McCall if (!GlobalsToCompare.empty()) {
8758c5088dSJohn McCall for (unsigned I = 0, E = GlobalsToCompare.size(); I != E; ++I)
88d233b06aSRafael Espindola diffGlobal(Engine, *LModule, *RModule, GlobalsToCompare[I]);
895e6a16d7SJohn McCall
9058c5088dSJohn McCall // Otherwise, diff everything in the module.
915e6a16d7SJohn McCall } else {
92d233b06aSRafael Espindola Engine.diff(LModule.get(), RModule.get());
935e6a16d7SJohn McCall }
945e6a16d7SJohn McCall
955e6a16d7SJohn McCall return Consumer.hadDifferences();
965e6a16d7SJohn McCall }
97