xref: /freebsd-src/contrib/llvm-project/llvm/tools/llvm-diff/llvm-diff.cpp (revision 0b57cec536236d46e3dba9bd041533462f33dbb7)
1*0b57cec5SDimitry Andric //===-- llvm-diff.cpp - Module comparator command-line driver ---*- C++ -*-===//
2*0b57cec5SDimitry Andric //
3*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*0b57cec5SDimitry Andric //
7*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
8*0b57cec5SDimitry Andric //
9*0b57cec5SDimitry Andric // This file defines the command-line driver for the difference engine.
10*0b57cec5SDimitry Andric //
11*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
12*0b57cec5SDimitry Andric 
13*0b57cec5SDimitry Andric #include "DiffLog.h"
14*0b57cec5SDimitry Andric #include "DifferenceEngine.h"
15*0b57cec5SDimitry Andric #include "llvm/ADT/StringRef.h"
16*0b57cec5SDimitry Andric #include "llvm/IR/LLVMContext.h"
17*0b57cec5SDimitry Andric #include "llvm/IR/Module.h"
18*0b57cec5SDimitry Andric #include "llvm/IR/Type.h"
19*0b57cec5SDimitry Andric #include "llvm/IRReader/IRReader.h"
20*0b57cec5SDimitry Andric #include "llvm/Support/CommandLine.h"
21*0b57cec5SDimitry Andric #include "llvm/Support/MemoryBuffer.h"
22*0b57cec5SDimitry Andric #include "llvm/Support/SourceMgr.h"
23*0b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
24*0b57cec5SDimitry Andric #include <string>
25*0b57cec5SDimitry Andric #include <utility>
26*0b57cec5SDimitry Andric 
27*0b57cec5SDimitry Andric 
28*0b57cec5SDimitry Andric using namespace llvm;
29*0b57cec5SDimitry Andric 
30*0b57cec5SDimitry Andric /// Reads a module from a file.  On error, messages are written to stderr
31*0b57cec5SDimitry Andric /// and null is returned.
32*0b57cec5SDimitry Andric static std::unique_ptr<Module> readModule(LLVMContext &Context,
33*0b57cec5SDimitry Andric                                           StringRef Name) {
34*0b57cec5SDimitry Andric   SMDiagnostic Diag;
35*0b57cec5SDimitry Andric   std::unique_ptr<Module> M = parseIRFile(Name, Diag, Context);
36*0b57cec5SDimitry Andric   if (!M)
37*0b57cec5SDimitry Andric     Diag.print("llvm-diff", errs());
38*0b57cec5SDimitry Andric   return M;
39*0b57cec5SDimitry Andric }
40*0b57cec5SDimitry Andric 
41*0b57cec5SDimitry Andric static void diffGlobal(DifferenceEngine &Engine, Module &L, Module &R,
42*0b57cec5SDimitry Andric                        StringRef Name) {
43*0b57cec5SDimitry Andric   // Drop leading sigils from the global name.
44*0b57cec5SDimitry Andric   if (Name.startswith("@")) Name = Name.substr(1);
45*0b57cec5SDimitry Andric 
46*0b57cec5SDimitry Andric   Function *LFn = L.getFunction(Name);
47*0b57cec5SDimitry Andric   Function *RFn = R.getFunction(Name);
48*0b57cec5SDimitry Andric   if (LFn && RFn)
49*0b57cec5SDimitry Andric     Engine.diff(LFn, RFn);
50*0b57cec5SDimitry Andric   else if (!LFn && !RFn)
51*0b57cec5SDimitry Andric     errs() << "No function named @" << Name << " in either module\n";
52*0b57cec5SDimitry Andric   else if (!LFn)
53*0b57cec5SDimitry Andric     errs() << "No function named @" << Name << " in left module\n";
54*0b57cec5SDimitry Andric   else
55*0b57cec5SDimitry Andric     errs() << "No function named @" << Name << " in right module\n";
56*0b57cec5SDimitry Andric }
57*0b57cec5SDimitry Andric 
58*0b57cec5SDimitry Andric static cl::opt<std::string> LeftFilename(cl::Positional,
59*0b57cec5SDimitry Andric                                          cl::desc("<first file>"),
60*0b57cec5SDimitry Andric                                          cl::Required);
61*0b57cec5SDimitry Andric static cl::opt<std::string> RightFilename(cl::Positional,
62*0b57cec5SDimitry Andric                                           cl::desc("<second file>"),
63*0b57cec5SDimitry Andric                                           cl::Required);
64*0b57cec5SDimitry Andric static cl::list<std::string> GlobalsToCompare(cl::Positional,
65*0b57cec5SDimitry Andric                                               cl::desc("<globals to compare>"));
66*0b57cec5SDimitry Andric 
67*0b57cec5SDimitry Andric int main(int argc, char **argv) {
68*0b57cec5SDimitry Andric   cl::ParseCommandLineOptions(argc, argv);
69*0b57cec5SDimitry Andric 
70*0b57cec5SDimitry Andric   LLVMContext Context;
71*0b57cec5SDimitry Andric 
72*0b57cec5SDimitry Andric   // Load both modules.  Die if that fails.
73*0b57cec5SDimitry Andric   std::unique_ptr<Module> LModule = readModule(Context, LeftFilename);
74*0b57cec5SDimitry Andric   std::unique_ptr<Module> RModule = readModule(Context, RightFilename);
75*0b57cec5SDimitry Andric   if (!LModule || !RModule) return 1;
76*0b57cec5SDimitry Andric 
77*0b57cec5SDimitry Andric   DiffConsumer Consumer;
78*0b57cec5SDimitry Andric   DifferenceEngine Engine(Consumer);
79*0b57cec5SDimitry Andric 
80*0b57cec5SDimitry Andric   // If any global names were given, just diff those.
81*0b57cec5SDimitry Andric   if (!GlobalsToCompare.empty()) {
82*0b57cec5SDimitry Andric     for (unsigned I = 0, E = GlobalsToCompare.size(); I != E; ++I)
83*0b57cec5SDimitry Andric       diffGlobal(Engine, *LModule, *RModule, GlobalsToCompare[I]);
84*0b57cec5SDimitry Andric 
85*0b57cec5SDimitry Andric   // Otherwise, diff everything in the module.
86*0b57cec5SDimitry Andric   } else {
87*0b57cec5SDimitry Andric     Engine.diff(LModule.get(), RModule.get());
88*0b57cec5SDimitry Andric   }
89*0b57cec5SDimitry Andric 
90*0b57cec5SDimitry Andric   return Consumer.hadDifferences();
91*0b57cec5SDimitry Andric }
92