10b57cec5SDimitry Andric //===-- DiffConsumer.cpp - Difference Consumer ------------------*- C++ -*-===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // This files implements the LLVM difference Consumer
100b57cec5SDimitry Andric //
110b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
120b57cec5SDimitry Andric 
130b57cec5SDimitry Andric #include "DiffConsumer.h"
140b57cec5SDimitry Andric #include "llvm/IR/Instructions.h"
150b57cec5SDimitry Andric #include "llvm/Support/Debug.h"
160b57cec5SDimitry Andric #include "llvm/Support/ErrorHandling.h"
170b57cec5SDimitry Andric 
180b57cec5SDimitry Andric using namespace llvm;
190b57cec5SDimitry Andric 
ComputeNumbering(const Function * F,DenseMap<const Value *,unsigned> & Numbering)20*5f7ddb14SDimitry Andric static void ComputeNumbering(const Function *F,
21*5f7ddb14SDimitry Andric                              DenseMap<const Value *, unsigned> &Numbering) {
220b57cec5SDimitry Andric   unsigned IN = 0;
230b57cec5SDimitry Andric 
240b57cec5SDimitry Andric   // Arguments get the first numbers.
25*5f7ddb14SDimitry Andric   for (const auto &Arg : F->args())
26*5f7ddb14SDimitry Andric     if (!Arg.hasName())
27*5f7ddb14SDimitry Andric       Numbering[&Arg] = IN++;
280b57cec5SDimitry Andric 
290b57cec5SDimitry Andric   // Walk the basic blocks in order.
30*5f7ddb14SDimitry Andric   for (const auto &Func : *F) {
31*5f7ddb14SDimitry Andric     if (!Func.hasName())
32*5f7ddb14SDimitry Andric       Numbering[&Func] = IN++;
330b57cec5SDimitry Andric 
340b57cec5SDimitry Andric     // Walk the instructions in order.
35*5f7ddb14SDimitry Andric     for (const auto &BB : Func)
360b57cec5SDimitry Andric       // void instructions don't get numbers.
37*5f7ddb14SDimitry Andric       if (!BB.hasName() && !BB.getType()->isVoidTy())
38*5f7ddb14SDimitry Andric         Numbering[&BB] = IN++;
390b57cec5SDimitry Andric   }
400b57cec5SDimitry Andric 
410b57cec5SDimitry Andric   assert(!Numbering.empty() && "asked for numbering but numbering was no-op");
420b57cec5SDimitry Andric }
430b57cec5SDimitry Andric 
anchor()440b57cec5SDimitry Andric void Consumer::anchor() { }
450b57cec5SDimitry Andric 
printValue(const Value * V,bool isL)46*5f7ddb14SDimitry Andric void DiffConsumer::printValue(const Value *V, bool isL) {
470b57cec5SDimitry Andric   if (V->hasName()) {
480b57cec5SDimitry Andric     out << (isa<GlobalValue>(V) ? '@' : '%') << V->getName();
490b57cec5SDimitry Andric     return;
500b57cec5SDimitry Andric   }
510b57cec5SDimitry Andric   if (V->getType()->isVoidTy()) {
525ffd83dbSDimitry Andric     if (auto *SI = dyn_cast<StoreInst>(V)) {
530b57cec5SDimitry Andric       out << "store to ";
545ffd83dbSDimitry Andric       printValue(SI->getPointerOperand(), isL);
555ffd83dbSDimitry Andric     } else if (auto *CI = dyn_cast<CallInst>(V)) {
560b57cec5SDimitry Andric       out << "call to ";
575ffd83dbSDimitry Andric       printValue(CI->getCalledOperand(), isL);
585ffd83dbSDimitry Andric     } else if (auto *II = dyn_cast<InvokeInst>(V)) {
590b57cec5SDimitry Andric       out << "invoke to ";
605ffd83dbSDimitry Andric       printValue(II->getCalledOperand(), isL);
610b57cec5SDimitry Andric     } else {
620b57cec5SDimitry Andric       out << *V;
630b57cec5SDimitry Andric     }
640b57cec5SDimitry Andric     return;
650b57cec5SDimitry Andric   }
660b57cec5SDimitry Andric   if (isa<Constant>(V)) {
670b57cec5SDimitry Andric     out << *V;
680b57cec5SDimitry Andric     return;
690b57cec5SDimitry Andric   }
700b57cec5SDimitry Andric 
710b57cec5SDimitry Andric   unsigned N = contexts.size();
720b57cec5SDimitry Andric   while (N > 0) {
730b57cec5SDimitry Andric     --N;
740b57cec5SDimitry Andric     DiffContext &ctxt = contexts[N];
750b57cec5SDimitry Andric     if (!ctxt.IsFunction) continue;
760b57cec5SDimitry Andric     if (isL) {
770b57cec5SDimitry Andric       if (ctxt.LNumbering.empty())
780b57cec5SDimitry Andric         ComputeNumbering(cast<Function>(ctxt.L), ctxt.LNumbering);
790b57cec5SDimitry Andric       out << '%' << ctxt.LNumbering[V];
800b57cec5SDimitry Andric       return;
810b57cec5SDimitry Andric     } else {
820b57cec5SDimitry Andric       if (ctxt.RNumbering.empty())
830b57cec5SDimitry Andric         ComputeNumbering(cast<Function>(ctxt.R), ctxt.RNumbering);
840b57cec5SDimitry Andric       out << '%' << ctxt.RNumbering[V];
850b57cec5SDimitry Andric       return;
860b57cec5SDimitry Andric     }
870b57cec5SDimitry Andric   }
880b57cec5SDimitry Andric 
890b57cec5SDimitry Andric   out << "<anonymous>";
900b57cec5SDimitry Andric }
910b57cec5SDimitry Andric 
header()920b57cec5SDimitry Andric void DiffConsumer::header() {
930b57cec5SDimitry Andric   if (contexts.empty()) return;
940b57cec5SDimitry Andric   for (SmallVectorImpl<DiffContext>::iterator
950b57cec5SDimitry Andric          I = contexts.begin(), E = contexts.end(); I != E; ++I) {
960b57cec5SDimitry Andric     if (I->Differences) continue;
970b57cec5SDimitry Andric     if (isa<Function>(I->L)) {
980b57cec5SDimitry Andric       // Extra newline between functions.
990b57cec5SDimitry Andric       if (Differences) out << "\n";
1000b57cec5SDimitry Andric 
101*5f7ddb14SDimitry Andric       const Function *L = cast<Function>(I->L);
102*5f7ddb14SDimitry Andric       const Function *R = cast<Function>(I->R);
1030b57cec5SDimitry Andric       if (L->getName() != R->getName())
1040b57cec5SDimitry Andric         out << "in function " << L->getName()
1050b57cec5SDimitry Andric             << " / " << R->getName() << ":\n";
1060b57cec5SDimitry Andric       else
1070b57cec5SDimitry Andric         out << "in function " << L->getName() << ":\n";
1080b57cec5SDimitry Andric     } else if (isa<BasicBlock>(I->L)) {
109*5f7ddb14SDimitry Andric       const BasicBlock *L = cast<BasicBlock>(I->L);
110*5f7ddb14SDimitry Andric       const BasicBlock *R = cast<BasicBlock>(I->R);
1110b57cec5SDimitry Andric       if (L->hasName() && R->hasName() && L->getName() == R->getName())
1120b57cec5SDimitry Andric         out << "  in block %" << L->getName() << ":\n";
1130b57cec5SDimitry Andric       else {
1140b57cec5SDimitry Andric         out << "  in block ";
1150b57cec5SDimitry Andric         printValue(L, true);
1160b57cec5SDimitry Andric         out << " / ";
1170b57cec5SDimitry Andric         printValue(R, false);
1180b57cec5SDimitry Andric         out << ":\n";
1190b57cec5SDimitry Andric       }
1200b57cec5SDimitry Andric     } else if (isa<Instruction>(I->L)) {
1210b57cec5SDimitry Andric       out << "    in instruction ";
1220b57cec5SDimitry Andric       printValue(I->L, true);
1230b57cec5SDimitry Andric       out << " / ";
1240b57cec5SDimitry Andric       printValue(I->R, false);
1250b57cec5SDimitry Andric       out << ":\n";
1260b57cec5SDimitry Andric     }
1270b57cec5SDimitry Andric 
1280b57cec5SDimitry Andric     I->Differences = true;
1290b57cec5SDimitry Andric   }
1300b57cec5SDimitry Andric }
1310b57cec5SDimitry Andric 
indent()1320b57cec5SDimitry Andric void DiffConsumer::indent() {
1330b57cec5SDimitry Andric   unsigned N = Indent;
1340b57cec5SDimitry Andric   while (N--) out << ' ';
1350b57cec5SDimitry Andric }
1360b57cec5SDimitry Andric 
hadDifferences() const1370b57cec5SDimitry Andric bool DiffConsumer::hadDifferences() const {
1380b57cec5SDimitry Andric   return Differences;
1390b57cec5SDimitry Andric }
1400b57cec5SDimitry Andric 
enterContext(const Value * L,const Value * R)141*5f7ddb14SDimitry Andric void DiffConsumer::enterContext(const Value *L, const Value *R) {
1420b57cec5SDimitry Andric   contexts.push_back(DiffContext(L, R));
1430b57cec5SDimitry Andric   Indent += 2;
1440b57cec5SDimitry Andric }
1450b57cec5SDimitry Andric 
exitContext()1460b57cec5SDimitry Andric void DiffConsumer::exitContext() {
1470b57cec5SDimitry Andric   Differences |= contexts.back().Differences;
1480b57cec5SDimitry Andric   contexts.pop_back();
1490b57cec5SDimitry Andric   Indent -= 2;
1500b57cec5SDimitry Andric }
1510b57cec5SDimitry Andric 
log(StringRef text)1520b57cec5SDimitry Andric void DiffConsumer::log(StringRef text) {
1530b57cec5SDimitry Andric   header();
1540b57cec5SDimitry Andric   indent();
1550b57cec5SDimitry Andric   out << text << '\n';
1560b57cec5SDimitry Andric }
1570b57cec5SDimitry Andric 
logf(const LogBuilder & Log)1580b57cec5SDimitry Andric void DiffConsumer::logf(const LogBuilder &Log) {
1590b57cec5SDimitry Andric   header();
1600b57cec5SDimitry Andric   indent();
1610b57cec5SDimitry Andric 
1620b57cec5SDimitry Andric   unsigned arg = 0;
1630b57cec5SDimitry Andric 
1640b57cec5SDimitry Andric   StringRef format = Log.getFormat();
1650b57cec5SDimitry Andric   while (true) {
1660b57cec5SDimitry Andric     size_t percent = format.find('%');
1670b57cec5SDimitry Andric     if (percent == StringRef::npos) {
1680b57cec5SDimitry Andric       out << format;
1690b57cec5SDimitry Andric       break;
1700b57cec5SDimitry Andric     }
1710b57cec5SDimitry Andric     assert(format[percent] == '%');
1720b57cec5SDimitry Andric 
1730b57cec5SDimitry Andric     if (percent > 0) out << format.substr(0, percent);
1740b57cec5SDimitry Andric 
1750b57cec5SDimitry Andric     switch (format[percent+1]) {
1760b57cec5SDimitry Andric     case '%': out << '%'; break;
1770b57cec5SDimitry Andric     case 'l': printValue(Log.getArgument(arg++), true); break;
1780b57cec5SDimitry Andric     case 'r': printValue(Log.getArgument(arg++), false); break;
1790b57cec5SDimitry Andric     default: llvm_unreachable("unknown format character");
1800b57cec5SDimitry Andric     }
1810b57cec5SDimitry Andric 
1820b57cec5SDimitry Andric     format = format.substr(percent+2);
1830b57cec5SDimitry Andric   }
1840b57cec5SDimitry Andric 
1850b57cec5SDimitry Andric   out << '\n';
1860b57cec5SDimitry Andric }
1870b57cec5SDimitry Andric 
logd(const DiffLogBuilder & Log)1880b57cec5SDimitry Andric void DiffConsumer::logd(const DiffLogBuilder &Log) {
1890b57cec5SDimitry Andric   header();
1900b57cec5SDimitry Andric 
1910b57cec5SDimitry Andric   for (unsigned I = 0, E = Log.getNumLines(); I != E; ++I) {
1920b57cec5SDimitry Andric     indent();
1930b57cec5SDimitry Andric     switch (Log.getLineKind(I)) {
1940b57cec5SDimitry Andric     case DC_match:
1950b57cec5SDimitry Andric       out << "  ";
1960b57cec5SDimitry Andric       Log.getLeft(I)->print(dbgs()); dbgs() << '\n';
1970b57cec5SDimitry Andric       //printValue(Log.getLeft(I), true);
1980b57cec5SDimitry Andric       break;
1990b57cec5SDimitry Andric     case DC_left:
2000b57cec5SDimitry Andric       out << "< ";
2010b57cec5SDimitry Andric       Log.getLeft(I)->print(dbgs()); dbgs() << '\n';
2020b57cec5SDimitry Andric       //printValue(Log.getLeft(I), true);
2030b57cec5SDimitry Andric       break;
2040b57cec5SDimitry Andric     case DC_right:
2050b57cec5SDimitry Andric       out << "> ";
2060b57cec5SDimitry Andric       Log.getRight(I)->print(dbgs()); dbgs() << '\n';
2070b57cec5SDimitry Andric       //printValue(Log.getRight(I), false);
2080b57cec5SDimitry Andric       break;
2090b57cec5SDimitry Andric     }
2100b57cec5SDimitry Andric     //out << "\n";
2110b57cec5SDimitry Andric   }
2120b57cec5SDimitry Andric }
213