xref: /llvm-project/llvm/tools/llvm-diff/lib/DiffConsumer.cpp (revision b61359f92b0ea74205dc7c916b958e933a69594c)
14d293f21SBill Wendling //===-- DiffConsumer.cpp - Difference Consumer ------------------*- C++ -*-===//
24d293f21SBill Wendling //
34d293f21SBill Wendling // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
44d293f21SBill Wendling // See https://llvm.org/LICENSE.txt for license information.
54d293f21SBill Wendling // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
64d293f21SBill Wendling //
74d293f21SBill Wendling //===----------------------------------------------------------------------===//
84d293f21SBill Wendling //
94d293f21SBill Wendling // This files implements the LLVM difference Consumer
104d293f21SBill Wendling //
114d293f21SBill Wendling //===----------------------------------------------------------------------===//
124d293f21SBill Wendling 
134d293f21SBill Wendling #include "DiffConsumer.h"
144d293f21SBill Wendling #include "llvm/IR/Instructions.h"
154d293f21SBill Wendling #include "llvm/Support/Debug.h"
164d293f21SBill Wendling #include "llvm/Support/ErrorHandling.h"
174d293f21SBill Wendling 
184d293f21SBill Wendling using namespace llvm;
194d293f21SBill Wendling 
ComputeNumbering(const Function * F,DenseMap<const Value *,unsigned> & Numbering)204d293f21SBill Wendling static void ComputeNumbering(const Function *F,
214d293f21SBill Wendling                              DenseMap<const Value *, unsigned> &Numbering) {
224d293f21SBill Wendling   unsigned IN = 0;
234d293f21SBill Wendling 
244d293f21SBill Wendling   // Arguments get the first numbers.
254d293f21SBill Wendling   for (const auto &Arg : F->args())
264d293f21SBill Wendling     if (!Arg.hasName())
274d293f21SBill Wendling       Numbering[&Arg] = IN++;
284d293f21SBill Wendling 
294d293f21SBill Wendling   // Walk the basic blocks in order.
304d293f21SBill Wendling   for (const auto &Func : *F) {
314d293f21SBill Wendling     if (!Func.hasName())
324d293f21SBill Wendling       Numbering[&Func] = IN++;
334d293f21SBill Wendling 
344d293f21SBill Wendling     // Walk the instructions in order.
354d293f21SBill Wendling     for (const auto &BB : Func)
364d293f21SBill Wendling       // void instructions don't get numbers.
374d293f21SBill Wendling       if (!BB.hasName() && !BB.getType()->isVoidTy())
384d293f21SBill Wendling         Numbering[&BB] = IN++;
394d293f21SBill Wendling   }
404d293f21SBill Wendling 
414d293f21SBill Wendling   assert(!Numbering.empty() && "asked for numbering but numbering was no-op");
424d293f21SBill Wendling }
434d293f21SBill Wendling 
anchor()444d293f21SBill Wendling void Consumer::anchor() { }
454d293f21SBill Wendling 
printValue(const Value * V,bool isL)464d293f21SBill Wendling void DiffConsumer::printValue(const Value *V, bool isL) {
474d293f21SBill Wendling   if (V->hasName()) {
484d293f21SBill Wendling     out << (isa<GlobalValue>(V) ? '@' : '%') << V->getName();
494d293f21SBill Wendling     return;
504d293f21SBill Wendling   }
514d293f21SBill Wendling   if (V->getType()->isVoidTy()) {
524d293f21SBill Wendling     if (auto *SI = dyn_cast<StoreInst>(V)) {
534d293f21SBill Wendling       out << "store to ";
544d293f21SBill Wendling       printValue(SI->getPointerOperand(), isL);
554d293f21SBill Wendling     } else if (auto *CI = dyn_cast<CallInst>(V)) {
564d293f21SBill Wendling       out << "call to ";
574d293f21SBill Wendling       printValue(CI->getCalledOperand(), isL);
584d293f21SBill Wendling     } else if (auto *II = dyn_cast<InvokeInst>(V)) {
594d293f21SBill Wendling       out << "invoke to ";
604d293f21SBill Wendling       printValue(II->getCalledOperand(), isL);
614d293f21SBill Wendling     } else {
624d293f21SBill Wendling       out << *V;
634d293f21SBill Wendling     }
644d293f21SBill Wendling     return;
654d293f21SBill Wendling   }
664d293f21SBill Wendling   if (isa<Constant>(V)) {
674d293f21SBill Wendling     out << *V;
684d293f21SBill Wendling     return;
694d293f21SBill Wendling   }
704d293f21SBill Wendling 
714d293f21SBill Wendling   unsigned N = contexts.size();
724d293f21SBill Wendling   while (N > 0) {
734d293f21SBill Wendling     --N;
744d293f21SBill Wendling     DiffContext &ctxt = contexts[N];
754d293f21SBill Wendling     if (!ctxt.IsFunction) continue;
764d293f21SBill Wendling     if (isL) {
774d293f21SBill Wendling       if (ctxt.LNumbering.empty())
784d293f21SBill Wendling         ComputeNumbering(cast<Function>(ctxt.L), ctxt.LNumbering);
794d293f21SBill Wendling       out << '%' << ctxt.LNumbering[V];
804d293f21SBill Wendling       return;
814d293f21SBill Wendling     } else {
824d293f21SBill Wendling       if (ctxt.RNumbering.empty())
834d293f21SBill Wendling         ComputeNumbering(cast<Function>(ctxt.R), ctxt.RNumbering);
844d293f21SBill Wendling       out << '%' << ctxt.RNumbering[V];
854d293f21SBill Wendling       return;
864d293f21SBill Wendling     }
874d293f21SBill Wendling   }
884d293f21SBill Wendling 
894d293f21SBill Wendling   out << "<anonymous>";
904d293f21SBill Wendling }
914d293f21SBill Wendling 
header()924d293f21SBill Wendling void DiffConsumer::header() {
934d293f21SBill Wendling   if (contexts.empty()) return;
944d293f21SBill Wendling   for (SmallVectorImpl<DiffContext>::iterator
954d293f21SBill Wendling          I = contexts.begin(), E = contexts.end(); I != E; ++I) {
964d293f21SBill Wendling     if (I->Differences) continue;
974d293f21SBill Wendling     if (isa<Function>(I->L)) {
984d293f21SBill Wendling       // Extra newline between functions.
994d293f21SBill Wendling       if (Differences) out << "\n";
1004d293f21SBill Wendling 
1014d293f21SBill Wendling       const Function *L = cast<Function>(I->L);
1024d293f21SBill Wendling       const Function *R = cast<Function>(I->R);
1034d293f21SBill Wendling       if (L->getName() != R->getName())
1044d293f21SBill Wendling         out << "in function " << L->getName()
1054d293f21SBill Wendling             << " / " << R->getName() << ":\n";
1064d293f21SBill Wendling       else
1074d293f21SBill Wendling         out << "in function " << L->getName() << ":\n";
1084d293f21SBill Wendling     } else if (isa<BasicBlock>(I->L)) {
1094d293f21SBill Wendling       const BasicBlock *L = cast<BasicBlock>(I->L);
1104d293f21SBill Wendling       const BasicBlock *R = cast<BasicBlock>(I->R);
1114d293f21SBill Wendling       if (L->hasName() && R->hasName() && L->getName() == R->getName())
1124d293f21SBill Wendling         out << "  in block %" << L->getName() << ":\n";
1134d293f21SBill Wendling       else {
1144d293f21SBill Wendling         out << "  in block ";
1154d293f21SBill Wendling         printValue(L, true);
1164d293f21SBill Wendling         out << " / ";
1174d293f21SBill Wendling         printValue(R, false);
1184d293f21SBill Wendling         out << ":\n";
1194d293f21SBill Wendling       }
1204d293f21SBill Wendling     } else if (isa<Instruction>(I->L)) {
1214d293f21SBill Wendling       out << "    in instruction ";
1224d293f21SBill Wendling       printValue(I->L, true);
1234d293f21SBill Wendling       out << " / ";
1244d293f21SBill Wendling       printValue(I->R, false);
1254d293f21SBill Wendling       out << ":\n";
1264d293f21SBill Wendling     }
1274d293f21SBill Wendling 
1284d293f21SBill Wendling     I->Differences = true;
1294d293f21SBill Wendling   }
1304d293f21SBill Wendling }
1314d293f21SBill Wendling 
indent()1324d293f21SBill Wendling void DiffConsumer::indent() {
1334d293f21SBill Wendling   unsigned N = Indent;
1344d293f21SBill Wendling   while (N--) out << ' ';
1354d293f21SBill Wendling }
1364d293f21SBill Wendling 
reset()13739809eb1SBill Wendling void DiffConsumer::reset() {
138*b61359f9SBill Wendling   contexts.clear();
13939809eb1SBill Wendling   Differences = false;
14039809eb1SBill Wendling   Indent = 0;
14139809eb1SBill Wendling }
14239809eb1SBill Wendling 
hadDifferences() const1434d293f21SBill Wendling bool DiffConsumer::hadDifferences() const {
1444d293f21SBill Wendling   return Differences;
1454d293f21SBill Wendling }
1464d293f21SBill Wendling 
enterContext(const Value * L,const Value * R)1474d293f21SBill Wendling void DiffConsumer::enterContext(const Value *L, const Value *R) {
1484d293f21SBill Wendling   contexts.push_back(DiffContext(L, R));
1494d293f21SBill Wendling   Indent += 2;
1504d293f21SBill Wendling }
1514d293f21SBill Wendling 
exitContext()1524d293f21SBill Wendling void DiffConsumer::exitContext() {
1534d293f21SBill Wendling   Differences |= contexts.back().Differences;
1544d293f21SBill Wendling   contexts.pop_back();
1554d293f21SBill Wendling   Indent -= 2;
1564d293f21SBill Wendling }
1574d293f21SBill Wendling 
log(StringRef text)1584d293f21SBill Wendling void DiffConsumer::log(StringRef text) {
1594d293f21SBill Wendling   header();
1604d293f21SBill Wendling   indent();
1614d293f21SBill Wendling   out << text << '\n';
1624d293f21SBill Wendling }
1634d293f21SBill Wendling 
logf(const LogBuilder & Log)1644d293f21SBill Wendling void DiffConsumer::logf(const LogBuilder &Log) {
1654d293f21SBill Wendling   header();
1664d293f21SBill Wendling   indent();
1674d293f21SBill Wendling 
1684d293f21SBill Wendling   unsigned arg = 0;
1694d293f21SBill Wendling 
1704d293f21SBill Wendling   StringRef format = Log.getFormat();
1714d293f21SBill Wendling   while (true) {
1724d293f21SBill Wendling     size_t percent = format.find('%');
1734d293f21SBill Wendling     if (percent == StringRef::npos) {
1744d293f21SBill Wendling       out << format;
1754d293f21SBill Wendling       break;
1764d293f21SBill Wendling     }
1774d293f21SBill Wendling     assert(format[percent] == '%');
1784d293f21SBill Wendling 
1794d293f21SBill Wendling     if (percent > 0) out << format.substr(0, percent);
1804d293f21SBill Wendling 
1814d293f21SBill Wendling     switch (format[percent+1]) {
1824d293f21SBill Wendling     case '%': out << '%'; break;
1834d293f21SBill Wendling     case 'l': printValue(Log.getArgument(arg++), true); break;
1844d293f21SBill Wendling     case 'r': printValue(Log.getArgument(arg++), false); break;
1854d293f21SBill Wendling     default: llvm_unreachable("unknown format character");
1864d293f21SBill Wendling     }
1874d293f21SBill Wendling 
1884d293f21SBill Wendling     format = format.substr(percent+2);
1894d293f21SBill Wendling   }
1904d293f21SBill Wendling 
1914d293f21SBill Wendling   out << '\n';
1924d293f21SBill Wendling }
1934d293f21SBill Wendling 
logd(const DiffLogBuilder & Log)1944d293f21SBill Wendling void DiffConsumer::logd(const DiffLogBuilder &Log) {
1954d293f21SBill Wendling   header();
1964d293f21SBill Wendling 
1974d293f21SBill Wendling   for (unsigned I = 0, E = Log.getNumLines(); I != E; ++I) {
1984d293f21SBill Wendling     indent();
1994d293f21SBill Wendling     switch (Log.getLineKind(I)) {
2004d293f21SBill Wendling     case DC_match:
2014d293f21SBill Wendling       out << "  ";
2024d293f21SBill Wendling       Log.getLeft(I)->print(dbgs()); dbgs() << '\n';
2034d293f21SBill Wendling       //printValue(Log.getLeft(I), true);
2044d293f21SBill Wendling       break;
2054d293f21SBill Wendling     case DC_left:
2064d293f21SBill Wendling       out << "< ";
2074d293f21SBill Wendling       Log.getLeft(I)->print(dbgs()); dbgs() << '\n';
2084d293f21SBill Wendling       //printValue(Log.getLeft(I), true);
2094d293f21SBill Wendling       break;
2104d293f21SBill Wendling     case DC_right:
2114d293f21SBill Wendling       out << "> ";
2124d293f21SBill Wendling       Log.getRight(I)->print(dbgs()); dbgs() << '\n';
2134d293f21SBill Wendling       //printValue(Log.getRight(I), false);
2144d293f21SBill Wendling       break;
2154d293f21SBill Wendling     }
2164d293f21SBill Wendling     //out << "\n";
2174d293f21SBill Wendling   }
2184d293f21SBill Wendling }
219